#include "ConsoleScreen.h" #include "../Gui.h" #include "../../Minecraft.h" #include "../../player/LocalPlayer.h" #include "../../../platform/input/Keyboard.h" #include "../../../world/level/Level.h" #include "../../../network/RakNetInstance.h" #include "../../../network/ServerSideNetworkHandler.h" #include "../../../network/packet/ChatPacket.h" #include "../../../platform/log.h" #include #include #include ConsoleScreen::ConsoleScreen() : _input(""), _cursorBlink(0) { } void ConsoleScreen::init() { } void ConsoleScreen::tick() { _cursorBlink++; } bool ConsoleScreen::handleBackEvent(bool /*isDown*/) { minecraft->setScreen(NULL); return true; } void ConsoleScreen::keyPressed(int eventKey) { if (eventKey == Keyboard::KEY_ESCAPE) { minecraft->setScreen(NULL); } else if (eventKey == Keyboard::KEY_RETURN) { execute(); } else if (eventKey == Keyboard::KEY_BACKSPACE) { if (!_input.empty()) _input.erase(_input.size() - 1, 1); } else { super::keyPressed(eventKey); } } void ConsoleScreen::charPressed(char inputChar) { if (inputChar >= 32 && inputChar < 127) _input += inputChar; } // --------------------------------------------------------------------------- // execute: run _input as a command, print result, close screen // --------------------------------------------------------------------------- void ConsoleScreen::execute() { if (_input.empty()) { minecraft->setScreen(NULL); return; } if (_input[0] == '/') { // Command std::string result = processCommand(_input); if (!result.empty()) minecraft->gui.addMessage(result); } else { // Chat message: message std::string msg = std::string("<") + minecraft->player->name + "> " + _input; if (minecraft->netCallback && minecraft->raknetInstance->isServer()) { // Hosting a LAN game: displayGameMessage shows locally + broadcasts MessagePacket to clients static_cast(minecraft->netCallback)->displayGameMessage(msg); } else if (minecraft->netCallback) { // Connected client: send ChatPacket to server; server echoes it back as MessagePacket ChatPacket chatPkt(msg); minecraft->raknetInstance->send(chatPkt); } else { // Singleplayer: show locally only minecraft->gui.addMessage(msg); } } minecraft->setScreen(NULL); } // --------------------------------------------------------------------------- // processCommand // --------------------------------------------------------------------------- static std::string trim(const std::string& s) { size_t a = s.find_first_not_of(" \t"); if (a == std::string::npos) return ""; size_t b = s.find_last_not_of(" \t"); return s.substr(a, b - a + 1); } std::string ConsoleScreen::processCommand(const std::string& raw) { // strip leading '/' std::string line = raw; if (!line.empty() && line[0] == '/') line = line.substr(1); line = trim(line); // tokenise std::vector args; { std::istringstream ss(line); std::string tok; while (ss >> tok) args.push_back(tok); } if (args.empty()) return ""; Level* level = minecraft->level; if (!level) return "No level loaded."; // ----------------------------------------------------------------------- // /time ... // ----------------------------------------------------------------------- if (args[0] == "time") { if (args.size() < 2) return "Usage: /time ..."; const std::string& sub = args[1]; // -- time add ----------------------------------------------- if (sub == "add") { if (args.size() < 3) return "Usage: /time add "; long delta = std::atol(args[2].c_str()); long newTime = level->getTime() + delta; level->setTime(newTime); std::ostringstream out; out << "Set the time to " << (newTime % Level::TICKS_PER_DAY); return out.str(); } // -- time set ----------------------- if (sub == "set") { if (args.size() < 3) return "Usage: /time set "; const std::string& val = args[2]; long t = -1; if (val == "day") t = 1000; else if (val == "noon") t = 6000; else if (val == "night") t = 13000; else if (val == "midnight") t = 18000; else { // numeric — accept positive integers only bool numeric = true; for (char c : val) if (!std::isdigit((unsigned char)c)) { numeric = false; break; } if (!numeric) return std::string("Unknown value: ") + val; t = std::atol(val.c_str()); } // Preserve the total day count so only the time-of-day changes long dayCount = level->getTime() / Level::TICKS_PER_DAY; long newTime = dayCount * Level::TICKS_PER_DAY + (t % Level::TICKS_PER_DAY); level->setTime(newTime); std::ostringstream out; out << "Set the time to " << t; return out.str(); } // -- time query ------------------------------ if (sub == "query") { if (args.size() < 3) return "Usage: /time query "; const std::string& what = args[2]; long total = level->getTime(); long daytime = total % Level::TICKS_PER_DAY; long day = total / Level::TICKS_PER_DAY; std::ostringstream out; if (what == "daytime") { out << "The time of day is " << daytime; } else if (what == "gametime") { out << "The game time is " << total; } else if (what == "day") { out << "The day is " << day; } else return std::string("Unknown query: ") + what; return out.str(); } return "Unknown sub-command. Usage: /time ..."; } return std::string("Unknown command: /") + args[0]; } // --------------------------------------------------------------------------- // render // --------------------------------------------------------------------------- void ConsoleScreen::render(int /*xm*/, int /*ym*/, float /*a*/) { // Dim the game world slightly fillGradient(0, 0, width, height, 0x00000000, 0x40000000); const int boxH = 12; const int boxY = height - boxH - 2; const int boxX0 = 2; const int boxX1 = width - 2; // Input box background fill(boxX0, boxY, boxX1, boxY + boxH, 0xc0000000); // Border fill(boxX0, boxY, boxX1, boxY + 1, 0xff808080); fill(boxX0, boxY + boxH - 1, boxX1, boxY + boxH, 0xff808080); fill(boxX0, boxY, boxX0 + 1, boxY + boxH, 0xff808080); fill(boxX1 - 1, boxY, boxX1, boxY + boxH, 0xff808080); // Input text + blinking cursor std::string displayed = _input; if ((_cursorBlink / 10) % 2 == 0) displayed += '_'; // Placeholder hint when empty font->drawShadow(displayed, (float)(boxX0 + 2), (float)(boxY + 2), 0xffffffff); }