diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4454eba..da5b4c2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -60,13 +60,16 @@ jobs: - name: Build working-directory: ${{github.workspace}}/build - run: cmake --build . --config $BUILD_TYPE --target MinecraftPE --parallel + run: | + cmake --build . --config $BUILD_TYPE --target MinecraftPE --parallel + cmake --build . --config $BUILD_TYPE --target MinecraftPE-server --parallel - name: Upload Artifact uses: actions/upload-artifact@v4 with: name: mcpe-windows path: | + ${{github.workspace}}/build/MinecraftPE-server.exe ${{github.workspace}}/build/MinecraftPE.exe ${{github.workspace}}/build/libpng16.dll ${{github.workspace}}/build/OpenAL32.dll @@ -299,6 +302,12 @@ jobs: with: files: mcpe-windows/MinecraftPE.exe mcpe-windows/libpng16.dll mcpe-windows/OpenAL32.dll mcpe-windows/libz.dll dest: minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip + + - name: Zip Windows Server Artifacts + uses: vimtor/action-zip@v1.2 + with: + files: mcpe-windows/MinecraftPE-server.exe + dest: minecraftpe-server-${{ steps.ref.outputs.hash }}-windows.zip - name: Zip Linux Artifacts uses: vimtor/action-zip@v1.2 @@ -310,7 +319,7 @@ jobs: uses: vimtor/action-zip@v1.2 with: files: mcpe-linux/MinecraftPE-server - dest: minecraftpe-server-${{ steps.ref.outputs.hash }}.zip + dest: minecraftpe-server-${{ steps.ref.outputs.hash }}-linux.zip - name: Rename Android Artifacts run: | @@ -343,7 +352,11 @@ jobs: ./data.zip ./minecraftpe-server-${{ steps.ref.outputs.hash }}.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-windows.zip + ./minecraftpe-server-${{ steps.ref.outputs.hash }}-windows.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-linux.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-android-arm64-v8a.apk ./minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.apk + ./minecraftpe-server-${{ steps.ref.outputs.hash }}-linux.zip + ./minecraftpe-${{ steps.ref.outputs.hash }}-android-arm64-v8a.zip + ./minecraftpe-${{ steps.ref.outputs.hash }}-android-armeabi-v7a.zip ./minecraftpe-${{ steps.ref.outputs.hash }}-web.zip diff --git a/CMakeLists.txt b/CMakeLists.txt index fbb244c..0ec4358 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,6 @@ CPMAddPackage( "ALSOFT_STATIC_LIBGCC ON" ) -# TODO: Clear this paths with * file(GLOB SERVER_SOURCES "project/lib_projects/raknet/jni/RaknetSources/*.cpp" "src/NinecraftApp.cpp" @@ -150,7 +149,6 @@ file(GLOB SERVER_SOURCES "src/platform/CThread.cpp" "src/platform/HttpClient.cpp" - "src/platform/PngLoader.cpp" "src/platform/time.cpp" "src/platform/input/Controller.cpp" @@ -216,6 +214,7 @@ file(GLOB SERVER_SOURCES "src/world/level/tile/entity/*.cpp" "src/world/phys/HitResult.cpp" + "src/commands/*.cpp" ) file(GLOB CLIENT_SOURCES @@ -299,6 +298,8 @@ file(GLOB CLIENT_SOURCES "src/AppPlatform_glfw.cpp" "src/main.cpp" + + "src/commands/*.cpp" ) if (${PLATFORM} STREQUAL "Desktop") @@ -306,19 +307,16 @@ if (${PLATFORM} STREQUAL "Desktop") endif() # Server -if(UNIX) - add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES}) +add_executable("${PROJECT_NAME}-server" ${SERVER_SOURCES}) - target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER") +target_compile_definitions("${PROJECT_NAME}-server" PUBLIC "STANDALONE_SERVER" "SERVER_PROFILER") - target_include_directories("${PROJECT_NAME}-server" PUBLIC - "${CMAKE_SOURCE_DIR}/glad/include/" - "${CMAKE_SOURCE_DIR}/src/" - "project/lib_projects/raknet/jni/RaknetSources" - ) +target_include_directories("${PROJECT_NAME}-server" PUBLIC + "${CMAKE_SOURCE_DIR}/src/" + "project/lib_projects/raknet/jni/RaknetSources" +) - target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT}) -endif() +target_link_libraries("${PROJECT_NAME}-server" ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBS}) add_executable(${PROJECT_NAME} ${CLIENT_SOURCES}) diff --git a/project/android/jni/Android.mk b/project/android/jni/Android.mk index 551ee31..2ff71e7 100755 --- a/project/android/jni/Android.mk +++ b/project/android/jni/Android.mk @@ -110,6 +110,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \ ../../../src/client/renderer/Textures.cpp \ ../../../src/client/renderer/TileRenderer.cpp \ ../../../src/client/renderer/gles.cpp \ +../../../src/world/level/LevelConstants.cpp \ ../../../src/client/renderer/culling/Frustum.cpp \ ../../../src/client/renderer/entity/ArrowRenderer.cpp \ ../../../src/client/renderer/entity/ChickenRenderer.cpp \ @@ -140,6 +141,12 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \ ../../../src/network/Packet.cpp \ ../../../src/network/RakNetInstance.cpp \ ../../../src/network/ServerSideNetworkHandler.cpp \ +../../../src/commands/Command.cpp \ +../../../src/commands/CommandHelp.cpp \ +../../../src/commands/CommandKick.cpp \ +../../../src/commands/CommandBan.cpp \ +../../../src/commands/CommandManager.cpp \ +../../../src/commands/CommandOp.cpp \ ../../../src/server/ServerLevel.cpp \ ../../../src/server/ServerPlayer.cpp \ ../../../src/util/DataIO.cpp \ diff --git a/project/android_java/jni/Android.mk b/project/android_java/jni/Android.mk index a654801..8e3ae22 100755 --- a/project/android_java/jni/Android.mk +++ b/project/android_java/jni/Android.mk @@ -232,6 +232,7 @@ LOCAL_SRC_FILES := ../../../src/main.cpp \ ../../../src/world/level/tile/entity/TileEntity.cpp \ ../../../src/world/level/tile/entity/FurnaceTileEntity.cpp \ ../../../src/world/phys/HitResult.cpp +../../../src/world/level/LevelConstants.cpp LOCAL_CFLAGS := -Wno-psabi $(LOCAL_CFLAGS) diff --git a/project/lib_projects/raknet/jni/RaknetSources/GetTime.cpp b/project/lib_projects/raknet/jni/RaknetSources/GetTime.cpp index 4f868f8..effd244 100755 --- a/project/lib_projects/raknet/jni/RaknetSources/GetTime.cpp +++ b/project/lib_projects/raknet/jni/RaknetSources/GetTime.cpp @@ -140,7 +140,7 @@ RakNet::TimeUS GetTimeUS_Windows( void ) #if _MSC_VER >= 1400 && defined (_M_X64) GetProcessAffinityMask(mProc, (PDWORD_PTR)&mProcMask, (PDWORD_PTR)&mSysMask); #else - GetProcessAffinityMask(mProc, &mProcMask, &mSysMask); + GetProcessAffinityMask(mProc, (PDWORD_PTR)&mProcMask, (PDWORD_PTR)&mSysMask); #endif mThread = GetCurrentThread(); diff --git a/src/NinecraftApp.cpp b/src/NinecraftApp.cpp index d2feea6..60e9fee 100755 --- a/src/NinecraftApp.cpp +++ b/src/NinecraftApp.cpp @@ -136,7 +136,7 @@ void NinecraftApp::teardown() Recipes ::teardownRecipes(); TileEntity::teardownTileEntities(); #endif -#ifdef WIN32 +#if defined(WIN32) && !defined(STANDALONE_SERVER) ItemRenderer::teardown_static(); if (EntityTileRenderer::instance != NULL) { delete EntityTileRenderer::instance; diff --git a/src/client/Minecraft.cpp b/src/client/Minecraft.cpp index 4992be4..2db00dc 100755 --- a/src/client/Minecraft.cpp +++ b/src/client/Minecraft.cpp @@ -2,6 +2,7 @@ #include "Options.h" #include "client/Options.h" #include "client/player/input/IBuildInput.h" +#include "commands/CommandManager.hpp" #include "platform/input/Keyboard.h" #include "world/item/Item.h" #include "world/item/ItemInstance.h" @@ -180,7 +181,8 @@ Minecraft::Minecraft() : _powerVr(false), commandPort(4711), reserved_d1(0),reserved_d2(0), - reserved_f1(0),reserved_f2(0), options(this) + reserved_f1(0),reserved_f2(0), options(this), + m_commandManager() { //#ifdef ANDROID @@ -261,9 +263,10 @@ void Minecraft::selectLevel( const std::string& levelId, const std::string& leve void Minecraft::setLevel(Level* level, const std::string& message /* ="" */, LocalPlayer* forceInsertPlayer /* = NULL */) { cameraTargetPlayer = NULL; - LOGI("Seed is %ld\n", level->getSeed()); if (level != NULL) { + LOGI("Seed is %ld\n", level->getSeed()); + level->raknetInstance = raknetInstance; gameMode->initLevel(level); @@ -280,6 +283,11 @@ void Minecraft::setLevel(Level* level, const std::string& message /* ="" */, Loc } } this->level = level; + // So uhhh + std::string op = options.getStringValue(OPTIONS_USERNAME); + std::transform(op.begin(), op.end(), op.begin(), ::tolower); + + level->ops.emplace(op); _hasSignaledGeneratingLevelFinished = false; #ifdef STANDALONE_SERVER const bool threadedLevelCreation = false; @@ -363,12 +371,12 @@ void Minecraft::prepareLevel(const std::string& title) { if (!level->isNew()) level->setUpdateLights(false); - int Max = CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; + int Max = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH; int pp = 0; - for (int x = 8; x < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); x += CHUNK_WIDTH) { - for (int z = 8; z < (CHUNK_CACHE_WIDTH * CHUNK_WIDTH); z += CHUNK_WIDTH) { - progressStagePercentage = 100 * pp++ / Max; - //printf("level generation progress %d\n", progressStagePercentage); + for (int x = 8; x < (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH); x += LevelConstants::CHUNK_WIDTH) { + for (int z = 8; z < (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH); z += LevelConstants::CHUNK_WIDTH) { + progressStagePercentage = 100 * pp++ / Max; + //printf("level generation progress %d\n", progressStagePercentage); B.start(); level->getTile(x, 64, z); B.stop(); @@ -383,9 +391,9 @@ void Minecraft::prepareLevel(const std::string& title) { level->setUpdateLights(true); C.start(); - for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) + for (int x = 0; x < LevelConstants::CHUNK_CACHE_WIDTH; x++) { - for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) + for (int z = 0; z < LevelConstants::CHUNK_CACHE_WIDTH; z++) { LevelChunk* chunk = level->getChunk(x, z); if (chunk && !chunk->createdFromSave) @@ -559,7 +567,7 @@ void Minecraft::tick(int nTick, int maxTick) { level->tickEntities(); level->tick(); #ifndef STANDALONE_SERVER - TIMER_POP_PUSH("animateTick"); + TIMER_POP_PUSH("animateTick"); if (player) { level->animateTick(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)); } @@ -732,6 +740,21 @@ void Minecraft::tickInput() { if (key == Keyboard::KEY_F3) { options.toggle(OPTIONS_RENDER_DEBUG); } + + // TODO: replace it with client /give command :face_vomiting: + // if (key == Keyboard::KEY_F4) { + // player->inventory->add(new ItemInstance(Tile::redBrick)); + // player->inventory->add(new ItemInstance(Item::ironIngot, 64)); + // player->inventory->add(new ItemInstance(Item::ironIngot, 34)); + // player->inventory->add(new ItemInstance(Tile::stonecutterBench)); + // player->inventory->add(new ItemInstance(Tile::workBench)); + // player->inventory->add(new ItemInstance(Tile::furnace)); + // player->inventory->add(new ItemInstance(Tile::wood, 54)); + // player->inventory->add(new ItemInstance(Item::stick, 14)); + // player->inventory->add(new ItemInstance(Item::coal, 31)); + // player->inventory->add(new ItemInstance(Tile::sand, 6)); + + // } if (key == Keyboard::KEY_F5) { options.toggle(OPTIONS_THIRD_PERSON_VIEW); @@ -1136,6 +1159,7 @@ bool Minecraft::supportNonTouchScreen() { } void Minecraft::init() { + LevelChunk::ChunkBlockCount = LevelConstants::CHUNK_BLOCK_COUNT; #ifndef STANDALONE_SERVER checkGlError("Init enter"); @@ -1373,12 +1397,9 @@ bool Minecraft::joinMultiplayerFromString( const std::string& server ) } else { ip = server; } - - printf("%s \n", port.c_str()); - + if (isLookingForMultiplayer && netCallback) { isLookingForMultiplayer = false; - printf("test"); int portNum = atoi(port.c_str()); return raknetInstance->connect(ip.c_str(), portNum); } @@ -1686,3 +1707,11 @@ void Minecraft::optionUpdated(OptionId option, int value ) { setSize(width, height); } } + +void Minecraft::addMessage(const std::string& msg) { +#ifndef STANDALONE_SERVER + gui.addMessage(msg); +#else + LOGI("%s \n", msg.c_str()); +#endif +} \ No newline at end of file diff --git a/src/client/Minecraft.h b/src/client/Minecraft.h index 72d3be7..f1d966f 100755 --- a/src/client/Minecraft.h +++ b/src/client/Minecraft.h @@ -2,6 +2,7 @@ #define NET_MINECRAFT_CLIENT__Minecraft_H__ #include "Options.h" +#include "commands/CommandManager.hpp" #ifndef STANDALONE_SERVER #include "MouseHandler.h" #include "gui/Gui.h" @@ -128,11 +129,17 @@ public: void optionUpdated(OptionId option, bool value); void optionUpdated(OptionId option, float value); void optionUpdated(OptionId option, int value); + + int getTicks() { return ticks; } + + void addMessage(const std::string& msg); #ifdef __APPLE__ bool _isSuperFast; bool isSuperFast() { return _isSuperFast; } #endif + CommandManager& commandManager() { return m_commandManager; } + protected: void _levelGenerated(); @@ -205,7 +212,8 @@ public: std::string externalCacheStoragePath; protected: Timer timer; - // @note @attn @warn: this is dangerous as fuck! + + // @note @attn @warn: this is dangerous as fuck! volatile bool isGeneratingLevel; bool _hasSignaledGeneratingLevelFinished; @@ -233,6 +241,8 @@ private: PerfRenderer* _perfRenderer; CommandServer* _commandServer; + + CommandManager m_commandManager; }; #endif /*NET_MINECRAFT_CLIENT__Minecraft_H__*/ diff --git a/src/client/gamemode/GameMode.cpp b/src/client/gamemode/GameMode.cpp index de6df50..8009d64 100755 --- a/src/client/gamemode/GameMode.cpp +++ b/src/client/gamemode/GameMode.cpp @@ -90,8 +90,12 @@ bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x float clickY = hit.y - y; float clickZ = hit.z - z; if (level->isClientSide) { + LOGI("%f %f %f \n", player->x, player->y, player->z); + item = player->inventory->getSelected(); - UseItemPacket packet(x, y, z, face, item, player->entityId, clickX, clickY, clickZ); + UseItemPacket packet(x, y, z, face, item, player->entityId, clickX, clickY, clickZ, player->x, player->y, player->z, + player->bb.x0, player->bb.y0, player->bb.z0, player->bb.x1, player->bb.y1, player->bb.z1); + minecraft->raknetInstance->send(packet); } int t = level->getTile(x, y, z); @@ -100,7 +104,7 @@ bool GameMode::useItemOn(Player* player, Level* level, ItemInstance* item, int x return true; if (item == NULL) return false; - if(isCreativeType()) { + if (isCreativeType()) { int aux = item->getAuxValue(); int count = item->count; bool success = item->useOn(player, level, x, y, z, face, clickX, clickY, clickZ); @@ -117,7 +121,8 @@ bool GameMode::useItem( Player* player, Level* level, ItemInstance* item ) { ItemInstance* itemInstance = item->use(level, player); if(level->isClientSide) { - UseItemPacket packet(item, player->entityId, player->aimDirection); + UseItemPacket packet(item, player->entityId, player->aimDirection, player->x, player->y, player->z, + player->bb.x0, player->bb.y0, player->bb.z0, player->bb.x1, player->bb.y1, player->bb.z1); minecraft->raknetInstance->send(packet); } if (itemInstance != item || (itemInstance != NULL && itemInstance->count != oldCount)) { diff --git a/src/client/gamemode/SurvivalMode.cpp b/src/client/gamemode/SurvivalMode.cpp index ac49fda..c53c198 100755 --- a/src/client/gamemode/SurvivalMode.cpp +++ b/src/client/gamemode/SurvivalMode.cpp @@ -68,6 +68,7 @@ bool SurvivalMode::destroyBlock( int x, int y, int z, int face ) { minecraft->player->inventory->clearSlot(minecraft->player->inventory->selected); } } + if (changed && couldDestroy) { ItemInstance instance(t, 1, data); Tile::tiles[t]->playerDestroy(minecraft->level, minecraft->player, x, y, z, data); diff --git a/src/client/gui/Gui.cpp b/src/client/gui/Gui.cpp index 324ba15..9026abc 100755 --- a/src/client/gui/Gui.cpp +++ b/src/client/gui/Gui.cpp @@ -755,7 +755,6 @@ void Gui::renderDebugInfo() { // Position float px = p->x, py = p->y - p->heightOffset, pz = p->z; - posTranslator.to(px, py, pz); int bx = (int)floorf(px), by = (int)floorf(py), bz = (int)floorf(pz); int cx = bx >> 4, cz = bz >> 4; diff --git a/src/client/gui/screens/ConsoleScreen.cpp b/src/client/gui/screens/ConsoleScreen.cpp index 939cb74..42f47ee 100644 --- a/src/client/gui/screens/ConsoleScreen.cpp +++ b/src/client/gui/screens/ConsoleScreen.cpp @@ -8,6 +8,7 @@ #include "../../../network/ServerSideNetworkHandler.h" #include "../../../network/packet/ChatPacket.h" #include "../../../platform/log.h" +#include "util/StringUtils.h" #include #include @@ -54,141 +55,37 @@ void ConsoleScreen::charPressed(char inputChar) _input += inputChar; } -// --------------------------------------------------------------------------- -// execute: run _input as a command, print result, close screen -// --------------------------------------------------------------------------- void ConsoleScreen::execute() { + if (!minecraft->level) return; + if (_input.empty()) { - minecraft->setScreen(NULL); - return; + return minecraft->setScreen(NULL); } if (_input[0] == '/') { // Command - std::string result = processCommand(_input); - if (!result.empty()) - minecraft->gui.addMessage(result); + _input = Util::stringTrim(_input.substr(1)); + + std::istringstream iss(minecraft->commandManager().execute(*minecraft, *minecraft->player, _input)); + for (std::string line; std::getline(iss, line); ) { + minecraft->gui.addMessage(line); + } } else { - // Chat message: message - std::string msg = std::string("<") + minecraft->player->name + "> " + _input; + // @ai @rewrite if (minecraft->netCallback && minecraft->raknetInstance->isServer()) { - // Hosting a LAN game: displayGameMessage shows locally + broadcasts MessagePacket to clients - static_cast(minecraft->netCallback)->displayGameMessage(msg); + static_cast(minecraft->netCallback)->displayGameMessage(_input); } else if (minecraft->netCallback) { - // Connected client: send ChatPacket to server; server echoes it back as MessagePacket - ChatPacket chatPkt(msg); + ChatPacket chatPkt(_input); minecraft->raknetInstance->send(chatPkt); } else { - // Singleplayer: show locally only - minecraft->gui.addMessage(msg); + minecraft->gui.addMessage("<" + minecraft->player->name + "> " + _input); } } minecraft->setScreen(NULL); } -// --------------------------------------------------------------------------- -// processCommand -// --------------------------------------------------------------------------- -static std::string trim(const std::string& s) { - size_t a = s.find_first_not_of(" \t"); - if (a == std::string::npos) return ""; - size_t b = s.find_last_not_of(" \t"); - return s.substr(a, b - a + 1); -} - -std::string ConsoleScreen::processCommand(const std::string& raw) -{ - // strip leading '/' - std::string line = raw; - if (!line.empty() && line[0] == '/') line = line.substr(1); - line = trim(line); - - // tokenise - std::vector args; - { - std::istringstream ss(line); - std::string tok; - while (ss >> tok) args.push_back(tok); - } - - if (args.empty()) return ""; - - Level* level = minecraft->level; - if (!level) return "No level loaded."; - - // ----------------------------------------------------------------------- - // /time ... - // ----------------------------------------------------------------------- - if (args[0] == "time") { - if (args.size() < 2) - return "Usage: /time ..."; - - const std::string& sub = args[1]; - - // -- time add ----------------------------------------------- - if (sub == "add") { - if (args.size() < 3) return "Usage: /time add "; - long delta = std::atol(args[2].c_str()); - long newTime = level->getTime() + delta; - level->setTime(newTime); - std::ostringstream out; - out << "Set the time to " << (newTime % Level::TICKS_PER_DAY); - return out.str(); - } - - // -- time set ----------------------- - if (sub == "set") { - if (args.size() < 3) return "Usage: /time set "; - const std::string& val = args[2]; - - long t = -1; - if (val == "day") t = 1000; - else if (val == "noon") t = 6000; - else if (val == "night") t = 13000; - else if (val == "midnight") t = 18000; - else { - // numeric — accept positive integers only - bool numeric = true; - for (char c : val) - if (!std::isdigit((unsigned char)c)) { numeric = false; break; } - if (!numeric) return std::string("Unknown value: ") + val; - t = std::atol(val.c_str()); - } - - // Preserve the total day count so only the time-of-day changes - long dayCount = level->getTime() / Level::TICKS_PER_DAY; - long newTime = dayCount * Level::TICKS_PER_DAY + (t % Level::TICKS_PER_DAY); - level->setTime(newTime); - std::ostringstream out; - out << "Set the time to " << t; - return out.str(); - } - - // -- time query ------------------------------ - if (sub == "query") { - if (args.size() < 3) return "Usage: /time query "; - const std::string& what = args[2]; - - long total = level->getTime(); - long daytime = total % Level::TICKS_PER_DAY; - long day = total / Level::TICKS_PER_DAY; - - std::ostringstream out; - if (what == "daytime") { out << "The time of day is " << daytime; } - else if (what == "gametime") { out << "The game time is " << total; } - else if (what == "day") { out << "The day is " << day; } - else return std::string("Unknown query: ") + what; - return out.str(); - } - - return "Unknown sub-command. Usage: /time ..."; - } - - return std::string("Unknown command: /") + args[0]; -} - // --------------------------------------------------------------------------- // render // --------------------------------------------------------------------------- diff --git a/src/client/gui/screens/ConsoleScreen.h b/src/client/gui/screens/ConsoleScreen.h index e0074b9..f0c1fd5 100644 --- a/src/client/gui/screens/ConsoleScreen.h +++ b/src/client/gui/screens/ConsoleScreen.h @@ -25,7 +25,6 @@ public: private: void execute(); - std::string processCommand(const std::string& cmd); std::string _input; int _cursorBlink; // tick counter for cursor blink diff --git a/src/client/gui/screens/crafting/PaneCraftingScreen.cpp b/src/client/gui/screens/crafting/PaneCraftingScreen.cpp index 4e3d025..6d6e407 100755 --- a/src/client/gui/screens/crafting/PaneCraftingScreen.cpp +++ b/src/client/gui/screens/crafting/PaneCraftingScreen.cpp @@ -16,7 +16,12 @@ #include "../../../../world/level/Level.h" #include "../../../../world/item/DyePowderItem.h" #include "../../../../world/item/crafting/Recipe.h" +#include "network/RakNetInstance.h" +#include "network/packet/WantCreatePacket.h" #include "platform/input/Keyboard.h" +#include +#include +#include static NinePatchLayer* guiPaneFrame = NULL; @@ -193,6 +198,26 @@ void PaneCraftingScreen::setupPositions() { } void PaneCraftingScreen::tick() { + if (minecraft->isOnline()) { + // TODO: Make better algorithm + static std::map oldMap = {}; + std::map newMap = {}; + + for (int i = Inventory::MAX_SELECTION_SIZE; i < minecraft->player->inventory->getContainerSize(); ++i) { + auto itm = minecraft->player->inventory->getItem(i); + + if (itm != NULL) { + newMap[itm->id] += itm->count; + } + } + + if (oldMap != newMap) { + oldMap = newMap; + newMap = {}; + recheckRecipes(); + } + } + if (pane) pane->tick(); } @@ -439,25 +464,29 @@ void PaneCraftingScreen::craftSelectedItem() ItemInstance resultItem = currentItem->item; if (minecraft->player) { + if (minecraft->isOnline()) { + WantCreatePacket packet(minecraft->player->entityId, resultItem.count, resultItem.getAuxValue(), resultItem.id); + minecraft->raknetInstance->send(packet); + } // Remove all items required for the recipe and ... for (unsigned int i = 0; i < currentItem->neededItems.size(); ++i) { CItem::ReqItem& req = currentItem->neededItems[i]; - // If the recipe allows any aux-value as ingredients, first deplete - // aux == 0 from inventory. Since I'm not sure if this always is - // correct, let's only do it for ingredient sandstone for now. - ItemInstance toRemove = req.item; + // If the recipe allows any aux-value as ingredients, first deplete + // aux == 0 from inventory. Since I'm not sure if this always is + // correct, let's only do it for ingredient sandstone for now. + ItemInstance toRemove = req.item; - if (Tile::sandStone->id == req.item.id - && Recipe::ANY_AUX_VALUE == req.item.getAuxValue()) { - toRemove.setAuxValue(0); - toRemove.count = minecraft->player->inventory->removeResource(toRemove, true); - toRemove.setAuxValue(Recipe::ANY_AUX_VALUE); - } + if (Tile::sandStone->id == req.item.id + && Recipe::ANY_AUX_VALUE == req.item.getAuxValue()) { + toRemove.setAuxValue(0); + toRemove.count = minecraft->player->inventory->removeResource(toRemove, true); + toRemove.setAuxValue(Recipe::ANY_AUX_VALUE); + } - if (toRemove.count > 0) { - minecraft->player->inventory->removeResource(toRemove); - } + if (toRemove.count > 0) { + minecraft->player->inventory->removeResource(toRemove); + } } // ... add the new one! (in this order, to fill empty slots better) // if it doesn't fit, throw it on the ground! diff --git a/src/client/player/LocalPlayer.cpp b/src/client/player/LocalPlayer.cpp index bc612c9..86a345f 100755 --- a/src/client/player/LocalPlayer.cpp +++ b/src/client/player/LocalPlayer.cpp @@ -460,7 +460,7 @@ void LocalPlayer::tick() { { sentInventoryItemId = newItemId; sentInventoryItemData = newItemData; - PlayerEquipmentPacket packet(entityId, newItemId, newItemData); + PlayerEquipmentPacket packet(entityId, newItemId, newItemData, inventory->selected, inventory->getSlot(newItemId, newItemData)); minecraft->raknetInstance->send(packet); } } diff --git a/src/client/renderer/LevelRenderer.cpp b/src/client/renderer/LevelRenderer.cpp index 2630d63..ba57fb6 100755 --- a/src/client/renderer/LevelRenderer.cpp +++ b/src/client/renderer/LevelRenderer.cpp @@ -69,7 +69,7 @@ LevelRenderer::LevelRenderer( Minecraft* mc) destroyProgress(0) { #ifdef OPENGL_ES - int maxChunksWidth = 2 * LEVEL_WIDTH / CHUNK_SIZE + 1; + int maxChunksWidth = 2 * LevelConstants::LEVEL_WIDTH / CHUNK_SIZE + 1; numListsOrBuffers = maxChunksWidth * maxChunksWidth * (128/CHUNK_SIZE) * 3; chunkBuffers = new GLuint[numListsOrBuffers]; glGenBuffers2(numListsOrBuffers, chunkBuffers); @@ -339,15 +339,15 @@ int LevelRenderer::render( Mob* player, int layer, float alpha ) allChanged(); } - int currentFogType = mc->options.getIntValue(OPTIONS_FOG_TYPE); - if (currentFogType != lastFogType) { - lastFogType = currentFogType; - - if (level && level->dimension) { - level->dimension->FogType = currentFogType; // use new fog stuff - } - - allChanged(); + int currentFogType = mc->options.getIntValue(OPTIONS_FOG_TYPE); + if (currentFogType != lastFogType) { + lastFogType = currentFogType; + + if (level && level->dimension) { + level->dimension->FogType = currentFogType; // use new fog stuff + } + + allChanged(); } bool SmoothLightState = mc->options.getBooleanValue(OPTIONS_AMBIENT_OCCLUSION); if (SmoothLightState != mc->useAmbientOcclusion){ @@ -1073,56 +1073,56 @@ std::string LevelRenderer::gatherStats1() { // int[] toRender = new int[50000]; // IntBuffer resultBuffer = MemoryTracker.createIntBuffer(64); - void LevelRenderer::generateStars() { - // ported from java beta again, - // converted the doubles into floats to be consistent, shouldnt affect much - shredder - - Random random = Random(10842L); - Tesselator& t = Tesselator::instance; - t.begin(); - starVertexCount = 0; - - for (int i = 0; i < 1500; i++) { - float d = random.nextFloat() * 2.0F - 1.0F; - float e = random.nextFloat() * 2.0F - 1.0F; - float f = random.nextFloat() * 2.0F - 1.0F; - float g = 0.25F + random.nextFloat() * 0.25F; - float h = d * d + e * e + f * f; - if (h < 1.0 && h > 0.01) { - h = 1.0 / Mth::sqrt(h); - d *= h; - e *= h; - f *= h; - float j = d * 100.0; - float k = e * 100.0; - float l = f * 100.0; - float m = Mth::atan2(d, f); - float n = Mth::sin(m); - float o = Mth::cos(m); - float p = Mth::atan2(Mth::sqrt(d * d + f * f), e); - float q = Mth::sin(p); - float r = Mth::cos(p); - float s = random.nextDouble() * Mth::PI * 2.0; - float t2 = Mth::sin(s); - float u = Mth::cos(s); - - for (int v = 0; v < 4; v++) { - float w = 0.0; - float x = ((v & 2) - 1) * g; - float y = ((v + 1 & 2) - 1) * g; - float aa = x * u - y * t2; - float ab = y * u + x * t2; - float ad = aa * q + w * r; - float ae = w * q - aa * r; - float af = ae * n - ab * o; - float ah = ab * n + ae * o; - t.vertex(j + af, k + ad, l + ah); - } - starVertexCount += 4; - } - } - - t.end(true, starBuffer); + void LevelRenderer::generateStars() { + // ported from java beta again, + // converted the doubles into floats to be consistent, shouldnt affect much - shredder + + Random random = Random(10842L); + Tesselator& t = Tesselator::instance; + t.begin(); + starVertexCount = 0; + + for (int i = 0; i < 1500; i++) { + float d = random.nextFloat() * 2.0F - 1.0F; + float e = random.nextFloat() * 2.0F - 1.0F; + float f = random.nextFloat() * 2.0F - 1.0F; + float g = 0.25F + random.nextFloat() * 0.25F; + float h = d * d + e * e + f * f; + if (h < 1.0 && h > 0.01) { + h = 1.0 / Mth::sqrt(h); + d *= h; + e *= h; + f *= h; + float j = d * 100.0; + float k = e * 100.0; + float l = f * 100.0; + float m = Mth::atan2(d, f); + float n = Mth::sin(m); + float o = Mth::cos(m); + float p = Mth::atan2(Mth::sqrt(d * d + f * f), e); + float q = Mth::sin(p); + float r = Mth::cos(p); + float s = random.nextDouble() * Mth::PI * 2.0; + float t2 = Mth::sin(s); + float u = Mth::cos(s); + + for (int v = 0; v < 4; v++) { + float w = 0.0; + float x = ((v & 2) - 1) * g; + float y = ((v + 1 & 2) - 1) * g; + float aa = x * u - y * t2; + float ab = y * u + x * t2; + float ad = aa * q + w * r; + float ae = w * q - aa * r; + float af = ae * n - ab * o; + float ah = ab * n + ae * o; + t.vertex(j + af, k + ad, l + ah); + } + starVertexCount += 4; + } + } + + t.end(true, starBuffer); } void LevelRenderer::renderSky(float alpha) { if (mc->level->dimension->foggy) return; @@ -1155,100 +1155,100 @@ void LevelRenderer::renderSky(float alpha) { #ifdef OPENGL_ES drawArrayVT(skyBuffer, skyVertexCount); #endif - glDisable(GL_FOG); - glDisable(GL_ALPHA_TEST); - - // re ported this again from beta 1.6.6, thanks to the mcpe 0.1 decomp team's code for some bit of help about the void layer - shredder - - // Sunrise - if (mc->options.getBooleanValue(OPTIONS_BEAUTIFUL_SKY)) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - Lighting::turnOff(); - float* c = level->dimension->getSunriseColor(level->getTimeOfDay(alpha), alpha); - if (c != nullptr) - { - glDisable(GL_TEXTURE_2D); -// glShadeModel(GL_SMOOTH); // - - glPushMatrix(); - glRotatef(90.0f, 1.0f, 0.0f, 0.0f); - glRotatef(level->getTimeOfDay(alpha) > 0.5f ? 180 : 0, 0.0f, 0.0f, 1.0f); - t.begin(GL_TRIANGLE_FAN); - t.color(c[0], c[1], c[2], c[3]); - t.vertex(0.0f, 100.0f, 0.0f); - t.color(c[0], c[1], c[2], 0.0f); - - int steps = 16; - for (int i = 0; i <= steps; i++) - { - float a = i * 3.1415927f * 2.0f / steps; - float sin = Mth::sin(a); - float cos = Mth::cos(a); - t.vertex((sin * 120.0f), (cos * 120.0f), (-cos * 40.0f * c[3])); - } - - t.draw(); - glPopMatrix(); -// glShadeModel(GL_FLAT); // - } - - // gets the time of day and rotates the sun and moon png based on the time - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + glDisable(GL_FOG); + glDisable(GL_ALPHA_TEST); + + // re ported this again from beta 1.6.6, thanks to the mcpe 0.1 decomp team's code for some bit of help about the void layer - shredder + + // Sunrise + if (mc->options.getBooleanValue(OPTIONS_BEAUTIFUL_SKY)) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + Lighting::turnOff(); + float* c = level->dimension->getSunriseColor(level->getTimeOfDay(alpha), alpha); + if (c != nullptr) + { + glDisable(GL_TEXTURE_2D); +// glShadeModel(GL_SMOOTH); // + + glPushMatrix(); + glRotatef(90.0f, 1.0f, 0.0f, 0.0f); + glRotatef(level->getTimeOfDay(alpha) > 0.5f ? 180 : 0, 0.0f, 0.0f, 1.0f); + t.begin(GL_TRIANGLE_FAN); + t.color(c[0], c[1], c[2], c[3]); + t.vertex(0.0f, 100.0f, 0.0f); + t.color(c[0], c[1], c[2], 0.0f); + + int steps = 16; + for (int i = 0; i <= steps; i++) + { + float a = i * 3.1415927f * 2.0f / steps; + float sin = Mth::sin(a); + float cos = Mth::cos(a); + t.vertex((sin * 120.0f), (cos * 120.0f), (-cos * 40.0f * c[3])); + } + + t.draw(); + glPopMatrix(); +// glShadeModel(GL_FLAT); // + } + + // gets the time of day and rotates the sun and moon png based on the time + glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); glPushMatrix(); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glTranslatef(sc.x, sc.y, sc.z); - glRotatef(0.0f, 0.0f, 0.0f, 1.0f); - glRotatef(level->getTimeOfDay(alpha) * 360.0f, 1.0f, 0.0f, 0.0f); - - float ss = 30.0f; - - - textures->loadAndBindTexture("terrain/sun.png"); - t.begin(); - t.vertexUV(-ss, 100.0f, -ss, 0.0f, 0.0f); - t.vertexUV(ss, 100.0f, -ss, 1.0f, 0.0f); - t.vertexUV(ss, 100.0f, ss, 1.0f, 1.0f); - t.vertexUV(-ss, 100.0f, ss, 0.0f, 1.0f); - t.draw(); - - ss = 20.0f; - textures->loadAndBindTexture("terrain/moon.png"); - t.begin(); - t.vertexUV(-ss, -100.0f, ss, 1.0f, 1.0f); - t.vertexUV(ss, -100.0f, ss, 0.0f, 1.0f); - t.vertexUV(ss, -100.0f, -ss, 0.0f, 0.0f); - t.vertexUV(-ss, -100.0f, -ss, 1.0f, 0.0f); - t.draw(); - - - glDisable(GL_TEXTURE_2D); - - float a = level->getStarBrightness(alpha); - if (a > 0.0f) - { - glColor4f(a, a, a, a); - drawArrayVT(starBuffer, starVertexCount); - } - } - - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glDisable(GL_BLEND); - glEnable(GL_ALPHA_TEST); - glEnable(GL_FOG); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glTranslatef(sc.x, sc.y, sc.z); + glRotatef(0.0f, 0.0f, 0.0f, 1.0f); + glRotatef(level->getTimeOfDay(alpha) * 360.0f, 1.0f, 0.0f, 0.0f); + + float ss = 30.0f; + + + textures->loadAndBindTexture("terrain/sun.png"); + t.begin(); + t.vertexUV(-ss, 100.0f, -ss, 0.0f, 0.0f); + t.vertexUV(ss, 100.0f, -ss, 1.0f, 0.0f); + t.vertexUV(ss, 100.0f, ss, 1.0f, 1.0f); + t.vertexUV(-ss, 100.0f, ss, 0.0f, 1.0f); + t.draw(); + + ss = 20.0f; + textures->loadAndBindTexture("terrain/moon.png"); + t.begin(); + t.vertexUV(-ss, -100.0f, ss, 1.0f, 1.0f); + t.vertexUV(ss, -100.0f, ss, 0.0f, 1.0f); + t.vertexUV(ss, -100.0f, -ss, 0.0f, 0.0f); + t.vertexUV(-ss, -100.0f, -ss, 1.0f, 0.0f); + t.draw(); + + + glDisable(GL_TEXTURE_2D); + + float a = level->getStarBrightness(alpha); + if (a > 0.0f) + { + glColor4f(a, a, a, a); + drawArrayVT(starBuffer, starVertexCount); + } + } + + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glDisable(GL_BLEND); + glEnable(GL_ALPHA_TEST); + glEnable(GL_FOG); glPopMatrix(); // ported over void plane (the blue bottom plane seen in java) because pocket edition lacks it @TODO test if it's buggy - shredder - -// glColor3f(sc.x * 0.2f + 0.04f, sc.y * 0.2f + 0.04f, sc.z * 0.6f + 0.1f); - glColor4f(sc.x * 0.2f + 0.04f, sc.y * 0.2f + 0.04f, sc.z * 0.6f + 0.1f, 1.0f); - glDisable(GL_TEXTURE_2D); - if(mc->options.getBooleanValue(OPTIONS_BETA_SKY)){ - drawArrayVT(voidBuffer, voidVertexCount); - } + +// glColor3f(sc.x * 0.2f + 0.04f, sc.y * 0.2f + 0.04f, sc.z * 0.6f + 0.1f); + glColor4f(sc.x * 0.2f + 0.04f, sc.y * 0.2f + 0.04f, sc.z * 0.6f + 0.1f, 1.0f); + glDisable(GL_TEXTURE_2D); + if(mc->options.getBooleanValue(OPTIONS_BETA_SKY)){ + drawArrayVT(voidBuffer, voidVertexCount); + } glEnable(GL_TEXTURE_2D); // @TODO shredder - should not enable or disable depth mask if using legacy sky because mcpe sky rendering is awful and will render clouds above terrain @@ -1311,194 +1311,195 @@ void LevelRenderer::renderClouds( float alpha ) { glEnable(GL_CULL_FACE); } -void LevelRenderer::renderAdvancedClouds(float alpha) { - - // ported from java beta, tesselation code for the 3d clouds, renders broken if mcpe sky rendering option is used - shredder - - glDisable(GL_CULL_FACE); - - float px = mc->player->xOld + (mc->player->x - mc->player->xOld) * alpha; - float py = mc->player->yOld + (mc->player->y - mc->player->yOld) * alpha; - float pz = mc->player->zOld + (mc->player->z - mc->player->zOld) * alpha; - - Tesselator& t = Tesselator::instance; - float ss = 12.0f; - float h = 4.0f; - - float cloudTime = (float)ticks + alpha; - - float xo = (px + cloudTime * 0.03f) / ss; - float zo = pz / ss + 0.33f; - - float yy = 108.0f - py + 0.33f; - - int xWraps = Mth::floor(xo / 2048.0); - int zWraps = Mth::floor(zo / 2048.0); - xo -= xWraps * 2048; - zo -= zWraps * 2048; - - textures->loadAndBindTexture("environment/clouds.png"); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - Vec3 cc = level->getCloudColor(alpha); - float cr = cc.x; - float cg = cc.y; - float cb = cc.z; - - float uvScale = 1.0f / 256.0f; - float uo = (float)Mth::floor(xo) * uvScale; - float vo = (float)Mth::floor(zo) * uvScale; - - float xOffs = (float)(xo - Mth::floor(xo)); - float zOffs = (float)(zo - Mth::floor(zo)); - - int D = 8; - int radius = 3; - float e = 1.0f / 1024.0f; - - glPushMatrix(); - glScalef(ss, 1.0f, ss); - - for (int pass = 0; pass < 2; pass++) { - - if (pass == 0) glColorMask(false, false, false, false); - else glColorMask(true, true, true, true); - - for (int xPos = -radius + 1; xPos <= radius; xPos++) { - for (int zPos = -radius + 1; zPos <= radius; zPos++) { - t.begin(); - float xx = (float)(xPos * D); - float zz = (float)(zPos * D); - float xp = xx - xOffs; - float zp = zz - zOffs; - - - if (yy > -h - 1.0f) { - t.color(cr * 0.7f, cg * 0.7f, cb * 0.7f, 0.8f); - t.normal(0.0f, -1.0f, 0.0f); - t.vertexUV(xp + 0, yy + 0, zp + D, (xx + 0) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + D, yy + 0, zp + D, (xx + D) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + D, yy + 0, zp + 0, (xx + D) * uvScale + uo, (zz + 0) * uvScale + vo); - t.vertexUV(xp + 0, yy + 0, zp + 0, (xx + 0) * uvScale + uo, (zz + 0) * uvScale + vo); - } - - - if (yy <= h + 1.0f) { - t.color(cr, cg, cb, 0.8f); - t.normal(0.0f, 1.0f, 0.0f); - t.vertexUV(xp + 0, yy + h - e, zp + D, (xx + 0) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + D, yy + h - e, zp + D, (xx + D) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + D, yy + h - e, zp + 0, (xx + D) * uvScale + uo, (zz + 0) * uvScale + vo); - t.vertexUV(xp + 0, yy + h - e, zp + 0, (xx + 0) * uvScale + uo, (zz + 0) * uvScale + vo); - } - - t.color(cr * 0.9f, cg * 0.9f, cb * 0.9f, 0.8f); - - - if (xPos > -1) { - t.normal(-1.0f, 0.0f, 0.0f); - for (int i = 0; i < D; i++) { - t.vertexUV(xp + i + 0, yy + 0, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + i + 0, yy + h, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + i + 0, yy + h, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); - t.vertexUV(xp + i + 0, yy + 0, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); - } - } - if (xPos <= 1) { - t.normal(1.0f, 0.0f, 0.0f); - for (int i = 0; i < D; i++) { - t.vertexUV(xp + i + 1 - e, yy + 0, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + i + 1 - e, yy + h, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); - t.vertexUV(xp + i + 1 - e, yy + h, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); - t.vertexUV(xp + i + 1 - e, yy + 0, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); - } - } - - t.color(cr * 0.8f, cg * 0.8f, cb * 0.8f, 0.8f); - - - if (zPos > -1) { - t.normal(0.0f, 0.0f, -1.0f); - for (int i = 0; i < D; i++) { - t.vertexUV(xp + 0, yy + h, zp + i + 0, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - t.vertexUV(xp + D, yy + h, zp + i + 0, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - t.vertexUV(xp + D, yy + 0, zp + i + 0, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - t.vertexUV(xp + 0, yy + 0, zp + i + 0, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - } - } - if (zPos <= 1) { - t.normal(0.0f, 0.0f, 1.0f); - for (int i = 0; i < D; i++) { - t.vertexUV(xp + 0, yy + h, zp + i + 1 - e, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - t.vertexUV(xp + D, yy + h, zp + i + 1 - e, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - t.vertexUV(xp + D, yy + 0, zp + i + 1 - e, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - t.vertexUV(xp + 0, yy + 0, zp + i + 1 - e, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); - } - } - t.endOverrideAndDraw(); - } - } - } - - glPopMatrix(); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - glDisable(GL_BLEND); - glEnable(GL_CULL_FACE); +void LevelRenderer::renderAdvancedClouds(float alpha) { + + // ported from java beta, tesselation code for the 3d clouds, renders broken if mcpe sky rendering option is used - shredder + + glDisable(GL_CULL_FACE); + + float px = mc->player->xOld + (mc->player->x - mc->player->xOld) * alpha; + float py = mc->player->yOld + (mc->player->y - mc->player->yOld) * alpha; + float pz = mc->player->zOld + (mc->player->z - mc->player->zOld) * alpha; + + Tesselator& t = Tesselator::instance; + float ss = 12.0f; + float h = 4.0f; + + float cloudTime = (float)ticks + alpha; + + float xo = (px + cloudTime * 0.03f) / ss; + float zo = pz / ss + 0.33f; + + float yy = 108.0f - py + 0.33f; + + int xWraps = Mth::floor(xo / 2048.0); + int zWraps = Mth::floor(zo / 2048.0); + xo -= xWraps * 2048; + zo -= zWraps * 2048; + + textures->loadAndBindTexture("environment/clouds.png"); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + Vec3 cc = level->getCloudColor(alpha); + float cr = cc.x; + float cg = cc.y; + float cb = cc.z; + + float uvScale = 1.0f / 256.0f; + float uo = (float)Mth::floor(xo) * uvScale; + float vo = (float)Mth::floor(zo) * uvScale; + + float xOffs = (float)(xo - Mth::floor(xo)); + float zOffs = (float)(zo - Mth::floor(zo)); + + int D = 8; + int radius = 3; + float e = 1.0f / 1024.0f; + + glPushMatrix(); + glScalef(ss, 1.0f, ss); + + for (int pass = 0; pass < 2; pass++) { + + if (pass == 0) glColorMask(false, false, false, false); + else glColorMask(true, true, true, true); + + for (int xPos = -radius + 1; xPos <= radius; xPos++) { + for (int zPos = -radius + 1; zPos <= radius; zPos++) { + t.begin(); + float xx = (float)(xPos * D); + float zz = (float)(zPos * D); + float xp = xx - xOffs; + float zp = zz - zOffs; + + + if (yy > -h - 1.0f) { + t.color(cr * 0.7f, cg * 0.7f, cb * 0.7f, 0.8f); + t.normal(0.0f, -1.0f, 0.0f); + t.vertexUV(xp + 0, yy + 0, zp + D, (xx + 0) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + D, yy + 0, zp + D, (xx + D) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + D, yy + 0, zp + 0, (xx + D) * uvScale + uo, (zz + 0) * uvScale + vo); + t.vertexUV(xp + 0, yy + 0, zp + 0, (xx + 0) * uvScale + uo, (zz + 0) * uvScale + vo); + } + + + if (yy <= h + 1.0f) { + t.color(cr, cg, cb, 0.8f); + t.normal(0.0f, 1.0f, 0.0f); + t.vertexUV(xp + 0, yy + h - e, zp + D, (xx + 0) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + D, yy + h - e, zp + D, (xx + D) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + D, yy + h - e, zp + 0, (xx + D) * uvScale + uo, (zz + 0) * uvScale + vo); + t.vertexUV(xp + 0, yy + h - e, zp + 0, (xx + 0) * uvScale + uo, (zz + 0) * uvScale + vo); + } + + t.color(cr * 0.9f, cg * 0.9f, cb * 0.9f, 0.8f); + + + if (xPos > -1) { + t.normal(-1.0f, 0.0f, 0.0f); + for (int i = 0; i < D; i++) { + t.vertexUV(xp + i + 0, yy + 0, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + i + 0, yy + h, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + i + 0, yy + h, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); + t.vertexUV(xp + i + 0, yy + 0, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); + } + } + if (xPos <= 1) { + t.normal(1.0f, 0.0f, 0.0f); + for (int i = 0; i < D; i++) { + t.vertexUV(xp + i + 1 - e, yy + 0, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + i + 1 - e, yy + h, zp + D, (xx + i + 0.5f) * uvScale + uo, (zz + D) * uvScale + vo); + t.vertexUV(xp + i + 1 - e, yy + h, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); + t.vertexUV(xp + i + 1 - e, yy + 0, zp + 0, (xx + i + 0.5f) * uvScale + uo, (zz + 0) * uvScale + vo); + } + } + + t.color(cr * 0.8f, cg * 0.8f, cb * 0.8f, 0.8f); + + + if (zPos > -1) { + t.normal(0.0f, 0.0f, -1.0f); + for (int i = 0; i < D; i++) { + t.vertexUV(xp + 0, yy + h, zp + i + 0, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + t.vertexUV(xp + D, yy + h, zp + i + 0, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + t.vertexUV(xp + D, yy + 0, zp + i + 0, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + t.vertexUV(xp + 0, yy + 0, zp + i + 0, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + } + } + if (zPos <= 1) { + t.normal(0.0f, 0.0f, 1.0f); + for (int i = 0; i < D; i++) { + t.vertexUV(xp + 0, yy + h, zp + i + 1 - e, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + t.vertexUV(xp + D, yy + h, zp + i + 1 - e, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + t.vertexUV(xp + D, yy + 0, zp + i + 1 - e, (xx + D) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + t.vertexUV(xp + 0, yy + 0, zp + i + 1 - e, (xx + 0) * uvScale + uo, (zz + i + 0.5f) * uvScale + vo); + } + } + t.endOverrideAndDraw(); + } + } + } + + glPopMatrix(); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glDisable(GL_BLEND); + glEnable(GL_CULL_FACE); } void LevelRenderer::playSound(const std::string& name, float x, float y, float z, float volume, float pitch) { // @todo: deny sounds here if sound is off (rather than waiting 'til SoundEngine) float dd = 16; - if (volume > 1) dd *= volume; - if (mc->cameraTargetPlayer->distanceToSqr(x, y, z) < dd * dd) { - mc->soundEngine->play(name, x, y, z, volume, pitch); - } + if (volume > 1) dd *= volume; + if (mc->cameraTargetPlayer != NULL && mc->cameraTargetPlayer->distanceToSqr(x, y, z) < dd * dd) { + mc->soundEngine->play(name, x, y, z, volume, pitch); + } } void LevelRenderer::addParticle(const std::string& name, float x, float y, float z, float xa, float ya, float za, int data) { + if (mc->cameraTargetPlayer != NULL) { + float xd = mc->cameraTargetPlayer->x - x; + float yd = mc->cameraTargetPlayer->y - y; + float zd = mc->cameraTargetPlayer->z - z; + float distanceSquared = xd * xd + yd * yd + zd * zd; - float xd = mc->cameraTargetPlayer->x - x; - float yd = mc->cameraTargetPlayer->y - y; - float zd = mc->cameraTargetPlayer->z - z; - float distanceSquared = xd * xd + yd * yd + zd * zd; + //Particle* p = NULL; + //if (name == "hugeexplosion") p = new HugeExplosionSeedParticle(level, x, y, z, xa, ya, za); + //else if (name == "largeexplode") p = new HugeExplosionParticle(textures, level, x, y, z, xa, ya, za); - //Particle* p = NULL; - //if (name == "hugeexplosion") p = new HugeExplosionSeedParticle(level, x, y, z, xa, ya, za); - //else if (name == "largeexplode") p = new HugeExplosionParticle(textures, level, x, y, z, xa, ya, za); + //if (p) { + // if (distanceSquared < 32 * 32) { + // mc->particleEngine->add(p); + // } else { delete p; } + // return; + //} - //if (p) { - // if (distanceSquared < 32 * 32) { - // mc->particleEngine->add(p); - // } else { delete p; } - // return; - //} + const float particleDistance = 16; + if (distanceSquared > particleDistance * particleDistance) return; - const float particleDistance = 16; - if (distanceSquared > particleDistance * particleDistance) return; + //static Stopwatch sw; + //sw.start(); - //static Stopwatch sw; - //sw.start(); + if (name == "bubble") mc->particleEngine->add(new BubbleParticle(level, x, y, z, xa, ya, za)); + else if (name == "crit") mc->particleEngine->add(new CritParticle2(level, x, y, z, xa, ya, za)); + else if (name == "smoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za)); + //else if (name == "note") mc->particleEngine->add(new NoteParticle(level, x, y, z, xa, ya, za)); + else if (name == "explode") mc->particleEngine->add(new ExplodeParticle(level, x, y, z, xa, ya, za)); + else if (name == "flame") mc->particleEngine->add(new FlameParticle(level, x, y, z, xa, ya, za)); + else if (name == "lava") mc->particleEngine->add(new LavaParticle(level, x, y, z)); + //else if (name == "splash") mc->particleEngine->add(new SplashParticle(level, x, y, z, xa, ya, za)); + else if (name == "largesmoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f)); + else if (name == "reddust") mc->particleEngine->add(new RedDustParticle(level, x, y, z, xa, ya, za)); + else if (name == "iconcrack") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data])); + else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); + //else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); + //else if (name == "slime") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::slimeBall)); + //else if (name == "heart") mc->particleEngine->add(new HeartParticle(level, x, y, z, xa, ya, za)); - if (name == "bubble") mc->particleEngine->add(new BubbleParticle(level, x, y, z, xa, ya, za)); - else if (name == "crit") mc->particleEngine->add(new CritParticle2(level, x, y, z, xa, ya, za)); - else if (name == "smoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za)); - //else if (name == "note") mc->particleEngine->add(new NoteParticle(level, x, y, z, xa, ya, za)); - else if (name == "explode") mc->particleEngine->add(new ExplodeParticle(level, x, y, z, xa, ya, za)); - else if (name == "flame") mc->particleEngine->add(new FlameParticle(level, x, y, z, xa, ya, za)); - else if (name == "lava") mc->particleEngine->add(new LavaParticle(level, x, y, z)); - //else if (name == "splash") mc->particleEngine->add(new SplashParticle(level, x, y, z, xa, ya, za)); - else if (name == "largesmoke") mc->particleEngine->add(new SmokeParticle(level, x, y, z, xa, ya, za, 2.5f)); - else if (name == "reddust") mc->particleEngine->add(new RedDustParticle(level, x, y, z, xa, ya, za)); - else if (name == "iconcrack") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, xa, ya, za, Item::items[data])); - else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); - //else if (name == "snowballpoof") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::snowBall)); - //else if (name == "slime") mc->particleEngine->add(new BreakingItemParticle(level, x, y, z, Item::slimeBall)); - //else if (name == "heart") mc->particleEngine->add(new HeartParticle(level, x, y, z, xa, ya, za)); - - //sw.stop(); - //sw.printEvery(50, "add-particle-string"); + //sw.stop(); + //sw.printEvery(50, "add-particle-string"); + } } /* diff --git a/src/client/renderer/entity/PlayerRenderer.cpp b/src/client/renderer/entity/PlayerRenderer.cpp index 13b2b3f..092b9dc 100755 --- a/src/client/renderer/entity/PlayerRenderer.cpp +++ b/src/client/renderer/entity/PlayerRenderer.cpp @@ -77,10 +77,10 @@ void PlayerRenderer::render(Entity* mob_, float x, float y, float z, float rot, model = desired; humanoidModel = desired; } -// LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n", // don't log it always, only for debug - shredder -// ((Player*)mob)->name.c_str(), mob->getTexture().c_str(), -// humanoidModel->texWidth, humanoidModel->texHeight, -// (desired == playerModel64 ? "64" : "32")); + /* LOGI("[PlayerRenderer] %s: skin=%s, modelTex=%dx%d, desired=%s\n", + ((Player*)mob)->name.c_str(), mob->getTexture().c_str(), + humanoidModel->texWidth, humanoidModel->texHeight, + (desired == playerModel64 ? "64" : "32")); */ HumanoidMobRenderer::render(mob_, x, y, z, rot, a); } diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp new file mode 100644 index 0000000..187267c --- /dev/null +++ b/src/commands/Command.cpp @@ -0,0 +1,10 @@ +#include "Command.hpp" +#include "world/level/Level.h" +#include + +bool Command::isPlayerOp(Minecraft& mc, Player& player) { + std::string nicknameLower = player.name; + std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower); + + return mc.level->ops.find(nicknameLower) != mc.level->ops.end(); +} \ No newline at end of file diff --git a/src/commands/Command.hpp b/src/commands/Command.hpp new file mode 100644 index 0000000..fb3fdd0 --- /dev/null +++ b/src/commands/Command.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +enum CommandFlags { + COMMAND_FLAG_SINGLEPLAYER_ONLY = (1 << 1), + COMMAND_FLAG_NO_ARGS = (1 << 2), +}; + +class Minecraft; +class Player; + +class Command { +public: + const std::string& getName() { return m_name; } + const CommandFlags getFlags() { return m_flags; } + + bool isPlayerOp(Minecraft& mc, Player& player); + + virtual std::string execute(Minecraft& mc, Player& player, const std::vector& args) = 0; + virtual std::string help(Minecraft& mc) = 0; + +protected: + Command(const std::string& name, CommandFlags flags = (CommandFlags)0) : m_name(name), m_flags(flags) {} + + const std::string m_name; + const CommandFlags m_flags; +}; \ No newline at end of file diff --git a/src/commands/CommandBan.cpp b/src/commands/CommandBan.cpp new file mode 100644 index 0000000..0373d5b --- /dev/null +++ b/src/commands/CommandBan.cpp @@ -0,0 +1,52 @@ +#include "CommandBan.hpp" +#include "commands/Command.hpp" +#include "network/RakNetInstance.h" +#include "raknet/RakPeerInterface.h" +#include "world/level/Level.h" +#include +#include + +CommandBan::CommandBan() : Command("ban") {} + +std::string CommandBan::execute(Minecraft& mc, Player& player, const std::vector& args) { + if (!isPlayerOp(mc, player)) { + return "You aren't enough priveleged to run this command"; + } + + if (args.empty()) { + return help(mc); + } + + std::string nicknameLower = args[0]; + std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower); + + auto it = std::find_if(mc.level->players.begin(), mc.level->players.end(), [args, nicknameLower] (auto& it) -> bool { + std::string lower = it->name; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + + return lower == nicknameLower; + }); + + if (*it == (Player*)mc.player) { + return "ban: you can't ban urself lol"; + } + + if (it != mc.level->players.end()) { + mc.level->removePlayer(*it); + (*it)->remove(); + mc.raknetInstance->getPeer()->CloseConnection((*it)->owner, true); + } else { + for (auto& banned : mc.level->bannedPpl) { + if (nicknameLower == banned) { + return args[0] + "already banned!"; + } + } + } + + mc.level->bannedPpl.insert(nicknameLower); + return "ban: successfully banned player " + args[0]; +} + +std::string CommandBan::help(Minecraft& mc) { + return "Usage: /ban "; +} \ No newline at end of file diff --git a/src/commands/CommandBan.hpp b/src/commands/CommandBan.hpp new file mode 100644 index 0000000..b688800 --- /dev/null +++ b/src/commands/CommandBan.hpp @@ -0,0 +1,9 @@ +#include "Command.hpp" + +class CommandBan : public Command { +public: + CommandBan(); + + std::string execute(Minecraft& mc, Player& player, const std::vector& args); + std::string help(Minecraft& mc); +}; \ No newline at end of file diff --git a/src/commands/CommandHelp.cpp b/src/commands/CommandHelp.cpp new file mode 100644 index 0000000..9f09da4 --- /dev/null +++ b/src/commands/CommandHelp.cpp @@ -0,0 +1,35 @@ +#include "CommandHelp.hpp" +#include "commands/Command.hpp" +#include "CommandManager.hpp" +#include +#include + +CommandHelp::CommandHelp() : Command("help") {} + +std::string CommandHelp::execute(Minecraft& mc, Player& player, const std::vector& args) { + if (args.empty()) { + auto cmds = mc.commandManager().getListAllCommands(); + + std::ostringstream output; + + output << "List of all commands:" << std::endl; + + for (auto& cmd : cmds) { + output << " - " + cmd << std::endl;; + } + + return output.str(); + } + + Command* cmd = mc.commandManager().getCommand(args[0]); + + if (cmd != nullptr) { + return cmd->help(mc); + } + + return "help: command " + args[0] + " not found"; +} + +std::string CommandHelp::help(Minecraft& mc) { + return "Usage: /help "; +} \ No newline at end of file diff --git a/src/commands/CommandHelp.hpp b/src/commands/CommandHelp.hpp new file mode 100644 index 0000000..4c2349a --- /dev/null +++ b/src/commands/CommandHelp.hpp @@ -0,0 +1,9 @@ +#include "Command.hpp" + +class CommandHelp : public Command { +public: + CommandHelp(); + + std::string execute(Minecraft& mc, Player& player, const std::vector& args); + std::string help(Minecraft& mc); +}; \ No newline at end of file diff --git a/src/commands/CommandKick.cpp b/src/commands/CommandKick.cpp new file mode 100644 index 0000000..b876d9a --- /dev/null +++ b/src/commands/CommandKick.cpp @@ -0,0 +1,46 @@ +#include "CommandKick.hpp" +#include "commands/Command.hpp" +#include "network/RakNetInstance.h" +#include "raknet/RakPeerInterface.h" +#include "world/level/Level.h" +#include +#include + +CommandKick::CommandKick() : Command("kick") {} + +std::string CommandKick::execute(Minecraft& mc, Player& player, const std::vector& args) { + if (!isPlayerOp(mc, player)) { + return "You aren't enough priveleged to run this command"; + } + + if (args.empty()) { + return help(mc); + } + + std::string nicknameLower = args[0]; + std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower); + + auto it = std::find_if(mc.level->players.begin(), mc.level->players.end(), [args, nicknameLower] (auto& it) -> bool { + std::string lower = it->name; + std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); + + return lower == nicknameLower; + }); + + if (it == mc.level->players.end()) { + return "kick: can't find player with name " + args[0]; + } + + if (*it == (Player*)mc.player) { + return "kick: you can't kick urself lol"; + } + + mc.level->removePlayer(*it); + (*it)->remove(); + mc.raknetInstance->getPeer()->CloseConnection((*it)->owner, true); + return "kick: successfully kicked player " + args[0]; +} + +std::string CommandKick::help(Minecraft& mc) { + return "Usage: /kick "; +} \ No newline at end of file diff --git a/src/commands/CommandKick.hpp b/src/commands/CommandKick.hpp new file mode 100644 index 0000000..5b94819 --- /dev/null +++ b/src/commands/CommandKick.hpp @@ -0,0 +1,9 @@ +#include "Command.hpp" + +class CommandKick : public Command { +public: + CommandKick(); + + std::string execute(Minecraft& mc, Player& player, const std::vector& args); + std::string help(Minecraft& mc); +}; \ No newline at end of file diff --git a/src/commands/CommandManager.cpp b/src/commands/CommandManager.cpp new file mode 100644 index 0000000..fbb9324 --- /dev/null +++ b/src/commands/CommandManager.cpp @@ -0,0 +1,75 @@ +#include "CommandManager.hpp" +#include +#include +#include +#include "client/Minecraft.h" +#include "commands/Command.hpp" +#include "commands/CommandHelp.hpp" +#include "commands/CommandKick.hpp" +#include "commands/CommandOp.hpp" +#include "commands/CommandBan.hpp" +#include "network/packet/ChatPacket.h" +#include "network/RakNetInstance.h" +#include "world/level/Level.h" + +CommandManager::CommandManager() { + registerAllCommands(); +} + +void CommandManager::registerAllCommands() { + m_commands.push_back(new CommandHelp()); + m_commands.push_back(new CommandKick()); + m_commands.push_back(new CommandOp()); + m_commands.push_back(new CommandBan()); +} + +std::vector CommandManager::getListAllCommands() { + std::vector ret; + + for (auto& cmd : m_commands) { + ret.push_back(cmd->getName()); + } + + return ret; +} + +std::string CommandManager::execute(Minecraft& mc, Player& player, const std::string& input) { + std::istringstream ss(input); + std::string cmd; + + ss >> cmd; + + auto it = std::find_if(m_commands.begin(), m_commands.end(), [cmd](auto& it) -> bool { + return it->getName() == cmd; + }); + + if (it == m_commands.end()) { + return "Command /" + cmd + " not found"; + } + + std::vector args; + + std::string tok; + while (ss >> tok) args.push_back(tok); + + if (!mc.level->isClientSide || (*it)->getFlags() & CommandFlags::COMMAND_FLAG_SINGLEPLAYER_ONLY) { + return (*it)->execute(mc, player, args); + } else { + ChatPacket packet("/" + input); + mc.raknetInstance->send(packet); + } + + return ""; +} + +Command* CommandManager::getCommand(const std::string& name) { + auto it = std::find_if(m_commands.begin(), m_commands.end(), [name](auto& it) -> bool { + return it->getName() == name; + }); + + if (it == m_commands.end()) { + return *it; + } + + return nullptr; +} \ No newline at end of file diff --git a/src/commands/CommandManager.hpp b/src/commands/CommandManager.hpp new file mode 100644 index 0000000..c33b363 --- /dev/null +++ b/src/commands/CommandManager.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include + +#include "Command.hpp" + +class CommandManager { +public: + CommandManager(); + + std::vector getListAllCommands(); + + std::string execute(Minecraft& mc, Player& player, const std::string& input); + + Command* getCommand(const std::string& name); + +private: + void registerAllCommands(); + + std::vector m_commands; +}; \ No newline at end of file diff --git a/src/commands/CommandOp.cpp b/src/commands/CommandOp.cpp new file mode 100644 index 0000000..7fc2c30 --- /dev/null +++ b/src/commands/CommandOp.cpp @@ -0,0 +1,31 @@ +#include "CommandOp.hpp" +#include "commands/Command.hpp" +#include "world/level/Level.h" +#include +#include + +CommandOp::CommandOp() : Command("op") {} + +std::string CommandOp::execute(Minecraft& mc, Player& player, const std::vector& args) { + if (!isPlayerOp(mc, player)) { + return "You aren't enough priveleged to run this command"; + } + + if (args.empty()) { + return help(mc); + } + + std::string nicknameLower = args[0]; + std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower); + + if (mc.level->ops.find(nicknameLower) != mc.level->ops.end()) { + return "op: player " + args[0] + " already opped"; + } + + mc.level->ops.emplace(nicknameLower); + return "op: successfully opped player " + args[0]; +} + +std::string CommandOp::help(Minecraft& mc) { + return "Usage: /op "; +} \ No newline at end of file diff --git a/src/commands/CommandOp.hpp b/src/commands/CommandOp.hpp new file mode 100644 index 0000000..e91eea9 --- /dev/null +++ b/src/commands/CommandOp.hpp @@ -0,0 +1,9 @@ +#include "Command.hpp" + +class CommandOp : public Command { +public: + CommandOp(); + + std::string execute(Minecraft& mc, Player& player, const std::vector& args); + std::string help(Minecraft& mc); +}; \ No newline at end of file diff --git a/src/main_dedicated.cpp b/src/main_dedicated.cpp index 8aa14cb..fcf14ce 100755 --- a/src/main_dedicated.cpp +++ b/src/main_dedicated.cpp @@ -1,16 +1,20 @@ +#include #include #include "NinecraftApp.h" #include "AppPlatform.h" #include #include #include +#ifdef __linux__ #include +#endif #include "world/level/LevelSettings.h" #include "world/level/Level.h" #include "server/ArgumentsSettings.h" #include "platform/time.h" #include "SharedConstants.h" +#include "world/level/LevelConstants.h" #define MAIN_CLASS NinecraftApp static App* g_app = 0; @@ -27,36 +31,175 @@ void signal_callback_handler(int signum) { } } -int main(int numArguments, char* pszArgs[]) { - ArgumentsSettings aSettings(numArguments, pszArgs); - if(aSettings.getShowHelp()) { - ArgumentsSettings defaultSettings(0, NULL); - printf("Minecraft Pockect Edition Server %s\n", Common::getGameVersionString("").c_str()); - printf("-------------------------------------------------------\n"); - printf("--cachepath - Path to where the server can store temp stuff (not sure if this is used) [default: \"%s\"]\n", defaultSettings.getCachePath().c_str()); - printf("--externalpath - The path to the place where the server should store the levels. [default: \"%s\"]\n", defaultSettings.getExternalPath().c_str()); - printf("--levelname - The name of the server [default: \"%s\"]\n", defaultSettings.getLevelName().c_str()); - printf("--leveldir - The name of the server [default: \"%s\"]\n", defaultSettings.getLevelDir().c_str()); - printf("--help - Shows this message.\n"); - printf("--port - The port to run the server on. [default: %d]\n", defaultSettings.getPort()); - printf("--serverkey - The key that the server should use for API calls. [default: \"%s\"]\n", defaultSettings.getServerKey().c_str()); - printf("-------------------------------------------------------\n"); - return 0; +std::string findStringInConfig(std::string line, std::string config) { + auto valuePos = config.find(line); + + if (line.empty()) { + throw std::runtime_error("Key cannot be empty"); + } + + if (valuePos == std::string::npos) { + throw std::runtime_error("Cannot find value"); + } + + std::string valueStr = ""; + + valuePos += 1 + line.size(); + + while (true) { + auto sym = config.at(valuePos); + + if (sym == '\n') { + break; + } + + if (valuePos == config.size()) { + throw std::runtime_error("Cannot find end of the line"); + } + + valueStr += sym; + valuePos++; + } + + return valueStr; +} + + +int main(int numArguments, char* pszArgs[]) { + std::ifstream serverProperties("server.properties"); + + int port = 0; + int gamemode = 0; + int worldSize = 0; + + std::string levelDir = ""; + std::string cachePath = ""; + std::string externalPath = ""; + std::string levelName = ""; + + if (serverProperties.is_open()) { + std::string propString; + std::string line; + + while (std::getline(serverProperties, line)) { + propString += line; + propString += "\n"; + } + + if (propString.empty()) { + throw std::runtime_error("Config cannot be empty"); + } + + port = std::stoi(findStringInConfig("port", propString)); + worldSize = std::stoi(findStringInConfig("world-size", propString)); + + if (worldSize < 16 || worldSize > 32) { + throw std::runtime_error("Incorrect world size."); + } + + LevelConstants::CHUNK_CACHE_WIDTH = worldSize; + LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH; + LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH; + + cachePath = findStringInConfig("level-cachepath", propString); + externalPath = findStringInConfig("level-externalpath", propString); + levelName = findStringInConfig("level-name", propString); + levelDir = findStringInConfig("level-dir", propString); + + std::string gamemodeStr = findStringInConfig("gamemode", propString); + + if (gamemodeStr == "survival") { + gamemode = GameType::Survival; + } else if (gamemodeStr == "creative") { + gamemode = GameType::Creative; + } else { + gamemode = GameType::Survival; + } + + printf("%d %s %s %d %d\n", port, cachePath.c_str(), externalPath.c_str(), gamemode, LevelConstants::CHUNK_CACHE_WIDTH); + } else { + std::ofstream defaultProperties("server.properties"); + + if (defaultProperties.is_open()) { + ArgumentsSettings defaultSettings(0, NULL); + + std::stringstream buffer; + + buffer << "// MCPE Server properties" << std::endl; + buffer << "port=" << defaultSettings.getPort() << std::endl; + buffer << "level-dir=" << defaultSettings.getLevelDir() << std::endl; + buffer << "level-cachepath=" << defaultSettings.getCachePath() << std::endl; + buffer << "level-externalpath=" << defaultSettings.getExternalPath() << std::endl; + buffer << "gamemode=survival" << std::endl; + buffer << "level-name=" << defaultSettings.getLevelName() << std::endl; + buffer << "world-size=16" << std::endl; + + defaultProperties << buffer.str(); + + printf("%s \n", buffer.str().c_str()); + + printf("Edit a config file first!\n"); + + defaultProperties.close(); + exit(0); + } else { + throw std::runtime_error("Cannot create default config."); + } } - printf("Level Name: %s\n", aSettings.getLevelName().c_str()); + + printf("Level Name: %s\n", levelName.c_str()); + AppContext appContext; appContext.platform = new AppPlatform(); App* app = new MAIN_CLASS(); signal(SIGINT, signal_callback_handler); g_app = app; - ((MAIN_CLASS*)g_app)->externalStoragePath = aSettings.getExternalPath(); - ((MAIN_CLASS*)g_app)->externalCacheStoragePath = aSettings.getCachePath(); + ((MAIN_CLASS*)g_app)->externalStoragePath = externalPath; + ((MAIN_CLASS*)g_app)->externalCacheStoragePath = cachePath; g_app->init(appContext); - LevelSettings settings(getEpochTimeS(), GameType::Creative); + LevelSettings settings(getEpochTimeS(), gamemode); float startTime = getTimeS(); - ((MAIN_CLASS*)g_app)->selectLevel(aSettings.getLevelDir(), aSettings.getLevelName(), settings); - ((MAIN_CLASS*)g_app)->hostMultiplayer(aSettings.getPort()); + ((MAIN_CLASS*)g_app)->selectLevel(levelDir, levelName, settings); + ((MAIN_CLASS*)g_app)->hostMultiplayer(port); + + // Reading ops + std::ifstream ops("ops.txt"); + + if (ops.is_open()) { + std::string line; + + while (std::getline(ops, line)) { + if (!line.empty()) { + ((MAIN_CLASS*)g_app)->level->ops.insert(line); + } + } + } else { + std::ofstream opsDefault("ops.txt"); + + if (!opsDefault.is_open()) { + throw std::runtime_error("Cannot create ops list."); + } + } + + // Reading banned ppl + std::ifstream banned("banned-players.txt"); + + if (banned.is_open()) { + std::string line; + + while (std::getline(banned, line)) { + if (!line.empty()) { + ((MAIN_CLASS*)g_app)->level->bannedPpl.insert(line); + } + } + } else { + std::ofstream bannedPpl("banned-players.txt"); + + if (!bannedPpl.is_open()) { + throw std::runtime_error("Cannot create banned players list."); + } + } std::cout << "Level has been generated in " << getTimeS() - startTime << std::endl; ((MAIN_CLASS*)g_app)->level->saveLevelData(); @@ -67,7 +210,31 @@ int main(int numArguments, char* pszArgs[]) { //pthread_yield(); sleepMs(20); } + + std::ofstream opsWrite("ops.txt"); + + if (opsWrite.is_open()) { + for (auto& op : ((MAIN_CLASS*)g_app)->level->ops) { + opsWrite << op << std::endl; + } + opsWrite.close(); + } else { + throw std::runtime_error("Cannot open ops list."); + } + + std::ofstream bannedWrite("banned-players.txt"); + + if (bannedWrite.is_open()) { + for (auto& banned : ((MAIN_CLASS*)g_app)->level->bannedPpl) { + bannedWrite << banned << std::endl; + } + bannedWrite.close(); + } else { + throw std::runtime_error("Cannot open banned players list."); + } + ((MAIN_CLASS*)g_app)->level->saveLevelData(); + delete app; appContext.platform->finish(); delete appContext.platform; diff --git a/src/network/ClientSideNetworkHandler.cpp b/src/network/ClientSideNetworkHandler.cpp index d754b47..022b35f 100755 --- a/src/network/ClientSideNetworkHandler.cpp +++ b/src/network/ClientSideNetworkHandler.cpp @@ -1,6 +1,7 @@ #include "ClientSideNetworkHandler.h" #include "client/Options.h" +#include "network/packet/LoginStatusPacket.h" #include "packet/PacketInclude.h" #include "RakNetInstance.h" #include "../world/level/chunk/ChunkSource.h" @@ -10,6 +11,9 @@ #include "../world/entity/player/Inventory.h" #include "../client/Minecraft.h" #include "../client/gamemode/GameMode.h" +#include "world/item/ItemInstance.h" +#include "world/level/LevelConstants.h" +#include #ifndef STANDALONE_SERVER #include "../client/gui/screens/DisconnectionScreen.h" #endif @@ -42,6 +46,9 @@ ClientSideNetworkHandler::ClientSideNetworkHandler(Minecraft* minecraft, IRakNet requestNextChunkPosition(0), requestNextChunkIndex(0) { + NumRequestChunks = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH; + requestNextChunkIndexList.resize(NumRequestChunks); + chunksLoaded.resize(NumRequestChunks); rakPeer = raknetInstance->getPeer(); } @@ -59,7 +66,7 @@ void ClientSideNetworkHandler::requestNextChunk() //LOGI("requesting chunks @ (%d, %d)\n", chunk.x, chunk.y); - //raknetInstance->send(new RequestChunkPacket(requestNextChunkPosition % CHUNK_CACHE_WIDTH, requestNextChunkPosition / CHUNK_CACHE_WIDTH)); + //raknetInstance->send(new RequestChunkPacket(requestNextChunkPosition % LevelConstants::CHUNK_CACHE_WIDTH, requestNextChunkPosition / LevelConstants::CHUNK_CACHE_WIDTH)); requestNextChunkIndex++; requestNextChunkPosition++; } @@ -67,16 +74,16 @@ void ClientSideNetworkHandler::requestNextChunk() bool ClientSideNetworkHandler::areAllChunksLoaded() { - return (requestNextChunkPosition >= (CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH)); + return (requestNextChunkPosition >= (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH)); } bool ClientSideNetworkHandler::isChunkLoaded(int x, int z) { - if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH) { + if (x < 0 || x >= LevelConstants::CHUNK_CACHE_WIDTH || z < 0 || z >= LevelConstants::CHUNK_CACHE_WIDTH) { LOGE("Error: Tried to request chunk (%d, %d)\n", x, z); return true; } - return chunksLoaded[x * CHUNK_CACHE_WIDTH + z]; + return chunksLoaded[x * LevelConstants::CHUNK_CACHE_WIDTH + z]; //return areAllChunksLoaded(); } @@ -86,7 +93,7 @@ void ClientSideNetworkHandler::onConnect(const RakNet::RakNetGUID& hostGuid) serverGuid = hostGuid; clearChunksLoaded(); - LoginPacket packet(minecraft->options.getStringValue(OPTIONS_USERNAME).c_str(), SharedConstants::NetworkProtocolVersion); + LoginPacket packet(minecraft->options.getStringValue(OPTIONS_USERNAME).c_str(), SharedConstants::NetworkProtocolVersion, true); raknetInstance->send(packet); } @@ -97,6 +104,11 @@ void ClientSideNetworkHandler::onUnableToConnect() void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) { + LevelConstants::CHUNK_CACHE_WIDTH = 16; + LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH; + LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH; + + // TODO: Good disconnecting LOGI("onDisconnect\n"); if (level) { @@ -109,9 +121,13 @@ void ClientSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) } } } -#ifndef STANDALONE_SERVER - minecraft->gui.addMessage("Disconnected from server"); -#endif + minecraft->leaveGame(); +// minecraft->setLevel(NULL); +// #ifndef STANDALONE_SERVER +// minecraft->gui.addMessage("Disconnected from server"); +// // TODO: screen with error +// minecraft->screenChooser.setScreen(SCREEN_STARTMENU); +// #endif } void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginStatusPacket* packet) { @@ -130,6 +146,18 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginSta LOGI("Disconnect! Server is outdated!\n"); #ifndef STANDALONE_SERVER minecraft->setScreen(new DisconnectionScreen("Could not connect: Outdated server!")); +#endif + } + if (packet->status == LoginStatus::Failed_TakenNickname) { + LOGI("Disconnect! Nickname is taken!\n"); +#ifndef STANDALONE_SERVER + minecraft->setScreen(new DisconnectionScreen("Could not connect: Nickname is taken!")); +#endif + } + if (packet->status == LoginStatus::Failed_Banned) { + LOGI("Disconnect! You're banned from this server!\n"); +#ifndef STANDALONE_SERVER + minecraft->setScreen(new DisconnectionScreen("Could not connect: You're banned from this server!")); #endif } } @@ -146,6 +174,19 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, StartGam } #endif + // @todo @note i think its trash + // we can put it directly to selectLevel? + if (packet->chunkCacheWidth != 0) { + printf("lol \n"); + LevelConstants::CHUNK_CACHE_WIDTH = packet->chunkCacheWidth; + LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH; + LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH; + LevelChunk::ChunkBlockCount = LevelConstants::CHUNK_BLOCK_COUNT; + } + NumRequestChunks = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH; + requestNextChunkIndexList.resize(NumRequestChunks); + chunksLoaded.resize(NumRequestChunks); + const std::string& levelId = LevelStorageSource::TempLevelId; LevelStorageSource* storageSource = minecraft->getLevelSource(); storageSource->deleteLevel(levelId); @@ -182,7 +223,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetTimeP if (!level) return; - LOGI("SetTimePacket\n"); + // LOGI("SetTimePacket\n"); level->setTime(packet->time); } @@ -238,7 +279,7 @@ void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, AddPain } void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddMobPacket* packet) { - LOGI("AddMobPacket (%p)\n", level); + // LOGI("AddMobPacket (%p)\n", level); if (!level) { LOGW("Trying to add a mob with no level!\n"); @@ -324,7 +365,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveEn if (!level) return; Entity* entity = level->getEntity(packet->entityId); - LOGI("RemoveEntityPacket %p %p, %d\n", entity, minecraft->player, entity?(int)(entity->isPlayer()): -1); + // LOGI("RemoveEntityPacket %p %p, %d\n", entity, minecraft->player, entity?(int)(entity->isPlayer()): -1); if (!entity) return; level->removeEntity(entity); @@ -344,6 +385,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AddItemE } void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemEntityPacket* packet) { + // printf("TakeItemEntityPacket \n"); if (!level) return; Entity* e = level->getEntity(packet->itemId); @@ -386,6 +428,54 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlay } } +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SendInventoryPacket* packet) { + if (!level) return; + + if (packet->entityId == minecraft->player->entityId) { + auto items = packet->items; + + minecraft->player->inventory->replace(items); + + for (int i = 0; i < packet->linkedSlot.size(); i++) { + minecraft->player->inventory->linkSlot(i, packet->linkedSlot[i].inventorySlot, true); + LOGI("%i -> %i\n", packet->linkedSlot[i].inventorySlot, i); + } + } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, TakeItemPacket* packet) { + if (!level) return; + + LOGI("TakeItemPacket\n"); + + ItemInstance* item; + + item->count = packet->count; + item->id = packet->itemId; + item->setAuxValue(packet->auxValue); + + // if (minecraft->player->entityId == packet->playerId) { + if (!minecraft->player->inventory->add(item)) { + minecraft->player->drop(new ItemInstance(*item), false); + } + // } +} + +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveItemPacket* packet) { + // Idk how it works... + if (!level) return; + + ItemInstance item; + + item.count = packet->count; + item.id = packet->itemId; + item.setAuxValue(packet->auxValue); + + // if (minecraft->player->entityId == packet->playerId) { + minecraft->player->inventory->removeResource(item); + // } +} + void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MoveEntityPacket* packet) { if (!level) @@ -475,19 +565,19 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat //unsigned char* blockIds = chunk->getBlockData(); DataLayer& blockData = chunk->data; - const int setSize = LEVEL_HEIGHT / 8; - const int setShift = 4; // power of LEVEL_HEIGHT / 8 + const int setSize = LevelConstants::LEVEL_HEIGHT / 8; + const int setShift = 4; // power of LevelConstants::LEVEL_HEIGHT / 8 bool recalcHeight = false; - int x0 = 16, x1 = 0, z0 = 16, z1 = 0, y0 = LEVEL_HEIGHT, y1 = 0; + int x0 = 16, x1 = 0, z0 = 16, z1 = 0, y0 = LevelConstants::LEVEL_HEIGHT, y1 = 0; int rx = packet->x << 4; int rz = packet->z << 4; - unsigned char readBlockBuffer[setSize]; - unsigned char readDataBuffer[setSize / 2]; + unsigned char* readBlockBuffer = new unsigned char[setSize]; + unsigned char* readDataBuffer = new unsigned char[setSize / 2]; - for (int i = 0; i < CHUNK_COLUMNS; i++) + for (int i = 0; i < LevelConstants::CHUNK_COLUMNS; i++) { unsigned char updateBits = 0; packet->chunkData.Read(updateBits); @@ -496,8 +586,8 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat { recalcHeight = true; - int colX = (i % CHUNK_WIDTH); - int colZ = (i / CHUNK_WIDTH); + int colX = (i % LevelConstants::CHUNK_WIDTH); + int colZ = (i / LevelConstants::CHUNK_WIDTH); int colDataPosition = colX << 11 | colZ << 7; for (int set = 0; set < 8; set++) @@ -531,30 +621,33 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat { y0 = ((1 << set) << setShift); } - if (((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1 > y1) + if (((1 << set) << setShift) + (LevelConstants::LEVEL_HEIGHT / 8) - 1 > y1) { - y1 = ((1 << set) << setShift) + (LEVEL_HEIGHT / 8) - 1; + y1 = ((1 << set) << setShift) + (LevelConstants::LEVEL_HEIGHT / 8) - 1; } } - if ((i % CHUNK_WIDTH) < x0) + if ((i % LevelConstants::CHUNK_WIDTH) < x0) { - x0 = (i % CHUNK_WIDTH); + x0 = (i % LevelConstants::CHUNK_WIDTH); } - if ((i % CHUNK_WIDTH) > x1) + if ((i % LevelConstants::CHUNK_WIDTH) > x1) { - x1 = (i % CHUNK_WIDTH); + x1 = (i % LevelConstants::CHUNK_WIDTH); } - if ((i / CHUNK_WIDTH) < z0) + if ((i / LevelConstants::CHUNK_WIDTH) < z0) { - z0 = (i / CHUNK_WIDTH); + z0 = (i / LevelConstants::CHUNK_WIDTH); } - if ((i / CHUNK_WIDTH) > z1) + if ((i / LevelConstants::CHUNK_WIDTH) > z1) { - z1 = (i / CHUNK_WIDTH); + z1 = (i / LevelConstants::CHUNK_WIDTH); } } } + delete[] readBlockBuffer; + delete[] readDataBuffer; + if (recalcHeight) { // chunk->recalcHeightmap(); @@ -579,7 +672,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChunkDat //chunk->terrainPopulated = true; chunk->unsaved = false; - chunksLoaded[packet->x * CHUNK_CACHE_WIDTH + packet->z] = true; + chunksLoaded[packet->x * LevelConstants::CHUNK_CACHE_WIDTH + packet->z] = true; if (areAllChunksLoaded()) { @@ -627,18 +720,18 @@ void ClientSideNetworkHandler::arrangeRequestChunkOrder() { clearChunksLoaded(); // Default sort is around center of the world - int cx = CHUNK_CACHE_WIDTH / 2; - int cz = CHUNK_CACHE_WIDTH / 2; + int cx = LevelConstants::CHUNK_CACHE_WIDTH / 2; + int cz = LevelConstants::CHUNK_CACHE_WIDTH / 2; // If player exists, let's sort around him Player* p = minecraft? minecraft->player : NULL; if (p) { - cx = Mth::floor(p->x / (float)CHUNK_WIDTH); - cz = Mth::floor(p->z / (float)CHUNK_DEPTH); + cx = Mth::floor(p->x / (float)LevelConstants::CHUNK_WIDTH); + cz = Mth::floor(p->z / (float)LevelConstants::CHUNK_DEPTH); } _ChunkSorter sorter(cx, cz); - std::sort(requestNextChunkIndexList, requestNextChunkIndexList + NumRequestChunks, sorter); + std::sort(requestNextChunkIndexList.begin(), requestNextChunkIndexList.end(), sorter); } void ClientSideNetworkHandler::levelGenerated(Level* level) @@ -728,7 +821,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetEntit if (!level) return; - LOGI("SetEntityDataPacket\n"); + // LOGI("SetEntityDataPacket\n"); Entity* e = level->getEntity(packet->id); if (e) { @@ -782,6 +875,10 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimateP } } +void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet) +{ +} + void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) { } @@ -791,6 +888,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, SetHealt if (!level || !minecraft->player) return; + printf("SetHealthPacket \n"); minecraft->player->hurtTo(packet->health); } @@ -886,7 +984,11 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe void ClientSideNetworkHandler::handle( const RakNet::RakNetGUID& source, ChatPacket* packet ) { #ifndef STANDALONE_SERVER - minecraft->gui.displayClientMessage(packet->message); + // minecraft->gui.displayClientMessage(packet->message); + std::istringstream iss(packet->message); + for (std::string line; std::getline(iss, line); ) { + minecraft->gui.addMessage(line); + } #endif } @@ -919,8 +1021,8 @@ void ClientSideNetworkHandler::clearChunksLoaded() { // Init the chunk positions for (int i = 0; i < NumRequestChunks; ++i) { - requestNextChunkIndexList[i].x = i/CHUNK_WIDTH; - requestNextChunkIndexList[i].y = i%CHUNK_WIDTH; + requestNextChunkIndexList[i].x = i / LevelConstants::CHUNK_WIDTH; + requestNextChunkIndexList[i].y = i % LevelConstants::CHUNK_WIDTH; chunksLoaded[i] = false; } } diff --git a/src/network/ClientSideNetworkHandler.h b/src/network/ClientSideNetworkHandler.h index 1505ec7..57e0d81 100755 --- a/src/network/ClientSideNetworkHandler.h +++ b/src/network/ClientSideNetworkHandler.h @@ -77,6 +77,11 @@ public: virtual void handle(const RakNet::RakNetGUID& source, ChatPacket* packet); virtual void handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet); virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet); + virtual void handle(const RakNet::RakNetGUID& source, RemoveItemPacket* packet); + virtual void handle(const RakNet::RakNetGUID& source, TakeItemPacket* packet); + virtual void handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet); + virtual void handle(const RakNet::RakNetGUID& source, SendInventoryPacket* packet); + private: void requestNextChunk(); @@ -97,11 +102,11 @@ private: BlockUpdateList bufferedBlockUpdates; int requestNextChunkPosition; - static const int NumRequestChunks = CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; + int NumRequestChunks; int requestNextChunkIndex; - IntPair requestNextChunkIndexList[NumRequestChunks]; - bool chunksLoaded[NumRequestChunks]; + std::vector requestNextChunkIndexList; + std::vector chunksLoaded; }; #endif diff --git a/src/network/NATPunchHandler.cpp b/src/network/NATPunchHandler.cpp deleted file mode 100755 index 35108b0..0000000 --- a/src/network/NATPunchHandler.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "NATPunchHandler.h" -#include "../raknet/TCPInterface.h" -#include "../raknet/HTTPConnection.h" -#include "PHPDirectoryServer2.h" - -using namespace RakNet; -NATPuchHandler::NATPuchHandler() { - tcpInterface = new TCPInterface; -} -NATPuchHandler::~NATPuchHandler() { - delete tcpInterface; -} - -void NATPuchHandler::initialize() { - tcpInterface->Start(0, 64); -} - -void NATPuchHandler::registerToGameList(const RakNet::RakString& serverName, int port) { - HTTPConnection httpConnection; - httpConnection.Init(tcpInterface, "johanbernhardsson.se"); - PHPDirectoryServer2 directoryServer; - directoryServer.Init(&httpConnection, "/DirectoryServer.php"); - directoryServer.UploadTable("", serverName, port, true); -} - -void NATPuchHandler::removeFromGameList() { - -} - -void NATPuchHandler::close() { - -} - diff --git a/src/network/NATPunchHandler.h b/src/network/NATPunchHandler.h deleted file mode 100755 index 0246c0d..0000000 --- a/src/network/NATPunchHandler.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _MINECRAFT_NETWORK_NATPUNCHHANDLER_H_ -#define _MINECRAFT_NETWORK_NATPUNCHHANDLER_H_ -#include "../raknet/TCPInterface.h" -#include "../raknet/RakString.h" -class NATPuchHandler { -public: - enum NATPuchHandlerStatus { - NATPuchInitilized = 0, - NATPuchFetchingServerList = 1, - NATPuchConnecting = 2, - NATPuchConnected = 3, - NATPuchDissconnected = 4 - }; - NATPuchHandler(); - ~NATPuchHandler(); - void initialize(); - void registerToGameList(const RakNet::RakString& serverName, int port); - void removeFromGameList(); - void close(); -private: - RakNet::TCPInterface *tcpInterface; -}; - -#endif /* _MINECRAFT_NETWORK_NATPUNCHHANDLER_H_ */ diff --git a/src/network/NetEventCallback.h b/src/network/NetEventCallback.h index 53e5fa4..db3e22b 100755 --- a/src/network/NetEventCallback.h +++ b/src/network/NetEventCallback.h @@ -18,6 +18,8 @@ class RemovePlayerPacket; class RemoveEntityPacket; class MoveEntityPacket; //class TeleportEntityPacket; +class RemoveItemPacket; +class TakeItemPacket; class MovePlayerPacket; class PlaceBlockPacket; class RemoveBlockPacket; @@ -48,6 +50,7 @@ class ContainerClosePacket; class ContainerSetSlotPacket; class ContainerSetDataPacket; class ContainerSetContentPacket; +class WantCreatePacket; class ChatPacket; class SignUpdatePacket; class Minecraft; @@ -119,6 +122,9 @@ public: virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet) {} virtual void handle(const RakNet::RakNetGUID& source, AdventureSettingsPacket* packet) {} virtual void handle(const RakNet::RakNetGUID& source, AnimatePacket* packet) {} + virtual void handle(const RakNet::RakNetGUID& source, RemoveItemPacket* packet) {} + virtual void handle(const RakNet::RakNetGUID& source, TakeItemPacket* packet) {} + virtual void handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet) {} // // Common implementation for Client and Server diff --git a/src/network/Packet.cpp b/src/network/Packet.cpp index ca1b328..d060356 100755 --- a/src/network/Packet.cpp +++ b/src/network/Packet.cpp @@ -2,6 +2,7 @@ #include "Packet.h" #include "../world/level/chunk/LevelChunk.h" +#include "network/packet/TakeItemPacket.h" #include "packet/PacketInclude.h" Packet::Packet() @@ -41,10 +42,16 @@ Packet* MinecraftPackets::createPacket(int id) case PACKET_ADDITEMENTITY: packet = new AddItemEntityPacket(); break; + case PACKET_REMOVEITEM: + packet = new RemoveItemPacket(); + break; + case PACKET_TAKEITEM: + packet = new TakeItemPacket(); + break; case PACKET_TAKEITEMENTITY: packet = new TakeItemEntityPacket(); break; - case PACKET_ADDMOB: + case PACKET_ADDMOB: packet = new AddMobPacket(); break; case PACKET_ADDPLAYER: @@ -68,6 +75,9 @@ Packet* MinecraftPackets::createPacket(int id) case PACKET_RESPAWN: packet = new RespawnPacket(); break; + case PACKET_WANTCREATEITEM: + packet = new WantCreatePacket(); + break; case PACKET_REMOVEENTITY: packet = new RemoveEntityPacket(); break; diff --git a/src/network/Packet.h b/src/network/Packet.h index e872219..3525bd4 100755 --- a/src/network/Packet.h +++ b/src/network/Packet.h @@ -33,7 +33,10 @@ enum MinecraftPacketIds PACKET_REMOVEENTITY, PACKET_ADDITEMENTITY, PACKET_TAKEITEMENTITY, - + PACKET_TAKEITEM, + PACKET_REMOVEITEM, + PACKET_WANTCREATEITEM, + PACKET_MOVEENTITY, PACKET_MOVEENTITY_POS, PACKET_MOVEENTITY_ROT, diff --git a/src/network/ServerSideNetworkHandler.cpp b/src/network/ServerSideNetworkHandler.cpp index 7736908..474d9ad 100755 --- a/src/network/ServerSideNetworkHandler.cpp +++ b/src/network/ServerSideNetworkHandler.cpp @@ -5,6 +5,16 @@ #include "../world/entity/player/Inventory.h" #include "../world/Container.h" #include "../world/inventory/BaseContainerMenu.h" +#include "network/packet/ChatPacket.h" +#include "network/packet/ContainerSetSlotPacket.h" +#include "network/packet/LoginStatusPacket.h" +#include "network/packet/MovePlayerPacket.h" +#include "network/packet/RemoveBlockPacket.h" +#include "network/packet/SendInventoryPacket.h" +#include "network/packet/UpdateBlockPacket.h" +#include "network/packet/RemoveItemPacket.h" +#include "network/packet/TakeItemPacket.h" +#include "network/packet/WantCreatePacket.h" #include "packet/PacketInclude.h" #include "RakNetInstance.h" @@ -13,6 +23,17 @@ #include "../client/gamemode/GameMode.h" #include "../raknet/RakPeerInterface.h" #include "../raknet/PacketPriority.h" +#include "platform/log.h" +#include "util/Mth.h" +#include "util/StringUtils.h" +#include "world/item/ItemInstance.h" +#include "world/level/LevelConstants.h" +#include "world/level/storage/LevelStorage.h" +#include "world/phys/Vec3.h" +#include "world/item/crafting/Recipe.h" +#include "world/item/crafting/Recipes.h" +#include +#include #ifndef STANDALONE_SERVER #include "../client/sound/SoundEngine.h" #endif @@ -53,11 +74,11 @@ void ServerSideNetworkHandler::tileChanged(int x, int y, int z) Packet* ServerSideNetworkHandler::getAddPacketFromEntity( Entity* entity ) { if (entity->isMob() && !entity->isPlayer()) { //@fix: This code is duplicated. See if it can be unified. - if (minecraft->player) { + // if (minecraft->player) { // I guess this should always be true, but it crashed somewhere in this // function once and I only see this one as a potential problem return new AddMobPacket((Mob*)entity); - } + // } } else if (entity->isPlayer()) { @@ -136,7 +157,18 @@ void ServerSideNetworkHandler::displayGameMessage(const std::string& message) void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ChatPacket* packet) { - displayGameMessage(packet->message); + auto player = getPlayer(source); + + if (player == nullptr) return; // @todo maybe kick? + + if (packet->message[0] == '/') { + // This is a command + + ChatPacket resp(minecraft->commandManager().execute(*minecraft, *player, Util::stringTrim(packet->message.substr(1)))); + return sendPrivate(resp, source); + } + + displayGameMessage("<" + player->name + "> " + packet->message); } void ServerSideNetworkHandler::onNewClient(const RakNet::RakNetGUID& clientGuid) @@ -156,6 +188,8 @@ void ServerSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) if (player->owner == guid) { + minecraft->level->getLevelStorage()->savePlayer(*player); + std::string message = player->name; message += " disconnected from the game"; displayGameMessage(message); @@ -179,15 +213,39 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPac if (!_allowIncoming) return; LOGI("LoginPacket\n"); - + int loginStatus = LoginStatus::Success; // // Bad/incompatible client version // bool oldClient = packet->clientNetworkVersion < SharedConstants::NetworkProtocolLowestSupportedVersion; bool oldServer = packet->clientNetworkLowestSupportedVersion > SharedConstants::NetworkProtocolVersion; - if (oldClient || oldServer) - loginStatus = oldClient? LoginStatus::Failed_ClientOld : LoginStatus::Failed_ServerOld; + if (oldClient || oldServer || !packet->newProto) + loginStatus = oldClient || !packet->newProto? LoginStatus::Failed_ClientOld : LoginStatus::Failed_ServerOld; + + std::string nicknameLower = packet->clientName.C_String(); + std::transform(nicknameLower.begin(), nicknameLower.end(), nicknameLower.begin(), ::tolower); + + printf("%s lower \n", nicknameLower.c_str()); + for (int i = 0; i < level->players.size(); i++) { + ServerPlayer* player = (ServerPlayer*) level->players.at(i); + + std::string clientLower = player->name; + std::transform(clientLower.begin(), clientLower.end(), clientLower.begin(), ::tolower); + + // @todo to lower case + if (nicknameLower == clientLower) { + loginStatus = packet->newProto ? LoginStatus::Failed_TakenNickname : LoginStatus::Failed_ClientOld; + break; + } + } + + for (auto& banned : level->bannedPpl) { + if (nicknameLower == banned) { + loginStatus = packet->newProto ? LoginStatus::Failed_Banned : LoginStatus::Failed_ClientOld; + break; + } + } RakNet::BitStream bitStream; LoginStatusPacket(loginStatus).write(&bitStream); @@ -199,13 +257,16 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPac // // Valid client version // - Player* newPlayer = new ServerPlayer(minecraft, level); - + + Player* newPlayer = new ServerPlayer(minecraft, level, packet->newProto); + minecraft->gameMode->initAbilities(newPlayer->abilities); newPlayer->owner = source; newPlayer->name = packet->clientName.C_String(); _pendingPlayers.push_back(newPlayer); + LOGI("Adding new player... isCreative: %i\n", minecraft->isCreativeMode()); + // Reset the player so he doesn't spawn inside blocks while (newPlayer->y > 0) { newPlayer->setPos(newPlayer->x, newPlayer->y, newPlayer->z); @@ -228,7 +289,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, LoginPac level->getLevelData()->getGeneratorVersion(), gameType, newPlayer->entityId, - newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z + newPlayer->x, newPlayer->y - newPlayer->heightOffset, newPlayer->z, + LevelConstants::CHUNK_CACHE_WIDTH ).write(&bitStream); rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); @@ -244,6 +306,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ReadyPac if (packet->type == ReadyPacket::READY_REQUESTEDCHUNKS) onReady_RequestedChunks(source); + + LOGI("Ready player two ready ready player two!!\n "); } void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID& source) @@ -301,6 +365,36 @@ void ServerSideNetworkHandler::onReady_ClientGeneration(const RakNet::RakNetGUID } } + if (!minecraft->level->getLevelStorage()->loadPlayer(*newPlayer)) { + LOGW("Failed to load %s data\n", newPlayer->name.c_str()); + } + + // Credits to EpikIzCool + bitStream.Reset(); + MovePlayerPacket mv(newPlayer->entityId, newPlayer->x, newPlayer->y - newPlayer->heightOffset, + newPlayer->z, newPlayer->xRot, newPlayer->yRot); + mv.write(&bitStream); + + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + bitStream.Reset(); + SetHealthPacket hp(newPlayer->health); + hp.write(&bitStream); + + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + if (newPlayer->hasRespawnPosition()) { + bitStream.Reset(); + SetSpawnPositionPacket sp(newPlayer->getRespawnPosition()); + sp.write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + } + + bitStream.Reset(); + SendInventoryPacket(newPlayer, false).write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); + + // Additional packets // * set spawn /* @@ -338,15 +432,32 @@ void ServerSideNetworkHandler::onReady_RequestedChunks(const RakNet::RakNetGUID& void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, MovePlayerPacket* packet) { if (!level) return; + + // LOGI("MovePlayerPacket\n"); + if (Entity* entity = level->getEntity(packet->entityId)) { + ServerPlayer* player = (ServerPlayer*) getPlayer(source); - //LOGI("MovePlayerPacket\n"); - if (Entity* entity = level->getEntity(packet->entityId)) - { - entity->xd = entity->yd = entity->zd = 0; + // int timeElapsed = minecraft->getTicks() - player->getLastMoveTicks(); + + // if (timeElapsed > 0) { + // float dist = player->distanceTo(packet->x, player->y, packet->z); + // float speed = dist / (minecraft->getTicks() - player->getLastMoveTicks()); + // player->setLastMoveTicks(minecraft->getTicks()); + + // float maxSpeed = (minecraft->isCreativeMode()) ? 1.65f : 1.f; + + // if (speed > maxSpeed) { + // MovePlayerPacket refuse(player->entityId, player->x, player->y, player->z, player->xRot, player->yRot); + // return raknetInstance->send(refuse); + // } + // } + + entity->xd = entity->yd = entity->zd = 0; entity->lerpTo(packet->x, packet->y, packet->z, packet->yRot, packet->xRot, 3); - + // broadcast this packet to other clients redistributePacket(packet, source); + } } @@ -368,12 +479,29 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RemoveBl if (oldTile != NULL && changed) { level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, oldTile->soundType->getBreakSound(), (oldTile->soundType->getVolume() + 1) / 2, oldTile->soundType->getPitch() * 0.8f); - if (minecraft->gameMode->isSurvivalType() && player->canDestroy(oldTile)) - //oldTile->spawnResources(level, x, y, z, data, 1); //@todo + if (minecraft->gameMode->isSurvivalType() && player->canDestroy(oldTile)) { + // From SurvivalMode.cpp + // Why tf i have to copy this shit from SurvivalMode class + // Why SurvivalMode class locked to LOCAL MINECRAFT PLAYER :sob: :sob: :sob: :sob: :sob: :sob: :sob: :sob: + // @fix @warn @ahtung @alert + ItemInstance* item = player->inventory->getSelected(); + if (item != NULL) { + item->mineBlock(oldTile->id, x, y, z); + if (item->count == 0) { + //item->snap(minecraft->player); + player->inventory->clearSlot(player->inventory->selected); + } + } + + // oldTile->spawnResources(level, x, y, z, data, 1); //@todo oldTile->playerDestroy(level, player, x, y, z, data); + } + oldTile->destroy(level, x, y, z, data); } + + LOGI("Remove block [%i, %i, %i]\n", packet->x, packet->y, packet->z); } void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestChunkPacket* packet) @@ -403,6 +531,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, RequestC raknetInstance->send(source, p); } } + + // LOGI("Requested chunk [%i, %i]\n", packet->x, packet->z); } void ServerSideNetworkHandler::levelGenerated( Level* level ) @@ -429,23 +559,31 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerEq if (!player) return; if (rakPeer->GetMyGUID() == player->owner) return; + LOGI("Equip item: id %i aux %i\n", packet->itemId, packet->itemAuxValue); + // override the player's inventory - //int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); - int slot = Inventory::MAX_SELECTION_SIZE; - if (slot >= 0) { - if (packet->itemId == 0) { - player->inventory->clearSlot(slot); - } else { - // @note: 128 is an ugly hack for depletable items. - // @todo: fix - ItemInstance newItem(packet->itemId, 128, packet->itemAuxValue); - player->inventory->replaceSlot(slot, &newItem); - } - player->inventory->moveToSelectedSlot(slot, true); - redistributePacket(packet, source); - } else { - LOGW("Warning: Remote player doesn't have his thing, Odd!\n"); + int slot = player->inventory->getSlot(packet->itemId, packet->itemAuxValue); + + if (slot >= 0 && slot != packet->inventorySlot && packet->itemId != 0) { + LOGW("PlayerEquipmentPacket: Item in player inventory but slots doesn't match!"); + packet->inventorySlot = slot; } + + if (slot < 0 && packet->itemId != 0) { + LOGW("PlayerEquipmentPacket: Remote player doesn't have his thing (or crafted it)!\n"); + + SendInventoryPacket newInventory (player, false); + raknetInstance->send(newInventory); + + return; + } + + player->inventory->selectSlot(packet->selectedSlot); + player->inventory->linkSlot(packet->selectedSlot, packet->inventorySlot, true); + + player->inventory->print(); + + redistributePacket(packet, source); } void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerArmorEquipmentPacket* packet) { @@ -455,6 +593,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, PlayerAr if (!player) return; if (rakPeer->GetMyGUID() == player->owner) return; + // LOGI("Equip armor: %i %i %i %i\n", packet->head, packet->torso, packet->legs, packet->feet); + packet->fillIn(player); redistributePacket(packet, source); } @@ -466,6 +606,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Interact Entity* entity = level->getEntity(packet->targetId); if (src && entity && src->isPlayer()) { + LOGI("Interact: source %i target %i\n", packet->sourceId, packet->targetId); + Player* player = (Player*) src; if (InteractPacket::Attack == packet->action) { player->swing(); @@ -506,14 +648,75 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, AnimateP } redistributePacket(packet, source); } +void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet) { + LOGI("WantCreatePacket\n"); + Entity* entity = level->getEntity(packet->playerId); + + if (entity && entity->isPlayer()) { + Player* p = (Player*)entity; + + auto playerInv = p->inventory; + + ItemInstance wantCreate; + + wantCreate.id = packet->itemId; + wantCreate.count = packet->count; + wantCreate.setAuxValue(packet->auxValue); + + Recipe* recipe = Recipes::getInstance()->getRecipeFor(wantCreate); + + std::vector items = recipe->getItemPack().getItemInstances(); + + std::vector checkForExists = {}; + + for (int i = Inventory::MAX_SELECTION_SIZE; i < p->inventory->getContainerSize(); ++i) { + auto itm = p->inventory->getItem(i); + + if (itm != NULL) { + for (int y = 0; y < items.size(); y++) { + auto itmRecipe = items.at(y); + + if (itmRecipe.id == itm->id && itm->count >= itmRecipe.count) { + checkForExists.push_back(itm->id); + } + } + } + } + + if (checkForExists.empty()) { + return; + } + + for (int i = 0; i < items.size(); i++) { + auto item = items.at(i); + + auto it = std::find(checkForExists.begin(), checkForExists.end(), item.id); + + if (it == checkForExists.end() && checkForExists.size() > 1) { + return; + } + } + + for (int i = 0; i < items.size(); i++) { + p->inventory->removeResource(ItemInstance(items.at(i).id, items.at(i).count, items.at(i).getAuxValue())); + } + // TakeItemPacket itemAdd(p->entityId, wantCreate.count, wantCreate.getAuxValue(), wantCreate.id); + // raknetInstance->send(source, itemAdd); + + p->inventory->add(new ItemInstance(wantCreate.id, wantCreate.count, wantCreate.getAuxValue())); + } +} void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemPacket* packet) { if (!level) return; - LOGI("UseItemPacket\n"); + LOGI("UseItemPacket: id %i data %i\n", packet->itemId, packet->itemData); Entity* entity = level->getEntity(packet->entityId); + if (entity && entity->isPlayer()) { + LOGI("%f %f %f \n", entity->x, entity->y, entity->z); + Player* player = (Player*) entity; int x = packet->x, y = packet->y, z = packet->z; Tile* t = Tile::tiles[level->getTile(x, y, z)]; @@ -522,7 +725,41 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemP if (t && t->use(level, x, y, z, player)) return; if (packet->item.isNull()) return; - ItemInstance* item = &packet->item; + ItemInstance* packetItem = &packet->item; + + int slot = player->inventory->getSlot(packet->itemId, packet->itemData); + + if (slot < 0) { + LOGW("UseItemPacket: Player doesn't have this item!\n"); + + auto pos = Vec3(packet->x, packet->y, packet->z); + + if (ItemInstance::isBlock(packetItem)) { + LOGI("UseItemPacket: This is even block!!!\n"); + + pos.x += packet->clickX; + pos.y += packet->clickY; + pos.z += packet->clickZ; + } + + UpdateBlockPacket refuse(pos.x, pos.y, pos.z, level->getTile(pos.x, pos.y, pos.z), level->getData(pos.x, pos.y, pos.z)); + raknetInstance->send(refuse); + + return; + } + + ItemInstance* item = player->inventory->getItem(slot); + player->x = packet->playerX; + player->y = packet->playerY; + player->z = packet->playerZ; + + player->bb.x0 = packet->playerX0; + player->bb.y0 = packet->playerY0; + player->bb.z0 = packet->playerZ0; + + player->bb.x1 = packet->playerX1; + player->bb.y1 = packet->playerY1; + player->bb.z1 = packet->playerZ1; if(packet->face == 255) { // Special case: x,y,z means direction-of-action @@ -533,6 +770,10 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemP minecraft->gameMode->useItemOn(player, level, item, packet->x, packet->y, packet->z, packet->face, Vec3(packet->clickX + packet->x, packet->clickY + packet->y, packet->clickZ + packet->z)); } + + if (item && item->count <= 0) { + player->inventory->clearSlot(slot); + } //LOGW("Use Item not working! Out of synch?\n"); @@ -544,6 +785,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, UseItemP void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, EntityEventPacket* packet) { if (!level) return; + LOGI("EntityEventPacket: id %i\n", packet->eventId); + if (Entity* e = level->getEntity(packet->entityId)) e->handleEntityEvent(packet->eventId); } @@ -577,6 +820,11 @@ void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SendInv { if (!level) return; + LOGI("SendInventoryPacket:\n"); + for (int i = 0; i < packet->numItems; i++) { + LOGI("\t %i: %s (%i)\n", i, packet->items.at(i).getName().c_str(), packet->items.at(i).count); + } + Entity* entity = level->getEntity(packet->entityId); if (entity && entity->isPlayer()) { Player* p = (Player*)entity; @@ -592,15 +840,27 @@ void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, DropIte { if (!level) return; + LOGI("DropItemPacket\n"); + Entity* entity = level->getEntity(packet->entityId); if (entity && entity->isPlayer()) { Player* p = (Player*)entity; - p->drop(new ItemInstance(packet->item), packet->dropType != 0); + // p->drop(new ItemInstance(packet->item), packet->dropType != 0); + + int slot = p->inventory->getSlot(packet->item.id, packet->item.getAuxValue()); + + if (slot < 0) { + LOGW("DropItemPacket: player doesn't have these items!\n"); + return; + } + + p->inventory->dropSlot(slot, false, packet->dropType != 0); } } void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet) { if (!level) return; + LOGI("ContainerClosePacket\n"); Player* p = findPlayer(level, &source); if (!p) return; @@ -612,6 +872,16 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, ContainerSetSlotPacket* packet) { if (!level) return; + const char* type = "unknown"; + + switch (packet->setType) { + case ContainerSetSlotPacket::SETTYPE_ADD: type = "add"; break; + case ContainerSetSlotPacket::SETTYPE_SET: type = "set"; break; + case ContainerSetSlotPacket::SETTYPE_TAKE: type = "take"; break; + }; + + LOGI("ContainerSetSlot: slot %i item %s type %s\n", packet->slot, packet->item.getName().c_str(), type); + Player* p = findPlayer(level, &source); if (!p) return; @@ -619,11 +889,79 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe LOGW("User has no container!\n"); return; } - if (p->containerMenu->containerId != packet->containerId) - { + + if (p->containerMenu->containerId != packet->containerId) { LOGW("Wrong container id: %d vs %d\n", p->containerMenu->containerId, packet->containerId); return; } + + if (packet->item.count > 64) { + LOGW("ContainerSetSlotPacket: player tried to put more than 64"); + return; + } + + auto contItems = p->containerMenu->getItems(); + + // find same item in player inventory (used not in all cases) + int invSlot = p->inventory->getSlot(packet->item.id, packet->item.getAuxValue()); + auto invItem = p->inventory->getItem(invSlot); + + if (contItems.at(packet->slot).id == 0 && packet->item.id != 0) { + LOGI("ContainerSetSlotPacket: player tried to put items to slot %i\n", packet->slot); + + if (invSlot < 0) { + LOGW("ContainerSetSlotPacket: player doesn't have this item\n"); + return; + } + + if (invItem->count < packet->item.count) { + LOGW("ContainerSetSlotPacket: player tried to put more than he have\n"); + packet->item.count = invItem->count; + } + + invItem->count -= packet->item.count; + + if (invItem->count <= 0) { + p->inventory->removeItem(invItem); + } + } else if(contItems.at(packet->slot).id == packet->item.id) { + int deltaItem = packet->item.count - contItems.at(packet->slot).count; + + if (deltaItem > 0) { + LOGI("ContainerSetSlotPacket: player tried to add %i items to slot %i\n", deltaItem, packet->slot); + + auto invItem = p->inventory->getItem(invSlot); + + if (invSlot < 0) { + LOGW("ContainerSetSlotPacket: player doesn't have this item\n"); + return; + } + + if (invItem->count < deltaItem) { + LOGW("ContainerSetSlotPacket: player tried to put more than he have"); + packet->item.count -= (deltaItem - invItem->count); + deltaItem = invItem->count; + } + + invItem->count -= deltaItem; + + if (invItem->count <= 0) { + p->inventory->removeItem(invItem); + } + } else if (deltaItem < 0) { + LOGW("ContainerSetSlotPacket: player tried to take %i items from slot %i\n", -deltaItem, packet->slot); + p->inventory->add(new ItemInstance(packet->item.getItem(), -deltaItem, contItems.at(packet->slot).getAuxValue())); + } + } else if(contItems.at(packet->slot).id && !packet->item.id) { + LOGI("ContainerSetSlotPacket: player tried to take all items from slot %i\n", packet->slot); + packet->item.count = 0; + packet->item.setAuxValue(0); + + p->inventory->add(new ItemInstance(contItems.at(packet->slot).getItem(), contItems.at(packet->slot).count, contItems.at(packet->slot).getAuxValue())); + } else { + LOGW("ContainerSetSlotPacket: illegal container operation in slot %i\n", packet->slot); + return; + } if (ContainerType::FURNACE == p->containerMenu->containerType) { //LOGI("Server:Setting slot %d: %s\n", packet->slot, packet->item.toString().c_str()); @@ -635,6 +973,8 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& source, Containe p->containerMenu->setSlot(packet->slot, &packet->item); //p->containerMenu->setSlot(packet->slot, packet->item.isNull()? NULL : &packet->item); } + + p->inventory->print(); } void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SetHealthPacket* packet ) @@ -657,6 +997,8 @@ void ServerSideNetworkHandler::handle( const RakNet::RakNetGUID& source, SignUpd if (!level) return; + LOGI("SignUpdate: [%i, %i, %i]\n", packet->x, packet->y, packet->z); + TileEntity* te = level->getTileEntity(packet->x, packet->y, packet->z); if (TileEntity::isType(te, TileEntityType::Sign)) { SignTileEntity* ste = (SignTileEntity*) te; @@ -713,3 +1055,9 @@ Player* ServerSideNetworkHandler::getPlayer( const RakNet::RakNetGUID& source ) if (source == level->players[i]->owner) return level->players[i]; return NULL; } + +void ServerSideNetworkHandler::sendPrivate(Packet& packet, const RakNet::RakNetGUID& source) { + RakNet::BitStream bitStream; + packet.write(&bitStream); + rakPeer->Send(&bitStream, HIGH_PRIORITY, RELIABLE_ORDERED, 0, source, false); +} \ No newline at end of file diff --git a/src/network/ServerSideNetworkHandler.h b/src/network/ServerSideNetworkHandler.h index 51531cf..1e9585d 100755 --- a/src/network/ServerSideNetworkHandler.h +++ b/src/network/ServerSideNetworkHandler.h @@ -58,7 +58,8 @@ public: virtual void handle(const RakNet::RakNetGUID& source, ContainerClosePacket* packet); virtual void handle(const RakNet::RakNetGUID& source, SignUpdatePacket* packet); virtual void handle(const RakNet::RakNetGUID& source, ChatPacket* packet); - + virtual void handle(const RakNet::RakNetGUID& source, WantCreatePacket* packet); + bool allowsIncomingConnections() { return _allowIncoming; } void allowIncomingConnections(bool doAllow); @@ -70,6 +71,12 @@ private: * @brief Send packet to all players */ void redistributePacket(Packet* packet, const RakNet::RakNetGUID& fromPlayer); + + /** + * @brief Send packer private with GUID + */ + void sendPrivate(Packet& packet, const RakNet::RakNetGUID& source); + Player* getPlayer(const RakNet::RakNetGUID& source); Minecraft* minecraft; diff --git a/src/network/command/CommandServer.cpp b/src/network/command/CommandServer.cpp index 14417c2..280b0a9 100755 --- a/src/network/command/CommandServer.cpp +++ b/src/network/command/CommandServer.cpp @@ -236,9 +236,9 @@ std::string CommandServer::parse(ConnectedClient& client, const std::string& s) if (x0 < 0) x0 = 0; if (y0 < 0) y0 = 0; if (z0 < 0) z0 = 0; - if (x1 >= LEVEL_WIDTH ) x1 = LEVEL_WIDTH - 1; - if (y1 >= LEVEL_HEIGHT) y1 = LEVEL_HEIGHT - 1; - if (z1 >= LEVEL_DEPTH ) z1 = LEVEL_DEPTH - 1; + if (x1 >= LevelConstants::LEVEL_WIDTH ) x1 = LevelConstants::LEVEL_WIDTH - 1; + if (y1 >= LevelConstants::LEVEL_HEIGHT) y1 = LevelConstants::LEVEL_HEIGHT - 1; + if (z1 >= LevelConstants::LEVEL_DEPTH ) z1 = LevelConstants::LEVEL_DEPTH - 1; for (int y = y0; y <= y1; ++y) for (int z = z0; z <= z1; ++z) @@ -456,7 +456,7 @@ std::string CommandServer::parse(ConnectedClient& client, const std::string& s) sw.start(); // Save a cuboid around the player - const int CSize = CHUNK_CACHE_WIDTH; + const int CSize = LevelConstants::CHUNK_CACHE_WIDTH; int cx = (int)e->x / CSize; int cz = (int)e->z / CSize; @@ -504,7 +504,7 @@ bool CommandServer::handleCheckpoint(bool doRestore ) { const int cz = restorePos.z; const int y0 = restorePos.y; const int y1 = y0 + RestoreHeight; - const int CSize = CHUNK_CACHE_WIDTH; + const int CSize = LevelConstants::CHUNK_CACHE_WIDTH; const int numChunkBytes = RestoreHeight * CSize * CSize * 20 / 8; if (!restoreBuffer) { diff --git a/src/network/packet/ChunkDataPacket.h b/src/network/packet/ChunkDataPacket.h index 51f1719..b272685 100755 --- a/src/network/packet/ChunkDataPacket.h +++ b/src/network/packet/ChunkDataPacket.h @@ -33,18 +33,18 @@ public: unsigned char* blockIds = chunk->getBlockData(); DataLayer& blockData = chunk->data; - const int setSize = LEVEL_HEIGHT / 8; - const int setShift = 4; // power of LEVEL_HEIGHT / 8 + const int setSize = LevelConstants::LEVEL_HEIGHT / 8; + const int setShift = 4; // power of LevelConstants::LEVEL_HEIGHT / 8 chunkData.Reset(); - for (int i = 0; i < CHUNK_COLUMNS; i++) + for (int i = 0; i < LevelConstants::CHUNK_COLUMNS; i++) { unsigned char updateBits = chunk->updateMap[i]; chunkData.Write(updateBits); if (updateBits > 0) { - int colDataPosition = (i % CHUNK_WIDTH) << 11 | (i / CHUNK_WIDTH) << 7; + int colDataPosition = (i % LevelConstants::CHUNK_WIDTH) << 11 | (i / LevelConstants::CHUNK_WIDTH) << 7; for (int set = 0; set < 8; set++) { diff --git a/src/network/packet/LoginPacket.h b/src/network/packet/LoginPacket.h index b44a44a..50caee3 100755 --- a/src/network/packet/LoginPacket.h +++ b/src/network/packet/LoginPacket.h @@ -9,17 +9,20 @@ public: RakNet::RakString clientName; int clientNetworkVersion; int clientNetworkLowestSupportedVersion; + bool newProto; LoginPacket() : clientNetworkVersion(-1), - clientNetworkLowestSupportedVersion(-1) + clientNetworkLowestSupportedVersion(-1), + newProto(false) { } - LoginPacket(const RakNet::RakString& clientName, int clientVersion) + LoginPacket(const RakNet::RakString& clientName, int clientVersion, bool newProto) : clientName(clientName), clientNetworkVersion(clientVersion), - clientNetworkLowestSupportedVersion(clientVersion) + clientNetworkLowestSupportedVersion(clientVersion), + newProto(newProto) { } @@ -29,6 +32,7 @@ public: bitStream->Write(clientName); bitStream->Write(clientNetworkVersion); bitStream->Write(clientNetworkLowestSupportedVersion); + bitStream->Write(newProto); } void read(RakNet::BitStream* bitStream) @@ -39,6 +43,11 @@ public: if (bitStream->GetNumberOfUnreadBits() > 0) { bitStream->Read(clientNetworkVersion); bitStream->Read(clientNetworkLowestSupportedVersion); + + // Checking for new proto + if (bitStream->GetNumberOfUnreadBits() > 0) { + bitStream->Read(newProto); + } } } diff --git a/src/network/packet/LoginStatusPacket.h b/src/network/packet/LoginStatusPacket.h index b194f8f..e2e0957 100755 --- a/src/network/packet/LoginStatusPacket.h +++ b/src/network/packet/LoginStatusPacket.h @@ -3,10 +3,13 @@ #include "../Packet.h" +// wtf why not enum namespace LoginStatus { const int Success = 0; const int Failed_ClientOld = 1; const int Failed_ServerOld = 2; + const int Failed_TakenNickname = 3; + const int Failed_Banned = 4; } class LoginStatusPacket : public Packet { diff --git a/src/network/packet/PacketInclude.h b/src/network/packet/PacketInclude.h index 09aeae8..ff884d2 100755 --- a/src/network/packet/PacketInclude.h +++ b/src/network/packet/PacketInclude.h @@ -50,5 +50,7 @@ #include "TileEventPacket.h" #include "UpdateBlockPacket.h" #include "UseItemPacket.h" - +#include "RemoveItemPacket.h" +#include "WantCreatePacket.h" +#include "TakeItemPacket.h" #endif /*NET_MINECRAFT_NETWORK_PACKET__PacketInclude_H__*/ diff --git a/src/network/packet/PlayerEquipmentPacket.h b/src/network/packet/PlayerEquipmentPacket.h index 5dfb315..b49974c 100755 --- a/src/network/packet/PlayerEquipmentPacket.h +++ b/src/network/packet/PlayerEquipmentPacket.h @@ -9,15 +9,19 @@ public: int entityId; unsigned short itemId; unsigned short itemAuxValue; + unsigned char selectedSlot; + unsigned char inventorySlot; PlayerEquipmentPacket() { } - PlayerEquipmentPacket(int entityId, int itemId, int data) + PlayerEquipmentPacket(int entityId, int itemId, int data, int selSlot, int invSlot) : entityId(entityId), itemId(itemId), - itemAuxValue(data) + itemAuxValue(data), + selectedSlot(selSlot), + inventorySlot(invSlot) { } @@ -28,6 +32,8 @@ public: bitStream->Write(entityId); bitStream->Write(itemId); bitStream->Write(itemAuxValue); + bitStream->Write(selectedSlot); + bitStream->Write(inventorySlot); } void read(RakNet::BitStream* bitStream) @@ -35,6 +41,8 @@ public: bitStream->Read(entityId); bitStream->Read(itemId); bitStream->Read(itemAuxValue); + bitStream->Read(selectedSlot); + bitStream->Read(inventorySlot); } void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) diff --git a/src/network/packet/RemoveItemPacket.h b/src/network/packet/RemoveItemPacket.h new file mode 100644 index 0000000..f4a1d0a --- /dev/null +++ b/src/network/packet/RemoveItemPacket.h @@ -0,0 +1,54 @@ +#ifndef NET_MINECRAFT_NETWORK_PACKET__RemoveItemPacket_H__ +#define NET_MINECRAFT_NETWORK_PACKET__RemoveItemPacket_H__ + +//package net.minecraft.network.packet; + +#include "../Packet.h" + +class RemoveItemPacket: public Packet +{ +public: + RemoveItemPacket() { + } + + RemoveItemPacket(int playerId, int count, int auxValue, int itemId) + : + playerId(playerId), + count(count), + auxValue(auxValue), + itemId(itemId) + { + } + + void write(RakNet::BitStream* bitStream) + { + bitStream->Write((RakNet::MessageID)(ID_USER_PACKET_ENUM + PACKET_REMOVEITEM)); + bitStream->Write(itemId); + bitStream->Write(count); + bitStream->Write(auxValue); + + bitStream->Write(playerId); + } + + void read(RakNet::BitStream* bitStream) + { + bitStream->Read(itemId); + bitStream->Read(count); + bitStream->Read(auxValue); + + bitStream->Read(playerId); + } + + void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) + { + callback->handle(source, (RemoveItemPacket*)this); + } + + int playerId; + + int itemId; + int count; + int auxValue; +}; + +#endif /*NET_MINECRAFT_NETWORK_PACKET__RemoveItemPacket_H__*/ diff --git a/src/network/packet/SendInventoryPacket.h b/src/network/packet/SendInventoryPacket.h index 65d12f4..b744b58 100755 --- a/src/network/packet/SendInventoryPacket.h +++ b/src/network/packet/SendInventoryPacket.h @@ -2,13 +2,14 @@ #define NET_MINECRAFT_NETWORK_PACKET__SendInventoryPacket_H__ #include "../Packet.h" +#include "world/entity/player/Inventory.h" +#include "world/inventory/FillingContainer.h" +#include class SendInventoryPacket: public Packet { public: - SendInventoryPacket() - { - } + SendInventoryPacket() {} SendInventoryPacket(Player* player, bool dropItems) : entityId(player->entityId), @@ -21,10 +22,15 @@ public: ItemInstance* item = inv->getItem(i); items.push_back(item? *item : ItemInstance()); } + for (int i = 0; i < NumArmorItems; ++i) { ItemInstance* item = player->getArmor(i); items.push_back(item? *item : ItemInstance()); } + + for (int i = 0; i < inv->numLinkedSlots; ++i) { + linkedSlot[i] = inv->linkedSlots[i]; + } } void write(RakNet::BitStream* bitStream) @@ -39,6 +45,13 @@ public: // Armor for (int i = 0; i < NumArmorItems; ++i) PacketUtil::writeItemInstance(items[i + numItems], bitStream); + + int lSlots = Inventory::MAX_SELECTION_SIZE; + + // Linked slots + bitStream->Write(lSlots); + for (int i = 0; i < lSlots; ++i) + bitStream->Write(linkedSlot[i]); } void read(RakNet::BitStream* bitStream) @@ -50,6 +63,12 @@ public: // Inventory, Armor for (int i = 0; i < numItems + NumArmorItems; ++i) items.push_back(PacketUtil::readItemInstance(bitStream)); + + // Linked slots + int lSlots = 0; + bitStream->Read(lSlots); + for (int i = 0; i < lSlots; ++i) + bitStream->Read(linkedSlot[i]); } void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) @@ -62,6 +81,8 @@ public: short numItems; unsigned char extra; + std::array linkedSlot; + static const int ExtraDrop = 1; static const int NumArmorItems = 4; }; diff --git a/src/network/packet/StartGamePacket.h b/src/network/packet/StartGamePacket.h index 24adead..f2ce50f 100755 --- a/src/network/packet/StartGamePacket.h +++ b/src/network/packet/StartGamePacket.h @@ -2,6 +2,7 @@ #define NET_MINECRAFT_NETWORK_PACKET__StartGamePacket_H__ #include "../Packet.h" +#include "world/level/LevelConstants.h" #include class StartGamePacket : public Packet @@ -14,18 +15,20 @@ public: int entityId; float x, y, z; + int chunkCacheWidth = 0; StartGamePacket() { } - StartGamePacket(long seed, int levelGeneratorVersion, int gameType, int entityId, float x, float y, float z) + StartGamePacket(long seed, int levelGeneratorVersion, int gameType, int entityId, float x, float y, float z, int chunkCacheWidth) : levelSeed((int32_t)seed), levelGeneratorVersion(levelGeneratorVersion), gameType(gameType), entityId(entityId), x(x), y(y), - z(z) + z(z), + chunkCacheWidth(chunkCacheWidth) { } @@ -40,6 +43,7 @@ public: bitStream->Write(x); bitStream->Write(y); bitStream->Write(z); + bitStream->Write(LevelConstants::CHUNK_CACHE_WIDTH); } void read(RakNet::BitStream* bitStream) @@ -51,6 +55,10 @@ public: bitStream->Read(x); bitStream->Read(y); bitStream->Read(z); + + if (bitStream->GetNumberOfUnreadBits() > 0) { + bitStream->Read(chunkCacheWidth); + } } void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) diff --git a/src/network/packet/TakeItemPacket.h b/src/network/packet/TakeItemPacket.h new file mode 100644 index 0000000..17eee0f --- /dev/null +++ b/src/network/packet/TakeItemPacket.h @@ -0,0 +1,54 @@ +#ifndef NET_MINECRAFT_NETWORK_PACKET__TakeItemPacket_H__ +#define NET_MINECRAFT_NETWORK_PACKET__TakeItemPacket_H__ + +//package net.minecraft.network.packet; + +#include "../Packet.h" + +class TakeItemPacket: public Packet +{ +public: + TakeItemPacket() { + } + + TakeItemPacket(int playerId, int count, int auxValue, int itemId) + : + playerId(playerId), + count(count), + auxValue(auxValue), + itemId(itemId) + { + } + + void write(RakNet::BitStream* bitStream) + { + bitStream->Write((RakNet::MessageID)(ID_USER_PACKET_ENUM + PACKET_TAKEITEM)); + bitStream->Write(itemId); + bitStream->Write(count); + bitStream->Write(auxValue); + + bitStream->Write(playerId); + } + + void read(RakNet::BitStream* bitStream) + { + bitStream->Read(itemId); + bitStream->Read(count); + bitStream->Read(auxValue); + + bitStream->Read(playerId); + } + + void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) + { + callback->handle(source, (TakeItemPacket*)this); + } + + int playerId; + + int itemId; + int count; + int auxValue; +}; + +#endif /*NET_MINECRAFT_NETWORK_PACKET__TakeItemPacket_H__*/ diff --git a/src/network/packet/UseItemPacket.h b/src/network/packet/UseItemPacket.h index e1583de..3f67c41 100755 --- a/src/network/packet/UseItemPacket.h +++ b/src/network/packet/UseItemPacket.h @@ -16,10 +16,14 @@ public: short itemId; unsigned char itemData; ItemInstance item; + float playerX, playerY, playerZ; + float playerX0, playerY0, playerZ0; + float playerX1, playerY1, playerZ1; UseItemPacket() {} - UseItemPacket(int x, int y, int z, int face, const ItemInstance* item, int entityId, float clickX, float clickY, float clickZ) + UseItemPacket(int x, int y, int z, int face, const ItemInstance* item, int entityId, float clickX, float clickY, float clickZ, + float plrX, float plrY, float plrZ, float plrX0, float plrY0, float plrZ0, float plrX1, float plrY1, float plrZ1) : x(x), y(y), z(z), @@ -29,17 +33,36 @@ public: entityId(entityId), clickX(clickX), clickY(clickY), - clickZ(clickZ) + clickZ(clickZ), + playerX(plrX), + playerY(plrY), + playerZ(plrZ), + playerX0(plrX0), + playerY0(plrY0), + playerZ0(plrZ0), + playerX1(plrX1), + playerY1(plrY1), + playerZ1(plrZ1) {} - UseItemPacket(const ItemInstance* item, int entityId, const Vec3& aim) + UseItemPacket(const ItemInstance* item, int entityId, const Vec3& aim, float plrX, float plrY, float plrZ, + float plrX0, float plrY0, float plrZ0, float plrX1, float plrY1, float plrZ1) : face(255), itemId(item? item->id : 0), itemData(item? item->getAuxValue() : 0), entityId(entityId), x((int)(aim.x * 32768.0f)), y((int)(aim.y * 32768.0f)), - z((int)(aim.z * 32768.0f)) + z((int)(aim.z * 32768.0f)), + playerX(plrX), + playerY(plrY), + playerZ(plrZ), + playerX0(plrX0), + playerY0(plrY0), + playerZ0(plrZ0), + playerX1(plrX1), + playerY1(plrY1), + playerZ1(plrZ1) { } @@ -57,6 +80,15 @@ public: bitStream->Write(clickX); bitStream->Write(clickY); bitStream->Write(clickZ); + bitStream->Write(playerX); + bitStream->Write(playerY); + bitStream->Write(playerZ); + bitStream->Write(playerX0); + bitStream->Write(playerY0); + bitStream->Write(playerZ0); + bitStream->Write(playerX1); + bitStream->Write(playerY1); + bitStream->Write(playerZ1); } void read(RakNet::BitStream* bitStream) @@ -74,7 +106,15 @@ public: item.id = itemId; item.setAuxValue(itemData); item.count = (itemId == 0 && itemData == 0)? 0 : 1; - + bitStream->Read(playerX); + bitStream->Read(playerY); + bitStream->Read(playerZ); + bitStream->Read(playerX0); + bitStream->Read(playerY0); + bitStream->Read(playerZ0); + bitStream->Read(playerX1); + bitStream->Read(playerY1); + bitStream->Read(playerZ1); } void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) diff --git a/src/network/packet/WantCreatePacket.h b/src/network/packet/WantCreatePacket.h new file mode 100644 index 0000000..48873c5 --- /dev/null +++ b/src/network/packet/WantCreatePacket.h @@ -0,0 +1,54 @@ +#ifndef NET_MINECRAFT_NETWORK_PACKET__WantCreatePacket_H__ +#define NET_MINECRAFT_NETWORK_PACKET__WantCreatePacket_H__ + +//package net.minecraft.network.packet; + +#include "../Packet.h" + +class WantCreatePacket: public Packet +{ +public: + WantCreatePacket() { + } + + WantCreatePacket(int playerId, int count, int auxValue, int itemId) + : + playerId(playerId), + count(count), + auxValue(auxValue), + itemId(itemId) + { + } + + void write(RakNet::BitStream* bitStream) + { + bitStream->Write((RakNet::MessageID)(ID_USER_PACKET_ENUM + PACKET_WANTCREATEITEM)); + bitStream->Write(itemId); + bitStream->Write(count); + bitStream->Write(auxValue); + + bitStream->Write(playerId); + } + + void read(RakNet::BitStream* bitStream) + { + bitStream->Read(itemId); + bitStream->Read(count); + bitStream->Read(auxValue); + + bitStream->Read(playerId); + } + + void handle(const RakNet::RakNetGUID& source, NetEventCallback* callback) + { + callback->handle(source, (WantCreatePacket*)this); + } + + int playerId; + + int itemId; + int count; + int auxValue; +}; + +#endif /*NET_MINECRAFT_NETWORK_PACKET__WantCreatePacket_H__*/ diff --git a/src/server/ArgumentsSettings.cpp b/src/server/ArgumentsSettings.cpp index 88bcd51..d41633c 100755 --- a/src/server/ArgumentsSettings.cpp +++ b/src/server/ArgumentsSettings.cpp @@ -17,6 +17,11 @@ ArgumentsSettings::ArgumentsSettings(int numArguments, char** arguments) levelName = std::string(arguments[a+1]); a++; // Skip the next argument since it's part of this one. } + } else if(strcmp(arguments[a], "--gamemode") == 0) { + if(a + 1 < numArguments) { + gamemode = std::string(arguments[a+1]); + a++; // Skip the next argument since it's part of this one. + } } else if(strcmp(arguments[a], "--leveldir") == 0) { if(a + 1 < numArguments) { levelDir = std::string(arguments[a+1]); @@ -51,6 +56,9 @@ std::string ArgumentsSettings::getServerKey() { std::string ArgumentsSettings::getCachePath() { return cachePath; } +std::string ArgumentsSettings::getGamemode() { + return gamemode; +} std::string ArgumentsSettings::getLevelDir() { return levelDir; } diff --git a/src/server/ArgumentsSettings.h b/src/server/ArgumentsSettings.h index 0dcd781..2861b48 100755 --- a/src/server/ArgumentsSettings.h +++ b/src/server/ArgumentsSettings.h @@ -4,20 +4,27 @@ class ArgumentsSettings { public: ArgumentsSettings(int numArguments, char** arguments); + std::string getExternalPath(); std::string getLevelName(); std::string getServerKey(); std::string getCachePath(); std::string getLevelDir(); + std::string getGamemode(); + bool getShowHelp(); + int getPort(); private: std::string cachePath; std::string externalPath; std::string levelName; + std::string gamemode; std::string levelDir; std::string serverKey; + bool showHelp; + int port; }; diff --git a/src/server/ServerLevel.cpp b/src/server/ServerLevel.cpp index e57d6b8..d65ee86 100755 --- a/src/server/ServerLevel.cpp +++ b/src/server/ServerLevel.cpp @@ -12,16 +12,19 @@ ServerLevel::ServerLevel(LevelStorage* levelStorage, const std::string& levelNam void ServerLevel::updateSleepingPlayerList() { bool allPlayersWasSleeping = allPlayersAreSleeping; allPlayersAreSleeping = !players.empty(); - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + + for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) { Player* player = *it; - if(!player->isSleeping()) { + + if (!player->isSleeping()) { allPlayersAreSleeping = false; break; } } - if(!allPlayersWasSleeping && allPlayersAreSleeping) { + if (!allPlayersWasSleeping && allPlayersAreSleeping) { levelEvent(NULL, LevelEvent::ALL_PLAYERS_SLEEPING, 0, 0, 0, 0); - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + + for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) { (*it)->setAllPlayersSleeping(); } } @@ -29,23 +32,26 @@ void ServerLevel::updateSleepingPlayerList() { void ServerLevel::awakenAllPlayers() { allPlayersAreSleeping = false; - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + + for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) { Player* player = *it; - if(player->isSleeping()) { + + if (player->isSleeping()) { player->stopSleepInBed(false, false, true); player->health = Player::MAX_HEALTH; player->lastHealth = Player::MAX_HEALTH; } } + SetHealthPacket packet(Player::MAX_HEALTH); raknetInstance->send(packet); } bool ServerLevel::allPlayersSleeping() { - if(allPlayersAreSleeping && !isClientSide) { + if (allPlayersAreSleeping && !isClientSide) { // all players are sleeping, but have they slept long enough? - for(PlayerList::iterator it = players.begin(); it != players.end(); ++it) { - if(!(*it)->isSleepingLongEnough()) { + for (PlayerList::iterator it = players.begin(); it != players.end(); ++it) { + if (!(*it)->isSleepingLongEnough()) { return false; } } @@ -55,13 +61,17 @@ bool ServerLevel::allPlayersSleeping() { return false; } -void ServerLevel::tick(){ +void ServerLevel::tick() { super::tick(); - if(allPlayersSleeping()) { + + if (allPlayersSleeping()) { long newTime = levelData.getTime() + TICKS_PER_DAY; + levelData.setTime(newTime - (newTime % TICKS_PER_DAY)); + SetTimePacket packet(levelData.getTime()); raknetInstance->send(packet); + awakenAllPlayers(); } } diff --git a/src/server/ServerPlayer.cpp b/src/server/ServerPlayer.cpp index ad3b4a9..9f4f1dc 100755 --- a/src/server/ServerPlayer.cpp +++ b/src/server/ServerPlayer.cpp @@ -19,14 +19,17 @@ #include "../network/packet/AnimatePacket.h" #include "../world/level/tile/entity/ChestTileEntity.h" #include "../network/packet/HurtArmorPacket.h" +#include "network/packet/SendInventoryPacket.h" +#include "world/entity/player/Inventory.h" -ServerPlayer::ServerPlayer( Minecraft* minecraft, Level* level ) +ServerPlayer::ServerPlayer( Minecraft* minecraft, Level* level, bool proto) : super(level, minecraft->isCreativeMode()), _mc(minecraft), _prevHealth(-999), - _containerCounter(0) + _containerCounter(0), + isNewProto(proto) { - hasFakeInventory = true; + // hasFakeInventory = true; footSize = 0; } @@ -67,7 +70,16 @@ void ServerPlayer::tick() { void ServerPlayer::take( Entity* e, int orgCount ) { TakeItemEntityPacket packet(e->entityId, entityId); + // SendInventoryPacket packet(this, false); _mc->raknetInstance->send(packet); + printf("TakeItemEntityPacket \n"); + + LOGI("Inventory:\n"); + for (int i = 0; i < inventory->numLinkedSlots; i++) { + auto item = inventory->getItem(i); + if (item) + LOGI("\t %i: %s (%i)\n", i, item->getName().c_str(), item->count); + } super::take(e, orgCount); } @@ -118,20 +130,20 @@ bool ServerPlayer::hasResource( int id ) { void ServerPlayer::setContainerData( BaseContainerMenu* menu, int id, int value ) { ContainerSetDataPacket p(menu->containerId, id, value); _mc->raknetInstance->send(owner, p); - //LOGI("Setting container data for id %d: %d\n", id, value); + LOGI("Setting container data for id %d: %d\n", id, value); } void ServerPlayer::slotChanged( BaseContainerMenu* menu, int slot, const ItemInstance& item, bool isResultSlot ) { if (isResultSlot) return; ContainerSetSlotPacket p(menu->containerId, slot, item); _mc->raknetInstance->send(owner, p); - //LOGI("Slot %d changed\n", slot); + LOGI("Slot %d changed\n", slot); } void ServerPlayer::refreshContainer( BaseContainerMenu* menu, const std::vector& items ) { ContainerSetContentPacket p(menu->containerId, menu->getItems()); _mc->raknetInstance->send(owner, p); - //LOGI("Refreshing container with %d items\n", items.size()); + LOGI("Refreshing container with %zu items\n", items.size()); } void ServerPlayer::nextContainerCounter() { @@ -163,3 +175,12 @@ void ServerPlayer::displayClientMessage( const std::string& messageId ) { ChatPacket package(messageId); _mc->raknetInstance->send(owner, package); } + +void ServerPlayer::causeFallDamage(float distance) { + int dmg = (int) ceil((distance - 3)); + if (dmg > 0) { + SetHealthPacket packet(SetHealthPacket::HEALTH_MODIFY_OFFSET + dmg); + _mc->raknetInstance->send(owner, packet); + } + super::causeFallDamage(distance); +} \ No newline at end of file diff --git a/src/server/ServerPlayer.h b/src/server/ServerPlayer.h index de20661..c578025 100755 --- a/src/server/ServerPlayer.h +++ b/src/server/ServerPlayer.h @@ -15,7 +15,7 @@ class ServerPlayer: public Player, { typedef Player super; public: - ServerPlayer(Minecraft* minecraft, Level* level); + ServerPlayer(Minecraft* minecraft, Level* level, bool proto); ~ServerPlayer(); @@ -43,6 +43,17 @@ public: virtual void stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool saveRespawnPoint); void completeUsingItem(); + + void setLastMoveTicks(int lastMoveTicks) { this->lastMoveTicks = lastMoveTicks; } + int getLastMoveTicks() { return lastMoveTicks; } + + void setTicksInAir(int ticksInAir) { this->ticksInAir = ticksInAir; } + int getTicksInAir() { return ticksInAir; } + + void setNewProto(bool proto) { isNewProto = proto; } + bool getProto() { return isNewProto; } + + virtual void causeFallDamage(float distance); private: void nextContainerCounter(); void setContainerMenu( BaseContainerMenu* menu ); @@ -50,6 +61,11 @@ private: Minecraft* _mc; int _prevHealth; int _containerCounter; + + int lastMoveTicks = 0; + int ticksInAir = 0; + + bool isNewProto = false; }; #endif /*ServerPlayer_H__*/ diff --git a/src/world/entity/Entity.cpp b/src/world/entity/Entity.cpp index 7be3325..47ac1d8 100755 --- a/src/world/entity/Entity.cpp +++ b/src/world/entity/Entity.cpp @@ -880,8 +880,8 @@ bool Entity::load( CompoundTag* tag ) // Add a small padding if standing next to the world edges const float padding = bbWidth * 0.5f + 0.001f; - xx = Mth::clamp(xx, padding, (float)LEVEL_WIDTH - padding); - zz = Mth::clamp(zz, padding, (float)LEVEL_DEPTH - padding); + xx = Mth::clamp(xx, padding, (float)LevelConstants::LEVEL_WIDTH - padding); + zz = Mth::clamp(zz, padding, (float)LevelConstants::LEVEL_DEPTH - padding); xo = xOld = x = xx; yo = yOld = y = yy; diff --git a/src/world/entity/Entity.h b/src/world/entity/Entity.h index 02436a0..be6c4d9 100755 --- a/src/world/entity/Entity.h +++ b/src/world/entity/Entity.h @@ -131,6 +131,7 @@ public: virtual bool isHangingEntity(); virtual int getAuxData(); + virtual void checkFallDamage(float ya, bool onGround); protected: virtual void setRot(float yRot, float xRot); @@ -139,7 +140,6 @@ protected: virtual void resetPos(bool clearMore); virtual void outOfWorld(); - virtual void checkFallDamage(float ya, bool onGround); virtual void causeFallDamage(float fallDamage2); virtual void markHurt(); diff --git a/src/world/entity/Mob.cpp b/src/world/entity/Mob.cpp index be601c8..e275ea8 100755 --- a/src/world/entity/Mob.cpp +++ b/src/world/entity/Mob.cpp @@ -743,7 +743,6 @@ bool Mob::isWaterMob() void Mob::aiStep() { //@todo? 30 lines of code here in java version - TIMER_PUSH("ai"); if (isImmobile()) { jumping = false; diff --git a/src/world/entity/Mob.h b/src/world/entity/Mob.h index 89f0347..f9a0fa0 100755 --- a/src/world/entity/Mob.h +++ b/src/world/entity/Mob.h @@ -224,6 +224,9 @@ protected: double xc, yc, zc; public: + void setxxa(float xxa) { this->xxa = xxa; } + void setyya(float yya) { this->yya = yya; } + // Cape position accessors (for renderers) double getCapeX() const { return xCape; } double getCapeY() const { return yCape; } diff --git a/src/world/entity/player/Inventory.cpp b/src/world/entity/player/Inventory.cpp index 480627b..00f16a2 100755 --- a/src/world/entity/player/Inventory.cpp +++ b/src/world/entity/player/Inventory.cpp @@ -358,3 +358,12 @@ bool Inventory::removeItem( const ItemInstance* samePtr ) { } return false; } + +void Inventory::print() { + LOGI("%s's Inventory:\n", player->name.c_str()); + + for (int i = 0; i < numTotalSlots; i++) { + auto item = getItem(i); + if (item) LOGI("\t %i: %s (%i) %s\n", i, item->getName().c_str(), item->count, (player->inventory->getLinked(i))? "(Linked)" : ""); + } +} \ No newline at end of file diff --git a/src/world/entity/player/Inventory.h b/src/world/entity/player/Inventory.h index 3e8696e..e1ad435 100755 --- a/src/world/entity/player/Inventory.h +++ b/src/world/entity/player/Inventory.h @@ -45,6 +45,8 @@ public: int getAttackDamage(Entity* entity); float getDestroySpeed(Tile* tile); bool canDestroy(Tile* tile); + + void print(); private: void setupDefault(); public: diff --git a/src/world/inventory/FillingContainer.cpp b/src/world/inventory/FillingContainer.cpp index 10028b0..e4fcd5d 100755 --- a/src/world/inventory/FillingContainer.cpp +++ b/src/world/inventory/FillingContainer.cpp @@ -141,6 +141,11 @@ bool FillingContainer::add( ItemInstance* item ) // // silently destroy the item when having a full inventory // item->count = 0; // return true; + + LOGI("Inventory:\n"); + for (int i = 0; i < numTotalSlots; i++) { + LOGI("\t %i: %s (%i)\n", i, items.at(i)->getName().c_str(), items.at(i)->count); + } } return false; diff --git a/src/world/item/ItemInstance.cpp b/src/world/item/ItemInstance.cpp index 9d7d03f..d52d9f1 100755 --- a/src/world/item/ItemInstance.cpp +++ b/src/world/item/ItemInstance.cpp @@ -290,3 +290,7 @@ bool ItemInstance::isArmorItem( const ItemInstance* instance ) { return item->isArmor(); } + +bool ItemInstance::isBlock(const ItemInstance* instance) { + return instance->id < 256; +} \ No newline at end of file diff --git a/src/world/item/ItemInstance.h b/src/world/item/ItemInstance.h index b65a97d..9b1926d 100755 --- a/src/world/item/ItemInstance.h +++ b/src/world/item/ItemInstance.h @@ -81,6 +81,8 @@ public: static bool isArmorItem(const ItemInstance* instance); + static bool isBlock(const ItemInstance* instance); + /** * Checks if this item is the same item as the other one, disregarding the * 'count' value. diff --git a/src/world/item/TileItem.h b/src/world/item/TileItem.h index c75084e..08bd1d0 100755 --- a/src/world/item/TileItem.h +++ b/src/world/item/TileItem.h @@ -61,7 +61,7 @@ public: if (level->setTileAndData(x, y, z, tileId, data)) { Tile::tiles[tileId]->setPlacedBy(level, x, y, z, player); level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getStepSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); - + printf("%f %f %f \n", player->x, player->y, player->z); /* PlaceBlockPacket packet(player->entityId, x, y, z, face, tileId, instance->getAuxValue()); //LOGI("Place block at @ %d, %d, %d\n", x, y, z); diff --git a/src/world/level/Level.cpp b/src/world/level/Level.cpp index 21e1a2f..522bad1 100755 --- a/src/world/level/Level.cpp +++ b/src/world/level/Level.cpp @@ -29,6 +29,9 @@ #include "../Difficulty.h" #include "../../network/packet/ExplodePacket.h" +const int Level::DEPTH = LevelConstants::LEVEL_HEIGHT; +const int Level::SEA_LEVEL = Level::DEPTH / 2 - 1; + Level::Level(LevelStorage* levelStorage, const std::string& levelName, const LevelSettings& settings, int generatorVersion, Dimension* fixedDimension /* = NULL */) : levelStorage(levelStorage), isClientSide(false), @@ -278,8 +281,8 @@ void Level::tickTiles() { for (int i = 0; i < pollChunkOffsetsSize; i += 2) { const int xp = xx + pollChunkOffsets[i]; const int zp = zz + pollChunkOffsets[i+1]; - if (xp >= 0 && xp < CHUNK_CACHE_WIDTH && - zp >= 0 && zp < CHUNK_CACHE_WIDTH) + if (xp >= 0 && xp < LevelConstants::CHUNK_CACHE_WIDTH && + zp >= 0 && zp < LevelConstants::CHUNK_CACHE_WIDTH) _chunksToPoll.insert(ChunkPos(xp, zp)); } } @@ -427,21 +430,21 @@ bool Level::findPath(Path* path, Entity* from, int xBest, int yBest, int zBest, */ /*protected*/ void Level::setInitialSpawn() { - isFindingSpawn = true; - int xSpawn = CHUNK_CACHE_WIDTH * CHUNK_WIDTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; - int ySpawn = 64; - int zSpawn = CHUNK_CACHE_WIDTH * CHUNK_DEPTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; - while (!dimension->isValidSpawn(xSpawn, zSpawn)) { - xSpawn += random.nextInt(32) - random.nextInt(32); - zSpawn += random.nextInt(32) - random.nextInt(32); + isFindingSpawn = true; + int xSpawn = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_WIDTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; + int ySpawn = 64; + int zSpawn = LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_DEPTH / 2; // (Level.MAX_LEVEL_SIZE - 100) * 0; + while (!dimension->isValidSpawn(xSpawn, zSpawn)) { + xSpawn += random.nextInt(32) - random.nextInt(32); + zSpawn += random.nextInt(32) - random.nextInt(32); if (xSpawn < 4) xSpawn += 32; - if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 32; + if (xSpawn >= LevelConstants::LEVEL_WIDTH-4) xSpawn -= 32; if (zSpawn < 4) zSpawn += 32; - if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 32; - } - levelData.setSpawn(xSpawn, ySpawn, zSpawn); - isFindingSpawn = false; + if (zSpawn >= LevelConstants::LEVEL_DEPTH-4) zSpawn -= 32; + } + levelData.setSpawn(xSpawn, ySpawn, zSpawn); + isFindingSpawn = false; } /*public*/ @@ -456,12 +459,12 @@ void Level::validateSpawn() { zSpawn += random.nextInt(8) - random.nextInt(8); if (xSpawn < 4) xSpawn += 8; - if (xSpawn >= LEVEL_WIDTH-4) xSpawn -= 8; + if (xSpawn >= LevelConstants::LEVEL_WIDTH-4) xSpawn -= 8; if (zSpawn < 4) zSpawn += 8; - if (zSpawn >= LEVEL_DEPTH-4) zSpawn -= 8; - } - levelData.setXSpawn(xSpawn); - levelData.setZSpawn(zSpawn); + if (zSpawn >= LevelConstants::LEVEL_DEPTH-4) zSpawn -= 8; + } + levelData.setXSpawn(xSpawn); + levelData.setZSpawn(zSpawn); } int Level::getTopTile(int x, int z) { @@ -944,7 +947,7 @@ HitResult Level::clip(const Vec3& A, const Vec3& b, bool liquid /*= false*/, boo if (solidOnly && tile != NULL && tile->getAABB(this, xTile0, yTile0, zTile0) == NULL) { // No collision } else if (t > 0 && tile->mayPick(data, liquid)) { - if(xTile0 >= 0 && zTile0 >= 0 && xTile0 < LEVEL_WIDTH && zTile0 < LEVEL_WIDTH) { + if(xTile0 >= 0 && zTile0 >= 0 && xTile0 < LevelConstants::LEVEL_WIDTH && zTile0 < LevelConstants::LEVEL_WIDTH) { HitResult r = tile->clip(this, xTile0, yTile0, zTile0, a, b); if (r.isHit()) return r; } @@ -1984,10 +1987,10 @@ void Level::prepare() { ; } -bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities,unsigned char face) { - int targetType = getTile(x, y, z); - const Tile* targetTile = Tile::tiles[targetType]; - Tile* tile = Tile::tiles[tileId]; +bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities,unsigned char face) { + int targetType = getTile(x, y, z); + const Tile* targetTile = Tile::tiles[targetType]; + Tile* tile = Tile::tiles[tileId]; AABB* aabb = tile->getAABB(this, x, y, z); if (ignoreEntities) aabb = NULL; @@ -2247,9 +2250,9 @@ void Level::setNightMode( bool isNightMode ) { } bool Level::inRange( int x, int y, int z ) { - return x >= 0 && x < LEVEL_WIDTH - && y >= 0 && y < LEVEL_HEIGHT - && z >= 0 && z < LEVEL_DEPTH; + return x >= 0 && x < LevelConstants::LEVEL_WIDTH + && y >= 0 && y < LevelConstants::LEVEL_HEIGHT + && z >= 0 && z < LevelConstants::LEVEL_DEPTH; } // diff --git a/src/world/level/Level.h b/src/world/level/Level.h index 17d9942..17c1d48 100755 --- a/src/world/level/Level.h +++ b/src/world/level/Level.h @@ -67,8 +67,8 @@ class Level: public LevelSource public: static const int MAX_LEVEL_SIZE = 32000000; - static const short DEPTH = LEVEL_HEIGHT; - static const short SEA_LEVEL = DEPTH / 2 - 1; + static const int DEPTH; + static const int SEA_LEVEL; static const int MAX_BRIGHTNESS = 15; static const int TICKS_PER_DAY = SharedConstants::TicksPerSecond * 60 * 16;// SharedConstants::TicksPerSecond * 60 * 12; // ORG:20*60*20 @@ -310,6 +310,9 @@ public: Dimension* dimension; IRakNetInstance* raknetInstance; Random random; + + std::set ops; + std::set bannedPpl; protected: bool isFindingSpawn; diff --git a/src/world/level/LevelConstants.cpp b/src/world/level/LevelConstants.cpp new file mode 100644 index 0000000..6a36246 --- /dev/null +++ b/src/world/level/LevelConstants.cpp @@ -0,0 +1,10 @@ +#include "LevelConstants.h" + +int LevelConstants::LEVEL_HEIGHT = 128; +int LevelConstants::CHUNK_CACHE_WIDTH = 16; // in chunks +int LevelConstants::CHUNK_WIDTH = 16; // in blocks +int LevelConstants::CHUNK_DEPTH = 16; +int LevelConstants::LEVEL_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH * CHUNK_WIDTH; +int LevelConstants::LEVEL_DEPTH = LevelConstants::CHUNK_CACHE_WIDTH * CHUNK_DEPTH; +int LevelConstants::CHUNK_COLUMNS = LevelConstants::CHUNK_WIDTH * LevelConstants::CHUNK_DEPTH; +int LevelConstants::CHUNK_BLOCK_COUNT = LevelConstants::CHUNK_COLUMNS * LevelConstants::LEVEL_HEIGHT; \ No newline at end of file diff --git a/src/world/level/LevelConstants.h b/src/world/level/LevelConstants.h index 4d6865b..ed77861 100755 --- a/src/world/level/LevelConstants.h +++ b/src/world/level/LevelConstants.h @@ -1,14 +1,14 @@ -#ifndef _MINECRAFT_WORLD_LEVELCONSTANTS_H_ -#define _MINECRAFT_WORLD_LEVELCONSTANTS_H_ +#pragma once - -const int LEVEL_HEIGHT = 128; -const int CHUNK_CACHE_WIDTH = 16; // in chunks -const int CHUNK_WIDTH = 16; // in blocks -const int CHUNK_DEPTH = 16; -const int LEVEL_WIDTH = CHUNK_CACHE_WIDTH * CHUNK_WIDTH; -const int LEVEL_DEPTH = CHUNK_CACHE_WIDTH * CHUNK_DEPTH; -const int CHUNK_COLUMNS = CHUNK_WIDTH * CHUNK_DEPTH; -const int CHUNK_BLOCK_COUNT = CHUNK_COLUMNS * LEVEL_HEIGHT; - -#endif +class LevelConstants { +public: + static int CHUNK_CACHE_WIDTH; // in chunks + static int LEVEL_WIDTH; + static int LEVEL_DEPTH; + static int LEVEL_HEIGHT; + + static int CHUNK_WIDTH; // in blocks + static int CHUNK_DEPTH; + static int CHUNK_COLUMNS; + static int CHUNK_BLOCK_COUNT; +}; \ No newline at end of file diff --git a/src/world/level/chunk/ChunkCache.h b/src/world/level/chunk/ChunkCache.h index f6e5376..a770686 100755 --- a/src/world/level/chunk/ChunkCache.h +++ b/src/world/level/chunk/ChunkCache.h @@ -10,7 +10,7 @@ #include "../LevelConstants.h" class ChunkCache: public ChunkSource { - //static const int CHUNK_CACHE_WIDTH = CHUNK_CACHE_WIDTH; // WAS 32; + //static const int LevelConstants::CHUNK_CACHE_WIDTH = LevelConstants::CHUNK_CACHE_WIDTH; // WAS 32; static const int MAX_SAVES = 2; public: ChunkCache(Level* level_, ChunkStorage* storage_, ChunkSource* source_) @@ -24,14 +24,17 @@ public: isChunkCache = true; //emptyChunk = new EmptyLevelChunk(level_, emptyChunkBlocks, 0, 0); emptyChunk = new EmptyLevelChunk(level_, NULL, 0, 0); - memset(chunks, 0, sizeof(LevelChunk*) * CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH); + + chunks = new LevelChunk *[LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH]; + memset(chunks, 0, sizeof(LevelChunk*) * LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH); + LOGI("Chunks allocated."); } ~ChunkCache() { delete source; delete emptyChunk; - for (int i = 0; i < CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH; i++) + for (int i = 0; i < LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH; i++) { if (chunks[i]) { @@ -42,7 +45,7 @@ public: } bool fits(int x, int z) { - return (x >= 0 && z >= 0 && x < CHUNK_CACHE_WIDTH && z < CHUNK_CACHE_WIDTH); + return (x >= 0 && z >= 0 && x < LevelConstants::CHUNK_CACHE_WIDTH && z < LevelConstants::CHUNK_CACHE_WIDTH); } bool hasChunk(int x, int z) { @@ -52,9 +55,9 @@ public: if (x == xLast && z == zLast && last != NULL) { return true; } - int xs = x & (CHUNK_CACHE_WIDTH - 1); - int zs = z & (CHUNK_CACHE_WIDTH - 1); - int slot = xs + zs * CHUNK_CACHE_WIDTH; + int xs = x & (LevelConstants::CHUNK_CACHE_WIDTH - 1); + int zs = z & (LevelConstants::CHUNK_CACHE_WIDTH - 1); + int slot = xs + zs * LevelConstants::CHUNK_CACHE_WIDTH; return chunks[slot] != NULL && (chunks[slot] == emptyChunk || chunks[slot]->isAt(x, z)); } @@ -71,9 +74,9 @@ public: } if (!fits(x, z)) return emptyChunk; //if (!level->isFindingSpawn && !fits(x, z)) return emptyChunk; - int xs = x & (CHUNK_CACHE_WIDTH - 1); - int zs = z & (CHUNK_CACHE_WIDTH - 1); - int slot = xs + zs * CHUNK_CACHE_WIDTH; + int xs = x & (LevelConstants::CHUNK_CACHE_WIDTH - 1); + int zs = z & (LevelConstants::CHUNK_CACHE_WIDTH - 1); + int slot = xs + zs * LevelConstants::CHUNK_CACHE_WIDTH; if (!hasChunk(x, z)) { if (chunks[slot] != NULL) { chunks[slot]->unload(); @@ -202,8 +205,8 @@ public: void saveAll(bool onlyUnsaved) { if (storage != NULL) { std::vector chunks; - for (int z = 0; z < CHUNK_CACHE_WIDTH; ++z) - for (int x = 0; x < CHUNK_CACHE_WIDTH; ++x) { + for (int z = 0; z < LevelConstants::CHUNK_CACHE_WIDTH; ++z) + for (int x = 0; x < LevelConstants::CHUNK_CACHE_WIDTH; ++x) { LevelChunk* chunk = level->getChunk(x, z); if (!onlyUnsaved || chunk->shouldSave(false)) chunks.push_back( chunk ); @@ -214,7 +217,7 @@ public: private: LevelChunk* load(int x, int z) { if (storage == NULL) return emptyChunk; - if (x < 0 || x >= CHUNK_CACHE_WIDTH || z < 0 || z >= CHUNK_CACHE_WIDTH) + if (x < 0 || x >= LevelConstants::CHUNK_CACHE_WIDTH || z < 0 || z >= LevelConstants::CHUNK_CACHE_WIDTH) { return emptyChunk; } @@ -257,7 +260,7 @@ private: LevelChunk* emptyChunk; ChunkSource* source; ChunkStorage* storage; - LevelChunk* chunks[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH]; + LevelChunk** chunks; Level* level; LevelChunk* last; diff --git a/src/world/level/chunk/LevelChunk.cpp b/src/world/level/chunk/LevelChunk.cpp index ef13d1b..fd61715 100755 --- a/src/world/level/chunk/LevelChunk.cpp +++ b/src/world/level/chunk/LevelChunk.cpp @@ -12,13 +12,14 @@ /*static*/ bool LevelChunk::touchedSky = false; +int LevelChunk::ChunkBlockCount; LevelChunk::LevelChunk( Level* level, int x, int z ) : level(level), x(x), z(z), - xt(x * CHUNK_WIDTH), - zt(z * CHUNK_DEPTH) + xt(x * LevelConstants::CHUNK_WIDTH), + zt(z * LevelConstants::CHUNK_DEPTH) { init(); } @@ -27,8 +28,8 @@ LevelChunk::LevelChunk( Level* level, unsigned char* blocks, int x, int z ) : level(level), x(x), z(z), - xt(x * CHUNK_WIDTH), - zt(z * CHUNK_DEPTH), + xt(x * LevelConstants::CHUNK_WIDTH), + zt(z * LevelConstants::CHUNK_DEPTH), blocks(blocks), data(ChunkBlockCount), skyLight(ChunkBlockCount), @@ -45,6 +46,9 @@ LevelChunk::~LevelChunk() void LevelChunk::init() { + heightmap = new char[LevelConstants::CHUNK_COLUMNS]; + updateMap = new unsigned char[LevelConstants::CHUNK_COLUMNS]; + terrainPopulated = false; dontSave = false; unsaved = false; diff --git a/src/world/level/chunk/LevelChunk.h b/src/world/level/chunk/LevelChunk.h index 5735744..8fe7281 100755 --- a/src/world/level/chunk/LevelChunk.h +++ b/src/world/level/chunk/LevelChunk.h @@ -106,9 +106,9 @@ private: void recalcHeight(int x, int yStart, int z); public: static bool touchedSky; - static const int ChunkBlockCount = CHUNK_BLOCK_COUNT; - static const int ChunkSize = ChunkBlockCount; - static const int UpdateMapBitShift = 4; // power of (LEVEL_HEIGHT / 8) == 16 + static int ChunkBlockCount; + const int ChunkSize = ChunkBlockCount; + static const int UpdateMapBitShift = 4; // power of (LevelConstants::LEVEL_HEIGHT / 8) == 16 int blocksLength; // ? needed or not? (i.e. are all chunks the same size?) @@ -118,12 +118,12 @@ public: DataLayer skyLight; DataLayer blockLight; - char heightmap[CHUNK_COLUMNS]; - unsigned char updateMap[CHUNK_COLUMNS]; // marks regions within block columns that have been modified + char* heightmap; // [LevelConstants::CHUNK_COLUMNS] + unsigned char* updateMap; // marks regions within block columns that have been modified [LevelConstants::CHUNK_COLUMNS] int minHeight; - const int x, z; - const int xt, zt; + int x, z; + int xt, zt; bool terrainPopulated; bool unsaved; diff --git a/src/world/level/levelgen/RandomLevelSource.cpp b/src/world/level/levelgen/RandomLevelSource.cpp index 5d84f35..dbaa87b 100755 --- a/src/world/level/levelgen/RandomLevelSource.cpp +++ b/src/world/level/levelgen/RandomLevelSource.cpp @@ -64,9 +64,9 @@ RandomLevelSource::~RandomLevelSource() { /*public*/ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, unsigned char* blocks, /*Biome*/void* biomes, float* temperatures) { - - int xChunks = 16 / CHUNK_WIDTH; - int waterHeight = Level::DEPTH - 64; + + int xChunks = 16 / LevelConstants::CHUNK_WIDTH; + int waterHeight = Level::DEPTH - 64; int xSize = xChunks + 1; int ySize = 128 / CHUNK_HEIGHT + 1; @@ -87,36 +87,36 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, unsigned char* bloc float s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; float s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; - for (int y = 0; y < CHUNK_HEIGHT; y++) { - float xStep = 1 / (float) CHUNK_WIDTH; + for (int y = 0; y < CHUNK_HEIGHT; y++) { + float xStep = 1 / (float) LevelConstants::CHUNK_WIDTH; float _s0 = s0; float _s1 = s1; float _s0a = (s2 - s0) * xStep; float _s1a = (s3 - s1) * xStep; - for (int x = 0; x < CHUNK_WIDTH; x++) { - int offs = (x + xc * CHUNK_WIDTH) << 11 | (0 + zc * CHUNK_WIDTH) << 7 | (yc * CHUNK_HEIGHT + y); - int step = 1 << 7; - float zStep = 1 / (float) CHUNK_WIDTH; + for (int x = 0; x < LevelConstants::CHUNK_WIDTH; x++) { + int offs = (x + xc * LevelConstants::CHUNK_WIDTH) << 11 | (0 + zc * LevelConstants::CHUNK_WIDTH) << 7 | (yc * CHUNK_HEIGHT + y); + int step = 1 << 7; + float zStep = 1 / (float) LevelConstants::CHUNK_WIDTH; - float val = _s0; - float vala = (_s1 - _s0) * zStep; - for (int z = 0; z < CHUNK_WIDTH; z++) { - // + (zc * CHUNK_WIDTH + z)]; - float temp = temperatures[(xc * CHUNK_WIDTH + x) * 16 + (zc * CHUNK_WIDTH + z)]; - int tileId = 0; - if (yc * CHUNK_HEIGHT + y < waterHeight) { - if (temp < SNOW_CUTOFF && yc * CHUNK_HEIGHT + y >= waterHeight - 1) { - tileId = Tile::ice->id; - } else { - tileId = Tile::calmWater->id; - } - } - if (val > 0) { - tileId = Tile::rock->id; - } else { - } + float val = _s0; + float vala = (_s1 - _s0) * zStep; + for (int z = 0; z < LevelConstants::CHUNK_WIDTH; z++) { +// + (zc * LevelConstants::CHUNK_WIDTH + z)]; + float temp = temperatures[(xc * LevelConstants::CHUNK_WIDTH + x) * 16 + (zc * LevelConstants::CHUNK_WIDTH + z)]; + int tileId = 0; + if (yc * CHUNK_HEIGHT + y < waterHeight) { + if (temp < SNOW_CUTOFF && yc * CHUNK_HEIGHT + y >= waterHeight - 1) { + tileId = Tile::ice->id; + } else { + tileId = Tile::calmWater->id; + } + } + if (val > 0) { + tileId = Tile::rock->id; + } else { + } blocks[offs] = (unsigned char) tileId; offs += step; diff --git a/src/world/level/storage/ExternalFileLevelStorage.cpp b/src/world/level/storage/ExternalFileLevelStorage.cpp index 91bcf45..93ee9f1 100755 --- a/src/world/level/storage/ExternalFileLevelStorage.cpp +++ b/src/world/level/storage/ExternalFileLevelStorage.cpp @@ -1,3 +1,6 @@ +#include +#include +#include #if !defined(DEMO_MODE) && !defined(APPLE_DEMO_PROMOTION) #include "LevelData.h" @@ -88,6 +91,9 @@ ExternalFileLevelStorage::ExternalFileLevelStorage(const std::string& levelId, c { createFolderIfNotExists(levelPath.c_str()); + std::string playerFolder = levelPath + "/players"; + createFolderIfNotExists(playerFolder.c_str()); + std::string datFileName = levelPath + "/" + fnLevelDat; std::string levelFileName = levelPath + "/" + fnPlayerDat; loadedLevelData = new LevelData(); @@ -113,6 +119,7 @@ void ExternalFileLevelStorage::saveLevelData(LevelData& levelData, std::vector

