[Add] Implement database persistance and Login UI.
[Build System] - Integrate 'sqlite3' and 'sqlite_modern_cpp' using FetchContent. - Enabled 'C' language to allow compilation of 'sqlite3' lib. [Persistance] - Adds a 'DatabaseManager' class to handle all SQLite operations. - Creates a 'players' table on server startup. - Server uses separate database for single-player 'bettola_sp.db' and 'bettola.db' [UI] - Adds a new 'LoginScreen' UI. - Game flow is now MainMenu -> LoginScreen -> bootSequence -> Desktop. - 'LoginScreen' has interactive tabs to switch between "Login" and "Create Account" 'modes'. - Full client-server communication for creating accounts and authentication. [Server] - Refactor 'NetworkManager' to handle an 'AUTHENTICATING' state for new connectiosn. - Player state is only set to 'ACTIVE' after a successful login
This commit is contained in:
		
							parent
							
								
									564512225f
								
							
						
					
					
						commit
						fce3b3aad6
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -17,3 +17,4 @@ compile_commands.json
 | 
			
		||||
assets/design_doc.org
 | 
			
		||||
.clangd
 | 
			
		||||
*.swp
 | 
			
		||||
*.db
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ void GameState::_init_desktop(void) {
 | 
			
		||||
 | 
			
		||||
void GameState::_run_server(void) {
 | 
			
		||||
  try {
 | 
			
		||||
    NetworkManager server;
 | 
			
		||||
    NetworkManager server("bettola_sp.db");
 | 
			
		||||
    server.start(SINGLE_PLAYER_PORT);
 | 
			
		||||
    /*
 | 
			
		||||
     * Server's start() method is non-blocking, but NetworkManager
 | 
			
		||||
@ -123,27 +123,6 @@ void GameState::update(float dt, int draw_calls, int shape_verts, int text_verts
 | 
			
		||||
      _main_menu.reset(); /* Free mem. */
 | 
			
		||||
 | 
			
		||||
      if(_current_screen == Screen::LOGIN) {
 | 
			
		||||
        _login_screen = std::make_unique<LoginScreen>(_screen_width, _screen_height);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  case Screen::LOGIN:
 | 
			
		||||
    if(_login_screen && _login_screen->is_login_attempted()) {
 | 
			
		||||
      /* TODO: Send credentials to server for verification. */
 | 
			
		||||
      printf("Login attempt: user=%s, pass=%s, host=%s\n",
 | 
			
		||||
            _login_screen->get_username().c_str(),
 | 
			
		||||
            _login_screen->get_password().c_str(),
 | 
			
		||||
            _login_screen->get_hostname().c_str());
 | 
			
		||||
 | 
			
		||||
      _current_screen = Screen::BOOTING;
 | 
			
		||||
      _login_screen.reset(); /* Free mem. */
 | 
			
		||||
      _boot_sequence = std::make_unique<BootSequence>();
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  case Screen::BOOTING: {
 | 
			
		||||
    if(!_boot_sequence) break; /* Shouldn't happen. */
 | 
			
		||||
    if(_boot_sequence->is_finished()) {
 | 
			
		||||
        /* Connect to server. */
 | 
			
		||||
        if(_is_single_player) {
 | 
			
		||||
          fprintf(stdout, "Starting in single-player mode...\n");
 | 
			
		||||
@ -158,6 +137,45 @@ void GameState::update(float dt, int draw_calls, int shape_verts, int text_verts
 | 
			
		||||
            /* TODO: Handle connection failure. */
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        _login_screen = std::make_unique<LoginScreen>(_screen_width, _screen_height);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    break;
 | 
			
		||||
  }
 | 
			
		||||
  case Screen::LOGIN: {
 | 
			
		||||
    if(_login_screen && _login_screen->is_login_attempted()) {
 | 
			
		||||
      std::string username = _login_screen->get_username();
 | 
			
		||||
      std::string password = _login_screen->get_password();
 | 
			
		||||
 | 
			
		||||
      if(_login_screen->is_new_account_mode()) {
 | 
			
		||||
        std::string hostname = _login_screen->get_hostname();
 | 
			
		||||
        std::string msg = "C_ACC::" + username + "::" + password + "::" + hostname;
 | 
			
		||||
        _network->send(msg);
 | 
			
		||||
      } else {
 | 
			
		||||
        std::string msg = "LOGIN::" + username + "::" + password;
 | 
			
		||||
        _network->send(msg);
 | 
			
		||||
      }
 | 
			
		||||
      _login_screen->clear_login_attempt(); /* Try to spam my server now b.tch! */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Check for server response to our login attempt. */
 | 
			
		||||
    std::string server_msg;
 | 
			
		||||
    while(_network->poll_message(server_msg)) {
 | 
			
		||||
      if(server_msg == "LOGIN_SUCCESS" || server_msg == "C_ACC_SUCCESS") {
 | 
			
		||||
        _current_screen = Screen::BOOTING;
 | 
			
		||||
        _login_screen.reset(); /* Free mem. */
 | 
			
		||||
        _boot_sequence = std::make_unique<BootSequence>();
 | 
			
		||||
        break;
 | 
			
		||||
      } else if(server_msg == "LOGIN_FAIL") {
 | 
			
		||||
        _login_screen->set_error_message("Invalid username or password.");
 | 
			
		||||
      } else if(server_msg == "C_ACC_FAIL") {
 | 
			
		||||
        _login_screen->set_error_message("Username already exists.");
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  } break;
 | 
			
		||||
  case Screen::BOOTING: {
 | 
			
		||||
    if(!_boot_sequence) break; /* Shouldn't happen. */
 | 
			
		||||
    if(_boot_sequence->is_finished()) {
 | 
			
		||||
      _current_screen = Screen::DESKTOP;
 | 
			
		||||
      _init_desktop();
 | 
			
		||||
      _boot_sequence.reset(); /* Free mem. */
 | 
			
		||||
 | 
			
		||||
@ -5,8 +5,18 @@
 | 
			
		||||
#include "ui/ui_renderer.h"
 | 
			
		||||
#include "ui/login_screen.h"
 | 
			
		||||
 | 
			
		||||
LoginScreen::LoginScreen(int screen_width, int screen_height) 
 | 
			
		||||
    : _screen_width(screen_width), _screen_height(screen_height) {}
 | 
			
		||||
LoginScreen::LoginScreen(int screen_width, int screen_height) :
 | 
			
		||||
    _screen_width(screen_width),
 | 
			
		||||
    _screen_height(screen_height) {
 | 
			
		||||
 | 
			
		||||
  _is_new_account = false; /* Default to login. */
 | 
			
		||||
 | 
			
		||||
  /* Position tabs relative to the form. */
 | 
			
		||||
  const int form_center_x   = _screen_width  / 2 - 25;
 | 
			
		||||
  const int tabs_y          = (_screen_height / 2 - 100) + 200;
 | 
			
		||||
  _login_tab_rect           = { form_center_x-90, tabs_y, 80,  30 };
 | 
			
		||||
  _create_account_tab_rect  = { form_center_x+10, tabs_y, 150, 30 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LoginScreen::~LoginScreen(void) {}
 | 
			
		||||
 | 
			
		||||
@ -18,10 +28,13 @@ void LoginScreen::render(const RenderContext& context) const {
 | 
			
		||||
  UIRenderer* ui_renderer = context.ui_renderer;
 | 
			
		||||
 | 
			
		||||
  /* Colours. */
 | 
			
		||||
  const Color bg_color            = { 0.06f,  0.07f,  0.09f };
 | 
			
		||||
  const Color text_color          = { 0.8f,   0.8f,   0.8f  };
 | 
			
		||||
  const Color inactive_box_color  = { 0.1f,   0.1f,   0.15f };
 | 
			
		||||
  const Color active_box_color    = { 0.15f,  0.15f,  0.2f  };
 | 
			
		||||
  const Color warning_color       = { 0.7f,   0.3f,   0.3f  };
 | 
			
		||||
  const Color active_tab_color    = { 0.9f,   0.9f,   0.9f  };
 | 
			
		||||
  const Color inactive_tab_color  = { 0.4f,   0.5f,   0.6f  };
 | 
			
		||||
 | 
			
		||||
  /* Layout. */
 | 
			
		||||
  const int box_width   = 300;
 | 
			
		||||
@ -36,11 +49,28 @@ void LoginScreen::render(const RenderContext& context) const {
 | 
			
		||||
  ui_renderer->begin_shapes();
 | 
			
		||||
  ui_renderer->begin_text();
 | 
			
		||||
 | 
			
		||||
  /* Draw background. */
 | 
			
		||||
  ui_renderer->draw_rect(0, 0, _screen_width, _screen_height, bg_color);
 | 
			
		||||
 | 
			
		||||
  /* Draw mode-switch tabs. */
 | 
			
		||||
  ui_renderer->render_text("[Login]", _login_tab_rect.x, _login_tab_rect.y + 20,
 | 
			
		||||
                           _is_new_account ? inactive_tab_color : active_tab_color);
 | 
			
		||||
  ui_renderer->render_text("[Create Account]", _create_account_tab_rect.x,
 | 
			
		||||
                           _create_account_tab_rect.y + 20,
 | 
			
		||||
                           _is_new_account ? active_tab_color : inactive_tab_color);
 | 
			
		||||
 | 
			
		||||
  /* Draw title. */
 | 
			
		||||
  const char* title = _is_new_account ? "Create Account" : "Login";
 | 
			
		||||
  float title_width = ui_renderer->get_text_renderer()->get_text_width(title, 1.0f);
 | 
			
		||||
  ui_renderer->render_text(title, (_screen_width-title_width)/2, start_y, text_color);
 | 
			
		||||
 | 
			
		||||
  /* Draw error message if it exists. */
 | 
			
		||||
  if(!_error_message.empty()) {
 | 
			
		||||
    float error_width = ui_renderer->get_text_renderer()->get_text_width(_error_message.c_str(), 1.0f);
 | 
			
		||||
    ui_renderer->render_text(_error_message.c_str(), (_screen_width-error_width)/2,
 | 
			
		||||
                             start_y+20, warning_color);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Draw input boxes and labels. */
 | 
			
		||||
  /* Username */
 | 
			
		||||
  ui_renderer->render_text("Username", username_rect.x, username_rect.y-5, text_color);
 | 
			
		||||
@ -99,6 +129,10 @@ void LoginScreen::render(const RenderContext& context) const {
 | 
			
		||||
  ui_renderer->flush_text();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LoginScreen::set_error_message(const std::string& msg) {
 | 
			
		||||
  _error_message = msg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LoginScreen::handle_event(const SDL_Event* event) {
 | 
			
		||||
  if(event->type == SDL_EVENT_TEXT_INPUT) {
 | 
			
		||||
    /* Append character to active input string. */
 | 
			
		||||
@ -139,11 +173,23 @@ void LoginScreen::handle_event(const SDL_Event* event) {
 | 
			
		||||
    const Rect password_rect = { center_x, start_y+100, box_width, 30 };
 | 
			
		||||
    const Rect hostname_rect = { center_x, start_y+160, box_width, 30 };
 | 
			
		||||
 | 
			
		||||
    if(mouse_y >= username_rect.y && mouse_y <= username_rect.y + username_rect.h)
 | 
			
		||||
    auto is_inside = [&](const Rect& rect) {
 | 
			
		||||
      return mouse_x >= rect.x && mouse_x <= rect.x + rect.w &&
 | 
			
		||||
             mouse_y >= rect.y && mouse_y <= rect.y + rect.h;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if(is_inside(_login_tab_rect)) {
 | 
			
		||||
      _is_new_account = false;
 | 
			
		||||
      _username_input.clear(); _password_input.clear(); _hostname_input.clear();
 | 
			
		||||
    } else if(is_inside(_create_account_tab_rect)) {
 | 
			
		||||
      _is_new_account = true;
 | 
			
		||||
      _username_input.clear(); _password_input.clear(); _hostname_input.clear();
 | 
			
		||||
    } else if(is_inside(username_rect)) {
 | 
			
		||||
      _active_field = 0;
 | 
			
		||||
    else if(mouse_y >= password_rect.y && mouse_y <= password_rect.y + password_rect.h)
 | 
			
		||||
    } else if(is_inside(password_rect)) {
 | 
			
		||||
      _active_field = 1;
 | 
			
		||||
    else if(_is_new_account && (mouse_y >= hostname_rect.y && mouse_y <= hostname_rect.y + hostname_rect.h))
 | 
			
		||||
    } else if(_is_new_account && is_inside(hostname_rect)) {
 | 
			
		||||
      _active_field = 2;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -18,12 +18,16 @@ public:
 | 
			
		||||
  std::string get_username(void) const { return _username_input;  }
 | 
			
		||||
  std::string get_password(void) const { return _password_input;  }
 | 
			
		||||
  std::string get_hostname(void) const { return _hostname_input;  }
 | 
			
		||||
  bool is_new_account_mode(void) const { return _is_new_account;  }
 | 
			
		||||
  void clear_login_attempt(void)       { _login_attempted = false;}
 | 
			
		||||
  void set_error_message(const std::string& msg);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  /* UI State. */
 | 
			
		||||
  std::string _username_input;
 | 
			
		||||
  std::string _password_input;
 | 
			
		||||
  std::string _hostname_input;
 | 
			
		||||
  std::string _error_message;
 | 
			
		||||
 | 
			
		||||
  bool _login_attempted   = false;
 | 
			
		||||
  bool _is_new_account    = true;
 | 
			
		||||
@ -32,4 +36,8 @@ private:
 | 
			
		||||
  /* Screen dimensions. */
 | 
			
		||||
  int _screen_width;
 | 
			
		||||
  int _screen_height;
 | 
			
		||||
 | 
			
		||||
  /* Clickable tabs for mode switching. */
 | 
			
		||||
  Rect _create_account_tab_rect;
 | 
			
		||||
  Rect _login_tab_rect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								common/src/db/database_manager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								common/src/db/database_manager.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
#include "database_manager.h"
 | 
			
		||||
 | 
			
		||||
DatabaseManager::DatabaseManager(const std::string& db_path) : _db(db_path) {
 | 
			
		||||
  /* db is opened in the construtor's init list. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DatabaseManager::~DatabaseManager(void) {
 | 
			
		||||
  /* db is auto closed when _db goes out of scope. */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DatabaseManager::init(void) {
 | 
			
		||||
  _db <<  "CREATE TABLE IF NOT EXISTS players("
 | 
			
		||||
          "id INTEGER PRIMARY KEY AUTOINCREMENT,"
 | 
			
		||||
          "username TEXT NOT NULL UNIQUE,"
 | 
			
		||||
          "password TEXT NOT NULL,"
 | 
			
		||||
          "hostname TEXT NOT NULL"
 | 
			
		||||
          ");";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DatabaseManager::create_player(const std::string& username, const std::string& password,
 | 
			
		||||
                                    const std::string& hostname) {
 | 
			
		||||
  try {
 | 
			
		||||
    _db << "INSERT INTO players (username, password, hostname) VALUES (?, ?, ?);"
 | 
			
		||||
        << username
 | 
			
		||||
        << password
 | 
			
		||||
        << hostname;
 | 
			
		||||
  } catch(const std::exception& e) {
 | 
			
		||||
    /* Fail if the username exists. */
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DatabaseManager::auth_player(const std::string& username, const std::string& password) {
 | 
			
		||||
  bool authed = false;
 | 
			
		||||
  _db << "SELECT id FROM players WHERE username = ? AND password = ?;"
 | 
			
		||||
      << username
 | 
			
		||||
      << password
 | 
			
		||||
      >> [&](long long id) { authed = true; };
 | 
			
		||||
 | 
			
		||||
  return authed;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								common/src/db/database_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								common/src/db/database_manager.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "db.h"
 | 
			
		||||
 | 
			
		||||
class DatabaseManager {
 | 
			
		||||
public:
 | 
			
		||||
  DatabaseManager(const std::string& db_path);
 | 
			
		||||
  ~DatabaseManager(void);
 | 
			
		||||
 | 
			
		||||
  void init(void);
 | 
			
		||||
 | 
			
		||||
  /* Return true on success, false if user already exists. */
 | 
			
		||||
  bool create_player(const std::string& username, const std::string& password,
 | 
			
		||||
                     const std::string& hostname);
 | 
			
		||||
 | 
			
		||||
  /* Return true if creds are valid. */
 | 
			
		||||
  bool auth_player(const std::string& username, const std::string& password);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  sqlite::database _db;
 | 
			
		||||
};
 | 
			
		||||
@ -6,11 +6,12 @@
 | 
			
		||||
#include "network_manager.h"
 | 
			
		||||
#include "net/constants.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
const std::string DB_FILE = "bettola.db";
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
  try {
 | 
			
		||||
    /* We'll keep main thread alive while server runs in background. */
 | 
			
		||||
    NetworkManager server;
 | 
			
		||||
    NetworkManager server(DB_FILE);
 | 
			
		||||
    server.start(MULTIPLAYER_PORT);
 | 
			
		||||
    while(true) {
 | 
			
		||||
      std::this_thread::sleep_for(std::chrono::seconds(1));
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,10 @@
 | 
			
		||||
#include <exception>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
#include "network_manager.h"
 | 
			
		||||
#include "db/database_manager.h"
 | 
			
		||||
 | 
			
		||||
#include "asio/error_code.hpp"
 | 
			
		||||
#include "asio/ip/tcp.hpp"
 | 
			
		||||
@ -13,7 +15,9 @@
 | 
			
		||||
#include "net/tcp_connection.h"
 | 
			
		||||
#include "vfs.h"
 | 
			
		||||
 | 
			
		||||
NetworkManager::NetworkManager(void) : _acceptor(_io_context) {
 | 
			
		||||
NetworkManager::NetworkManager(const std::string& db_path) :
 | 
			
		||||
    _db_manager(std::make_unique<DatabaseManager>(db_path)),
 | 
			
		||||
    _acceptor(_io_context) {
 | 
			
		||||
  /* World setup. */
 | 
			
		||||
  _world_machines["8.8.8.8"]   = _machine_manager.create_machine(1000, "dns.google", "npc");
 | 
			
		||||
  _world_machines["10.0.2.15"] = _machine_manager.create_machine(1001, "corp.internal", "npc");
 | 
			
		||||
@ -22,6 +26,8 @@ NetworkManager::NetworkManager(void) : _acceptor(_io_context) {
 | 
			
		||||
  _world_machines["8.8.8.8"]->services[80] = "HTTPD v2.4";
 | 
			
		||||
  _world_machines["10.0.2.15"]->services[21] = "FTPd v3.0";
 | 
			
		||||
 | 
			
		||||
  _db_manager->init();
 | 
			
		||||
 | 
			
		||||
  fprintf(stderr, "Created world with %zu networks\n", _world_machines.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -99,6 +105,17 @@ void NetworkManager::start_accept(void) {
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::vector<std::string> split_message(const std::string& s, const std::string& delimiter) {
 | 
			
		||||
  std::vector<std::string> tokens;
 | 
			
		||||
  size_t start = 0, end = 0;
 | 
			
		||||
  while((end = s.find(delimiter, start)) != std::string::npos) {
 | 
			
		||||
    tokens.push_back(s.substr(start, end-start));
 | 
			
		||||
    start = end + delimiter.length();
 | 
			
		||||
  }
 | 
			
		||||
  tokens.push_back(s.substr(start));
 | 
			
		||||
  return tokens;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
 | 
			
		||||
                                const std::string& message) {
 | 
			
		||||
  Player* player = _players[connection->get_id()].get();
 | 
			
		||||
@ -107,6 +124,51 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(player->state == PlayerState::AUTHENTICATING) {
 | 
			
		||||
    if(message.rfind("C_ACC::", 0) == 0) {
 | 
			
		||||
      std::string payload = message.substr(7);
 | 
			
		||||
      auto parts = split_message(payload, "::");
 | 
			
		||||
      if(parts.size() == 3) {
 | 
			
		||||
        if(_db_manager->create_player(parts[0], parts[1], parts[2])) {
 | 
			
		||||
          /*
 | 
			
		||||
           * TODO: When creating a player, also create their machine and save it.
 | 
			
		||||
           * for now, they will juse use a temp machine on auth.
 | 
			
		||||
           */
 | 
			
		||||
          player->state = PlayerState::ACTIVE;
 | 
			
		||||
          connection->send("C_ACC_SUCCESS");
 | 
			
		||||
          /* send initial prompt. */
 | 
			
		||||
          std::string prompt = "\n" + get_full_path(player->cmd_processor->get_current_dir());
 | 
			
		||||
          connection->send(prompt);
 | 
			
		||||
        } else {
 | 
			
		||||
          connection->send("C_ACC_FAIL");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else if(message.rfind("LOGIN::", 0) == 0) {
 | 
			
		||||
      std::string payload = message.substr(7);
 | 
			
		||||
      auto parts = split_message(payload, "::");
 | 
			
		||||
      if(parts.size() == 2) {
 | 
			
		||||
        if(_db_manager->auth_player(parts[0], parts[1])) {
 | 
			
		||||
          /*
 | 
			
		||||
           * TODO: Load the player's machine from the database.
 | 
			
		||||
           * For now, just auth them and use a temp machine.
 | 
			
		||||
           */
 | 
			
		||||
          player->state = PlayerState::ACTIVE;
 | 
			
		||||
          connection->send("LOGIN_SUCCESS");
 | 
			
		||||
          /* Send initial prompt. */
 | 
			
		||||
          std::string prompt = "\n" + get_full_path(player->cmd_processor->get_current_dir());
 | 
			
		||||
          connection->send(prompt);
 | 
			
		||||
        } else {
 | 
			
		||||
          connection->send("LOGIN_FAIL");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      /* Ignore all other messages while authing. */
 | 
			
		||||
      connection->send("ERR: Not authenticated.\n");
 | 
			
		||||
    }
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  /* === PLAYER BECOMES ACTIVE HERE === */
 | 
			
		||||
 | 
			
		||||
  /* Check for "special" message prefixes. */
 | 
			
		||||
  if(message.rfind("WRITEF::", 0) == 0) {
 | 
			
		||||
    /* Message format: WRITEF::/path/to/file::content. */
 | 
			
		||||
 | 
			
		||||
@ -12,9 +12,11 @@
 | 
			
		||||
#include "player.h"
 | 
			
		||||
#include "machine_manager.h"
 | 
			
		||||
 | 
			
		||||
class DatabaseManager;
 | 
			
		||||
 | 
			
		||||
class NetworkManager {
 | 
			
		||||
public:
 | 
			
		||||
  NetworkManager();
 | 
			
		||||
  NetworkManager(const std::string& db_path);
 | 
			
		||||
  ~NetworkManager(void);
 | 
			
		||||
 | 
			
		||||
  void start(uint16_t port);
 | 
			
		||||
@ -36,4 +38,5 @@ private:
 | 
			
		||||
 | 
			
		||||
  std::map<std::string, Machine*> _world_machines; /* For NPC's. */
 | 
			
		||||
  MachineManager _machine_manager;
 | 
			
		||||
  std::unique_ptr<DatabaseManager> _db_manager;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,8 @@
 | 
			
		||||
 | 
			
		||||
Player::Player(uint32_t new_id, Machine* home_machine,
 | 
			
		||||
               std::map<std::string, Machine*>& world_machines) :
 | 
			
		||||
    id(new_id) {
 | 
			
		||||
    id(new_id),
 | 
			
		||||
    state(PlayerState::AUTHENTICATING) {
 | 
			
		||||
 | 
			
		||||
  cmd_processor = new CommandProcessor(home_machine, world_machines);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,11 +7,17 @@
 | 
			
		||||
#include "command_processor.h"
 | 
			
		||||
#include "machine.h"
 | 
			
		||||
 | 
			
		||||
enum class PlayerState {
 | 
			
		||||
  AUTHENTICATING,
 | 
			
		||||
  ACTIVE
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Player {
 | 
			
		||||
public:
 | 
			
		||||
  Player(uint32_t id, Machine* home_machine, std::map<std::string, Machine*>& world_machines);
 | 
			
		||||
  ~Player(void);
 | 
			
		||||
 | 
			
		||||
  uint32_t id;
 | 
			
		||||
  PlayerState state;
 | 
			
		||||
  CommandProcessor* cmd_processor; /* Manages the VFS state for the remote session. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user