[Add] File loading and fix local 'exit' command.
This commit is contained in:
parent
ebd1e222d7
commit
666b4f554b
@ -4,7 +4,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include "../../server/src/network_manager.h"
|
#include "network_manager.h"
|
||||||
#include "game_state.h"
|
#include "game_state.h"
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
@ -12,7 +12,7 @@
|
|||||||
#include "ui/desktop.h"
|
#include "ui/desktop.h"
|
||||||
#include "ui/i_window_content.h"
|
#include "ui/i_window_content.h"
|
||||||
#include "ui/ui_window.h"
|
#include "ui/ui_window.h"
|
||||||
#include "ui/window_action.h"
|
#include "ui/editor.h"
|
||||||
#include <ui/main_menu.h>
|
#include <ui/main_menu.h>
|
||||||
#include <ui/boot_sequence.h>
|
#include <ui/boot_sequence.h>
|
||||||
|
|
||||||
@ -128,6 +128,33 @@ void GameState::update(void) {
|
|||||||
case Screen::DESKTOP: {
|
case Screen::DESKTOP: {
|
||||||
std::string server_msg;
|
std::string server_msg;
|
||||||
while(_network->poll_message(server_msg)) {
|
while(_network->poll_message(server_msg)) {
|
||||||
|
/* Check for 'special', non-terminal messages first. */
|
||||||
|
if(server_msg.rfind("FILEDATA::", 0) == 0) {
|
||||||
|
std::string payload = server_msg.substr(10);
|
||||||
|
size_t separator_pos = payload.find("::");
|
||||||
|
if(separator_pos != std::string::npos) {
|
||||||
|
std::string filepath = payload.substr(0, separator_pos);
|
||||||
|
std::string content = payload.substr(separator_pos+2);
|
||||||
|
auto editor = std::make_unique<Editor>();
|
||||||
|
editor->set_buffer_content(content);
|
||||||
|
auto editor_window = std::make_unique<UIWindow>(filepath.c_str(),
|
||||||
|
200, 200, 600, 400);
|
||||||
|
editor_window->set_content(std::move(editor));
|
||||||
|
_desktop->add_window(std::move(editor_window));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(server_msg == "__DISCONNECTED__") {
|
||||||
|
IWindowContent* content = _desktop->get_focused_window() ?
|
||||||
|
_desktop->get_focused_window()->get_content() : nullptr;
|
||||||
|
Terminal* terminal = dynamic_cast<Terminal*>(content);
|
||||||
|
if(terminal) {
|
||||||
|
terminal->add_history("Connection closed.");
|
||||||
|
_network->send("");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If not 'special' message, assume it's for terminal. */
|
||||||
IWindowContent* content = _desktop->get_focused_window() ?
|
IWindowContent* content = _desktop->get_focused_window() ?
|
||||||
_desktop->get_focused_window()->get_content() : nullptr;
|
_desktop->get_focused_window()->get_content() : nullptr;
|
||||||
Terminal* terminal = dynamic_cast<Terminal*>(content);
|
Terminal* terminal = dynamic_cast<Terminal*>(content);
|
||||||
@ -154,18 +181,6 @@ void GameState::update(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(_desktop) {
|
if(_desktop) {
|
||||||
WindowAction action = _desktop->get_pending_action();
|
|
||||||
switch(action.type) {
|
|
||||||
case ActionType::WRITE_FILE: {
|
|
||||||
std::string message = "WRITEF::" + action.payload1 + "::" + action.payload2;
|
|
||||||
_network->send(message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ActionType::NONE:
|
|
||||||
default:
|
|
||||||
/* Do nothing. */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* TODO: These fuck'in window dimensions just need to be global at this point!!
|
* TODO: These fuck'in window dimensions just need to be global at this point!!
|
||||||
* Pass GameState by reference ?
|
* Pass GameState by reference ?
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
@ -12,7 +13,7 @@
|
|||||||
|
|
||||||
Terminal::Terminal(ClientNetwork* network)
|
Terminal::Terminal(ClientNetwork* network)
|
||||||
: _network(network), _should_close(false), _scroll_offset(0),
|
: _network(network), _should_close(false), _scroll_offset(0),
|
||||||
_prompt("") {
|
_prompt(""), _pending_action({ActionType::NONE}) {
|
||||||
_input_view = std::make_unique<TextView>(&_input_buffer, false);
|
_input_view = std::make_unique<TextView>(&_input_buffer, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +35,6 @@ void Terminal::add_history(const std::string& line) {
|
|||||||
_history.push_back(line_with_spaces);
|
_history.push_back(line_with_spaces);
|
||||||
|
|
||||||
if(line == "__CLOSE_CONNECTION__") {
|
if(line == "__CLOSE_CONNECTION__") {
|
||||||
_history.back() = "Connection closed by server.";
|
|
||||||
_should_close = true;
|
_should_close = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,25 +43,38 @@ void Terminal::set_prompt(const std::string& prompt) {
|
|||||||
_prompt = prompt;
|
_prompt = prompt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Terminal::should_close(void) { return _should_close; }
|
bool Terminal::should_close(void) {
|
||||||
|
return _should_close;
|
||||||
|
}
|
||||||
|
|
||||||
WindowAction Terminal::get_pending_action(void) {
|
WindowAction Terminal::get_pending_action(void) {
|
||||||
return { ActionType::NONE };
|
WindowAction action = _pending_action;
|
||||||
|
_pending_action.type = ActionType::NONE;
|
||||||
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
_input_buffer.newline(); /* Add newline to buffer for histroy. */
|
|
||||||
_input_buffer.clear();
|
_input_buffer.clear();
|
||||||
|
|
||||||
/* Add the command to history. */
|
|
||||||
_history.push_back(_prompt + "> " + command);
|
|
||||||
|
|
||||||
if(command == "clear") {
|
if(command == "clear") {
|
||||||
|
_history.push_back(_prompt + "> " + command);
|
||||||
_history.clear();
|
_history.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Client-side command handling. */
|
||||||
|
std::stringstream ss(command);
|
||||||
|
std::string cmd_name;
|
||||||
|
ss >> cmd_name;
|
||||||
|
if(cmd_name == "edit") {
|
||||||
|
_history.push_back(_prompt + "> " + command);
|
||||||
|
ss >> _pending_action.payload1; /* filename. */
|
||||||
|
_pending_action.type = ActionType::READ_FILE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_history.push_back(_prompt + "> " + command);
|
||||||
_network->send(command);
|
_network->send(command);
|
||||||
|
|
||||||
/* TODO: Ugly hack. Refactor to pass window height
|
/* TODO: Ugly hack. Refactor to pass window height
|
||||||
@ -77,9 +90,7 @@ void Terminal::_on_ret_press(void) {
|
|||||||
|
|
||||||
void Terminal::handle_input(SDL_Event* event) {
|
void Terminal::handle_input(SDL_Event* event) {
|
||||||
/* Pass input to TextView; if true, RET was pressed. */
|
/* Pass input to TextView; if true, RET was pressed. */
|
||||||
if(_input_view->handle_event(event)) {
|
if(_input_view->handle_event(event)) { _on_ret_press(); }
|
||||||
_on_ret_press();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Terminal::scroll(int amount, int win_content_height) {
|
void Terminal::scroll(int amount, int win_content_height) {
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "ui/text_buffer.h"
|
#include "ui/text_buffer.h"
|
||||||
#include "ui/text_view.h"
|
#include "ui/text_view.h"
|
||||||
#include "ui/i_window_content.h"
|
#include "ui/i_window_content.h"
|
||||||
|
#include "ui/window_action.h"
|
||||||
|
|
||||||
class Terminal : public IWindowContent {
|
class Terminal : public IWindowContent {
|
||||||
public:
|
public:
|
||||||
@ -33,5 +34,6 @@ private:
|
|||||||
std::string _prompt;
|
std::string _prompt;
|
||||||
ClientNetwork* _network;
|
ClientNetwork* _network;
|
||||||
TextBuffer _input_buffer;
|
TextBuffer _input_buffer;
|
||||||
|
WindowAction _pending_action;
|
||||||
std::unique_ptr<TextView> _input_view;
|
std::unique_ptr<TextView> _input_view;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "ui/editor.h"
|
#include "ui/editor.h"
|
||||||
@ -158,6 +159,31 @@ void Desktop::handle_event(SDL_Event* event, int screen_width, int screen_height
|
|||||||
|
|
||||||
void Desktop::update(int screen_width, int screen_height) {
|
void Desktop::update(int screen_width, int screen_height) {
|
||||||
/* Remove closed windows. */
|
/* Remove closed windows. */
|
||||||
|
if(_focused_window) {
|
||||||
|
IWindowContent* content = _focused_window->get_content();
|
||||||
|
if(content) {
|
||||||
|
WindowAction action = content->get_pending_action();
|
||||||
|
switch(action.type) {
|
||||||
|
case ActionType::WRITE_FILE: {
|
||||||
|
std::string message = "WRITEF::" + action.payload1 + "::" + action.payload2;
|
||||||
|
_network->send(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ActionType::READ_FILE: {
|
||||||
|
std::string message = "READF::" + action.payload1;
|
||||||
|
_network->send(message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(auto& window : _windows) {
|
||||||
|
if(window) {
|
||||||
|
window->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
_update_wallpaper(screen_width, screen_height);
|
_update_wallpaper(screen_width, 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) {
|
||||||
@ -172,16 +198,6 @@ void Desktop::update(int screen_width, int screen_height) {
|
|||||||
_windows.end());
|
_windows.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowAction Desktop::get_pending_action(void) {
|
|
||||||
if(_focused_window) {
|
|
||||||
IWindowContent* content = _focused_window->get_content();
|
|
||||||
if(content) {
|
|
||||||
return content->get_pending_action();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { ActionType::NONE };
|
|
||||||
}
|
|
||||||
|
|
||||||
UIWindow* Desktop::get_focused_window(void) {
|
UIWindow* Desktop::get_focused_window(void) {
|
||||||
return _focused_window;
|
return _focused_window;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
#include "ui/ui_window.h"
|
#include "ui/ui_window.h"
|
||||||
#include "ui/taskbar.h"
|
#include "ui/taskbar.h"
|
||||||
#include "ui/launcher.h"
|
#include "ui/launcher.h"
|
||||||
#include "ui/window_action.h"
|
|
||||||
|
|
||||||
/* Animated background stuff. */
|
/* Animated background stuff. */
|
||||||
struct ScrollingText {
|
struct ScrollingText {
|
||||||
@ -32,7 +31,6 @@ public:
|
|||||||
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
|
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
|
||||||
bool show_cursor);
|
bool show_cursor);
|
||||||
|
|
||||||
WindowAction get_pending_action(void);
|
|
||||||
UIWindow* get_focused_window(void);
|
UIWindow* get_focused_window(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -38,6 +38,10 @@ bool Editor::should_close(void) {
|
|||||||
return _should_close;
|
return _should_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Editor::set_buffer_content(const std::string& content) {
|
||||||
|
_buffer.set_text(content);
|
||||||
|
}
|
||||||
|
|
||||||
WindowAction Editor::get_pending_action(void) {
|
WindowAction Editor::get_pending_action(void) {
|
||||||
WindowAction action = _pending_action;
|
WindowAction action = _pending_action;
|
||||||
_pending_action.type = ActionType::NONE; /* Clear action. */
|
_pending_action.type = ActionType::NONE; /* Clear action. */
|
||||||
|
|||||||
@ -19,6 +19,7 @@ public:
|
|||||||
bool show_cursor) override;
|
bool show_cursor) override;
|
||||||
void scroll(int amount, int content_height) override;
|
void scroll(int amount, int content_height) override;
|
||||||
bool should_close(void) override;
|
bool should_close(void) override;
|
||||||
|
void set_buffer_content(const std::string& content);
|
||||||
WindowAction get_pending_action(void) override;
|
WindowAction get_pending_action(void) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
#include "gfx/types.h"
|
#include "gfx/types.h"
|
||||||
#include "ui/i_window_content.h"
|
#include "ui/i_window_content.h"
|
||||||
|
#include "ui/window_action.h"
|
||||||
|
|
||||||
UIWindow::UIWindow(const char* title, int x, int y, int width, int height) :
|
UIWindow::UIWindow(const char* title, int x, int y, int width, int height) :
|
||||||
_title(title),
|
_title(title),
|
||||||
@ -54,6 +55,12 @@ bool UIWindow::should_close(void) const {
|
|||||||
return _should_close;
|
return _should_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UIWindow::update(void) {
|
||||||
|
if(_content) {
|
||||||
|
if(_content->should_close()) { _should_close = true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void UIWindow::set_content(std::unique_ptr<IWindowContent> content) {
|
void UIWindow::set_content(std::unique_ptr<IWindowContent> content) {
|
||||||
_content = std::move(content);
|
_content = std::move(content);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public:
|
|||||||
UIWindow(const char* title, int x, int y, int width, int height);
|
UIWindow(const char* title, int x, int y, int width, int height);
|
||||||
~UIWindow(void);
|
~UIWindow(void);
|
||||||
|
|
||||||
|
void update(void);
|
||||||
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
|
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
|
||||||
bool show_cursor);
|
bool show_cursor);
|
||||||
void handle_event(SDL_Event* event, int screen_width, int screen_height,
|
void handle_event(SDL_Event* event, int screen_width, int screen_height,
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
enum class ActionType {
|
enum class ActionType {
|
||||||
NONE,
|
NONE,
|
||||||
WRITE_FILE
|
WRITE_FILE,
|
||||||
|
READ_FILE,
|
||||||
|
CLOSE_WINDOW
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WindowAction {
|
struct WindowAction {
|
||||||
|
|||||||
@ -103,6 +103,15 @@ vfs_node* find_node_by_path(vfs_node* root, const std::string& path) {
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string CommandProcessor::read_file(const std::string& path) {
|
||||||
|
vfs_node* root = get_session_machine()->vfs_root;
|
||||||
|
vfs_node* node = find_node_by_path(root, path);
|
||||||
|
if(node && node->type == FILE_NODE) {
|
||||||
|
return node->content;
|
||||||
|
}
|
||||||
|
return "Error: file not found.";
|
||||||
|
}
|
||||||
|
|
||||||
void CommandProcessor::ensure_vfs_is_writable(void) {
|
void CommandProcessor::ensure_vfs_is_writable(void) {
|
||||||
if(!_session_machine->is_vfs_a_copy) {
|
if(!_session_machine->is_vfs_a_copy) {
|
||||||
/* VFS shared, copy required. */
|
/* VFS shared, copy required. */
|
||||||
|
|||||||
@ -14,6 +14,7 @@ public:
|
|||||||
|
|
||||||
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);
|
||||||
|
std::string read_file(const std::string& path);
|
||||||
|
|
||||||
/* Public interface for API functions. */
|
/* Public interface for API functions. */
|
||||||
vfs_node* get_current_dir(void);
|
vfs_node* get_current_dir(void);
|
||||||
|
|||||||
@ -84,3 +84,14 @@ void TextBuffer::clear(void) {
|
|||||||
_cursor_row = 0;
|
_cursor_row = 0;
|
||||||
_cursor_col = 0;
|
_cursor_col = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextBuffer::set_text(const std::string& text) {
|
||||||
|
_lines.clear();
|
||||||
|
std::stringstream ss(text);
|
||||||
|
std::string line;
|
||||||
|
while(std::getline(ss, line, '\n')) {
|
||||||
|
_lines.push_back(line);
|
||||||
|
}
|
||||||
|
_cursor_row = 0;
|
||||||
|
_cursor_col = 0;
|
||||||
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ public:
|
|||||||
Point get_cursor_pos(void) const;
|
Point get_cursor_pos(void) const;
|
||||||
std::string get_text(void) const;
|
std::string get_text(void) const;
|
||||||
void clear(void);
|
void clear(void);
|
||||||
|
void set_text(const std::string& text);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::string> _lines;
|
std::vector<std::string> _lines;
|
||||||
|
|||||||
@ -122,6 +122,14 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(message.rfind("READF::", 0) == 0) {
|
||||||
|
std::string filepath = message.substr(7);
|
||||||
|
fprintf(stderr, "[Player %u] Read file: '%s'\n", player->id, filepath.c_str());
|
||||||
|
std::string content = player->cmd_processor->read_file(filepath);
|
||||||
|
/* Send the content back to the client. */
|
||||||
|
connection->send("FILEDATA::" + filepath + "::" + content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* If no prefix, treat as normal terminal command. */
|
/* If no prefix, treat as normal terminal command. */
|
||||||
fprintf(stderr, "[Player %u] Command: '%s'\n", player->id, message.c_str());
|
fprintf(stderr, "[Player %u] Command: '%s'\n", player->id, message.c_str());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user