* players ) { + // @todo: completely rewrite std::string directory = levelPath + "/"; std::string tmpFile = directory + fnLevelDatNew; std::string datFile = directory + fnLevelDat; @@ -141,6 +148,67 @@ void ExternalFileLevelStorage::saveLevelData( const std::string& levelPath, Leve // Remove the temporary save, if the rename didn't do it remove(tmpFile.c_str()); + + // Save players + // fuck mojang for that + if (!players || players->empty()) { + return; + } + + for (auto& player : *players) { + if (player != NULL) { + savePlayer(*player, directory); + } + } +} + +void ExternalFileLevelStorage::savePlayer(Player& player, const std::string& worldDir) { + std::string playerPath = worldDir + "/players/" + player.name + ".dat"; + + LOGI("Saving player %s to %s...\n", player.name.c_str(), playerPath.c_str()); + + RakNet::BitStream data; + RakDataOutput buf(data); + CompoundTag playerTag; + player.saveWithoutId(&playerTag); + + NbtIo::write(&playerTag, &buf); + + std::ofstream file(playerPath, std::ios::out | std::ios::binary); + file.write((const char*)data.GetData(), (size_t)data.GetNumberOfBytesUsed()); +} + +bool ExternalFileLevelStorage::loadPlayer(Player& player, const std::string& worldDir) { + std::string playerPath = worldDir + "/players/" + player.name + ".dat"; + + LOGI("Loading player %s from %s...\n", player.name.c_str(), playerPath.c_str()); + + std::ifstream file(playerPath, std::ios::in | std::ios::binary); + if (!file.is_open()) { + return false; + } + + std::vector data((std::istreambuf_iterator(file)), std::istreambuf_iterator()); + + RakNet::BitStream bitStream(data.data(), data.size(), false); + RakDataInput stream(bitStream); + + CompoundTag* tag = NbtIo::read(&stream); + if (tag) { + player.load(tag); + tag->deleteChildren(); + delete tag; + } + + return true; +} + +void ExternalFileLevelStorage::savePlayer(Player& player) { + ExternalFileLevelStorage::savePlayer(player, levelPath); +} + +bool ExternalFileLevelStorage::loadPlayer(Player& player) { + return ExternalFileLevelStorage::loadPlayer(player, levelPath); } LevelData* ExternalFileLevelStorage::prepareLevel(Level* _level) @@ -275,8 +343,8 @@ bool ExternalFileLevelStorage::readPlayerData(const std::string& filename, Level Vec3& pos = dest.playerData.pos; if (pos.x < 0.5f) pos.x = 0.5f; if (pos.z < 0.5f) pos.z = 0.5f; - if (pos.x > (LEVEL_WIDTH - 0.5f)) pos.x = LEVEL_WIDTH - 0.5f; - if (pos.z > (LEVEL_DEPTH - 0.5f)) pos.z = LEVEL_DEPTH - 0.5f; + if (pos.x > (LevelConstants::LEVEL_WIDTH - 0.5f)) pos.x = LevelConstants::LEVEL_WIDTH - 0.5f; + if (pos.z > (LevelConstants::LEVEL_DEPTH - 0.5f)) pos.z = LevelConstants::LEVEL_DEPTH - 0.5f; if (pos.y < 0) pos.y = 64; dest.playerDataVersion = version; @@ -294,14 +362,14 @@ void ExternalFileLevelStorage::tick() LOGI("Saving level...\n"); // look for chunks that needs to be saved - for (int z = 0; z < CHUNK_CACHE_WIDTH; z++) + for (int z = 0; z < LevelConstants::CHUNK_CACHE_WIDTH; z++) { - for (int x = 0; x < CHUNK_CACHE_WIDTH; x++) + for (int x = 0; x < LevelConstants::CHUNK_CACHE_WIDTH; x++) { LevelChunk* chunk = level->getChunk(x, z); if (chunk && chunk->unsaved) { - int pos = x + z * CHUNK_CACHE_WIDTH; + int pos = x + z * LevelConstants::CHUNK_CACHE_WIDTH; UnsavedChunkList::iterator prev = unsavedChunkList.begin(); for ( ; prev != unsavedChunkList.end(); ++prev) { @@ -347,13 +415,13 @@ void ExternalFileLevelStorage::save(Level* level, LevelChunk* levelChunk) // Write chunk RakNet::BitStream chunkData; - chunkData.Write((const char*)levelChunk->getBlockData(), CHUNK_BLOCK_COUNT); - chunkData.Write((const char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2); + chunkData.Write((const char*)levelChunk->getBlockData(), LevelConstants::CHUNK_BLOCK_COUNT); + chunkData.Write((const char*)levelChunk->data.data, LevelConstants::CHUNK_BLOCK_COUNT / 2); - chunkData.Write((const char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2); - chunkData.Write((const char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2); + chunkData.Write((const char*)levelChunk->skyLight.data, LevelConstants::CHUNK_BLOCK_COUNT / 2); + chunkData.Write((const char*)levelChunk->blockLight.data, LevelConstants::CHUNK_BLOCK_COUNT / 2); - chunkData.Write((const char*)levelChunk->updateMap, CHUNK_COLUMNS); + chunkData.Write((const char*)levelChunk->updateMap, LevelConstants::CHUNK_COLUMNS); regionFile->writeChunk(levelChunk->x, levelChunk->z, chunkData); @@ -385,16 +453,16 @@ LevelChunk* ExternalFileLevelStorage::load(Level* level, int x, int z) chunkData->ResetReadPointer(); - unsigned char* blockIds = new unsigned char[CHUNK_BLOCK_COUNT]; - chunkData->Read((char*)blockIds, CHUNK_BLOCK_COUNT); + unsigned char* blockIds = new unsigned char[LevelConstants::CHUNK_BLOCK_COUNT]; + chunkData->Read((char*)blockIds, LevelConstants::CHUNK_BLOCK_COUNT); LevelChunk* levelChunk = new LevelChunk(level, blockIds, x, z); - chunkData->Read((char*)levelChunk->data.data, CHUNK_BLOCK_COUNT / 2); + chunkData->Read((char*)levelChunk->data.data, LevelConstants::CHUNK_BLOCK_COUNT / 2); if (loadedStorageVersion >= ChunkVersion_Light) { - chunkData->Read((char*)levelChunk->skyLight.data, CHUNK_BLOCK_COUNT / 2); - chunkData->Read((char*)levelChunk->blockLight.data, CHUNK_BLOCK_COUNT / 2); + chunkData->Read((char*)levelChunk->skyLight.data, LevelConstants::CHUNK_BLOCK_COUNT / 2); + chunkData->Read((char*)levelChunk->blockLight.data, LevelConstants::CHUNK_BLOCK_COUNT / 2); } - chunkData->Read((char*)levelChunk->updateMap, CHUNK_COLUMNS); + chunkData->Read((char*)levelChunk->updateMap, LevelConstants::CHUNK_COLUMNS); // This will be difficult to maintain.. Storage version could be per chunk // too (but probably better to just read all -> write all, so that all // chunks got same version anyway) @@ -417,7 +485,7 @@ LevelChunk* ExternalFileLevelStorage::load(Level* level, int x, int z) //bool dbg = (x == 7 && z == 9); //int t = 0; - //for (int i = 0; i < CHUNK_COLUMNS; ++i) { + //for (int i = 0; i < LevelConstants::CHUNK_COLUMNS; ++i) { // char bits = levelChunk->updateMap[i]; // t += (bits != 0); // int xx = x * 16 + i%16; diff --git a/src/world/level/storage/ExternalFileLevelStorage.h b/src/world/level/storage/ExternalFileLevelStorage.h index b7dd960..9aad448 100755 --- a/src/world/level/storage/ExternalFileLevelStorage.h +++ b/src/world/level/storage/ExternalFileLevelStorage.h @@ -67,6 +67,19 @@ public: void saveGame(Level* level); void saveAll(Level* level, std::vector& levelChunks); + /** + * @brief Save player to /player/.dat file + */ + static void savePlayer(Player& player, const std::string& worldDir); + + /** + * @brief Load player from /player/.dat file + */ + static bool loadPlayer(Player& player, const std::string& worldDir); + + virtual void savePlayer(Player& player); + virtual bool loadPlayer(Player& player); + virtual void tick(); virtual void flush() {} private: diff --git a/src/world/level/storage/LevelStorage.h b/src/world/level/storage/LevelStorage.h index 84c0f62..d3098d2 100755 --- a/src/world/level/storage/LevelStorage.h +++ b/src/world/level/storage/LevelStorage.h @@ -32,6 +32,9 @@ public: virtual void saveGame(Level* level) {} virtual void loadEntities(Level* level, LevelChunk* levelChunk) {} + virtual void savePlayer(Player& player) = 0; + virtual bool loadPlayer(Player& player) = 0; + //void checkSession() throws LevelConflictException; //PlayerIO getPlayerIO(); }; diff --git a/src/world/level/tile/Mushroom.cpp b/src/world/level/tile/Mushroom.cpp index 6de05ce..2992405 100755 --- a/src/world/level/tile/Mushroom.cpp +++ b/src/world/level/tile/Mushroom.cpp @@ -47,7 +47,7 @@ bool Mushroom::mayPlaceOn( int tile ) { } bool Mushroom::canSurvive( Level* level, int x, int y, int z ) { - if (y < 0 || y >= LEVEL_HEIGHT/*Level::maxBuildHeight*/) + if (y < 0 || y >= LevelConstants::LEVEL_HEIGHT/*Level::maxBuildHeight*/) return false; int below = level->getTile(x, y - 1, z); diff --git a/src/world/level/tile/NetherReactor.cpp b/src/world/level/tile/NetherReactor.cpp index 04404eb..00849b9 100755 --- a/src/world/level/tile/NetherReactor.cpp +++ b/src/world/level/tile/NetherReactor.cpp @@ -53,7 +53,7 @@ bool NetherReactor::canSpawnStartNetherReactor( Level* level, int x, int y, int if(!allPlayersCloseToReactor(level, x, y, z)) { player->displayClientMessage("All players need to be close to the reactor."); return false; - } else if(y > LEVEL_HEIGHT - 28) { + } else if(y > LevelConstants::LEVEL_HEIGHT - 28) { player->displayClientMessage("The nether reactor needs to be built lower down."); return false; } else if(y < 2) { diff --git a/src/world/level/tile/Tile.cpp b/src/world/level/tile/Tile.cpp index a5acf7a..6736bc7 100755 --- a/src/world/level/tile/Tile.cpp +++ b/src/world/level/tile/Tile.cpp @@ -22,6 +22,7 @@ #include "../../item/StoneSlabTileItem.h" #include "../../item/SaplingTileItem.h" #include "../../item/ItemCategory.h" +#include "world/level/LevelConstants.h" const int Tile::RENDERLAYER_OPAQUE = 0; const int Tile::RENDERLAYER_ALPHATEST = 1; @@ -512,10 +513,15 @@ bool Tile::shouldRenderFace( LevelSource* level, int x, int y, int z, int face ) { if (face == 0 && y == -1) return false; // For fixed size worlds //@todo: external constants rather than magic numbers + // @fixme @ahtung temp fix + + auto xz = LevelConstants::CHUNK_CACHE_WIDTH == 16 ? 256 : + LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH / (LevelConstants::CHUNK_CACHE_WIDTH * LevelConstants::CHUNK_CACHE_WIDTH / 256 / 2); + if (face == 2 && z == -1) return false; - if (face == 3 && z == 256) return false; + if (face == 3 && z == xz) return false; if (face == 4 && x == -1) return false; - if (face == 5 && x == 256) return false; + if (face == 5 && x == xz) return false; // Common if (face == 0 && yy0 > 0) return true; if (face == 1 && yy1 < 1) return true; diff --git a/src/world/level/tile/entity/NetherReactorTileEntity.cpp b/src/world/level/tile/entity/NetherReactorTileEntity.cpp index f55c12d..5b4728a 100755 --- a/src/world/level/tile/entity/NetherReactorTileEntity.cpp +++ b/src/world/level/tile/entity/NetherReactorTileEntity.cpp @@ -130,7 +130,7 @@ Vec3 NetherReactorTileEntity::getSpawnPosition( float minDistance, float varible void NetherReactorTileEntity::spawnEnemy() { Mob* mob = MobFactory::CreateMob(MobTypes::PigZombie, level); Vec3 enemyPosition = getSpawnPosition(3, 4, -1); - while(enemyPosition.x < 0 || enemyPosition.z < 0 || enemyPosition.x >= LEVEL_WIDTH || enemyPosition.z >= LEVEL_DEPTH) { + while(enemyPosition.x < 0 || enemyPosition.z < 0 || enemyPosition.x >= LevelConstants::LEVEL_WIDTH || enemyPosition.z >= LevelConstants::LEVEL_DEPTH) { enemyPosition = getSpawnPosition(3, 4, -1); } MobSpawner::addMob(level, mob, enemyPosition.x, enemyPosition.y, enemyPosition.z, 0, 0, true); @@ -140,7 +140,7 @@ void NetherReactorTileEntity::spawnEnemy() { void NetherReactorTileEntity::spawnItem() { Vec3 itemPosition= getSpawnPosition(3, 4, -1); - while(itemPosition.x < 0 || itemPosition.z < 0 || itemPosition.x >= LEVEL_WIDTH || itemPosition.z >= LEVEL_DEPTH) { + while(itemPosition.x < 0 || itemPosition.z < 0 || itemPosition.x >= LevelConstants::LEVEL_WIDTH || itemPosition.z >= LevelConstants::LEVEL_DEPTH) { itemPosition = getSpawnPosition(3, 4, -1); } ItemEntity* item = new ItemEntity(level, itemPosition.x, itemPosition.y, itemPosition.z, getSpawnItem());