[Add] Not your boring main menu.
This commit is contained in:
parent
b1bdb86b76
commit
e72cc987ff
34
assets/menu_background_snippets.txt
Normal file
34
assets/menu_background_snippets.txt
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
map -sV 10.0.2.15
|
||||||
|
ls -la /etc/
|
||||||
|
ps aux | grep 'sshd'
|
||||||
|
gcc exploit.c -o exploit
|
||||||
|
SELECT * FROM users;
|
||||||
|
import requests
|
||||||
|
while(true){};
|
||||||
|
});
|
||||||
|
sudo rm -rf /
|
||||||
|
netstat -anp
|
||||||
|
arp -a
|
||||||
|
ssh root@192.168.1.1
|
||||||
|
git commit -m 'Initial commit'
|
||||||
|
hydra -l user -P wordlist.txt ftp://...
|
||||||
|
Hello, world.
|
||||||
|
All your base are belong to us
|
||||||
|
// TODO: fix this later
|
||||||
|
42
|
||||||
|
1337
|
||||||
|
zerocool
|
||||||
|
acidburn
|
||||||
|
cereal_killer
|
||||||
|
ping -c 4 google.com
|
||||||
|
traceroute 8.8.8.8
|
||||||
|
</div>
|
||||||
|
<a>
|
||||||
|
password123
|
||||||
|
GOD
|
||||||
|
Have you tried turning it off and on again?
|
||||||
|
Connection established.
|
||||||
|
SYN/ACK
|
||||||
|
Firewall breach detected.
|
||||||
|
Decrypting /etc/shadow...
|
||||||
|
root::0:0:root:/root:/bin/bash
|
||||||
@ -1,13 +1,17 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "../../server/src/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"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
#include "ui/desktop.h"
|
#include "ui/desktop.h"
|
||||||
#include "ui/ui_window.h"
|
#include "ui/ui_window.h"
|
||||||
|
#include <ui/main_menu.h>
|
||||||
|
|
||||||
void GameState::_init_desktop(void) {
|
void GameState::_init_desktop(void) {
|
||||||
_desktop = std::make_unique<Desktop>();
|
_desktop = std::make_unique<Desktop>();
|
||||||
@ -18,15 +22,41 @@ void GameState::_init_desktop(void) {
|
|||||||
_desktop->add_window(std::move(term_window));
|
_desktop->add_window(std::move(term_window));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameState::_run_server(void) {
|
||||||
|
try {
|
||||||
|
NetworkManager server;
|
||||||
|
server.start(1337);
|
||||||
|
/*
|
||||||
|
* Server's start() method is non-blocking, but NetworkManager
|
||||||
|
* object must be kept alive. We'll just loop forever and let the OS
|
||||||
|
* clean up the thread when main exits ;)
|
||||||
|
*/
|
||||||
|
while(true) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||||
|
}
|
||||||
|
} catch(const std::exception& e) {
|
||||||
|
fprintf(stderr, "Single-player server thread exception: %s\n", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameState::GameState(void) : _current_screen(Screen::MAIN_MENU) {}
|
GameState::GameState(void) : _current_screen(Screen::MAIN_MENU) {}
|
||||||
|
|
||||||
GameState::~GameState(void) = default;
|
GameState::~GameState(void) = default;
|
||||||
|
|
||||||
void GameState::init(void) {
|
void GameState::init(int screen_width, int screen_height) {
|
||||||
/* Create and connect the network client. */
|
/* Create and connect the network client. */
|
||||||
_network = std::make_unique<ClientNetwork>();
|
_network = std::make_unique<ClientNetwork>();
|
||||||
|
|
||||||
/* TODO: For now, connect immediately, later, trigger by menu option. */
|
_main_menu = std::make_unique<MainMenu>(screen_width, screen_height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameState::start_single_player_now(int screen_width, int screen_height) {
|
||||||
|
fprintf(stdout, "Starting in single-player mode...\n");
|
||||||
|
std::thread server_thread(&GameState::_run_server, this);
|
||||||
|
server_thread.detach();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
|
|
||||||
|
_network = std::make_unique<ClientNetwork>();
|
||||||
if(!_network->connect("127.0.0.1", 1337)) {
|
if(!_network->connect("127.0.0.1", 1337)) {
|
||||||
/* TODO: Handle connection failure. */
|
/* TODO: Handle connection failure. */
|
||||||
}
|
}
|
||||||
@ -37,7 +67,9 @@ void GameState::init(void) {
|
|||||||
void GameState::handle_event(SDL_Event* event) {
|
void GameState::handle_event(SDL_Event* event) {
|
||||||
switch(_current_screen) {
|
switch(_current_screen) {
|
||||||
case Screen::MAIN_MENU:
|
case Screen::MAIN_MENU:
|
||||||
/* TODO: */
|
if(_main_menu) {
|
||||||
|
_main_menu->handle_event(event);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Screen::BOOTING:
|
case Screen::BOOTING:
|
||||||
/* TODO: */
|
/* TODO: */
|
||||||
@ -52,13 +84,33 @@ void GameState::handle_event(SDL_Event* event) {
|
|||||||
|
|
||||||
void GameState::update(void) {
|
void GameState::update(void) {
|
||||||
switch(_current_screen) {
|
switch(_current_screen) {
|
||||||
case Screen::MAIN_MENU:
|
case Screen::MAIN_MENU: {
|
||||||
/* TODO: */
|
if(!_main_menu) break;
|
||||||
|
Screen next_screen = _main_menu->update();
|
||||||
|
if(next_screen != Screen::MAIN_MENU) {
|
||||||
|
_current_screen = next_screen;
|
||||||
|
_main_menu.reset(); /* Free mem. */
|
||||||
|
|
||||||
|
if(_current_screen == Screen::BOOTING) {
|
||||||
|
fprintf(stdout, "Starting in single-player mode...\n");
|
||||||
|
std::thread server_thread(&GameState::_run_server, this);
|
||||||
|
server_thread.detach();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
|
|
||||||
|
if(!_network->connect("127.0.0.1", 1337)) {
|
||||||
|
/* TODO: Handle connection failure. */
|
||||||
|
}
|
||||||
|
/* TODO: transition to book screen. */
|
||||||
|
_current_screen = Screen::DESKTOP;
|
||||||
|
_init_desktop();
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Screen::BOOTING:
|
case Screen::BOOTING:
|
||||||
/* TODO: */
|
/* TODO: */
|
||||||
break;
|
break;
|
||||||
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)) {
|
||||||
UIWindow* focused_window = _desktop->get_focused_window();
|
UIWindow* focused_window = _desktop->get_focused_window();
|
||||||
@ -94,12 +146,15 @@ void GameState::update(void) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GameState::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
void GameState::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
||||||
int screen_height, bool show_cursor) {
|
int screen_height, bool show_cursor) {
|
||||||
switch(_current_screen) {
|
switch(_current_screen) {
|
||||||
case Screen::MAIN_MENU:
|
case Screen::MAIN_MENU:
|
||||||
/* TODO: */
|
if(_main_menu) {
|
||||||
|
_main_menu->render(shape_renderer, txt_renderer);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Screen::BOOTING:
|
case Screen::BOOTING:
|
||||||
/* TODO: */
|
/* TODO: */
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
class ClientNetwork;
|
class ClientNetwork;
|
||||||
class Desktop;
|
class Desktop;
|
||||||
|
class MainMenu;
|
||||||
class ShapeRenderer;
|
class ShapeRenderer;
|
||||||
class TextRenderer;
|
class TextRenderer;
|
||||||
union SDL_Event;
|
union SDL_Event;
|
||||||
@ -19,7 +20,8 @@ public:
|
|||||||
GameState(void);
|
GameState(void);
|
||||||
~GameState(void);
|
~GameState(void);
|
||||||
|
|
||||||
void init(void);
|
void init(int screen_width, int screen_height);
|
||||||
|
void start_single_player_now(int screen_width, int screen_height);
|
||||||
void handle_event(SDL_Event* event);
|
void handle_event(SDL_Event* event);
|
||||||
void update(void);
|
void update(void);
|
||||||
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer,
|
||||||
@ -28,7 +30,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
std::unique_ptr<ClientNetwork> _network;
|
std::unique_ptr<ClientNetwork> _network;
|
||||||
std::unique_ptr<Desktop> _desktop;
|
std::unique_ptr<Desktop> _desktop;
|
||||||
|
std::unique_ptr<MainMenu> _main_menu;
|
||||||
Screen _current_screen;
|
Screen _current_screen;
|
||||||
|
|
||||||
void _init_desktop(void);
|
void _init_desktop(void);
|
||||||
|
void _run_server(void);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,47 +1,17 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <SDL3/SDL_keyboard.h>
|
#include <SDL3/SDL_keyboard.h>
|
||||||
|
|
||||||
/* For single player mode. */
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
#include <chrono>
|
|
||||||
#include "../../server/src/network_manager.h"
|
|
||||||
|
|
||||||
#include "gfx/shape_renderer.h"
|
#include "gfx/shape_renderer.h"
|
||||||
#include "gfx/txt_renderer.h"
|
#include "gfx/txt_renderer.h"
|
||||||
#include "game_state.h"
|
#include "game_state.h"
|
||||||
|
|
||||||
void run_server(void) {
|
|
||||||
try {
|
|
||||||
NetworkManager server;
|
|
||||||
server.start(1337);
|
|
||||||
/*
|
|
||||||
* Server's start() method is non-blocking, but NetworkManager
|
|
||||||
* object must be kept alive. We'll just loop forever and let the OS
|
|
||||||
* clean up the thread when main exits ;)
|
|
||||||
*/
|
|
||||||
while(true) {
|
|
||||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
|
||||||
}
|
|
||||||
} catch(const std::exception& e) {
|
|
||||||
fprintf(stderr, "Single-player server thread exception: %s\n", e.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const int SCREEN_WIDTH = 1280;
|
const int SCREEN_WIDTH = 1280;
|
||||||
const int SCREEN_HEIGHT = 720;
|
const int SCREEN_HEIGHT = 720;
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
if(argc > 1 && std::string(argv[1]) == "-sp") {
|
|
||||||
fprintf(stdout, "Starting in single-player mode...\n");
|
|
||||||
std::thread server_thread(run_server);
|
|
||||||
server_thread.detach();
|
|
||||||
fprintf(stdout, "Waiting for server initialise...\n");
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Init SDL. */
|
/* Init SDL. */
|
||||||
if(!SDL_Init(SDL_INIT_VIDEO)) {
|
if(!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
printf("SDL could not initialise! SDL_ERROR: %s\n", SDL_GetError());
|
printf("SDL could not initialise! SDL_ERROR: %s\n", SDL_GetError());
|
||||||
@ -104,7 +74,11 @@ int main(int argc, char** argv) {
|
|||||||
ShapeRenderer* shape_renderer_instance = new ShapeRenderer(SCREEN_WIDTH, SCREEN_HEIGHT);
|
ShapeRenderer* shape_renderer_instance = new ShapeRenderer(SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
|
||||||
auto game_state = std::make_unique<GameState>();
|
auto game_state = std::make_unique<GameState>();
|
||||||
game_state->init();
|
if(argc > 1 && std::string(argv[1]) == "-sp") {
|
||||||
|
game_state->start_single_player_now(SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
} else {
|
||||||
|
game_state->init(SCREEN_WIDTH, SCREEN_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
/* timer for cursor blink. */
|
/* timer for cursor blink. */
|
||||||
Uint32 last_blink_time = 0;
|
Uint32 last_blink_time = 0;
|
||||||
|
|||||||
142
client/src/ui/main_menu.cpp
Normal file
142
client/src/ui/main_menu.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include <SDL3/SDL_events.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "gfx/shape_renderer.h"
|
||||||
|
#include "gfx/txt_renderer.h"
|
||||||
|
|
||||||
|
#include "main_menu.h"
|
||||||
|
|
||||||
|
/* Get a random snippet form loaded word list. */
|
||||||
|
const std::string& get_random_snippet(const std::vector<std::string>& snippets) {
|
||||||
|
/* If empty, return a default to avoid a crash? */
|
||||||
|
if(snippets.empty()) {
|
||||||
|
static const std::string empty_str = "ERROR: snippets file not found";
|
||||||
|
return empty_str;
|
||||||
|
}
|
||||||
|
int index = rand() % snippets.size();
|
||||||
|
return snippets[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
MainMenu::MainMenu(int screen_width, int screen_height) :
|
||||||
|
_screen_width(screen_width), _screen_height(screen_height),
|
||||||
|
_next_screen(Screen::MAIN_MENU) {
|
||||||
|
|
||||||
|
/* Load snippets form file. */
|
||||||
|
std::ifstream snippet_file("assets/menu_background_snippets.txt");
|
||||||
|
if(!snippet_file.is_open()) {
|
||||||
|
printf("ERROR: Failed to open assets/menu_background_snippets.txt\n");
|
||||||
|
} else {
|
||||||
|
std::string line;
|
||||||
|
while(std::getline(snippet_file, line)) {
|
||||||
|
if(!line.empty()) {
|
||||||
|
_snippets.push_back(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise buttons. */
|
||||||
|
const int button_width = 200;
|
||||||
|
const int button_height = 50;
|
||||||
|
const int center_x = (screen_width/2) - (button_width/2);
|
||||||
|
const int center_y = (screen_height/2);
|
||||||
|
|
||||||
|
_buttons.push_back({
|
||||||
|
"Single-Player",
|
||||||
|
{ center_x, center_y + 30, button_width, button_height },
|
||||||
|
Screen::BOOTING, /* This will trigger the booting screen. */
|
||||||
|
false
|
||||||
|
});
|
||||||
|
_buttons.push_back({
|
||||||
|
"Online",
|
||||||
|
{ center_x, center_y - 30, button_width, button_height },
|
||||||
|
Screen::BOOTING,
|
||||||
|
false
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Initialise animated background. */
|
||||||
|
srand(time(NULL));
|
||||||
|
for(int i = 0; i < 100; ++i) {
|
||||||
|
_background_text.push_back({
|
||||||
|
get_random_snippet(_snippets),
|
||||||
|
(float)(rand() % screen_width),
|
||||||
|
(float)(rand() % screen_height),
|
||||||
|
(float)(rand() % 50 + 20) / 100.0f /* Random speed. */
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MainMenu::~MainMenu(void) {}
|
||||||
|
|
||||||
|
void MainMenu::handle_event(SDL_Event* event) {
|
||||||
|
if(event->type == SDL_EVENT_MOUSE_MOTION) {
|
||||||
|
int mouse_x = event->motion.x;
|
||||||
|
int mouse_y = event->motion.y;
|
||||||
|
for(auto& button : _buttons) {
|
||||||
|
/* Invert mouse_y for UI coordinate system. */
|
||||||
|
int inverted_y = _screen_height - mouse_y;
|
||||||
|
button.is_hovered = (mouse_x >= button.rect.x
|
||||||
|
&& mouse_x <= button.rect.x + button.rect.w
|
||||||
|
&& inverted_y >= button.rect.y
|
||||||
|
&& inverted_y <= button.rect.y + button.rect.h);
|
||||||
|
}
|
||||||
|
} else if(event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
||||||
|
for(const auto& button : _buttons) {
|
||||||
|
if(button.is_hovered) {
|
||||||
|
_next_screen = button.action;
|
||||||
|
break; /* Once clicked button found, exit. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Screen MainMenu::update(void) {
|
||||||
|
_update_background();
|
||||||
|
return _next_screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenu::render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer) {
|
||||||
|
_render_background(txt_renderer);
|
||||||
|
|
||||||
|
/* Button colours. */
|
||||||
|
const Color button_color = { 0.1f, 0.15f, 0.2f };
|
||||||
|
const Color button_hover_color = { 0.2f, 0.25f, 0.3f };
|
||||||
|
const Color text_color = { 0.8f, 0.8f, 0.8f };
|
||||||
|
|
||||||
|
for(const auto& button : _buttons) {
|
||||||
|
/* Draw button background. */
|
||||||
|
if(button.is_hovered) {
|
||||||
|
shape_renderer->draw_rect(button.rect.x, button.rect.y, button.rect.w,
|
||||||
|
button.rect.h, button_hover_color);
|
||||||
|
} else {
|
||||||
|
shape_renderer->draw_rect(button.rect.x, button.rect.y, button.rect.w,
|
||||||
|
button.rect.h, button_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Draw button text centered.
|
||||||
|
* TODO: Calculate text width for perfect centering.
|
||||||
|
*/
|
||||||
|
txt_renderer->render_text(button.label.c_str(), button.rect.x + 50,
|
||||||
|
button.rect.y + 18, 1.0f, text_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenu::_update_background(void) {
|
||||||
|
for(auto& line : _background_text) {
|
||||||
|
line.y -= line.speed;
|
||||||
|
if(line.y < 0) {
|
||||||
|
line.y = _screen_height;
|
||||||
|
line.x = (float)(rand() % _screen_width);
|
||||||
|
line.text = get_random_snippet(_snippets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenu::_render_background(TextRenderer* txt_renderer) {
|
||||||
|
const Color background_text_color = { 0.0f, 0.35f, 0.15f }; /* Dark green. */
|
||||||
|
for(const auto& line : _background_text) {
|
||||||
|
txt_renderer->render_text(line.text.c_str(), line.x, line.y, 1.0f,
|
||||||
|
background_text_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
client/src/ui/main_menu.h
Normal file
49
client/src/ui/main_menu.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "gfx/txt_renderer.h"
|
||||||
|
#include "gfx/shape_renderer.h"
|
||||||
|
#include "gfx/types.h"
|
||||||
|
#include "game_state.h"
|
||||||
|
|
||||||
|
union SDL_Event;
|
||||||
|
|
||||||
|
struct MenuButton {
|
||||||
|
std::string label;
|
||||||
|
Rect rect;
|
||||||
|
Screen action; /* Change state. */
|
||||||
|
bool is_hovered = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MainMenu {
|
||||||
|
public:
|
||||||
|
MainMenu(int screen_width, int screen_height);
|
||||||
|
~MainMenu(void);
|
||||||
|
|
||||||
|
void handle_event(SDL_Event* event);
|
||||||
|
Screen update(void);
|
||||||
|
void render(ShapeRenderer* shape_renderer, TextRenderer* txt_renderer);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _update_background(void);
|
||||||
|
void _render_background(TextRenderer* txdt_renderer);
|
||||||
|
|
||||||
|
/* For animated background. */
|
||||||
|
struct ScrollingText {
|
||||||
|
std::string text;
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float speed;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ScrollingText> _background_text;
|
||||||
|
int _screen_height;
|
||||||
|
int _screen_width;
|
||||||
|
|
||||||
|
/* Buttons. */
|
||||||
|
std::vector<MenuButton> _buttons;
|
||||||
|
std::vector<std::string> _snippets;
|
||||||
|
Screen _next_screen;
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user