From 6829fc2e4ae3f8701dd118fdbbb18c9eaa037ee9 Mon Sep 17 00:00:00 2001 From: GabsPuNs Date: Mon, 11 May 2026 00:10:52 -0400 Subject: [PATCH] Merge more changes --- Minecraft.Client/ChatScreen.cpp | 19 +++ Minecraft.Client/ChatScreen.h | 4 + Minecraft.Client/Common/UI/UIController.cpp | 4 + Minecraft.Client/Common/UI/UIScene_HUD.cpp | 32 +++-- Minecraft.Client/Gui.h | 1 + Minecraft.Client/LevelRenderer.cpp | 2 +- Minecraft.Client/MinecraftServer.cpp | 1 - Minecraft.Server/Windows64/ServerMain.cpp | 47 +++++--- Minecraft.Server/cmake/sources/Common.cmake | 2 + Minecraft.World/ConsoleSaveFileOriginal.cpp | 124 ++++++++++++++++++++ Minecraft.World/ConsoleSaveFileOriginal.h | 5 + Minecraft.World/PathFinder.cpp | 58 ++++++--- 12 files changed, 253 insertions(+), 46 deletions(-) diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp index 53c90722..d445f988 100644 --- a/Minecraft.Client/ChatScreen.cpp +++ b/Minecraft.Client/ChatScreen.cpp @@ -22,6 +22,8 @@ ChatScreen::ChatScreen() frame = 0; cursorIndex = 0; s_historyIndex = -1; + + ChatScreen::s_chatIndex = 0; } void ChatScreen::init() @@ -83,6 +85,23 @@ void ChatScreen::handleHistoryDown() applyHistoryMessage(); } +int ChatScreen::getChatIndex() +{ + return ChatScreen::s_chatIndex; +} + +void ChatScreen::correctChatIndex(int newChatIndex) +{ + ChatScreen::s_chatIndex = newChatIndex; +} + +void ChatScreen::setWheelValue(int wheel) +{ + ChatScreen::s_chatIndex += wheel; + if (ChatScreen::s_chatIndex < 0) + ChatScreen::s_chatIndex = 0; +} + void ChatScreen::keyPressed(wchar_t ch, int eventKey) { if (eventKey == Keyboard::KEY_ESCAPE) diff --git a/Minecraft.Client/ChatScreen.h b/Minecraft.Client/ChatScreen.h index c4e37a93..70d65e8c 100644 --- a/Minecraft.Client/ChatScreen.h +++ b/Minecraft.Client/ChatScreen.h @@ -16,6 +16,7 @@ private: static std::vector s_chatHistory; static int s_historyIndex; static wstring s_historyDraft; + static int s_chatIndex; static const wstring allowedChars; static bool isAllowedChatChar(wchar_t c); @@ -28,6 +29,9 @@ public: virtual void handleHistoryUp(); virtual void handleHistoryDown(); + static int getChatIndex(); + static void correctChatIndex(int newChatIndex); + static void setWheelValue(int wheel); protected: void keyPressed(wchar_t ch, int eventKey); public: diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index e332bf9b..bdc0175e 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "UIController.h" +#include #include "UI.h" #include "UIScene.h" #include "UIControl_Slider.h" @@ -1428,6 +1429,9 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) } #endif + if (key == 4) ChatScreen::setWheelValue(1); + if (key == 5) ChatScreen::setWheelValue(-1); + if(pressed) app.DebugPrintf("Pressed %d\n",key); if(released) app.DebugPrintf("Released %d\n",key); // Repeat handling diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp index ae745c36..9237944a 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp @@ -6,9 +6,8 @@ #include "..\..\Minecraft.h" #include "..\..\MultiplayerLocalPlayer.h" #include "..\..\..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h" -#include "..\..\EnderDragonRenderer.h" #include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" -#include "..\..\..\Minecraft.World\StringHelpers.h" +#include UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { @@ -768,16 +767,31 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor void UIScene_HUD::handleTimerComplete(int id) { Minecraft *pMinecraft = Minecraft::GetInstance(); - + + bool isChatOpen = (dynamic_cast(pMinecraft->getScreen()) != nullptr); bool anyVisible = false; if(pMinecraft->localplayers[m_iPad]!= nullptr) { Gui *pGui = pMinecraft->gui; //DWORD messagesToDisplay = min( CHAT_LINES_COUNT, pGui->getMessagesCount(m_iPad) ); - for( unsigned int i = 0; i < CHAT_LINES_COUNT; ++i ) + DWORD totalMessages = pGui->getMessagesCount(m_iPad); + DWORD messagesToDisplay = min(CHAT_LINES_COUNT, totalMessages); + DWORD maxScroll = max(0, totalMessages - messagesToDisplay); + + bool canScroll = messagesToDisplay < totalMessages; + int startIndex = (canScroll && isChatOpen ? ChatScreen::getChatIndex() : 0); + + if (startIndex > maxScroll) { - float opacity = pGui->getOpacity(m_iPad, i); - if( opacity > 0 ) + ChatScreen::correctChatIndex(maxScroll); + startIndex = maxScroll; + } + + for( unsigned int i = 0; i < messagesToDisplay; ++i ) + { + unsigned int msgIndex = startIndex + i; + float opacity = pGui->getOpacity(m_iPad, msgIndex); + if( opacity > 0 || isChatOpen) { #if 0 // def _WINDOWS64 // Use Iggy chat until Gui::render has visual parity // Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats. @@ -785,9 +799,9 @@ void UIScene_HUD::handleTimerComplete(int id) m_labelChatText[i].setOpacity(0); m_labelChatText[i].setLabel(L""); #else - m_controlLabelBackground[i].setOpacity(opacity); - m_labelChatText[i].setOpacity(opacity); - m_labelChatText[i].setLabel( pGui->getMessagesCount(m_iPad) ? pGui->getMessage(m_iPad,i) : L"" ); + m_controlLabelBackground[i].setOpacity((isChatOpen ? 1 : opacity)); + m_labelChatText[i].setOpacity((isChatOpen ? 1 : opacity)); + m_labelChatText[i].setLabel(pGui->getMessage(m_iPad, msgIndex)); #endif anyVisible = true; } diff --git a/Minecraft.Client/Gui.h b/Minecraft.Client/Gui.h index 64b8dfbe..440d4e5b 100644 --- a/Minecraft.Client/Gui.h +++ b/Minecraft.Client/Gui.h @@ -17,6 +17,7 @@ private: static const int m_iMaxMessageWidth = 280; static ItemRenderer *itemRenderer; vector guiMessages[XUSER_MAX_COUNT]; + int chatIndex = 0; Random *random; Minecraft *minecraft; diff --git a/Minecraft.Client/LevelRenderer.cpp b/Minecraft.Client/LevelRenderer.cpp index c8c409ca..7494891c 100644 --- a/Minecraft.Client/LevelRenderer.cpp +++ b/Minecraft.Client/LevelRenderer.cpp @@ -443,7 +443,7 @@ void LevelRenderer::allChanged(int playerIndex) lastPlayerCount[playerIndex] = activePlayers(); xChunks = dist; - yChunks = Level::maxBuildHeight / CHUNK_SIZE; + yChunks = CHUNK_Y_COUNT; zChunks = dist; if( chunks[playerIndex].data != nullptr ) diff --git a/Minecraft.Client/MinecraftServer.cpp b/Minecraft.Client/MinecraftServer.cpp index d8bb9ce5..f57681a8 100644 --- a/Minecraft.Client/MinecraftServer.cpp +++ b/Minecraft.Client/MinecraftServer.cpp @@ -1792,7 +1792,6 @@ void MinecraftServer::run(int64_t seed, void *lpParameter) chunkPacketManagement_PostTick(); } - lastTime = getCurrentTimeMillis(); // Is this a good fix? //int64_t afterall = System::currentTimeMillis(); //PIXReportCounter(L"Server time all",(float)(afterall-beforeall)); //PIXReportCounter(L"Server ticks",(float)tickcount); diff --git a/Minecraft.Server/Windows64/ServerMain.cpp b/Minecraft.Server/Windows64/ServerMain.cpp index ad5e53ec..1c0ef266 100644 --- a/Minecraft.Server/Windows64/ServerMain.cpp +++ b/Minecraft.Server/Windows64/ServerMain.cpp @@ -28,6 +28,7 @@ #include "../../Minecraft.World/TilePos.h" #include "../../Minecraft.World/compression.h" #include "../../Minecraft.World/OldChunkStorage.h" +#include "../../Minecraft.World/ConsoleSaveFileOriginal.h" #include "../../Minecraft.World/net.minecraft.world.level.tile.h" #include "../../Minecraft.World/Random.h" @@ -183,10 +184,10 @@ using ServerRuntime::WorldBootstrapResult; static bool ParseIntArg(const char *value, int *outValue) { - if (value == NULL || *value == 0) + if (value == nullptr || *value == 0) return false; - char *end = NULL; + char *end = nullptr; long parsed = strtol(value, &end, 10); if (end == value || *end != 0) return false; @@ -197,10 +198,10 @@ static bool ParseIntArg(const char *value, int *outValue) static bool ParseInt64Arg(const char *value, __int64 *outValue) { - if (value == NULL || *value == 0) + if (value == nullptr || *value == 0) return false; - char *end = NULL; + char *end = nullptr; __int64 parsed = _strtoi64(value, &end, 10); if (end == value || *end != 0) return false; @@ -277,9 +278,9 @@ static bool ParseCommandLine(int argc, char **argv, DedicatedServerConfig *confi static void SetExeWorkingDirectory() { char exePath[MAX_PATH] = {}; - GetModuleFileNameA(NULL, exePath, MAX_PATH); + GetModuleFileNameA(nullptr, exePath, MAX_PATH); char *slash = strrchr(exePath, '\\'); - if (slash != NULL) + if (slash != nullptr) { *(slash + 1) = 0; SetCurrentDirectoryA(exePath); @@ -288,7 +289,7 @@ static void SetExeWorkingDirectory() static void ApplyServerPropertiesToDedicatedConfig(const ServerPropertiesConfig &serverProperties, DedicatedServerConfig *config) { - if (config == NULL) + if (config == nullptr) { return; } @@ -325,6 +326,7 @@ static void TickCoreSystems() g_NetworkManager.DoWork(); ProfileManager.Tick(); StorageManager.Tick(); + ConsoleSaveFileOriginal::flushPendingBackgroundSave(); } /** @@ -420,7 +422,7 @@ int main(int argc, char **argv) #endif LogStartupStep("registering hidden window class"); - HINSTANCE hInstance = GetModuleHandle(NULL); + HINSTANCE hInstance = GetModuleHandle(nullptr); MyRegisterClass(hInstance); LogStartupStep("creating hidden window"); @@ -490,7 +492,7 @@ int main(int argc, char **argv) LogStartupStep("creating Minecraft singleton"); Minecraft::main(); Minecraft *minecraft = Minecraft::GetInstance(); - if (minecraft == NULL) + if (minecraft == nullptr) { LogError("startup", "Minecraft initialization failed."); CleanupDevice(); @@ -655,7 +657,7 @@ int main(int argc, char **argv) break; } - if (autosaveRequested && app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle) + if (autosaveRequested && app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle && !ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { LogWorldIO("autosave completed"); autosaveRequested = false; @@ -669,7 +671,7 @@ int main(int argc, char **argv) DWORD now = GetTickCount(); if ((LONG)(now - nextAutosaveTick) >= 0) { - if (app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle) + if (app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle && !ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { LogWorldIO("requesting autosave"); app.SetXuiServerAction(kServerActionPad, eXuiServerAction_AutoSaveGame); @@ -685,25 +687,38 @@ int main(int argc, char **argv) LogInfof("shutdown", "Dedicated server stopped"); MinecraftServer *server = MinecraftServer::getInstance(); - if (server != NULL) + if (server != nullptr && !ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { server->setSaveOnExit(true); - } - if (server != NULL) - { LogWorldIO("requesting save before shutdown"); LogWorldIO("using saveOnExit for shutdown"); } + if (ConsoleSaveFileOriginal::hasPendingBackgroundSave()) + { + LogWorldIO("Waiting for autosave to complete..."); + } + MinecraftServer::HaltServer(); if (g_NetworkManager.ServerStoppedValid()) { - C4JThread waitThread(&WaitForServerStoppedThreadProc, NULL, "WaitServerStopped"); + C4JThread waitThread(&WaitForServerStoppedThreadProc, nullptr, "WaitServerStopped"); waitThread.Run(); + while (waitThread.isRunning()) + { + TickCoreSystems(); + Sleep(10); + } waitThread.WaitForCompletion(INFINITE); } + while (ConsoleSaveFileOriginal::hasPendingBackgroundSave()) + { + TickCoreSystems(); + Sleep(10); + } + LogInfof("shutdown", "Cleaning up and exiting."); WinsockNetLayer::Shutdown(); LogDebugf("shutdown", "Network layer shutdown complete."); diff --git a/Minecraft.Server/cmake/sources/Common.cmake b/Minecraft.Server/cmake/sources/Common.cmake index a496a622..28ff00d4 100644 --- a/Minecraft.Server/cmake/sources/Common.cmake +++ b/Minecraft.Server/cmake/sources/Common.cmake @@ -480,6 +480,8 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/iob_shim.asm" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/stdafx.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/stubs.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/ConsoleSaveFileOriginal.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/ConsoleSaveFileOriginal.h" "${CMAKE_CURRENT_SOURCE_DIR}/Console/ServerCliInput.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Console/ServerCliInput.h" ) diff --git a/Minecraft.World/ConsoleSaveFileOriginal.cpp b/Minecraft.World/ConsoleSaveFileOriginal.cpp index 122d11c5..71a843e5 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/ConsoleSaveFileOriginal.cpp @@ -12,6 +12,25 @@ #include "..\Minecraft.Client\Common\GameRules\LevelGenerationOptions.h" #include "..\Minecraft.World\net.minecraft.world.level.chunk.storage.h" +#ifdef MINECRAFT_SERVER_BUILD +#include +#include +#include + +static std::atomic s_bgSaveActive{false}; +static std::mutex s_bgSaveMutex; + +struct BackgroundSaveResult +{ + ConsoleSaveFile *owner = nullptr; + PBYTE thumbData = nullptr; + DWORD thumbSize = 0; + BYTE textMeta[88] = {}; + int textMetaBytes = 0; + bool pending = false; +}; +static BackgroundSaveResult s_bgResult; +#endif #ifdef _XBOX #define RESERVE_ALLOCATION MEM_RESERVE | MEM_LARGE_PAGES @@ -678,6 +697,85 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) unsigned int fileSize = header.GetFileSize(); +#ifdef MINECRAFT_SERVER_BUILD + // on the server we dont want to block the tick thread doing compression!!! + // sna[pshot pvSaveMem while we still hold the lock then hand it off to a background thread + byte *snap = new (std::nothrow) byte[fileSize]; + if (snap) + { + // copy the save buffer while we still own the lock so nothing can write to it mid-copy + QueryPerformanceCounter(&qwTime); + memcpy(snap, pvSaveMem, fileSize); + QueryPerformanceCounter(&qwNewTime); + app.DebugPrintf("snapshot %u bytes in %.3f sec\n", fileSize, + (qwNewTime.QuadPart - qwTime.QuadPart) * fSecsPerTick); + + PBYTE thumb = nullptr; + DWORD thumbSz = 0; + app.GetSaveThumbnail(&thumb, &thumbSz); + + BYTE meta[88]; + ZeroMemory(meta, 88); + int64_t seed = 0; + bool hasSeed = false; + if (MinecraftServer *sv = MinecraftServer::getInstance(); sv && sv->levels[0]) + { + seed = sv->levels[0]->getLevelData()->getSeed(); + hasSeed = true; + } + int metaLen = app.CreateImageTextData(meta, seed, hasSeed, + app.GetGameHostOption(eGameHostOption_All), Minecraft::GetInstance()->getCurrentTexturePackId()); + + // telemetry + INT uid = 0; + StorageManager.GetSaveUniqueNumber(&uid); + TelemetryManager->RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), uid, fileSize); + + ReleaseSaveAccess(); + s_bgSaveActive.store(true, std::memory_order_release); + + std::thread([snap, fileSize, thumb, thumbSz, meta, metaLen, this]() + { + Compression::UseDefaultThreadStorage(); + unsigned int compLen = fileSize + 8; + byte *buf = static_cast(StorageManager.AllocateSaveData(compLen)); + if (!buf) + { + // FAIL!! attempt precalc + compLen = 0; + Compression::getCompression()->Compress(nullptr, &compLen, snap, fileSize); + compLen += 8; + buf = static_cast(StorageManager.AllocateSaveData(compLen)); + } + if (buf) + { + // COM,PRESS + Compression::getCompression()->Compress(buf + 8, &compLen, snap, fileSize); + ZeroMemory(buf, 8); + memcpy(buf + 4, &fileSize, sizeof(fileSize)); + + // store the result so flushPendingBackgroundSave() can pick it up on the main thread next tick + // StorageManager isnt thread safe so we cant call SetSaveImages or SaveSaveData from here. Bwoomp + std::lock_guard lk(s_bgSaveMutex); + s_bgResult.owner = this; + s_bgResult.thumbData = thumb; + s_bgResult.thumbSize = thumbSz; + memcpy(s_bgResult.textMeta, meta, sizeof(meta)); + s_bgResult.textMetaBytes = metaLen; + s_bgResult.pending = true; + } + else + { + app.DebugPrintf("save buf alloc failed\n"); + s_bgSaveActive.store(false, std::memory_order_release); + } + delete[] snap; + }).detach(); + return; + } + app.DebugPrintf("snapshot alloc failed (%u bytes)\n", fileSize); +#endif + // Assume that the compression will make it smaller so initially attempt to allocate the current file size // We add 4 bytes to the start so that we can signal compressed data // And another 4 bytes to store the decompressed data size @@ -843,6 +941,10 @@ int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes) { ConsoleSaveFile *pClass=static_cast(lpParam); +#ifdef MINECRAFT_SERVER_BUILD + s_bgSaveActive.store(false, std::memory_order_release); +#endif + return 0; } @@ -1090,3 +1192,25 @@ void *ConsoleSaveFileOriginal::getWritePointer(FileEntry *file) { return static_cast(pvSaveMem) + file->currentFilePointer;; } + +#ifdef MINECRAFT_SERVER_BUILD +void ConsoleSaveFileOriginal::flushPendingBackgroundSave() +{ + std::lock_guard lk(s_bgSaveMutex); + if (!s_bgResult.pending) + return; + + StorageManager.SetSaveImages( + s_bgResult.thumbData, s_bgResult.thumbSize, + nullptr, 0, s_bgResult.textMeta, s_bgResult.textMetaBytes); + StorageManager.SaveSaveData(&ConsoleSaveFileOriginal::SaveSaveDataCallback, s_bgResult.owner); + + s_bgResult.pending = false; + // the actual write isnt done until SaveSaveDataCallback fires +} + +bool ConsoleSaveFileOriginal::hasPendingBackgroundSave() +{ + return s_bgSaveActive.load(std::memory_order_acquire); +} +#endif \ No newline at end of file diff --git a/Minecraft.World/ConsoleSaveFileOriginal.h b/Minecraft.World/ConsoleSaveFileOriginal.h index 9c91fafc..453cacd9 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.h +++ b/Minecraft.World/ConsoleSaveFileOriginal.h @@ -77,6 +77,11 @@ public: virtual void LockSaveAccess(); virtual void ReleaseSaveAccess(); +#ifdef MINECRAFT_SERVER_BUILD + static void flushPendingBackgroundSave(); + static bool hasPendingBackgroundSave(); +#endif + virtual ESavePlatform getSavePlatform(); virtual bool isSaveEndianDifferent(); virtual void setLocalPlatform(); diff --git a/Minecraft.World/PathFinder.cpp b/Minecraft.World/PathFinder.cpp index eb3bd45e..cf42029f 100644 --- a/Minecraft.World/PathFinder.cpp +++ b/Minecraft.World/PathFinder.cpp @@ -210,58 +210,78 @@ int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size) int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size, bool avoidWater, bool canOpenDoors, bool canPassDoors) { bool walkable = false; + + int xt = Mth::floor(entity->x); + int yt = Mth::floor(entity->y); + int zt = Mth::floor(entity->z); + + //Use 4J XZY Loops order instead of Mojang XYZ Loops orders for (int xx = x; xx < x + size->x; xx++) - for (int yy = y; yy < y + size->y; yy++) - for (int zz = z; zz < z + size->z; zz++) + { + for (int zz = z; zz < z + size->z; zz++) + { + for (int yy = y; yy < y + size->y; yy++) { int tileId = entity->level->getTile(xx, yy, zz); - if(tileId <= 0) continue; - if (tileId == Tile::trapdoor_Id) walkable = true; + + if(tileId <= 0) + continue; + + if (tileId == Tile::trapdoor_Id) + walkable = true; + else if (tileId == Tile::water_Id || tileId == Tile::calmWater_Id) { - if (avoidWater) return TYPE_WATER; - else walkable = true; + if (avoidWater) + return TYPE_WATER; + + walkable = true; + continue; } else if (!canPassDoors && tileId == Tile::door_wood_Id) - { return TYPE_BLOCKED; - } Tile *tile = Tile::tiles[tileId]; // 4J Stu - Use new getTileRenderShape passing in the tileId we have already got if (entity->level->getTileRenderShape(tileId) == Tile::SHAPE_RAIL) { - int xt = Mth::floor(entity->x); - int yt = Mth::floor(entity->y); - int zt = Mth::floor(entity->z); if (entity->level->getTileRenderShape(xt, yt, zt) == Tile::SHAPE_RAIL - || entity->level->getTileRenderShape(xt, yt - 1, zt) == Tile::SHAPE_RAIL) + || entity->level->getTileRenderShape(xt, yt - 1, zt) == Tile::SHAPE_RAIL) { continue; } else - { return TYPE_FENCE; - } } - if (tile->isPathfindable(entity->level, xx, yy, zz)) continue; - if (canOpenDoors && tileId == Tile::door_wood_Id) continue; + if (tile->isPathfindable(entity->level, xx, yy, zz)) + continue; + + if (canOpenDoors && tileId == Tile::door_wood_Id) + continue; int renderShape = tile->getRenderShape(); - if (renderShape == Tile::SHAPE_FENCE || tileId == Tile::fenceGate_Id || renderShape == Tile::SHAPE_WALL) return TYPE_FENCE; - if (tileId == Tile::trapdoor_Id) return TYPE_TRAP; + if (renderShape == Tile::SHAPE_FENCE || tileId == Tile::fenceGate_Id || renderShape == Tile::SHAPE_WALL) + return TYPE_FENCE; + + if (tileId == Tile::trapdoor_Id) + return TYPE_TRAP; + Material *m = tile->material; if (m == Material::lava) { - if (entity->isInLava()) continue; + if (entity->isInLava()) + continue; + return TYPE_LAVA; } return TYPE_BLOCKED; } + } return walkable ? TYPE_WALKABLE : TYPE_OPEN; + } } // function reconstruct_path(came_from,current_node)