parent
b150c814fe
commit
651f7c415e
@ -1,6 +1,7 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
@ -25,9 +26,13 @@ void GameState::_init_desktop(void) {
|
|||||||
_desktop = std::make_unique<Desktop>(_screen_width, _screen_height, this);
|
_desktop = std::make_unique<Desktop>(_screen_width, _screen_height, this);
|
||||||
|
|
||||||
auto term = std::make_unique<Terminal>(this);
|
auto term = std::make_unique<Terminal>(this);
|
||||||
|
term->set_session_id(_initial_session_id);
|
||||||
|
|
||||||
auto term_window = std::make_unique<UIWindow>("Terminal", 100, 100, 800, 500);
|
auto term_window = std::make_unique<UIWindow>("Terminal", 100, 100, 800, 500);
|
||||||
|
UIWindow* window_ptr = term_window.get();
|
||||||
term_window->set_content(std::move(term));
|
term_window->set_content(std::move(term));
|
||||||
_desktop->add_window(std::move(term_window));
|
_desktop->add_window(std::move(term_window));
|
||||||
|
_desktop->register_session(_initial_session_id, window_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameState::_run_server(void) {
|
void GameState::_run_server(void) {
|
||||||
@ -52,7 +57,8 @@ GameState::GameState(void) :
|
|||||||
_screen_width(0),
|
_screen_width(0),
|
||||||
_screen_height(0),
|
_screen_height(0),
|
||||||
_is_single_player(false),
|
_is_single_player(false),
|
||||||
_show_debug_overlay(false) {_debug_overlay = std::make_unique<DebugOverlay>();}
|
_show_debug_overlay(false),
|
||||||
|
_initial_session_id(0) {_debug_overlay = std::make_unique<DebugOverlay>();}
|
||||||
|
|
||||||
GameState::~GameState(void) = default;
|
GameState::~GameState(void) = default;
|
||||||
|
|
||||||
@ -170,6 +176,12 @@ void GameState::update(float dt, int draw_calls, int shape_verts, int text_verts
|
|||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case net_protocol::Opcode::S2C_LOGIN_SUCCESS:
|
case net_protocol::Opcode::S2C_LOGIN_SUCCESS:
|
||||||
case net_protocol::Opcode::S2C_CREATE_ACCOUNT_SUCCESS:
|
case net_protocol::Opcode::S2C_CREATE_ACCOUNT_SUCCESS:
|
||||||
|
/* Don't switch screen yet, wait for the session ID. */
|
||||||
|
break;
|
||||||
|
case net_protocol::Opcode::S2C_SESSION_CREATED:
|
||||||
|
if(!args.empty()) {
|
||||||
|
_initial_session_id = std::stoul(args[0]);
|
||||||
|
}
|
||||||
_current_screen = Screen::BOOTING;
|
_current_screen = Screen::BOOTING;
|
||||||
_login_screen.reset(); /* Free mem. */
|
_login_screen.reset(); /* Free mem. */
|
||||||
_boot_sequence = std::make_unique<BootSequence>();
|
_boot_sequence = std::make_unique<BootSequence>();
|
||||||
@ -210,57 +222,79 @@ void GameState::update(float dt, int draw_calls, int shape_verts, int text_verts
|
|||||||
net_protocol::parse_message(server_msg, opcode, args);
|
net_protocol::parse_message(server_msg, opcode, args);
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
|
case net_protocol::Opcode::S2C_SESSION_CREATED:
|
||||||
|
if(!args.empty()) {
|
||||||
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
|
UIWindow* new_term = _desktop->get_window_awaiting_session_id();
|
||||||
|
if(new_term) {
|
||||||
|
Terminal* term = dynamic_cast<Terminal*>(new_term->get_content());
|
||||||
|
if(term) {
|
||||||
|
term->set_session_id(session_id);
|
||||||
|
_desktop->register_session(session_id, new_term);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case net_protocol::Opcode::S2C_FILE_DATA:
|
case net_protocol::Opcode::S2C_FILE_DATA:
|
||||||
if(args.size() == 2) {
|
if(args.size() == 3) {
|
||||||
auto editor = std::make_unique<Editor>(args[0]);
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
editor->set_buffer_content(args[1]);
|
auto editor = std::make_unique<Editor>(args[1]);
|
||||||
auto editor_window = std::make_unique<UIWindow>(args[0].c_str(),
|
editor->set_buffer_content(args[2]);
|
||||||
|
auto editor_window = std::make_unique<UIWindow>(args[1].c_str(),
|
||||||
200, 200, 600, 400);
|
200, 200, 600, 400);
|
||||||
editor_window->set_content(std::move(editor));
|
editor_window->set_content(std::move(editor));
|
||||||
_desktop->add_window(std::move(editor_window));
|
_desktop->add_window(std::move(editor_window));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case net_protocol::Opcode::S2C_DISCONNECT: {
|
case net_protocol::Opcode::S2C_DISCONNECT: {
|
||||||
IWindowContent* content = _desktop->get_focused_window() ?
|
if(!args.empty()) {
|
||||||
_desktop->get_focused_window()->get_content() : nullptr;
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
Terminal* terminal = dynamic_cast<Terminal*>(content);
|
UIWindow* window = _desktop->get_window_by_session_id(session_id);
|
||||||
|
if(window) {
|
||||||
if(terminal) {
|
Terminal* terminal = dynamic_cast<Terminal*>(window->get_content());
|
||||||
terminal->add_history("Connection closed.");
|
if(terminal) {
|
||||||
|
terminal->add_history("Connection closed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case net_protocol::Opcode::S2C_CLOSE_WINDOW: {
|
case net_protocol::Opcode::S2C_CLOSE_WINDOW: {
|
||||||
if(_desktop) {
|
if(!args.empty()) {
|
||||||
UIWindow* focused_window = _desktop->get_focused_window();
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
if(focused_window) { focused_window->close(); }
|
UIWindow* window = _desktop->get_window_by_session_id(session_id);
|
||||||
|
if(window) {
|
||||||
|
window->close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case net_protocol::Opcode::S2C_COMMAND_RESPONSE: {
|
case net_protocol::Opcode::S2C_COMMAND_RESPONSE: {
|
||||||
if(!args.empty()) {
|
if(args.size() == 2) {
|
||||||
IWindowContent* content = _desktop->get_focused_window() ?
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
_desktop->get_focused_window()->get_content() : nullptr;
|
UIWindow* window = _desktop->get_window_by_session_id(session_id);
|
||||||
Terminal* terminal = dynamic_cast<Terminal*>(content);
|
if(window) {
|
||||||
if(!terminal) continue;
|
Terminal* terminal = dynamic_cast<Terminal*>(window->get_content());
|
||||||
|
if(terminal) {
|
||||||
|
/* Server sends "output\nprompt", split them. */
|
||||||
|
size_t last_newline = args[1].find_last_of('\n');
|
||||||
|
if(last_newline != std::string::npos) {
|
||||||
|
std::string prompt = args[1].substr(last_newline+1);
|
||||||
|
terminal->set_prompt(prompt);
|
||||||
|
|
||||||
/* Server sends "output\nprompt", split them. */
|
std::string output = args[1].substr(0, last_newline);
|
||||||
size_t last_newline = args[0].find_last_of('\n');
|
if(!output.empty()) {
|
||||||
if(last_newline != std::string::npos) {
|
/* Split multiline output and push each line to history. */
|
||||||
std::string prompt = args[0].substr(last_newline+1);
|
std::stringstream ss(output);
|
||||||
terminal->set_prompt(prompt);
|
std::string line;
|
||||||
|
while(std::getline(ss, line, '\n')) {
|
||||||
std::string output = args[0].substr(0, last_newline);
|
terminal->add_history(line);
|
||||||
if(!output.empty()) {
|
}
|
||||||
/* Split multiline output and push each line to history. */
|
}
|
||||||
std::stringstream ss(output);
|
} else {
|
||||||
std::string line;
|
terminal->add_history(args[1]);
|
||||||
while(std::getline(ss, line, '\n')) {
|
|
||||||
terminal->add_history(line);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
terminal->add_history(args[0]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,13 +309,6 @@ void GameState::update(float dt, int draw_calls, int shape_verts, int text_verts
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameState::send_network_command(const std::string& command) {
|
|
||||||
if(_network && _network->is_connected()) {
|
|
||||||
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_COMMAND,
|
|
||||||
{command}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameState::render(const RenderContext& context) {
|
void GameState::render(const RenderContext& context) {
|
||||||
switch(_current_screen) {
|
switch(_current_screen) {
|
||||||
case Screen::MAIN_MENU:
|
case Screen::MAIN_MENU:
|
||||||
@ -311,12 +338,26 @@ void GameState::render(const RenderContext& context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameState::send_file_write_request(const std::string& path, const std::string& content) {
|
void GameState::send_network_command(uint32_t session_id, const std::string& command) {
|
||||||
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_WRITE_FILE,
|
if(_network && _network->is_connected()) {
|
||||||
{path, content}));
|
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_COMMAND,
|
||||||
|
{std::to_string(session_id), command}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameState::send_file_read_request(const std::string& path) {
|
void GameState::send_file_write_request(uint32_t session_id, const std::string& path,
|
||||||
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_READ_FILE,
|
const std::string& content) {
|
||||||
{path}));
|
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_WRITE_FILE,
|
||||||
|
{std::to_string(session_id), path, content}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameState::send_file_read_request(uint32_t session_id, const std::string& path) {
|
||||||
|
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_READ_FILE,
|
||||||
|
{std::to_string(session_id), path}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameState::send_create_session_request(void) {
|
||||||
|
if(_network && _network->is_connected()) {
|
||||||
|
_network->send(net_protocol::build_message(net_protocol::Opcode::C2S_CREATE_SESSION));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,9 +33,10 @@ public:
|
|||||||
void render(const RenderContext& context);
|
void render(const RenderContext& context);
|
||||||
|
|
||||||
/* Public network interface for UI components. */
|
/* Public network interface for UI components. */
|
||||||
void send_network_command(const std::string& command);
|
void send_network_command(uint32_t session_id, const std::string& command);
|
||||||
void send_file_write_request(const std::string& path, const std::string& content);
|
void send_file_write_request(uint32_t session_id, const std::string& path, const std::string& content);
|
||||||
void send_file_read_request(const std::string& path);
|
void send_file_read_request(uint32_t session_id, const std::string& path);
|
||||||
|
void send_create_session_request(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<ClientNetwork> _network;
|
std::unique_ptr<ClientNetwork> _network;
|
||||||
@ -49,8 +50,8 @@ private:
|
|||||||
int _screen_width;
|
int _screen_width;
|
||||||
int _screen_height;
|
int _screen_height;
|
||||||
bool _is_single_player;
|
bool _is_single_player;
|
||||||
|
uint32_t _initial_session_id;
|
||||||
|
|
||||||
void _init_desktop(void);
|
void _init_desktop(void);
|
||||||
void _send_network_command(const std::string& command);
|
|
||||||
void _run_server(void);
|
void _run_server(void);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
Terminal::Terminal(GameState* game_state)
|
Terminal::Terminal(GameState* game_state)
|
||||||
: _game_state(game_state), _should_close(false), _command_history_index(0),
|
: _game_state(game_state), _should_close(false), _command_history_index(0),
|
||||||
_scroll_offset(0), _prompt(""), _pending_action({ActionType::NONE}) {
|
_scroll_offset(0), _prompt(""), _pending_action({ActionType::NONE}),
|
||||||
|
_session_id(0) {
|
||||||
_input_view = std::make_unique<TextView>(&_input_buffer, false, false);
|
_input_view = std::make_unique<TextView>(&_input_buffer, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,6 +53,14 @@ WindowAction Terminal::get_pending_action(void) {
|
|||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Terminal::set_session_id(uint32_t id) {
|
||||||
|
_session_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Terminal::get_session_id(void) const {
|
||||||
|
return _session_id;
|
||||||
|
}
|
||||||
|
|
||||||
void Terminal::_on_ret_press(void) {
|
void Terminal::_on_ret_press(void) {
|
||||||
std::string command = _input_buffer.get_line(0);
|
std::string command = _input_buffer.get_line(0);
|
||||||
if(!command.empty()) {
|
if(!command.empty()) {
|
||||||
@ -79,7 +88,7 @@ void Terminal::_on_ret_press(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_history.push_back(_prompt + "> " + command);
|
_history.push_back(_prompt + "> " + command);
|
||||||
_game_state->send_network_command(command);
|
_game_state->send_network_command(_session_id, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
void Terminal::handle_input(SDL_Event* event, int window_x, int window_y, int window_gl_y) {
|
||||||
|
|||||||
@ -26,6 +26,8 @@ public:
|
|||||||
void set_prompt(const std::string& prompt);
|
void set_prompt(const std::string& prompt);
|
||||||
bool should_close(void) override;
|
bool should_close(void) override;
|
||||||
WindowAction get_pending_action(void) override;
|
WindowAction get_pending_action(void) override;
|
||||||
|
void set_session_id(uint32_t id);
|
||||||
|
uint32_t get_session_id(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _on_ret_press(void);
|
void _on_ret_press(void);
|
||||||
@ -39,5 +41,6 @@ private:
|
|||||||
GameState* _game_state;
|
GameState* _game_state;
|
||||||
TextBuffer _input_buffer;
|
TextBuffer _input_buffer;
|
||||||
WindowAction _pending_action;
|
WindowAction _pending_action;
|
||||||
|
uint32_t _session_id;
|
||||||
std::unique_ptr<TextView> _input_view;
|
std::unique_ptr<TextView> _input_view;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -30,6 +30,7 @@ Desktop::Desktop(int screen_width, int screen_height, GameState* game_state) {
|
|||||||
_taskbar = std::make_unique<Taskbar>(screen_width, screen_height);
|
_taskbar = std::make_unique<Taskbar>(screen_width, screen_height);
|
||||||
_game_state= game_state;
|
_game_state= game_state;
|
||||||
_focused_window = nullptr;
|
_focused_window = nullptr;
|
||||||
|
_window_awaiting_session_id = nullptr;
|
||||||
_launcher_is_open = false;
|
_launcher_is_open = false;
|
||||||
_launcher = std::make_unique<Launcher>(5, 0, 200); /* Tmp y-coord. */
|
_launcher = std::make_unique<Launcher>(5, 0, 200); /* Tmp y-coord. */
|
||||||
int launcher_y = screen_height - _taskbar->get_height() - _launcher->get_height();
|
int launcher_y = screen_height - _taskbar->get_height() - _launcher->get_height();
|
||||||
@ -135,9 +136,11 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height
|
|||||||
if(app_to_launch == "Terminal") {
|
if(app_to_launch == "Terminal") {
|
||||||
auto term = std::make_unique<Terminal>(_game_state);
|
auto term = std::make_unique<Terminal>(_game_state);
|
||||||
auto term_window = std::make_unique<UIWindow>("Terminal", 150, 150, 800, 500);
|
auto term_window = std::make_unique<UIWindow>("Terminal", 150, 150, 800, 500);
|
||||||
|
_window_awaiting_session_id = term_window.get();
|
||||||
term_window->set_content(std::move(term));
|
term_window->set_content(std::move(term));
|
||||||
add_window(std::move(term_window));
|
add_window(std::move(term_window));
|
||||||
_launcher_is_open = false;
|
_launcher_is_open = false;
|
||||||
|
_game_state->send_create_session_request();
|
||||||
} else if(app_to_launch == "Editor") {
|
} else if(app_to_launch == "Editor") {
|
||||||
auto editor = std::make_unique<Editor>();
|
auto editor = std::make_unique<Editor>();
|
||||||
auto editor_window = std::make_unique<UIWindow>("Editor", 200, 200, 600, 400);
|
auto editor_window = std::make_unique<UIWindow>("Editor", 200, 200, 600, 400);
|
||||||
@ -180,13 +183,21 @@ void Desktop::update(float dt, int screen_width, int screen_height) {
|
|||||||
IWindowContent* content = _focused_window->get_content();
|
IWindowContent* content = _focused_window->get_content();
|
||||||
if(content) {
|
if(content) {
|
||||||
WindowAction action = content->get_pending_action();
|
WindowAction action = content->get_pending_action();
|
||||||
|
uint32_t session_id = 0;
|
||||||
|
if(auto term = dynamic_cast<Terminal*>(content)) {
|
||||||
|
session_id = term->get_session_id();
|
||||||
|
}
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case ActionType::WRITE_FILE: {
|
case ActionType::WRITE_FILE: {
|
||||||
_game_state->send_file_write_request(action.payload1, action.payload2);
|
if(session_id != 0) {
|
||||||
|
_game_state->send_file_write_request(session_id, action.payload1, action.payload2);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ActionType::READ_FILE: {
|
case ActionType::READ_FILE: {
|
||||||
_game_state->send_file_read_request(action.payload1);
|
if(session_id != 0) {
|
||||||
|
_game_state->send_file_read_request(session_id, action.payload1);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -203,6 +214,16 @@ void Desktop::update(float dt, int screen_width, int screen_height) {
|
|||||||
_windows.erase(std::remove_if(_windows.begin(), _windows.end(),
|
_windows.erase(std::remove_if(_windows.begin(), _windows.end(),
|
||||||
[this](const std::unique_ptr<UIWindow>& w) {
|
[this](const std::unique_ptr<UIWindow>& w) {
|
||||||
if (w->should_close()) {
|
if (w->should_close()) {
|
||||||
|
/* Also remove from session map. */
|
||||||
|
uint32_t session_to_remove = 0;
|
||||||
|
for(auto const& [sid, win] : _session_windows) {
|
||||||
|
if(win == w.get()) {
|
||||||
|
session_to_remove = sid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(session_to_remove != 0)
|
||||||
|
_session_windows.erase(session_to_remove);
|
||||||
_taskbar->remove_window(w.get());
|
_taskbar->remove_window(w.get());
|
||||||
if (w.get() == _focused_window) {
|
if (w.get() == _focused_window) {
|
||||||
_focused_window = nullptr;
|
_focused_window = nullptr;
|
||||||
@ -214,10 +235,28 @@ void Desktop::update(float dt, int screen_width, int screen_height) {
|
|||||||
_windows.end());
|
_windows.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Desktop::register_session(uint32_t session_id, UIWindow* window) {
|
||||||
|
_session_windows[session_id] = window;
|
||||||
|
if(_window_awaiting_session_id == window) {
|
||||||
|
_window_awaiting_session_id = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UIWindow* Desktop::get_window_by_session_id(uint32_t session_id) {
|
||||||
|
if(_session_windows.count(session_id)) {
|
||||||
|
return _session_windows.at(session_id);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
UIWindow* Desktop::get_focused_window(void) {
|
UIWindow* Desktop::get_focused_window(void) {
|
||||||
return _focused_window;
|
return _focused_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UIWindow* Desktop::get_window_awaiting_session_id(void) {
|
||||||
|
return _window_awaiting_session_id;
|
||||||
|
}
|
||||||
|
|
||||||
void Desktop::render(const RenderContext& context) {
|
void Desktop::render(const RenderContext& context) {
|
||||||
/* Pass 1: Background. */
|
/* Pass 1: Background. */
|
||||||
context.ui_renderer->begin_text();
|
context.ui_renderer->begin_text();
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
#include "gfx/types.h"
|
#include "gfx/types.h"
|
||||||
@ -31,7 +32,10 @@ public:
|
|||||||
void update(float dt, int screen_width, int screen_height);
|
void update(float dt, int screen_width, int screen_height);
|
||||||
void render(const RenderContext& context);
|
void render(const RenderContext& context);
|
||||||
|
|
||||||
|
void register_session(uint32_t session_id, UIWindow* window);
|
||||||
|
UIWindow* get_window_by_session_id(uint32_t session_id);
|
||||||
UIWindow* get_focused_window(void);
|
UIWindow* get_focused_window(void);
|
||||||
|
UIWindow* get_window_awaiting_session_id(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _set_focused_window(UIWindow* window);
|
void _set_focused_window(UIWindow* window);
|
||||||
@ -39,11 +43,13 @@ private:
|
|||||||
void _update_wallpaper(float dt, int screen_width, int screen_height);
|
void _update_wallpaper(float dt, int screen_width, int screen_height);
|
||||||
|
|
||||||
std::vector<std::unique_ptr<UIWindow>> _windows;
|
std::vector<std::unique_ptr<UIWindow>> _windows;
|
||||||
std::unique_ptr<Taskbar> _taskbar;
|
std::unique_ptr<Taskbar> _taskbar;
|
||||||
std::unique_ptr<Launcher> _launcher;
|
std::unique_ptr<Launcher> _launcher;
|
||||||
UIWindow* _focused_window;
|
UIWindow* _focused_window;
|
||||||
GameState* _game_state;
|
UIWindow* _window_awaiting_session_id;
|
||||||
std::vector<ScrollingText> _background_text;
|
std::map<uint32_t, UIWindow*> _session_windows;
|
||||||
std::vector<std::string> _snippets;
|
GameState* _game_state;
|
||||||
bool _launcher_is_open;
|
std::vector<ScrollingText> _background_text;
|
||||||
|
std::vector<std::string> _snippets;
|
||||||
|
bool _launcher_is_open;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,17 +4,17 @@
|
|||||||
|
|
||||||
#include "i_network_bridge.h"
|
#include "i_network_bridge.h"
|
||||||
#include "lua_api.h"
|
#include "lua_api.h"
|
||||||
#include "command_processor.h"
|
#include "session.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
vfs_node* get_current_dir(CommandProcessor& context) {
|
vfs_node* get_current_dir(Session& context) {
|
||||||
return context.get_current_dir();
|
return context.get_current_dir();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string rm(CommandProcessor& context, const std::string& filename) {
|
std::string rm(Session& context, const std::string& filename) {
|
||||||
vfs_node* current_dir = context.get_current_dir();
|
vfs_node* current_dir = context.get_current_dir();
|
||||||
auto it = current_dir->children.find(filename);
|
auto it = current_dir->children.find(filename);
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ std::string rm(CommandProcessor& context, const std::string& filename) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string write_file(CommandProcessor& context, const std::string& filename,
|
std::string write_file(Session& context, const std::string& filename,
|
||||||
const std::string& content) {
|
const std::string& content) {
|
||||||
vfs_node* current_dir = context.get_current_dir();
|
vfs_node* current_dir = context.get_current_dir();
|
||||||
auto it = current_dir->children.find(filename);
|
auto it = current_dir->children.find(filename);
|
||||||
@ -50,7 +50,7 @@ std::string write_file(CommandProcessor& context, const std::string& filename,
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string cd(CommandProcessor& context, const std::string& path) {
|
std::string cd(Session& context, const std::string& path) {
|
||||||
vfs_node* current_dir = context.get_current_dir();
|
vfs_node* current_dir = context.get_current_dir();
|
||||||
|
|
||||||
if(path == "..") {
|
if(path == "..") {
|
||||||
@ -68,7 +68,7 @@ std::string cd(CommandProcessor& context, const std::string& path) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ls(CommandProcessor& context) {
|
std::string ls(Session& context) {
|
||||||
vfs_node* dir = context.get_current_dir();
|
vfs_node* dir = context.get_current_dir();
|
||||||
if(dir->type != DIR_NODE) {
|
if(dir->type != DIR_NODE) {
|
||||||
return "ls: not a directory";
|
return "ls: not a directory";
|
||||||
@ -85,7 +85,7 @@ std::string ls(CommandProcessor& context) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ssh(CommandProcessor& context, const std::string& ip) {
|
std::string ssh(Session& context, const std::string& ip) {
|
||||||
INetworkBridge* bridge = context.get_network_bridge();
|
INetworkBridge* bridge = context.get_network_bridge();
|
||||||
Machine* target_machine = bridge->get_machine_by_ip(ip);
|
Machine* target_machine = bridge->get_machine_by_ip(ip);
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ std::string ssh(CommandProcessor& context, const std::string& ip) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string nmap(CommandProcessor& context, const std::string& ip) {
|
std::string nmap(Session& context, const std::string& ip) {
|
||||||
long long machine_id = context.get_machine_manager()->get_machine_id_by_ip(ip);
|
long long machine_id = context.get_machine_manager()->get_machine_id_by_ip(ip);
|
||||||
if(machine_id == 0) {
|
if(machine_id == 0) {
|
||||||
return "nmap: Could not resolve host: " + ip;
|
return "nmap: Could not resolve host: " + ip;
|
||||||
@ -117,7 +117,7 @@ std::string nmap(CommandProcessor& context, const std::string& ip) {
|
|||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string disconnect(CommandProcessor& context) {
|
std::string disconnect(Session& context) {
|
||||||
Machine* current_machine = context.get_session_machine();
|
Machine* current_machine = context.get_session_machine();
|
||||||
if(current_machine != context.get_home_machine()) {
|
if(current_machine != context.get_home_machine()) {
|
||||||
INetworkBridge* bridge = context.get_network_bridge();
|
INetworkBridge* bridge = context.get_network_bridge();
|
||||||
@ -127,7 +127,7 @@ std::string disconnect(CommandProcessor& context) {
|
|||||||
return "Connection closed.";
|
return "Connection closed.";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string close_terminal(CommandProcessor& context) {
|
std::string close_terminal(Session& context) {
|
||||||
return "__CLOSE_CONNECTION__";
|
return "__CLOSE_CONNECTION__";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ ScpPath parse_scp_path(const std::string& arg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string scp(CommandProcessor& context, const std::string& source_arg,
|
std::string scp(Session& context, const std::string& source_arg,
|
||||||
const std::string& dest_arg) {
|
const std::string& dest_arg) {
|
||||||
ScpPath source_path = parse_scp_path(source_arg);
|
ScpPath source_path = parse_scp_path(source_arg);
|
||||||
ScpPath dest_path = parse_scp_path(dest_arg);
|
ScpPath dest_path = parse_scp_path(dest_arg);
|
||||||
|
|||||||
@ -3,27 +3,27 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
class CommandProcessor;
|
class Session;
|
||||||
class NetworkManager;
|
class NetworkManager;
|
||||||
|
|
||||||
namespace api {
|
namespace api {
|
||||||
|
|
||||||
/* FILESYSTEM ACTIONS. */
|
/* FILESYSTEM ACTIONS. */
|
||||||
vfs_node* get_current_dir(CommandProcessor& context);
|
vfs_node* get_current_dir(Session& context);
|
||||||
std::string rm(CommandProcessor& context, const std::string& filename);
|
std::string rm(Session& context, const std::string& filename);
|
||||||
std::string write_file(CommandProcessor& context, const std::string& filename,
|
std::string write_file(Session& context, const std::string& filename,
|
||||||
const std::string& content);
|
const std::string& content);
|
||||||
std::string ls(CommandProcessor& context);
|
std::string ls(Session& context);
|
||||||
std::string cd(CommandProcessor& context, const std::string& path);
|
std::string cd(Session& context, const std::string& path);
|
||||||
std::string scp(CommandProcessor& context, const std::string& source,
|
std::string scp(Session& context, const std::string& source,
|
||||||
const std::string& destination);
|
const std::string& destination);
|
||||||
|
|
||||||
/* NETWORK ACTIONS. */
|
/* NETWORK ACTIONS. */
|
||||||
std::string ssh(CommandProcessor& context, const std::string& ip);
|
std::string ssh(Session& context, const std::string& ip);
|
||||||
std::string nmap(CommandProcessor& context, const std::string& ip);
|
std::string nmap(Session& context, const std::string& ip);
|
||||||
std::string disconnect(CommandProcessor& context);
|
std::string disconnect(Session& context);
|
||||||
|
|
||||||
/* SYSTEM ACTIONS. */
|
/* SYSTEM ACTIONS. */
|
||||||
std::string close_terminal(CommandProcessor& context);
|
std::string close_terminal(Session& context);
|
||||||
|
|
||||||
} /* namespace api */
|
} /* namespace api */
|
||||||
|
|||||||
@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
#include "lua_processor.h"
|
#include "lua_processor.h"
|
||||||
#include "lua_api.h"
|
#include "lua_api.h"
|
||||||
#include "command_processor.h"
|
#include "session.h"
|
||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
|
|
||||||
LuaProcessor::LuaProcessor(CommandProcessor& context) {
|
LuaProcessor::LuaProcessor(Session& context) {
|
||||||
_lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::io, sol::lib::table);
|
_lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::io, sol::lib::table);
|
||||||
|
|
||||||
/* Expose vfs_node struct members to Lua. */
|
/* Expose vfs_node struct members to Lua. */
|
||||||
@ -19,7 +19,7 @@ LuaProcessor::LuaProcessor(CommandProcessor& context) {
|
|||||||
"content", &vfs_node::content);
|
"content", &vfs_node::content);
|
||||||
|
|
||||||
/* Expose CommandProcessor to Lua. DON'T ALLOW SCRIPTS TO CREATE IT THOUGH! */
|
/* Expose CommandProcessor to Lua. DON'T ALLOW SCRIPTS TO CREATE IT THOUGH! */
|
||||||
_lua.new_usertype<CommandProcessor>("CommandProcessor", sol::no_constructor);
|
_lua.new_usertype<Session>("Session", sol::no_constructor);
|
||||||
|
|
||||||
/* Create the 'bettola' API table. */
|
/* Create the 'bettola' API table. */
|
||||||
sol::table bettola_api = _lua.create_named_table("bettola");
|
sol::table bettola_api = _lua.create_named_table("bettola");
|
||||||
@ -37,7 +37,7 @@ LuaProcessor::LuaProcessor(CommandProcessor& context) {
|
|||||||
|
|
||||||
LuaProcessor::~LuaProcessor(void) {}
|
LuaProcessor::~LuaProcessor(void) {}
|
||||||
|
|
||||||
sol::object LuaProcessor::execute(const std::string& script, CommandProcessor& context,
|
sol::object LuaProcessor::execute(const std::string& script, Session& context,
|
||||||
const std::vector<std::string>& args, bool is_remote) {
|
const std::vector<std::string>& args, bool is_remote) {
|
||||||
try {
|
try {
|
||||||
/* Pass C++ objects/points into the Lua env. */
|
/* Pass C++ objects/points into the Lua env. */
|
||||||
|
|||||||
@ -5,15 +5,15 @@
|
|||||||
#include <vfs.h>
|
#include <vfs.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class CommandProcessor;
|
class Session;
|
||||||
|
|
||||||
class LuaProcessor {
|
class LuaProcessor {
|
||||||
public:
|
public:
|
||||||
LuaProcessor(CommandProcessor& context);
|
LuaProcessor(Session& context);
|
||||||
~LuaProcessor(void);
|
~LuaProcessor(void);
|
||||||
|
|
||||||
/* Executes a string of lua code and returns result as a string. */
|
/* Executes a string of lua code and returns result as a string. */
|
||||||
sol::object execute(const std::string& script, CommandProcessor& context,
|
sol::object execute(const std::string& script, Session& context,
|
||||||
const std::vector<std::string>& args, bool is_remote);
|
const std::vector<std::string>& args, bool is_remote);
|
||||||
private:
|
private:
|
||||||
sol::state _lua;
|
sol::state _lua;
|
||||||
|
|||||||
@ -16,19 +16,21 @@ enum class Opcode : uint8_t {
|
|||||||
/* Client -> Server messages. */
|
/* Client -> Server messages. */
|
||||||
C2S_CREATE_ACCOUNT,
|
C2S_CREATE_ACCOUNT,
|
||||||
C2S_LOGIN,
|
C2S_LOGIN,
|
||||||
C2S_COMMAND,
|
C2S_CREATE_SESSION,
|
||||||
C2S_WRITE_FILE,
|
C2S_COMMAND, /* args: [session_id, command] */
|
||||||
C2S_READ_FILE,
|
C2S_WRITE_FILE, /* args: [session_id, path, content] */
|
||||||
|
C2S_READ_FILE, /* args: [session_id, path] */
|
||||||
|
|
||||||
/* Server -> Client messages. */
|
/* Server -> Client messages. */
|
||||||
S2C_CREATE_ACCOUNT_SUCCESS,
|
S2C_CREATE_ACCOUNT_SUCCESS,
|
||||||
S2C_CREATE_ACCOUNT_FAIL,
|
S2C_CREATE_ACCOUNT_FAIL,
|
||||||
S2C_LOGIN_SUCCESS,
|
S2C_LOGIN_SUCCESS,
|
||||||
S2C_LOGIN_FAIL,
|
S2C_LOGIN_FAIL,
|
||||||
S2C_COMMAND_RESPONSE,
|
S2C_SESSION_CREATED, /* args: [session_id] */
|
||||||
S2C_FILE_DATA,
|
S2C_COMMAND_RESPONSE, /* args: [session_id, response] */
|
||||||
S2C_DISCONNECT,
|
S2C_FILE_DATA, /* args: [session_id, path, content] */
|
||||||
S2C_CLOSE_WINDOW,
|
S2C_DISCONNECT, /* args: [session_id] */
|
||||||
|
S2C_CLOSE_WINDOW, /* args: [session_id] */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include <sol/types.hpp>
|
#include <sol/types.hpp>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "command_processor.h"
|
#include "session.h"
|
||||||
#include "db/database_manager.h"
|
#include "db/database_manager.h"
|
||||||
#include "i_network_bridge.h"
|
#include "i_network_bridge.h"
|
||||||
#include "lua_api.h"
|
#include "lua_api.h"
|
||||||
@ -22,10 +22,10 @@ vfs_node* find_node_by_id(vfs_node* root, long long id) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandProcessor::CommandProcessor(Machine* home_machine,
|
Session::Session(Machine* home_machine,
|
||||||
DatabaseManager* db_manager,
|
DatabaseManager* db_manager,
|
||||||
MachineManager* machine_manager,
|
MachineManager* machine_manager,
|
||||||
INetworkBridge* network_bridge) :
|
INetworkBridge* network_bridge) :
|
||||||
_machine_manager(machine_manager),
|
_machine_manager(machine_manager),
|
||||||
_db_manager(db_manager),
|
_db_manager(db_manager),
|
||||||
_network_bridge(network_bridge),
|
_network_bridge(network_bridge),
|
||||||
@ -35,40 +35,40 @@ CommandProcessor::CommandProcessor(Machine* home_machine,
|
|||||||
if(home_machine) _current_dir = home_machine->vfs_root;
|
if(home_machine) _current_dir = home_machine->vfs_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandProcessor::~CommandProcessor(void) {
|
Session::~Session(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
vfs_node* CommandProcessor::get_current_dir(void) {
|
vfs_node* Session::get_current_dir(void) {
|
||||||
return _current_dir;
|
return _current_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
Machine* CommandProcessor::get_home_machine(void) { return _home_machine; }
|
Machine* Session::get_home_machine(void) { return _home_machine; }
|
||||||
Machine* CommandProcessor::get_session_machine(void) { return _session_machine; }
|
Machine* Session::get_session_machine(void) { return _session_machine; }
|
||||||
|
|
||||||
DatabaseManager* CommandProcessor::get_db_manager(void) {
|
DatabaseManager* Session::get_db_manager(void) {
|
||||||
return _db_manager;
|
return _db_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
MachineManager* CommandProcessor::get_machine_manager(void) {
|
MachineManager* Session::get_machine_manager(void) {
|
||||||
return _machine_manager;
|
return _machine_manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
INetworkBridge* CommandProcessor::get_network_bridge(void) {
|
INetworkBridge* Session::get_network_bridge(void) {
|
||||||
return _network_bridge;
|
return _network_bridge;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::set_current_dir(vfs_node* node) {
|
void Session::set_current_dir(vfs_node* node) {
|
||||||
_current_dir = node;
|
_current_dir = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CommandProcessor::set_session_machine(Machine* machine) {
|
void Session::set_session_machine(Machine* machine) {
|
||||||
_session_machine = machine;
|
_session_machine = machine;
|
||||||
if(_session_machine) {
|
if(_session_machine) {
|
||||||
_current_dir = _session_machine->vfs_root;
|
_current_dir = _session_machine->vfs_root;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CommandProcessor::process_command(const std::string& command) {
|
std::string Session::process_command(const std::string& command) {
|
||||||
/*
|
/*
|
||||||
* Creating the Lua processor on-demand to ensure it exists on the same
|
* Creating the Lua processor on-demand to ensure it exists on the same
|
||||||
* thread that will execute the script.
|
* thread that will execute the script.
|
||||||
@ -113,11 +113,11 @@ std::string CommandProcessor::process_command(const std::string& command) {
|
|||||||
return "Unknown command: " + command_name + "\n";
|
return "Unknown command: " + command_name + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CommandProcessor::write_file(const std::string& path, const std::string& content) {
|
std::string Session::write_file(const std::string& path, const std::string& content) {
|
||||||
return api::write_file(*this, path, content);
|
return api::write_file(*this, path, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string CommandProcessor::read_file(const std::string& path) {
|
std::string Session::read_file(const std::string& path) {
|
||||||
vfs_node* root = get_session_machine()->vfs_root;
|
vfs_node* root = get_session_machine()->vfs_root;
|
||||||
vfs_node* node = find_node_by_path(root, path);
|
vfs_node* node = find_node_by_path(root, path);
|
||||||
if(node && node->type == FILE_NODE) {
|
if(node && node->type == FILE_NODE) {
|
||||||
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
class LuaProcessor;
|
class LuaProcessor;
|
||||||
|
|
||||||
class CommandProcessor {
|
class Session {
|
||||||
public:
|
public:
|
||||||
CommandProcessor(Machine* home_machine, DatabaseManager* db_manager,
|
Session(Machine* home_machine, DatabaseManager* db_manager,
|
||||||
MachineManager* machine_manager, INetworkBridge* network_bridge);
|
MachineManager* machine_manager, INetworkBridge* network_bridge);
|
||||||
~CommandProcessor(void);
|
~Session(void);
|
||||||
|
|
||||||
std::string process_command(const std::string& command);
|
std::string process_command(const std::string& command);
|
||||||
std::string write_file(const std::string& path, const std::string& content);
|
std::string write_file(const std::string& path, const std::string& content);
|
||||||
@ -2,6 +2,7 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "network_manager.h"
|
#include "network_manager.h"
|
||||||
#include "net/message_protocol.h"
|
#include "net/message_protocol.h"
|
||||||
@ -9,7 +10,7 @@
|
|||||||
|
|
||||||
#include "asio/error_code.hpp"
|
#include "asio/error_code.hpp"
|
||||||
#include "asio/ip/tcp.hpp"
|
#include "asio/ip/tcp.hpp"
|
||||||
#include "command_processor.h"
|
#include "session.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "net/tcp_connection.h"
|
#include "net/tcp_connection.h"
|
||||||
@ -112,37 +113,42 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
|||||||
if(args.size() == 3) {
|
if(args.size() == 3) {
|
||||||
if(_db_manager->create_player(args[0], args[1], args[2],
|
if(_db_manager->create_player(args[0], args[1], args[2],
|
||||||
_machine_manager.get_vfs_template())) {
|
_machine_manager.get_vfs_template())) {
|
||||||
long long home_machine_id = _db_manager->players().get_home_machine_id(args[0]);
|
long long home_machine_id = _db_manager->players().get_home_machine_id(args[0]);
|
||||||
Machine* home_machine = _get_or_load_machine(home_machine_id);
|
Machine* home_machine = _get_or_load_machine(home_machine_id);
|
||||||
delete player->cmd_processor; /* Delete old command processor. */
|
player->state = PlayerState::ACTIVE;
|
||||||
player->cmd_processor = new CommandProcessor(home_machine, _db_manager.get(),
|
|
||||||
&_machine_manager, this);
|
/* Create first session for player. */
|
||||||
player->state = PlayerState::ACTIVE;
|
uint32_t session_id = _next_session_id++;
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_CREATE_ACCOUNT_SUCCESS));
|
player->sessions[session_id] = std::make_unique<Session>(home_machine,
|
||||||
/* send initial prompt. */
|
_db_manager.get(),
|
||||||
std::string prompt = "\n" + get_full_path(player->cmd_processor->get_current_dir());
|
&_machine_manager, this);
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_COMMAND_RESPONSE,
|
|
||||||
{prompt}));
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_CREATE_ACCOUNT_SUCCESS));
|
||||||
} else {
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_SESSION_CREATED,
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_CREATE_ACCOUNT_FAIL,
|
{std::to_string(session_id)}));
|
||||||
{"Username already exists."}));
|
} else {
|
||||||
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_CREATE_ACCOUNT_FAIL,
|
||||||
|
{"Username already exists."}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
case net_protocol::Opcode::C2S_LOGIN:
|
case net_protocol::Opcode::C2S_LOGIN:
|
||||||
if(args.size() == 2) {
|
if(args.size() == 2) {
|
||||||
if(_db_manager->players().authenticate(args[0], args[1])) {
|
if(_db_manager->players().authenticate(args[0], args[1])) {
|
||||||
long long home_machine_id = _db_manager->players().get_home_machine_id(args[0]);
|
long long home_machine_id = _db_manager->players().get_home_machine_id(args[0]);
|
||||||
Machine* home_machine = _get_or_load_machine(home_machine_id);
|
Machine* home_machine = _get_or_load_machine(home_machine_id);
|
||||||
delete player->cmd_processor; /* Delete old command processor. */
|
|
||||||
player->cmd_processor = new CommandProcessor(home_machine, _db_manager.get(),
|
|
||||||
&_machine_manager, this);
|
|
||||||
player->state = PlayerState::ACTIVE;
|
player->state = PlayerState::ACTIVE;
|
||||||
|
|
||||||
|
/* Create first session for player. */
|
||||||
|
uint32_t session_id = _next_session_id++;
|
||||||
|
player->sessions[session_id] = std::make_unique<Session>(home_machine,
|
||||||
|
_db_manager.get(),
|
||||||
|
&_machine_manager, this);
|
||||||
|
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_LOGIN_SUCCESS));
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_LOGIN_SUCCESS));
|
||||||
/* Send initial prompt. */
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_SESSION_CREATED,
|
||||||
std::string prompt = "\n" + get_full_path(player->cmd_processor->get_current_dir());
|
{std::to_string(session_id)}));
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_COMMAND_RESPONSE,
|
|
||||||
{prompt}));
|
|
||||||
} else {
|
} else {
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_LOGIN_FAIL,
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_LOGIN_FAIL,
|
||||||
{"Invalid username or password."}));
|
{"Invalid username or password."}));
|
||||||
@ -159,36 +165,49 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
|||||||
/* === PLAYER BECOMES ACTIVE HERE === */
|
/* === PLAYER BECOMES ACTIVE HERE === */
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
|
case net_protocol::Opcode::C2S_CREATE_SESSION: {
|
||||||
|
uint32_t session_id = _next_session_id++;
|
||||||
|
/* Find player's home machine to init the session. */
|
||||||
|
Machine* home_machine = nullptr;
|
||||||
|
if(!player->sessions.empty()) {
|
||||||
|
home_machine = player->sessions.begin()->second->get_home_machine();
|
||||||
|
}
|
||||||
|
player->sessions[session_id] = std::make_unique<Session>(home_machine,
|
||||||
|
_db_manager.get(),
|
||||||
|
&_machine_manager, this);
|
||||||
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_SESSION_CREATED,
|
||||||
|
{std::to_string(session_id)}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
case net_protocol::Opcode::C2S_WRITE_FILE:
|
case net_protocol::Opcode::C2S_WRITE_FILE:
|
||||||
if(args.size() == 2) {
|
if(args.size() == 3) {
|
||||||
fprintf(stderr, "[Player %u] Write file: '%s'\n", player->id, args[0].c_str());
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
player->cmd_processor->write_file(args[0], args[1]);
|
if(player->sessions.count(session_id)) {
|
||||||
/* Response not required for a file write. */
|
player->sessions.at(session_id)->write_file(args[1], args[2]);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
case net_protocol::Opcode::C2S_READ_FILE:
|
case net_protocol::Opcode::C2S_READ_FILE:
|
||||||
if(!args.empty()) {
|
if(args.size() == 2) {
|
||||||
fprintf(stderr, "[Player %u] Read file: '%s'\n", player->id, args[0].c_str());
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
std::string content = player->cmd_processor->read_file(args[0]);
|
if(player->sessions.count(session_id)) {
|
||||||
/* Send the content back to the client. */
|
std::string content = player->sessions.at(session_id)->read_file(args[1]);
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_FILE_DATA,
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_FILE_DATA,
|
||||||
{args[0], content}));
|
{args[0], args[1], content}));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case net_protocol::Opcode::C2S_COMMAND:
|
case net_protocol::Opcode::C2S_COMMAND:
|
||||||
if(!args.empty()) {
|
if(args.size() == 2) {
|
||||||
fprintf(stderr, "[Player %u] Command: '%s'\n", player->id, args[0].c_str());
|
uint32_t session_id = std::stoul(args[0]);
|
||||||
std::string response = player->cmd_processor->process_command(args[0]);
|
if(player->sessions.count(session_id)) {
|
||||||
|
Session* session = player->sessions.at(session_id).get();
|
||||||
if(response == "__CLOSE_CONNECTION__") {
|
std::string response = session->process_command(args[1]);
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_CLOSE_WINDOW));
|
std::string new_prompt = get_full_path(session->get_current_dir());
|
||||||
return;
|
response += "\n" + new_prompt;
|
||||||
|
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_COMMAND_RESPONSE,
|
||||||
|
{args[0], response}));
|
||||||
}
|
}
|
||||||
std::string new_prompt = get_full_path(player->cmd_processor->get_current_dir());
|
|
||||||
response += "\n" + new_prompt;
|
|
||||||
|
|
||||||
connection->send(net_protocol::build_message(net_protocol::Opcode::S2C_COMMAND_RESPONSE,
|
|
||||||
{response}));
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -202,15 +221,14 @@ void NetworkManager::on_disconnect(std::shared_ptr<net::TcpConnection> connectio
|
|||||||
uint32_t player_id = connection->get_id();
|
uint32_t player_id = connection->get_id();
|
||||||
Player* player = _players[player_id].get();
|
Player* player = _players[player_id].get();
|
||||||
|
|
||||||
if(player && player->cmd_processor) {
|
if(player) {
|
||||||
Machine* home_machine = player->cmd_processor->get_home_machine();
|
for(auto const& [session_id, session] : player->sessions) {
|
||||||
Machine* session_machine = player->cmd_processor->get_session_machine();
|
Machine* home_machine = session->get_home_machine();
|
||||||
|
Machine* session_machine = session->get_session_machine();
|
||||||
if(home_machine) {
|
if(home_machine) { release_machine(home_machine->id); }
|
||||||
release_machine(home_machine->id);
|
if(session_machine && session_machine != home_machine) {
|
||||||
}
|
release_machine(session_machine->id);
|
||||||
if(session_machine && session_machine != home_machine) {
|
}
|
||||||
release_machine(session_machine->id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,8 @@ private:
|
|||||||
std::deque<std::shared_ptr<net::TcpConnection>> _connections;
|
std::deque<std::shared_ptr<net::TcpConnection>> _connections;
|
||||||
std::unordered_map<uint32_t, std::unique_ptr<Player>> _players;
|
std::unordered_map<uint32_t, std::unique_ptr<Player>> _players;
|
||||||
std::map<long long, CachedMachine> _active_machines;
|
std::map<long long, CachedMachine> _active_machines;
|
||||||
uint32_t _next_player_id = 1;
|
uint32_t _next_player_id = 1;
|
||||||
|
uint32_t _next_session_id = 1;
|
||||||
|
|
||||||
std::unique_ptr<DatabaseManager> _db_manager;
|
std::unique_ptr<DatabaseManager> _db_manager;
|
||||||
MachineManager _machine_manager;
|
MachineManager _machine_manager;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "command_processor.h"
|
#include "session.h"
|
||||||
#include "db/database_manager.h"
|
#include "db/database_manager.h"
|
||||||
#include "i_network_bridge.h"
|
#include "i_network_bridge.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
@ -9,12 +9,6 @@ Player::Player(uint32_t new_id, Machine* home_machine,
|
|||||||
MachineManager* machine_manager,
|
MachineManager* machine_manager,
|
||||||
INetworkBridge* network_bridge) :
|
INetworkBridge* network_bridge) :
|
||||||
id(new_id),
|
id(new_id),
|
||||||
state(PlayerState::AUTHENTICATING) {
|
state(PlayerState::AUTHENTICATING) {}
|
||||||
|
|
||||||
cmd_processor = new CommandProcessor(home_machine, db_manager, machine_manager,
|
Player::~Player(void) {}
|
||||||
network_bridge);
|
|
||||||
}
|
|
||||||
|
|
||||||
Player::~Player(void) {
|
|
||||||
delete cmd_processor;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "db/database_manager.h"
|
#include "db/database_manager.h"
|
||||||
#include "command_processor.h"
|
#include "session.h"
|
||||||
#include "i_network_bridge.h"
|
#include "i_network_bridge.h"
|
||||||
#include "machine.h"
|
#include "machine.h"
|
||||||
#include "machine_manager.h"
|
#include "machine_manager.h"
|
||||||
@ -21,5 +23,7 @@ public:
|
|||||||
|
|
||||||
uint32_t id;
|
uint32_t id;
|
||||||
PlayerState state;
|
PlayerState state;
|
||||||
CommandProcessor* cmd_processor; /* Manages the VFS state for the remote session. */
|
|
||||||
|
/* Map of session IDs to their respective session objects. */
|
||||||
|
std::unordered_map<uint32_t, std::unique_ptr<Session>> sessions;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user