[Add] File loading and fix local 'exit' command.
This commit is contained in:
		
							parent
							
								
									ebd1e222d7
								
							
						
					
					
						commit
						666b4f554b
					
				@ -4,7 +4,7 @@
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <chrono>
 | 
			
		||||
 | 
			
		||||
#include "../../server/src/network_manager.h"
 | 
			
		||||
#include "network_manager.h"
 | 
			
		||||
#include "game_state.h"
 | 
			
		||||
#include "gfx/shape_renderer.h"
 | 
			
		||||
#include "gfx/txt_renderer.h"
 | 
			
		||||
@ -12,7 +12,7 @@
 | 
			
		||||
#include "ui/desktop.h"
 | 
			
		||||
#include "ui/i_window_content.h"
 | 
			
		||||
#include "ui/ui_window.h"
 | 
			
		||||
#include "ui/window_action.h"
 | 
			
		||||
#include "ui/editor.h"
 | 
			
		||||
#include <ui/main_menu.h>
 | 
			
		||||
#include <ui/boot_sequence.h>
 | 
			
		||||
 | 
			
		||||
@ -128,6 +128,33 @@ void GameState::update(void) {
 | 
			
		||||
  case Screen::DESKTOP: {
 | 
			
		||||
    std::string 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() ?
 | 
			
		||||
            _desktop->get_focused_window()->get_content() : nullptr;
 | 
			
		||||
        Terminal* terminal = dynamic_cast<Terminal*>(content);
 | 
			
		||||
@ -154,18 +181,6 @@ void GameState::update(void) {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      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!!
 | 
			
		||||
         * Pass GameState by reference ?
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <SDL3/SDL.h>
 | 
			
		||||
#include <GL/glew.h>
 | 
			
		||||
#include <SDL3/SDL_events.h>
 | 
			
		||||
@ -12,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
Terminal::Terminal(ClientNetwork* network)
 | 
			
		||||
    : _network(network), _should_close(false), _scroll_offset(0),
 | 
			
		||||
      _prompt("") {
 | 
			
		||||
      _prompt(""), _pending_action({ActionType::NONE}) {
 | 
			
		||||
  _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);
 | 
			
		||||
 | 
			
		||||
  if(line == "__CLOSE_CONNECTION__") {
 | 
			
		||||
    _history.back() = "Connection closed by server.";
 | 
			
		||||
    _should_close = true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -43,25 +43,38 @@ void Terminal::set_prompt(const std::string& 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) {
 | 
			
		||||
  return { ActionType::NONE };
 | 
			
		||||
  WindowAction action = _pending_action;
 | 
			
		||||
  _pending_action.type = ActionType::NONE;
 | 
			
		||||
  return action;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Terminal::_on_ret_press(void) {
 | 
			
		||||
  std::string command = _input_buffer.get_line(0);
 | 
			
		||||
  _input_buffer.newline(); /* Add newline to buffer for histroy. */
 | 
			
		||||
  _input_buffer.clear();
 | 
			
		||||
 | 
			
		||||
  /* Add the command to history. */
 | 
			
		||||
  _history.push_back(_prompt + "> " + command);
 | 
			
		||||
 | 
			
		||||
  if(command == "clear") {
 | 
			
		||||
    _history.push_back(_prompt + "> " + command);
 | 
			
		||||
    _history.clear();
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
  /* 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) {
 | 
			
		||||
  /* Pass input to TextView; if true, RET was pressed. */
 | 
			
		||||
  if(_input_view->handle_event(event)) {
 | 
			
		||||
    _on_ret_press();
 | 
			
		||||
  }
 | 
			
		||||
  if(_input_view->handle_event(event)) { _on_ret_press(); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Terminal::scroll(int amount, int win_content_height) {
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
#include "ui/text_buffer.h"
 | 
			
		||||
#include "ui/text_view.h"
 | 
			
		||||
#include "ui/i_window_content.h"
 | 
			
		||||
#include "ui/window_action.h"
 | 
			
		||||
 | 
			
		||||
class Terminal : public IWindowContent {
 | 
			
		||||
public:
 | 
			
		||||
@ -33,5 +34,6 @@ private:
 | 
			
		||||
  std::string _prompt;
 | 
			
		||||
  ClientNetwork* _network;
 | 
			
		||||
  TextBuffer _input_buffer;
 | 
			
		||||
  WindowAction _pending_action;
 | 
			
		||||
  std::unique_ptr<TextView> _input_view;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
#include <ctime>
 | 
			
		||||
#include <fstream>
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#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) {
 | 
			
		||||
  /* 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);
 | 
			
		||||
  _windows.erase(std::remove_if(_windows.begin(), _windows.end(),
 | 
			
		||||
                                [this](const std::unique_ptr<UIWindow>& w) {
 | 
			
		||||
@ -172,16 +198,6 @@ void Desktop::update(int screen_width, int screen_height) {
 | 
			
		||||
                 _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) {
 | 
			
		||||
  return _focused_window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,6 @@
 | 
			
		||||
#include "ui/ui_window.h"
 | 
			
		||||
#include "ui/taskbar.h"
 | 
			
		||||
#include "ui/launcher.h"
 | 
			
		||||
#include "ui/window_action.h"
 | 
			
		||||
 | 
			
		||||
/* Animated background stuff. */
 | 
			
		||||
struct ScrollingText {
 | 
			
		||||
@ -32,7 +31,6 @@ public:
 | 
			
		||||
  void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
 | 
			
		||||
              bool show_cursor);
 | 
			
		||||
 | 
			
		||||
  WindowAction get_pending_action(void);
 | 
			
		||||
  UIWindow* get_focused_window(void);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,10 @@ bool Editor::should_close(void) {
 | 
			
		||||
  return _should_close;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Editor::set_buffer_content(const std::string& content) {
 | 
			
		||||
  _buffer.set_text(content);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WindowAction Editor::get_pending_action(void) {
 | 
			
		||||
  WindowAction action = _pending_action;
 | 
			
		||||
  _pending_action.type = ActionType::NONE; /* Clear action. */
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ public:
 | 
			
		||||
              bool show_cursor) override;
 | 
			
		||||
  void scroll(int amount, int content_height) override;
 | 
			
		||||
  bool should_close(void) override;
 | 
			
		||||
  void set_buffer_content(const std::string& content);
 | 
			
		||||
  WindowAction get_pending_action(void) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
#include "gfx/txt_renderer.h"
 | 
			
		||||
#include "gfx/types.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) :
 | 
			
		||||
    _title(title),
 | 
			
		||||
@ -54,6 +55,12 @@ bool UIWindow::should_close(void) const {
 | 
			
		||||
  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) {
 | 
			
		||||
  _content = std::move(content);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@ public:
 | 
			
		||||
  UIWindow(const char* title, int x, int y, int width, int height);
 | 
			
		||||
  ~UIWindow(void);
 | 
			
		||||
 | 
			
		||||
  void update(void);
 | 
			
		||||
  void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer, int screen_height,
 | 
			
		||||
              bool show_cursor);
 | 
			
		||||
  void handle_event(SDL_Event* event, int screen_width, int screen_height,
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,9 @@
 | 
			
		||||
 | 
			
		||||
enum class ActionType {
 | 
			
		||||
  NONE,
 | 
			
		||||
  WRITE_FILE
 | 
			
		||||
  WRITE_FILE,
 | 
			
		||||
  READ_FILE,
 | 
			
		||||
  CLOSE_WINDOW
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct WindowAction {
 | 
			
		||||
 | 
			
		||||
@ -103,6 +103,15 @@ vfs_node* find_node_by_path(vfs_node* root, const std::string& path) {
 | 
			
		||||
  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) {
 | 
			
		||||
  if(!_session_machine->is_vfs_a_copy) {
 | 
			
		||||
    /* VFS shared, copy required. */
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  std::string process_command(const std::string& command);
 | 
			
		||||
  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. */
 | 
			
		||||
  vfs_node* get_current_dir(void);
 | 
			
		||||
 | 
			
		||||
@ -84,3 +84,14 @@ void TextBuffer::clear(void) {
 | 
			
		||||
  _cursor_row = 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;
 | 
			
		||||
  std::string get_text(void) const;
 | 
			
		||||
  void clear(void);
 | 
			
		||||
  void set_text(const std::string& text);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  std::vector<std::string> _lines;
 | 
			
		||||
 | 
			
		||||
@ -122,6 +122,14 @@ void NetworkManager::on_message(std::shared_ptr<net::TcpConnection> connection,
 | 
			
		||||
    }
 | 
			
		||||
    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. */
 | 
			
		||||
  fprintf(stderr, "[Player %u] Command: '%s'\n", player->id, message.c_str());
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user