diff --git a/.clang-format b/.clang-format index 4407457..ce02044 100644 --- a/.clang-format +++ b/.clang-format @@ -2,16 +2,17 @@ BasedOnStyle: LLVM IndentWidth: 4 # logical indent level = 1 tab TabWidth: 4 # how wide a tab renders (adjust per team preference) -UseTab: ForIndentation # use tabs for indentation, spaces for alignment +UseTab: Always # use tabs for indentation, spaces for alignment ContinuationIndentWidth: 8 BreakBeforeBraces: Attach -ColumnLimit: 100 +ColumnLimit: 150 AllowShortIfStatementsOnASingleLine: true AllowShortFunctionsOnASingleLine: true PointerAlignment: Left SpaceBeforeParens: ControlStatements -AlignConsecutiveAssignments: Consecutive -AlignConsecutiveDeclarations: None +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: true +AlignConsecutiveMacros: true BinPackArguments: false BinPackParameters: false Cpp11BracedListStyle: true diff --git a/.clangd b/.clangd index e308436..b9e3cdd 100644 --- a/.clangd +++ b/.clangd @@ -1,6 +1,6 @@ CompileFlags: Add: - - "-std=c++17" + - "-std=c++23" - "-Wall" - "-Wextra" - "-Wpedantic" diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000..166c638 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,43 @@ +name: clang-format + +on: + push: + pull_request: + +jobs: + clang-format: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref || github.ref_name }} + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Install clang-format + run: | + sudo apt-get update + sudo apt-get install -y clang-format + + - name: Run clang-format + run: | + find . -name '*.cpp' -o -name '*.h' -o -name '*.c' -o -name '*.hpp' -o -name '*.cc' -o -name '*.cxx' \ + | grep -v "include/lib/json.hpp" \ + | xargs clang-format -i --style=file + + - name: Commit and push changes + run: | + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + + if ! git diff --quiet; then + git add -A + git commit -m "Apply clang-format [skip ci]" + git push + echo "Code formatted and pushed" + else + echo "No formatting changes needed" + fi diff --git a/.github/workflows/verif-build.yml b/.github/workflows/verif-build.yml deleted file mode 100644 index d21eb7c..0000000 --- a/.github/workflows/verif-build.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: C/C++ CI - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: make - run: make diff --git a/.gitignore b/.gitignore index a92ec07..bb837ff 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ compile_commands.json .cache .vscode logs + +# Test server directory +test-server diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..f495b05 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "data-generator"] + path = data-generator + url = https://github.com/Random-stuff-unlimited/data-generator.git diff --git a/Makefile b/Makefile index af546ad..24ed34c 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ INCLUDE_FLAGS := -I$(INCLUDE_DIR) # Linker flags (add your libraries here) LDFLAGS := -LIBS := +LIBS := -lz # ================================ COLOR SETUP =============================== # ANSI color codes for beautiful output @@ -82,7 +82,7 @@ else endif # ================================= TARGETS ================================== -.PHONY: all clean debug release info help run install uninstall compile_commands +.PHONY: all clean distclean clean-test debug release info help run install uninstall compile_commands # Default target all: info $(TARGET) @@ -129,14 +129,44 @@ $(DEPS_DIR): # Clean build artifacts clean: @printf "$(BOLD)$(BRIGHT_RED)🧹 Cleaning build artifacts...$(RESET)\n" + @find $(BUILD_DIR) -type f -name "*.o" -delete 2>/dev/null || true + @find $(BUILD_DIR) -name "$(TARGET_NAME)" -delete 2>/dev/null || true + @find $(BUILD_DIR) -type d -empty -delete 2>/dev/null || true + @find $(DEPS_DIR) -type f -name "*.d" -delete 2>/dev/null || true + @find $(DEPS_DIR) -type d -empty -delete 2>/dev/null || true + @printf "$(BOLD)$(BRIGHT_GREEN)✨ Clean completed! (Preserved directories and config.json)$(RESET)\n" + +# Complete clean - removes everything including directories +distclean: + @printf "$(BOLD)$(BRIGHT_RED)🧹 Complete cleanup (removing all build artifacts and directories)...$(RESET)\n" @rm -rf $(BUILD_DIR) $(DEPS_DIR) - @printf "$(BOLD)$(BRIGHT_GREEN)✨ Clean completed!$(RESET)\n" + @printf "$(BOLD)$(BRIGHT_GREEN)✨ Complete cleanup finished!$(RESET)\n" + +# Clean test-server directory +clean-test: + @printf "$(BOLD)$(BRIGHT_RED)🧹 Cleaning test-server directory...$(RESET)\n" + @rm -rf test-server + @printf "$(BOLD)$(BRIGHT_GREEN)✨ Test-server cleanup finished!$(RESET)\n" # Run the executable run: $(TARGET) + @printf "$(BOLD)$(BRIGHT_MAGENTA)πŸš€ Setting up test-server environment...$(RESET)\n" + @mkdir -p test-server + @printf "$(BOLD)$(BRIGHT_BLUE)πŸ“¦ Copying executable to test-server...$(RESET)\n" + @cp $(TARGET) test-server/$(TARGET_NAME) + @printf "$(BOLD)$(BRIGHT_BLUE)πŸ“¦ Copying config.json to test-server...$(RESET)\n" + @cp -f config.json test-server/ 2>/dev/null || printf "$(YELLOW)⚠️ config.json not found, skipping...$(RESET)\n" + @printf "$(BOLD)$(BRIGHT_BLUE)πŸ“¦ Copying world folder to test-server...$(RESET)\n" + @if [ -d "world" ]; then \ + cp -r world test-server/; \ + printf "$(BOLD)$(BRIGHT_GREEN)βœ… World folder copied successfully!$(RESET)\n"; \ + else \ + printf "$(YELLOW)⚠️ World folder not found, skipping...$(RESET)\n"; \ + fi + @printf "$(BOLD)$(BRIGHT_GREEN)βœ… Test environment ready!$(RESET)\n" @printf "$(BOLD)$(BRIGHT_MAGENTA)πŸš€ Running $(TARGET_NAME)...$(RESET)\n" @printf "$(DIM)$(WHITE)" && echo "================================================" && printf "$(RESET)" - @./$(TARGET) + @cd test-server && ./$(TARGET_NAME) @printf "$(DIM)$(WHITE)" && echo "================================================" && printf "$(RESET)" # Display project information @@ -190,8 +220,10 @@ help: @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "all" "Build the project (default: release mode)" @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "debug" "Build in debug mode" @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "release" "Build in release mode" - @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "clean" "Remove all build artifacts" - @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "run" "Build and run the executable" + @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "clean" "Remove build artifacts (preserve dirs)" + @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "distclean" "Remove all build artifacts and dirs" + @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "clean-test" "Remove test-server directory" + @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "run" "Setup test-server and run executable" @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "compile_commands" "Generate compile_commands.json for LSP" @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "install" "Install the executable to system" @printf "$(BOLD)$(BRIGHT_CYAN)β•‘$(RESET) $(BRIGHT_GREEN)%-10s$(RESET) %-39s $(BOLD)$(BRIGHT_CYAN) β•‘$(RESET)\n" "uninstall" "Remove the executable from system" diff --git a/config.json b/config.json index 27204e7..6e2b30b 100644 --- a/config.json +++ b/config.json @@ -1,12 +1,17 @@ { - "version": { - "name": "1.21.5", - "protocol": 770 - }, - "server": { - "ip-address": "127.0.0.1", - "port": 25565, - "motd": "Β§aServeur Minecraft en C!", - "max-players": 20 - } + "version": { + "name": "1.21.5", + "protocol": 770 + }, + "server": { + "ip-address": "127.0.0.1", + "port": 25565, + "motd": "Β§aServeur Minecraft en C!", + "max-players": 20 + }, + "world": { + "name": "world", + "gamemode": "survival", + "difficulty": "normal" + } } diff --git a/data-generator b/data-generator new file mode 160000 index 0000000..ab45d37 --- /dev/null +++ b/data-generator @@ -0,0 +1 @@ +Subproject commit ab45d37535cfab95b2c6d340b7c4f9a14ff45a82 diff --git a/ideas/console-log.md b/ideas/console-log.md deleted file mode 100644 index 03b823d..0000000 --- a/ideas/console-log.md +++ /dev/null @@ -1,33 +0,0 @@ -# Console Idea - -### Console Section -- **Server Control**: Start, stop, restart server -- **Player Management**: Kick, ban, whitelist players, view player list, view player info -- **World Management**: Load, save, backup world data -- **Configuration**: Modify server settings on runtime -- **Logging section**: View and filter server logs (network, chat, game info (Filter for warning / error)) - -### Console Architecture -``` -ConsoleManager -β”œβ”€β”€ ServerControl -β”œβ”€β”€ PlayerManagement - β”œβ”€β”€ player list - β”œβ”€β”€ player info / Kick / Ban / Whitelist - β”œβ”€β”€ add player to Whitelist (if enabled) -β”œβ”€β”€ WorldManagement (soon) - β”œβ”€β”€ world list - β”œβ”€β”€ world info / Load / Save / Backup - β”œβ”€β”€ world info -β”œβ”€β”€ Configuration (soon) - β”œβ”€β”€ config list - β”œβ”€β”€ config info / Load / Save / Backup -β”œβ”€β”€ LoggingSection - β”œβ”€β”€ log network / all / chat / gameinfo - β”œβ”€β”€ filter (error / warning / info) -``` - -# Logging Idea - -1 file network (all error / warning / info) -1 file gameinfo (all error / warning / info) diff --git a/include/buffer.hpp b/include/buffer.hpp deleted file mode 100644 index 42c7d4a..0000000 --- a/include/buffer.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef BUFFER_HPP -#define BUFFER_HPP - -#include "UUID.hpp" - -#include -#include -#include -#include - -class Buffer { - private: - std::vector _data; - size_t _pos; - - public: - Buffer(); - explicit Buffer(const std::vector& data); - - int readVarInt(); - void writeVarInt(int value); - void writeInt(int32_t value); - void writeIdentifierArray(const std::vector& ids); - void writeUInt(uint32_t value); - - std::string readString(int maxLength); - void writeString(const std::string& str); - - std::vector& getData(); - size_t remaining() const; - uint16_t readUShort(); - uint64_t readUInt64(); - long readLong(); - void writeLong(long value); - uint8_t readByte(); - void writeByte(uint8_t byte); - void writeBytes(const std::string& data); - void writeBytes(const std::vector& data); - void writeUUID(const UUID& uuid); - - void writeBool(bool value); - void writeNBT(const std::string& nbtData); - void writePosition(int32_t x, int32_t y, int32_t z); - void writeFloat(float value); - void writeDouble(double value); - void writeIdentifier(const std::string& id); - void writeVarLong(int64_t value); -}; - -#endif diff --git a/include/config.hpp b/include/config.hpp new file mode 100644 index 0000000..5b022a7 --- /dev/null +++ b/include/config.hpp @@ -0,0 +1,53 @@ +#ifndef CONFIG_HPP +#define CONFIG_HPP + +#include +#include + +class Config { + private: + std::filesystem::path _execPath; + + // Version Config + std::string _gameVersion; + int _protocolVersion; + + // Server Config + std::string _serverMotd; + std::string _serverAddress; + int _serverPort; + int _serverSize; + + // World Config + std::string _worldName; + std::string _gamemode; + std::string _difficulty; + + public: + Config(); + ~Config(); + bool loadConfig(); + bool reloadConfig(); + + int getServerPort(); + int getProtocolVersion(); + int getServerSize(); + std::string getVersion(); + std::string getServerMotd(); + std::string getServerAddress(); + std::string getWorldName(); + std::string getGamemode(); + std::string getDifficulty(); + + void setProtocolVersion(int ProtoVersion); + void setServerSize(int ServerSize); + void setServerPort(int ServerPort); + void setServerMotd(std::string ServerMotd); + void setServerVersion(std::string ServerVersion); + void setServerAddress(std::string ServerAddress); + void setWorldName(std::string WorldName); + void setGamemode(std::string Gamemode); + void setDifficulty(std::string Difficulty); +}; + +#endif diff --git a/include/MD5.hpp b/include/lib/MD5.hpp similarity index 100% rename from include/MD5.hpp rename to include/lib/MD5.hpp diff --git a/include/UUID.hpp b/include/lib/UUID.hpp similarity index 73% rename from include/UUID.hpp rename to include/lib/UUID.hpp index e5599e1..cd8f823 100644 --- a/include/UUID.hpp +++ b/include/lib/UUID.hpp @@ -19,13 +19,13 @@ class UUID { uint64_t getMostSigBits() const; uint64_t getLeastSigBits() const; - void setMostSigBits(uint64_t val); - void setLeastSigBits(uint64_t val); + void setMostSigBits(uint64_t val); + void setLeastSigBits(uint64_t val); std::string toString() const; - void readFromBuffer(Buffer& buf); - void writeToBuffer(Buffer& buf) const; + void readFromBuffer(Buffer& buf); + void writeToBuffer(Buffer& buf) const; static UUID fromOfflinePlayer(const std::string& name); }; diff --git a/include/lib/filesystem.hpp b/include/lib/filesystem.hpp new file mode 100644 index 0000000..fd165e9 --- /dev/null +++ b/include/lib/filesystem.hpp @@ -0,0 +1,8 @@ +#ifndef FS_H +#define FS_H + +#include + +std::filesystem::path getPath(); + +#endif diff --git a/include/json.hpp b/include/lib/json.hpp similarity index 100% rename from include/json.hpp rename to include/lib/json.hpp diff --git a/include/nbt.hpp b/include/lib/nbt.hpp similarity index 63% rename from include/nbt.hpp rename to include/lib/nbt.hpp index 4ba4a90..11f4d22 100644 --- a/include/nbt.hpp +++ b/include/lib/nbt.hpp @@ -12,62 +12,59 @@ Compatible with older C++ compilers #endif #include -#include #include +#include #include #include #include #include #include #include -#include // Compatibility implementations for GCC 10.5 #if __cpp_lib_byteswap < 202110L namespace std { - template - constexpr T byteswap(T value) noexcept { - static_assert(std::is_integral_v, "byteswap requires integral type"); - if constexpr (sizeof(T) == 1) { - return value; - } else if constexpr (sizeof(T) == 2) { - return __builtin_bswap16(value); - } else if constexpr (sizeof(T) == 4) { - return __builtin_bswap32(value); - } else if constexpr (sizeof(T) == 8) { - return __builtin_bswap64(value); - } - } -} + template constexpr T byteswap(T value) noexcept { + static_assert(std::is_integral_v, "byteswap requires integral type"); + if constexpr (sizeof(T) == 1) { + return value; + } else if constexpr (sizeof(T) == 2) { + return __builtin_bswap16(value); + } else if constexpr (sizeof(T) == 4) { + return __builtin_bswap32(value); + } else if constexpr (sizeof(T) == 8) { + return __builtin_bswap64(value); + } + } +} // namespace std #endif #if __cpp_lib_bit_cast < 201806L namespace std { - template - constexpr To bit_cast(const From& src) noexcept { - static_assert(sizeof(To) == sizeof(From), "bit_cast requires same size types"); - static_assert(std::is_trivially_copyable_v, "bit_cast requires trivially copyable To type"); - static_assert(std::is_trivially_copyable_v, "bit_cast requires trivially copyable From type"); - To dst; - std::memcpy(&dst, &src, sizeof(To)); - return dst; - } -} + template constexpr To bit_cast(const From& src) noexcept { + static_assert(sizeof(To) == sizeof(From), "bit_cast requires same size types"); + static_assert(std::is_trivially_copyable_v, "bit_cast requires trivially copyable To type"); + static_assert(std::is_trivially_copyable_v, "bit_cast requires trivially copyable From type"); + To dst; + std::memcpy(&dst, &src, sizeof(To)); + return dst; + } +} // namespace std #endif namespace nbt { // Basic NBT types - typedef std::nullptr_t TagEnd; - typedef std::int8_t TagByte; - typedef std::int16_t TagShort; - typedef std::int32_t TagInt; - typedef std::int64_t TagLong; - typedef float TagFloat; - typedef double TagDouble; - typedef std::string TagString; + typedef std::nullptr_t TagEnd; + typedef std::int8_t TagByte; + typedef std::int16_t TagShort; + typedef std::int32_t TagInt; + typedef std::int64_t TagLong; + typedef float TagFloat; + typedef double TagDouble; + typedef std::string TagString; typedef std::vector TagByteArray; - typedef std::vector TagIntArray; + typedef std::vector TagIntArray; typedef std::vector TagLongArray; // Forward declaration for recursive types @@ -78,19 +75,19 @@ namespace nbt { // Tag variant - using struct to avoid forward declaration issues struct Tag { std::variant, - std::shared_ptr, - TagIntArray, - TagLongArray> - data; + TagByte, + TagShort, + TagInt, + TagLong, + TagFloat, + TagDouble, + TagByteArray, + TagString, + std::shared_ptr, + std::shared_ptr, + TagIntArray, + TagLongArray> + data; // Constructors Tag() : data(TagEnd{}) {} @@ -166,11 +163,11 @@ namespace nbt { }; // Helper functions for creating tags - inline TagByte createByte(std::int8_t value) { return value; } - inline TagShort createShort(std::int16_t value) { return value; } - inline TagInt createInt(std::int32_t value) { return value; } - inline TagLong createLong(std::int64_t value) { return value; } - inline TagFloat createFloat(float value) { return value; } + inline TagByte createByte(std::int8_t value) { return value; } + inline TagShort createShort(std::int16_t value) { return value; } + inline TagInt createInt(std::int32_t value) { return value; } + inline TagLong createLong(std::int64_t value) { return value; } + inline TagFloat createFloat(float value) { return value; } inline TagDouble createDouble(double value) { return value; } inline TagString createString(const std::string& value) { return value; } @@ -185,10 +182,10 @@ namespace nbt { NBT(const std::string& name) : name(name) {} NBT(const std::string& name, const TagCompound& tags) : name(name), root(tags) {} - void setName(const std::string& n) { name = n; } + void setName(const std::string& n) { name = n; } std::string getName() const { return name; } - TagCompound& getRoot() { return root; } + TagCompound& getRoot() { return root; } const TagCompound& getRoot() const { return root; } void encode(std::ostream& os) const { root.encode(os); } diff --git a/include/lib/nbtParser.hpp b/include/lib/nbtParser.hpp new file mode 100644 index 0000000..6fe258a --- /dev/null +++ b/include/lib/nbtParser.hpp @@ -0,0 +1,34 @@ +#ifndef NBT_PARSER_HPP +#define NBT_PARSER_HPP + +#include "lib/nbt.hpp" + +#include +#include +#include +#include + +namespace nbt { + + // NBT binary parser for Minecraft's Named Binary Tag format. + // This class parses a binary NBT buffer into the simplified NBT model in lib/nbt.hpp. + class Parser { + public: + Parser() = default; + + // Parse an NBT payload (binary) into an NBT object. + // Expects the data to start with a root tag type and name. + NBT parse(const std::vector& data); + + private: + // Helper utilities for decoding the binary stream (big-endian). + template T read(const std::vector& data, size_t& cursor); + std::string parseTagName(const std::vector& data, size_t& cursor); + TagCompound parseCompound(const std::vector& data, size_t& cursor); + TagList parseList(const std::vector& data, size_t& cursor); + Tag parseTag(const std::vector& data, size_t& cursor, uint8_t tagType); + }; + +} // namespace nbt + +#endif // NBT_PARSER_HPP diff --git a/include/logger.hpp b/include/logger.hpp index 9855387..fb9c778 100644 --- a/include/logger.hpp +++ b/include/logger.hpp @@ -1,6 +1,6 @@ #pragma once #ifndef LOGGER_HPP -# define LOGGER_HPP +#define LOGGER_HPP #include #include #include @@ -15,39 +15,35 @@ enum LogCategory { NETWORK, GAMEINFO }; struct LogEntry { std::chrono::system_clock::time_point timestamp; - LogLevel level; - LogCategory category; - std::string message; - std::string source; + LogLevel level; + LogCategory category; + std::string message; + std::string source; }; class LogManager { private: std::filesystem::path _logDir; - std::ofstream _networkFile; - std::ofstream _gameInfoFile; - std::queue _logQueue; - std::mutex _queueMutex; - std::mutex _fileMutex; - std::thread _writerThread; - bool _running; - + std::ofstream _networkFile; + std::ofstream _gameInfoFile; + std::queue _logQueue; + std::mutex _queueMutex; + std::mutex _fileMutex; + std::thread _writerThread; + bool _running; public: LogManager(); ~LogManager(); // Core logging methods - void log(LogLevel level, - LogCategory category, - const std::string& message, - const std::string& source = ""); + void log(LogLevel level, LogCategory category, const std::string& message, const std::string& source = ""); void logNetwork(LogLevel level, const std::string& message, const std::string& source = ""); void logGameInfo(LogLevel level, const std::string& message, const std::string& source = ""); private: - bool initializeLogDirectory(); - void writerThreadLoop(); + bool initializeLogDirectory(); + void writerThreadLoop(); std::string formatLogEntry(const LogEntry& entry); std::string getCurrentTimestamp(); std::string getDetailedTimestamp(); @@ -55,5 +51,5 @@ class LogManager { // Global logger instance extern std::unique_ptr g_logger; -void initializeGlobalLogger(); +void initializeGlobalLogger(); #endif diff --git a/include/network/buffer.hpp b/include/network/buffer.hpp new file mode 100644 index 0000000..c55a28c --- /dev/null +++ b/include/network/buffer.hpp @@ -0,0 +1,50 @@ +#ifndef BUFFER_HPP +#define BUFFER_HPP + +#include "lib/UUID.hpp" + +#include +#include +#include +#include + +class Buffer { + private: + std::vector _data; + size_t _pos; + + public: + Buffer(); + explicit Buffer(const std::vector& data); + + int readVarInt(); + void writeVarInt(int value); + void writeInt(int32_t value); + void writeIdentifierArray(const std::vector& ids); + void writeUInt(uint32_t value); + + std::string readString(int maxLength); + void writeString(const std::string& str); + + std::vector& getData(); + size_t remaining() const; + uint16_t readUShort(); + uint64_t readUInt64(); + long readLong(); + void writeLong(long value); + uint8_t readByte(); + void writeByte(uint8_t byte); + void writeBytes(const std::string& data); + void writeBytes(const std::vector& data); + void writeUUID(const UUID& uuid); + + void writeBool(bool value); + void writeNBT(const std::string& nbtData); + void writePosition(int32_t x, int32_t y, int32_t z); + void writeFloat(float value); + void writeDouble(double value); + void writeIdentifier(const std::string& id); + void writeVarLong(int64_t value); +}; + +#endif diff --git a/include/id_manager.hpp b/include/network/id_manager.hpp similarity index 67% rename from include/id_manager.hpp rename to include/network/id_manager.hpp index 912ceef..39ade0b 100644 --- a/include/id_manager.hpp +++ b/include/network/id_manager.hpp @@ -8,7 +8,7 @@ class IdManager { private: - uint32_t _nextId; + uint32_t _nextId; std::set _freedIds; mutable std::mutex _mutex; @@ -17,10 +17,10 @@ class IdManager { ~IdManager(); uint32_t allocate(); - void release(uint32_t id); - size_t getAllocatedCount() const; - size_t getFreedCount() const; - void reset(); + void release(uint32_t id); + size_t getAllocatedCount() const; + size_t getFreedCount() const; + void reset(); }; #endif diff --git a/include/networking.hpp b/include/network/networking.hpp similarity index 70% rename from include/networking.hpp rename to include/network/networking.hpp index e1e7bd9..5025183 100644 --- a/include/networking.hpp +++ b/include/network/networking.hpp @@ -1,27 +1,27 @@ #ifndef NETWORKING_HPP #define NETWORKING_HPP -#include "UUID.hpp" +#include "../player.hpp" +#include "lib/UUID.hpp" #include "packet.hpp" -#include "player.hpp" // Forward declaration to avoid circular dependency class Server; #include #include #include +#include #include #include #include #include #include #include -#include template class ThreadSafeQueue { private: - std::queue _queue; - mutable std::mutex _mutex; + std::queue _queue; + mutable std::mutex _mutex; std::condition_variable _condition; public: @@ -33,8 +33,7 @@ template class ThreadSafeQueue { bool tryPop(T& item) { std::lock_guard lock(_mutex); - if (_queue.empty()) - return false; + if (_queue.empty()) return false; item = std::move(_queue.front()); _queue.pop(); @@ -72,18 +71,18 @@ class NetworkManager { ThreadSafeQueue _outgoingPackets; std::vector _workerThreads; - std::atomic _shutdownFlag; - std::thread _receiverThread; - std::thread _senderThread; - char _receiverThreadInit; - char _senderThreadInit; - Server& _server; - int _epollFd; - int _serverSocket; + std::atomic _shutdownFlag; + std::thread _receiverThread; + std::thread _senderThread; + char _receiverThreadInit; + char _senderThreadInit; + Server& _server; + int _epollFd; + int _serverSocket; public: - NetworkManager(size_t worker_count, - Server& s); // Could use std::thread::hardware_concurrency() for the worker size; + NetworkManager(size_t worker_count, + Server& s); // Could use std::thread::hardware_concurrency() for the worker size; ~NetworkManager() { if (_epollFd != -1) { close(_epollFd); @@ -95,12 +94,11 @@ class NetworkManager { void stopThreads(); void shutdown(); - void addPlayerConnection(std::shared_ptr connection); - void removePlayerConnection(UUID id); + void addPlayerConnection(std::shared_ptr connection); + void removePlayerConnection(UUID id); + ThreadSafeQueue* getOutgoingQueue() { return &_outgoingPackets; } - Server& getServer() { - return _server; - } + Server& getServer() { return _server; } void enqueueOutgoingPacket(Packet* p); @@ -114,23 +112,23 @@ class NetworkManager { void handleIncomingData(int socket); }; -void packetRouter(Packet* packet, Server& server, ThreadSafeQueue* _outgoingPackets); +void packetRouter(Packet* packet, Server& server); void handleHandshakePacket(Packet& packet, Server& server); void handleStatusPacket(Packet& packet, Server& server); void handlePingPacket(Packet& packet, Server& server); -void handleClientInformation(Packet& packet, Server &server); +void handleClientInformation(Packet& packet, Server& server); void handleLoginStartPacket(Packet& packet, Server& server); void handleLoginAcknowledged(Packet& packet, Server& server); void handleCookieRequest(Packet& packet, Server& server); void handleFinishConfiguration(Packet& packet, Server& server); void handleAcknowledgeFinishConfiguration(Packet& packet, Server& server); -void writePlayPacket(Packet& packet, Server& server); +void writePlayPacket(Packet& packet); void writeSetCenterPacket(Packet& packet, Server& server); // Chunk batch functions void sendChunkBatchStart(Packet& packet, Server& server); void sendChunkBatchFinished(Packet& packet, Server& server, int batchSize); -void sendChunkBatchSequence(Packet& packet, Server& server, ThreadSafeQueue* outgoingPackets); +void sendChunkBatchSequence(Packet& packet, Server& server); // Chunk data functions void sendChunkData(Packet& packet, Server& server, int chunkX, int chunkZ); @@ -144,6 +142,12 @@ void sendSetExperience(Packet& packet, Server& server); void sendUpdateTime(Packet& packet, Server& server); void sendSetHeldItem(Packet& packet, Server& server); void handleConfirmTeleportation(Packet& packet, Server& server); -void completeSpawnSequence(Packet& packet, Server& server, ThreadSafeQueue* outgoingPackets); +void completeSpawnSequence(Packet& packet, Server& server); +void sendDisconnectPacket(Packet* packet, const std::string& reason, Server& server); + +Buffer generateEmptyChunkSections(); +void writeLightData(Buffer& buf, const World::ChunkData& chunkData); +void writeActualLightData(Buffer& buf, const World::ChunkData& chunkData); +void writeEmptyLightData(Buffer& buf); #endif diff --git a/include/packet.hpp b/include/network/packet.hpp similarity index 51% rename from include/packet.hpp rename to include/network/packet.hpp index 280d68d..b344acd 100644 --- a/include/packet.hpp +++ b/include/network/packet.hpp @@ -1,11 +1,12 @@ #ifndef PACKET_HPP #define PACKET_HPP +#include "../player.hpp" #include "buffer.hpp" -#include "player.hpp" #include "server.hpp" #include +#include enum PacketResult { PACKET_OK = 0, PACKET_SEND = 1, PACKET_DISCONNECT = 2, PACKET_ERROR = -1 }; @@ -13,10 +14,10 @@ class Packet { private: int32_t _size; int32_t _id; - Buffer _data; + Buffer _data; Player* _player; - int _socketFd; - int _returnPacket; + int _socketFd; + int _returnPacket; public: Packet(Player* player); @@ -24,21 +25,21 @@ class Packet { Packet(const Packet& other); Packet& operator=(const Packet& other); ~Packet(); - static int readVarint(int sock); - static int readVarint(int sock, int* bytesRead); + static int readVarint(int sock); + static int readVarint(int sock, int* bytesRead); static void writeVarint(int sock, int value); - static int varintLen(int value); + static int varintLen(int value); static bool isSocketValid(int sock); - Player* getPlayer() const; - uint32_t getSize(); - uint32_t getId(); - Buffer& getData(); - int getSocket() const; - void setReturnPacket(int value); - int getReturnPacket(); - int getVarintSize(int32_t value); - void setPacketSize(int32_t value); - void setPacketId(uint32_t value); + Player* getPlayer() const; + uint32_t getSize(); + uint32_t getId(); + Buffer& getData(); + int getSocket() const; + void setReturnPacket(int value); + int getReturnPacket(); + int getVarintSize(int32_t value); + void setPacketSize(int32_t value); + void setPacketId(uint32_t value); }; #endif diff --git a/include/network/server.hpp b/include/network/server.hpp new file mode 100644 index 0000000..a12f5ec --- /dev/null +++ b/include/network/server.hpp @@ -0,0 +1,58 @@ +#ifndef SERVER_HPP +#define SERVER_HPP + +class NetworkManager; +#include "../config.hpp" +#include "../player.hpp" +#include "../world/world.hpp" +#include "id_manager.hpp" +#include "lib/json.hpp" + +#include +#include +#include +#include + +using json = nlohmann::json; + +class Server { + private: + std::unordered_map _playerLst; + std::unordered_map _tempPlayerLst; + json _playerSample; + std::mutex _playerLock; + std::mutex _tempPlayerLock; + Config _config; + NetworkManager* _networkManager; + IdManager _idManager; + World::Manager _worldManager; + World::LevelDat _worldData; + + public: + Server(); + ~Server(); + + int start_server(); + + int getAmountOnline(); + Config& getConfig() { return _config; } + std::unordered_map& getPlayerLst() { return _playerLst; } + std::unordered_map& getTempPlayerLst() { return _tempPlayerLst; } + + void addPlayerToSample(const std::string& name); + void removePlayerToSample(const std::string& name); + Player* addPlayer(const std::string& name, const PlayerState state, const int socket); + void removePlayer(Player* player); + Player* addTempPlayer(const std::string& name, const PlayerState state, const int socket); + void removeTempPlayer(Player* player); + void promoteTempPlayer(Player* player); + void removePlayerFromAnyList(Player* player); + json getPlayerSample(); + IdManager& getIdManager() { return (_idManager); } + + NetworkManager& getNetworkManager() { return *_networkManager; } + World::Manager& ManagManagererWorldManager() { return _worldManager; } + World::LevelDat& getWorldData() { return _worldData; } +}; + +#endif diff --git a/include/player.hpp b/include/player.hpp index 8e1b7ec..a868e13 100644 --- a/include/player.hpp +++ b/include/player.hpp @@ -1,38 +1,38 @@ #ifndef PLAYER_HPP #define PLAYER_HPP -#include "UUID.hpp" +#include "lib/UUID.hpp" -#include #include +#include class Server; -enum class PlayerState { None, Configuration ,Handshake, Status, Login, Play }; +enum class PlayerState { None, Configuration, Handshake, Status, Login, Play }; class PlayerConfig { private: - int _chatMode; - int _mainHand; + int _chatMode; + int _mainHand; std::string _locale; - uint8_t _viewDistance; - uint8_t _displayedSkinParts; - bool _chatColors; - bool _enableTextFiltering; - bool _allowServerListings; + uint8_t _viewDistance; + uint8_t _displayedSkinParts; + bool _chatColors; + bool _enableTextFiltering; + bool _allowServerListings; public: PlayerConfig(); ~PlayerConfig(); // Getters - int getChatMode() const { return _chatMode; } - int getMainHand() const { return _mainHand; } + int getChatMode() const { return _chatMode; } + int getMainHand() const { return _mainHand; } std::string getLocale() const { return _locale; } - uint8_t getViewDistance() const { return _viewDistance; } - uint8_t getDisplayedSkinParts() const { return _displayedSkinParts; } - bool getChatColors() const { return _chatColors; } - bool getTextFiltering() const { return _enableTextFiltering; } - bool getServerListings() const { return _allowServerListings; } + uint8_t getViewDistance() const { return _viewDistance; } + uint8_t getDisplayedSkinParts() const { return _displayedSkinParts; } + bool getChatColors() const { return _chatColors; } + bool getTextFiltering() const { return _enableTextFiltering; } + bool getServerListings() const { return _allowServerListings; } // Setters void setChatMode(int mode) { _chatMode = mode; } @@ -47,14 +47,14 @@ class PlayerConfig { class Player { private: - std::string _name; - PlayerState _state; - int _socketFd; - int x, y, z; - int health; - UUID _uuid; - int _playerId; - Server& _server; + std::string _name; + PlayerState _state; + int _socketFd; + int x, y, z; + int health; + UUID _uuid; + int _playerId; + Server& _server; PlayerConfig* _config; public: @@ -64,16 +64,16 @@ class Player { ~Player(); std::string getPlayerName(void); - void setPlayerName(const std::string& name); + void setPlayerName(const std::string& name); PlayerState getPlayerState(); - void setPlayerState(PlayerState state); - void setSocketFd(int socket); - int getSocketFd() const; + void setPlayerState(PlayerState state); + void setSocketFd(int socket); + int getSocketFd() const; // Get PlayerConfig instance PlayerConfig* getPlayerConfig() { return _config; } - int getPlayerID() const; - void setUUID(UUID uuid); + int getPlayerID() const; + void setUUID(UUID uuid); }; #endif diff --git a/include/server.hpp b/include/server.hpp deleted file mode 100644 index 41d2efc..0000000 --- a/include/server.hpp +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef SERVER_HPP -#define SERVER_HPP - -class NetworkManager; -#include "id_manager.hpp" -#include "json.hpp" -#include "player.hpp" - -#include -#include -#include -#include -#define ConfigFileName "config.json" - -using json = nlohmann::json; - -class Server { - private: - std::unordered_map _playerLst; - std::unordered_map _tempPlayerLst; - json _playerSample; - std::mutex _playerLock; - std::mutex _tempPlayerLock; - int _protocolVersion; - int _serverSize; - int loadConfig(); - std::string _gameVersion; - std::string _serverMOTD; - int _serverPort; - std::string _serverAddr; - NetworkManager* _networkManager; - IdManager _idManager; - - public: - Server(); - ~Server(); - - int start_server(); - - int getProtocolVersion(); - int getServerSize(); - int getAmountOnline(); - std::string getGameVersion(); - std::string getServerMOTD(); - int getServerPort() { - return _serverPort; - } - std::string getServerAddr() { - return _serverAddr; - } - std::unordered_map& getPlayerLst() { - return _playerLst; - } - std::unordered_map& getTempPlayerLst() { - return _tempPlayerLst; - } - - void addPlayerToSample(const std::string& name); - void removePlayerToSample(const std::string& name); - Player* addPlayer(const std::string& name, const PlayerState state, const int socket); - void removePlayer(Player* player); - Player* addTempPlayer(const std::string& name, const PlayerState state, const int socket); - void removeTempPlayer(Player* player); - void promoteTempPlayer(Player* player); - void removePlayerFromAnyList(Player* player); - json getPlayerSample(); - IdManager& getIdManager() { - return (_idManager); - } - - NetworkManager& getNetworkManager() { - return *_networkManager; - } -}; - -#endif diff --git a/include/world/world.hpp b/include/world/world.hpp new file mode 100644 index 0000000..59d48a0 --- /dev/null +++ b/include/world/world.hpp @@ -0,0 +1,120 @@ +#ifndef WORLD_MANAGER_HPP +#define WORLD_MANAGER_HPP + +#include "lib/nbt.hpp" +#include "logger.hpp" + +#include +#include +#include +#include +#include +#include + +namespace World { + + struct LevelDat { // see https://minecraft.wiki/w/Java_Edition_level_format#level.dat_format + // Existing fields + bool allowCommands; + double BorderCenterX; + double BorderCenterY; + double BorderDamagePerBlock; + double BorderSafeZone; + long BorderSizeLerpTarget; + double BorderWarningBlocks; + double BorderWarningTime; + int clearWeatherTime; + int DataVersion; + long DayTime; + std::byte Difficulty; + bool DifficultyLocked; + int GameType; + std::string generatorName; + int generatorVersiona; + bool hardcore; + bool initialized; + long LastPlayed; + std::string LevelName; + bool MapFeatures; + bool raining; + int rainTime; + long RandomSeed; + long SizeOnDisk; + int SpawnX; + int SpawnY; + int SpawnZ; + bool thundering; + int thunderTime; + long Time; + int version; + int WanderingTraderSpawnChange; + int WanderingTraderSpawnDelay; + bool WasModded; + + // The full NBT data, for accessing less common or custom tags + nbt::NBT nbtData; + }; + + struct ChunkData { + int chunkX; + int chunkZ; + + std::vector blockData; + std::vector biomeData; + std::vector heightmaps; + std::vector blockEntities; + + std::vector skyLight; + std::vector blockLight; + + ChunkData(int x, int z) : chunkX(x), chunkZ(z) {} + + bool isEmpty() const { return blockData.empty(); } + }; + + class Manager { + public: + static std::vector decompressGzip(std::filesystem::path compressedFilePath); + static std::vector decompressGzip(const std::vector& compressedData); + static std::vector decompressZlib(const std::vector& compressedData); + static std::filesystem::path locateRegionFileByChunkCoord(int ChunkX, int ChunkZ); + LevelDat loadLevelDat(std::filesystem::path levelDatPath); + + private: + LevelDat _LevelDat; + }; + + class Query { + public: + ChunkData fetchChunk(int chunkX, int chunkZ) { + ChunkData chunk(chunkX, chunkZ); + + try { + auto regionPath = World::Manager::locateRegionFileByChunkCoord(chunkX, chunkZ); + chunk = loadChunkFromRegion(regionPath, chunkX, chunkZ); + } catch (const std::exception& e) { + g_logger->logGameInfo(DEBUG, + "Chunk (" + std::to_string(chunkX) + ", " + std::to_string(chunkZ) + + ") not found, sending empty chunk: " + e.what(), + "World::Query::fetchChunk"); + chunk = generateEmptyChunk(chunkX, chunkZ); + } + + return chunk; + } + + private: + private: + void extractChunkDataFromNBT(const nbt::NBT& chunkNBT, ChunkData& chunk); + void extractSectionsData(const nbt::TagList& sections, ChunkData& chunk); + void extractBlockStatesFromSection(const nbt::TagCompound& blockStates, ChunkData& chunk, int8_t sectionY); + void extractHeightmaps(const nbt::TagCompound& heightmaps, ChunkData& chunk); + void extractBlockEntities(const nbt::TagList& blockEntities, ChunkData& chunk); + void extractBiomesFromSections(const nbt::TagCompound& root, ChunkData& chunk); + ChunkData generateEmptyChunk(int chunkX, int chunkZ); + ChunkData loadChunkFromRegion(const std::filesystem::path& regionPath, int chunkX, int chunkZ); + }; + +} // namespace World + +#endif diff --git a/src/entities/player.cpp b/src/entities/player.cpp new file mode 100644 index 0000000..2f6944a --- /dev/null +++ b/src/entities/player.cpp @@ -0,0 +1,54 @@ +#include "player.hpp" + +#include "lib/UUID.hpp" +#include "network/server.hpp" + +#include + +Player::Player(Server& server) + : _name("Player_entity"), _state(PlayerState::None), _socketFd(-1), x(0), y(0), z(0), health(0), _uuid(), + _playerId(server.getIdManager().allocate()), _server(server), _config(new PlayerConfig()) {} + +Player::Player(const std::string& name, const PlayerState state, const int socket, Server& server) + : _state(state), _socketFd(socket), x(0), y(0), z(0), health(20), _uuid(), _playerId(server.getIdManager().allocate()), _server(server), + _config(new PlayerConfig()) { + if (name.length() > 32) + _name = name.substr(0, 31); + else + _name = name; +} + +Player& Player::operator=(const Player& src) { + if (this != &src) { + this->_name = src._name; + this->_socketFd = src._socketFd; + this->health = src.health; + this->x = src.x; + this->y = src.y; + this->z = src.z; + } + return (*this); +} + +Player::~Player() { + _server.getIdManager().release(_playerId); + delete _config; +} + +std::string Player::getPlayerName(void) { return (this->_name); }; +void Player::setPlayerName(const std::string& name) { this->_name = name; } +PlayerState Player::getPlayerState() { return (this->_state); } +void Player::setPlayerState(PlayerState state) { this->_state = state; } +void Player::setSocketFd(int socket) { this->_socketFd = socket; } +int Player::getSocketFd() const { return (this->_socketFd); } + +void Player::setUUID(UUID uuid) { _uuid = uuid; } + +int Player::getPlayerID() const { return (_playerId); } + +// PlayerConfig implementation +PlayerConfig::PlayerConfig() + : _chatMode(0), _mainHand(1), _locale("en_US"), _viewDistance(10), _displayedSkinParts(0), _chatColors(true), _enableTextFiltering(false), + _allowServerListings(true) {} + +PlayerConfig::~PlayerConfig() {} diff --git a/src/MD5.cpp b/src/lib/MD5.cpp similarity index 73% rename from src/MD5.cpp rename to src/lib/MD5.cpp index 4d3f919..27c65b5 100644 --- a/src/MD5.cpp +++ b/src/lib/MD5.cpp @@ -1,4 +1,4 @@ -#include "MD5.hpp" +#include "lib/MD5.hpp" #include @@ -12,22 +12,12 @@ namespace { constexpr uint32_t initC = 0x98badcfe; constexpr uint32_t initD = 0x10325476; - inline uint32_t F(uint32_t x, uint32_t y, uint32_t z) { - return (x & y) | (~x & z); - } - inline uint32_t G(uint32_t x, uint32_t y, uint32_t z) { - return (x & z) | (y & ~z); - } - inline uint32_t H(uint32_t x, uint32_t y, uint32_t z) { - return x ^ y ^ z; - } - inline uint32_t I(uint32_t x, uint32_t y, uint32_t z) { - return y ^ (x | ~z); - } + inline uint32_t F(uint32_t x, uint32_t y, uint32_t z) { return (x & y) | (~x & z); } + inline uint32_t G(uint32_t x, uint32_t y, uint32_t z) { return (x & z) | (y & ~z); } + inline uint32_t H(uint32_t x, uint32_t y, uint32_t z) { return x ^ y ^ z; } + inline uint32_t I(uint32_t x, uint32_t y, uint32_t z) { return y ^ (x | ~z); } - inline uint32_t rotate_left(uint32_t x, int n) { - return (x << n) | (x >> (32 - n)); - } + inline uint32_t rotate_left(uint32_t x, int n) { return (x << n) | (x >> (32 - n)); } } // namespace // petite implΓ©mentation brute de MD5 @@ -55,8 +45,7 @@ std::vector MD5::hash(const std::string& input) { for (size_t offset = 0; offset < data.size(); offset += 64) { uint32_t M[16]; for (int i = 0; i < 16; ++i) { - M[i] = (data[offset + i * 4]) | (data[offset + i * 4 + 1] << 8) | - (data[offset + i * 4 + 2] << 16) | (data[offset + i * 4 + 3] << 24); + M[i] = (data[offset + i * 4]) | (data[offset + i * 4 + 1] << 8) | (data[offset + i * 4 + 2] << 16) | (data[offset + i * 4 + 3] << 24); } uint32_t a = A, b = B, c = C, d = D; @@ -74,9 +63,9 @@ std::vector MD5::hash(const std::string& input) { // rΓ©sultat en octets (little-endian) std::vector digest(16); - uint32_t state[4] = {A, B, C, D}; + uint32_t state[4] = {A, B, C, D}; for (int i = 0; i < 4; i++) { - digest[i * 4] = state[i] & 0xFF; + digest[i * 4] = state[i] & 0xFF; digest[i * 4 + 1] = (state[i] >> 8) & 0xFF; digest[i * 4 + 2] = (state[i] >> 16) & 0xFF; digest[i * 4 + 3] = (state[i] >> 24) & 0xFF; diff --git a/src/UUID.cpp b/src/lib/UUID.cpp similarity index 69% rename from src/UUID.cpp rename to src/lib/UUID.cpp index 40c81a5..5f67cca 100644 --- a/src/UUID.cpp +++ b/src/lib/UUID.cpp @@ -1,6 +1,7 @@ -#include "MD5.hpp" -#include "UUID.hpp" -#include "buffer.hpp" +#include "lib/UUID.hpp" + +#include "lib/MD5.hpp" +#include "network/buffer.hpp" #include #include @@ -13,25 +14,16 @@ UUID::UUID() : _mostSigBits(0), _leastSigBits(0) {} UUID::UUID(uint64_t most, uint64_t least) : _mostSigBits(most), _leastSigBits(least) {} UUID::~UUID() {} -uint64_t UUID::getMostSigBits() const { - return _mostSigBits; -} -uint64_t UUID::getLeastSigBits() const { - return _leastSigBits; -} -void UUID::setMostSigBits(uint64_t val) { - _mostSigBits = val; -} -void UUID::setLeastSigBits(uint64_t val) { - _leastSigBits = val; -} +uint64_t UUID::getMostSigBits() const { return _mostSigBits; } +uint64_t UUID::getLeastSigBits() const { return _leastSigBits; } +void UUID::setMostSigBits(uint64_t val) { _mostSigBits = val; } +void UUID::setLeastSigBits(uint64_t val) { _leastSigBits = val; } std::string UUID::toString() const { std::stringstream ss; - ss << std::hex << std::setfill('0') << std::setw(8) << ((_mostSigBits >> 32) & 0xFFFFFFFF) - << "-" << std::setw(4) << ((_mostSigBits >> 16) & 0xFFFF) << "-" << std::setw(4) - << (_mostSigBits & 0xFFFF) << "-" << std::setw(4) << ((_leastSigBits >> 48) & 0xFFFF) << "-" - << std::setw(12) << (_leastSigBits & 0xFFFFFFFFFFFFULL); + ss << std::hex << std::setfill('0') << std::setw(8) << ((_mostSigBits >> 32) & 0xFFFFFFFF) << "-" << std::setw(4) + << ((_mostSigBits >> 16) & 0xFFFF) << "-" << std::setw(4) << (_mostSigBits & 0xFFFF) << "-" << std::setw(4) << ((_leastSigBits >> 48) & 0xFFFF) + << "-" << std::setw(12) << (_leastSigBits & 0xFFFFFFFFFFFFULL); return ss.str(); } diff --git a/src/buffer.cpp b/src/lib/buffer.cpp similarity index 67% rename from src/buffer.cpp rename to src/lib/buffer.cpp index 2467363..1ca0ea0 100644 --- a/src/buffer.cpp +++ b/src/lib/buffer.cpp @@ -1,5 +1,6 @@ -#include "UUID.hpp" -#include "buffer.hpp" +#include "network/buffer.hpp" + +#include "lib/UUID.hpp" #include #include @@ -10,22 +11,15 @@ Buffer::Buffer() : _pos(0) {} Buffer::Buffer(const std::vector& data) : _data(data), _pos(0) {} uint8_t Buffer::readByte() { - if (_pos >= _data.size()) - throw std::runtime_error("Buffer underflow on byte"); + if (_pos >= _data.size()) throw std::runtime_error("Buffer underflow on byte"); return _data[_pos++]; } -void Buffer::writeByte(uint8_t byte) { - _data.push_back(byte); -} +void Buffer::writeByte(uint8_t byte) { _data.push_back(byte); } -void Buffer::writeBytes(const std::string& data) { - _data.insert(_data.end(), data.begin(), data.end()); -} +void Buffer::writeBytes(const std::string& data) { _data.insert(_data.end(), data.begin(), data.end()); } -void Buffer::writeBytes(const std::vector& data) { - _data.insert(_data.end(), data.begin(), data.end()); -} +void Buffer::writeBytes(const std::vector& data) { _data.insert(_data.end(), data.begin(), data.end()); } void Buffer::writeUUID(const UUID& uuid) { uint64_t msb = uuid.getMostSigBits(); @@ -37,15 +31,14 @@ void Buffer::writeUUID(const UUID& uuid) { } int Buffer::readVarInt() { - int value = 0, position = 0; + int value = 0, position = 0; uint8_t currentByte; do { currentByte = readByte(); value |= (currentByte & 0x7F) << position; position += 7; - if (position >= 32) - throw std::runtime_error("VarInt too big"); + if (position >= 32) throw std::runtime_error("VarInt too big"); } while (currentByte & 0x80); return value; @@ -105,13 +98,9 @@ void Buffer::writeString(const std::string& str) { _data.insert(_data.end(), str.begin(), str.end()); } -std::vector& Buffer::getData() { - return _data; -} +std::vector& Buffer::getData() { return _data; } -size_t Buffer::remaining() const { - return _data.size() - _pos; -} +size_t Buffer::remaining() const { return _data.size() - _pos; } uint16_t Buffer::readUShort() { uint16_t val = (readByte() << 8) | readByte(); @@ -140,43 +129,43 @@ void Buffer::writeLong(long value) { } } -void Buffer::writeBool(bool value) { - writeByte(value ? 0x01 : 0x00); -} +void Buffer::writeBool(bool value) { writeByte(value ? 0x01 : 0x00); } -void Buffer::writeNBT(const std::string& nbtData) { - writeBytes(nbtData); -} +void Buffer::writeNBT(const std::string& nbtData) { writeBytes(nbtData); } void Buffer::writePosition(int32_t x, int32_t y, int32_t z) { - int64_t packed = ((int64_t)(x & 0x3FFFFFF) << 38) | ((int64_t)(y & 0xFFF) << 26) | (int64_t)(z & 0x3FFFFFF); - writeLong(packed); + int64_t packed = ((int64_t)(x & 0x3FFFFFF) << 38) | ((int64_t)(y & 0xFFF) << 26) | (int64_t)(z & 0x3FFFFFF); + writeLong(packed); } void Buffer::writeFloat(float value) { - union { float f; uint32_t i; } u; - u.f = value; - writeUInt(u.i); + union { + float f; + uint32_t i; + } u; + u.f = value; + writeUInt(u.i); } void Buffer::writeDouble(double value) { - union { double d; uint64_t i; } u; - u.d = value; - writeLong(u.i); + union { + double d; + uint64_t i; + } u; + u.d = value; + writeLong(u.i); } void Buffer::writeVarLong(int64_t value) { - while (true) { - if ((value & ~0x7FL) == 0) { - writeByte((uint8_t)value); - return; - } else { - writeByte((uint8_t)((value & 0x7F) | 0x80)); - value >>= 7; - } - } + while (true) { + if ((value & ~0x7FL) == 0) { + writeByte((uint8_t)value); + return; + } else { + writeByte((uint8_t)((value & 0x7F) | 0x80)); + value >>= 7; + } + } } -void Buffer::writeIdentifier(const std::string& id) { - writeString(id); -} +void Buffer::writeIdentifier(const std::string& id) { writeString(id); } diff --git a/src/lib/config.cpp b/src/lib/config.cpp new file mode 100644 index 0000000..586a0f4 --- /dev/null +++ b/src/lib/config.cpp @@ -0,0 +1,111 @@ +#include "config.hpp" + +#include "lib/filesystem.hpp" +#include "lib/json.hpp" +#include "logger.hpp" + +#include +#include + +using json = nlohmann::json; + +Config::Config() + : _execPath(getPath()), _gameVersion("1.21.5"), _protocolVersion(770), _serverMotd("A Minecraft Server"), _serverAddress("127.0.0.1"), + _serverPort(25565), _serverSize(20), _worldName("world"), _gamemode("survival"), _difficulty("normal") {} + +bool Config::loadConfig() { + std::ifstream inputFile(_execPath.parent_path() / "config.json"); // Should change the config path later if needed + + if (!inputFile.is_open()) { + g_logger->logGameInfo(DEBUG, "Error: Could not open: config.json", "SERVER"); + return true; + } + + json config; + + try { + inputFile >> config; + Config::setServerVersion(config["version"]["name"]); + Config::setProtocolVersion(config["version"]["protocol"]); + Config::setServerSize(config["server"]["max-players"]); + Config::setServerMotd(config["server"]["motd"]); + Config::setServerAddress(config["server"]["ip-address"]); + Config::setServerPort(config["server"]["port"]); + Config::setWorldName(config["world"]["name"]); + Config::setGamemode(config["world"]["gamemode"]); + Config::setDifficulty(config["world"]["difficulty"]); + } catch (json::parse_error& e) { + g_logger->logGameInfo(ERROR, "Error parsing config.json: " + std::string(e.what()), "SERVER"); + inputFile.close(); + return true; + } + inputFile.close(); + return false; +} + +bool Config::reloadConfig() { + std::ifstream inputFile(_execPath.root_directory() / "config.json"); // Should change the config path later if needed + + if (!inputFile.is_open()) { + g_logger->logGameInfo(DEBUG, "Error: Could not open: config.json", "SERVER"); + return true; + } + + json config; + + try { + inputFile >> config; + // Reload server settings that can be changed at runtime + Config::setServerSize(config["server"]["max-players"]); + Config::setServerMotd(config["server"]["motd"]); + + // Reload world settings that can be changed at runtime + Config::setGamemode(config["world"]["gamemode"]); + Config::setDifficulty(config["world"]["difficulty"]); + } catch (json::parse_error& e) { + g_logger->logGameInfo(ERROR, "Error parsing config.json: " + std::string(e.what()), "SERVER"); + inputFile.close(); + return true; + } + return false; +} + +Config::~Config() {} + +// Getter methods +int Config::getServerPort() { return _serverPort; } + +int Config::getProtocolVersion() { return _protocolVersion; } + +int Config::getServerSize() { return _serverSize; } + +std::string Config::getVersion() { return _gameVersion; } + +std::string Config::getServerMotd() { return _serverMotd; } + +std::string Config::getServerAddress() { return _serverAddress; } + +std::string Config::getWorldName() { return _worldName; } + +std::string Config::getGamemode() { return _gamemode; } + +std::string Config::getDifficulty() { return _difficulty; } + +// Setter methods +void Config::setProtocolVersion(int ProtoVersion) { _protocolVersion = ProtoVersion; } + +void Config::setServerSize(int ServerSize) { _serverSize = ServerSize; } + +void Config::setServerPort(int ServerPort) { _serverPort = ServerPort; } + +void Config::setServerMotd(std::string ServerMotd) { _serverMotd = ServerMotd; } + +void Config::setServerVersion(std::string ServerVersion) { _gameVersion = ServerVersion; } + +void Config::setServerAddress(std::string ServerAddress) { _serverAddress = ServerAddress; } + +void Config::setWorldName(std::string WorldName) { _worldName = WorldName; } + +void Config::setGamemode(std::string Gamemode) { _gamemode = Gamemode; } + +void Config::setDifficulty(std::string Difficulty) { _difficulty = Difficulty; } diff --git a/src/lib/fs.cpp b/src/lib/fs.cpp new file mode 100644 index 0000000..ea6f364 --- /dev/null +++ b/src/lib/fs.cpp @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#include +#include + +std::filesystem::path getPath() { + char buffer[PATH_MAX]; + ssize_t len = readlink("/proc/self/exe", buffer, sizeof(buffer) - 1); + if (len != -1) { + buffer[len] = '\0'; + return std::filesystem::path(buffer); + } + return {}; +} diff --git a/src/id_manager.cpp b/src/lib/idManager.cpp similarity index 90% rename from src/id_manager.cpp rename to src/lib/idManager.cpp index 812b9bd..f616e1a 100644 --- a/src/id_manager.cpp +++ b/src/lib/idManager.cpp @@ -1,4 +1,4 @@ -#include "id_manager.hpp" +#include "network/id_manager.hpp" #include #include @@ -25,8 +25,7 @@ uint32_t IdManager::allocate() { void IdManager::release(uint32_t id) { std::lock_guard lock(_mutex); if (id >= _nextId) { - std::cerr << "[IdManager] WARNING: Trying to release invalid ID " << id - << " (nextId: " << _nextId << ")" << std::endl; + std::cerr << "[IdManager] WARNING: Trying to release invalid ID " << id << " (nextId: " << _nextId << ")" << std::endl; return; } if (_freedIds.find(id) != _freedIds.end()) { @@ -35,8 +34,7 @@ void IdManager::release(uint32_t id) { } _freedIds.insert(id); - std::cout << "[IdManager] Released ID: " << id << " (freed count: " << _freedIds.size() << ")" - << std::endl; + std::cout << "[IdManager] Released ID: " << id << " (freed count: " << _freedIds.size() << ")" << std::endl; } size_t IdManager::getAllocatedCount() const { diff --git a/src/logger.cpp b/src/lib/logger.cpp similarity index 80% rename from src/logger.cpp rename to src/lib/logger.cpp index b4fd564..bdc9e87 100644 --- a/src/logger.cpp +++ b/src/lib/logger.cpp @@ -1,23 +1,25 @@ #include "logger.hpp" +#include "lib/filesystem.hpp" + #include +#include #include #include #include #include +#include +#include #include +#include #include #include -#include -#include -#include -#include namespace fs = std::filesystem; LogManager::LogManager() : _running(false) { if (initializeLogDirectory()) { - _running = true; + _running = true; _writerThread = std::thread(&LogManager::writerThreadLoop, this); // Logger initialized - using console for initialization message std::cout << "Logger initialized successfully in directory: " << _logDir << std::endl; @@ -43,7 +45,7 @@ LogManager::~LogManager() { } std::string LogManager::getCurrentTimestamp() { - auto now = std::chrono::system_clock::now(); + auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); std::stringstream ss; @@ -52,9 +54,9 @@ std::string LogManager::getCurrentTimestamp() { } std::string LogManager::getDetailedTimestamp() { - auto now = std::chrono::system_clock::now(); + auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); - auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; std::stringstream ss; ss << std::put_time(std::localtime(&time_t), "%H:%M:%S"); @@ -66,7 +68,7 @@ bool LogManager::initializeLogDirectory() { std::string timestamp = getCurrentTimestamp(); // Create base logs directory - fs::path baseLogsDir = "logs"; + fs::path baseLogsDir = getPath().parent_path() / "logs"; if (!fs::exists(baseLogsDir)) { if (!fs::create_directories(baseLogsDir)) { std::cerr << "Failed to create base logs directory: " << baseLogsDir << std::endl; @@ -109,16 +111,13 @@ bool LogManager::initializeLogDirectory() { return true; } -void LogManager::log(LogLevel level, - LogCategory category, - const std::string& message, - const std::string& source) { +void LogManager::log(LogLevel level, LogCategory category, const std::string& message, const std::string& source) { LogEntry entry; entry.timestamp = std::chrono::system_clock::now(); - entry.level = level; - entry.category = category; - entry.message = message; - entry.source = source; + entry.level = level; + entry.category = category; + entry.message = message; + entry.source = source; // Add to queue for file writing { @@ -127,25 +126,19 @@ void LogManager::log(LogLevel level, } if (category == GAMEINFO || category == NETWORK) { // Remove category == NETWORK on release build - std::string formattedEntry = formatLogEntry(entry); - std::cout << formattedEntry << std::endl; + std::string formattedEntry = formatLogEntry(entry); + std::cout << formattedEntry << std::endl; } } -void LogManager::logNetwork(LogLevel level, const std::string& message, const std::string& source) { - log(level, NETWORK, message, source); -} +void LogManager::logNetwork(LogLevel level, const std::string& message, const std::string& source) { log(level, NETWORK, message, source); } -void LogManager::logGameInfo(LogLevel level, - const std::string& message, - const std::string& source) { - log(level, GAMEINFO, message, source); -} +void LogManager::logGameInfo(LogLevel level, const std::string& message, const std::string& source) { log(level, GAMEINFO, message, source); } void LogManager::writerThreadLoop() { while (_running || !_logQueue.empty()) { LogEntry entry; - bool hasEntry = false; + bool hasEntry = false; // Get entry from queue { @@ -160,7 +153,7 @@ void LogManager::writerThreadLoop() { if (hasEntry) { // Write to appropriate file std::lock_guard fileLock(_fileMutex); - std::string formattedEntry = formatLogEntry(entry); + std::string formattedEntry = formatLogEntry(entry); if (entry.category == NETWORK && _networkFile.is_open()) { _networkFile << formattedEntry << std::endl; @@ -181,9 +174,7 @@ std::string LogManager::formatLogEntry(const LogEntry& entry) { // Add timestamp auto time_t = std::chrono::system_clock::to_time_t(entry.timestamp); - auto ms = std::chrono::duration_cast( - entry.timestamp.time_since_epoch()) % - 1000; + auto ms = std::chrono::duration_cast(entry.timestamp.time_since_epoch()) % 1000; ss << "[" << std::put_time(std::localtime(&time_t), "%H:%M:%S"); ss << "." << std::setfill('0') << std::setw(3) << ms.count() << "] "; diff --git a/src/lib/nbtParser.cpp b/src/lib/nbtParser.cpp new file mode 100644 index 0000000..90237f8 --- /dev/null +++ b/src/lib/nbtParser.cpp @@ -0,0 +1,184 @@ +#include "lib/nbtParser.hpp" + +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr uint8_t TAG_END = 0; + constexpr uint8_t TAG_BYTE = 1; + constexpr uint8_t TAG_SHORT = 2; + constexpr uint8_t TAG_INT = 3; + constexpr uint8_t TAG_LONG = 4; + constexpr uint8_t TAG_FLOAT = 5; + constexpr uint8_t TAG_DOUBLE = 6; + constexpr uint8_t TAG_BYTE_ARRAY = 7; + constexpr uint8_t TAG_STRING = 8; + constexpr uint8_t TAG_LIST = 9; + constexpr uint8_t TAG_COMPOUND = 10; + constexpr uint8_t TAG_INT_ARRAY = 11; + constexpr uint8_t TAG_LONG_ARRAY = 12; +} // namespace + +namespace nbt { + + NBT Parser::parse(const std::vector& data) { + if (data.empty()) { + throw std::runtime_error("NBT parsing error: empty data."); + } + + size_t cursor = 0; + + uint8_t rootType = read(data, cursor); + if (rootType != TAG_COMPOUND) { + throw std::runtime_error("NBT parsing error: root must be a TAG_Compound."); + } + + std::string rootName = parseTagName(data, cursor); + TagCompound rootComp = parseCompound(data, cursor); + + return NBT(rootName, rootComp); + } + + template T Parser::read(const std::vector& data, size_t& cursor) { + if (cursor + sizeof(T) > data.size()) { + throw std::runtime_error("NBT parsing error: unexpected end of data."); + } + T value; + std::memcpy(&value, &data[cursor], sizeof(T)); + cursor += sizeof(T); + + if constexpr (sizeof(T) > 1) { + if (std::endian::native == std::endian::little) { + return std::byteswap(value); + } + } + return value; + } + + // Explicit instantiations for the types we use + template int8_t Parser::read(const std::vector&, size_t&); + template uint8_t Parser::read(const std::vector&, size_t&); + template int16_t Parser::read(const std::vector&, size_t&); + template uint16_t Parser::read(const std::vector&, size_t&); + template int32_t Parser::read(const std::vector&, size_t&); + template uint32_t Parser::read(const std::vector&, size_t&); + template int64_t Parser::read(const std::vector&, size_t&); + template uint64_t Parser::read(const std::vector&, size_t&); + + std::string Parser::parseTagName(const std::vector& data, size_t& cursor) { + uint16_t length = read(data, cursor); + if (length == 0) { + return ""; + } + if (cursor + length > data.size()) { + throw std::runtime_error("NBT parsing error: invalid tag name length."); + } + std::string name(data.begin() + cursor, data.begin() + cursor + length); + cursor += length; + return name; + } + + TagCompound Parser::parseCompound(const std::vector& data, size_t& cursor) { + TagCompound compound; + while (cursor < data.size()) { + uint8_t tagType = read(data, cursor); + if (tagType == TAG_END) { + break; + } + + std::string tagName = parseTagName(data, cursor); + compound[tagName] = parseTag(data, cursor, tagType); + } + return compound; + } + + TagList Parser::parseList(const std::vector& data, size_t& cursor) { + TagList list; + uint8_t listType = read(data, cursor); + int32_t length = read(data, cursor); + + if (length < 0) { + throw std::runtime_error("NBT parsing error: negative TAG_List length."); + } + + for (int32_t i = 0; i < length; ++i) { + list.push_back(parseTag(data, cursor, listType)); + } + return list; + } + + Tag Parser::parseTag(const std::vector& data, size_t& cursor, uint8_t tagType) { + switch (tagType) { + case TAG_BYTE: + return Tag(read(data, cursor)); + case TAG_SHORT: + return Tag(read(data, cursor)); + case TAG_INT: + return Tag(read(data, cursor)); + case TAG_LONG: + return Tag(read(data, cursor)); + case TAG_FLOAT: + return Tag(std::bit_cast(read(data, cursor))); + case TAG_DOUBLE: + return Tag(std::bit_cast(read(data, cursor))); + case TAG_STRING: { + uint16_t length = read(data, cursor); + if (cursor + length > data.size()) { + throw std::runtime_error("NBT parsing error: invalid string length."); + } + std::string str(data.begin() + cursor, data.begin() + cursor + length); + cursor += length; + return Tag(str); + } + case TAG_BYTE_ARRAY: { + int32_t length = read(data, cursor); + if (length < 0) { + throw std::runtime_error("NBT parsing error: negative TAG_Byte_Array length."); + } + TagByteArray array; + if (length > 0) { + array.resize(static_cast(length)); + std::memcpy(array.data(), &data[cursor], static_cast(length)); + cursor += static_cast(length); + } + return Tag(array); + } + case TAG_INT_ARRAY: { + int32_t length = read(data, cursor); + if (length < 0) { + throw std::runtime_error("NBT parsing error: negative TAG_Int_Array length."); + } + TagIntArray array; + array.reserve(static_cast(length)); + for (int32_t i = 0; i < length; ++i) { + array.push_back(read(data, cursor)); + } + return Tag(array); + } + case TAG_LONG_ARRAY: { + int32_t length = read(data, cursor); + if (length < 0) { + throw std::runtime_error("NBT parsing error: negative TAG_Long_Array length."); + } + TagLongArray array; + array.reserve(static_cast(length)); + for (int32_t i = 0; i < length; ++i) { + array.push_back(read(data, cursor)); + } + return Tag(array); + } + case TAG_LIST: + return Tag(std::make_shared(parseList(data, cursor))); + case TAG_COMPOUND: + return Tag(std::make_shared(parseCompound(data, cursor))); + default: + throw std::runtime_error("NBT parsing error: unsupported tag type: " + std::to_string(tagType)); + } + } + +} // namespace nbt diff --git a/src/packet.cpp b/src/lib/packet.cpp similarity index 64% rename from src/packet.cpp rename to src/lib/packet.cpp index e87f013..f52745e 100644 --- a/src/packet.cpp +++ b/src/lib/packet.cpp @@ -1,9 +1,10 @@ -#include "buffer.hpp" -#include "json.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" +#include "network/packet.hpp" + +#include "lib/json.hpp" #include "logger.hpp" +#include "network/buffer.hpp" +#include "network/server.hpp" +#include "player.hpp" #include #include @@ -21,18 +22,17 @@ using json = nlohmann::json; Packet::~Packet() {} Packet::Packet(const Packet& other) - : _size(other._size), _id(other._id), _data(other._data), _player(other._player), - _socketFd(other._socketFd), _returnPacket(other._returnPacket) { + : _size(other._size), _id(other._id), _data(other._data), _player(other._player), _socketFd(other._socketFd), _returnPacket(other._returnPacket) { std::cout << "[Packet] Copy constructor called" << std::endl; } Packet& Packet::operator=(const Packet& other) { if (this != &other) { - _size = other._size; - _id = other._id; - _data = other._data; - _player = other._player; - _socketFd = other._socketFd; + _size = other._size; + _id = other._id; + _data = other._data; + _player = other._player; + _socketFd = other._socketFd; _returnPacket = other._returnPacket; std::cout << "[Packet] Assignment operator called" << std::endl; } @@ -40,30 +40,28 @@ Packet& Packet::operator=(const Packet& other) { } Packet::Packet(Player* player) : _player(player), _socketFd(-1), _returnPacket(0) { - if (_player == nullptr) - throw std::runtime_error("Packet init with null player"); + if (_player == nullptr) throw std::runtime_error("Packet init with null player"); _socketFd = _player->getSocketFd(); - // g_logger->logNetwork(INFO, "Constructor: Socket FD = " + std::to_string(_socketFd), "Packet"); + // g_logger->logNetwork(INFO, "Constructor: Socket FD = " + std::to_string(_socketFd), + // "Packet"); _size = readVarint(_socketFd); - if (_size == -1) - throw std::runtime_error("Failed to read packet size"); + if (_size == -1) throw std::runtime_error("Failed to read packet size"); // g_logger->logNetwork(INFO, "Read size: " + std::to_string(_size), "Packet"); int idBytesRead = 0; - _id = readVarint(_socketFd, &idBytesRead); - if (_id == -1) - throw std::runtime_error("Failed to read packet id"); + _id = readVarint(_socketFd, &idBytesRead); + if (_id == -1) throw std::runtime_error("Failed to read packet id"); // g_logger->logNetwork(INFO, "Read ID: " + std::to_string(_id), "Packet"); int remaining = _size - idBytesRead; - // g_logger->logNetwork(INFO, "Calculated remaining: " + std::to_string(remaining) + " (size=" + std::to_string(_size) + " - idBytes=" + std::to_string(idBytesRead) + ")", "Packet"); + // g_logger->logNetwork(INFO, "Calculated remaining: " + std::to_string(remaining) + " (size=" + + // std::to_string(_size) + " - idBytes=" + std::to_string(idBytesRead) + ")", "Packet"); - if (remaining < 0) - throw std::runtime_error("Invalid packet size"); + if (remaining < 0) throw std::runtime_error("Invalid packet size"); if (remaining > 0) { std::vector tmp(remaining); - ssize_t totalRead = 0; + ssize_t totalRead = 0; while (totalRead < remaining) { ssize_t bytesRead = ::read(_socketFd, tmp.data() + totalRead, remaining - totalRead); @@ -82,26 +80,24 @@ Packet::Packet(Player* player) : _player(player), _socketFd(-1), _returnPacket(0 } } -Packet::Packet(int socketFd, Server& server) - : _player(nullptr), _socketFd(socketFd), _returnPacket(0) { - // g_logger->logNetwork(INFO, "Constructor (socket): Socket FD = " + std::to_string(_socketFd), "Packet"); +Packet::Packet(int socketFd, Server& server) : _player(nullptr), _socketFd(socketFd), _returnPacket(0) { + // g_logger->logNetwork(INFO, "Constructor (socket): Socket FD = " + std::to_string(_socketFd), + // "Packet"); _size = readVarint(_socketFd); - if (_size == -1) - throw std::runtime_error("Failed to read packet size"); + if (_size == -1) throw std::runtime_error("Failed to read packet size"); // g_logger->logNetwork(INFO, "Read size: " + std::to_string(_size), "Packet"); int idBytesRead = 0; - _id = readVarint(_socketFd, &idBytesRead); - if (_id == -1) - throw std::runtime_error("Failed to read packet id"); + _id = readVarint(_socketFd, &idBytesRead); + if (_id == -1) throw std::runtime_error("Failed to read packet id"); // g_logger->logNetwork(INFO, "Read ID: " + std::to_string(_id), "Packet"); int remaining = _size - idBytesRead; - // g_logger->logNetwork(INFO, "Calculated remaining: " + std::to_string(remaining) + " (size=" + std::to_string(_size) + " - idBytes=" + std::to_string(idBytesRead) + ")", "Packet"); + // g_logger->logNetwork(INFO, "Calculated remaining: " + std::to_string(remaining) + " (size=" + + // std::to_string(_size) + " - idBytes=" + std::to_string(idBytesRead) + ")", "Packet"); - if (remaining < 0) - throw std::runtime_error("Invalid packet size"); + if (remaining < 0) throw std::runtime_error("Invalid packet size"); try { _player = server.addTempPlayer("None", PlayerState::Handshake, socketFd); @@ -112,7 +108,7 @@ Packet::Packet(int socketFd, Server& server) if (remaining > 0) { std::vector tmp(remaining); - ssize_t totalRead = 0; + ssize_t totalRead = 0; while (totalRead < remaining) { ssize_t bytesRead = ::read(_socketFd, tmp.data() + totalRead, remaining - totalRead); @@ -133,17 +129,17 @@ Packet::Packet(int socketFd, Server& server) int Packet::getVarintSize(int32_t value) { if (value < 0) { - std::cerr << "[Packet] ERROR: getVarintSize called with negative value: " << value - << std::endl; + std::cerr << "[Packet] ERROR: getVarintSize called with negative value: " << value << std::endl; throw std::runtime_error("getVarintSize called with negative value"); } - int size = 0; + int size = 0; int original_value = value; do { value >>= 7; size++; } while (value != 0); - // g_logger->logNetwork(INFO, "getVarintSize(" + std::to_string(original_value) + ") = " + std::to_string(size), "Packet"); + // g_logger->logNetwork(INFO, "getVarintSize(" + std::to_string(original_value) + ") = " + + // std::to_string(size), "Packet"); return size; } @@ -152,35 +148,31 @@ int Packet::readVarint(int sock, int* bytesRead) { return -1; } - int value = 0, position = 0; + int value = 0, position = 0; uint8_t byte; - int localBytesRead = 0; + int localBytesRead = 0; while (true) { ssize_t result = ::read(sock, &byte, 1); if (result <= 0) { - std::cerr << "readVarint: Failed to read byte " << localBytesRead << " from socket " << sock - << " (errno: " << errno << ")" << std::endl; + std::cerr << "readVarint: Failed to read byte " << localBytesRead << " from socket " << sock << " (errno: " << errno << ")" << std::endl; return -1; } localBytesRead++; value |= (byte & 0x7F) << position; - if (!(byte & 0x80)) - break; // Last byte of varint + if (!(byte & 0x80)) break; // Last byte of varint position += 7; if (position >= 32) { - std::cerr << "readVarint: Varint too long (> 32 bits) after " << localBytesRead << " bytes" - << std::endl; + std::cerr << "readVarint: Varint too long (> 32 bits) after " << localBytesRead << " bytes" << std::endl; return -1; } // Safety check to prevent infinite loops if (localBytesRead > 5) { - std::cerr << "readVarint: Too many bytes read (" << localBytesRead << "), corrupted varint" - << std::endl; + std::cerr << "readVarint: Too many bytes read (" << localBytesRead << "), corrupted varint" << std::endl; return -1; } } @@ -189,17 +181,16 @@ int Packet::readVarint(int sock, int* bytesRead) { *bytesRead = localBytesRead; } - // g_logger->logNetwork(INFO, "readVarint: Successfully read " + std::to_string(value) + " (" + std::to_string(localBytesRead) + " bytes)", "Packet"); + // g_logger->logNetwork(INFO, "readVarint: Successfully read " + std::to_string(value) + " (" + + // std::to_string(localBytesRead) + " bytes)", "Packet"); return value; } -int Packet::readVarint(int sock) { - return readVarint(sock, nullptr); -} +int Packet::readVarint(int sock) { return readVarint(sock, nullptr); } void Packet::writeVarint(int sock, int value) { std::vector tmp; - Buffer buf(tmp); + Buffer buf(tmp); buf.writeVarInt(value); (void)!::write(sock, buf.getData().data(), buf.getData().size()); } @@ -211,7 +202,7 @@ bool Packet::isSocketValid(int sock) { } struct pollfd pfd; - pfd.fd = sock; + pfd.fd = sock; pfd.events = POLLIN; int result = poll(&pfd, 1, 0); @@ -221,20 +212,15 @@ bool Packet::isSocketValid(int sock) { } if (pfd.revents & (POLLHUP | POLLERR)) { - std::cerr << "Socket validation: Socket " << sock << " is disconnected or has error" - << std::endl; + std::cerr << "Socket validation: Socket " << sock << " is disconnected or has error" << std::endl; return false; } return true; } -void Packet::setReturnPacket(int value) { - this->_returnPacket = value; -} -int Packet::getReturnPacket() { - return (this->_returnPacket); -} +void Packet::setReturnPacket(int value) { this->_returnPacket = value; } +int Packet::getReturnPacket() { return (this->_returnPacket); } int Packet::varintLen(int value) { int len = 0; @@ -245,24 +231,10 @@ int Packet::varintLen(int value) { return (len); } -Player* Packet::getPlayer() const { - return (_player); -} -uint32_t Packet::getSize() { - return (_size); -} -uint32_t Packet::getId() { - return (_id); -} -Buffer& Packet::getData() { - return (_data); -} -int Packet::getSocket() const { - return (_socketFd); -}; -void Packet::setPacketSize(int32_t value) { - _size = value; -} -void Packet::setPacketId(uint32_t value) { - _id = value; -} +Player* Packet::getPlayer() const { return (_player); } +uint32_t Packet::getSize() { return (_size); } +uint32_t Packet::getId() { return (_id); } +Buffer& Packet::getData() { return (_data); } +int Packet::getSocket() const { return (_socketFd); }; +void Packet::setPacketSize(int32_t value) { _size = value; } +void Packet::setPacketId(uint32_t value) { _id = value; } diff --git a/src/main.cpp b/src/main.cpp index a51254c..df27ea9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,4 @@ -#include "server.hpp" +#include "network/server.hpp" int main() { Server server; diff --git a/src/networking/networkManager.cpp b/src/networking/networkManager.cpp index 82be534..a7392f0 100644 --- a/src/networking/networkManager.cpp +++ b/src/networking/networkManager.cpp @@ -1,5 +1,5 @@ -#include "networking.hpp" -#include "server.hpp" +#include "network/networking.hpp" +#include "network/server.hpp" #include #include @@ -13,9 +13,8 @@ #include NetworkManager::NetworkManager(size_t workerCount, Server& s) - : _incomingPackets(), _outgoingPackets(), _workerThreads(), _shutdownFlag(false), - _receiverThread(), _senderThread(), _receiverThreadInit(0), _senderThreadInit(0), _server(s), - _epollFd(-1), _serverSocket(-1) { + : _incomingPackets(), _outgoingPackets(), _workerThreads(), _shutdownFlag(false), _receiverThread(), _senderThread(), _receiverThreadInit(0), + _senderThreadInit(0), _server(s), _epollFd(-1), _serverSocket(-1) { _workerThreads.reserve(workerCount); setupEpoll(); @@ -34,12 +33,12 @@ void NetworkManager::startThreads() { _shutdownFlag = false; if (!_receiverThreadInit) { - _receiverThread = std::thread(&NetworkManager::receiverThreadLoop, this); + _receiverThread = std::thread(&NetworkManager::receiverThreadLoop, this); _receiverThreadInit = 1; } if (!_senderThreadInit) { - _senderThread = std::thread(&NetworkManager::senderThreadLoop, this); + _senderThread = std::thread(&NetworkManager::senderThreadLoop, this); _senderThreadInit = 1; } size_t workerCount = _workerThreads.capacity(); @@ -96,12 +95,12 @@ void NetworkManager::start() { struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; - serverAddr.sin_port = htons(getServer().getServerPort()); + serverAddr.sin_port = htons(getServer().getConfig().getServerPort()); - if (strcmp(getServer().getServerAddr().c_str(), "0.0.0.0") == 0) { + if (strcmp(getServer().getConfig().getServerAddress().c_str(), "0.0.0.0") == 0) { serverAddr.sin_addr.s_addr = INADDR_ANY; } else { - if (inet_aton(getServer().getServerAddr().c_str(), &serverAddr.sin_addr) == 0) { + if (inet_aton(getServer().getConfig().getServerAddress().c_str(), &serverAddr.sin_addr) == 0) { close(_serverSocket); throw std::runtime_error("Invalid IP address"); } @@ -109,9 +108,8 @@ void NetworkManager::start() { if (bind(_serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) { close(_serverSocket); - throw std::runtime_error("Failed to bind socket to " + - std::string(getServer().getServerAddr()) + ":" + - std::to_string(getServer().getServerPort())); + throw std::runtime_error("Failed to bind socket to " + std::string(getServer().getConfig().getServerAddress()) + ":" + + std::to_string(getServer().getConfig().getServerPort())); } if (listen(_serverSocket, SOMAXCONN) < 0) { diff --git a/src/networking/networkQueuer.cpp b/src/networking/networkQueuer.cpp index 04fa202..3782121 100644 --- a/src/networking/networkQueuer.cpp +++ b/src/networking/networkQueuer.cpp @@ -1,8 +1,8 @@ -#include "networking.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" #include "logger.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" #include #include @@ -10,59 +10,56 @@ #include #include #include +#include #include #include #include -#include void NetworkManager::receiverThreadLoop() { - const int MaxEvent = 256; + const int MaxEvent = 256; epoll_event events[MaxEvent]; while (!_shutdownFlag.load()) { int eventCount = epoll_wait(_epollFd, events, MaxEvent, 50); if (eventCount == -1) { - if (errno == EINTR) - continue; + if (errno == EINTR) continue; break; } for (int i = 0; i < eventCount; i++) { - int fd = events[i].data.fd; + int fd = events[i].data.fd; uint32_t eventFlags = events[i].events; if (fd == _serverSocket) { sockaddr_in client_addr{}; - socklen_t addr_len = sizeof(client_addr); - int client_fd = accept(_serverSocket, (sockaddr*)&client_addr, &addr_len); + socklen_t addr_len = sizeof(client_addr); + int client_fd = accept(_serverSocket, (sockaddr*)&client_addr, &addr_len); if (client_fd != -1) { - // g_logger->logNetwork(INFO, "New connection accepted on socket " + std::to_string(client_fd), "Network Manager"); + // g_logger->logNetwork(INFO, "New connection accepted on socket " + + // std::to_string(client_fd), "Network Manager"); epoll_event event; event.events = EPOLLIN; event.data.fd = client_fd; if (epoll_ctl(_epollFd, EPOLL_CTL_ADD, client_fd, &event) == -1) { - std::cerr << "[Network Manager] Failed to add new client socket to epoll" - << std::endl; + std::cerr << "[Network Manager] Failed to add new client socket to epoll" << std::endl; close(client_fd); } } continue; } - auto it = getServer().getPlayerLst().find(fd); - Player* p = nullptr; + auto it = getServer().getPlayerLst().find(fd); + Player* p = nullptr; if (it != getServer().getPlayerLst().end()) { p = it->second; } else { auto temp_it = getServer().getTempPlayerLst().find(fd); - if (temp_it != getServer().getTempPlayerLst().end()) - p = temp_it->second; + if (temp_it != getServer().getTempPlayerLst().end()) p = temp_it->second; } if (eventFlags & EPOLLERR || eventFlags & EPOLLHUP) { - if (p) - getServer().removePlayerFromAnyList(p); + if (p) getServer().removePlayerFromAnyList(p); epoll_ctl(_epollFd, EPOLL_CTL_DEL, fd, nullptr); close(fd); continue; @@ -75,8 +72,7 @@ void NetworkManager::receiverThreadLoop() { else handleIncomingData(fd); } catch (const std::exception& e) { - if (p) - getServer().removePlayerFromAnyList(p); + if (p) getServer().removePlayerFromAnyList(p); epoll_ctl(_epollFd, EPOLL_CTL_DEL, fd, nullptr); close(fd); } @@ -90,14 +86,14 @@ void NetworkManager::senderThreadLoop() { Packet* p = nullptr; while (_outgoingPackets.tryPop(p)) { - if (p == nullptr) - break; + if (p == nullptr) break; try { // g_logger->logNetwork(INFO, "Sending packet to player", "Network Manager"); send(p->getSocket(), p->getData().getData().data(), p->getSize(), MSG_NOSIGNAL); if (p->getPlayer() && p->getPlayer()->getPlayerState() == PlayerState::None) { - // g_logger->logNetwork(INFO, "Closing status connection after response", "Network Manager"); + // g_logger->logNetwork(INFO, "Closing status connection after response", + // "Network Manager"); getServer().removePlayerFromAnyList(p->getPlayer()); epoll_ctl(_epollFd, EPOLL_CTL_DEL, p->getSocket(), nullptr); close(p->getSocket()); @@ -113,9 +109,7 @@ void NetworkManager::senderThreadLoop() { } } -void NetworkManager::enqueueOutgoingPacket(Packet* p) { - _outgoingPackets.push(p); -} +void NetworkManager::enqueueOutgoingPacket(Packet* p) { _outgoingPackets.push(p); } void NetworkManager::handleIncomingData(Player* connection) { Packet* p; @@ -131,7 +125,8 @@ void NetworkManager::handleIncomingData(Player* connection) { void NetworkManager::handleIncomingData(int socket) { Packet* p; - // g_logger->logNetwork(INFO, "Handling incoming data for socket " + std::to_string(socket), "Network Manager"); + // g_logger->logNetwork(INFO, "Handling incoming data for socket " + std::to_string(socket), + // "Network Manager"); try { p = new Packet(socket, getServer()); _incomingPackets.push(p); diff --git a/src/networking/networkWorker.cpp b/src/networking/networkWorker.cpp index ad7a5df..4909e72 100644 --- a/src/networking/networkWorker.cpp +++ b/src/networking/networkWorker.cpp @@ -1,8 +1,8 @@ #include "logger.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" #include #include @@ -19,7 +19,7 @@ void NetworkManager::workerThreadLoop() { try { // g_logger->logNetwork(INFO, "Handling incoming data for player", "Worker"); - packetRouter(packet, getServer(), &_outgoingPackets); + packetRouter(packet, getServer()); if (packet->getReturnPacket() == PACKET_SEND) { _outgoingPackets.push(packet); packet = nullptr; diff --git a/src/networking/packet/chunkBatch.cpp b/src/networking/packet/chunkBatch.cpp index 83dc2a6..6ff67d1 100644 --- a/src/networking/packet/chunkBatch.cpp +++ b/src/networking/packet/chunkBatch.cpp @@ -1,110 +1,125 @@ -#include "UUID.hpp" -#include "buffer.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "lib/UUID.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" #include void sendChunkBatchStart(Packet& packet, Server& server) { - std::cout << "=== Sending Chunk Batch Start ===\n"; + std::cout << "=== Sending Chunk Batch Start ===\n"; - // Chunk Batch Start has no fields - just the packet ID - Buffer buf; - // No data to write for this packet + // Chunk Batch Start has no fields - just the packet ID + Buffer buf; + // No data to write for this packet - int packetId = 0x0C; // Chunk Batch Start packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x0C; // Chunk Batch Start packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - if (!buf.getData().empty()) { - finalBuf.writeBytes(buf.getData()); - } + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + if (!buf.getData().empty()) { + finalBuf.writeBytes(buf.getData()); + } - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void sendChunkBatchFinished(Packet& packet, Server& server, int batchSize) { - std::cout << "=== Sending Chunk Batch Finished (batch size: " << batchSize << ") ===\n"; + std::cout << "=== Sending Chunk Batch Finished (batch size: " << batchSize << ") ===\n"; - Buffer buf; - buf.writeVarInt(batchSize); // Number of chunks in the batch + Buffer buf; + buf.writeVarInt(batchSize); // Number of chunks in the batch - int packetId = 0x0B; // Chunk Batch Finished packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x0B; // Chunk Batch Finished packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } -void sendChunkBatchSequence(Packet& packet, Server& server, ThreadSafeQueue* outgoingPackets) { - Player* player = packet.getPlayer(); - if (!player || !outgoingPackets) return; - - // Player spawn position (you should get this from player data) - int playerChunkX = 0; // player->getChunkX(); - int playerChunkZ = 0; // player->getChunkZ(); - - // Get view distance from player config - int viewDistance = 5; // Default - if (player->getPlayerConfig()) { - viewDistance = player->getPlayerConfig()->getViewDistance(); - } - - std::cout << "=== Starting chunk batch sequence for player: " << player->getPlayerName() - << " (view distance: " << viewDistance << ") ===\n"; - - // 1. Send Chunk Batch Start - try { - Packet* batchStartPacket = new Packet(packet); - sendChunkBatchStart(*batchStartPacket, server); - outgoingPackets->push(batchStartPacket); - } catch (const std::exception& e) { - std::cerr << "Error sending chunk batch start: " << e.what() << std::endl; - return; - } - - // 2. Send chunks in a radius around player - int chunksCount = 0; - for (int x = playerChunkX - viewDistance; x <= playerChunkX + viewDistance; x++) { - for (int z = playerChunkZ - viewDistance; z <= playerChunkZ + viewDistance; z++) { - try { - Packet* chunkPacket = new Packet(packet); - sendChunkData(*chunkPacket, server, x, z); - outgoingPackets->push(chunkPacket); - chunksCount++; - } catch (const std::exception& e) { - std::cerr << "Error sending chunk (" << x << ", " << z << "): " << e.what() << std::endl; - } - } - } - - // 3. Send Chunk Batch Finished - try { - Packet* batchFinishedPacket = new Packet(packet); - sendChunkBatchFinished(*batchFinishedPacket, server, chunksCount); - outgoingPackets->push(batchFinishedPacket); - } catch (const std::exception& e) { - std::cerr << "Error sending chunk batch finished: " << e.what() << std::endl; - return; - } - - std::cout << "=== Chunk batch sequence completed: " << chunksCount << " chunks sent ===\n"; +void sendChunkBatchSequence(Packet& packet, Server& server) { + Player* player = packet.getPlayer(); + ThreadSafeQueue* outgoingPackets = server.getNetworkManager().getOutgoingQueue(); + if (!player || !outgoingPackets) return; + + int playerChunkX = 0; + int playerChunkZ = 0; + int viewDistance = 3; // Reasonable size + + std::cout << "=== Starting chunk batch sequence for player: " << player->getPlayerName() << " (view distance: " << viewDistance << ") ===\n"; + + // 1. Send Chunk Batch Start + try { + Packet* batchStartPacket = new Packet(packet); + sendChunkBatchStart(*batchStartPacket, server); + outgoingPackets->push(batchStartPacket); + } catch (const std::exception& e) { + std::cerr << "Error sending chunk batch start: " << e.what() << std::endl; + return; + } + + // 2. Send chunks in smaller batches + int chunksCount = 0; + int batchSize = 0; + const int MAX_BATCH_SIZE = 16; // Limit chunks per batch + + for (int x = playerChunkX - viewDistance; x <= playerChunkX + viewDistance; x++) { + for (int z = playerChunkZ - viewDistance; z <= playerChunkZ + viewDistance; z++) { + try { + Packet* chunkPacket = new Packet(packet); + sendChunkData(*chunkPacket, server, x, z); + outgoingPackets->push(chunkPacket); + chunksCount++; + batchSize++; + + // Send batch finished and start new batch if we hit limit + if (batchSize >= MAX_BATCH_SIZE) { + // Send batch finished + Packet* batchFinishedPacket = new Packet(packet); + sendChunkBatchFinished(*batchFinishedPacket, server, batchSize); + outgoingPackets->push(batchFinishedPacket); + + // Start new batch + Packet* batchStartPacket = new Packet(packet); + sendChunkBatchStart(*batchStartPacket, server); + outgoingPackets->push(batchStartPacket); + + batchSize = 0; + } + + } catch (const std::exception& e) { + std::cerr << "Error sending chunk (" << x << ", " << z << "): " << e.what() << std::endl; + } + } + } + + // 3. Send final batch finished + if (batchSize > 0) { + try { + Packet* batchFinishedPacket = new Packet(packet); + sendChunkBatchFinished(*batchFinishedPacket, server, batchSize); + outgoingPackets->push(batchFinishedPacket); + } catch (const std::exception& e) { + std::cerr << "Error sending chunk batch finished: " << e.what() << std::endl; + } + } + + std::cout << "=== Chunk batch sequence completed: " << chunksCount << " chunks sent ===\n"; } diff --git a/src/networking/packet/chunkDataSimple.cpp b/src/networking/packet/chunkDataSimple.cpp index 75cc299..76de89a 100644 --- a/src/networking/packet/chunkDataSimple.cpp +++ b/src/networking/packet/chunkDataSimple.cpp @@ -1,171 +1,248 @@ -#include "UUID.hpp" -#include "buffer.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "lib/UUID.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" #include void sendChunkData(Packet& packet, Server& server, int chunkX, int chunkZ) { - std::cout << "=== Sending Chunk Data (" << chunkX << ", " << chunkZ << ") ===\n"; - - Buffer buf; - - // Chunk X and Z coordinates - buf.writeInt(chunkX); - buf.writeInt(chunkZ); - - // Heightmaps (NBT) - minimal implementation using empty compound tag - buf.writeByte(0x0A); - buf.writeByte(0x00); - buf.writeByte(0x00); - buf.writeByte(0x00); - - // Chunk data array - simplified version - Buffer chunkData; - - // Number of sections (24 sections for world height -64 to 319) - const int NUM_SECTIONS = 24; - - for (int section = 0; section < NUM_SECTIONS; section++) { - // Block count (non-air blocks in this section) - write as 2 bytes for short - buf.writeByte(0x00); - buf.writeByte(0x00); - - // Block states palette - chunkData.writeByte(0); - chunkData.writeVarInt(0); - chunkData.writeVarInt(0); - - // Biomes palette - chunkData.writeByte(0); - chunkData.writeVarInt(1); - chunkData.writeVarInt(0); - } - - // Write chunk data size and data - buf.writeVarInt(chunkData.getData().size()); - buf.writeBytes(chunkData.getData()); - - // Number of block entities - buf.writeVarInt(0); - - // Light data - simplified version - // Sky Light Mask (BitSet) - all sections have sky light - buf.writeVarInt(1); - buf.writeLong(0x1FFFFFF); - - // Block Light Mask (BitSet) - no block light - buf.writeVarInt(1); - buf.writeLong(0); - - // Empty Sky Light Mask - buf.writeVarInt(1); - buf.writeLong(0); - - // Empty Block Light Mask - buf.writeVarInt(1); - buf.writeLong(0); - - // Sky Light arrays (2048 bytes each for sections with sky light) - for (int i = 0; i < 25; i++) { - buf.writeVarInt(2048); - for (int j = 0; j < 2048; j++) { - buf.writeByte(0xFF); - } - } - - // No Block Light arrays since mask is 0 - - // Create final packet - int packetId = 0x27; - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); - - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); - - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); - - (void)server; + std::cout << "=== Sending Chunk Data (" << chunkX << ", " << chunkZ << ") ===\n"; + + Buffer buf; + + try { + // Use your new chunk loading system + World::Query query; + World::ChunkData chunkData = query.fetchChunk(chunkX, chunkZ); + + // Write chunk coordinates + buf.writeInt(chunkX); + buf.writeInt(chunkZ); + + // Write heightmaps (simplified) + if (!chunkData.heightmaps.empty()) { + buf.writeBytes(chunkData.heightmaps); + } else { + // Empty heightmap + buf.writeByte(0x0A); // Compound tag + buf.writeByte(0x00); // Empty name length + buf.writeByte(0x00); // End tag + } + + // Write chunk data + if (!chunkData.blockData.empty()) { + buf.writeVarInt(chunkData.blockData.size()); + buf.writeBytes(chunkData.blockData); + } else { + // Generate simple empty chunk inline + Buffer emptyData; + const int NUM_SECTIONS = 24; + + for (int section = 0; section < NUM_SECTIONS; section++) { + emptyData.writeByte(0x00); // Block count low + emptyData.writeByte(0x00); // Block count high + + // Block states - single air block + emptyData.writeByte(0); // Bits per entry + emptyData.writeVarInt(0); // Air block state + emptyData.writeVarInt(0); // No data array + + // Biomes - single plains biome + emptyData.writeByte(0); // Bits per entry + emptyData.writeVarInt(1); // Plains biome + emptyData.writeVarInt(0); // No data array + } + + buf.writeVarInt(emptyData.getData().size()); + buf.writeBytes(emptyData.getData()); + } + + // Block entities + buf.writeVarInt(0); + + // Light data (simplified version) + buf.writeVarInt(1); // Sky light mask length + buf.writeLong(0x1FFFFFF); // All sections have sky light + buf.writeVarInt(1); // Block light mask length + buf.writeLong(0); // No block light + buf.writeVarInt(1); // Empty sky light mask length + buf.writeLong(0); // No empty sky light sections + buf.writeVarInt(1); // Empty block light mask length + buf.writeLong(0); // No empty block light sections + + // Sky light arrays + for (int i = 0; i < 25; i++) { + buf.writeVarInt(2048); + for (int j = 0; j < 2048; j++) { + buf.writeByte(0xFF); + } + } + + } catch (const std::exception& e) { + std::cerr << "Error in sendChunkData: " << e.what() << std::endl; + // Return without setting packet data - this will cause the packet to be skipped + return; + } + + // Create final packet + int packetId = 0x27; + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); + + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); + + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); + + (void)server; +} + +// Helper function to generate empty chunk sections +Buffer generateEmptyChunkSections() { + Buffer chunkData; + const int NUM_SECTIONS = 24; // Sections for world height -64 to 319 + + for (int section = 0; section < NUM_SECTIONS; section++) { + // Block count (non-air blocks) - 0 for empty sections + chunkData.writeByte(0x00); + chunkData.writeByte(0x00); + + // Block states palette - single entry for air + chunkData.writeByte(0); // Bits per entry (0 = single valued) + chunkData.writeVarInt(0); // Air block state ID + chunkData.writeVarInt(0); // No data array needed for single valued + + // Biomes palette - single entry for plains + chunkData.writeByte(0); // Bits per entry (0 = single valued) + chunkData.writeVarInt(1); // Plains biome ID + chunkData.writeVarInt(0); // No data array needed for single valued + } + + return chunkData; +} + +// Helper function to write light data from loaded chunk +void writeLightData(Buffer& buf, const World::ChunkData& chunkData) { + if (!chunkData.skyLight.empty() || !chunkData.blockLight.empty()) { + // Use actual light data from chunk + writeActualLightData(buf, chunkData); + } else { + // Fallback to default light data + writeEmptyLightData(buf); + } +} + +void writeActualLightData(Buffer& buf, const World::ChunkData& chunkData) { + // This is complex - you need to reconstruct the light data format + // For now, fallback to empty light data + // TODO: Implement proper light data reconstruction from chunkData.skyLight and chunkData.blockLight + writeEmptyLightData(buf); +} + +void writeEmptyLightData(Buffer& buf) { + // Sky Light Mask (BitSet) - all sections have sky light + buf.writeVarInt(1); + buf.writeLong(0x1FFFFFF); + + // Block Light Mask (BitSet) - no block light + buf.writeVarInt(1); + buf.writeLong(0); + + // Empty Sky Light Mask + buf.writeVarInt(1); + buf.writeLong(0); + + // Empty Block Light Mask + buf.writeVarInt(1); + buf.writeLong(0); + + // Sky Light arrays (2048 bytes each for sections with sky light) + for (int i = 0; i < 25; i++) { + buf.writeVarInt(2048); + for (int j = 0; j < 2048; j++) { + buf.writeByte(0xFF); // Full sky light + } + } + // No Block Light arrays since mask is 0 } void sendPlayerPositionAndLook(Packet& packet, Server& server) { - std::cout << "=== Sending Player Position and Look ===\n"; + std::cout << "=== Sending Player Position and Look ===\n"; - Buffer buf; + Buffer buf; - // Teleport ID - buf.writeVarInt(1); + // Teleport ID + buf.writeVarInt(1); - // Player position (using writeLong for double precision storage) - // Note: This is a simplified approach - ideally you'd add writeDouble to Buffer - int64_t x_bits = 0x3FE0000000000000; - int64_t y_bits = 0x4050000000000000; - int64_t z_bits = 0x3FE0000000000000; + // Player position (using writeLong for double precision storage) + // Note: This is a simplified approach - ideally you'd add writeDouble to Buffer + int64_t x_bits = 0x3FE0000000000000; + int64_t y_bits = 0x4050000000000000; + int64_t z_bits = 0x3FE0000000000000; - buf.writeLong(x_bits); - buf.writeLong(y_bits); - buf.writeLong(z_bits); + buf.writeLong(x_bits); + buf.writeLong(y_bits); + buf.writeLong(z_bits); - // Velocity (all zero) - buf.writeLong(0); - buf.writeLong(0); - buf.writeLong(0); + // Velocity (all zero) + buf.writeLong(0); + buf.writeLong(0); + buf.writeLong(0); - // Rotation (using writeInt for float storage) - buf.writeInt(0); - buf.writeInt(0); + // Rotation (using writeInt for float storage) + buf.writeInt(0); + buf.writeInt(0); - // Flags (0x00 = absolute positioning) - buf.writeInt(0x00); + // Flags (0x00 = absolute positioning) + buf.writeInt(0x00); - int packetId = 0x41; - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x41; + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void sendSpawnPosition(Packet& packet, Server& server) { - std::cout << "=== Sending Spawn Position ===\n"; + std::cout << "=== Sending Spawn Position ===\n"; - Buffer buf; + Buffer buf; - // Encode position as long (X=0, Y=64, Z=0 packed into 64 bits) - // Position format: ((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF) - int64_t encodedPos = ((int64_t)0 << 38) | ((int64_t)0 << 12) | (64 & 0xFFF); - buf.writeLong(encodedPos); + // Encode position as long (X=0, Y=64, Z=0 packed into 64 bits) + // Position format: ((x & 0x3FFFFFF) << 38) | ((z & 0x3FFFFFF) << 12) | (y & 0xFFF) + int64_t encodedPos = ((int64_t)0 << 38) | ((int64_t)0 << 12) | (64 & 0xFFF); + buf.writeLong(encodedPos); - // Spawn angle (0.0f as int bits) - buf.writeInt(0); + // Spawn angle (0.0f as int bits) + buf.writeInt(0); - int packetId = 0x5A; // Set Default Spawn Position packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x5A; // Set Default Spawn Position packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } diff --git a/src/networking/packet/cookieRequest.cpp b/src/networking/packet/cookieRequest.cpp index 5cd75df..3118504 100644 --- a/src/networking/packet/cookieRequest.cpp +++ b/src/networking/packet/cookieRequest.cpp @@ -1,84 +1,93 @@ -#include "networking.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" #include "logger.hpp" -#include "buffer.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" + #include void handleCookieRequest(Packet& packet, Server& server) { - // g_logger->logNetwork(INFO, "Received Cookie Request in Configuration state", "Configuration"); - - Player* player = packet.getPlayer(); - if (!player) { - // g_logger->logNetwork(ERROR, "Error: No player associated with Cookie Request packet", "Configuration"); - packet.setReturnPacket(PACKET_DISCONNECT); - return; - } - - // Debug: Log raw packet data - // g_logger->logNetwork(INFO, "Cookie Request packet size: " + std::to_string(packet.getSize()) + " bytes", "Configuration"); - - // Read the cookie identifier from the request - std::string cookieIdentifier; - try { - // Create a fresh buffer from the packet data to read from beginning - Buffer cookieBuffer(packet.getData().getData()); - cookieIdentifier = cookieBuffer.readString(32767); // Max string length - // g_logger->logNetwork(INFO, "Cookie Request for identifier: '" + cookieIdentifier + "'", "Configuration"); - } catch (const std::exception& e) { - // g_logger->logNetwork(ERROR, "Failed to read cookie identifier: " + std::string(e.what()), "Configuration"); - // Send empty response instead of disconnecting - cookieIdentifier = "unknown"; - } - - // Create Cookie Response packet (0x01) - Buffer payload; - payload.writeVarInt(0x01); // Cookie Response packet ID - payload.writeString(cookieIdentifier); // Echo back the identifier - - // For now, send empty cookie data (no stored cookie) - payload.writeByte(0x00); // Has payload: false (no cookie data) - - Buffer final; - final.writeVarInt(payload.getData().size()); - final.writeBytes(payload.getData()); - - packet.getData() = final; - packet.setReturnPacket(PACKET_SEND); - packet.setPacketSize(final.getData().size()); - - // g_logger->logNetwork(INFO, "Sent Cookie Response for identifier: '" + cookieIdentifier + "' (no data), response size: " + std::to_string(final.getData().size()), "Configuration"); - - // g_logger->logNetwork(INFO, "Cookie Response sent - now sending Finish Configuration to advance sequence", "Configuration"); - - (void)server; // Suppress unused parameter warning + // g_logger->logNetwork(INFO, "Received Cookie Request in Configuration state", + // "Configuration"); + + Player* player = packet.getPlayer(); + if (!player) { + // g_logger->logNetwork(ERROR, "Error: No player associated with Cookie Request packet", + // "Configuration"); + packet.setReturnPacket(PACKET_DISCONNECT); + return; + } + + // Debug: Log raw packet data + // g_logger->logNetwork(INFO, "Cookie Request packet size: " + std::to_string(packet.getSize()) + // + " bytes", "Configuration"); + + // Read the cookie identifier from the request + std::string cookieIdentifier; + try { + // Create a fresh buffer from the packet data to read from beginning + Buffer cookieBuffer(packet.getData().getData()); + cookieIdentifier = cookieBuffer.readString(32767); // Max string length + // g_logger->logNetwork(INFO, "Cookie Request for identifier: '" + cookieIdentifier + "'", + // "Configuration"); + } catch (const std::exception& e) { + // g_logger->logNetwork(ERROR, "Failed to read cookie identifier: " + std::string(e.what()), + // "Configuration"); Send empty response instead of disconnecting + cookieIdentifier = "unknown"; + } + + // Create Cookie Response packet (0x01) + Buffer payload; + payload.writeVarInt(0x01); // Cookie Response packet ID + payload.writeString(cookieIdentifier); // Echo back the identifier + + // For now, send empty cookie data (no stored cookie) + payload.writeByte(0x00); // Has payload: false (no cookie data) + + Buffer final; + final.writeVarInt(payload.getData().size()); + final.writeBytes(payload.getData()); + + packet.getData() = final; + packet.setReturnPacket(PACKET_SEND); + packet.setPacketSize(final.getData().size()); + + // g_logger->logNetwork(INFO, "Sent Cookie Response for identifier: '" + cookieIdentifier + "' + // (no data), response size: " + std::to_string(final.getData().size()), "Configuration"); + + // g_logger->logNetwork(INFO, "Cookie Response sent - now sending Finish Configuration to + // advance sequence", "Configuration"); + + (void)server; // Suppress unused parameter warning } void sendFinishConfigurationAfterCookie(Packet& packet, Server& server) { - // g_logger->logNetwork(INFO, "Sending Finish Configuration to advance sequence", "Configuration"); - - Player* player = packet.getPlayer(); - if (!player) { - // g_logger->logNetwork(ERROR, "Error: No player for Finish Configuration", "Configuration"); - return; - } - - // Create Finish Configuration packet (0x03) - Buffer payload; - payload.writeVarInt(0x03); // Finish Configuration packet ID - - Buffer final; - final.writeVarInt(payload.getData().size()); - final.writeBytes(payload.getData()); - - // Create a new packet for Finish Configuration - Packet* finishPacket = new Packet(packet); - finishPacket->getData() = final; - finishPacket->setReturnPacket(PACKET_SEND); - finishPacket->setPacketSize(final.getData().size()); - - // g_logger->logNetwork(INFO, "Finish Configuration packet prepared", "Configuration"); - - (void)server; + // g_logger->logNetwork(INFO, "Sending Finish Configuration to advance sequence", + // "Configuration"); + + Player* player = packet.getPlayer(); + if (!player) { + // g_logger->logNetwork(ERROR, "Error: No player for Finish Configuration", + // "Configuration"); + return; + } + + // Create Finish Configuration packet (0x03) + Buffer payload; + payload.writeVarInt(0x03); // Finish Configuration packet ID + + Buffer final; + final.writeVarInt(payload.getData().size()); + final.writeBytes(payload.getData()); + + // Create a new packet for Finish Configuration + Packet* finishPacket = new Packet(packet); + finishPacket->getData() = final; + finishPacket->setReturnPacket(PACKET_SEND); + finishPacket->setPacketSize(final.getData().size()); + + // g_logger->logNetwork(INFO, "Finish Configuration packet prepared", "Configuration"); + + (void)server; } diff --git a/src/networking/packet/finishConfiguration.cpp b/src/networking/packet/finishConfiguration.cpp index e75801b..6bc95b6 100644 --- a/src/networking/packet/finishConfiguration.cpp +++ b/src/networking/packet/finishConfiguration.cpp @@ -1,56 +1,60 @@ -#include "networking.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" #include "logger.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" + #include void handleFinishConfiguration(Packet& packet, Server& server) { - // g_logger->logNetwork(INFO, "Starting configuration finish sequence", "Configuration"); + // g_logger->logNetwork(INFO, "Starting configuration finish sequence", "Configuration"); - Player* player = packet.getPlayer(); - if (!player) { - // g_logger->logNetwork(ERROR, "Error: No player associated with packet", "Configuration"); - packet.setReturnPacket(PACKET_DISCONNECT); - return; - } + Player* player = packet.getPlayer(); + if (!player) { + // g_logger->logNetwork(ERROR, "Error: No player associated with packet", "Configuration"); + packet.setReturnPacket(PACKET_DISCONNECT); + return; + } - // g_logger->logNetwork(INFO, "Sending Finish Configuration packet to " + player->getPlayerName(), "Configuration"); + // g_logger->logNetwork(INFO, "Sending Finish Configuration packet to " + + // player->getPlayerName(), "Configuration"); - // Send Finish Configuration packet (0x03) - Buffer payload; - payload.writeVarInt(0x03); // Finish Configuration packet ID + // Send Finish Configuration packet (0x03) + Buffer payload; + payload.writeVarInt(0x03); // Finish Configuration packet ID - Buffer final; - final.writeVarInt(payload.getData().size()); - final.writeBytes(payload.getData()); + Buffer final; + final.writeVarInt(payload.getData().size()); + final.writeBytes(payload.getData()); - packet.getData() = final; - packet.setReturnPacket(PACKET_SEND); - packet.setPacketSize(final.getData().size()); + packet.getData() = final; + packet.setReturnPacket(PACKET_SEND); + packet.setPacketSize(final.getData().size()); - // g_logger->logNetwork(INFO, "Finish Configuration packet sent, waiting for client acknowledgment", "Configuration"); + // g_logger->logNetwork(INFO, "Finish Configuration packet sent, waiting for client + // acknowledgment", "Configuration"); - (void)server; // Suppress unused parameter warning + (void)server; // Suppress unused parameter warning } void handleAcknowledgeFinishConfiguration(Packet& packet, Server& server) { - // g_logger->logNetwork(INFO, "Received Acknowledge Finish Configuration", "Configuration"); + // g_logger->logNetwork(INFO, "Received Acknowledge Finish Configuration", "Configuration"); - Player* player = packet.getPlayer(); - if (!player) { - // g_logger->logNetwork(ERROR, "Error: No player associated with packet", "Configuration"); - packet.setReturnPacket(PACKET_DISCONNECT); - return; - } + Player* player = packet.getPlayer(); + if (!player) { + // g_logger->logNetwork(ERROR, "Error: No player associated with packet", "Configuration"); + packet.setReturnPacket(PACKET_DISCONNECT); + return; + } - // Client has acknowledged finish configuration, now transition to Play state - player->setPlayerState(PlayerState::Play); + // Client has acknowledged finish configuration, now transition to Play state + player->setPlayerState(PlayerState::Play); - // g_logger->logNetwork(INFO, "Player " + player->getPlayerName() + " transitioned to Play state - ready for game packets", "Configuration"); + // g_logger->logNetwork(INFO, "Player " + player->getPlayerName() + " transitioned to Play state + // - ready for game packets", "Configuration"); - // Just acknowledge the packet - the actual game sequence will be triggered separately - packet.setReturnPacket(PACKET_OK); + // Just acknowledge the packet - the actual game sequence will be triggered separately + packet.setReturnPacket(PACKET_OK); - (void)server; // Suppress unused parameter warning + (void)server; // Suppress unused parameter warning } diff --git a/src/networking/packet/handleClientInformation.cpp b/src/networking/packet/handleClientInformation.cpp index 1a84fdc..d00036a 100644 --- a/src/networking/packet/handleClientInformation.cpp +++ b/src/networking/packet/handleClientInformation.cpp @@ -1,6 +1,6 @@ #include "logger.hpp" -#include "packet.hpp" -#include "server.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include @@ -31,11 +31,11 @@ void handleClientInformation(Packet& packet, Server& server) { // g_logger->logGameInfo( // INFO, "Main Hand: " + std::to_string(config->getMainHand()), "ClientInfo"); // g_logger->logGameInfo(INFO, - // "Enabled Text Filtering: " + std::to_string(config->getTextFiltering()), - // "ClientInfo"); + // "Enabled Text Filtering: " + + // std::to_string(config->getTextFiltering()), "ClientInfo"); // g_logger->logGameInfo(INFO, - // "Allow Server Listings: " + std::to_string(config->getServerListings()), - // "ClientInfo"); + // "Allow Server Listings: " + + // std::to_string(config->getServerListings()), "ClientInfo"); packet.setReturnPacket(PACKET_OK); (void)server; } diff --git a/src/networking/packet/handshake.cpp b/src/networking/packet/handshake.cpp index bbe728d..f44ab58 100644 --- a/src/networking/packet/handshake.cpp +++ b/src/networking/packet/handshake.cpp @@ -1,7 +1,7 @@ -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" #include "logger.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" #include #include @@ -13,11 +13,12 @@ void handleHandshakePacket(Packet& packet, Server& server) { packet.setReturnPacket(PACKET_DISCONNECT); return; } - int protocolVersion = packet.getData().readVarInt(); - std::string serverAddr = packet.getData().readString(255); - uint16_t port = packet.getData().readUShort(); - int nextState = packet.getData().readVarInt(); - // g_logger->logNetwork(INFO, "Protocol=" + std::to_string(protocolVersion) + ", Addr=" + serverAddr + ", State=" + std::to_string(nextState), "Handshake"); + int protocolVersion = packet.getData().readVarInt(); + std::string serverAddr = packet.getData().readString(255); + uint16_t port = packet.getData().readUShort(); + int nextState = packet.getData().readVarInt(); + // g_logger->logNetwork(INFO, "Protocol=" + std::to_string(protocolVersion) + ", Addr=" + + // serverAddr + ", State=" + std::to_string(nextState), "Handshake"); if (nextState == 1) { packet.getPlayer()->setPlayerState(PlayerState::Status); // g_logger->logNetwork(INFO, "Status request - keeping in temp list", "Handshake"); diff --git a/src/networking/packet/loginAcknowledged.cpp b/src/networking/packet/loginAcknowledged.cpp index d75a8f5..47d9d0b 100644 --- a/src/networking/packet/loginAcknowledged.cpp +++ b/src/networking/packet/loginAcknowledged.cpp @@ -1,30 +1,35 @@ -#include "networking.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" #include "logger.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" + #include void handleLoginAcknowledged(Packet& packet, Server& server) { - // g_logger->logNetwork(INFO, "Login Acknowledged received - transitioning to Configuration state", "Login"); + // g_logger->logNetwork(INFO, "Login Acknowledged received - transitioning to Configuration + // state", "Login"); - Player* player = packet.getPlayer(); - if (!player) { - // g_logger->logNetwork(ERROR, "Error: No player associated with Login Acknowledged packet", "Login"); - packet.setReturnPacket(PACKET_DISCONNECT); - return; - } + Player* player = packet.getPlayer(); + if (!player) { + // g_logger->logNetwork(ERROR, "Error: No player associated with Login Acknowledged packet", + // "Login"); + packet.setReturnPacket(PACKET_DISCONNECT); + return; + } - // The Login Acknowledged packet has no payload (0 bytes), so nothing to read + // The Login Acknowledged packet has no payload (0 bytes), so nothing to read - // The client has acknowledged the login success, now we officially transition to Configuration state - player->setPlayerState(PlayerState::Configuration); + // The client has acknowledged the login success, now we officially transition to Configuration + // state + player->setPlayerState(PlayerState::Configuration); - // g_logger->logNetwork(INFO, "Player " + player->getPlayerName() + " successfully acknowledged login - transitioned to Configuration state", "Login"); + // g_logger->logNetwork(INFO, "Player " + player->getPlayerName() + " successfully acknowledged + // login - transitioned to Configuration state", "Login"); - // Just acknowledge the packet - don't send anything yet - // The client will send Client Information (packet 0x03) next in Configuration state - packet.setReturnPacket(PACKET_OK); + // Just acknowledge the packet - don't send anything yet + // The client will send Client Information (packet 0x03) next in Configuration state + packet.setReturnPacket(PACKET_OK); - (void)server; // Suppress unused parameter warning + (void)server; // Suppress unused parameter warning } diff --git a/src/networking/packet/loginStart.cpp b/src/networking/packet/loginStart.cpp index 0febb03..721af5d 100644 --- a/src/networking/packet/loginStart.cpp +++ b/src/networking/packet/loginStart.cpp @@ -1,12 +1,11 @@ -#include "UUID.hpp" -#include "buffer.hpp" -#include "networking.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" +#include "lib/UUID.hpp" #include "logger.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" -#include #include void handleLoginStartPacket(Packet& packet, Server& server) { @@ -25,7 +24,7 @@ void handleLoginStartPacket(Packet& packet, Server& server) { payload.writeUUID(uuid); payload.writeString(username); payload.writeVarInt(0); // properties length (no properties) - + // Debug: Log the raw payload bytes std::string payloadHex = ""; for (size_t i = 0; i < payload.getData().size(); i++) { @@ -37,20 +36,20 @@ void handleLoginStartPacket(Packet& packet, Server& server) { g_logger->logNetwork(INFO, "Login Success payload bytes: " + payloadHex, "Login"); // Calculate total packet size (packet ID + payload) - int packetId = 0x02; - int payloadSize = payload.getData().size(); + int packetId = 0x02; + int payloadSize = payload.getData().size(); int packetIdVarintSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdVarintSize + payloadSize; + int totalPayloadSize = packetIdVarintSize + payloadSize; Buffer final; - final.writeVarInt(totalPayloadSize); // Total packet size - final.writeVarInt(packetId); // Login Success packet ID (0x02) - final.writeBytes(payload.getData()); // UUID + username + properties + final.writeVarInt(totalPayloadSize); // Total packet size + final.writeVarInt(packetId); // Login Success packet ID (0x02) + final.writeBytes(payload.getData()); // UUID + username + properties packet.getData() = final; packet.setReturnPacket(PACKET_SEND); packet.setPacketSize(final.getData().size()); - + // Debug: Log the complete packet bytes std::string finalHex = ""; for (size_t i = 0; i < final.getData().size(); i++) { @@ -60,8 +59,11 @@ void handleLoginStartPacket(Packet& packet, Server& server) { if (i < final.getData().size() - 1) finalHex += " "; } g_logger->logNetwork(INFO, "Complete Login Success packet bytes: " + finalHex, "Login"); - + // Don't transition to Configuration yet - wait for Login Acknowledged - g_logger->logNetwork(INFO, "Login Success sent for user: " + username + ", UUID: " + uuid.toString() + ", packet size: " + std::to_string(final.getData().size()), "Login"); + g_logger->logNetwork(INFO, + "Login Success sent for user: " + username + ", UUID: " + uuid.toString() + + ", packet size: " + std::to_string(final.getData().size()), + "Login"); (void)server; } diff --git a/src/networking/packet/packetRouter.cpp b/src/networking/packet/packetRouter.cpp index 55679dc..b2cdaca 100644 --- a/src/networking/packet/packetRouter.cpp +++ b/src/networking/packet/packetRouter.cpp @@ -1,33 +1,27 @@ #include "logger.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" - -#include - -// Forward declarations of state handlers -void handleHandshakeState(Packet* packet, - Server& server, - ThreadSafeQueue* outgoingPackets); -void handleStatusState(Packet* packet, Server& server, ThreadSafeQueue* outgoingPackets); -void handleLoginState(Packet* packet, Server& server, ThreadSafeQueue* outgoingPackets); -void handleConfigurationState(Packet* packet, - Server& server, - ThreadSafeQueue* outgoingPackets); -void handlePlayState(Packet* packet, Server& server, ThreadSafeQueue* outgoingPackets); -void sendDisconnectPacket(Packet* packet, - const std::string& reason, - ThreadSafeQueue* outgoingPackets); -void initGameSequence(Packet* packet, ThreadSafeQueue* _outgoingPackets, Server& server); + +#include + +void handleHandshakeState(Packet* packet, Server& server); +void handleStatusState(Packet* packet, Server& server); +void handleLoginState(Packet* packet, Server& server); +void handleConfigurationState(Packet* packet, Server& server); +void handlePlayState(Packet* packet, Server& server); +void sendDisconnectPacket(Packet* packet, const std::string& reason, Server& server); +void initGameSequence(Packet* packet, Server& server); // ======================================== // Main Packet Router // ======================================== -void packetRouter(Packet* packet, Server& server, ThreadSafeQueue* _outgoingPackets) { +void packetRouter(Packet* packet, Server& server) { + if (packet == nullptr) return; - if (_outgoingPackets == nullptr) return; + if (server.getNetworkManager().getOutgoingQueue() == nullptr) return; Player* player = packet->getPlayer(); @@ -37,33 +31,29 @@ void packetRouter(Packet* packet, Server& server, ThreadSafeQueue* _out } g_logger->logNetwork(INFO, - "Routing packet ID: 0x" + std::to_string(packet->getId()) + - " (size: " + std::to_string(packet->getSize()) + ") for state: " + - std::to_string(static_cast(player->getPlayerState())), - "PacketRouter"); + "Routing packet ID: 0x" + std::to_string(packet->getId()) + " (size: " + std::to_string(packet->getSize()) + + ") for state: " + std::to_string(static_cast(player->getPlayerState())), + "PacketRouter"); switch (player->getPlayerState()) { case PlayerState::Handshake: - handleHandshakeState(packet, server, _outgoingPackets); + handleHandshakeState(packet, server); break; case PlayerState::Status: - handleStatusState(packet, server, _outgoingPackets); + handleStatusState(packet, server); break; case PlayerState::Login: - handleLoginState(packet, server, _outgoingPackets); + handleLoginState(packet, server); break; case PlayerState::Configuration: - handleConfigurationState(packet, server, _outgoingPackets); + handleConfigurationState(packet, server); break; case PlayerState::Play: - handlePlayState(packet, server, _outgoingPackets); + handlePlayState(packet, server); break; default: - g_logger->logNetwork(WARN, - "Unknown player state: " + - std::to_string(static_cast(player->getPlayerState())) + - ", disconnecting", - "PacketRouter"); + g_logger->logNetwork( + WARN, "Unknown player state: " + std::to_string(static_cast(player->getPlayerState())) + ", disconnecting", "PacketRouter"); packet->setReturnPacket(PACKET_DISCONNECT); break; } @@ -73,26 +63,19 @@ void packetRouter(Packet* packet, Server& server, ThreadSafeQueue* _out // Handshake State Handler // ======================================== -void handleHandshakeState(Packet* packet, - Server& server, - ThreadSafeQueue* outgoingPackets) { - handleHandshakePacket(*packet, server); -} +void handleHandshakeState(Packet* packet, Server& server) { handleHandshakePacket(*packet, server); } // ======================================== // Status State Handler // ======================================== -void handleStatusState(Packet* packet, Server& server, ThreadSafeQueue* outgoingPackets) { +void handleStatusState(Packet* packet, Server& server) { if (packet->getId() == 0x00) { handleStatusPacket(*packet, server); } else if (packet->getId() == 0x01) { handlePingPacket(*packet, server); } else { - g_logger->logNetwork(WARN, - "Unknown packet ID in Status state: 0x" + - std::to_string(packet->getId()), - "PacketRouter"); + g_logger->logNetwork(WARN, "Unknown packet ID in Status state: 0x" + std::to_string(packet->getId()), "PacketRouter"); packet->getPlayer()->setPlayerState(PlayerState::None); packet->setReturnPacket(PACKET_DISCONNECT); } @@ -102,12 +85,10 @@ void handleStatusState(Packet* packet, Server& server, ThreadSafeQueue* // Login State Handler // ======================================== -void handleLoginState(Packet* packet, Server& server, ThreadSafeQueue* outgoingPackets) { +void handleLoginState(Packet* packet, Server& server) { // Add safety check for packet data integrity if (packet->getSize() > 32767) { // Max packet size - g_logger->logNetwork(ERROR, - "Packet size too large: " + std::to_string(packet->getSize()), - "PacketRouter"); + g_logger->logNetwork(ERROR, "Packet size too large: " + std::to_string(packet->getSize()), "PacketRouter"); packet->setReturnPacket(PACKET_DISCONNECT); return; } @@ -118,8 +99,7 @@ void handleLoginState(Packet* packet, Server& server, ThreadSafeQueue* handleLoginStartPacket(*packet, server); } else if (packet->getId() == 0x02) { // Login Plugin Response - safe to ignore most of the time - g_logger->logNetwork( - INFO, "Received Login Plugin Response (0x02) - acknowledging", "PacketRouter"); + g_logger->logNetwork(INFO, "Received Login Plugin Response (0x02) - acknowledging", "PacketRouter"); packet->setReturnPacket(PACKET_OK); } else if (packet->getId() == 0x03) { // Login Acknowledged @@ -127,14 +107,10 @@ void handleLoginState(Packet* packet, Server& server, ThreadSafeQueue* handleLoginAcknowledged(*packet, server); } else if (packet->getId() == 0x04) { // Cookie Response (login) - g_logger->logNetwork( - INFO, "Received Login Cookie Response (0x04) - acknowledging", "PacketRouter"); + g_logger->logNetwork(INFO, "Received Login Cookie Response (0x04) - acknowledging", "PacketRouter"); packet->setReturnPacket(PACKET_OK); } else { - g_logger->logNetwork(WARN, - "Unknown packet ID in Login state: 0x" + - std::to_string(packet->getId()), - "PacketRouter"); + g_logger->logNetwork(WARN, "Unknown packet ID in Login state: 0x" + std::to_string(packet->getId()), "PacketRouter"); packet->getPlayer()->setPlayerState(PlayerState::None); packet->setReturnPacket(PACKET_DISCONNECT); } @@ -144,9 +120,7 @@ void handleLoginState(Packet* packet, Server& server, ThreadSafeQueue* // Configuration State Handler // ======================================== -void handleConfigurationState(Packet* packet, - Server& server, - ThreadSafeQueue* outgoingPackets) { +void handleConfigurationState(Packet* packet, Server& server) { if (packet->getId() == 0x00) { // Client Information (configuration) // g_logger->logNetwork(INFO, "Received Client Information in Configuration state", @@ -157,7 +131,7 @@ void handleConfigurationState(Packet* packet, // After processing client info, tell client we're done configuring Packet* finishPacket = new Packet(*packet); handleFinishConfiguration(*finishPacket, server); - outgoingPackets->push(finishPacket); + server.getNetworkManager().getOutgoingQueue()->push(finishPacket); // g_logger->logNetwork(INFO, "Sent Finish Configuration after Client Information", // "Configuration"); @@ -169,20 +143,15 @@ void handleConfigurationState(Packet* packet, } else if (packet->getId() == 0x02) { // Serverbound Plugin Message (configuration) - g_logger->logNetwork(INFO, - "Received Serverbound Plugin Message (0x02), size: " + - std::to_string(packet->getSize()) + " bytes", - "PacketRouter"); + g_logger->logNetwork( + INFO, "Received Serverbound Plugin Message (0x02), size: " + std::to_string(packet->getSize()) + " bytes", "PacketRouter"); packet->setReturnPacket(PACKET_OK); } else if (packet->getId() == 0x03) { // Acknowledge Finish Configuration -> enter Play - g_logger->logNetwork( - INFO, - "Received Acknowledge Finish Configuration - transitioning to Play state", - "PacketRouter"); + g_logger->logNetwork(INFO, "Received Acknowledge Finish Configuration - transitioning to Play state", "PacketRouter"); handleAcknowledgeFinishConfiguration(*packet, server); - initGameSequence(packet, outgoingPackets, server); + initGameSequence(packet, server); } else if (packet->getId() == 0x04) { // Keep Alive (configuration) @@ -214,11 +183,8 @@ void handleConfigurationState(Packet* packet, packet->setReturnPacket(PACKET_OK); } else { - g_logger->logNetwork(WARN, - "Unknown packet ID in Configuration state: 0x" + - std::to_string(packet->getId()), - "PacketRouter"); - sendDisconnectPacket(packet, "Unknown packet in Configuration state", outgoingPackets); + g_logger->logNetwork(WARN, "Unknown packet ID in Configuration state: 0x" + std::to_string(packet->getId()), "PacketRouter"); + sendDisconnectPacket(packet, "Unknown packet in Configuration state", server); packet->getPlayer()->setPlayerState(PlayerState::None); packet->setReturnPacket(PACKET_DISCONNECT); } @@ -228,7 +194,7 @@ void handleConfigurationState(Packet* packet, // Play State Handler // ======================================== -void handlePlayState(Packet* packet, Server& server, ThreadSafeQueue* outgoingPackets) { +void handlePlayState(Packet* packet, Server& server) { if (packet->getId() == 0x00) { // Confirm Teleportation handleConfirmTeleportation(*packet, server); @@ -247,16 +213,14 @@ void handlePlayState(Packet* packet, Server& server, ThreadSafeQueue* o // Disconnect Packet Creation // ======================================== -void sendDisconnectPacket(Packet* packet, - const std::string& reason, - ThreadSafeQueue* outgoingPackets) { +void sendDisconnectPacket(Packet* packet, const std::string& reason, Server& server) { + ThreadSafeQueue* outgoingPackets = server.getNetworkManager().getOutgoingQueue(); if (!packet || !outgoingPackets) return; Player* player = packet->getPlayer(); if (!player) return; - g_logger->logNetwork( - INFO, "Sending disconnect packet to player with reason: " + reason, "PacketRouter"); + g_logger->logNetwork(INFO, "Sending disconnect packet to player with reason: " + reason, "PacketRouter"); try { // Create Disconnect packet (0x02 in Configuration state) @@ -272,7 +236,7 @@ void sendDisconnectPacket(Packet* packet, final.writeBytes(payload.getData()); // Create new packet for disconnect - Packet* disconnectPacket = new Packet(*packet); + Packet* disconnectPacket = new Packet(*packet); disconnectPacket->getData() = final; disconnectPacket->setReturnPacket(PACKET_SEND); disconnectPacket->setPacketSize(final.getData().size()); @@ -281,9 +245,7 @@ void sendDisconnectPacket(Packet* packet, g_logger->logNetwork(INFO, "Disconnect packet queued for sending", "PacketRouter"); } catch (const std::exception& e) { - g_logger->logNetwork(ERROR, - "Error creating disconnect packet: " + std::string(e.what()), - "PacketRouter"); + g_logger->logNetwork(ERROR, "Error creating disconnect packet: " + std::string(e.what()), "PacketRouter"); } } @@ -291,50 +253,48 @@ void sendDisconnectPacket(Packet* packet, // Game Initialization Sequence // ======================================== -void initGameSequence(Packet* packet, ThreadSafeQueue* _outgoingPackets, Server& server) { - if (packet == nullptr || _outgoingPackets == nullptr) return; +void initGameSequence(Packet* packet, Server& server) { + if (packet == nullptr || server.getNetworkManager().getOutgoingQueue() == nullptr) return; Player* player = packet->getPlayer(); if (player == nullptr) return; // Player should already be in Play state at this point - g_logger->logNetwork( - INFO, "Starting game sequence for player: " + player->getPlayerName(), "PacketRouter"); + g_logger->logNetwork(INFO, "Starting game sequence for player: " + player->getPlayerName(), "PacketRouter"); try { // 1. Send Login (play) packet - 0x2B g_logger->logNetwork(INFO, "Sending Login (play) packet", "PacketRouter"); Packet* playPacket = new Packet(*packet); - writePlayPacket(*playPacket, server); - _outgoingPackets->push(playPacket); + writePlayPacket(*playPacket); + server.getNetworkManager().getOutgoingQueue()->push(playPacket); // 2. Send Set Center Chunk - 0x57 Packet* setCenterPacket = new Packet(*packet); writeSetCenterPacket(*setCenterPacket, server); - _outgoingPackets->push(setCenterPacket); + server.getNetworkManager().getOutgoingQueue()->push(setCenterPacket); // 3. Send complete chunk batch sequence (Start -> Chunks -> Finished) - sendChunkBatchSequence(*packet, server, _outgoingPackets); + sendChunkBatchSequence(*packet, server); // 4. Send player position and look - 0x41 Packet* positionPacket = new Packet(*packet); sendPlayerPositionAndLook(*positionPacket, server); - _outgoingPackets->push(positionPacket); + server.getNetworkManager().getOutgoingQueue()->push(positionPacket); // 5. Send spawn position - 0x5A Packet* spawnPacket = new Packet(*packet); sendSpawnPosition(*spawnPacket, server); - _outgoingPackets->push(spawnPacket); + server.getNetworkManager().getOutgoingQueue()->push(spawnPacket); // // 6. Complete spawn sequence (abilities, health, experience, time, held item) - completeSpawnSequence(*packet, server, _outgoingPackets); + completeSpawnSequence(*packet, server); g_logger->logNetwork(INFO, "Complete game sequence sent to player: ", "PacketRouter"); packet->setReturnPacket(PACKET_OK); } catch (const std::exception& e) { - g_logger->logNetwork( - ERROR, "Error in game sequence: " + std::string(e.what()), "PacketRouter"); + g_logger->logNetwork(ERROR, "Error in game sequence: " + std::string(e.what()), "PacketRouter"); packet->setReturnPacket(PACKET_ERROR); } } diff --git a/src/networking/packet/ping.cpp b/src/networking/packet/ping.cpp index eaf7a40..e104535 100644 --- a/src/networking/packet/ping.cpp +++ b/src/networking/packet/ping.cpp @@ -1,9 +1,9 @@ -#include "buffer.hpp" -#include "networking.hpp" -#include "packet.hpp" -#include "player.hpp" -#include "server.hpp" #include "logger.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" +#include "player.hpp" #include @@ -16,9 +16,10 @@ void handlePingPacket(Packet& packet, Server& server) { long timestamp = packet.getData().readLong(); - // g_logger->logNetwork(INFO, "Received ping request with timestamp: " + std::to_string(timestamp), "Ping"); + // g_logger->logNetwork(INFO, "Received ping request with timestamp: " + + // std::to_string(timestamp), "Ping"); - int packetId = 0x01; + int packetId = 0x01; int packetIdVarintSize = packet.getVarintSize(packetId); int totalPayloadSize = packetIdVarintSize + 8; @@ -32,7 +33,8 @@ void handlePingPacket(Packet& packet, Server& server) { packet.setPacketSize(buf.getData().size()); packet.getPlayer()->setPlayerState(PlayerState::None); - // g_logger->logNetwork(INFO, "Pong response ready - echoing timestamp " + std::to_string(timestamp), "Ping"); + // g_logger->logNetwork(INFO, "Pong response ready - echoing timestamp " + + // std::to_string(timestamp), "Ping"); (void)server; } diff --git a/src/networking/packet/play.cpp b/src/networking/packet/play.cpp index 258a967..da584f6 100644 --- a/src/networking/packet/play.cpp +++ b/src/networking/packet/play.cpp @@ -1,86 +1,81 @@ -#include -#include -#include -#include -#include +#include "network/buffer.hpp" +#include "network/packet.hpp" +#include "player.hpp" -#include "networking.hpp" -#include "server.hpp" -#include "packet.hpp" -#include "buffer.hpp" +#include -void writePlayPacket(Packet& packet, Server& server) { - Player* player = packet.getPlayer(); - if (!player) return; +void writePlayPacket(Packet& packet) { + Player* player = packet.getPlayer(); + if (!player) return; - Buffer buf; + Buffer buf; - // 1. Entity ID - buf.writeInt(player->getPlayerID()); + // 1. Entity ID + buf.writeInt(player->getPlayerID()); - // 2. Is Hardcore (false) - buf.writeBool(false); + // 2. Is Hardcore (false) + buf.writeBool(false); - // 3. Game mode (survival = 0) - buf.writeByte(0); + // 3. Game mode (survival = 0) + buf.writeByte(0); - // 4. Previous game mode (-1 = not set) - buf.writeByte(-1); + // 4. Previous game mode (-1 = not set) + buf.writeByte(-1); - // 5. World names (just overworld for now) - buf.writeVarInt(1); // Number of worlds - buf.writeString("minecraft:overworld"); + // 5. World names (just overworld for now) + buf.writeVarInt(1); // Number of worlds + buf.writeString("minecraft:overworld"); - // 6. Registry codec (empty/minimal for now) - // We'll write a minimal empty NBT structure - buf.writeByte(0x0A); // TAG_Compound - buf.writeByte(0); // Short value (high byte) - buf.writeByte(0); // Short value (low byte) - buf.writeByte(0x00); // TAG_End + // 6. Registry codec (empty/minimal for now) + // We'll write a minimal empty NBT structure + buf.writeByte(0x0A); // TAG_Compound + buf.writeByte(0); // Short value (high byte) + buf.writeByte(0); // Short value (low byte) + buf.writeByte(0x00); // TAG_End - // 7. Dimension (empty/minimal for now) - // We'll write a minimal empty NBT structure - buf.writeByte(0x0A); // TAG_Compound - buf.writeByte(0); // Short value (high byte) - buf.writeByte(0); // Short value (low byte) - buf.writeByte(0x00); // TAG_End + // 7. Dimension (empty/minimal for now) + // We'll write a minimal empty NBT structure + buf.writeByte(0x0A); // TAG_Compound + buf.writeByte(0); // Short value (high byte) + buf.writeByte(0); // Short value (low byte) + buf.writeByte(0x00); // TAG_End - // 8. World name - buf.writeString("minecraft:overworld"); + // 8. World name + buf.writeString("minecraft:overworld"); - // 9. Hashed seed - buf.writeLong(12345678L); + // 9. Hashed seed + buf.writeLong(12345678L); - // 10. Max players - buf.writeVarInt(20); + // 10. Max players + buf.writeVarInt(20); - // 11. View distance - buf.writeVarInt(10); + // 11. View distance + buf.writeVarInt(10); - // 12. Simulation distance - buf.writeVarInt(10); + // 12. Simulation distance + buf.writeVarInt(10); - // 13. Reduced debug info - buf.writeBool(false); + // 13. Reduced debug info + buf.writeBool(false); - // 14. Enable respawn screen - buf.writeBool(true); + // 14. Enable respawn screen + buf.writeBool(true); - // 15. Do limited crafting - buf.writeBool(false); + // 15. Do limited crafting + buf.writeBool(false); - // 16. Dimension type - buf.writeString("minecraft:overworld"); + // 16. Dimension type + buf.writeString("minecraft:overworld"); - // 17. Dimension name - buf.writeString("minecraft:overworld"); + // 17. Dimension name + buf.writeString("minecraft:overworld"); - // 18. Portal cooldown - buf.writeVarInt(0); + // 18. Portal cooldown + buf.writeVarInt(0); - // 19. Enforces secure chat - buf.writeBool(false); + // 19. Enforces secure chat + buf.writeBool(false); - packet.setPacketId(0x2B); // Login (play) packet ID - packet.getData() = buf; + packet.setPacketId(0x2B); // Login (play) packet ID + packet.getData() = buf; } diff --git a/src/networking/packet/setCenterChunck.cpp b/src/networking/packet/setCenterChunck.cpp index 6b84f5b..5e161be 100644 --- a/src/networking/packet/setCenterChunck.cpp +++ b/src/networking/packet/setCenterChunck.cpp @@ -1,9 +1,9 @@ -#include "UUID.hpp" -#include "buffer.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "lib/UUID.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" #include @@ -14,8 +14,8 @@ void writeSetCenterPacket(Packet& packet, Server& server) { buf.writeVarInt(0); buf.writeVarInt(0); - int packetId = 0x57; - int packetIdSize = packet.getVarintSize(packetId); + int packetId = 0x57; + int packetIdSize = packet.getVarintSize(packetId); int totalPayloadSize = packetIdSize + buf.getData().size(); Buffer finalBuf; diff --git a/src/networking/packet/spawnSequence.cpp b/src/networking/packet/spawnSequence.cpp index 4473443..ca9044a 100644 --- a/src/networking/packet/spawnSequence.cpp +++ b/src/networking/packet/spawnSequence.cpp @@ -1,216 +1,218 @@ -#include "UUID.hpp" -#include "buffer.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "lib/UUID.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" #include void sendPlayerAbilities(Packet& packet, Server& server) { - std::cout << "=== Sending Player Abilities ===\n"; + std::cout << "=== Sending Player Abilities ===\n"; - Buffer buf; + Buffer buf; - // Flags (byte) - bit field for player abilities - uint8_t flags = 0x00; - // 0x01: Invulnerable - // 0x02: Flying - // 0x04: Allow Flying (creative mode) - // 0x08: Creative Mode (instant break) - buf.writeByte(flags); + // Flags (byte) - bit field for player abilities + uint8_t flags = 0x00; + // 0x01: Invulnerable + // 0x02: Flying + // 0x04: Allow Flying (creative mode) + // 0x08: Creative Mode (instant break) + buf.writeByte(flags); - // Flying Speed (float) - 0.05 by default - // Convert 0.05f to IEEE 754 bits: 0x3D4CCCCD - buf.writeInt(0x3D4CCCCD); + // Flying Speed (float) - 0.05 by default + // Convert 0.05f to IEEE 754 bits: 0x3D4CCCCD + buf.writeInt(0x3D4CCCCD); - // Field of View Modifier (float) - 0.1 by default - // Convert 0.1f to IEEE 754 bits: 0x3DCCCCCD - buf.writeInt(0x3DCCCCCD); + // Field of View Modifier (float) - 0.1 by default + // Convert 0.1f to IEEE 754 bits: 0x3DCCCCCD + buf.writeInt(0x3DCCCCCD); - int packetId = 0x39; // Player Abilities packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x39; // Player Abilities packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void sendSetHealth(Packet& packet, Server& server) { - std::cout << "=== Sending Set Health ===\n"; + std::cout << "=== Sending Set Health ===\n"; - Buffer buf; + Buffer buf; - // Health (float) - 20.0 = full health - // Convert 20.0f to IEEE 754 bits: 0x41A00000 - buf.writeInt(0x41A00000); + // Health (float) - 20.0 = full health + // Convert 20.0f to IEEE 754 bits: 0x41A00000 + buf.writeInt(0x41A00000); - // Food (VarInt) - 20 = full food bar - buf.writeVarInt(20); + // Food (VarInt) - 20 = full food bar + buf.writeVarInt(20); - // Food Saturation (float) - 5.0 by default - // Convert 5.0f to IEEE 754 bits: 0x40A00000 - buf.writeInt(0x40A00000); + // Food Saturation (float) - 5.0 by default + // Convert 5.0f to IEEE 754 bits: 0x40A00000 + buf.writeInt(0x40A00000); - int packetId = 0x61; // Set Health packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x61; // Set Health packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void sendSetExperience(Packet& packet, Server& server) { - std::cout << "=== Sending Set Experience ===\n"; + std::cout << "=== Sending Set Experience ===\n"; - Buffer buf; + Buffer buf; - // Experience bar (float) - 0.0 to 1.0 (progress to next level) - // Convert 0.0f to IEEE 754 bits: 0x00000000 - buf.writeInt(0x00000000); + // Experience bar (float) - 0.0 to 1.0 (progress to next level) + // Convert 0.0f to IEEE 754 bits: 0x00000000 + buf.writeInt(0x00000000); - // Level (VarInt) - current experience level - buf.writeVarInt(0); + // Level (VarInt) - current experience level + buf.writeVarInt(0); - // Total Experience (VarInt) - total experience points - buf.writeVarInt(0); + // Total Experience (VarInt) - total experience points + buf.writeVarInt(0); - int packetId = 0x60; // Set Experience packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x60; // Set Experience packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void sendUpdateTime(Packet& packet, Server& server) { - std::cout << "=== Sending Update Time ===\n"; + std::cout << "=== Sending Update Time ===\n"; - Buffer buf; + Buffer buf; - // World Age (Long) - total ticks since world creation - buf.writeLong(0); + // World Age (Long) - total ticks since world creation + buf.writeLong(0); - // Time of day (Long) - 0 = sunrise, 6000 = noon, 12000 = sunset, 18000 = midnight - buf.writeLong(1000); // Morning time + // Time of day (Long) - 0 = sunrise, 6000 = noon, 12000 = sunset, 18000 = midnight + buf.writeLong(1000); // Morning time - // Time of day increasing (Boolean) - should client auto-advance time - buf.writeByte(0x01); // true + // Time of day increasing (Boolean) - should client auto-advance time + buf.writeByte(0x01); // true - int packetId = 0x6A; // Update Time packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x6A; // Update Time packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void sendSetHeldItem(Packet& packet, Server& server) { - std::cout << "=== Sending Set Held Item ===\n"; + std::cout << "=== Sending Set Held Item ===\n"; - Buffer buf; + Buffer buf; - // Slot (VarInt) - hotbar slot selected (0-8) - buf.writeVarInt(0); // First slot selected + // Slot (VarInt) - hotbar slot selected (0-8) + buf.writeVarInt(0); // First slot selected - int packetId = 0x62; // Set Held Item packet ID for protocol 770 - int packetIdSize = packet.getVarintSize(packetId); - int totalPayloadSize = packetIdSize + buf.getData().size(); + int packetId = 0x62; // Set Held Item packet ID for protocol 770 + int packetIdSize = packet.getVarintSize(packetId); + int totalPayloadSize = packetIdSize + buf.getData().size(); - Buffer finalBuf; - finalBuf.writeVarInt(totalPayloadSize); - finalBuf.writeVarInt(packetId); - finalBuf.writeBytes(buf.getData()); + Buffer finalBuf; + finalBuf.writeVarInt(totalPayloadSize); + finalBuf.writeVarInt(packetId); + finalBuf.writeBytes(buf.getData()); - packet.getData() = finalBuf; - packet.setPacketSize(finalBuf.getData().size()); - packet.setReturnPacket(PACKET_SEND); + packet.getData() = finalBuf; + packet.setPacketSize(finalBuf.getData().size()); + packet.setReturnPacket(PACKET_SEND); - (void)server; + (void)server; } void handleConfirmTeleportation(Packet& packet, Server& server) { - std::cout << "=== Received Confirm Teleportation ===\n"; + std::cout << "=== Received Confirm Teleportation ===\n"; - // Read teleport ID from packet data - int teleportId = packet.getData().readVarInt(); + // Read teleport ID from packet data + int teleportId = packet.getData().readVarInt(); - std::cout << "Player confirmed teleportation with ID: " << teleportId << std::endl; + std::cout << "Player confirmed teleportation with ID: " << teleportId << std::endl; - // Mark packet as processed - packet.setReturnPacket(PACKET_OK); + // Mark packet as processed + packet.setReturnPacket(PACKET_OK); - (void)server; + (void)server; } -void completeSpawnSequence(Packet& packet, Server& server, ThreadSafeQueue* outgoingPackets) { - Player* player = packet.getPlayer(); - if (!player || !outgoingPackets) return; - - // std::cout << "=== Completing spawn sequence for player: " << player->getPlayerName() << " ===\n"; - std::cout << "=== Completing spawn sequence for player: " << " ===\n"; - - try { - // 9. Player Abilities (0x39) - Packet* abilitiesPacket = new Packet(packet); - sendPlayerAbilities(*abilitiesPacket, server); - outgoingPackets->push(abilitiesPacket); - - // 10. Set Health (0x61) - Packet* healthPacket = new Packet(packet); - sendSetHealth(*healthPacket, server); - outgoingPackets->push(healthPacket); - - // 11. Set Experience (0x60) - Packet* experiencePacket = new Packet(packet); - sendSetExperience(*experiencePacket, server); - outgoingPackets->push(experiencePacket); - - // 12. Update Time (0x6A) - Packet* timePacket = new Packet(packet); - sendUpdateTime(*timePacket, server); - outgoingPackets->push(timePacket); - - // 13. Set Held Item (0x62) - Packet* heldItemPacket = new Packet(packet); - sendSetHeldItem(*heldItemPacket, server); - outgoingPackets->push(heldItemPacket); - - std::cout << "=== Spawn sequence completed! Player should now be fully spawned ===\n"; - - } catch (const std::exception& e) { - std::cerr << "Error completing spawn sequence: " << e.what() << std::endl; - } +void completeSpawnSequence(Packet& packet, Server& server) { + Player* player = packet.getPlayer(); + ThreadSafeQueue* outgoingPackets = server.getNetworkManager().getOutgoingQueue(); + if (!player || !outgoingPackets) return; + + // std::cout << "=== Completing spawn sequence for player: " << player->getPlayerName() << " + // ===\n"; + std::cout << "=== Completing spawn sequence for player: " << " ===\n"; + + try { + // 9. Player Abilities (0x39) + Packet* abilitiesPacket = new Packet(packet); + sendPlayerAbilities(*abilitiesPacket, server); + outgoingPackets->push(abilitiesPacket); + + // 10. Set Health (0x61) + Packet* healthPacket = new Packet(packet); + sendSetHealth(*healthPacket, server); + outgoingPackets->push(healthPacket); + + // 11. Set Experience (0x60) + Packet* experiencePacket = new Packet(packet); + sendSetExperience(*experiencePacket, server); + outgoingPackets->push(experiencePacket); + + // 12. Update Time (0x6A) + Packet* timePacket = new Packet(packet); + sendUpdateTime(*timePacket, server); + outgoingPackets->push(timePacket); + + // 13. Set Held Item (0x62) + Packet* heldItemPacket = new Packet(packet); + sendSetHeldItem(*heldItemPacket, server); + outgoingPackets->push(heldItemPacket); + + std::cout << "=== Spawn sequence completed! Player should now be fully spawned ===\n"; + + } catch (const std::exception& e) { + std::cerr << "Error completing spawn sequence: " << e.what() << std::endl; + } } diff --git a/src/networking/packet/status.cpp b/src/networking/packet/status.cpp index 45bc47d..7536ff3 100644 --- a/src/networking/packet/status.cpp +++ b/src/networking/packet/status.cpp @@ -1,10 +1,9 @@ -#include "buffer.hpp" -#include "json.hpp" -#include "networking.hpp" -#include "packet.hpp" +#include "lib/json.hpp" +#include "network/buffer.hpp" +#include "network/networking.hpp" +#include "network/packet.hpp" +#include "network/server.hpp" #include "player.hpp" -#include "server.hpp" -#include "logger.hpp" #include #include @@ -18,16 +17,13 @@ void handleStatusPacket(Packet& packet, Server& server) { return; } - json jres = {{"version", - {{"name", server.getGameVersion()}, {"protocol", server.getProtocolVersion()}}}, - {"players", - {{"max", server.getServerSize()}, - {"online", server.getAmountOnline()}, - {"sample", server.getPlayerSample()}}}, - {"description", {{"text", server.getServerMOTD()}}}}; + json jres = { + {"version", {{"name", server.getConfig().getVersion()}, {"protocol", server.getConfig().getProtocolVersion()}}}, + {"players", {{"max", server.getConfig().getServerSize()}, {"online", server.getAmountOnline()}, {"sample", server.getPlayerSample()}}}, + {"description", {{"text", server.getConfig().getServerMotd()}}}}; std::string payload = jres.dump(); - int jsonLen = payload.size(); + int jsonLen = payload.size(); int packetId = 0x00; int packetIdVarintSize = packet.getVarintSize(packetId); diff --git a/src/player.cpp b/src/player.cpp deleted file mode 100644 index e3c05c0..0000000 --- a/src/player.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include "UUID.hpp" -#include "player.hpp" -#include "server.hpp" - -#include - -Player::Player(Server& server) - : _name("Player_entity"), _state(PlayerState::None), _socketFd(-1), x(0), y(0), z(0), health(0), - _uuid(), _playerId(server.getIdManager().allocate()), _server(server), _config(new PlayerConfig()) {} - -Player::Player(const std::string& name, const PlayerState state, const int socket, Server& server) - : _state(state), _socketFd(socket), x(0), y(0), z(0), health(20), _uuid(), - _playerId(server.getIdManager().allocate()), _server(server), _config(new PlayerConfig()) { - if (name.length() > 32) - _name = name.substr(0, 31); - else - _name = name; -} - -Player& Player::operator=(const Player& src) { - if (this != &src) { - this->_name = src._name; - this->_socketFd = src._socketFd; - this->health = src.health; - this->x = src.x; - this->y = src.y; - this->z = src.z; - } - return (*this); -} - -Player::~Player() { - _server.getIdManager().release(_playerId); - delete _config; -} - -std::string Player::getPlayerName(void) { - return (this->_name); -}; -void Player::setPlayerName(const std::string& name) { - this->_name = name; -} -PlayerState Player::getPlayerState() { - return (this->_state); -} -void Player::setPlayerState(PlayerState state) { - this->_state = state; -} -void Player::setSocketFd(int socket) { - this->_socketFd = socket; -} -int Player::getSocketFd() const { - return (this->_socketFd); -} - -void Player::setUUID(UUID uuid) { - _uuid = uuid; -} - -int Player::getPlayerID() const { - return (_playerId); -} - -// PlayerConfig implementation -PlayerConfig::PlayerConfig() - : _chatMode(0), _mainHand(1), _locale("en_US"), _viewDistance(10), - _displayedSkinParts(0), _chatColors(true), _enableTextFiltering(false), - _allowServerListings(true) {} - -PlayerConfig::~PlayerConfig() {} diff --git a/src/server.cpp b/src/server.cpp index 8c16f4a..6645d57 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1,21 +1,23 @@ -#include "json.hpp" +#include "network/server.hpp" + +#include "config.hpp" +#include "lib/filesystem.hpp" +#include "lib/json.hpp" #include "logger.hpp" -#include "networking.hpp" +#include "network/networking.hpp" #include "player.hpp" -#include "server.hpp" +#include "world/world.hpp" #include #include -#include +#include #include #include #include using json = nlohmann::json; -Server::Server() - : _playerLst(), _protocolVersion(770), _serverSize(-100000000), _gameVersion("1.12.5"), - _serverMOTD(), _serverPort(25565), _serverAddr("0.0.0.0"), _networkManager(nullptr) {} +Server::Server() : _playerLst(), _config(), _networkManager(nullptr) {} Server::~Server() { if (_networkManager) { @@ -26,11 +28,52 @@ Server::~Server() { int Server::start_server() { try { - initializeGlobalLogger(); - Server::loadConfig(); + initializeGlobalLogger(); + if (_config.loadConfig()) { + g_logger->logGameInfo(ERROR, "Failed to load config", "SERVER"); + return 1; + } + + // Load world data + g_logger->logGameInfo(INFO, "Loading world...", "SERVER"); + try { + std::string worldName = _config.getWorldName(); + std::filesystem::path levelDatPath = getPath().parent_path() / worldName / "level.dat"; + + if (!std::filesystem::exists(levelDatPath)) { + g_logger->logGameInfo(ERROR, "level.dat not found at: " + levelDatPath.string(), "SERVER"); + return 1; + } + + _worldData = _worldManager.loadLevelDat(levelDatPath); + + // Log world information + g_logger->logGameInfo(INFO, "World loaded successfully: " + _worldData.LevelName, "SERVER"); + g_logger->logGameInfo(INFO, + "Spawn Point: X=" + std::to_string(_worldData.SpawnX) + " Y=" + std::to_string(_worldData.SpawnY) + + " Z=" + std::to_string(_worldData.SpawnZ), + "SERVER"); + g_logger->logGameInfo(INFO, "Random Seed: " + std::to_string(_worldData.RandomSeed), "SERVER"); + g_logger->logGameInfo(INFO, "Game Type: " + std::to_string(_worldData.GameType), "SERVER"); + g_logger->logGameInfo(INFO, "Data Version: " + std::to_string(_worldData.DataVersion), "SERVER"); + g_logger->logGameInfo(INFO, "Difficulty: " + std::to_string(static_cast(_worldData.Difficulty)), "SERVER"); + g_logger->logGameInfo(INFO, "Hardcore: " + std::string(_worldData.hardcore ? "true" : "false"), "SERVER"); + g_logger->logGameInfo(INFO, "Time: " + std::to_string(_worldData.Time), "SERVER"); + g_logger->logGameInfo(INFO, "Day Time: " + std::to_string(_worldData.DayTime), "SERVER"); + g_logger->logGameInfo(INFO, "Generator: " + _worldData.generatorName, "SERVER"); + g_logger->logGameInfo(INFO, "Raining: " + std::string(_worldData.raining ? "true" : "false"), "SERVER"); + g_logger->logGameInfo(INFO, "Thundering: " + std::string(_worldData.thundering ? "true" : "false"), "SERVER"); + + } catch (const std::exception& e) { + g_logger->logGameInfo(ERROR, "Failed to load world: " + std::string(e.what()), "SERVER"); + return 1; + } + + std::filesystem::path regionFile = _worldManager.locateRegionFileByChunkCoord(0, 0); + g_logger->logGameInfo(INFO, "Region File: " + regionFile.string(), "SERVER"); + size_t workerCount = 4; - if (workerCount == 0) - workerCount = 4; // fallback + if (workerCount == 0) workerCount = 4; // fallback // Create NetworkManager with BOTH required parameters _networkManager = new NetworkManager(workerCount, *this); @@ -48,39 +91,6 @@ int Server::start_server() { return (0); } -int Server::loadConfig() { - std::ifstream inputFile(ConfigFileName); - - if (!inputFile.is_open()) { - std::cerr << "[Server] Error: Could not open " << ConfigFileName << std::endl; - return 1; - } - - json j; - - try { - inputFile >> j; - - // g_logger->logGameInfo(INFO, "Successfully parsed " + std::string(ConfigFileName) + "!", "Server"); - _gameVersion = j["version"]["name"]; - // g_logger->logGameInfo(INFO, "Game version: " + _gameVersion, "Server"); - _protocolVersion = j["version"]["protocol"]; - // g_logger->logGameInfo(INFO, "Protocol version: " + std::to_string(_protocolVersion), "Server"); - _serverSize = j["server"]["max-players"]; - // g_logger->logGameInfo(INFO, "Server size: " + std::to_string(_serverSize), "Server"); - _serverMOTD = j["server"]["motd"]; - // g_logger->logGameInfo(INFO, "Server MOTD: " + _serverMOTD, "Server"); - _serverAddr = j["server"]["ip-address"]; - // g_logger->logGameInfo(INFO, "Server IP address : " + _serverAddr, "Server"); - _serverPort = j["server"]["port"]; - // g_logger->logGameInfo(INFO, "Server port: " + std::to_string(_serverPort), "Server"); - } catch (json::parse_error& e) { - std::cerr << "[Server]: Json parse error: " << e.what() << std::endl; - return (1); - } - return (0); -} - Player* Server::addPlayer(const std::string& name, const PlayerState state, const int socket) { Player* newPlayer = nullptr; try { @@ -119,7 +129,8 @@ Player* Server::addTempPlayer(const std::string& name, const PlayerState state, std::lock_guard lock(_tempPlayerLock); _tempPlayerLst[socket] = newPlayer; - // g_logger->logGameInfo(INFO, "Added temp player on socket " + std::to_string(socket), "Server"); + // g_logger->logGameInfo(INFO, "Added temp player on socket " + std::to_string(socket), + // "Server"); return (newPlayer); } @@ -127,16 +138,16 @@ void Server::removeTempPlayer(Player* player) { if (!player) { return; } - int socket = player->getSocketFd(); + int socket = player->getSocketFd(); std::lock_guard lock(_tempPlayerLock); _tempPlayerLst.erase(socket); delete player; - // g_logger->logGameInfo(INFO, "Removed temp player from socket " + std::to_string(socket), "Server"); + // g_logger->logGameInfo(INFO, "Removed temp player from socket " + std::to_string(socket), + // "Server"); } void Server::promoteTempPlayer(Player* player) { - if (!player) - return; + if (!player) return; int socket = player->getSocketFd(); std::lock_guard lockTemp(_tempPlayerLock); @@ -145,7 +156,8 @@ void Server::promoteTempPlayer(Player* player) { std::lock_guard lockPlayer(_playerLock); _playerLst[socket] = player; - // g_logger->logGameInfo(INFO, "Promoted temp player to main list on socket " + std::to_string(socket), "Server"); + // g_logger->logGameInfo(INFO, "Promoted temp player to main list on socket " + + // std::to_string(socket), "Server"); } void Server::removePlayerFromAnyList(Player* player) { @@ -156,32 +168,33 @@ void Server::removePlayerFromAnyList(Player* player) { { std::lock_guard lock(_tempPlayerLock); - auto temp_it = _tempPlayerLst.find(socket); + auto temp_it = _tempPlayerLst.find(socket); if (temp_it != _tempPlayerLst.end()) { _tempPlayerLst.erase(socket); delete player; - // g_logger->logGameInfo(INFO, "Removed temp player from socket " + std::to_string(socket), "Server"); + // g_logger->logGameInfo(INFO, "Removed temp player from socket " + + // std::to_string(socket), "Server"); return; } } { std::lock_guard lock(_playerLock); - auto main_it = _playerLst.find(socket); + auto main_it = _playerLst.find(socket); if (main_it != _playerLst.end()) { _playerLst.erase(socket); delete player; - // g_logger->logGameInfo(INFO, "Removed main player from socket " + std::to_string(socket), "Server"); + // g_logger->logGameInfo(INFO, "Removed main player from socket " + + // std::to_string(socket), "Server"); return; } } delete player; - // g_logger->logGameInfo(INFO, "Deleted orphaned player from socket " + std::to_string(socket), "Server"); + // g_logger->logGameInfo(INFO, "Deleted orphaned player from socket " + std::to_string(socket), + // "Server"); } -void Server::addPlayerToSample(const std::string& name) { - _playerSample.push_back(name); -} +void Server::addPlayerToSample(const std::string& name) { _playerSample.push_back(name); } void Server::removePlayerToSample(const std::string& name) { for (size_t i = 0; i < _playerLst.size(); i++) @@ -191,21 +204,5 @@ void Server::removePlayerToSample(const std::string& name) { } } -std::string Server::getGameVersion() { - return _gameVersion; -} -std::string Server::getServerMOTD() { - return _serverMOTD; -} -int Server::getProtocolVersion() { - return _protocolVersion; -} -int Server::getServerSize() { - return _serverSize; -} -int Server::getAmountOnline() { - return _playerLst.size(); -} -json Server::getPlayerSample() { - return _playerSample; -} +int Server::getAmountOnline() { return _playerLst.size(); } +json Server::getPlayerSample() { return _playerSample; } diff --git a/src/world/manager.cpp b/src/world/manager.cpp new file mode 100644 index 0000000..c537d03 --- /dev/null +++ b/src/world/manager.cpp @@ -0,0 +1,235 @@ +#include "lib/filesystem.hpp" +#include "lib/nbtParser.hpp" +#include "logger.hpp" +#include "world/world.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +std::vector World::Manager::decompressGzip(std::filesystem::path compressedFilePath) { + // Read file into memory + std::ifstream file(compressedFilePath, std::ios::binary); + if (!file) { + throw std::runtime_error("Could not open file: " + compressedFilePath.string()); + } + + std::vector compressed((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + file.close(); + + // Initialize zlib stream + z_stream stream; + std::memset(&stream, 0, sizeof(stream)); + + // 16 + MAX_WBITS tells zlib to decode gzip format + if (inflateInit2(&stream, 16 + MAX_WBITS) != Z_OK) { + throw std::runtime_error("Failed to initialize gzip decompression"); + } + + // Allocate output buffer (level.dat is usually < 10MB) + std::vector decompressed(10 * 1024 * 1024); + + stream.avail_in = static_cast(compressed.size()); + stream.next_in = compressed.data(); + stream.avail_out = static_cast(decompressed.size()); + stream.next_out = decompressed.data(); + + int ret = inflate(&stream, Z_FINISH); + + if (ret != Z_STREAM_END) { + inflateEnd(&stream); + throw std::runtime_error("Decompression failed: " + std::to_string(ret)); + } + + // Resize to actual decompressed size + decompressed.resize(stream.total_out); + inflateEnd(&stream); + + return decompressed; +} + +World::LevelDat World::Manager::loadLevelDat(std::filesystem::path levelDatPath) { + std::vector decompressedData = decompressGzip(levelDatPath); + if (decompressedData.empty()) { + throw std::runtime_error("Decompressed level.dat data is empty."); + } + + // Parse NBT using the dedicated parser + nbt::Parser parser; + nbt::NBT n = parser.parse(decompressedData); + + World::LevelDat dataStruct; + dataStruct.nbtData = std::move(n); + + // --- Populate the Data struct for easy access --- + const auto& dataCompound = dataStruct.nbtData.getRoot().at("Data").get>(); + + // Helper to safely get a value from a compound tag + auto getTagValue = [&](const std::string& key, auto& member) { + using MemberType = std::remove_reference_t; + if (dataCompound->contains(key)) { + try { + if constexpr (std::is_same_v) { + // NBT uses TagByte for booleans + member = (dataCompound->at(key).get() != 0); + } else if constexpr (std::is_same_v) { + member = std::byte(dataCompound->at(key).get()); + } else { + member = dataCompound->at(key).get(); + } + } catch (const std::bad_variant_access&) { + // Type mismatch, leave member as default + } + } + }; + + getTagValue("allowCommands", dataStruct.allowCommands); + getTagValue("BorderCenterX", dataStruct.BorderCenterX); + getTagValue("BorderCenterY", dataStruct.BorderCenterY); + getTagValue("BorderDamagePerBlock", dataStruct.BorderDamagePerBlock); + getTagValue("BorderSafeZone", dataStruct.BorderSafeZone); + getTagValue("BorderSizeLerpTarget", dataStruct.BorderSizeLerpTarget); + getTagValue("BorderWarningBlocks", dataStruct.BorderWarningBlocks); + getTagValue("BorderWarningTime", dataStruct.BorderWarningTime); + getTagValue("clearWeatherTime", dataStruct.clearWeatherTime); + getTagValue("DataVersion", dataStruct.DataVersion); + getTagValue("DayTime", dataStruct.DayTime); + getTagValue("Difficulty", dataStruct.Difficulty); + getTagValue("DifficultyLocked", dataStruct.DifficultyLocked); + getTagValue("GameType", dataStruct.GameType); + getTagValue("generatorName", dataStruct.generatorName); + getTagValue("generatorVersion", dataStruct.generatorVersiona); + getTagValue("hardcore", dataStruct.hardcore); + getTagValue("initialized", dataStruct.initialized); + getTagValue("LastPlayed", dataStruct.LastPlayed); + getTagValue("LevelName", dataStruct.LevelName); + getTagValue("MapFeatures", dataStruct.MapFeatures); + getTagValue("raining", dataStruct.raining); + getTagValue("rainTime", dataStruct.rainTime); + getTagValue("RandomSeed", dataStruct.RandomSeed); + getTagValue("SizeOnDisk", dataStruct.SizeOnDisk); + getTagValue("SpawnX", dataStruct.SpawnX); + getTagValue("SpawnY", dataStruct.SpawnY); + getTagValue("SpawnZ", dataStruct.SpawnZ); + getTagValue("thundering", dataStruct.thundering); + getTagValue("thunderTime", dataStruct.thunderTime); + getTagValue("Time", dataStruct.Time); + getTagValue("version", dataStruct.version); + getTagValue("WanderingTraderSpawnChance", dataStruct.WanderingTraderSpawnChange); + getTagValue("WanderingTraderSpawnDelay", dataStruct.WanderingTraderSpawnDelay); + getTagValue("WasModded", dataStruct.WasModded); + + return dataStruct; +} + +std::filesystem::path World::Manager::locateRegionFileByChunkCoord(int localX, int localZ) { + const auto regionDir = getPath().parent_path() / "world" / "region"; + const std::string filename = "r." + std::to_string(localX / 32) + "." + std::to_string(localZ / 32) + ".mca"; + const std::filesystem::path path = regionDir / filename; + + if (std::filesystem::exists(path)) { + return path; + } else { + g_logger->logGameInfo(ERROR, "Cannot find the region file asked" + path.string()); + throw std::runtime_error("Cannot find the region file asked"); + } +} + +std::vector World::Manager::decompressZlib(const std::vector& compressedData) { + if (compressedData.empty()) { + return {}; + } + + // Initialize zlib stream + z_stream stream = {}; + stream.next_in = const_cast(compressedData.data()); + stream.avail_in = static_cast(compressedData.size()); + + // Initialize for zlib format (not gzip) + int ret = inflateInit(&stream); + if (ret != Z_OK) { + throw std::runtime_error("Failed to initialize zlib decompression"); + } + + // Estimate output size (start with 4x input size) + std::vector decompressed(compressedData.size() * 4); + + do { + stream.next_out = decompressed.data() + stream.total_out; + stream.avail_out = static_cast(decompressed.size() - stream.total_out); + + ret = inflate(&stream, Z_NO_FLUSH); + + if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { + inflateEnd(&stream); + throw std::runtime_error("Zlib decompression error: " + std::to_string(ret)); + } + + // If we need more space, double the buffer + if (stream.avail_out == 0 && ret != Z_STREAM_END) { + decompressed.resize(decompressed.size() * 2); + } + + } while (ret != Z_STREAM_END); + + inflateEnd(&stream); + + // Resize to actual decompressed size + decompressed.resize(stream.total_out); + return decompressed; +} + +std::vector World::Manager::decompressGzip(const std::vector& compressedData) { + if (compressedData.empty()) { + return {}; + } + + // Initialize zlib stream for gzip format + z_stream stream = {}; + stream.next_in = const_cast(compressedData.data()); + stream.avail_in = static_cast(compressedData.size()); + + // Use inflateInit2 with gzip flag (16 + MAX_WBITS) + int ret = inflateInit2(&stream, 16 + MAX_WBITS); + if (ret != Z_OK) { + throw std::runtime_error("Failed to initialize gzip decompression"); + } + + // Estimate output size (start with 4x input size) + std::vector decompressed(compressedData.size() * 4); + + do { + stream.next_out = decompressed.data() + stream.total_out; + stream.avail_out = static_cast(decompressed.size() - stream.total_out); + + ret = inflate(&stream, Z_NO_FLUSH); + + if (ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) { + inflateEnd(&stream); + throw std::runtime_error("Gzip decompression error: " + std::to_string(ret)); + } + + // If we need more space, double the buffer + if (stream.avail_out == 0 && ret != Z_STREAM_END) { + decompressed.resize(decompressed.size() * 2); + } + + } while (ret != Z_STREAM_END); + + inflateEnd(&stream); + + // Resize to actual decompressed size + decompressed.resize(stream.total_out); + return decompressed; +} diff --git a/src/world/query.cpp b/src/world/query.cpp new file mode 100644 index 0000000..cdf6a01 --- /dev/null +++ b/src/world/query.cpp @@ -0,0 +1,217 @@ +#include "lib/nbt.hpp" +#include "lib/nbtParser.hpp" +#include "logger.hpp" +#include "world/world.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +World::ChunkData World::Query::loadChunkFromRegion(const std::filesystem::path& regionPath, int chunkX, int chunkZ) { + + // Get the byte index inside the location table + int localX = chunkX & 31, localZ = chunkZ & 31; + int chunkIndex = (localZ << 5) + localX; + + std::ifstream file(regionPath, std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("Cannot open region file"); + } + + file.seekg(chunkIndex * 4); + uint32_t locationData; + file.read(reinterpret_cast(&locationData), 4); + locationData = ntohl(locationData); + + uint32_t offset = (locationData >> 8) & 0xFFFFFF; + uint8_t sectorCount = locationData & 0xFF; + + if (offset == 0 || sectorCount == 0) { + // Chunk doesn't exist in this region + return ChunkData(chunkX, chunkZ); + } + + file.seekg(offset * 4096); + + uint32_t chunkLength; + file.read(reinterpret_cast(&chunkLength), 4); + chunkLength = ntohl(chunkLength); + + uint8_t compressionType; + file.read(reinterpret_cast(&compressionType), 1); + + std::vector compressedData(chunkLength - 1); + file.read(reinterpret_cast(compressedData.data()), chunkLength - 1); + + std::vector decompressedData; + switch (compressionType) { + case 1: // GZip + decompressedData = World::Manager::decompressGzip(compressedData); + break; + case 2: // Zlib + decompressedData = World::Manager::decompressZlib(compressedData); + break; + case 3: // Uncompressed + decompressedData = compressedData; + break; + default: + throw std::runtime_error("Unknown compression type: " + std::to_string(compressionType)); + }; + + nbt::Parser parser; + nbt::NBT chunkNBT = parser.parse(decompressedData); + + ChunkData chunk(chunkX, chunkZ); + extractChunkDataFromNBT(chunkNBT, chunk); + + return chunk; +} + +void World::Query::extractChunkDataFromNBT(const nbt::NBT& chunkNBT, World::ChunkData& chunk) { + try { + const auto& root = chunkNBT.getRoot(); + + // Modern format (1.18+) - data directly in root + + // Extract sections (block data) + if (root.contains("sections")) { + const auto& sectionsTag = root.at("sections").get>(); + extractSectionsData(*sectionsTag, chunk); + } + + // Extract heightmaps + if (root.contains("Heightmaps")) { + const auto& heightmapsTag = root.at("Heightmaps").get>(); + extractHeightmaps(*heightmapsTag, chunk); + } + + // Extract biomes from sections + extractBiomesFromSections(root, chunk); + + // Extract block entities + if (root.contains("block_entities")) { + const auto& blockEntitiesTag = root.at("block_entities").get>(); + extractBlockEntities(*blockEntitiesTag, chunk); + } + + } catch (const std::exception& e) { + g_logger->logGameInfo(ERROR, "Failed to extract chunk data from NBT: " + std::string(e.what()), "World::Query"); + // Leave chunk data empty - it will be treated as empty chunk + } +} + +void World::Query::extractSectionsData(const nbt::TagList& sections, World::ChunkData& chunk) { + for (size_t i = 0; i < sections.size(); i++) { + const auto& sectionTag = sections[i].get>(); + + // Get section Y coordinate + int8_t sectionY = 0; + if (sectionTag->contains("Y")) { + sectionY = sectionTag->at("Y").get(); + } + + // Extract block states + if (sectionTag->contains("block_states")) { + const auto& blockStatesTag = sectionTag->at("block_states").get>(); + extractBlockStatesFromSection(*blockStatesTag, chunk, sectionY); + } + + // Extract light data if present + if (sectionTag->contains("SkyLight")) { + const auto& skyLightTag = sectionTag->at("SkyLight").get(); + // Append to chunk.skyLight + size_t offset = chunk.skyLight.size(); + chunk.skyLight.resize(offset + skyLightTag.size()); + std::memcpy(chunk.skyLight.data() + offset, skyLightTag.data(), skyLightTag.size()); + } + + if (sectionTag->contains("BlockLight")) { + const auto& blockLightTag = sectionTag->at("BlockLight").get(); + // Append to chunk.blockLight + size_t offset = chunk.blockLight.size(); + chunk.blockLight.resize(offset + blockLightTag.size()); + std::memcpy(chunk.blockLight.data() + offset, blockLightTag.data(), blockLightTag.size()); + } + } +} + +void World::Query::extractBlockStatesFromSection(const nbt::TagCompound& blockStates, World::ChunkData& chunk, int8_t sectionY) { + // Block states contain palette and packed data array + + if (blockStates.contains("data")) { + const auto& dataTag = blockStates.at("data").get(); + + // For now, just append raw packed data + // In a full implementation, you'd unpack the bits based on palette size + size_t offset = chunk.blockData.size(); + chunk.blockData.resize(offset + dataTag.size() * sizeof(int64_t)); + std::memcpy(chunk.blockData.data() + offset, dataTag.data(), dataTag.size() * sizeof(int64_t)); + } + + // Note: To properly decode blocks, you'd also need to: + // 1. Read the "palette" array to get block state mappings + // 2. Calculate bits per entry based on palette size + // 3. Unpack the long array using the calculated bits per entry + // 4. Map indices back to actual block states using the palette +} + +void World::Query::extractHeightmaps(const nbt::TagCompound& heightmaps, World::ChunkData& chunk) { + // Modern chunks typically have multiple heightmap types + if (heightmaps.contains("MOTION_BLOCKING")) { + const auto& motionBlockingTag = heightmaps.at("MOTION_BLOCKING").get(); + + size_t dataSize = motionBlockingTag.size() * sizeof(int64_t); + chunk.heightmaps.resize(dataSize); + std::memcpy(chunk.heightmaps.data(), motionBlockingTag.data(), dataSize); + } +} + +void World::Query::extractBiomesFromSections(const nbt::TagCompound& root, World::ChunkData& chunk) { + // In modern format, biomes are stored in sections + if (root.contains("sections")) { + const auto& sectionsTag = root.at("sections").get>(); + + for (size_t i = 0; i < sectionsTag->size(); i++) { + const auto& sectionTag = (*sectionsTag)[i].get>(); + + if (sectionTag->contains("biomes")) { + const auto& biomesTag = sectionTag->at("biomes").get>(); + + if (biomesTag->contains("data")) { + const auto& biomeDataTag = biomesTag->at("data").get(); + + // Append biome data + size_t offset = chunk.biomeData.size(); + chunk.biomeData.resize(offset + biomeDataTag.size() * sizeof(int64_t)); + std::memcpy(chunk.biomeData.data() + offset, biomeDataTag.data(), biomeDataTag.size() * sizeof(int64_t)); + } + } + } + } +} + +void World::Query::extractBlockEntities(const nbt::TagList& blockEntities, World::ChunkData& chunk) { + // For now, just reserve some space + // In a full implementation, you'd serialize each block entity properly + chunk.blockEntities.reserve(blockEntities.size() * 100); // Rough estimate + + // You could iterate through and extract specific block entity data if needed + // For basic functionality, leaving empty is fine +} + +World::ChunkData World::Query::generateEmptyChunk(int chunkX, int chunkZ) { + World::ChunkData emptyChunk(chunkX, chunkZ); + + // Leave all vectors empty - this represents an empty chunk + // The isEmpty() function will return true for this chunk + + g_logger->logGameInfo(DEBUG, "Generated empty chunk (" + std::to_string(chunkX) + ", " + std::to_string(chunkZ) + ")", "World::Query"); + + return emptyChunk; +} diff --git a/world/DIM-1/data/chunks.dat b/world/DIM-1/data/chunks.dat new file mode 100644 index 0000000..4089fbc Binary files /dev/null and b/world/DIM-1/data/chunks.dat differ diff --git a/world/DIM-1/data/raids.dat b/world/DIM-1/data/raids.dat new file mode 100644 index 0000000..82c8463 Binary files /dev/null and b/world/DIM-1/data/raids.dat differ diff --git a/world/DIM1/data/chunks.dat b/world/DIM1/data/chunks.dat new file mode 100644 index 0000000..4089fbc Binary files /dev/null and b/world/DIM1/data/chunks.dat differ diff --git a/world/DIM1/data/raids_end.dat b/world/DIM1/data/raids_end.dat new file mode 100644 index 0000000..82c8463 Binary files /dev/null and b/world/DIM1/data/raids_end.dat differ diff --git a/world/advancements/4572e510-ac24-44b0-a915-5ed21da4028c.json b/world/advancements/4572e510-ac24-44b0-a915-5ed21da4028c.json new file mode 100644 index 0000000..5e01b24 --- /dev/null +++ b/world/advancements/4572e510-ac24-44b0-a915-5ed21da4028c.json @@ -0,0 +1,15 @@ +{ + "minecraft:recipes/decorations/crafting_table": { + "criteria": { + "unlock_right_away": "2025-10-10 17:26:39 +0200" + }, + "done": true + }, + "minecraft:adventure/adventuring_time": { + "criteria": { + "minecraft:plains": "2025-10-10 17:26:40 +0200" + }, + "done": false + }, + "DataVersion": 4325 +} \ No newline at end of file diff --git a/world/data/chunks.dat b/world/data/chunks.dat new file mode 100644 index 0000000..4089fbc Binary files /dev/null and b/world/data/chunks.dat differ diff --git a/world/data/raids.dat b/world/data/raids.dat new file mode 100644 index 0000000..82c8463 Binary files /dev/null and b/world/data/raids.dat differ diff --git a/world/data/random_sequences.dat b/world/data/random_sequences.dat new file mode 100644 index 0000000..ce54a5f Binary files /dev/null and b/world/data/random_sequences.dat differ diff --git a/world/data/scoreboard.dat b/world/data/scoreboard.dat new file mode 100644 index 0000000..4089fbc Binary files /dev/null and b/world/data/scoreboard.dat differ diff --git a/world/entities/r.-1.-1.mca b/world/entities/r.-1.-1.mca new file mode 100644 index 0000000..37abe1d Binary files /dev/null and b/world/entities/r.-1.-1.mca differ diff --git a/world/entities/r.-1.0.mca b/world/entities/r.-1.0.mca new file mode 100644 index 0000000..1363904 Binary files /dev/null and b/world/entities/r.-1.0.mca differ diff --git a/world/entities/r.0.-1.mca b/world/entities/r.0.-1.mca new file mode 100644 index 0000000..8cbb021 Binary files /dev/null and b/world/entities/r.0.-1.mca differ diff --git a/world/entities/r.0.0.mca b/world/entities/r.0.0.mca new file mode 100644 index 0000000..e69de29 diff --git a/world/icon.png b/world/icon.png new file mode 100644 index 0000000..bdd5dd7 Binary files /dev/null and b/world/icon.png differ diff --git a/world/level.dat b/world/level.dat new file mode 100644 index 0000000..8741cba Binary files /dev/null and b/world/level.dat differ diff --git a/world/level.dat_old b/world/level.dat_old new file mode 100644 index 0000000..4a8682f Binary files /dev/null and b/world/level.dat_old differ diff --git a/world/playerdata/4572e510-ac24-44b0-a915-5ed21da4028c.dat b/world/playerdata/4572e510-ac24-44b0-a915-5ed21da4028c.dat new file mode 100644 index 0000000..33d1392 Binary files /dev/null and b/world/playerdata/4572e510-ac24-44b0-a915-5ed21da4028c.dat differ diff --git a/world/playerdata/4572e510-ac24-44b0-a915-5ed21da4028c.dat_old b/world/playerdata/4572e510-ac24-44b0-a915-5ed21da4028c.dat_old new file mode 100644 index 0000000..e84bee2 Binary files /dev/null and b/world/playerdata/4572e510-ac24-44b0-a915-5ed21da4028c.dat_old differ diff --git a/world/poi/r.-1.-1.mca b/world/poi/r.-1.-1.mca new file mode 100644 index 0000000..e69de29 diff --git a/world/poi/r.-1.0.mca b/world/poi/r.-1.0.mca new file mode 100644 index 0000000..e69de29 diff --git a/world/poi/r.0.-1.mca b/world/poi/r.0.-1.mca new file mode 100644 index 0000000..e69de29 diff --git a/world/poi/r.0.0.mca b/world/poi/r.0.0.mca new file mode 100644 index 0000000..e69de29 diff --git a/world/region/r.-1.-1.mca b/world/region/r.-1.-1.mca new file mode 100644 index 0000000..fe56428 Binary files /dev/null and b/world/region/r.-1.-1.mca differ diff --git a/world/region/r.-1.0.mca b/world/region/r.-1.0.mca new file mode 100644 index 0000000..4e8b5ac Binary files /dev/null and b/world/region/r.-1.0.mca differ diff --git a/world/region/r.0.-1.mca b/world/region/r.0.-1.mca new file mode 100644 index 0000000..1c4760a Binary files /dev/null and b/world/region/r.0.-1.mca differ diff --git a/world/region/r.0.0.mca b/world/region/r.0.0.mca new file mode 100644 index 0000000..3b35084 Binary files /dev/null and b/world/region/r.0.0.mca differ diff --git a/world/session.lock b/world/session.lock new file mode 100644 index 0000000..0d7e5f8 --- /dev/null +++ b/world/session.lock @@ -0,0 +1 @@ +β˜ƒ \ No newline at end of file diff --git a/world/stats/4572e510-ac24-44b0-a915-5ed21da4028c.json b/world/stats/4572e510-ac24-44b0-a915-5ed21da4028c.json new file mode 100644 index 0000000..758ac4b --- /dev/null +++ b/world/stats/4572e510-ac24-44b0-a915-5ed21da4028c.json @@ -0,0 +1 @@ +{"stats":{"minecraft:custom":{"minecraft:time_since_rest":45,"minecraft:total_world_time":53,"minecraft:leave_game":1,"minecraft:play_time":45,"minecraft:time_since_death":45}},"DataVersion":4325} \ No newline at end of file