[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
|
assets/design_doc.org
|
||||||
.clangd
|
.clangd
|
||||||
*.swp
|
*.swp
|
||||||
|
*.db
|
||||||
|
|||||||
@ -30,7 +30,7 @@ void GameState::_init_desktop(void) {
|
|||||||
|
|
||||||
void GameState::_run_server(void) {
|
void GameState::_run_server(void) {
|
||||||
try {
|
try {
|
||||||
NetworkManager server;
|
NetworkManager server("bettola_sp.db");
|
||||||
server.start(SINGLE_PLAYER_PORT);
|
server.start(SINGLE_PLAYER_PORT);
|
||||||
/*
|
/*
|
||||||
* Server's start() method is non-blocking, but NetworkManager
|
* 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. */
|
_main_menu.reset(); /* Free mem. */
|
||||||
|
|
||||||
if(_current_screen == Screen::LOGIN) {
|
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. */
|
/* Connect to server. */
|
||||||
if(_is_single_player) {
|
if(_is_single_player) {
|
||||||
fprintf(stdout, "Starting in single-player mode...\n");
|
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. */
|
/* 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;
|
_current_screen = Screen::DESKTOP;
|
||||||
_init_desktop();
|
_init_desktop();
|
||||||
_boot_sequence.reset(); /* Free mem. */
|
_boot_sequence.reset(); /* Free mem. */
|
||||||
|
|||||||
@ -5,8 +5,18 @@
|
|||||||
#include "ui/ui_renderer.h"
|
#include "ui/ui_renderer.h"
|
||||||
#include "ui/login_screen.h"
|
#include "ui/login_screen.h"
|
||||||
|
|
||||||
LoginScreen::LoginScreen(int screen_width, int screen_height)
|
LoginScreen::LoginScreen(int screen_width, int screen_height) :
|
||||||
: _screen_width(screen_width), _screen_height(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) {}
|
LoginScreen::~LoginScreen(void) {}
|
||||||
|
|
||||||
@ -18,10 +28,13 @@ void LoginScreen::render(const RenderContext& context) const {
|
|||||||
UIRenderer* ui_renderer = context.ui_renderer;
|
UIRenderer* ui_renderer = context.ui_renderer;
|
||||||
|
|
||||||
/* Colours. */
|
/* Colours. */
|
||||||
|
const Color bg_color = { 0.06f, 0.07f, 0.09f };
|
||||||
const Color text_color = { 0.8f, 0.8f, 0.8f };
|
const Color text_color = { 0.8f, 0.8f, 0.8f };
|
||||||
const Color inactive_box_color = { 0.1f, 0.1f, 0.15f };
|
const Color inactive_box_color = { 0.1f, 0.1f, 0.15f };
|
||||||
const Color active_box_color = { 0.15f, 0.15f, 0.2f };
|
const Color active_box_color = { 0.15f, 0.15f, 0.2f };
|
||||||
const Color warning_color = { 0.7f, 0.3f, 0.3f };
|
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. */
|
/* Layout. */
|
||||||
const int box_width = 300;
|
const int box_width = 300;
|
||||||
@ -36,11 +49,28 @@ void LoginScreen::render(const RenderContext& context) const {
|
|||||||
ui_renderer->begin_shapes();
|
ui_renderer->begin_shapes();
|
||||||
ui_renderer->begin_text();
|
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. */
|
/* Draw title. */
|
||||||
const char* title = _is_new_account ? "Create Account" : "Login";
|
const char* title = _is_new_account ? "Create Account" : "Login";
|
||||||
float title_width = ui_renderer->get_text_renderer()->get_text_width(title, 1.0f);
|
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);
|
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. */
|
/* Draw input boxes and labels. */
|
||||||
/* Username */
|
/* Username */
|
||||||
ui_renderer->render_text("Username", username_rect.x, username_rect.y-5, text_color);
|
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();
|
ui_renderer->flush_text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LoginScreen::set_error_message(const std::string& msg) {
|
||||||
|
_error_message = msg;
|
||||||
|
}
|
||||||
|
|
||||||
void LoginScreen::handle_event(const SDL_Event* event) {
|
void LoginScreen::handle_event(const SDL_Event* event) {
|
||||||
if(event->type == SDL_EVENT_TEXT_INPUT) {
|
if(event->type == SDL_EVENT_TEXT_INPUT) {
|
||||||
/* Append character to active input string. */
|
/* 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 password_rect = { center_x, start_y+100, box_width, 30 };
|
||||||
const Rect hostname_rect = { center_x, start_y+160, 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;
|
_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;
|
_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;
|
_active_field = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -18,12 +18,16 @@ public:
|
|||||||
std::string get_username(void) const { return _username_input; }
|
std::string get_username(void) const { return _username_input; }
|
||||||
std::string get_password(void) const { return _password_input; }
|
std::string get_password(void) const { return _password_input; }
|
||||||
std::string get_hostname(void) const { return _hostname_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:
|
private:
|
||||||
/* UI State. */
|
/* UI State. */
|
||||||
std::string _username_input;
|
std::string _username_input;
|
||||||
std::string _password_input;
|
std::string _password_input;
|
||||||
std::string _hostname_input;
|
std::string _hostname_input;
|
||||||
|
std::string _error_message;
|
||||||
|
|
||||||
bool _login_attempted = false;
|
bool _login_attempted = false;
|
||||||
bool _is_new_account = true;
|
bool _is_new_account = true;
|
||||||
@ -32,4 +36,8 @@ private:
|
|||||||
/* Screen dimensions. */
|
/* Screen dimensions. */
|
||||||
int _screen_width;
|
int _screen_width;
|
||||||
int _screen_height;
|
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 "network_manager.h"
|
||||||
#include "net/constants.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 {
|
try {
|
||||||
/* We'll keep main thread alive while server runs in background. */
|
/* We'll keep main thread alive while server runs in background. */
|
||||||
NetworkManager server;
|
NetworkManager server(DB_FILE);
|
||||||
server.start(MULTIPLAYER_PORT);
|
server.start(MULTIPLAYER_PORT);
|
||||||
while(true) {
|
while(true) {
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
|||||||
@ -2,8 +2,10 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "network_manager.h"
|
#include "network_manager.h"
|
||||||
|
#include "db/database_manager.h"
|
||||||
|
|
||||||
#include "asio/error_code.hpp"
|
#include "asio/error_code.hpp"
|
||||||
#include "asio/ip/tcp.hpp"
|
#include "asio/ip/tcp.hpp"
|
||||||
@ -13,7 +15,9 @@
|
|||||||
#include "net/tcp_connection.h"
|
#include "net/tcp_connection.h"
|
||||||
#include "vfs.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 setup. */
|
||||||
_world_machines["8.8.8.8"] = _machine_manager.create_machine(1000, "dns.google", "npc");
|
_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");
|
_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["8.8.8.8"]->services[80] = "HTTPD v2.4";
|
||||||
_world_machines["10.0.2.15"]->services[21] = "FTPd v3.0";
|
_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());
|
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,
|
void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
||||||
const std::string& message) {
|
const std::string& message) {
|
||||||
Player* player = _players[connection->get_id()].get();
|
Player* player = _players[connection->get_id()].get();
|
||||||
@ -107,6 +124,51 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
|||||||
return;
|
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. */
|
/* Check for "special" message prefixes. */
|
||||||
if(message.rfind("WRITEF::", 0) == 0) {
|
if(message.rfind("WRITEF::", 0) == 0) {
|
||||||
/* Message format: WRITEF::/path/to/file::content. */
|
/* Message format: WRITEF::/path/to/file::content. */
|
||||||
|
|||||||
@ -12,9 +12,11 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "machine_manager.h"
|
#include "machine_manager.h"
|
||||||
|
|
||||||
|
class DatabaseManager;
|
||||||
|
|
||||||
class NetworkManager {
|
class NetworkManager {
|
||||||
public:
|
public:
|
||||||
NetworkManager();
|
NetworkManager(const std::string& db_path);
|
||||||
~NetworkManager(void);
|
~NetworkManager(void);
|
||||||
|
|
||||||
void start(uint16_t port);
|
void start(uint16_t port);
|
||||||
@ -36,4 +38,5 @@ private:
|
|||||||
|
|
||||||
std::map<std::string, Machine*> _world_machines; /* For NPC's. */
|
std::map<std::string, Machine*> _world_machines; /* For NPC's. */
|
||||||
MachineManager _machine_manager;
|
MachineManager _machine_manager;
|
||||||
|
std::unique_ptr<DatabaseManager> _db_manager;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
Player::Player(uint32_t new_id, Machine* home_machine,
|
Player::Player(uint32_t new_id, Machine* home_machine,
|
||||||
std::map<std::string, Machine*>& world_machines) :
|
std::map<std::string, Machine*>& world_machines) :
|
||||||
id(new_id) {
|
id(new_id),
|
||||||
|
state(PlayerState::AUTHENTICATING) {
|
||||||
|
|
||||||
cmd_processor = new CommandProcessor(home_machine, world_machines);
|
cmd_processor = new CommandProcessor(home_machine, world_machines);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,11 +7,17 @@
|
|||||||
#include "command_processor.h"
|
#include "command_processor.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
|
|
||||||
|
enum class PlayerState {
|
||||||
|
AUTHENTICATING,
|
||||||
|
ACTIVE
|
||||||
|
};
|
||||||
|
|
||||||
class Player {
|
class Player {
|
||||||
public:
|
public:
|
||||||
Player(uint32_t id, Machine* home_machine, std::map<std::string, Machine*>& world_machines);
|
Player(uint32_t id, Machine* home_machine, std::map<std::string, Machine*>& world_machines);
|
||||||
~Player(void);
|
~Player(void);
|
||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
|
PlayerState state;
|
||||||
CommandProcessor* cmd_processor; /* Manages the VFS state for the remote session. */
|
CommandProcessor* cmd_processor; /* Manages the VFS state for the remote session. */
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user