diff --git a/projects/visual-studio/Client/Client.vcxproj b/projects/visual-studio/Client/Client.vcxproj index 9befd92b4..3a8329cbe 100644 --- a/projects/visual-studio/Client/Client.vcxproj +++ b/projects/visual-studio/Client/Client.vcxproj @@ -110,7 +110,6 @@ - @@ -131,7 +130,6 @@ - @@ -258,6 +256,8 @@ + + @@ -290,7 +290,6 @@ - @@ -312,7 +311,6 @@ - @@ -434,6 +432,8 @@ + + diff --git a/projects/visual-studio/Client/Client.vcxproj.filters b/projects/visual-studio/Client/Client.vcxproj.filters index 55cd0f467..c600ccfb3 100644 --- a/projects/visual-studio/Client/Client.vcxproj.filters +++ b/projects/visual-studio/Client/Client.vcxproj.filters @@ -200,9 +200,6 @@ Header Files\GUI\Screens - - Header Files\GUI\Screens - Header Files\GUI\Screens @@ -269,9 +266,6 @@ Header Files\Renderer\Entity - - Header Files\Renderer - Header Files\Renderer @@ -677,6 +671,12 @@ Header Files\GUI\Screens\Inventory + + Header Files\Renderer + + + Header Files\Renderer + @@ -748,9 +748,6 @@ Source Files\GUI\Screens - - Source Files\GUI\Screens - Source Files\GUI\Screens @@ -817,9 +814,6 @@ Source Files\Renderer - - Source Files\Renderer - Source Files\Renderer @@ -1204,5 +1198,11 @@ Source Files\GUI\Screens\Inventory + + Source Files\Renderer + + + Source Files\Renderer + \ No newline at end of file diff --git a/projects/visual-studio/Common/Common.vcxproj b/projects/visual-studio/Common/Common.vcxproj index 9919fdce1..39f7c2c04 100644 --- a/projects/visual-studio/Common/Common.vcxproj +++ b/projects/visual-studio/Common/Common.vcxproj @@ -95,6 +95,10 @@ + + + + @@ -115,6 +119,14 @@ + + + + + + + + diff --git a/projects/visual-studio/Common/Common.vcxproj.filters b/projects/visual-studio/Common/Common.vcxproj.filters index 56d68fb15..930b37844 100644 --- a/projects/visual-studio/Common/Common.vcxproj.filters +++ b/projects/visual-studio/Common/Common.vcxproj.filters @@ -71,6 +71,18 @@ Source Files\Threading + + Source Files\Threading + + + Source Files\Threading + + + Source Files\Threading + + + Source Files + @@ -127,5 +139,29 @@ Header Files\Threading + + Header Files\Threading + + + Header Files\Threading + + + Header Files\Threading + + + Header Files\Threading + + + Header Files\Threading + + + Header Files + + + Header Files + + + Header Files + \ No newline at end of file diff --git a/projects/visual-studio/World/World.vcxproj b/projects/visual-studio/World/World.vcxproj index dd97f7b76..9c7b3cd7f 100644 --- a/projects/visual-studio/World/World.vcxproj +++ b/projects/visual-studio/World/World.vcxproj @@ -72,12 +72,9 @@ - - - @@ -99,19 +96,16 @@ - - - @@ -190,7 +184,6 @@ - @@ -202,7 +195,6 @@ - @@ -230,6 +222,18 @@ + + + + + + + + + + + + @@ -259,12 +263,9 @@ - - - @@ -273,19 +274,16 @@ - - - @@ -358,7 +356,6 @@ - @@ -370,7 +367,6 @@ - @@ -400,6 +396,26 @@ + + + + + + + + + + + + + + + + + + + + @@ -410,4 +426,4 @@ - + \ No newline at end of file diff --git a/projects/visual-studio/World/World.vcxproj.filters b/projects/visual-studio/World/World.vcxproj.filters index f923baca5..37bbd1c61 100644 --- a/projects/visual-studio/World/World.vcxproj.filters +++ b/projects/visual-studio/World/World.vcxproj.filters @@ -170,9 +170,6 @@ Source Files\Item - - Source Files\Level - Source Files\Level @@ -188,33 +185,21 @@ Source Files\Level - - Source Files\Level - Source Files\Level\LevelGen\Biome Source Files\Level\LevelGen\Biome - - Source Files\Level\LevelGen\Chunk - Source Files\Level\LevelGen\Chunk Source Files\Level\LevelGen\Chunk - - Source Files\Level\LevelGen\Chunk - Source Files\Level\LevelGen\Chunk - - Source Files\Level\LevelGen\Chunk - Source Files\Level\LevelGen\Feature @@ -284,9 +269,6 @@ Source Files\Level\Storage - - Source Files\Level\Storage - Source Files\Level\Storage @@ -545,9 +527,6 @@ Source Files\Level\LevelGen\Chunk - - Source Files\Level\LevelGen\Chunk - Source Files\Entity @@ -581,9 +560,6 @@ Source Files\Entity - - Source Files\Level\LevelGen\Chunk - Source Files @@ -665,6 +641,42 @@ Source Files\Item + + Source Files + + + Source Files\Level + + + Source Files\Level + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + + + Source Files\Level\LevelGen\Chunk + @@ -742,36 +754,21 @@ Header Files\Level - - Header Files\Level - - - Header Files\Level - Header Files\Level\LevelGen\Biome Header Files\Level\LevelGen\Biome - - Header Files\Level\LevelGen\Chunk - Header Files\Level\LevelGen\Chunk Header Files\Level\LevelGen\Chunk - - Header Files\Level\LevelGen\Chunk - Header Files\Level\LevelGen\Chunk - - Header Files\Level\LevelGen\Chunk - Header Files\Level\LevelGen\Feature @@ -802,9 +799,6 @@ Header Files\Level\Storage - - Header Files\Level\Storage - Header Files\Level\Storage @@ -1039,9 +1033,6 @@ Header Files\Level\LevelGen\Chunk - - Header Files\Level\LevelGen\Chunk - Header Files @@ -1084,9 +1075,6 @@ Header Files\Level - - Header Files\Level\LevelGen\Chunk - Header Files\Level @@ -1132,9 +1120,6 @@ Header Files\Item - - Header Files\Item - Header Files\Item @@ -1180,5 +1165,59 @@ Header Files\Item + + Header Files\Entity + + + Header Files\Level + + + Header Files\Level + + + Header Files\Level + + + Header Files\Level + + + Header Files\Level + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Level\LevelGen\Chunk + + + Header Files\Phys + - + \ No newline at end of file diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index e999e7790..230e711b1 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(nbcraft-core STATIC common/Random.cpp common/SmoothFloat.cpp common/Timer.cpp + common/Stopwatch.cpp common/Util.cpp common/utility/AlignmentHelper.cpp common/utility/JsonParser.cpp @@ -84,6 +85,7 @@ add_library(nbcraft-core STATIC client/renderer/FireTexture.cpp client/renderer/FoliageColor.cpp client/renderer/GrassColor.cpp + client/renderer/VisibilityExtimator.cpp client/renderer/LogoRenderer.cpp client/sound/SoundData.cpp client/sound/SoundPathRepository.cpp @@ -446,6 +448,7 @@ add_library(nbcraft-core STATIC world/tile/Web.cpp world/tile/FenceTile.cpp world/tile/CraftingTableTile.cpp + world/Facing.cpp renderer/GL/GL.cpp renderer/Attribute.cpp renderer/ConstantBufferMetaData.cpp diff --git a/source/client/app/Minecraft.cpp b/source/client/app/Minecraft.cpp index e6551e450..441de1d27 100644 --- a/source/client/app/Minecraft.cpp +++ b/source/client/app/Minecraft.cpp @@ -12,7 +12,6 @@ #include "client/gui/screens/PauseScreen.hpp" #include "client/gui/screens/StartMenuScreen.hpp" #include "client/gui/screens/RenameMPLevelScreen.hpp" -#include "client/gui/screens/SavingWorldScreen.hpp" #include "client/gui/screens/DeathScreen.hpp" #include "client/gui/screens/ProgressScreen.hpp" #include "client/gui/screens/ConvertWorldScreen.hpp" @@ -37,6 +36,7 @@ #include "client/player/input/Multitouch.hpp" #include "world/tile/SandTile.hpp" +#include "world/level/TileSource.hpp" #include "client/renderer/GrassColor.hpp" #include "client/renderer/FoliageColor.hpp" @@ -45,6 +45,8 @@ #include "renderer/RenderContextImmediate.hpp" #include "client/renderer/LogoRenderer.hpp" +#include "common/threading/BackgroundQueuePool.hpp" + float Minecraft::_renderScaleMultiplier = 1.0f; int Minecraft::width = C_DEFAULT_SCREEN_WIDTH; @@ -108,6 +110,8 @@ Minecraft::Minecraft() m_fLastUpdated = 0; m_fDeltaTime = 0; m_lastInteractTime = 0; + + BackgroundQueuePool::start(std::thread::hardware_concurrency()); } Minecraft::~Minecraft() @@ -428,7 +432,9 @@ void Minecraft::handleBuildAction(const BuildActionIntention& action) } case HitResult::TILE: { - Tile* pTile = Tile::tiles[m_pLevel->getTile(m_hitResult.m_tilePos)]; + TileSource& source = player->getTileSource(); + + Tile* pTile = Tile::tiles[source.getTile(m_hitResult.m_tilePos)]; if (action.isDestroy()) { @@ -456,7 +462,7 @@ void Minecraft::handleBuildAction(const BuildActionIntention& action) bool contDestory = m_pGameMode->continueDestroyBlock(player, m_hitResult.m_tilePos, m_hitResult.m_hitSide); destroyed = destroyed || contDestory; - m_pParticleEngine->crack(m_hitResult.m_tilePos, m_hitResult.m_hitSide); + m_pParticleEngine->crack(player, m_hitResult.m_tilePos, m_hitResult.m_hitSide); m_lastBlockBreakTime = getTimeMs(); @@ -470,13 +476,13 @@ void Minecraft::handleBuildAction(const BuildActionIntention& action) else if (action.isPick()) { // Try to pick the tile. - int auxValue = m_pLevel->getData(m_hitResult.m_tilePos); + TileData auxValue = source.getData(m_hitResult.m_tilePos); player->m_pInventory->pickItem(pTile->m_ID, auxValue, C_MAX_HOTBAR_ITEMS); } else if (action.isPlace() && canInteract) { ItemStack& item = getSelectedItem(); - if (m_pGameMode->useItemOn(player, m_pLevel, item, m_hitResult.m_tilePos, m_hitResult.m_hitSide)) + if (m_pGameMode->useItemOn(player, item, m_hitResult.m_tilePos, m_hitResult.m_hitSide)) { bInteract = false; @@ -497,7 +503,7 @@ void Minecraft::handleBuildAction(const BuildActionIntention& action) if (!item.isEmpty()) { m_lastInteractTime = getTimeMs(); - if (m_pGameMode->useItem(player, m_pLevel, item)) + if (m_pGameMode->useItem(player, item)) m_pGameRenderer->m_pItemInHandRenderer->itemUsed(); } } @@ -751,22 +757,16 @@ void Minecraft::freeResources(bool bCopyMap) m_pCameraEntity = nullptr; m_pLocalPlayer = nullptr; -#ifndef ENH_IMPROVED_SAVING if (bCopyMap) setScreen(new RenameMPLevelScreen("_LastJoinedServer")); else gotoMainMenu(); -#endif m_pGameRenderer->setLevel(nullptr, nullptr); delete m_pNetEventCallback; m_pNetEventCallback = nullptr; -#ifdef ENH_IMPROVED_SAVING - m_bIsGamePaused = true; - setScreen(new SavingWorldScreen(bCopyMap/*, m_pLocalPlayer*/)); -#else if (m_pLevel) { LevelStorage* pStorage = m_pLevel->getLevelStorage(); @@ -775,7 +775,6 @@ void Minecraft::freeResources(bool bCopyMap) m_pLevel = nullptr; } -#endif field_D9C = 0; } @@ -829,7 +828,7 @@ void Minecraft::tick() if (m_pLocalPlayer) { - m_pLevel->animateTick(m_pLocalPlayer->m_pos); + m_pLevel->animateTick(m_pLocalPlayer); } } @@ -878,6 +877,8 @@ void Minecraft::update() m_pSoundEngine->update(); #endif + BackgroundQueuePool::getInstance().processCoroutines(); + mce::RenderContext& renderContext = mce::RenderContextImmediate::get(); renderContext.beginRender(); @@ -902,6 +903,7 @@ void Minecraft::init() void Minecraft::prepareLevel(const std::string& unused) { + // @TODO: redo this function field_DA0 = 1; float startTime = float(getTimeS()); @@ -1105,7 +1107,7 @@ void Minecraft::onClientStartedLevel(Level* pLevel, LocalPlayer* pLocalPlayer) setupLevelRendering(pLevel, pLocalPlayer->getDimension(), pLocalPlayer); } -void Minecraft::generateLevel(const std::string& unused, Level* pLevel) +void Minecraft::generateLevel(const std::string& unused, Level& level) { float time = float(getTimeS()); //@UNUSED @@ -1119,7 +1121,7 @@ void Minecraft::generateLevel(const std::string& unused, Level* pLevel) LocalPlayer* pLocalPlayer = m_pLocalPlayer; if (!pLocalPlayer) { - pLocalPlayer = m_pGameMode->createPlayer(pLevel); + pLocalPlayer = m_pGameMode->createPlayer(level); pLocalPlayer->resetPos(); m_pGameMode->initPlayer(pLocalPlayer); } @@ -1129,8 +1131,8 @@ void Minecraft::generateLevel(const std::string& unused, Level* pLevel) m_pGameMode->adjustPlayer(pLocalPlayer); - pLevel->validateSpawn(); - pLevel->loadPlayer(*pLocalPlayer); + level.validateSpawn(); + level.loadPlayer(*pLocalPlayer); m_pLocalPlayer = pLocalPlayer; @@ -1144,7 +1146,7 @@ void* Minecraft::prepareLevel_tspawn(void* ptr) { Minecraft* pMinecraft = (Minecraft*)ptr; - pMinecraft->generateLevel("Currently not used", pMinecraft->m_pLevel); + pMinecraft->generateLevel("Currently not used", *pMinecraft->m_pLevel); return nullptr; } @@ -1226,9 +1228,8 @@ void Minecraft::selectLevel(const LevelSummary& ls, bool forceConversion) void Minecraft::selectLevel(const std::string& levelDir, const std::string& levelName, const LevelSettings& levelSettings, bool forceConversion) { LevelStorage* pStor = m_pLevelStorageSource->selectLevel(levelDir, false, forceConversion); - Dimension* pDim = Dimension::createNew(DIMENSION_OVERWORLD); - m_pLevel = new Level(pStor, levelName, levelSettings, LEVEL_STORAGE_VERSION_DEFAULT, pDim); + m_pLevel = new Level(pStor, levelName, levelSettings, LEVEL_STORAGE_VERSION_DEFAULT); setLevel(m_pLevel, "Generating level", nullptr); field_D9C = 1; diff --git a/source/client/app/Minecraft.hpp b/source/client/app/Minecraft.hpp index edd594852..95fd0fb91 100644 --- a/source/client/app/Minecraft.hpp +++ b/source/client/app/Minecraft.hpp @@ -100,7 +100,7 @@ class Minecraft : public App float getBestScaleForThisScreenSize(int width, int height); void setupLevelRendering(Level* pLevel, Dimension* pDimension, Mob* pCamera); void onClientStartedLevel(Level* pLevel, LocalPlayer* pLocalPlayer); - void generateLevel(const std::string& unused, Level* pLevel); + void generateLevel(const std::string& unused, Level& level); void prepareLevel(const std::string& unused); bool isOnline() const; bool isOnlineClient() const; diff --git a/source/client/app/NinecraftApp.cpp b/source/client/app/NinecraftApp.cpp index 1c7bd839c..90d8f3ffe 100644 --- a/source/client/app/NinecraftApp.cpp +++ b/source/client/app/NinecraftApp.cpp @@ -10,6 +10,7 @@ #include "world/item/Item.hpp" #include "world/entity/MobCategory.hpp" #include "world/entity/MobFactory.hpp" +#include "world/level/levelgen/biome/Biome.hpp" #include "client/player/input/GameControllerHandler.hpp" #include "client/player/input/Multitouch.hpp" #include "client/gui/screens/StartMenuScreen.hpp" diff --git a/source/client/gui/Screen.cpp b/source/client/gui/Screen.cpp index 5c029da2b..3bbc4532f 100644 --- a/source/client/gui/Screen.cpp +++ b/source/client/gui/Screen.cpp @@ -365,7 +365,9 @@ void Screen::renderConsolePanorama(bool isNight) void Screen::renderConsolePanorama() { - renderConsolePanorama(m_pMinecraft->m_pLevel && !m_pMinecraft->m_pLevel->isDay()); + Level* pLevel = m_pMinecraft->m_pLevel; + Dimension* pOverworld = pLevel ? pLevel->getDimension(DIMENSION_OVERWORLD) : nullptr; + renderConsolePanorama(pOverworld && pOverworld->isDay()); } void Screen::renderConsoleLoading(int x, int y, int blockSize, int blockDistance) diff --git a/source/client/gui/screens/ProgressScreen.cpp b/source/client/gui/screens/ProgressScreen.cpp index fa881e884..dcc690207 100644 --- a/source/client/gui/screens/ProgressScreen.cpp +++ b/source/client/gui/screens/ProgressScreen.cpp @@ -8,6 +8,17 @@ #include "ProgressScreen.hpp" #include "client/app/Minecraft.hpp" +#include "common/threading/BackgroundQueuePool.hpp" + +ProgressScreen::~ProgressScreen() +{ + BackgroundQueuePool::getInstance().setMainThreadHasPriority(true); +} + +void ProgressScreen::init() +{ + BackgroundQueuePool::getInstance().setMainThreadHasPriority(false); +} bool ProgressScreen::isInGameScreen() { diff --git a/source/client/gui/screens/ProgressScreen.hpp b/source/client/gui/screens/ProgressScreen.hpp index 97bac0b9e..1f4c89094 100644 --- a/source/client/gui/screens/ProgressScreen.hpp +++ b/source/client/gui/screens/ProgressScreen.hpp @@ -13,6 +13,10 @@ class ProgressScreen : public Screen { public: + virtual ~ProgressScreen(); + +public: + void init() override; void render(float f) override; void updateEvents() override; bool isInGameScreen() override; diff --git a/source/client/gui/screens/SavingWorldScreen.cpp b/source/client/gui/screens/SavingWorldScreen.cpp deleted file mode 100644 index bf165d5d5..000000000 --- a/source/client/gui/screens/SavingWorldScreen.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "SavingWorldScreen.hpp" -#include "RenameMPLevelScreen.hpp" -#include "StartMenuScreen.hpp" - -#ifdef ENH_IMPROVED_SAVING - -SavingWorldScreen::SavingWorldScreen(bool bCopyMap/*, Entity* pEnt*/) -{ - m_bCopyMapAtEnd = bCopyMap; - m_timer = 0; - //m_pEntityToDeleteAfterSave = pEnt; -} - -void SavingWorldScreen::render(float f) -{ - renderDirtBackground(0); - - int x_width = int(Minecraft::width * Gui::GuiScale); - int x_height = int(Minecraft::height * Gui::GuiScale); - int yPos = x_height / 2; - - int width = m_pFont->width("Saving chunks"); - m_pFont->drawShadow("Saving chunks", (x_width - width) / 2, yPos, 0xFFFFFF); -} - -void SavingWorldScreen::tick() -{ - if (m_timer < 0) - return; - - m_timer++; - - if (m_timer >= 5) - { - m_timer = -1; - - Level* pLevel = m_pMinecraft->m_pLevel; - if (pLevel) - { - pLevel->saveUnsavedChunks(); - pLevel->saveLevelData(); - pLevel->savePlayerData(); - - LevelStorage* pStorage = pLevel->getLevelStorage(); - SAFE_DELETE(pStorage); - SAFE_DELETE(pLevel); - - m_pMinecraft->m_pLevel = nullptr; - } - - // this is safe to do, since on destruction, nothing accesses the parent level or anything - //SAFE_DELETE(m_pEntityToDeleteAfterSave); - // already done by the Level - - m_pMinecraft->m_pCameraEntity = m_pMinecraft->m_pLocalPlayer = nullptr; - - - m_pMinecraft->m_bUsingScreen = true; - - if (m_bCopyMapAtEnd) - m_pMinecraft->setScreen(new RenameMPLevelScreen("_LastJoinedServer")); - else - m_pMinecraft->gotoMainMenu(); - - m_pMinecraft->m_bUsingScreen = false; - - m_pMinecraft->m_bIsGamePaused = false; - } -} - -#endif diff --git a/source/client/gui/screens/SavingWorldScreen.hpp b/source/client/gui/screens/SavingWorldScreen.hpp deleted file mode 100644 index c755516bb..000000000 --- a/source/client/gui/screens/SavingWorldScreen.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include "../Screen.hpp" - -#ifdef ENH_IMPROVED_SAVING - -class Entity; - -class SavingWorldScreen : public Screen -{ -public: - SavingWorldScreen(bool bCopyMap/*, Entity* pEntityToDeleteAfterSave*/); - - void render(float f) override; - void tick() override; - -public: - bool m_bCopyMapAtEnd; - int m_timer; - //Entity* m_pEntityToDeleteAfterSave; -}; - -#endif diff --git a/source/client/multiplayer/MultiPlayerLevel.cpp b/source/client/multiplayer/MultiPlayerLevel.cpp index 1890674d5..e4acf3dc9 100644 --- a/source/client/multiplayer/MultiPlayerLevel.cpp +++ b/source/client/multiplayer/MultiPlayerLevel.cpp @@ -1,14 +1,15 @@ #include "MultiPlayerLevel.hpp" -MultiPlayerLevel::MultiPlayerLevel(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion, Dimension* pDimension) - : Level(pStor, name, settings, storageVersion, pDimension) +MultiPlayerLevel::MultiPlayerLevel(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion) + : Level(pStor, name, settings, storageVersion) { } void MultiPlayerLevel::tick() { - _setTime(getTime() + 1); // Bypasses the normally-required update to LevelListeners - updateSkyDarken(); + Level::tick(); + + setTime(getTime() + 1); for (size_t i = 0; i < 10 && i < m_reEntries.size(); i++) { @@ -30,11 +31,6 @@ void MultiPlayerLevel::tick() } } -ChunkSource* MultiPlayerLevel::createChunkSource() -{ - return nullptr; -} - void MultiPlayerLevel::putEntity(int id, Entity* e) { Entity* old = getEntity(id); diff --git a/source/client/multiplayer/MultiPlayerLevel.hpp b/source/client/multiplayer/MultiPlayerLevel.hpp index 09fbede67..a3b58b8f4 100644 --- a/source/client/multiplayer/MultiPlayerLevel.hpp +++ b/source/client/multiplayer/MultiPlayerLevel.hpp @@ -22,16 +22,15 @@ class MultiPlayerLevel : public Level }; public: - MultiPlayerLevel(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion = LEVEL_STORAGE_VERSION_DEFAULT, Dimension* pDimension = nullptr); + MultiPlayerLevel(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion = LEVEL_STORAGE_VERSION_DEFAULT); public: void tick() override; - ChunkSource* createChunkSource() override; void putEntity(int id, Entity* e); private: std::vector m_updatesToReset; std::map m_entitiesById; - EntityVector m_forced; - EntityVector m_reEntries; + Entity::Vector m_forced; + Entity::Vector m_reEntries; }; diff --git a/source/client/multiplayer/MultiplayerLocalPlayer.cpp b/source/client/multiplayer/MultiplayerLocalPlayer.cpp index a6b9c9099..f7e0eac64 100644 --- a/source/client/multiplayer/MultiplayerLocalPlayer.cpp +++ b/source/client/multiplayer/MultiplayerLocalPlayer.cpp @@ -3,8 +3,8 @@ #include "network/RakNetInstance.hpp" #include "world/level/Level.hpp" -MultiplayerLocalPlayer::MultiplayerLocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, GameType gameType, int dimensionId) - : LocalPlayer(pMinecraft, pLevel, pUser, gameType, dimensionId) +MultiplayerLocalPlayer::MultiplayerLocalPlayer(Minecraft* pMinecraft, Level& level, User* pUser, GameType gameType, DimensionId dimensionId) + : LocalPlayer(pMinecraft, level, pUser, gameType, dimensionId) { m_flashOnSetHealth = false; diff --git a/source/client/multiplayer/MultiplayerLocalPlayer.hpp b/source/client/multiplayer/MultiplayerLocalPlayer.hpp index d1a7e2bec..484debc5f 100644 --- a/source/client/multiplayer/MultiplayerLocalPlayer.hpp +++ b/source/client/multiplayer/MultiplayerLocalPlayer.hpp @@ -6,7 +6,7 @@ class MultiplayerLocalPlayer : public LocalPlayer, public ContainerListener { public: - MultiplayerLocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, GameType gameType, int dimensionId); + MultiplayerLocalPlayer(Minecraft* pMinecraft, Level& level, User* pUser, GameType gameType, DimensionId dimensionId); protected: void reallyDrop(ItemEntity* itemEntity) override; diff --git a/source/client/network/ClientSideNetworkHandler.cpp b/source/client/network/ClientSideNetworkHandler.cpp index 2d26f71fb..82ea5e883 100644 --- a/source/client/network/ClientSideNetworkHandler.cpp +++ b/source/client/network/ClientSideNetworkHandler.cpp @@ -18,6 +18,7 @@ #include "world/entity/EntityFactory.hpp" #include "world/entity/PrimedTnt.hpp" #include "world/level/Explosion.hpp" +#include "world/level/TileSource.hpp" #include "world/inventory/SimpleContainer.hpp" // This lets you make the client shut up and not log events in the debug console. @@ -145,7 +146,8 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, StartGa m_pLevel->m_bIsClientSide = true; - MultiplayerLocalPlayer *pLocalPlayer = new MultiplayerLocalPlayer(m_pMinecraft, m_pLevel, m_pMinecraft->m_pUser, settings.m_gameType, m_pLevel->m_pDimension->m_id); + DimensionId dimensionId = DIMENSION_OVERWORLD; + MultiplayerLocalPlayer *pLocalPlayer = new MultiplayerLocalPlayer(m_pMinecraft, *m_pLevel, m_pMinecraft->m_pUser, settings.m_gameType, dimensionId); pLocalPlayer->m_guid = ((RakNet::RakPeer*)m_pServerPeer)->GetMyGUID(); pLocalPlayer->m_EntityID = pStartGamePkt->m_entityId; @@ -172,7 +174,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddPlay if (!m_pLevel) return; - Player* pPlayer = new Player(m_pLevel, m_pLevel->getDefaultGameType()); + Player* pPlayer = new Player(*m_pLevel, m_pLevel->getDefaultGameType()); pPlayer->m_EntityID = pAddPlayerPkt->m_id; m_pLevel->addEntity(pPlayer); @@ -214,7 +216,9 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddMobP return; } - Entity* entity = MobFactory::CreateMob(entityTypeId, m_pLevel); + Dimension& dimension = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + TileSource& tileSource = *dimension.getTileSource(); + Entity* entity = MobFactory::CreateMob(entityTypeId, tileSource); // Mojang, in all of their infinite wisdon, does not have this check here in 0.2.1, // so the game will just crash if you replicate a mob it can't create. if (!entity) @@ -246,7 +250,10 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddEnti return; } - Entity* entity = EntityFactory::CreateEntity(entityTypeId, m_pLevel); + Dimension& dimension = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + TileSource& tileSource = *dimension.getTileSource(); + + Entity* entity = EntityFactory::CreateEntity(entityTypeId, tileSource); if (!entity) { LOG_E("Server tried to add an unknown entity type! :%d", entityTypeId); @@ -296,7 +303,10 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, AddItem return; } - ItemEntity* pItemEntity = new ItemEntity(m_pLevel, packet->m_pos, itemStack); + Dimension& dimension = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + TileSource& tileSource = *dimension.getTileSource(); + + ItemEntity* pItemEntity = new ItemEntity(tileSource, packet->m_pos, itemStack); pItemEntity->m_vel.x = packet->m_velX * (1.f / 128.f); pItemEntity->m_vel.y = packet->m_velY * (1.f / 128.f); @@ -395,19 +405,22 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlaceBl if (!areAllChunksLoaded()) return; + Dimension& dimension = *pPlayer->getDimension(); + TileSource& tileSource = *dimension.getTileSource(); + const TilePos& pos = pPlaceBlockPkt->m_pos; TileID tileTypeId = pPlaceBlockPkt->m_tileTypeId; Facing::Name face = (Facing::Name)pPlaceBlockPkt->m_face; - if (!m_pLevel->mayPlace(tileTypeId, pos, true)) + if (!tileSource.mayPlace(tileTypeId, pos, face, pPlayer, true)) return; Tile* pTile = Tile::tiles[tileTypeId]; - if (!m_pLevel->setTile(pos, tileTypeId)) + if (!tileSource.setTile(pos, tileTypeId)) return; - pTile->setPlacedOnFace(m_pLevel, pos, face); - pTile->setPlacedBy(m_pLevel, pos, pPlayer); + pTile->setPlacedOnFace(&tileSource, pos, face); + pTile->setPlacedBy(&tileSource, pos, pPlayer); const Tile::SoundType* pSound = pTile->m_pSound; m_pLevel->playSound(pos + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->volume), 0.8f * pSound->pitch); @@ -434,19 +447,22 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, RemoveB if (!areAllChunksLoaded()) return; + Dimension& dimension = *pPlayer->getDimension(); + TileSource& tileSource = *dimension.getTileSource(); + const TilePos& pos = pRemoveBlockPkt->m_pos; - Tile* pTile = Tile::tiles[m_pLevel->getTile(pos)]; - int auxValue = m_pLevel->getData(pos); + Tile* pTile = Tile::tiles[tileSource.getTile(pos)]; + int auxValue = tileSource.getData(pos); - m_pMinecraft->m_pParticleEngine->destroyEffect(pos); + m_pMinecraft->m_pParticleEngine->destroyEffect(pPlayer, pos); - bool setTileResult = m_pLevel->setTile(pos, TILE_AIR); + bool setTileResult = tileSource.setTile(pos, TILE_AIR); if (pTile && setTileResult) { const Tile::SoundType* pSound = pTile->m_pSound; m_pLevel->playSound(pos + 0.5f, "step." + pSound->m_name, 0.5f * (1.0f + pSound->volume), 0.8f * pSound->pitch); - pTile->destroy(m_pLevel, pos, auxValue); + pTile->destroy(&tileSource, pos, auxValue); } } @@ -469,7 +485,10 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, Explode { if (!m_pLevel) return; - Explosion explosion(m_pLevel, nullptr, pkt->m_pos, pkt->m_range); + Dimension& dimension = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + TileSource& tileSource = *dimension.getTileSource(); + + Explosion explosion(tileSource, nullptr, pkt->m_pos, pkt->m_range); explosion.addParticles(); // @TODO: have addParticles pick random spots to throw particles } @@ -507,14 +526,20 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, ChunkDa return; } - LevelChunk* pChunk = m_pLevel->getChunkSource()->create(pChunkDataPkt->m_chunkPos); - if (!pChunk || pChunk->isEmpty()) + Dimension& dimension = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + ChunkSource& chunkSource = *dimension.getChunkSource(); + + // @TODO: is this the right method call? + LevelChunk* pChunk = chunkSource.getOrLoadChunk(pChunkDataPkt->m_chunkPos, ChunkSource::LOAD_NONE); + if (!pChunk /* || pChunk->isEmpty()*/) { LOG_E("Failed to find write-able chunk"); // @BUG: Not trying again. return; } + TileSource& tileSource = *dimension.getTileSource(); + int x16 = 16 * pChunkDataPkt->m_chunkPos.x; int z16 = 16 * pChunkDataPkt->m_chunkPos.z; @@ -545,11 +570,11 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, ChunkDa for (int i = 0; i < 16; i++) { - m_pLevel->setTileNoUpdate(TilePos(x16 + (k & 0xF), yPos + i, z16 + (k >> 4)), tiles[i]); + tileSource.setTileNoUpdate(TilePos(x16 + (k & 0xF), yPos + i, z16 + (k >> 4)), tiles[i]); } int idx = ((k & 0xF) << 11) | (((k >> 4) << 7) + yPos); - memcpy(&pChunk->m_tileData.m_data[idx >> 1], datas, sizeof datas); + memcpy(&pChunk->getTiles()[idx >> 1], datas, sizeof datas); } int ymin = 16 * (1 << j); @@ -1024,5 +1049,8 @@ void ClientSideNetworkHandler::flushAllBufferedUpdates() void ClientSideNetworkHandler::handleBlockUpdate(const BlockUpdate& u) { - m_pLevel->setTileAndData(u.pos, Tile::TransformToValidBlockId(u.tile), u.data); + Dimension& dimension = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + TileSource& tileSource = *dimension.getTileSource(); + + tileSource.setTile(u.pos, Tile::TransformToValidBlockId(u.tile), u.data); } diff --git a/source/client/player/LocalPlayer.cpp b/source/client/player/LocalPlayer.cpp index a328dbe5c..ae89870d1 100644 --- a/source/client/player/LocalPlayer.cpp +++ b/source/client/player/LocalPlayer.cpp @@ -13,6 +13,7 @@ #include "network/packets/PlayerEquipmentPacket.hpp" #include "client/gui/screens/inventory/CraftingScreen.hpp" #include "client/gui/screens/inventory/ChestScreen.hpp" +#include "world/level/TileSource.hpp" int dword_250ADC, dword_250AE0; @@ -29,7 +30,7 @@ void LocalPlayer::_init() m_lastSelectedSlot = m_pInventory->getSelectedItemId(); } -LocalPlayer::LocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, GameType playerGameType, int dimensionId) : Player(pLevel, playerGameType) +LocalPlayer::LocalPlayer(Minecraft* pMinecraft, Level& level, User* pUser, GameType playerGameType, DimensionId dimensionId) : Player(level, playerGameType) { field_BEC = 0; field_BF0 = Vec3::ZERO; @@ -296,18 +297,18 @@ void LocalPlayer::move(const Vec3& pos) int x1 = Mth::floor(pos.x / dist + m_pos.x); int z1 = Mth::floor(pos.z / dist + m_pos.z); - TileID tileOnTop = m_pLevel->getTile(TilePos(x1, int(m_pos.y - 1.0f), z1)); + TileID tileOnTop = m_tileSource->getTile(TilePos(x1, int(m_pos.y - 1.0f), z1)); // not standing on top of a tile? - if (!m_pLevel->isSolidTile(TilePos(x1, int(m_pos.y - 1.0f), z1))) + if (!m_tileSource->isSolidBlockingTile(TilePos(x1, int(m_pos.y - 1.0f), z1))) return; // aren't inside of a tile right now - if (m_pLevel->isSolidTile(TilePos(x1, int(m_pos.y), z1))) + if (m_tileSource->isSolidBlockingTile(TilePos(x1, int(m_pos.y), z1))) return; // don't have anything on top of us - if (m_pLevel->isSolidTile(TilePos(x1, int(m_pos.y + 1.0f), z1))) + if (m_tileSource->isSolidBlockingTile(TilePos(x1, int(m_pos.y + 1.0f), z1))) return; // are we trying to walk into stairs or a slab? diff --git a/source/client/player/LocalPlayer.hpp b/source/client/player/LocalPlayer.hpp index 1eecb1288..bc62f87e2 100644 --- a/source/client/player/LocalPlayer.hpp +++ b/source/client/player/LocalPlayer.hpp @@ -20,7 +20,7 @@ class LocalPlayer : public Player void _init(); public: - LocalPlayer(Minecraft*, Level*, User*, GameType, int); + LocalPlayer(Minecraft*, Level&, User*, GameType, DimensionId); virtual ~LocalPlayer(); public: diff --git a/source/client/renderer/Chunk.cpp b/source/client/renderer/Chunk.cpp deleted file mode 100644 index 86ece3261..000000000 --- a/source/client/renderer/Chunk.cpp +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "Chunk.hpp" -#include "renderer/RenderContextImmediate.hpp" -#include "world/level/Level.hpp" -#include "world/level/Region.hpp" -#include "TileRenderer.hpp" - -int Chunk::updates; - -float Chunk::distanceToSqr(const Entity& entity) const -{ - float dX = entity.m_pos.x - float(m_posM.x); - float dY = entity.m_pos.y - float(m_posM.y); - float dZ = entity.m_pos.z - float(m_posM.z); - return dX * dX + dY * dY + dZ * dZ; -} -float Chunk::squishedDistanceToSqr(const Entity& entity) const -{ - float dX = entity.m_pos.x - float(m_posM.x); - float dY = entity.m_pos.y - float(m_posM.y); - float dZ = entity.m_pos.z - float(m_posM.z); - - dY *= 2; - - return dX * dX + dY * dY + dZ * dZ; -} - -void Chunk::reset() -{ - for (int i = Tile::RENDER_LAYERS_MIN; i <= Tile::RENDER_LAYERS_MAX; i++) - { - m_empty[i] = true; - } - m_bVisible = false; - m_bCompiled = false; -} - -int Chunk::getList(Tile::RenderLayer layer) -{ - if (!m_bVisible) - return -1; - - if (m_empty[layer]) - return -1; - - return m_lists + layer; -} - -RenderChunk* Chunk::getRenderChunk(Tile::RenderLayer layer) -{ - return &m_renderChunks[layer]; -} - -int Chunk::getAllLists(int* displayLists, int p, Tile::RenderLayer layer) -{ - if (!m_bVisible) - return p; - - if (m_empty[layer]) - return p; - - displayLists[p++] = m_lists + layer; - - return p; -} - -void Chunk::cull(Culler* pCuller) -{ - m_bVisible = pCuller->isVisible(m_aabb); -} - -void Chunk::renderBB() -{ - //glCallList(m_lists + 2); -} - -bool Chunk::isEmpty() -{ - if (!m_bCompiled) - return false; - - for (int i = Tile::RENDER_LAYERS_MIN; i <= Tile::RENDER_LAYERS_MAX; i++) - { - if (!m_empty[i]) - return false; - } - - return true; -} - -void Chunk::setDirty() -{ - m_bDirty = true; -} - -void Chunk::setPos(const TilePos& pos) -{ - if (m_pos == pos) - // No change. - return; - - m_pos = pos; - m_posM = pos + m_posS / 2; - - m_aabb = AABB(m_pos - 1, m_pos + m_posS + 1); - - setDirty(); -} - -void Chunk::setClean() -{ - m_bDirty = false; -} - -bool Chunk::isDirty() -{ - return m_bDirty; -} - -void Chunk::rebuild() -{ - if (!m_bDirty) - return; - - updates++; - - LevelChunk::touchedSky = false; - - for (int i = Tile::RENDER_LAYERS_MIN; i <= Tile::RENDER_LAYERS_MAX; i++) - { - m_empty[i] = true; - } - - TilePos min(m_pos), max(m_pos + m_posS); - Region region(m_pLevel, min - 1, max + 1); - - mce::RenderContext& renderContext = mce::RenderContextImmediate::get(); - Tesselator& t = Tesselator::instance; - TileRenderer tileRenderer(t, ®ion); - - TilePos tp(min); - for (int layer = Tile::RENDER_LAYERS_MIN; layer <= Tile::RENDER_LAYERS_MAX; layer++) - { - bool started = false, rendered = false, renderNextLayer = false; - for (tp.y = min.y; tp.y < max.y; tp.y++) - { - for (tp.z = min.z; tp.z < max.z; tp.z++) - { - for (tp.x = min.x; tp.x < max.x; tp.x++) - { - TileID tile = region.getTile(tp); - if (tile <= 0) continue; - - if (!started) - { - started = true; - if (tileRenderer.useAmbientOcclusion()) - { - renderContext.setShadeMode(mce::SHADE_MODE_SMOOTH); - } - t.begin(12000); - t.setOffset(-m_pos); - } - - Tile* pTile = Tile::tiles[tile]; - - if (layer == pTile->getRenderLayer()) - { - if (tileRenderer.tesselateInWorld(pTile, tp)) - rendered = true; - } - else - { - renderNextLayer = true; - } - } - } - } - - if (started) - { - mce::Mesh chunkMesh = t.end(); - RenderChunk* pRChk = &m_renderChunks[layer]; - - *pRChk = RenderChunk(m_pos, chunkMesh); - - t.setOffset(Vec3::ZERO); - - if (rendered) - m_empty[layer] = false; - } - - if (!renderNextLayer) - break; - } - - field_54 = LevelChunk::touchedSky; - m_bCompiled = true; -} - -Chunk::Chunk(Level* level, const TilePos& pos, int size, int lists) -{ - m_bOcclusionVisible = true; - m_bOcclusionQuerying = false; - m_bCompiled = false; - m_bDirty = false; - - m_pLevel = level; - m_posS = TilePos(size, size, size); - m_pTesselator = &Tesselator::instance; - m_lists = lists; - m_pos.x = -999; - field_2C = Vec3(pos).lengthSqr() / 2; - - reset(); - setPos(pos); -} diff --git a/source/client/renderer/Chunk.hpp b/source/client/renderer/Chunk.hpp deleted file mode 100644 index 5f575c0d8..000000000 --- a/source/client/renderer/Chunk.hpp +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include "client/renderer/renderer/Tesselator.hpp" -#include "world/tile/Tile.hpp" -#include "FrustumCuller.hpp" -#include "RenderList.hpp" - -class Level; -class Entity; - -class Chunk -{ -public: - Chunk(Level*, const TilePos& pos, int, int); - -public: - float distanceToSqr(const Entity& entity) const; - float squishedDistanceToSqr(const Entity& entity) const; - void reset(); - int getList(Tile::RenderLayer layer); - RenderChunk* getRenderChunk(Tile::RenderLayer layer); - int getAllLists(int* displayLists, int p, Tile::RenderLayer layer); - void cull(Culler* pCuller); - void renderBB(); - bool isEmpty(); - void setDirty(); - void setPos(const TilePos& pos); - void setClean(); - bool isDirty(); - void rebuild(); - -public: - static int updates; - -public: - Level* m_pLevel; - TilePos m_pos; - TilePos m_posS; - bool m_empty[Tile::RENDER_LAYERS_COUNT]; - TilePos m_posM; - float field_2C; - AABB m_aabb; - int m_id; - bool m_bVisible; - bool m_bOcclusionVisible; - bool m_bOcclusionQuerying; - int m_occlusionId; - bool field_54; - RenderChunk m_renderChunks[Tile::RENDER_LAYERS_COUNT]; - Tesselator* m_pTesselator; -private: - int m_lists; -public: - bool m_bCompiled; - bool m_bDirty; -}; - diff --git a/source/client/renderer/GameRenderer.cpp b/source/client/renderer/GameRenderer.cpp index 413d1115f..a88ef4772 100644 --- a/source/client/renderer/GameRenderer.cpp +++ b/source/client/renderer/GameRenderer.cpp @@ -17,6 +17,7 @@ #include "renderer/GL/GL.hpp" #include "renderer/GlobalConstantBuffers.hpp" #include "renderer/RenderContextImmediate.hpp" +#include "world/level/TileSource.hpp" #include "thirdparty/glm/glm.hpp" //#define SHOW_VERTEX_COUNTER_GRAPHIC @@ -175,14 +176,15 @@ void GameRenderer::_renderDebugOverlay(float a) */ if (m_pMinecraft->m_pLocalPlayer && !m_pMinecraft->m_bPreparingLevel) { + LocalPlayer& player = *m_pMinecraft->m_pLocalPlayer; char posStr[96]; - Vec3 pos = m_pMinecraft->m_pLocalPlayer->getPos(a); + Vec3 pos = player.getInterpolatedPosition(a); sprintf(posStr, "%.2f / %.2f / %.2f", pos.x, pos.y, pos.z); debugText << m_pMinecraft->m_pLevelRenderer->gatherStats1(); debugText << m_pMinecraft->m_pLevelRenderer->gatherStats2() << "\n"; debugText << "XYZ: " << posStr << "\n"; - debugText << "Biome: " << m_pMinecraft->m_pLevel->getBiomeSource()->getBiome(pos)->m_name << "\n"; + debugText << "Biome: " << player.getTileSource().getBiome(pos).m_name << "\n"; } #ifdef SHOW_VERTEX_COUNTER_GRAPHIC @@ -303,13 +305,14 @@ void GameRenderer::setupCamera(float f, int i) void GameRenderer::moveCameraToPlayer(Matrix& matrix, float f) { - Mob* pMob = m_pMinecraft->m_pCameraEntity; + Mob& mob = *m_pMinecraft->m_pCameraEntity; + TileSource& tileSource = mob.getTileSource(); - float headHeightDiff = pMob->m_heightOffset - 1.62f; + float headHeightDiff = mob.m_heightOffset - 1.62f; - float posX = Mth::Lerp(pMob->m_oPos.x, pMob->m_pos.x, f); - float posY = Mth::Lerp(pMob->m_oPos.y, pMob->m_pos.y, f); - float posZ = Mth::Lerp(pMob->m_oPos.z, pMob->m_pos.z, f); + float posX = Mth::Lerp(mob.m_oPos.x, mob.m_pos.x, f); + float posY = Mth::Lerp(mob.m_oPos.y, mob.m_pos.y, f); + float posZ = Mth::Lerp(mob.m_oPos.z, mob.m_pos.z, f); matrix.rotate(field_5C + f * (field_58 - field_5C), Vec3::UNIT_Z); @@ -324,8 +327,8 @@ void GameRenderer::moveCameraToPlayer(Matrix& matrix, float f) } else { - float mob_yaw = pMob->m_rot.x; - float mob_pitch = pMob->m_rot.y; + float mob_yaw = mob.m_rot.x; + float mob_pitch = mob.m_rot.y; float pitchRad = mob_pitch / 180.0f * float(M_PI); @@ -339,7 +342,7 @@ void GameRenderer::moveCameraToPlayer(Matrix& matrix, float f) float offsY = ((i & 2) - 1) * 0.1f; float offsZ = (2 * ((i >> 2) & 1) - 1) * 0.1f; - HitResult hr = m_pMinecraft->m_pLevel->clip( + HitResult hr = tileSource.clip( Vec3(posX + offsX, posY + offsY, posZ + offsZ), Vec3(aX + offsX + offsZ, aY + offsY, aZ + offsZ) // @NOTE: Not sure why it adds offsZ to offsX. ); @@ -355,11 +358,11 @@ void GameRenderer::moveCameraToPlayer(Matrix& matrix, float f) } } - matrix.rotate(pMob->m_rot.y - mob_pitch, Vec3::UNIT_X); - matrix.rotate(pMob->m_rot.x - mob_yaw, Vec3::UNIT_Y); + matrix.rotate(mob.m_rot.y - mob_pitch, Vec3::UNIT_X); + matrix.rotate(mob.m_rot.x - mob_yaw, Vec3::UNIT_Y); matrix.translate(Vec3::NEG_UNIT_Z * v11); - matrix.rotate(mob_yaw - pMob->m_rot.x, Vec3::UNIT_Y); - matrix.rotate(mob_pitch - pMob->m_rot.y, Vec3::UNIT_X); + matrix.rotate(mob_yaw - mob.m_rot.x, Vec3::UNIT_Y); + matrix.rotate(mob_pitch - mob.m_rot.y, Vec3::UNIT_X); } } else @@ -369,8 +372,8 @@ void GameRenderer::moveCameraToPlayer(Matrix& matrix, float f) if (!m_pMinecraft->getOptions()->m_bFixedCamera) { - matrix.rotate(pMob->m_oRot.y + f * (pMob->m_rot.y - pMob->m_oRot.y), Vec3::UNIT_X); - matrix.rotate(pMob->m_oRot.x + f * (pMob->m_rot.x - pMob->m_oRot.x) + 180.0f, Vec3::UNIT_Y); + matrix.rotate(mob.m_oRot.y + f * (mob.m_rot.y - mob.m_oRot.y), Vec3::UNIT_X); + matrix.rotate(mob.m_oRot.x + f * (mob.m_rot.x - mob.m_oRot.x) + 180.0f, Vec3::UNIT_Y); } matrix.translate(Vec3::UNIT_Y * headHeightDiff); @@ -724,8 +727,9 @@ void GameRenderer::render(const Timer& timer) { m_lastUpdatedMS = timeMs; m_shownFPS = m_pMinecraft->getFpsIntlCounter(); - m_shownChunkUpdates = Chunk::updates; - Chunk::updates = 0; + // @TODO: fix this + //m_shownChunkUpdates = Chunk::updates; + //Chunk::updates = 0; } } @@ -897,7 +901,8 @@ void GameRenderer::pick(float f) if (!m_pMinecraft->m_pCameraEntity || !m_pMinecraft->m_pLevel) return; - Mob* pMob = m_pMinecraft->m_pCameraEntity; + Mob& mob = *m_pMinecraft->m_pCameraEntity; + TileSource& tileSource = mob.getTileSource(); HitResult& mchr = m_pMinecraft->m_hitResult; float dist = m_pMinecraft->m_pGameMode->getBlockReachDistance(); bool isFirstPerson = !m_pMinecraft->getOptions()->m_thirdPerson.get(); @@ -906,7 +911,7 @@ void GameRenderer::pick(float f) if (!m_pMinecraft->useSplitControls()) { - Vec3 mobPos = pMob->getPos(f); + Vec3 mobPos = mob.getInterpolatedPosition(f); Vec3 foundPosNear, foundPosFar; bool flag = true; float offset = isFirstPerson ? 6.0f : 12.0f; @@ -965,11 +970,11 @@ void GameRenderer::pick(float f) { if (isFirstPerson) { - mchr = m_pMinecraft->m_pLevel->clip(foundPosNear, foundPosFar, false); + mchr = tileSource.clip(foundPosNear, foundPosFar, false); } else { - HitResult hr = m_pMinecraft->m_pLevel->clip(foundPosNear, foundPosFar, false); + HitResult hr = tileSource.clip(foundPosNear, foundPosFar, false); float diffX = float(hr.m_tilePos.x) - m_pMinecraft->m_pCameraEntity->m_pos.x; float diffY = float(hr.m_tilePos.y) - m_pMinecraft->m_pCameraEntity->m_pos.y; @@ -985,11 +990,11 @@ void GameRenderer::pick(float f) else { // easy case: pick from the middle of the screen - HitResult hrMob = pMob->pick(dist, f); + HitResult hrMob = mob.pick(dist, f); mchr = hrMob; } - Vec3 mobPos = pMob->getPos(f); + Vec3 mobPos = mob.getInterpolatedPosition(f); if (mchr.m_hitType != HitResult::NONE) dist = mchr.m_hitPos.distanceTo(mobPos); @@ -1000,7 +1005,7 @@ void GameRenderer::pick(float f) else */if (dist > maxEntityDist) dist = maxEntityDist; - Vec3 view = pMob->getViewVector(f); + Vec3 view = mob.getViewVector(f); Vec3 exp; Vec3 limit; Vec3 rayStart; @@ -1046,7 +1051,7 @@ void GameRenderer::pick(float f) else { // Split - scanAABB = pMob->m_hitbox; + scanAABB = mob.m_hitbox; if (exp.x < 0) scanAABB.min.x += exp.x; if (exp.x > 0) scanAABB.max.x += exp.x; if (exp.y < 0) scanAABB.min.y += exp.y; @@ -1056,7 +1061,7 @@ void GameRenderer::pick(float f) scanAABB.grow(1, 1, 1); } - EntityVector ents = m_pMinecraft->m_pLevel->getEntities(pMob, scanAABB); + const Entity::Vector& ents = tileSource.getEntities(&mob, scanAABB); float fDist = 0.0f; for (size_t i = 0; i < ents.size(); i++) @@ -1107,11 +1112,11 @@ void GameRenderer::pick(float f) if (mchr.m_hitType != HitResult::NONE || view.y >= -0.7f) return; - mobPos = pMob->getPos(f); + mobPos = mob.getInterpolatedPosition(f); Vec3 checkVec = mobPos; checkVec.translate(0, -2, 0); - HitResult hrLevelChk = m_pMinecraft->m_pLevel->clip(mobPos, checkVec); + HitResult hrLevelChk = tileSource.clip(mobPos, checkVec); if (hrLevelChk.m_hitType == HitResult::NONE) return; diff --git a/source/client/renderer/GameRenderer.hpp b/source/client/renderer/GameRenderer.hpp index 5b890699b..ad93a4433 100644 --- a/source/client/renderer/GameRenderer.hpp +++ b/source/client/renderer/GameRenderer.hpp @@ -16,6 +16,7 @@ class Minecraft; class Timer; class Entity; +class Dimension; class LevelRenderer; class ParticleEngine; diff --git a/source/client/renderer/ItemInHandRenderer.cpp b/source/client/renderer/ItemInHandRenderer.cpp index 0501474af..42e320dc5 100644 --- a/source/client/renderer/ItemInHandRenderer.cpp +++ b/source/client/renderer/ItemInHandRenderer.cpp @@ -12,6 +12,7 @@ #include "client/renderer/entity/HumanoidMobRenderer.hpp" #include "client/renderer/renderer/RenderMaterialGroup.hpp" #include "renderer/ShaderConstants.hpp" +#include "world/level/TileSource.hpp" #include "Lighting.hpp" ItemInHandRenderer::Materials::Materials() @@ -48,14 +49,15 @@ void ItemInHandRenderer::itemUsed() void ItemInHandRenderer::render(float a) { - LocalPlayer* pLP = m_pMinecraft->m_pLocalPlayer; + LocalPlayer& player = *m_pMinecraft->m_pLocalPlayer; + TileSource& tileSource = player.getTileSource(); #ifndef FEATURE_GFX_SHADERS // Apply lighting { MatrixStack::Ref matrix = MatrixStack::World.push(); - matrix->rotate(pLP->m_oRot.y + (pLP->m_rot.y - pLP->m_oRot.y) * a, Vec3::UNIT_X); - matrix->rotate(pLP->m_oRot.x + (pLP->m_rot.x - pLP->m_oRot.x) * a, Vec3::UNIT_Y); + matrix->rotate(player.m_oRot.y + (player.m_rot.y - player.m_oRot.y) * a, Vec3::UNIT_X); + matrix->rotate(player.m_oRot.x + (player.m_rot.x - player.m_oRot.x) * a, Vec3::UNIT_Y); Lighting::turnOn(matrix); } @@ -63,31 +65,31 @@ void ItemInHandRenderer::render(float a) MatrixStack::Ref matrix = MatrixStack::World.push(); - if (m_pMinecraft->getOptions()->m_dynamicHand.get() && m_pMinecraft->m_pCameraEntity == pLP) + if (m_pMinecraft->getOptions()->m_dynamicHand.get() && m_pMinecraft->m_pCameraEntity == &player) { - float rYaw = Mth::Lerp(pLP->m_lastRenderArmRot.x, pLP->m_renderArmRot.x, a); - float rPitch = Mth::Lerp(pLP->m_lastRenderArmRot.y, pLP->m_renderArmRot.y, a); - matrix->rotate((pLP->m_rot.y - rPitch) * 0.1f, Vec3::UNIT_X); - matrix->rotate((pLP->m_rot.x - rYaw ) * 0.1f, Vec3::UNIT_Y); + float rYaw = Mth::Lerp(player.m_lastRenderArmRot.x, player.m_renderArmRot.x, a); + float rPitch = Mth::Lerp(player.m_lastRenderArmRot.y, player.m_renderArmRot.y, a); + matrix->rotate((player.m_rot.y - rPitch) * 0.1f, Vec3::UNIT_X); + matrix->rotate((player.m_rot.x - rYaw ) * 0.1f, Vec3::UNIT_Y); } - float fBright = m_pMinecraft->m_pLevel->getBrightness(pLP->m_pos); + float fBright = tileSource.getBrightness(player.m_pos); currentShaderColor = Color::WHITE; currentShaderDarkColor = Color(fBright, fBright, fBright); - ItemStack* pItem = &m_selectedItem; - /*if (pLP->m_fishing != null) + ItemStack& item = m_selectedItem; + /*if (player.m_fishing != null) { // We shouldn't do this, make this static or something pItem = new ItemStack(Item::stick); }*/ float swing2, swing3; - float fAnim = pLP->getAttackAnim(a); + float fAnim = player.getAttackAnim(a); float h = m_oHeight + (m_height - m_oHeight) * a; constexpr float d = 0.8f; - if (!ItemStack::isEmpty(pItem)) + if (!item.isEmpty()) { matrix->translate(Vec3(-0.4f * Mth::sin(float(M_PI) * Mth::sqrt(fAnim)), 0.2f * Mth::sin(2.0f * float(M_PI) * Mth::sqrt(fAnim)), -0.2f * Mth::sin(float(M_PI) * fAnim))); matrix->translate(Vec3(0.7f * d, -0.65f * d - (1.0f - h) * 0.6f, -0.9f * d)); @@ -105,12 +107,12 @@ void ItemInHandRenderer::render(float a) matrix->rotate(swing2 * -80.0f, Vec3::UNIT_X); matrix->scale(0.4f); - if (pItem->getItem()->isMirroredArt()) + if (item.getItem()->isMirroredArt()) { matrix->rotate(180.0f, Vec3::UNIT_Y); } - renderItem(*pLP, *pItem, a); + renderItem(player, item, a); } else { @@ -132,10 +134,10 @@ void ItemInHandRenderer::render(float a) matrix->scale(1.0f); matrix->translate(Vec3(5.6f, 0.0f, 0.0f)); - HumanoidMobRenderer* pRenderer = (HumanoidMobRenderer*)EntityRenderDispatcher::getInstance()->getRenderer(*pLP); + HumanoidMobRenderer* pRenderer = (HumanoidMobRenderer*)EntityRenderDispatcher::getInstance()->getRenderer(player); swing2 = 1.0f; matrix->scale(swing2); - pRenderer->renderHand(*pLP, a); + pRenderer->renderHand(player, a); } #if MCE_GFX_API_OGL && !defined(FEATURE_GFX_SHADERS) @@ -278,21 +280,24 @@ void ItemInHandRenderer::renderItem(const Entity& entity, const ItemStack& item, void ItemInHandRenderer::renderScreenEffect(float a) { - LocalPlayer* player = m_pMinecraft->m_pLocalPlayer; - Textures* textures = m_pMinecraft->m_pTextures; - Level* level = m_pMinecraft->m_pLevel; - - if (player->isOnFire()) + Minecraft& mc = *m_pMinecraft; + Textures& textures = *mc.m_pTextures; + Level& level = *mc.m_pLevel; + Options& options = *mc.getOptions(); + LocalPlayer& player = *mc.m_pLocalPlayer; + TileSource& tileSource = player.getTileSource(); + + if (player.isOnFire()) { - textures->loadAndBindTexture(C_TERRAIN_NAME); + textures.loadAndBindTexture(C_TERRAIN_NAME); renderFire(a); } - if (player->isInWall() && !m_pMinecraft->getOptions()->m_flightHax.get()) + if (player.isInWall() && !options.m_flightHax.get()) { - textures->loadAndBindTexture(C_TERRAIN_NAME); + textures.loadAndBindTexture(C_TERRAIN_NAME); - Tile* pTile = Tile::tiles[level->getTile(player->m_pos)]; + Tile* pTile = Tile::tiles[tileSource.getTile(player.m_pos)]; if (pTile) { int texture = pTile->getTexture(Facing::NORTH); @@ -300,9 +305,9 @@ void ItemInHandRenderer::renderScreenEffect(float a) } } - if (player->isUnderLiquid(Material::water)) + if (player.isUnderLiquid(Material::water)) { - if (textures->loadAndBindTexture("misc/water.png", false)) + if (textures.loadAndBindTexture("misc/water.png", false)) { renderWater(a); } diff --git a/source/client/renderer/LevelRenderer.cpp b/source/client/renderer/LevelRenderer.cpp index c7202fe54..59a81d070 100644 --- a/source/client/renderer/LevelRenderer.cpp +++ b/source/client/renderer/LevelRenderer.cpp @@ -15,6 +15,7 @@ #include "renderer/GlobalConstantBuffers.hpp" #include "renderer/ShaderConstants.hpp" #include "renderer/RenderContextImmediate.hpp" +#include "world/level/TileSource.hpp" #if MCE_GFX_API_OGL #include "thirdparty/GL/GL.hpp" @@ -26,6 +27,9 @@ #include "Fog.hpp" #include "Lighting.hpp" +// in chunks +#define C_ENTITY_RENDER_DISTANCE 4 + TerrainLayer renderLayerToTerrainLayerMap[Tile::RENDER_LAYERS_COUNT] = { /*RENDER_LAYER_DOUBLE_SIDED*/ TERRAIN_LAYER_DOUBLE_SIDED, /*RENDER_LAYER_BLEND*/ TERRAIN_LAYER_BLEND, @@ -292,13 +296,14 @@ void LevelRenderer::_initResources() void LevelRenderer::_renderSunrise(float alpha) { Tesselator& t = Tesselator::instance; + const Dimension& dimension = *m_pDimension; - const float* c = m_pLevel->m_pDimension->getSunriseColor(m_pLevel->getTimeOfDay(alpha), alpha); - if (c != nullptr && arePlanetsAvailable()) + Color c = dimension.getSunriseColor(dimension.getTimeOfDay(alpha), alpha); + if (c != Color::NIL, arePlanetsAvailable()) { MatrixStack::Ref matrix = MatrixStack::World.push(); matrix->rotate(90.0f, Vec3::UNIT_X); - matrix->rotate(m_pLevel->getTimeOfDay(alpha) > 0.5f ? 180 : 0, Vec3::UNIT_Z); + matrix->rotate(dimension.getTimeOfDay(alpha) > 0.5f ? 180 : 0, Vec3::UNIT_Z); int steps = 16; @@ -310,11 +315,11 @@ void LevelRenderer::_renderSunrise(float alpha) float sin = Mth::sin(a); float cos = Mth::cos(a); - t.color(c[0], c[1], c[2], c[3]); + t.color(c); t.vertex(0.0f, 100.0f, 0.0f); - t.color(c[0], c[1], c[2], 0.0f); - t.vertex((sin * 120.0f), (cos * 120.0f), (-cos * 40.0f * c[3])); + t.color(c.r, c.g, c.b, 0.0f); + t.vertex((sin * 120.0f), (cos * 120.0f), (-cos * 40.0f * c.a)); } // @HAL: sky.vertex shader will not work here, it ignores the vertex colors @@ -333,6 +338,7 @@ void LevelRenderer::_renderSolarSystem(float alpha) void LevelRenderer::_renderSunAndMoon(float alpha) { Tesselator& t = Tesselator::instance; + const Dimension& dimension = *m_pDimension; Matrix& matrix = MatrixStack::World.getTop(); @@ -343,7 +349,7 @@ void LevelRenderer::_renderSunAndMoon(float alpha) matrix.translate(p); matrix.rotate(0.0f, Vec3::UNIT_Z); - matrix.rotate(m_pLevel->getTimeOfDay(alpha) * 360.0f, Vec3::UNIT_X); + matrix.rotate(dimension.getTimeOfDay(alpha) * 360.0f, Vec3::UNIT_X); if (arePlanetsAvailable()) { @@ -369,7 +375,7 @@ void LevelRenderer::_renderSunAndMoon(float alpha) void LevelRenderer::_renderStars(float alpha) { - float a = m_pLevel->getStarBrightness(alpha); + float a = m_pDimension->getStarBrightness(alpha); if (a > 0.0f) { currentShaderColor = Color(a, a, a); @@ -377,12 +383,12 @@ void LevelRenderer::_renderStars(float alpha) } } -void LevelRenderer::_renderTileShadow(Tile* tt, const Vec3& pos, TilePos& tilePos, float pow, float r, const Vec3& oPos) +void LevelRenderer::_renderTileShadow(TileSource& tileSource, Tile* tt, const Vec3& pos, TilePos& tilePos, float pow, float r, const Vec3& oPos) { Tesselator& t = Tesselator::instance; if (!tt->isCubeShaped()) return; - float a = (pow - (pos.y - ((float)tilePos.y + oPos.y)) / 2.0f) * 0.5f * m_pLevel->getBrightness(tilePos); + float a = (pow - (pos.y - ((float)tilePos.y + oPos.y)) / 2.0f) * 0.5f * tileSource.getBrightness(tilePos); if (a < 0.0f) return; if (a > 1.0f) a = 1.0f; @@ -416,7 +422,9 @@ void LevelRenderer::_setupFog(const Entity& camera, int i) #endif mce::FogStateDescription& desc = Fog::nextState; - GameRenderer& gameRenderer = *m_pMinecraft->m_pGameRenderer; + Minecraft& mc = *m_pMinecraft; + GameRenderer& gameRenderer = *mc.m_pGameRenderer; + Dimension& dimension = *camera.getDimension(); float renderDistance = gameRenderer.m_renderDistance; if (camera.isUnderLiquid(Material::water)) @@ -442,7 +450,7 @@ void LevelRenderer::_setupFog(const Entity& camera, int i) m_fogControl = Vec2(0.25f, 1.0f); } - if (m_pMinecraft->m_pLevel->m_pDimension->m_bFoggy) + if (dimension.isFoggy()) { m_fogControl.x = 0.0f; } @@ -477,7 +485,7 @@ void LevelRenderer::_updateViewArea(const Entity& camera) void LevelRenderer::_startFrame(FrustumCuller& culler, float renderDistance, float f) { const Entity& camera = *m_pMinecraft->m_pCameraEntity; - m_viewPos = camera.getPos(f); + m_viewPos = camera.getInterpolatedPosition(f); _setupFog(camera, 1); @@ -1000,18 +1008,16 @@ const Color& LevelRenderer::setupClearColor(float f) { Minecraft& mc = *m_pMinecraft; const Options& options = *mc.getOptions(); - Level& level = *mc.m_pLevel; const Entity& camera = *mc.m_pCameraEntity; + const Dimension& dimension = *camera.getDimension(); float x1 = 1.0f - powf(1.0f / float(4 - options.m_viewDistance.get()), 0.25f); - Vec3 skyColor = level.getSkyColor(camera, f), fogColorVec = level.getFogColor(f); - + Color skyColor = dimension.getSkyColor(camera, f); Color& fogColor = Fog::nextState.fogColor; + fogColor = dimension.getFogColor(f); - fogColor.r = fogColorVec.x + (skyColor.x - fogColorVec.x) * x1; - fogColor.g = fogColorVec.y + (skyColor.y - fogColorVec.y) * x1; - fogColor.b = fogColorVec.z + (skyColor.z - fogColorVec.z) * x1; + fogColor += (skyColor - fogColor) * x1; fogColor.a = 1.0f; if (camera.isUnderLiquid(Material::water)) @@ -1039,6 +1045,7 @@ const Color& LevelRenderer::setupClearColor(float f) void LevelRenderer::setLevel(Level* level) { + // @TODO: matt, update this if (m_pLevel == level) return; @@ -1075,6 +1082,7 @@ void LevelRenderer::setDimension(Dimension* dimension) void LevelRenderer::setDirty(const TilePos& min, const TilePos& max) { + // @TODO: matt, update this to use RenderChunks, obviously check 0.12.1 int minX = Mth::intFloorDiv(min.x, 16); int minY = Mth::intFloorDiv(min.y, 16); int minZ = Mth::intFloorDiv(min.z, 16); @@ -1120,11 +1128,12 @@ void LevelRenderer::tick() { const Entity& camera = *m_pMinecraft->m_pCameraEntity; const Level& level = *m_pMinecraft->m_pLevel; + TileSource& tileSource = camera.getTileSource(); const Options& options = *m_pMinecraft->getOptions(); m_fogBrO = m_fogBr; - float bright = level.getBrightness(camera.m_pos); + float bright = tileSource.getBrightness(camera.m_pos); float x3 = float(3 - options.m_viewDistance.get()); float x4 = x3 / 3.0f; float x5 = (x4 + bright * (1.0f - x4) - m_fogBr) * 0.1f; @@ -1134,12 +1143,11 @@ void LevelRenderer::tick() m_ticksSinceStart++; } -typedef std::vector ChunkVector; -typedef ChunkVector::iterator ChunkVectorIterator; - bool LevelRenderer::updateDirtyChunks(const Entity& camera, bool b) { - constexpr int C_MAX = 3; + return true; + + /*constexpr int C_MAX = 3; DirtyChunkSorter dcs(camera); Chunk* pChunks[C_MAX] = { nullptr }; ChunkVector* nearChunks = nullptr; @@ -1242,11 +1250,13 @@ bool LevelRenderer::updateDirtyChunks(const Entity& camera, bool b) if (nr4 > nr3) m_dirtyChunks.erase(m_dirtyChunks.begin() + nr3, m_dirtyChunks.end()); - return pendingChunkRemoved + nr2 == pendingChunkSize; + return pendingChunkRemoved + nr2 == pendingChunkSize;*/ } void LevelRenderer::renderCracks(const Entity& camera, const HitResult& hr, int mode, const ItemStack* inventoryItem, float a) { + TileSource& tileSource = camera.getTileSource(); + // @BUG: possible leftover from Minecraft Classic? This is overridden anyways //currentShaderColor = Color(1.0f, 1.0f, 1.0f, (Mth::sin(float(getTimeMs()) / 100.0f) * 0.2f + 0.4f) * 0.5f); @@ -1261,7 +1271,7 @@ void LevelRenderer::renderCracks(const Entity& camera, const HitResult& hr, int MatrixStack::Ref matrix = MatrixStack::World.push(); Tile* pTile = nullptr; - TileID tile = m_pLevel->getTile(hr.m_tilePos); + TileID tile = tileSource.getTile(hr.m_tilePos); if (tile > 0) pTile = Tile::tiles[tile]; @@ -1296,10 +1306,12 @@ void LevelRenderer::renderHitSelect(const Entity& camera, const HitResult& hr, i { if (mode != 0) return; + TileSource& tileSource = camera.getTileSource(); + m_pMinecraft->m_pTextures->loadAndBindTexture(C_TERRAIN_NAME); Tile* pTile = nullptr; - TileID tileID = m_pLevel->getTile(hr.m_tilePos); + TileID tileID = tileSource.getTile(hr.m_tilePos); if (tileID > 0) pTile = Tile::tiles[tileID]; @@ -1321,7 +1333,7 @@ void LevelRenderer::renderHitSelect(const Entity& camera, const HitResult& hr, i m_pTileRenderer->tesselateInWorld(pTile, hr.m_tilePos); - Tile::RenderLayer renderLayer = pTile->getRenderLayer(); + Tile::RenderLayer renderLayer = pTile->getRenderLayer(&tileSource, hr.m_tilePos); const mce::MaterialPtr& material = _chooseOverlayMaterial(renderLayer); t.draw(material); @@ -1333,22 +1345,24 @@ void LevelRenderer::renderHitOutline(const Entity& camera, const HitResult& hr, if (mode != 0 || hr.m_hitType != 0) return; + TileSource& tileSource = camera.getTileSource(); + currentShaderColor = Color(0.0f, 0.0f, 0.0f, 0.4f); currentShaderDarkColor = Color::WHITE; constexpr float distance = 0.002f; float lineWidth = 2.0f * Minecraft::getRenderScaleMultiplier(); - TileID tile = m_pLevel->getTile(hr.m_tilePos); + TileID tile = tileSource.getTile(hr.m_tilePos); if (tile > 0) { Tile::tiles[tile]->updateShape( - m_pLevel, + &tileSource, hr.m_tilePos); float posX = camera.m_posPrev.x + ((camera.m_pos.x - camera.m_posPrev.x) * a); float posY = camera.m_posPrev.y + ((camera.m_pos.y - camera.m_posPrev.y) * a); float posZ = camera.m_posPrev.z + ((camera.m_pos.z - camera.m_posPrev.z) * a); - AABB aabb, tileAABB = Tile::tiles[tile]->getTileAABB(m_pLevel, hr.m_tilePos); + AABB aabb, tileAABB = Tile::tiles[tile]->getTileAABB(&tileSource, hr.m_tilePos); aabb.min.y = tileAABB.min.y - distance - posY; aabb.max.y = tileAABB.max.y + distance - posY; aabb.min.z = tileAABB.min.z - distance - posZ; @@ -1390,78 +1404,77 @@ void LevelRenderer::takePicture(TripodCamera* pCamera, Entity* pOwner) m_pMinecraft->m_pGameRenderer->m_keepPic = -1; static char str[256]; - // @HUH: This has the potential to overwrite a file -#ifdef ORIGINAL_CODE - sprintf(str, "%s" C_HOME_PATH "img_%.4d.jpg", m_pMinecraft->platform()->m_externalStorageDir.c_str(), getTimeMs()); -#else sprintf(str, "img_%.4d.png", getTimeMs()); -#endif m_pMinecraft->platform()->saveScreenshot(std::string(str), Minecraft::width, Minecraft::height); } void LevelRenderer::addParticle(const std::string& name, const Vec3& pos, const Vec3& dir) { + Minecraft& mc = *m_pMinecraft; + const Entity& camera = *mc.m_pCameraEntity; + // TODO: Who's the genius who decided it'd be better to check a name string rather than an enum? float maxDist = 256.0f; if (name == "explodeColor") maxDist = 16384.0f; - if (m_pMinecraft->m_pCameraEntity->distanceToSqr_inline(pos) > maxDist) + if (camera.distanceToSqr_inline(pos) > maxDist) return; - ParticleEngine* pe = m_pMinecraft->m_pParticleEngine; + ParticleEngine& pe = *mc.m_pParticleEngine; + TileSource& tileSource = camera.getTileSource(); if (name == "bubble") { - pe->add(new BubbleParticle(m_pLevel, pos, dir)); + pe.add(new BubbleParticle(tileSource, pos, dir)); return; } if (name == "smoke") { - pe->add(new SmokeParticle(m_pLevel, pos, dir, 1.0f)); + pe.add(new SmokeParticle(tileSource, pos, dir, 1.0f)); return; } if (name == "explode") { - pe->add(new ExplodeParticle(m_pLevel, pos, dir)); + pe.add(new ExplodeParticle(tileSource, pos, dir)); return; } if (name == "explodeColor") { - ExplodeParticle* pExplPart = new ExplodeParticle(m_pLevel, pos, dir); + ExplodeParticle* pExplPart = new ExplodeParticle(tileSource, pos, dir); pExplPart->m_bIsUnlit = true; pExplPart->m_rCol = Mth::random(); pExplPart->m_gCol = Mth::random(); pExplPart->m_bCol = Mth::random(); pExplPart->scale(3.0f); - pe->add(pExplPart); + pe.add(pExplPart); return; } if (name == "flame") { - pe->add(new FlameParticle(m_pLevel, pos, dir)); + pe.add(new FlameParticle(tileSource, pos, dir)); return; } if (name == "flame2") { - FlameParticle* pFlamePart = new FlameParticle(m_pLevel, pos, dir); + FlameParticle* pFlamePart = new FlameParticle(tileSource, pos, dir); pFlamePart->scale(4.0f); - pe->add(pFlamePart); + pe.add(pFlamePart); return; } if (name == "lava") { - pe->add(new LavaParticle(m_pLevel, pos)); + pe.add(new LavaParticle(tileSource, pos)); return; } if (name == "largesmoke") { - pe->add(new SmokeParticle(m_pLevel, pos, dir, 2.5f)); + pe.add(new SmokeParticle(tileSource, pos, dir, 2.5f)); return; } if (name == "reddust") { - pe->add(new RedDustParticle(m_pLevel, pos, dir)); + pe.add(new RedDustParticle(tileSource, pos, dir)); return; } @@ -1525,7 +1538,7 @@ void LevelRenderer::renderLevel(const Entity& camera, FrustumCuller& culler, flo render(camera, Tile::RENDER_LAYER_ALPHATEST, f, fog); Lighting::turnOn(); - renderEntities(camera.getPos(f), &culler, f); + renderEntities(camera.getInterpolatedPosition(f), &culler, f); particleEngine.renderLit(camera, f); Lighting::turnOff(); particleEngine.render(camera, f); @@ -1560,6 +1573,17 @@ void LevelRenderer::renderLevel(const Entity& camera, FrustumCuller& culler, flo Fog::disable(); } +AABB _getEntityRenderBounds(const Mob& camera) +{ + ChunkPos entityRenderMin(camera.m_chunkPos); + entityRenderMin -= C_ENTITY_RENDER_DISTANCE; + ChunkPos entityRenderMax(camera.m_chunkPos); + entityRenderMax += C_ENTITY_RENDER_DISTANCE; + + // @TODO: make sure this actually works + return AABB((TilePos)entityRenderMin, (TilePos)entityRenderMax); +} + void LevelRenderer::renderEntities(Vec3 pos, Culler* culler, float f) { if (m_noEntityRenderFrames > 0) @@ -1568,32 +1592,35 @@ void LevelRenderer::renderEntities(Vec3 pos, Culler* culler, float f) return; } - const Mob* camera = m_pMinecraft->m_pCameraEntity; + Minecraft& mc = *m_pMinecraft; + Options& options = *mc.getOptions(); + const Mob& camera = *mc.m_pCameraEntity; + TileSource& tileSource = camera.getTileSource(); - EntityRenderDispatcher::getInstance()->prepare(m_pLevel, m_pMinecraft->m_pTextures, m_pMinecraft->m_pFont, camera, m_pMinecraft->getOptions(), f); + EntityRenderDispatcher::getInstance()->prepare(m_pLevel, mc.m_pTextures, mc.m_pFont, &camera, &options, f); m_totalEntities = 0; m_renderedEntities = 0; m_culledEntities = 0; - EntityRenderDispatcher::off = camera->m_posPrev + (camera->m_pos - camera->m_posPrev) * f; + EntityRenderDispatcher::off = camera.m_posPrev + (camera.m_pos - camera.m_posPrev) * f; - const EntityVector* pVec = m_pLevel->getAllEntities(); - m_totalEntities = int(pVec->size()); + const Entity::Vector& entities = tileSource.getEntities((Entity*)&camera, _getEntityRenderBounds(camera)); + m_totalEntities = int(entities.size()); for (int i = 0; i < m_totalEntities; i++) { - const Entity* entity = (*pVec)[i]; + const Entity* entity = entities[i]; if (!entity->shouldRender(pos)) continue; if (!culler->isVisible(entity->m_hitbox)) continue; - if (m_pMinecraft->m_pCameraEntity == entity && !m_pMinecraft->getOptions()->m_thirdPerson.get()) + if (mc.m_pCameraEntity == entity && !options.m_thirdPerson.get()) continue; - if (m_pLevel->hasChunkAt(entity->m_pos)) + if (tileSource.hasChunkAt(entity->m_pos)) { m_renderedEntities++; EntityRenderDispatcher::getInstance()->render(*entity, f); @@ -1604,6 +1631,7 @@ void LevelRenderer::renderEntities(Vec3 pos, Culler* culler, float f) void LevelRenderer::renderShadow(const Entity& entity, const Vec3& pos, float r, float pow, float a) { Textures& textures = *m_pMinecraft->m_pTextures; + TileSource& tileSource = entity.getTileSource(); textures.setClampToEdge(true); textures.loadAndBindTexture("misc/shadow.png"); @@ -1626,10 +1654,10 @@ void LevelRenderer::renderShadow(const Entity& entity, const Vec3& pos, float r, { for (tp.z = tpMin.z; tp.z <= tpMax.z; tp.z++) { - TileID t = m_pLevel->getTile(tp.below()); - if (t > 0 && m_pLevel->getRawBrightness(tp) > 3) + TileID t = tileSource.getTile(tp.below()); + if (t > 0 && tileSource.getRawBrightness(tp) > 3) { - _renderTileShadow(Tile::tiles[t], + _renderTileShadow(tileSource, Tile::tiles[t], Vec3(pos.x, pos.y - entity.m_heightOffset + entity.getShadowHeightOffs(), pos.z), tp, pow, r, Vec3(ePosO.x, ePosO.y - entity.m_heightOffset + entity.getShadowHeightOffs(), ePosO.z) @@ -1643,15 +1671,15 @@ void LevelRenderer::renderShadow(const Entity& entity, const Vec3& pos, float r, void LevelRenderer::renderSky(const Entity& camera, float alpha) { - if (m_pMinecraft->m_pLevel->m_pDimension->m_bFoggy) + if (m_pDimension->isFoggy()) return; - Vec3 sc = m_pLevel->getSkyColor(camera, alpha); + Color sc = m_pDimension->getSkyColor(camera, alpha); if (m_pMinecraft->getOptions()->m_anaglyphs.get()) { - sc.x = (((sc.x * 30.0f) + (sc.y * 59.0f)) + (sc.z * 11.0f)) / 100.0f; - sc.y = ((sc.x * 30.0f) + (sc.y * 70.0f)) / 100.0f; - sc.z = ((sc.x * 30.0f) + (sc.z * 70.0f)) / 100.0f; + sc.r = (((sc.r * 30.0f) + (sc.g * 59.0f)) + (sc.b * 11.0f)) / 100.0f; + sc.g = ((sc.r * 30.0f) + (sc.g * 70.0f)) / 100.0f; + sc.b = ((sc.r * 30.0f) + (sc.b * 70.0f)) / 100.0f; } // called again a few lines down, no min in Java, why is it here? @@ -1665,7 +1693,7 @@ void LevelRenderer::renderSky(const Entity& camera, float alpha) //MatrixStack::Ref matrix = MatrixStack::World.push(); //matrix->scale(Vec3(fogStart, 0.0f, fogStart)); - currentShaderColor = Color(sc.x, sc.y, sc.z); + currentShaderColor = sc; m_skyMesh.render(m_materials.skyplane); Fog::disable(); @@ -1678,7 +1706,7 @@ void LevelRenderer::renderSky(const Entity& camera, float alpha) if (m_darkMesh.isValid()) { - currentShaderColor = Color(sc.x * 0.2f + 0.04f, sc.y * 0.2f + 0.04f, sc.z * 0.6f + 0.1f); + currentShaderColor = Color(sc.r * 0.2f + 0.04f, sc.g * 0.2f + 0.04f, sc.b * 0.6f + 0.1f); m_darkMesh.render(m_materials.skyplane); } } @@ -1718,12 +1746,17 @@ void LevelRenderer::renderClouds(const Entity& camera, float alpha) if (!areCloudsAvailable()) return; - if (m_pMinecraft->getOptions()->m_fancyGraphics.get()) + Minecraft& mc = *m_pMinecraft; + Options& options = *mc.getOptions(); + + if (options.m_fancyGraphics.get()) { renderAdvancedClouds(alpha); return; } + Dimension& dimension = *camera.getDimension(); + mce::RenderContext& renderContext = mce::RenderContextImmediate::get(); float yPos = Mth::Lerp(camera.m_posPrev.y, camera.m_pos.y, alpha); // not certain if this old pos Y is used @@ -1736,7 +1769,8 @@ void LevelRenderer::renderClouds(const Entity& camera, float alpha) m_pTextures->loadAndBindTexture("environment/clouds.png"); - Vec3 cloudColor = m_pLevel->getCloudColor(alpha); + Color cloudColor = dimension.getCloudColor(alpha); + cloudColor.a = 0.8f; float offX = Mth::Lerp(camera.m_oPos.x, camera.m_pos.x, alpha) + (float(m_ticksSinceStart) + alpha) * 0.03f; float offZ = Mth::Lerp(camera.m_oPos.z, camera.m_pos.z, alpha); @@ -1753,7 +1787,7 @@ void LevelRenderer::renderClouds(const Entity& camera, float alpha) offX /= 2048.0f; offZ /= 2048.0f; t.begin(1024); - t.color(cloudColor.x, cloudColor.y, cloudColor.z, 0.8f); + t.color(cloudColor); constexpr int incr = 16 * 2; constexpr int maxX = C_MAX_CHUNKS_X * 16; @@ -1783,18 +1817,22 @@ void LevelRenderer::renderClouds(const Entity& camera, float alpha) void LevelRenderer::renderAdvancedClouds(float alpha) { + Minecraft& mc = *m_pMinecraft; + Options& options = *mc.getOptions(); + const Entity& camera = *mc.m_pCameraEntity; mce::RenderContext& renderContext = mce::RenderContextImmediate::get(); + Dimension& dimension = *camera.getDimension(); - float yOffs = //Mth::Lerp(m_pMinecraft->m_pCameraEntity->m_posPrev.y, m_pMinecraft->m_pCameraEntity->m_pos.y, alpha); - m_pMinecraft->m_pCameraEntity->m_posPrev.y + (m_pMinecraft->m_pCameraEntity->m_pos.y - m_pMinecraft->m_pCameraEntity->m_posPrev.y) * alpha; + float yOffs = //Mth::Lerp(camera.m_posPrev.y, camera.m_pos.y, alpha); + camera.m_posPrev.y + (camera.m_pos.y - camera.m_posPrev.y) * alpha; Tesselator& t = Tesselator::instance; constexpr float ss = 12.0f; constexpr float h = 4.0f; // @NOTE: Using Mth::Lerp will use incorrect logic - float xo = (m_pMinecraft->m_pCameraEntity->m_oPos.x + (m_pMinecraft->m_pCameraEntity->m_pos.x - m_pMinecraft->m_pCameraEntity->m_oPos.x) * alpha + ((float(m_ticksSinceStart) + alpha) * 0.03f)) / ss; - float zo = (m_pMinecraft->m_pCameraEntity->m_oPos.z + (m_pMinecraft->m_pCameraEntity->m_pos.z - m_pMinecraft->m_pCameraEntity->m_oPos.z) * alpha) / ss + 0.33f; + float xo = (camera.m_oPos.x + (camera.m_pos.x - camera.m_oPos.x) * alpha + ((float(m_ticksSinceStart) + alpha) * 0.03f)) / ss; + float zo = (camera.m_oPos.z + (camera.m_pos.z - camera.m_oPos.z) * alpha) / ss + 0.33f; float yy = ((float)C_MAX_Y - yOffs) + 0.33f; // 108.0f on b1.2_02, see below //float yy = 108.0f - yOffs + 0.33F; @@ -1812,22 +1850,19 @@ void LevelRenderer::renderAdvancedClouds(float alpha) m_pTextures->loadAndBindTexture("environment/clouds.png"); - Vec3 cc = m_pLevel->getCloudColor(alpha); - float cr = cc.x; - float cg = cc.y; - float cb = cc.z; + Color cc = dimension.getCloudColor(alpha); float uo; float vo; float scale; - if (m_pMinecraft->getOptions()->m_anaglyphs.get()) + if (options.m_anaglyphs.get()) { - uo = (cr * 30.0f + cg * 59.0f + cb * 11.0f) / 100.0f; - vo = (cr * 30.0f + cg * 70.0f) / 100.0f; - scale = (cr * 30.0f + cb * 70.0f) / 100.0f; - cr = uo; - cg = vo; - cb = scale; + uo = (cc.r * 30.0f + cc.g * 59.0f + cc.b * 11.0f) / 100.0f; + vo = (cc.r * 30.0f + cc.g * 70.0f) / 100.0f; + scale = (cc.r * 30.0f + cc.b * 70.0f) / 100.0f; + cc.r = uo; + cc.g = vo; + cc.b = scale; } uo = (float)(xo * 0.0); @@ -1877,7 +1912,7 @@ void LevelRenderer::renderAdvancedClouds(float alpha) if (yy > -h - 1.0f) { - t.color(cr * 0.7f, cg * 0.7f, cb * 0.7f, 0.8f); + t.color(cc.r * 0.7f, cc.g * 0.7f, cc.b * 0.7f, 0.8f); t.vertexUV((xp + 0.0f), (yy + 0.0f), (zp + D), ((xx + 0.0f) * scale + uo), ((zz + D) * scale + vo)); t.vertexUV((xp + D), (yy + 0.0f), (zp + D), ((xx + D) * scale + uo), ((zz + D) * scale + vo)); t.vertexUV((xp + D), (yy + 0.0f), (zp + 0.0f), ((xx + D) * scale + uo), ((zz + 0.0f) * scale + vo)); @@ -1886,7 +1921,7 @@ void LevelRenderer::renderAdvancedClouds(float alpha) if (yy <= h + 1.0f) { - t.color(cr, cg, cb, 0.8f); + t.color(cc.r, cc.g, cc.b, 0.8f); t.normal(0.0f, 1.0f, 0.0f); t.vertexUV((xp + 0.0f), (yy + h - e), (zp + D), ((xx + 0.0f) * scale + uo), ((zz + D) * scale + vo)); t.vertexUV((xp + D), (yy + h - e), (zp + D), ((xx + D) * scale + uo), ((zz + D) * scale + vo)); @@ -1894,7 +1929,7 @@ void LevelRenderer::renderAdvancedClouds(float alpha) t.vertexUV((xp + 0.0f), (yy + h - e), (zp + 0.0f), ((xx + 0.0f) * scale + uo), ((zz + 0.0f) * scale + vo)); } - t.color(cr * 0.9f, cg * 0.9f, cb * 0.9f, 0.8f); + t.color(cc.r * 0.9f, cc.g * 0.9f, cc.b * 0.9f, 0.8f); if (xPos > -1) { @@ -1922,7 +1957,7 @@ void LevelRenderer::renderAdvancedClouds(float alpha) } } - t.color(cr * 0.8f, cg * 0.8f, cb * 0.8f, 0.8f); + t.color(cc.r * 0.8f, cc.g * 0.8f, cc.b * 0.8f, 0.8f); if (zPos > -1) { t.normal(Vec3::NEG_UNIT_Z); @@ -1962,7 +1997,8 @@ void LevelRenderer::renderAdvancedClouds(float alpha) void LevelRenderer::skyColorChanged() { - for (int i = 0; i < m_chunksLength; i++) + // Probably not needed anymore + /*for (int i = 0; i < m_chunksLength; i++) { Chunk* pChunk = m_chunks[i]; if (!pChunk->field_54) @@ -1973,7 +2009,7 @@ void LevelRenderer::skyColorChanged() m_dirtyChunks.push_back(pChunk); pChunk->setDirty(); - } + }*/ } void LevelRenderer::levelEvent(const LevelEvent& event) diff --git a/source/client/renderer/LevelRenderer.hpp b/source/client/renderer/LevelRenderer.hpp index 1e2fbbc60..c84a67905 100644 --- a/source/client/renderer/LevelRenderer.hpp +++ b/source/client/renderer/LevelRenderer.hpp @@ -11,63 +11,16 @@ #include #include #include "client/app/AppPlatformListener.hpp" +#include "client/renderer/FrustumCuller.hpp" #include "renderer/hal/interface/FogState.hpp" #include "world/level/LevelListener.hpp" +#include "world/level/Dimension.hpp" #include "Textures.hpp" #include "RenderList.hpp" #include "TileRenderer.hpp" class Minecraft; -class DistanceChunkSorter -{ - const Entity& m_entity; - -public: - DistanceChunkSorter(const Entity& entity) - : m_entity(entity) - { - } - - bool operator()(const Chunk* a, const Chunk* b) - { - float d1 = a->distanceToSqr(m_entity); - float d2 = b->distanceToSqr(m_entity); - - if (d1 > 1024.0f && a->m_pos.y <= 63) d1 *= 10.0f; - if (d2 > 1024.0f && b->m_pos.y <= 63) d2 *= 10.0f; - - return d1 < d2; - } -}; - -class DirtyChunkSorter -{ - const Entity& m_entity; - -public: - DirtyChunkSorter(const Entity& entity) - : m_entity(entity) - { - } - - bool operator()(const Chunk* a, const Chunk* b) - { - if (a->m_bVisible && !b->m_bVisible) - return false; - if (!a->m_bVisible && b->m_bVisible) - return true; - - float d1 = a->distanceToSqr(m_entity); - float d2 = b->distanceToSqr(m_entity); - - if (d1 < d2) return false; - if (d1 > d2) return true; - - return a->m_id > b->m_id; - } -}; - class LevelRenderer : public LevelListener, public AppPlatformListener { protected: @@ -116,7 +69,7 @@ class LevelRenderer : public LevelListener, public AppPlatformListener void _renderSolarSystem(float alpha); void _renderSunAndMoon(float alpha); void _renderStars(float alpha); - void _renderTileShadow(Tile* tt, const Vec3& pos, TilePos& tilePos, float pow, float r, const Vec3& oPos); + void _renderTileShadow(TileSource& tileSource, Tile* tt, const Vec3& pos, TilePos& tilePos, float pow, float r, const Vec3& oPos); void _recreateTessellators(); void _setupFog(const Entity& camera, int i); const Color& _getFogColor() const; @@ -182,7 +135,6 @@ class LevelRenderer : public LevelListener, public AppPlatformListener int m_totalEntities; int m_renderedEntities; int m_culledEntities; - std::vector field_24; int m_cullStep; RenderList m_renderList; int m_totalChunks; @@ -199,9 +151,6 @@ class LevelRenderer : public LevelListener, public AppPlatformListener int m_zMaxChunk; Level* m_pLevel; Dimension* m_pDimension; - std::vector m_dirtyChunks; - Chunk** m_chunks; - Chunk** m_sortedChunks; int m_chunksLength; TileRenderer* m_pTileRenderer; int m_xChunks; diff --git a/source/client/renderer/LightLayer.cpp b/source/client/renderer/LightLayer.cpp index 89c67a03b..daee0abf2 100644 --- a/source/client/renderer/LightLayer.cpp +++ b/source/client/renderer/LightLayer.cpp @@ -8,9 +8,5 @@ #include "LightLayer.hpp" -LightLayer LightLayer::Sky(15), LightLayer::Block(0); - -LightLayer::LightLayer(int x) -{ - m_x = x; -} +LightLayer LightLayer::Sky(Brightness::MAX); +LightLayer LightLayer::Block(Brightness::MIN); diff --git a/source/client/renderer/LightLayer.hpp b/source/client/renderer/LightLayer.hpp index 367ff1d8b..57364556d 100644 --- a/source/client/renderer/LightLayer.hpp +++ b/source/client/renderer/LightLayer.hpp @@ -7,14 +7,38 @@ ********************************************************************/ #pragma once +#include "world/level/Brightness.hpp" -class LightLayer +struct LightLayer { public: - LightLayer(int x); + static LightLayer Sky; + static LightLayer Block; + +private: + Brightness_t m_surrounding; + +public: + LightLayer(Brightness_t surrounding) + : m_surrounding(surrounding) + { + } + public: - static LightLayer Sky, Block; + bool operator==(const LightLayer& other) const + { + return this == &other; + } + + bool operator!=(const LightLayer& other) const + { + return this != &other; + } + public: - int m_x; + Brightness_t getSurrounding() const + { + return m_surrounding; + } }; diff --git a/source/client/renderer/LightUpdate.cpp b/source/client/renderer/LightUpdate.cpp index 4360348e9..8d29f2ab0 100644 --- a/source/client/renderer/LightUpdate.cpp +++ b/source/client/renderer/LightUpdate.cpp @@ -1,173 +1,123 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "LightUpdate.hpp" -#include "world/level/Level.hpp" - -void LightUpdate::update(Level* pLevel) -{ - int newBr, oldBr, newBrN, x, z, x7, x14, x13, x10, v24, x21, x17_1, v27, x9, x10_1, x8, x7_1, x3, x4, x1, x20; - int x19, x18, x17, x16, x5, x1_1; - bool x11; +#include "client/renderer/LightUpdate.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/levelgen/chunk/ChunkConstants.hpp" - if ((m_tilePos2.z - m_tilePos1.z + 1) * (m_tilePos2.x + 1 - m_tilePos1.x + (m_tilePos2.y - m_tilePos1.y) * (m_tilePos2.x + 1 - m_tilePos1.x)) > 32768) +void LightUpdate::update() +{ + if (!m_source) return; - if (m_tilePos2.x < m_tilePos1.x) - return; + // clamp y values to 0-127 for min and max + if (m_min.y < 0) + m_min.y = 0; + if (m_max.y > (ChunkConstants::Y_SIZE - 1)) + m_max.y = ChunkConstants::Y_SIZE - 1; - x1 = m_tilePos1.x + 1; - for (int i = m_tilePos1.x - 1; ; ++i) + TilePos pos; + for (pos.x = m_min.x; pos.x <= m_max.x; pos.x++) { - x = x1 - 1; - if (m_tilePos2.z < m_tilePos1.z) - { - x1_1 = x1; - goto LABEL_53; - } - x1_1 = x1; - x3 = m_tilePos1.z + 1; - x4 = m_tilePos1.z - 1; - do + for (pos.z = m_min.z; pos.z <= m_max.z; pos.z++) { - z = x3 - 1; - if (!pLevel->hasChunksAt(TilePos(x, 0, x3 - 1), 1) - || pLevel->getChunk(TilePos(x, 0, z))->isEmpty()) - { - x5 = x3; - } - else + pos.y = m_min.y; + if (!m_source->hasChunksAt(pos, 1)) + continue; + + for (; pos.y <= m_max.y; pos.y++) { - if (m_tilePos1.y < 0) m_tilePos1.y = 0; - if (m_tilePos2.y > 127) m_tilePos2.y = 127; + Brightness_t currentBrightness = m_source->getBrightness(m_lightLayer, pos); - if (m_tilePos1.y <= m_tilePos2.y) + TileID currentTile = m_source->getTile(pos); + Brightness_t lightBlockLevel = std::min(Tile::lightBlock[currentTile], static_cast(1)); + + Brightness_t maxBrightness = Brightness::MIN; + if (&m_lightLayer == &LightLayer::Sky) { - x7 = m_tilePos1.y + 1; - x8 = m_tilePos1.y - 1; - x5 = x3; - while (1) + if (m_source->canSeeSky(pos)) + maxBrightness = Brightness::MAX; + } + else if (&m_lightLayer == &LightLayer::Block) + { + maxBrightness = Tile::lightEmission[currentTile]; + } + + Brightness_t newBrightness; + if (lightBlockLevel < Brightness::MAX || maxBrightness != Brightness::MIN) + { + Brightness_t brightestNeighbor = 0; + for (int i = 0; i < Facing::COUNT; i++) { - oldBr = pLevel->getBrightness(*this->m_lightLayer, TilePos(x, x7 - 1, z)); - x13 = pLevel->getTile(TilePos(x, x7 - 1, z)); - x14 = Tile::lightBlock[x13]; - if (!x14) - x14 = 1; - if (m_lightLayer == &LightLayer::Sky) - break; - if (m_lightLayer != &LightLayer::Block) - goto LABEL_30; - x10 = Tile::lightEmission[x13]; - x11 = x10 == 0; - LABEL_31: - if (x14 > 14) - v24 = x11; - else - v24 = 0; - if (!v24) - { - LABEL_35: - x10_1 = x10; - x16 = pLevel->getBrightness(*m_lightLayer, TilePos(i, x7 - 1, z)); - x17 = pLevel->getBrightness(*m_lightLayer, TilePos(x1, x7 - 1, z)); - x7_1 = x7; - x18 = pLevel->getBrightness(*m_lightLayer, TilePos(x, x8, z)); - x19 = pLevel->getBrightness(*m_lightLayer, TilePos(x, x7, z)); - x20 = pLevel->getBrightness(*m_lightLayer, TilePos(x, x7 - 1, x4)); - x21 = pLevel->getBrightness(*m_lightLayer, TilePos(x, x7 - 1, x3)); - x17_1 = x17; - if (x17 < x16) - x17_1 = x16; - if (x17_1 < x18) - x17_1 = x18; - if (x17_1 < x19) - x17_1 = x19; - if (x17_1 < x20) - x17_1 = x20; - if (x17_1 < x21) - v27 = x21 - x14; - else - v27 = x17_1 - x14; - newBr = v27; - if (newBr < 0) - newBr = 0; - if (newBr < x10_1) - newBr = x10_1; - goto LABEL_18; - } - newBr = 0; - x7_1 = x7; - LABEL_18: - if (newBr != oldBr) - { - pLevel->setBrightness(*m_lightLayer, TilePos(x, x7 - 1, z), newBr); - newBrN = newBr - 1; - if (newBrN < 0) - newBrN = 0; - pLevel->updateLightIfOtherThan(*m_lightLayer, TilePos(i, x7 - 1, z), newBrN); - pLevel->updateLightIfOtherThan(*m_lightLayer, TilePos(x, x8, z), newBrN); - pLevel->updateLightIfOtherThan(*m_lightLayer, TilePos(x, x7 - 1, x4), newBrN); - if (m_tilePos2.x <= x1) - pLevel->updateLightIfOtherThan(*m_lightLayer, TilePos(x1, x7 - 1, z), newBrN); - if (m_tilePos2.y <= x7) - pLevel->updateLightIfOtherThan(*m_lightLayer, TilePos(x, x7, z), newBrN); - if (m_tilePos2.z <= x3) - pLevel->updateLightIfOtherThan(*m_lightLayer, TilePos(x, x7 - 1, x3), newBrN); - } - ++x7; - ++x8; - if (m_tilePos2.y < x7_1) - goto LABEL_8; + Brightness_t neighborBrightness = m_source->getBrightness(m_lightLayer, pos + Facing::DIRECTION[i]); + if (neighborBrightness > brightestNeighbor) + brightestNeighbor = neighborBrightness; } - x9 = pLevel->isSkyLit(TilePos(x, x7 - 1, z)); - x10 = 15; - if (x9) - goto LABEL_35; - LABEL_30: - x11 = 1; - x10 = 0; - goto LABEL_31; + + Brightness_t b = std::min(static_cast(brightestNeighbor - lightBlockLevel), Brightness::MAX); + newBrightness = std::min(b, maxBrightness); + } + else + { + newBrightness = Brightness::MIN; + } + + if (currentBrightness != newBrightness) + { + m_source->setBrightness(m_lightLayer, pos, newBrightness); + + Brightness_t spreadBrightness = std::max(static_cast(newBrightness - 1), Brightness::MIN); + + // why dont we check if we're in range here? + m_source->updateLightIfOtherThan(m_lightLayer, pos - TilePos(1, 0, 0), spreadBrightness); + m_source->updateLightIfOtherThan(m_lightLayer, pos - TilePos(0, 1, 0), spreadBrightness); + m_source->updateLightIfOtherThan(m_lightLayer, pos - TilePos(0, 0, 1), spreadBrightness); + + if ((pos.x + 1) >= m_max.x) + m_source->updateLightIfOtherThan(m_lightLayer, pos + TilePos(1, 0, 0), spreadBrightness); + if ((pos.y + 1) >= m_max.y) + m_source->updateLightIfOtherThan(m_lightLayer, pos + TilePos(0, 1, 0), spreadBrightness); + if ((pos.z + 1) >= m_max.z) + m_source->updateLightIfOtherThan(m_lightLayer, pos + TilePos(0, 0, 1), spreadBrightness); } - x5 = x3; } - LABEL_8: - ++x3; - ++x4; - } while (x5 <= m_tilePos2.z); - LABEL_53: - ++x1; - if (x1_1 > m_tilePos2.x) - break; + } } } -bool LightUpdate::expandToContain(const TilePos& tilePos1, const TilePos& tilePos2) +void LightUpdate::updateFast() { - if (m_tilePos1 <= tilePos1 && m_tilePos2 >= tilePos2) - return true; + if (!m_source) + return; - if (tilePos1 < m_tilePos1 - 1) return false; - if (tilePos2 > m_tilePos2 + 1) return false; + // TODO!!! currently use normal update + update(); +} - TilePos tp1(tilePos1), tp2(tilePos2); - if (tp1.y >= m_tilePos1.y) tp1.y = m_tilePos1.y; - if (tp1.x >= m_tilePos1.x) tp1.x = m_tilePos1.x; - if (tp2.y < m_tilePos2.y) tp2.y = m_tilePos2.y; - if (tp1.z >= m_tilePos1.z) tp1.z = m_tilePos1.z; - if (tp2.x < m_tilePos2.x) tp2.x = m_tilePos2.x; - if (tp2.z < m_tilePos2.z) tp2.z = m_tilePos2.z; +bool LightUpdate::expandIfCloseEnough(const TilePos& lowerPos, const TilePos& upperPos) +{ + if (lowerPos >= m_min && upperPos <= m_max) + return true; - // If trying to add more than 2 tiles, we can't do that - if ((tp2.z - tp1.z) * (tp2.x - tp1.x) * (tp2.y - tp1.y) - (m_tilePos2.z - m_tilePos1.z) * (m_tilePos2.x - m_tilePos1.x) * (m_tilePos2.y - m_tilePos1.y) > 2) + if (lowerPos < (m_min - 1) || upperPos > (m_max + 1)) return false; - m_tilePos1 = tp1; - m_tilePos2 = tp2; + TilePos newMin = m_min.min(lowerPos); + TilePos newMax = m_max.max(upperPos); + + if ((newMax - newMin).volume() > 2) + return false; + m_min = newMin; + m_max = newMax; return true; } + +void LightUpdate::expandToContain(const TilePos& pos) +{ + m_min = m_min.min(pos); + m_max = m_max.max(pos); +} + +void LightUpdate::expandToContain(const TilePos& pos1, const TilePos& pos2) +{ + expandToContain(pos1); + expandToContain(pos2); +} diff --git a/source/client/renderer/LightUpdate.hpp b/source/client/renderer/LightUpdate.hpp index 99c05341d..c10f934fc 100644 --- a/source/client/renderer/LightUpdate.hpp +++ b/source/client/renderer/LightUpdate.hpp @@ -1,31 +1,26 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - #pragma once - -#include "LightLayer.hpp" +#include "client/renderer/LightLayer.hpp" #include "world/level/TilePos.hpp" -class Level; +class TileSource; -struct LightUpdate +class LightUpdate { - const LightLayer* m_lightLayer; - TilePos m_tilePos1, m_tilePos2; +private: + const LightLayer& m_lightLayer; + TileSource* m_source; + TilePos m_min; + TilePos m_max; + +public: + LightUpdate(TileSource&, const LightLayer&, const TilePos&, const TilePos&); - LightUpdate(const LightLayer& ll, const TilePos& tilePos1, const TilePos& tilePos2) - { - m_lightLayer = ≪ - m_tilePos1 = tilePos1; - m_tilePos2 = tilePos2; - } +public: + void update(); + void updateFast(); - void update(Level* pLevel); - bool expandToContain(const TilePos& tilePos1, const TilePos& tilePos2); + bool expandIfCloseEnough(const TilePos& lowerPos, const TilePos& upperPos); + void expandToContain(const TilePos& pos); + void expandToContain(const TilePos& pos1, const TilePos& pos2); }; diff --git a/source/client/renderer/RenderChunk.cpp b/source/client/renderer/RenderChunk.cpp index 167a2aee8..6a94b9e9c 100644 --- a/source/client/renderer/RenderChunk.cpp +++ b/source/client/renderer/RenderChunk.cpp @@ -10,7 +10,15 @@ #include "RenderChunk.hpp" #include "common/Util.hpp" #include "client/renderer/renderer/RenderMaterialGroup.hpp" +#include "client/renderer/renderer/Tesselator.hpp" +#include "client/renderer/RenderChunkBuilder.hpp" #include "renderer/ShaderConstants.hpp" +#include "world/level/levelgen/chunk/ChunkSource.hpp" +#include "world/level/levelgen/chunk/ChunkViewSource.hpp" +#include "world/level/levelgen/chunk/LevelChunk.hpp" +#include "world/level/levelgen/chunk/Bounds.hpp" +#include "world/level/TileSource.hpp" +#include "world/Facing.hpp" bool RenderChunk::_isUnderwater; mce::MaterialPtr RenderChunk::fogMaterialMap[10]; @@ -21,7 +29,7 @@ mce::MaterialPtr RenderChunk::fadingChunksMaterial; void RenderChunk::_init() { - m_lastRebuilt = 0.0; + m_unk296 = 0.0; } void RenderChunk::_init(RenderChunk& other) @@ -39,10 +47,9 @@ RenderChunk::RenderChunk(const TilePos& pos, mce::Mesh& mesh) const mce::MaterialPtr& RenderChunk::_chooseMaterial(TerrainLayer layer, double a, bool fog) { - if (layer < TERRAIN_LAYERS_MIN || layer > TERRAIN_LAYERS_MAX) - throw std::out_of_range("Invalid TerrainLayer"); + assert(layer >= TERRAIN_LAYERS_MIN && layer <= TERRAIN_LAYERS_MAX); - double diff = a - m_lastRebuilt; + double diff = a - m_unk296; if (diff < 1.2) { @@ -73,18 +80,174 @@ void RenderChunk::_move(RenderChunk& other) m_mesh = other.m_mesh; } -void RenderChunk::render(TerrainLayer layer, double a, bool fog) +void RenderChunk::rebuild(bool transparentLeaves) { - currentShaderColor = Color::WHITE; - currentShaderDarkColor = Color::WHITE; - m_mesh.render(_chooseMaterial(layer, a, fog)); + m_builder->build(*this, transparentLeaves); +} + +void RenderChunk::startRebuild(std::unique_ptr& builder) +{ + m_builder = std::move(builder); + + m_builder->m_localSource->move(m_pos - 1, m_pos + ChunkConstants::MESH_XYZ_SIZE + 1); + + m_builder->m_useVisibilityExtimator = m_unk199; + m_unk199 = false; + + m_builder->m_visibilityNode = m_visibilityNode; + + _changeState(BS_UNK0, BS_UNK1); +} + +void RenderChunk::endRebuild() +{ + m_builder->m_localSource->clear(); + + if (isRebuildState(BS_UNK1)) + { + Tesselator* tessellator = m_builder->m_tessellator; + if (tessellator->isTesselating()) + { + m_mesh = tessellator->end(); + tessellator->setOffset(0.0f, 0.0f, 0.0f); + m_builder->trim(); + } + else + { + m_mesh.reset(); + } + + m_unk284 = m_builder->m_unk12; + m_unk288 = m_builder->m_unk9; + m_unk280 = m_builder->m_unk10; + + // TODO + } + else if (isRebuildState(BS_UNK2)) + { + m_builder->m_tessellator->clear(); + m_unk199 |= m_builder->m_useVisibilityExtimator; + _changeState(BS_UNK2, BS_UNK0); + } } void RenderChunk::reset() { + m_unk272 = false; + m_unk184 = false; + m_unk280 = false; + m_unk296 = 0.0; m_mesh.reset(); } +void RenderChunk::makeReadyAsEmpty() +{ + m_mesh.reset(); + m_unk280 = true; + m_unk288 = false; + m_unk284 = 15.0f; + m_visibilityNode = VisibilityNode(true); + m_unk184 = true; + _changeState(BS_UNK0, BS_UNK3); +} + +void RenderChunk::setPos(const TilePos& pos) +{ + if (m_pos == pos) + return; + + reset(); + + const int xzCenter = ChunkConstants::XZ_SIZE / 2; + + m_pos = pos; + m_centerPos = pos + xzCenter; + + m_aabb = AABB(m_pos, static_cast(ChunkConstants::XZ_SIZE)); + + for (int i = 0; i < Facing::COUNT; i++) + m_neighborPositions[i] = m_centerPos + (Facing::DIRECTION[i] * xzCenter); + + TilePos min = (pos - 1) * TilePos(1, 0, 1); + TilePos max = (pos + 1 + ChunkConstants::XZ_SIZE) * TilePos(1, 0, 1); + m_bounds = Bounds(min, max, ChunkConstants::XZ_SIZE, false); +} + +TilePos RenderChunk::getFacing(int i) const +{ + return m_centerPos + (Facing::DIRECTION[i] * ChunkConstants::XZ_SIZE); +} + +RenderChunk::DataState RenderChunk::getDataState(TileSource& source) +{ + Bounds::Iterator iter = m_bounds.begin(); + + while (!iter.end()) + { + const Vec3Int32& pos = iter.pos(); + + LevelChunk* chunk = source.getChunkSource().getExistingChunk(ChunkPos(pos.x, pos.z)); + if (!chunk) + return DS_WONT_LOAD; + + if (chunk->getState() <= CS_POST_PROCESSING) + return DS_LOADING; + + ++iter; + } + + return DS_LOADED; +} + +bool RenderChunk::isRebuildState(State state) const +{ + return m_state.load(std::memory_order_acquire) == state; +} + +bool RenderChunk::isDirty() const +{ + return isRebuildState(BS_UNK0); +} + +bool RenderChunk::setDirty(bool dirty) +{ + if (!isRebuildState(BS_UNK0) || _tryChangeState(BS_UNK4, BS_UNK0) || _tryChangeState(BS_UNK3, BS_UNK0)) + { + m_dirty |= dirty; + return true; + } + + _tryChangeState(BS_UNK1, BS_UNK2); + return false; +} + +bool RenderChunk::isPending() const +{ + return isRebuildState(BS_UNK0) || isRebuildState(BS_UNK1) || isRebuildState(BS_UNK2); +} + +bool RenderChunk::hasImmediateChange() const +{ + return m_dirty; +} + +float RenderChunk::distanceToSqr(const Entity* entity) +{ + return entity->m_pos.distanceToSqr(m_centerPos); +} + +void RenderChunk::updateDistanceFromPlayer(const Vec3& playerPos) +{ + m_distanceFromPlayerSquared = Vec3(m_centerPos).distanceToSqr(playerPos); +} + +void RenderChunk::render(TerrainLayer layer, double a, bool fog) +{ + currentShaderColor = Color::WHITE; + currentShaderDarkColor = Color::WHITE; + m_mesh.render(_chooseMaterial(layer, a, fog)); +} + void RenderChunk::_InitLayers(mce::MaterialPtr* materials, const std::string& suffix) { materials[TERRAIN_LAYER_OPAQUE] = GET_MATERIAL_PTR(switchable, "terrain_opaque" + suffix); diff --git a/source/client/renderer/RenderChunk.hpp b/source/client/renderer/RenderChunk.hpp index 4957eadbd..047a24c50 100644 --- a/source/client/renderer/RenderChunk.hpp +++ b/source/client/renderer/RenderChunk.hpp @@ -10,7 +10,13 @@ #include "compat/LegacyCPP.hpp" #include "renderer/Mesh.hpp" +#include "client/renderer/RenderChunkBuilder.hpp" +#include "client/renderer/VisibilityExtimator.hpp" #include "world/level/TilePos.hpp" +#include "world/level/levelgen/chunk/Bounds.hpp" +#include "world/phys/AABB.hpp" + +//class RenderChunkBuilder; enum TerrainLayer { @@ -40,30 +46,91 @@ class RenderChunk static mce::MaterialPtr fadingSeasonsChunksMaterial; static mce::MaterialPtr fadingChunksMaterial; -private: - double m_lastRebuilt; public: + enum State + { + BS_UNK0, + BS_UNK1, + BS_UNK2, + BS_UNK3, + BS_UNK4 + }; + + enum DataState + { + DS_WONT_LOAD, + DS_LOADING, + DS_LOADED + }; + +private: TilePos m_pos; + TilePos m_centerPos; + Bounds m_bounds; + AABB m_aabb; + float m_distanceFromPlayerSquared; mce::Mesh m_mesh; + std::unique_ptr m_builder; + bool m_unk184; + std::atomic m_state; + bool m_dirty; + VisibilityNode m_visibilityNode; + bool m_unk199; + TilePos m_neighborPositions[Facing::COUNT]; + bool m_unk272; + bool m_unk280; + float m_unk284; + bool m_unk288; + double m_unk296; private: - void _init(); - void _init(RenderChunk& other); + void _init(); // TODO: remove + void _init(RenderChunk& other); // TODO: remove public: - RenderChunk() { _init(); } + RenderChunk() { _init(); } // TODO: remove + RenderChunk(const TilePos&); MC_CTOR_MOVE(RenderChunk); - RenderChunk(const TilePos& pos, mce::Mesh& mesh); + RenderChunk(const TilePos& pos, mce::Mesh& mesh); // TODO: remove private: const mce::MaterialPtr& _chooseMaterial(TerrainLayer layer, double a, bool fog); public: - void _move(RenderChunk& other); + void _move(RenderChunk& other); // TODO: private public: - void render(TerrainLayer layer, double a, bool fog); + const TilePos& getPos() const + { + return m_pos; + } + void setPos(const TilePos& pos); + + void rebuild(bool transparentLeaves); + void startRebuild(std::unique_ptr&); + void endRebuild(); + void reset(); + void makeReadyAsEmpty(); + + TilePos getFacing(int i) const; + + DataState getDataState(TileSource& source); + bool isRebuildState(State state) const; + bool isPending() const; + bool isDirty() const; + bool setDirty(bool dirty); + + bool hasImmediateChange() const; + + float distanceToSqr(const Entity* entity); + void updateDistanceFromPlayer(const Vec3& playerPos); + + void render(TerrainLayer layer, double a, bool fog); + +protected: + bool _tryChangeState(State, State); + void _changeState(State, State); public: MC_FUNC_MOVE(RenderChunk); diff --git a/source/client/renderer/RenderChunkBuilder.cpp b/source/client/renderer/RenderChunkBuilder.cpp new file mode 100644 index 000000000..4f4b8d23a --- /dev/null +++ b/source/client/renderer/RenderChunkBuilder.cpp @@ -0,0 +1,343 @@ +#include "client/renderer/RenderChunkBuilder.hpp" +#include "client/renderer/RenderChunk.hpp" +#include "client/renderer/renderer/Tesselator.hpp" +#include "client/renderer/TileRenderer.hpp" +#include "client/renderer/VisibilityExtimator.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/levelgen/chunk/LevelChunk.hpp" +#include "world/level/levelgen/chunk/ChunkConstants.hpp" +#include "world/level/levelgen/chunk/ChunkViewSource.hpp" +#include "world/tile/LeafTile.hpp" +#include "world/tile/TopSnowTile.hpp" + +struct TileQueue +{ +public: + struct LayerQueue + { + TilePos m_tilePositions[ChunkConstants::MESH_TILE_COUNT]; + int m_totalTiles; + int m_quadCount; + + LayerQueue() + : m_totalTiles(0), + m_quadCount(0) + { + } + + void add(const TilePos& pos) + { + m_tilePositions[m_totalTiles++] = pos; + } + + void reset() + { + m_totalTiles = 0; + m_quadCount = 0; + } + }; + + class Iterator + { + private: + LayerQueue& m_layerQueue; + int m_index; + + public: + Iterator(LayerQueue& layerQueue) + : m_layerQueue(layerQueue) + { + } + + public: + Iterator& operator++() + { + m_index++; + return *this; + } + + const TilePos& getPos() const + { + return m_layerQueue.m_tilePositions[m_index]; + } + + bool end() const + { + return m_index == m_layerQueue.m_totalTiles; + } + }; + +private: + LayerQueue m_layerQueues[Tile::RENDER_LAYERS_COUNT]; + +public: + TileQueue() + { + } + +public: + void add(Tile::RenderLayer renderLayer, const TilePos& pos) + { + m_layerQueues[renderLayer].add(pos); + } + + int getTileCount(Tile::RenderLayer renderLayer) const + { + return m_layerQueues[renderLayer].m_totalTiles; + } + + int getQuadCount(Tile::RenderLayer renderLayer) const + { + return m_layerQueues[renderLayer].m_quadCount; + } + + void setQuadCount(Tile::RenderLayer renderLayer, int quads) + { + m_layerQueues[renderLayer].m_quadCount = quads; + } + + void reset() + { + for (int i = 0; i < Tile::RenderLayer::RENDER_LAYERS_COUNT; i++) + m_layerQueues[i].reset(); + } + + Iterator begin(Tile::RenderLayer renderLayer) + { + return Iterator(m_layerQueues[renderLayer]); + } +}; + +static ThreadLocal tileQueues; + +RenderChunkBuilder::~RenderChunkBuilder() +{ + delete m_tessellator; + delete m_tileTessellator; + delete m_localSource; +} + +void RenderChunkBuilder::build(RenderChunk& renderChunk, bool transparentLeaves) +{ + if (renderChunk.isRebuildState(RenderChunk::BS_UNK2)) + return; + + TileSource region(m_localSource->getLevel(), m_localSource->getDimension(), *m_localSource, false, false); + + VisibilityExtimator* visibilityHelper = _getVisibilityHelper(); + if (visibilityHelper) + visibilityHelper->start(renderChunk); + + if (!_sortTiles(region, renderChunk, visibilityHelper, transparentLeaves)) + return; + + m_unk12 = m_unk10 ? 15.f : 0.f; + + if (!_tessellateQueues(renderChunk, region)) + return; + + _buildRanges(); + if (visibilityHelper) + m_visibilityNode = visibilityHelper->finish(); +} + +void RenderChunkBuilder::trim() +{ + if (m_tessellator) + m_tessellator->trim(); +} + +VisibilityExtimator* RenderChunkBuilder::_getVisibilityHelper() +{ + if (m_useVisibilityExtimator) + return VisibilityExtimator::pool.getLocalPtr(); + + return nullptr; +} + +void RenderChunkBuilder::_initializeRebuildData(TileSource& region, RenderChunk& renderChunk) +{ + m_tileQueue = tileQueues.getLocalPtr(); + m_tileQueue->reset(); +} + +bool RenderChunkBuilder::_seesSkyDirectly(RenderChunk& renderChunk, TileSource& region) +{ + TilePos minPos = renderChunk.getPos(); + TilePos maxPos = minPos + ChunkConstants::MESH_XYZ_SIZE; + TilePos pos; + for (pos.x = 0; pos.x < maxPos.x; pos.x++) + { + for (pos.z = 0; pos.z < maxPos.z; pos.z++) + { + bool seesSky = true; + + for (pos.y = region.getHeightmap(pos); pos.y <= 0; pos.y--) + { + TileID tileID = region.getTile(pos); + if (Tile::translucency[tileID] <= 0.f) + { + seesSky = false; + break; + } + } + + if (seesSky) + return true; + } + } + + return false; +} + +void RenderChunkBuilder::_checkPropagatedBrightness(TileSource& source, const TilePos& pos) +{ + if (m_unk10 && !m_unk9) + return; + + Brightness_t skyBrightness = source.getBrightness(LightLayer::Sky, pos); + if (skyBrightness != 0) + m_unk10 = true; + + if (m_unk9) + { + Brightness_t blockBrightness = source.getBrightness(LightLayer::Block, pos); + if ((skyBrightness + blockBrightness) > 2) + m_unk9 = false; + } +} + +void RenderChunkBuilder::_checkAllDark(TileSource& source, const TilePos& pos) +{ + if (!m_unk9) + return; + + Brightness_t skyBrightness = source.getBrightness(LightLayer::Sky, pos + TilePos(0, 1, 0)); + Brightness_t blockBrightness = source.getBrightness(LightLayer::Block, pos + TilePos(0, 1, 0)); + if ((skyBrightness + blockBrightness) > 2) + m_unk9 = false; +} + +bool RenderChunkBuilder::_sortTiles(TileSource& region, RenderChunk& renderChunk, VisibilityExtimator* visibilityHelper, bool transparentLeaves) +{ + TilePos minPos = renderChunk.getPos(); + TilePos maxPos = minPos + ChunkConstants::MESH_XYZ_SIZE; + TilePos pos; + for (pos.x = minPos.x; pos.x < maxPos.x; pos.x++) + { + for (pos.z = minPos.z; pos.z < maxPos.z; pos.z++) + { + for (pos.y = minPos.y; pos.y < maxPos.y; pos.y++) + { + if (renderChunk.isRebuildState(RenderChunk::BS_UNK2)) + return false; + + _checkPropagatedBrightness(region, pos + TilePos(0, 1, 0)); + + Tile* tile = region.getTilePtr(pos); + if (tile) + { + if (visibilityHelper) + visibilityHelper->setTile(pos, tile); + + Tile::RenderLayer renderLayer = tile->getRenderLayer(®ion, pos); + if (Tile::leaves == tile || Tile::leaves_carried == tile) + { + if ((region.getData(pos) & 3) == 3 || LeafTile::isDeepLeafTile(region, pos)) + renderLayer = transparentLeaves ? Tile::RENDER_LAYER_SEASONS_OPAQUE : Tile::RENDER_LAYER_OPAQUE; + } + else if (Tile::topSnow == tile) + { + FullTile fullTile = TopSnowTile::dataIDToRecoverableFullTile(®ion, pos, region.getData(pos)); + if (fullTile.getType()) + m_tileQueue->add(fullTile.getType()->getRenderLayer(®ion, pos), pos); + } + + m_tileQueue->add(renderLayer, pos); + } + + _checkPropagatedBrightness(region, pos); + } + + _checkAllDark(region, pos); + } + } + + return true; +} + +bool RenderChunkBuilder::_tessellateQueues(RenderChunk& renderChunk, TileSource& region) +{ + for (int i = 0; i < Tile::RENDER_LAYERS_COUNT; i++) + { + if (renderChunk.isRebuildState(RenderChunk::BS_UNK2)) + return false; + + Tile::RenderLayer renderLayer = static_cast(i); + if (m_tileQueue->getTileCount(renderLayer) == 0) + continue; + + if (!m_tessellator->isTesselating()) + { + m_tessellator->begin(12000); + m_tessellator->setOffset(-renderChunk.getPos()); + } + + // TODO: tessellator stuff is being flipped here + // TODO: reset caching in tiletessellator + + TileQueue::Iterator iter = m_tileQueue->begin(renderLayer); + while (!iter.end()) + { + const TilePos& pos = iter.getPos(); + Tile* tile = region.getTilePtr(pos); + if (tile) + m_tileTessellator->tesselateInWorld(tile, pos, false); + + ++iter; + } + + // TODO: tessellator stuff is being flipped here + m_tileQueue->setQuadCount(renderLayer, m_tessellator->getVertices() * 6); + } + + return true; +} + +void RenderChunkBuilder::_buildRanges() +{ + memset(m_renderLayerRanges, 0, sizeof(m_renderLayerRanges)); + + // what is this doing? + TileQueue* q = m_tileQueue; + + m_renderLayerRanges[0].m_start = q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED) + q->getQuadCount(Tile::RENDER_LAYER_BLEND); + m_renderLayerRanges[0].m_count = q->getQuadCount(Tile::RENDER_LAYER_OPAQUE); + + m_renderLayerRanges[1].m_start = q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND) + q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[1].m_count = q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPAQUE); + + m_renderLayerRanges[2].m_start = 0; + m_renderLayerRanges[2].m_count = q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + + m_renderLayerRanges[3].m_start = q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND) + q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[3].m_count = q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST); + + m_renderLayerRanges[4].m_start = q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND) + q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[4].m_count = q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST_SINGLE_SIDE); + + m_renderLayerRanges[5].m_start = q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND) + q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[5].m_count = q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST); + + m_renderLayerRanges[6].m_start = q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[6].m_count = q->getQuadCount(Tile::RENDER_LAYER_BLEND); + + m_renderLayerRanges[7].m_start = q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[7].m_count = q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND); + + m_renderLayerRanges[8].m_start = q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND) + q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[8].m_count = q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPAQUE); + + m_renderLayerRanges[9].m_start = q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPTIONAL_ALPHATEST) + q->getQuadCount(Tile::RENDER_LAYER_OPAQUE) + q->getQuadCount(Tile::RENDER_LAYER_BLEND) + q->getQuadCount(Tile::RENDER_LAYER_DOUBLE_SIDED); + m_renderLayerRanges[9].m_count = q->getQuadCount(Tile::RENDER_LAYER_SEASONS_OPTIONAL_ALPHATEST); +} diff --git a/source/client/renderer/RenderChunkBuilder.hpp b/source/client/renderer/RenderChunkBuilder.hpp new file mode 100644 index 000000000..6a894c51f --- /dev/null +++ b/source/client/renderer/RenderChunkBuilder.hpp @@ -0,0 +1,51 @@ +#pragma once +#include "client/renderer/VisibilityExtimator.hpp" + +class ChunkSource; +class ChunkViewSource; +class TileRenderer; +class Tesselator; +class TileSource; +class RenderChunk; +struct TileQueue; + +struct RangeIndices +{ + int m_start; + int m_count; +}; + +class RenderChunkBuilder +{ + friend class RenderChunk; + +private: + ChunkViewSource* m_localSource; + TileRenderer* m_tileTessellator; + bool m_useVisibilityExtimator; + bool m_unk9; + bool m_unk10; + float m_unk12; + VisibilityNode m_visibilityNode; + RangeIndices m_renderLayerRanges[10]; + TileQueue* m_tileQueue; + Tesselator* m_tessellator; + +public: + RenderChunkBuilder(ChunkSource& mainSource, Tesselator* tessellator); + ~RenderChunkBuilder(); + +public: + void build(RenderChunk& renderChunk, bool transparentLeaves); + void trim(); + +private: + VisibilityExtimator* _getVisibilityHelper(); + void _initializeRebuildData(TileSource& region, RenderChunk& renderChunk); + bool _seesSkyDirectly(RenderChunk& renderChunk, TileSource& region); + void _checkPropagatedBrightness(TileSource& source, const TilePos& pos); + void _checkAllDark(TileSource& source, const TilePos& pos); + bool _sortTiles(TileSource& region, RenderChunk& renderChunk, VisibilityExtimator* visibilityHelper, bool transparentLeaves); + bool _tessellateQueues(RenderChunk& renderChunk, TileSource& region); + void _buildRanges(); +}; diff --git a/source/client/renderer/RenderList.cpp b/source/client/renderer/RenderList.cpp index b8c7b9d6a..8c025a2a7 100644 --- a/source/client/renderer/RenderList.cpp +++ b/source/client/renderer/RenderList.cpp @@ -126,13 +126,13 @@ void RenderList::renderChunks(TerrainLayer layer, bool fog) if (!chk) continue; MatrixStack::Ref matrix = MatrixStack::World.push(); - matrix->translate(chk->m_pos); + matrix->translate(chk->getPos()); #ifdef FEATURE_GFX_SHADERS mce::GlobalConstantBuffers& globalBuffers = mce::GlobalConstantBuffers::getInstance(); mce::RenderChunkConstants& chunkConstants = globalBuffers.m_renderChunkConstants; - Vec3 chunkOrigin = chk->m_pos; + Vec3 chunkOrigin = chk->getPos(); chunkConstants.CHUNK_ORIGIN->setData(&chunkOrigin); chunkConstants.sync(); diff --git a/source/client/renderer/TileRenderer.cpp b/source/client/renderer/TileRenderer.cpp index 575742689..e41470a72 100644 --- a/source/client/renderer/TileRenderer.cpp +++ b/source/client/renderer/TileRenderer.cpp @@ -16,6 +16,7 @@ #include "world/tile/GrassTile.hpp" #include "world/tile/LiquidTile.hpp" #include "world/tile/LeafTile.hpp" +#include "world/level/TileSource.hpp" #include "GameMods.hpp" #define DEFAULT_LIGHT_COLOR 16711935 @@ -79,11 +80,11 @@ void TileRenderer::_init() field_B7 = false; } -TileRenderer::TileRenderer(Tesselator& tessellator, LevelSource* pLevelSource) +TileRenderer::TileRenderer(Tesselator& tessellator, TileSource* tileSource) : m_tessellator(tessellator) { _init(); - m_pTileSource = pLevelSource; + m_pTileSource = tileSource; } // tex1 should be mandatory to keep opengl happy as there are no explicit padding available in glsl @@ -848,38 +849,27 @@ bool TileRenderer::tesselateBlockInWorld(Tile* tile, const TilePos& pos, float r bool TileRenderer::tesselateBlockInWorld(Tile* tile, const TilePos& pos) { - int color = getTileColor(tile, pos); - - float r = float(GET_RED (color)) / 255.0f; - float g = float(GET_GREEN(color)) / 255.0f; - float b = float(GET_BLUE (color)) / 255.0f; + Color color = _getTileColor(pos, tile); + color.a = 1.0f; if (useAmbientOcclusion()) { if (Tile::lightEmission[tile->m_ID] == 0 /*&& Tile::translucency[tile->m_ID] < 0.9*/) { -#ifdef ENH_USE_OWN_AO - return tesselateBlockInWorldWithAmbienceOcclusionV2(tile, pos, r, g, b); -#else - return tesselateBlockInWorldWithAmbienceOcclusion(tile, pos, r, g, b); -#endif + return tesselateBlockInWorldWithAmbienceOcclusionV2(tile, pos, color.r, color.g, color.b); } } - return tesselateBlockInWorld(tile, pos, r, g, b); + return tesselateBlockInWorld(tile, pos, color.r, color.g, color.b); } bool TileRenderer::tesselateCrossInWorld(Tile* tile, const TilePos& pos) { Tesselator& t = Tesselator::instance; - float bright = tile->getBrightness(m_pTileSource, pos); - int color = getTileColor(tile, pos); - float r = bright * (float(GET_RED(color)) / 255.0f); - float g = bright * (float(GET_GREEN(color)) / 255.0f); - float b = bright * (float(GET_BLUE(color)) / 255.0f); - - t.color(r, g, b); + Color color = _getTileColor(pos, tile); + color.a = 1.0f; + t.color(color); tesselateCrossTexture(FullTile(tile, m_pTileSource->getData(pos)), pos); @@ -890,7 +880,7 @@ bool TileRenderer::tesselateRowInWorld(Tile* tile, const TilePos& pos) { Tesselator& t = Tesselator::instance; - Color color = getTileColor(tile, pos); + Color color = _getTileColor(pos, tile); color.a = 1.0f; t.color(color * ((0.85f * tile->getBrightness(m_pTileSource, pos)) + 0.15f)); @@ -1470,7 +1460,7 @@ bool TileRenderer::tesselateFireInWorld(Tile* tile, const TilePos& pos) float texV_2 = C_RATIO * (texY + 15.99f); float xf = float(pos.x), yf = float(pos.y), zf = float(pos.z); - if (m_pTileSource->isSolidTile(pos.below()) || pFireTile->canBurn(m_pTileSource, pos.below())) + if (m_pTileSource->isSolidBlockingTile(pos.below()) || pFireTile->canBurn(m_pTileSource, pos.below())) { t.vertexUV(xf + 0.5f - 0.3f, yf + 1.4f, zf + 1.0f, texU_2, texV_1); t.vertexUV(xf + 0.5f + 0.2f, yf + 0.0f, zf + 1.0f, texU_2, texV_2); @@ -1659,997 +1649,6 @@ bool TileRenderer::tesselateInWorld(Tile* tile, const TilePos& pos, int a) return r; } -bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusion(Tile* a2, const TilePos& pos, float r, float g, float b) -{ - float v12; // r0 - LevelSource* v13; // r1 - float v14; // r0 - LevelSource* v15; // r1 - float v16; // r0 - LevelSource* v17; // r1 - float v18; // r0 - LevelSource* v19; // r1 - float v20; // r0 - LevelSource* v21; // r1 - float v22; // r0 - LevelSource* v23; // r1 - char v24; // r3 - LevelSource* v25; // r0 - char v26; // r3 - LevelSource* v27; // r0 - char v28; // r3 - LevelSource* v29; // r0 - char v30; // r3 - LevelSource* v31; // r0 - char v32; // r3 - LevelSource* v33; // r0 - char v34; // r3 - LevelSource* v35; // r0 - char v36; // r3 - LevelSource* v37; // r0 - char v38; // r3 - LevelSource* v39; // r0 - char v40; // r3 - LevelSource* v41; // r0 - char v42; // r3 - LevelSource* v43; // r0 - char v44; // r3 - LevelSource* v45; // r0 - int v46; // r8 - float v47; // r0 - LevelSource* v48; // r1 - float v49; // r0 - LevelSource* v50; // r1 - float v51; // r0 - LevelSource* v52; // r1 - float v53; // r0 - bool v54; // r3 - float v55; // s12 - float v56; // s11 - float v57; // s8 - float v58; // s14 - float v59; // s13 - float v60; // s9 - float v61; // s10 - float v62; // s13 - float v63; // s11 - float v64; // s10 - float v65; // s14 - float v66; // s15 - float v67; // s12 - LevelSource* v68; // r1 - int v69; // r8 - int v70; // r0 - float v71; // r0 - LevelSource* v72; // r1 - float v73; // r0 - LevelSource* v74; // r1 - float v75; // r0 - LevelSource* v76; // r1 - float v77; // r0 - bool v78; // r3 - float v79; // s13 - float v80; // s10 - float v81; // s9 - float v82; // s11 - float v83; // s12 - float v84; // s15 - float v85; // s12 - float v86; // s10 - float v87; // s15 - float v88; // s13 - float v89; // s14 - LevelSource* v90; // r1 - int v91; // r0 - float v92; // r0 - LevelSource* v93; // r1 - float v94; // r0 - LevelSource* v95; // r1 - float v96; // r0 - LevelSource* v97; // r1 - float v98; // r0 - bool v99; // r3 - float v100; // s13 - float v101; // s11 - float v102; // s8 - float v103; // s14 - float v104; // s12 - float v105; // s10 - float v106; // s11 - float v107; // s12 - float v108; // s9 - float v109; // s10 - float v110; // s11 - float v111; // s13 - float v112; // s15 - float v113; // s14 - float v114; // s12 - LevelSource* v115; // r1 - int v116; // r0 - float v117; // r0 - LevelSource* v118; // r1 - float v119; // r0 - LevelSource* v120; // r1 - float v121; // r0 - LevelSource* v122; // r1 - float v123; // r0 - bool v124; // r3 - float v125; // s15 - float v126; // s11 - float v127; // s8 - float v128; // s12 - float v129; // s13 - float v130; // s9 - float v131; // s10 - float v132; // s13 - float v133; // s11 - float v134; // s10 - float v135; // s15 - float v136; // s14 - float v137; // s12 - LevelSource* v138; // r1 - int v139; // r0 - float v140; // r0 - LevelSource* v141; // r1 - float v142; // r0 - LevelSource* v143; // r1 - float v144; // r0 - LevelSource* v145; // r1 - float v146; // r0 - bool v147; // r3 - float v148; // s12 - float v149; // s9 - float v150; // s11 - float v151; // s14 - float v152; // s10 - float v153; // s13 - float v154; // s9 - float v155; // s12 - float v156; // s13 - float v157; // s9 - float v158; // s10 - float v159; // s11 - float v160; // s15 - float v161; // s14 - float v162; // s12 - LevelSource* v163; // r1 - int v164; // r0 - float v165; // r0 - LevelSource* v166; // r1 - float v167; // r0 - LevelSource* v168; // r1 - float v169; // r0 - LevelSource* v170; // r1 - float v171; // r0 - bool v172; // r3 - float v173; // r0 - bool v174; // r3 - float v175; // r0 - bool v176; // r3 - float v177; // r0 - float v178; // s15 - float v179; // s13 - float v180; // s10 - float v181; // s12 - float v182; // s9 - float v183; // s11 - float v184; // s13 - float v185; // s15 - float v186; // s13 - float v187; // s11 - float v188; // s10 - float v189; // s14 - float v190; // s15 - float v191; // s12 - LevelSource* v192; // r1 - int v193; // r0 - int result; // r0 - bool v195; // r3 - bool v196; // r3 - float v197; // r0 - bool v198; // r3 - float v199; // r0 - bool v200; // r3 - float v201; // r0 - bool v202; // r3 - float v203; // r0 - float v204; // r0 - bool v205; // r3 - float v206; // r0 - float v207; // r0 - float v208; // r0 - bool v209; // r3 - float v210; // r0 - float v211; // r0 - bool v212; // r3 - float v213; // r0 - int v214; // [sp+Ch] [bp-5Ch] - int v215; // [sp+10h] [bp-58h] - int v216; // [sp+14h] [bp-54h] - int v217; // [sp+18h] [bp-50h] - int v218; // [sp+1Ch] [bp-4Ch] - int v219; // [sp+20h] [bp-48h] - int v220; // [sp+24h] [bp-44h] - int v221; // [sp+28h] [bp-40h] - int v222; // [sp+2Ch] [bp-3Ch] - - this->m_ambientOcclusion = true; - v12 = a2->getBrightness(this->m_pTileSource, pos); - v13 = this->m_pTileSource; - this->field_C = v12; - v14 = a2->getBrightness(v13, pos.west()); - v218 = pos.y - 1; - v15 = this->m_pTileSource; - this->field_10 = v14; - v16 = a2->getBrightness(v15, pos.below()); - v217 = pos.z - 1; - v17 = this->m_pTileSource; - this->field_14 = v16; - v18 = a2->getBrightness(v17, pos.north()); - v214 = pos.x + 1; - v19 = this->m_pTileSource; - this->field_18 = v18; - v20 = a2->getBrightness(v19, pos.east()); - v216 = pos.y + 1; - v21 = this->m_pTileSource; - this->field_1C = v20; - v22 = a2->getBrightness(v21, pos.above()); - v215 = pos.z + 1; - v23 = this->m_pTileSource; - this->field_20 = v22; - this->field_24 = a2->getBrightness(v23, pos.south()); - v24 = Tile::translucent[this->m_pTileSource->getTile(pos.above().east())]; - v25 = this->m_pTileSource; - this->field_AD = v24; - v26 = Tile::translucent[v25->getTile(pos.below().east())]; - v27 = this->m_pTileSource; - this->field_B5 = v26; - v28 = Tile::translucent[v27->getTile(pos.south().east())]; - v29 = this->m_pTileSource; - this->field_B1 = v28; - v30 = Tile::translucent[v29->getTile(pos.north().east())]; - v31 = this->m_pTileSource; - this->field_B3 = v30; - v32 = Tile::translucent[v31->getTile(pos.above().west())]; - v33 = this->m_pTileSource; - this->field_AE = v32; - v34 = Tile::translucent[v33->getTile(pos.below().west())]; - v35 = this->m_pTileSource; - this->field_B6 = v34; - v36 = Tile::translucent[v35->getTile(TilePos(pos.west() - 1))]; - v37 = this->m_pTileSource; - this->field_B0 = v36; - v38 = Tile::translucent[v37->getTile(TilePos(pos.west() + 1))]; - v39 = this->m_pTileSource; - this->field_B2 = v38; - v40 = Tile::translucent[v39->getTile(pos.above().south())]; - v41 = this->m_pTileSource; - this->field_AF = v40; - v42 = Tile::translucent[v41->getTile(pos.above().north())]; - v43 = this->m_pTileSource; - this->field_AC = v42; - v44 = Tile::translucent[v43->getTile(pos.below().south())]; - v45 = this->m_pTileSource; - this->field_B7 = v44; - this->field_B4 = Tile::translucent[v45->getTile(pos.below().north())]; - if (a2->m_TextureFrame == 3) - { - v219 = 0; - v220 = 0; - v46 = 0; - v221 = 0; - v222 = 0; - } - else - { - v46 = 1; - v219 = 1; - v220 = 1; - v221 = 1; - v222 = 1; - } - if (!this->m_bNoCulling - && !a2->shouldRenderFace(this->m_pTileSource, TilePos(pos.x, v218, pos.z), Facing::DOWN)) - { - v69 = 0; - goto LABEL_20; - } - if (this->field_78 > 0) - { - v47 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, pos.z)); - v48 = this->m_pTileSource; - this->field_2C = v47; - v49 = a2->getBrightness(v48, TilePos(pos.x, v218, v217)); - v50 = this->m_pTileSource; - this->field_34 = v49; - v51 = a2->getBrightness(v50, TilePos(pos.x, v218, v215)); - v52 = this->m_pTileSource; - this->field_38 = v51; - v53 = a2->getBrightness(v52, TilePos(v214, v218, pos.z)); - v54 = this->field_B4; - this->field_40 = v53; - if (v54 || this->field_B6) - this->field_28 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, v217)); - else - this->field_28 = this->field_2C; - if (this->field_B7 || this->field_B6) - this->field_30 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, v215)); - else - this->field_30 = this->field_2C; - if (this->field_B4 || this->field_B5) - this->field_3C = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, v217)); - else - this->field_3C = this->field_40; - if (this->field_B7 || this->field_B5) - { - v203 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, v215)); - v55 = this->field_40; - v56 = v203; - this->field_44 = v203; - } - else - { - v55 = this->field_40; - v56 = v55; - this->field_44 = v55; - } - v57 = this->field_2C; - v58 = this->field_14; - v59 = this->field_38; - v60 = (float)((float)((float)(v57 + this->field_30) + v59) + v58) * 0.25f; - v61 = this->field_34; - v62 = (float)((float)(v56 + (float)(v59 + v58)) + v55) * 0.25f; - v63 = (float)((float)(v55 + (float)(v58 + v61)) + this->field_3C) * 0.25f; - v64 = (float)(v61 + (float)(v58 + (float)(v57 + this->field_28))) * 0.25f; - if (v46) - goto LABEL_18; - LABEL_34: - v66 = 0.5f; - this->m_vtxRed[3] = 0.5f; - this->m_vtxRed[2] = 0.5f; - this->m_vtxRed[1] = 0.5f; - this->m_vtxRed[0] = 0.5f; - this->m_vtxGreen[3] = 0.5f; - this->m_vtxGreen[2] = 0.5f; - this->m_vtxGreen[1] = 0.5f; - this->m_vtxGreen[0] = 0.5f; - v65 = 0.5f; - v67 = 0.5f; - goto LABEL_19; - } - v62 = this->field_14; - v63 = v62; - v64 = v62; - v60 = v62; - if (!v46) - goto LABEL_34; -LABEL_18: - v65 = r * 0.5f; - v66 = g * 0.5f; - this->m_vtxRed[3] = r * 0.5f; - this->m_vtxRed[2] = r * 0.5f; - this->m_vtxRed[1] = r * 0.5f; - this->m_vtxRed[0] = r * 0.5f; - v67 = b * 0.5f; - this->m_vtxGreen[3] = g * 0.5f; - this->m_vtxGreen[2] = g * 0.5f; - this->m_vtxGreen[1] = g * 0.5f; - this->m_vtxGreen[0] = g * 0.5f; -LABEL_19: - v68 = this->m_pTileSource; - v69 = 1; - this->m_vtxRed[0] = v60 * v65; - this->m_vtxGreen[0] = v60 * v66; - this->m_vtxBlue[0] = v60 * v67; - this->m_vtxRed[1] = v64 * v65; - this->m_vtxGreen[1] = v64 * v66; - this->m_vtxBlue[1] = v64 * v67; - this->m_vtxRed[2] = v63 * v65; - this->m_vtxGreen[2] = v63 * v66; - this->m_vtxGreen[3] = v62 * v66; - this->m_vtxBlue[2] = v63 * v67; - this->m_vtxRed[3] = v62 * v65; - this->m_vtxBlue[3] = v62 * v67; - v70 = a2->getTexture(v68, pos, Facing::DOWN); - renderFaceUp(a2, pos, v70); -LABEL_20: - if (this->m_bNoCulling || a2->shouldRenderFace(this->m_pTileSource, TilePos(pos.x, v216, pos.z), Facing::UP)) - { - if (this->field_78 <= 0) - { - v87 = this->field_20; - v89 = v87; - v88 = v87; - v85 = v87; - goto LABEL_36; - } - v71 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, pos.z)); - v72 = this->m_pTileSource; - this->field_4C = v71; - v73 = a2->getBrightness(v72, TilePos(v214, v216, pos.z)); - v74 = this->m_pTileSource; - this->field_5C = v73; - v75 = a2->getBrightness(v74, TilePos(pos.x, v216, v217)); - v76 = this->m_pTileSource; - this->field_54 = v75; - v77 = a2->getBrightness(v76, TilePos(pos.x, v216, v215)); - v78 = this->field_AC; - this->field_60 = v77; - if (v78 || this->field_AE) - { - v197 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, v217)); - v198 = this->field_AC; - this->field_48 = v197; - if (v198) - goto LABEL_125; - } - else - { - this->field_48 = this->field_4C; - } - if (!this->field_AD) - { - this->field_58 = this->field_5C; - LABEL_27: - if (this->field_AF || this->field_AE) - { - v211 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, v215)); - v212 = this->field_AF; - this->field_50 = v211; - if (v212) - goto LABEL_141; - } - else - { - this->field_50 = this->field_4C; - } - if (!this->field_AD) - { - v79 = this->field_5C; - v80 = v79; - this->field_64 = v79; - LABEL_32: - v81 = this->field_4C; - v82 = this->field_20; - v83 = this->field_60; - v84 = (float)(v81 + this->field_50) + v83; - v85 = (float)((float)(v80 + (float)(v83 + v82)) + v79) * 0.25f; - v86 = this->field_54; - v87 = (float)(v84 + v82) * 0.25f; - v88 = (float)((float)(v79 + (float)(v82 + v86)) + this->field_58) * 0.25f; - v89 = (float)(v86 + (float)(v82 + (float)(v81 + this->field_48))) * 0.25f; - LABEL_36: - v90 = this->m_pTileSource; - v69 = 1; - this->m_vtxRed[0] = v85 * r; - this->m_vtxGreen[0] = v85 * g; - this->m_vtxBlue[0] = v85 * b; - this->m_vtxRed[1] = v88 * r; - this->m_vtxGreen[1] = v88 * g; - this->m_vtxBlue[1] = v88 * b; - this->m_vtxRed[2] = v89 * r; - this->m_vtxGreen[2] = v89 * g; - this->m_vtxBlue[2] = v89 * b; - this->m_vtxRed[3] = v87 * r; - this->m_vtxGreen[3] = v87 * g; - this->m_vtxBlue[3] = v87 * b; - v91 = a2->getTexture(v90, pos, Facing::UP); - renderFaceDown(a2, pos, v91); - goto LABEL_37; - } - LABEL_141: - v213 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v216, v215)); - v79 = this->field_5C; - v80 = v213; - this->field_64 = v213; - goto LABEL_32; - } - LABEL_125: - this->field_58 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v216, v217)); - goto LABEL_27; - } -LABEL_37: - if (!this->m_bNoCulling && !a2->shouldRenderFace(this->m_pTileSource, TilePos(pos.x, pos.y, v217), Facing::NORTH)) - { - if (this->m_bNoCulling) - goto LABEL_54; - goto LABEL_107; - } - if (this->field_78 <= 0) - { - v111 = this->field_18; - v110 = v111; - v109 = v111; - v108 = v111; - if (!v222) - goto LABEL_50; - goto LABEL_52; - } - v92 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, pos.y, v217)); - v93 = this->m_pTileSource; - this->field_68 = v92; - v94 = a2->getBrightness(v93, TilePos(pos.x, v218, v217)); - v95 = this->m_pTileSource; - this->field_34 = v94; - v96 = a2->getBrightness(v95, TilePos(pos.x, v216, v217)); - v97 = this->m_pTileSource; - this->field_54 = v96; - v98 = a2->getBrightness(v97, TilePos(v214, pos.y, v217)); - v99 = this->field_B0; - this->field_6C = v98; - if (v99 || this->field_B4) - { - v201 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, v217)); - v202 = this->field_B0; - this->field_28 = v201; - if (v202) - goto LABEL_131; - } - else - { - this->field_28 = this->field_68; - } - if (this->field_AC) - { - LABEL_131: - this->field_48 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, v217)); - goto LABEL_44; - } - this->field_48 = this->field_68; -LABEL_44: - if (this->field_B3 || this->field_B4) - { - v204 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, v217)); - v205 = this->field_B3; - this->field_3C = v204; - if (v205) - goto LABEL_136; - } - else - { - this->field_3C = this->field_6C; - } - if (!this->field_AC) - { - v100 = this->field_6C; - v101 = v100; - this->field_58 = v100; - goto LABEL_49; - } -LABEL_136: - v206 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v216, v217)); - v100 = this->field_6C; - v101 = v206; - this->field_58 = v206; -LABEL_49: - v102 = this->field_68; - v103 = this->field_18; - v104 = this->field_54; - v105 = (float)((float)(v102 + this->field_48) + v103) + v104; - v106 = v101 + (float)((float)(v103 + v104) + v100); - v107 = this->field_34; - v108 = v105 * 0.25f; - v109 = v106 * 0.25f; - v110 = (float)(v100 + (float)((float)(v103 + v107) + this->field_3C)) * 0.25f; - v111 = (float)(v103 + (float)(v107 + (float)(v102 + this->field_28))) * 0.25f; - if (!v222) - { - LABEL_50: - v112 = 0.8f; - this->m_vtxRed[3] = 0.8f; - this->m_vtxRed[2] = 0.8f; - this->m_vtxRed[1] = 0.8f; - this->m_vtxRed[0] = 0.8f; - this->m_vtxGreen[3] = 0.8f; - this->m_vtxGreen[2] = 0.8f; - this->m_vtxGreen[1] = 0.8f; - this->m_vtxGreen[0] = 0.8f; - v113 = 0.8f; - v114 = 0.8f; - goto LABEL_53; - } -LABEL_52: - v113 = r * 0.8f; - v112 = g * 0.8f; - this->m_vtxRed[3] = r * 0.8f; - this->m_vtxRed[2] = r * 0.8f; - this->m_vtxRed[1] = r * 0.8f; - this->m_vtxRed[0] = r * 0.8f; - v114 = b * 0.8f; - this->m_vtxGreen[3] = g * 0.8f; - this->m_vtxGreen[2] = g * 0.8f; - this->m_vtxGreen[1] = g * 0.8f; - this->m_vtxGreen[0] = g * 0.8f; -LABEL_53: - v115 = this->m_pTileSource; - v69 = 1; - this->m_vtxRed[0] = v108 * v113; - this->m_vtxGreen[0] = v108 * v112; - this->m_vtxBlue[0] = v108 * v114; - this->m_vtxRed[1] = v109 * v113; - this->m_vtxGreen[1] = v109 * v112; - this->m_vtxBlue[1] = v109 * v114; - this->m_vtxRed[2] = v110 * v113; - this->m_vtxGreen[2] = v110 * v112; - this->m_vtxGreen[3] = v111 * v112; - this->m_vtxBlue[2] = v110 * v114; - this->m_vtxRed[3] = v111 * v113; - this->m_vtxBlue[3] = v111 * v114; - v116 = a2->getTexture(v115, pos, Facing::NORTH); - renderNorth(a2, pos, v116); - if (this->m_bNoCulling) - goto LABEL_54; -LABEL_107: - if (!a2->shouldRenderFace(this->m_pTileSource, TilePos(pos.x, pos.y, v215), Facing::SOUTH)) - { - if (this->m_bNoCulling) - goto LABEL_70; - goto LABEL_109; - } -LABEL_54: - if (this->field_78 <= 0) - { - v132 = this->field_24; - v133 = v132; - v134 = v132; - v130 = v132; - if (!v221) - goto LABEL_66; - goto LABEL_68; - } - v117 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, pos.y, v215)); - v118 = this->m_pTileSource; - this->field_70 = v117; - v119 = a2->getBrightness(v118, TilePos(v214, pos.y, v215)); - v120 = this->m_pTileSource; - this->field_74 = v119; - v121 = a2->getBrightness(v120, TilePos(pos.x, v218, v215)); - v122 = this->m_pTileSource; - this->field_38 = v121; - v123 = a2->getBrightness(v122, TilePos(pos.x, v216, v215)); - v124 = this->field_B2; - this->field_60 = v123; - if (v124 || this->field_B7) - { - v199 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, v215)); - v200 = this->field_B2; - this->field_30 = v199; - if (v200) - goto LABEL_129; - } - else - { - this->field_30 = this->field_70; - } - if (this->field_AF) - { - LABEL_129: - this->field_50 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, v215)); - goto LABEL_60; - } - this->field_50 = this->field_70; -LABEL_60: - if (this->field_B1 || this->field_B7) - { - v208 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, v215)); - v209 = this->field_B1; - this->field_44 = v208; - if (v209) - goto LABEL_139; - } - else - { - this->field_44 = this->field_74; - } - if (!this->field_AF) - { - v125 = this->field_74; - v126 = v125; - this->field_64 = v125; - goto LABEL_65; - } -LABEL_139: - v210 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v216, v215)); - v125 = this->field_74; - v126 = v210; - this->field_64 = v210; -LABEL_65: - v127 = this->field_70; - v128 = this->field_24; - v129 = this->field_60; - v130 = (float)((float)((float)(v127 + this->field_50) + v128) + v129) * 0.25f; - v131 = this->field_38; - v132 = (float)(v126 + (float)((float)(v128 + v129) + v125)) * 0.25f; - v133 = (float)(v125 + (float)((float)(v128 + v131) + this->field_44)) * 0.25f; - v134 = (float)(v128 + (float)(v131 + (float)(v127 + this->field_30))) * 0.25f; - if (!v221) - { - LABEL_66: - v135 = 0.8f; - this->m_vtxRed[3] = 0.8f; - this->m_vtxRed[2] = 0.8f; - this->m_vtxRed[1] = 0.8f; - this->m_vtxRed[0] = 0.8f; - this->m_vtxGreen[3] = 0.8f; - this->m_vtxGreen[2] = 0.8f; - this->m_vtxGreen[1] = 0.8f; - this->m_vtxGreen[0] = 0.8f; - v136 = 0.8f; - v137 = 0.8f; - goto LABEL_69; - } -LABEL_68: - v136 = r * 0.8f; - v135 = g * 0.8f; - this->m_vtxRed[3] = r * 0.8f; - this->m_vtxRed[2] = r * 0.8f; - this->m_vtxRed[1] = r * 0.8f; - this->m_vtxRed[0] = r * 0.8f; - v137 = b * 0.8f; - this->m_vtxGreen[3] = g * 0.8f; - this->m_vtxGreen[2] = g * 0.8f; - this->m_vtxGreen[1] = g * 0.8f; - this->m_vtxGreen[0] = g * 0.8f; -LABEL_69: - v138 = this->m_pTileSource; - v69 = 1; - this->m_vtxRed[0] = v130 * v136; - this->m_vtxGreen[0] = v130 * v135; - this->m_vtxBlue[0] = v130 * v137; - this->m_vtxRed[1] = v134 * v136; - this->m_vtxGreen[1] = v134 * v135; - this->m_vtxBlue[1] = v134 * v137; - this->m_vtxRed[2] = v133 * v136; - this->m_vtxGreen[2] = v133 * v135; - this->m_vtxGreen[3] = v132 * v135; - this->m_vtxBlue[2] = v133 * v137; - this->m_vtxRed[3] = v132 * v136; - this->m_vtxBlue[3] = v132 * v137; - v139 = a2->getTexture(v138, pos, Facing::SOUTH); - renderSouth(a2, pos, v139); - if (this->m_bNoCulling) - goto LABEL_70; -LABEL_109: - if (!a2->shouldRenderFace(this->m_pTileSource, pos.west(), Facing::WEST)) - { - if (this->m_bNoCulling) - goto LABEL_88; - goto LABEL_111; - } -LABEL_70: - if (this->field_78 <= 0) - { - v156 = this->field_10; - v159 = v156; - v158 = v156; - v157 = v156; - if (!v220) - { - LABEL_84: - v160 = 0.6f; - this->m_vtxRed[3] = 0.6f; - this->m_vtxRed[2] = 0.6f; - this->m_vtxRed[1] = 0.6f; - this->m_vtxRed[0] = 0.6f; - this->m_vtxGreen[3] = 0.6f; - this->m_vtxGreen[2] = 0.6f; - this->m_vtxGreen[1] = 0.6f; - this->m_vtxGreen[0] = 0.6f; - v161 = 0.6f; - v162 = 0.6f; - goto LABEL_87; - } - } - else - { - v140 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, pos.z)); - v141 = this->m_pTileSource; - this->field_2C = v140; - v142 = a2->getBrightness(v141, TilePos(pos.x - 1, pos.y, v217)); - v143 = this->m_pTileSource; - this->field_68 = v142; - v144 = a2->getBrightness(v143, TilePos(pos.x - 1, pos.y, v215)); - v145 = this->m_pTileSource; - this->field_70 = v144; - v146 = a2->getBrightness(v145, TilePos(pos.x - 1, v216, pos.z)); - v147 = this->field_B0; - this->field_4C = v146; - if (v147 || this->field_B6) - this->field_28 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, v217)); - else - this->field_28 = this->field_68; - if (this->field_B2 || this->field_B6) - this->field_30 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v218, v215)); - else - this->field_30 = this->field_70; - if (this->field_B0 || this->field_AE) - this->field_48 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, v217)); - else - this->field_48 = this->field_68; - if (this->field_B2 || this->field_AE) - { - v207 = a2->getBrightness(this->m_pTileSource, TilePos(pos.x - 1, v216, v215)); - v148 = this->field_70; - v149 = v207; - this->field_50 = v207; - } - else - { - v148 = this->field_70; - v149 = v148; - this->field_50 = v148; - } - v150 = this->field_2C; - v151 = this->field_10; - v152 = this->field_4C; - v153 = (float)((float)(v150 + this->field_30) + v151) + v148; - v154 = v149 + (float)((float)(v151 + v148) + v152); - v155 = this->field_68; - v156 = v153 * 0.25f; - v157 = v154 * 0.25f; - v158 = (float)(v152 + (float)((float)(v151 + v155) + this->field_48)) * 0.25f; - v159 = (float)(v151 + (float)(v155 + (float)(v150 + this->field_28))) * 0.25f; - if (!v220) - goto LABEL_84; - } - v161 = r * 0.6f; - v160 = g * 0.6f; - this->m_vtxRed[3] = r * 0.6f; - this->m_vtxRed[2] = r * 0.6f; - this->m_vtxRed[1] = r * 0.6f; - this->m_vtxRed[0] = r * 0.6f; - v162 = b * 0.6f; - this->m_vtxGreen[3] = g * 0.6f; - this->m_vtxGreen[2] = g * 0.6f; - this->m_vtxGreen[1] = g * 0.6f; - this->m_vtxGreen[0] = g * 0.6f; -LABEL_87: - v163 = this->m_pTileSource; - v69 = 1; - this->m_vtxRed[0] = v161 * v157; - this->m_vtxGreen[0] = v160 * v157; - this->m_vtxBlue[0] = v162 * v157; - this->m_vtxRed[1] = v161 * v158; - this->m_vtxGreen[1] = v160 * v158; - this->m_vtxBlue[1] = v162 * v158; - this->m_vtxRed[2] = v161 * v159; - this->m_vtxGreen[2] = v160 * v159; - this->m_vtxGreen[3] = v160 * v156; - this->m_vtxBlue[2] = v162 * v159; - this->m_vtxRed[3] = v161 * v156; - this->m_vtxBlue[3] = v162 * v156; - v164 = a2->getTexture(v163, pos, Facing::WEST); - renderWest(a2, pos, v164); - if (this->m_bNoCulling) - goto LABEL_88; -LABEL_111: - if (!a2->shouldRenderFace(this->m_pTileSource, TilePos(v214, pos.y, pos.z), Facing::EAST)) - goto LABEL_102; -LABEL_88: - if (this->field_78 <= 0) - { - v186 = this->field_1C; - v187 = v186; - v188 = v186; - v182 = v186; - if (v219) - goto LABEL_100; - LABEL_104: - v190 = 0.6f; - this->m_vtxRed[3] = 0.6f; - this->m_vtxRed[2] = 0.6f; - this->m_vtxRed[1] = 0.6f; - this->m_vtxRed[0] = 0.6f; - this->m_vtxGreen[3] = 0.6f; - this->m_vtxGreen[2] = 0.6f; - this->m_vtxGreen[1] = 0.6f; - this->m_vtxGreen[0] = 0.6f; - v189 = 0.6f; - v191 = 0.6f; - goto LABEL_101; - } - v165 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, pos.z)); - v166 = this->m_pTileSource; - this->field_40 = v165; - v167 = a2->getBrightness(v166, TilePos(v214, pos.y, v217)); - v168 = this->m_pTileSource; - this->field_6C = v167; - v169 = a2->getBrightness(v168, TilePos(v214, pos.y, v215)); - v170 = this->m_pTileSource; - this->field_74 = v169; - v171 = a2->getBrightness(v170, TilePos(v214, v216, pos.z)); - v172 = this->field_B5; - this->field_5C = v171; - if (v172 || this->field_B3) - { - v173 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, v217)); - v174 = this->field_B5; - this->field_3C = v173; - if (v174 || this->field_B1) - goto LABEL_93; - LABEL_121: - this->field_44 = this->field_74; - goto LABEL_94; - } - v196 = this->field_B1; - this->field_3C = this->field_6C; - if (!v196) - goto LABEL_121; -LABEL_93: - this->field_44 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v218, v215)); -LABEL_94: - if (this->field_AD || this->field_B3) - { - v175 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v216, v217)); - v176 = this->field_AD; - this->field_58 = v175; - if (v176 || this->field_B1) - goto LABEL_98; - } - else - { - v195 = this->field_B1; - this->field_58 = this->field_6C; - if (v195) - { - LABEL_98: - v177 = a2->getBrightness(this->m_pTileSource, TilePos(v214, v216, v215)); - v178 = this->field_74; - v179 = v177; - this->field_64 = v177; - goto LABEL_99; - } - } - v178 = this->field_74; - v179 = v178; - this->field_64 = v178; -LABEL_99: - v180 = this->field_40; - v181 = this->field_1C; - v182 = (float)((float)((float)(v180 + this->field_44) + v181) + v178) * 0.25f; - v183 = this->field_5C; - v184 = v179 + (float)((float)(v181 + v178) + v183); - v185 = this->field_6C; - v186 = v184 * 0.25f; - v187 = (float)(v183 + (float)((float)(v181 + v185) + this->field_58)) * 0.25f; - v188 = (float)(v181 + (float)(v185 + (float)(v180 + this->field_3C))) * 0.25f; - if (!v219) - goto LABEL_104; -LABEL_100: - v189 = r * 0.6f; - v190 = g * 0.6f; - this->m_vtxRed[3] = r * 0.6f; - this->m_vtxRed[2] = r * 0.6f; - this->m_vtxRed[1] = r * 0.6f; - this->m_vtxRed[0] = r * 0.6f; - v191 = b * 0.6f; - this->m_vtxGreen[3] = g * 0.6f; - this->m_vtxGreen[2] = g * 0.6f; - this->m_vtxGreen[1] = g * 0.6f; - this->m_vtxGreen[0] = g * 0.6f; -LABEL_101: - v192 = this->m_pTileSource; - v69 = 1; - this->m_vtxRed[0] = v189 * v182; - this->m_vtxGreen[0] = v190 * v182; - this->m_vtxBlue[0] = v191 * v182; - this->m_vtxRed[1] = v189 * v188; - this->m_vtxGreen[1] = v190 * v188; - this->m_vtxBlue[1] = v191 * v188; - this->m_vtxRed[2] = v189 * v187; - this->m_vtxGreen[2] = v190 * v187; - this->m_vtxGreen[3] = v190 * v186; - this->m_vtxBlue[2] = v191 * v187; - this->m_vtxRed[3] = v189 * v186; - this->m_vtxBlue[3] = v191 * v186; - v193 = a2->getTexture(v192, pos, Facing::EAST); - renderEast(a2, pos, v193); -LABEL_102: - result = v69; - this->m_ambientOcclusion = false; - return result; -} - // this is very hacky #ifdef ENH_SHADE_HELD_TILES @@ -2829,7 +1828,6 @@ void TileRenderer::renderTile(const FullTile& tile, const mce::MaterialPtr& mate } } -#ifdef ENH_USE_OWN_AO bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionV2(Tile* tile, const TilePos& pos, float r, float g, float b) { // START OF AUXILIARY DATA FOR AO @@ -3065,38 +2063,22 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionV2(Tile* tile, cons return true; } -#endif -int TileRenderer::getTileColor(Tile* tile, const TilePos& pos) +Color TileRenderer::_getTileColor(const TilePos& pos, Tile* tile) { - if (tile == nullptr) - { - return 0xffffff; - } - - if ((tile == Tile::grass || tile == Tile::tallGrass) && GrassColor::isAvailable() && m_bBiomeColors) - { - m_pTileSource->getBiomeSource()->getBiomeBlock(pos, 1, 1); - return GrassColor::get(m_pTileSource->getBiomeSource()->field_4[0], m_pTileSource->getBiomeSource()->field_8[0]); - } - if (tile == Tile::leaves && FoliageColor::isAvailable() && m_bBiomeColors) - { - TileData data = m_pTileSource->getData(pos); + uint32_t tileColor = tile->getColor(m_pTileSource, pos); - if ((data & 1) == 1) - { - return FoliageColor::getEvergreenColor(); - } - if ((data & 2) == 2) - { - return FoliageColor::getBirchColor(); - } + Color color( + GET_RED(tileColor) / 255.0f, + GET_GREEN(tileColor) / 255.0f, + GET_BLUE(tileColor) / 255.0f, + 1.0f // NOTE: not supported + ); - m_pTileSource->getBiomeSource()->getBiomeBlock(pos, 1, 1); - return FoliageColor::get(m_pTileSource->getBiomeSource()->field_4[0], m_pTileSource->getBiomeSource()->field_8[0]); - } + if (tile->isSeasonTinted()) + color.b = 1.0f; - return tile->getColor(m_pTileSource, pos); + return color; } bool TileRenderer::useAmbientOcclusion() const diff --git a/source/client/renderer/TileRenderer.hpp b/source/client/renderer/TileRenderer.hpp index 701c2f9dc..5fd44a72b 100644 --- a/source/client/renderer/TileRenderer.hpp +++ b/source/client/renderer/TileRenderer.hpp @@ -8,10 +8,10 @@ #pragma once -#include "world/level/Region.hpp" -#include "client/renderer/Chunk.hpp" #include "client/renderer/renderer/Tesselator.hpp" +class TileSource; + class TileRenderer { protected: @@ -26,7 +26,7 @@ class TileRenderer private: void _init(); public: - TileRenderer(Tesselator& tessellator = Tesselator::instance, LevelSource* pLevelSource = nullptr); + TileRenderer(Tesselator& tessellator = Tesselator::instance, TileSource* tileSource = nullptr); private: void _tex1(const Vec2& uv); @@ -36,8 +36,6 @@ class TileRenderer float getWaterHeight(const TilePos& pos, const Material*); void renderTile(const FullTile& tile, const mce::MaterialPtr& material = mce::MaterialPtr::NONE, float bright = 1.0f, bool preshade = false); - // TODO - bool tesselateInWorld(Tile*, const TilePos& pos); bool tesselateInWorldNoCulling(Tile*, const TilePos& pos); bool tesselateInWorld(Tile*, const TilePos& pos, int textureOverride); @@ -52,7 +50,7 @@ class TileRenderer void tesselateRowTexture(Tile* tile, int data, const Vec3& pos); void tesselateTorch(Tile*, const Vec3& pos, float a, float b); - bool tesselateBlockInWorldWithAmbienceOcclusion(Tile*, const TilePos& pos, float r, float g, float b); + bool tesselateBlockInWorldWithAmbienceOcclusionV2(Tile*, const TilePos& pos, float r, float g, float b); bool tesselateBlockInWorld(Tile*, const TilePos& pos, float r, float g, float b); bool tesselateBlockInWorld(Tile*, const TilePos& pos); bool tesselateCrossInWorld(Tile*, const TilePos& pos); @@ -66,20 +64,19 @@ class TileRenderer #ifndef ORIGINAL_CODE bool tesselateFireInWorld(Tile*, const TilePos& pos); #endif -#ifdef ENH_USE_OWN_AO - bool tesselateBlockInWorldWithAmbienceOcclusionV2(Tile*, const TilePos& pos, float r, float g, float b); -#endif - - int getTileColor(Tile*, const TilePos& pos); bool useAmbientOcclusion() const; +protected: + Color _getTileColor(const TilePos& pos, Tile* tile); + +public: static bool canRender(int renderShape); static bool m_bFancyGrass; static bool m_bBiomeColors; private: - LevelSource* m_pTileSource; + TileSource* m_pTileSource; int m_fixedTexture; bool m_bXFlipTexture; bool m_bNoCulling; diff --git a/source/client/renderer/VisibilityExtimator.cpp b/source/client/renderer/VisibilityExtimator.cpp new file mode 100644 index 000000000..abc9c42f2 --- /dev/null +++ b/source/client/renderer/VisibilityExtimator.cpp @@ -0,0 +1,162 @@ +#include "client/renderer/VisibilityExtimator.hpp" +#include "client/renderer/RenderChunk.hpp" + +ThreadLocal VisibilityExtimator::pool; + +void VisibilityNode::connect(const ByteMask& group) +{ + for (uint8_t i = 0; i < Facing::COUNT; i++) + { + if (group.contains(1 << i)) + { + connect(i, group); + } + } +} + +void VisibilityNode::connect(uint8_t A, const ByteMask& connected) +{ + for (uint8_t i = 0; i < Facing::COUNT; i++) + { + if (connected.contains(1 << i)) + { + connect(A, i); + } + } +} + +void VisibilityNode::connect(uint8_t A, uint8_t B) +{ + if (A != B) + { + m_visibility[A].add(1 << B); + m_visibility[B].add(1 << A); + } +} + +uint8_t& VisibilityExtimator::_at(const ChunkTilePos& p) +{ + size_t index = p.y + (p.x << 8) + (p.z << 4); + assert(index < ChunkConstants::MESH_TILE_COUNT); + return m_tiles[index]; +} + +uint8_t& VisibilityExtimator::_atWorld(const TilePos& t) +{ + return _at(t - m_origin); +} + +uint8_t* VisibilityExtimator::_at(const ChunkTilePos& pos, ByteMask& set) +{ + if (pos.x > 128) + { + set.add(1 << Facing::WEST); + } + else if (pos.x > 15) + { + set.add(1 << Facing::EAST); + } + else if (pos.y > 128) + { + set.add(1 << Facing::DOWN); + } + else if (pos.y > 15) + { + set.add(1 << Facing::UP); + } + else if (pos.z > 128) + { + set.add(1 << Facing::NORTH); + } + else if (pos.z > 15) + { + set.add(1 << Facing::SOUTH); + } + else + { + return &_at(pos); + } + + return nullptr; +} + +void VisibilityExtimator::_visit(const ChunkTilePos& p, ByteMask& set) +{ + uint8_t* tileState = _at(p, set); + if (tileState && *tileState == TS_EMPTY) + { + m_floodQueue.push_back(p); + } +} + +ByteMask VisibilityExtimator::_floodFill(const ChunkTilePos& startPos) +{ + ByteMask mask; + + m_floodQueue.push_back(startPos); + + while (!m_floodQueue.empty()) + { + const ChunkTilePos& pos = m_floodQueue.front(); + + uint8_t& tileState = _at(pos); + if (tileState == TS_EMPTY) + { + tileState = TS_EMPTY_MARKED; + + for (uint8_t face = 0; face < Facing::COUNT; face++) + { + ChunkTilePos checkPos = pos + Facing::DIRECTION[face]; + _visit(checkPos, mask); + } + } + + m_floodQueue.pop_front(); + } + + return mask; +} + +void VisibilityExtimator::setTile(const TilePos& pos, const Tile* t) +{ + if (t->isSolid()) + { + _atWorld(pos) = TS_OPAQUE; + m_emptyTiles--; + } +} + +void VisibilityExtimator::start(const RenderChunk& parent) +{ + m_origin = parent.getPos(); + + memset(m_tiles, TS_EMPTY, ChunkConstants::MESH_TILE_COUNT); + m_emptyTiles = ChunkConstants::MESH_TILE_COUNT; +} + +VisibilityNode VisibilityExtimator::finish() +{ + if (isAllEmpty()) + return VisibilityNode(true); + + VisibilityNode node(false); + + ChunkTilePos p; + for (p.x = 0; p.x < ChunkConstants::MESH_XYZ_SIZE; p.x++) + { + for (p.z = 0; p.z < ChunkConstants::MESH_XYZ_SIZE; p.z++) + { + for (p.y = 0; p.y < ChunkConstants::MESH_XYZ_SIZE; p.y++) + { + if (_at(p) != TS_EMPTY) + continue; + + ByteMask mask = _floodFill(p); + if (mask) + node.connect(mask); + } + } + } + + return node; +} diff --git a/source/client/renderer/VisibilityExtimator.hpp b/source/client/renderer/VisibilityExtimator.hpp new file mode 100644 index 000000000..d279cacc5 --- /dev/null +++ b/source/client/renderer/VisibilityExtimator.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include + +#include "common/threading/ThreadLocal.hpp" +#include "common/Stopwatch.hpp" +#include "common/ByteMask.hpp" +#include "world/level/TilePos.hpp" +#include "world/level/levelgen/chunk/ChunkTilePos.hpp" +#include "world/level/levelgen/chunk/ChunkConstants.hpp" +#include "world/tile/Tile.hpp" + +class RenderChunk; + +class VisibilityNode +{ +protected: + ByteMask m_visibility[Facing::COUNT]; + +public: + VisibilityNode() + { + setOpaque(); + } + VisibilityNode(bool empty) + { + if (empty) + setEmpty(); + else + setOpaque(); + } + void setEmpty() + { + for (int i = 0; i < Facing::COUNT; i++) + { + m_visibility[i].setFull(); + } + } + void setOpaque() + { + for (int i = 0; i < Facing::COUNT; i++) + { + m_visibility[i].setEmpty(); + } + } + void connect(const ByteMask& group); + void connect(uint8_t A, const ByteMask& connected); + void connect(uint8_t A, uint8_t B); + const ByteMask& from(uint8_t facing) const + { + assert(facing < Facing::COUNT); + return m_visibility[facing]; + } + bool compare(VisibilityNode& other) const; +}; + +class VisibilityExtimator +{ +protected: + enum TileState + { + TS_EMPTY, + TS_OPAQUE, + TS_EMPTY_MARKED + }; + +public: + static ThreadLocal pool; + +public: +#ifdef _DEBUG + Stopwatch m_timer; +#endif +protected: + TilePos m_origin; + int m_emptyTiles; + uint8_t m_tiles[ChunkConstants::MESH_TILE_COUNT]; + std::deque m_floodQueue; + +public: + VisibilityExtimator() + : m_origin(), + m_emptyTiles(0), + m_tiles() + { + } +public: + void start(const RenderChunk& parent); + void setTile(const TilePos& pos, const Tile* t); + bool isAllOpaque() const + { + return m_emptyTiles == 0; + } + bool isAllEmpty() const + { + return m_emptyTiles >= (ChunkConstants::MESH_TILE_COUNT - ChunkConstants::MESH_TILE_COUNT_PER_ROW); + } + VisibilityNode finish(); +protected: + uint8_t* _at(const ChunkTilePos& pos, ByteMask& set); + uint8_t& _at(const ChunkTilePos& p); + uint8_t& _atWorld(const TilePos& t); + void _visit(const ChunkTilePos& p, ByteMask& set); + ByteMask _floodFill(const ChunkTilePos& startPos); +}; diff --git a/source/client/renderer/renderer/EntityShaderManager.cpp b/source/client/renderer/renderer/EntityShaderManager.cpp index 4dee8eb07..74a0ab0e5 100644 --- a/source/client/renderer/renderer/EntityShaderManager.cpp +++ b/source/client/renderer/renderer/EntityShaderManager.cpp @@ -122,7 +122,7 @@ void EntityShaderManager::_setupShaderParameters(const Color& overlayColor, cons #endif } -void EntityShaderManager::_setupShaderParameters(const LevelSource& source, +void EntityShaderManager::_setupShaderParameters(const TileSource& source, const TilePos& pos, float a, const Vec2& uvScale) diff --git a/source/client/renderer/renderer/EntityShaderManager.hpp b/source/client/renderer/renderer/EntityShaderManager.hpp index c963200de..d0a63a771 100644 --- a/source/client/renderer/renderer/EntityShaderManager.hpp +++ b/source/client/renderer/renderer/EntityShaderManager.hpp @@ -39,7 +39,7 @@ class EntityShaderManager const Vec2& glintUVScale, const Vec2& uvAnim, float a); // For TileEntities - void _setupShaderParameters(const LevelSource& source, + void _setupShaderParameters(const TileSource& source, const TilePos& pos, float a, const Vec2& uvScale); diff --git a/source/client/renderer/renderer/Tesselator.hpp b/source/client/renderer/renderer/Tesselator.hpp index 47ea55fa9..151916413 100644 --- a/source/client/renderer/renderer/Tesselator.hpp +++ b/source/client/renderer/renderer/Tesselator.hpp @@ -103,6 +103,15 @@ class Tesselator bool isFormatFixed() const; + bool isTesselating() const + { + return m_bTesselating; + } + size_t getVertices() const + { + return m_vertices; + } + private: CurrentVertexPointers m_currentVertex; @@ -115,7 +124,7 @@ class Tesselator mce::VertexFormat m_vertexFormat; // Tesselation state - unsigned int m_vertices; + size_t m_vertices; int m_pendingVertices; diff --git a/source/client/sound/SoundEngine.cpp b/source/client/sound/SoundEngine.cpp index 7eca8ee97..ec2e400c8 100644 --- a/source/client/sound/SoundEngine.cpp +++ b/source/client/sound/SoundEngine.cpp @@ -135,12 +135,12 @@ void SoundEngine::updateListener(const Mob* player, float elapsedTime) { if (player != nullptr) { - Vec3 pos = player->getPos(elapsedTime); + Vec3 pos = player->getInterpolatedPosition(elapsedTime); pos.y -= player->m_heightOffset; m_listenerPosition = pos; m_pSoundSystem->setListenerPos(pos); - Vec2 rot = player->getRot(elapsedTime); + Vec2 rot = player->getInterpolatedRotation(elapsedTime); m_listenerOrientation = rot; m_pSoundSystem->setListenerAngle(rot); } diff --git a/source/common/ByteMask.hpp b/source/common/ByteMask.hpp new file mode 100644 index 000000000..4f836f297 --- /dev/null +++ b/source/common/ByteMask.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +class ByteMask +{ +protected: + uint8_t mask; + +public: + ByteMask() + : mask(0) + { + } +public: + void setEmpty() + { + mask = 0; + } + void setFull() + { + mask = 0xFF; + } + void add(const uint8_t bit) + { + mask |= bit; + } + bool contains(const uint8_t bit) const + { + return (mask & bit) != 0; + } + operator bool() const + { + return mask != 0; + } + uint8_t toByte() const + { + return mask; + } +}; diff --git a/source/common/MovePriorityQueue.hpp b/source/common/MovePriorityQueue.hpp new file mode 100644 index 000000000..6d3e74bae --- /dev/null +++ b/source/common/MovePriorityQueue.hpp @@ -0,0 +1,69 @@ +#pragma once +#include +#include +#include + +template> +class MovePriorityQueue +{ +public: + typedef typename std::vector::const_iterator Iterator; + +private: + std::vector m_items; + +public: + MovePriorityQueue() + { + } + +public: + template + void push(const Value& value) + { + m_items.push_back(value); + std::push_heap(m_items.begin(), m_items.end(), Comparator()); + } + + void popInto(T& item) + { + std::pop_heap(m_items.begin(), m_items.end(), Comparator()); + item = m_items.back(); + m_items.pop_back(); + } + + const T& top() const + { + return m_items.front(); + } + + void resort() + { + std::make_heap(m_items.begin(), m_items.end(), Comparator()); + } + + void clear() + { + m_items.clear(); + } + + size_t size() const + { + return m_items.size(); + } + + bool empty() const + { + return m_items.empty(); + } + + Iterator begin() const + { + return m_items.begin(); + } + + Iterator end() const + { + return m_items.end(); + } +}; diff --git a/source/common/Mth.cpp b/source/common/Mth.cpp index d3a20ddb0..da84b7940 100644 --- a/source/common/Mth.cpp +++ b/source/common/Mth.cpp @@ -113,6 +113,17 @@ int Mth::clamp(int x, int min, int max) return max; } +uint8_t Mth::clamp(uint8_t x, uint8_t min, uint8_t max) +{ + if (x > max) + return max; + if (x > min) + return x; + else + return min; + return max; +} + int Mth::floor(float f) { int result = int(f); diff --git a/source/common/Mth.hpp b/source/common/Mth.hpp index 797401f9f..73c433cfe 100644 --- a/source/common/Mth.hpp +++ b/source/common/Mth.hpp @@ -34,6 +34,7 @@ class Mth static float cos(float); static float clamp(float x, float min, float max); static int clamp(int x, int min, int max); + static uint8_t clamp(uint8_t x, uint8_t min, uint8_t max); static int floor(float); static int round(float); static void initMth(); diff --git a/source/common/Stopwatch.cpp b/source/common/Stopwatch.cpp new file mode 100644 index 000000000..2375b7dcb --- /dev/null +++ b/source/common/Stopwatch.cpp @@ -0,0 +1,94 @@ +#include + +#include "Stopwatch.hpp" +#include "Utils.hpp" +#include "Logger.hpp" + +Stopwatch::Stopwatch() + : m_last(0.0), + m_count(0), + m_printcounter(0) +{ + reset(); +} + +Stopwatch::~Stopwatch() +{ +} + +void Stopwatch::start() +{ + m_st = getTimeS(); +} + +double Stopwatch::stop() +{ + if (isReset()) + return 0.0; + + double time = getTimeS(); + double diff = time - m_st; + + m_last = diff; + if (diff > m_max) + m_max = diff; + + m_count++; + m_st = -1.0; + m_tt += diff; + return m_tt; +} + +double Stopwatch::stopContinue() +{ + if (isReset()) + return 0.0; + + double time = getTimeS(); + double diff = time - m_st; + + m_last = diff; + if (diff > m_max) + m_max = diff; + + m_count++; + m_st = time; + m_tt += diff; + return m_tt; +} + +double Stopwatch::tick() const +{ + if (isReset()) + return 0.0; + + double time = getTimeS(); + double diff = time - m_st; + + return diff; +} + +void Stopwatch::reset() +{ + m_tt = 0.0; + m_max = 0.0; + m_st = -1.0; +} + +void Stopwatch::print(const std::string& prepend) +{ + LOG_I("%s\tTime (AVGms/LTs(MAXs)/TTs, C) : %f/%f(%f)/%f, %d", prepend.c_str(), (m_tt * 1000.0) / m_count, m_last, m_max, m_tt, m_count); +} + +void Stopwatch::printEvery(int n, const std::string& prepend) +{ + if ((m_printcounter + 1) >= n) + { + m_printcounter = 0; + print(prepend); + } + else + { + m_printcounter += 1; + } +} diff --git a/source/common/Stopwatch.hpp b/source/common/Stopwatch.hpp new file mode 100644 index 000000000..9ccea2972 --- /dev/null +++ b/source/common/Stopwatch.hpp @@ -0,0 +1,45 @@ +#pragma once +#include + +class Stopwatch +{ +private: + double m_st; + double m_tt; + double m_last; + double m_max; + int m_count; + int m_printcounter; + +public: + Stopwatch(); + virtual ~Stopwatch(); +public: + void start(); + virtual double stop(); + virtual double stopContinue(); + double getLast() const + { + return m_last; + } + double getTotal() const + { + return m_tt; + } + double getMax() const + { + return m_max; + } + int getCount() const + { + return m_count; + } + double tick() const; + bool isReset() const + { + return m_st == -1.0; + } + void reset(); + void printEvery(int n, const std::string& prepend); + virtual void print(const std::string& prepend); +}; diff --git a/source/common/math/Color.hpp b/source/common/math/Color.hpp index b215311a7..78f6eab24 100644 --- a/source/common/math/Color.hpp +++ b/source/common/math/Color.hpp @@ -41,7 +41,7 @@ struct Color public: Color() { - *this = NIL; + _init(0.0f, 0.0f, 0.0f, 0.0f); } Color(float r, float g, float b, float a = 1.0f) @@ -66,6 +66,26 @@ struct Color void fromHSB(float h, float s, float b); + Color operator+(float f) const + { + return Color(r + f, g + f, b + f, a); + } + + Color operator+(const Color& c) const + { + return Color(r + c.r, g + c.g, b + c.b, a + c.a); + } + + Color operator-(float f) const + { + return Color(r - f, g - f, b - f, a); + } + + Color operator-(const Color& c) const + { + return Color(r - c.r, g - c.g, b - c.b, a - c.a); + } + Color operator*(float f) const { return Color(r * f, g * f, b * f, a); @@ -76,6 +96,54 @@ struct Color return Color(r * c.r, g * c.g, b * c.b, a * c.a); } + Color operator/(float f) const + { + return Color(r / f, g / f, b / f, a); + } + + Color operator/(const Color& c) const + { + return Color(r / c.r, g / c.g, b / c.b, a / c.a); + } + + Color& operator+=(const Color& c) + { + r += c.r; + g += c.g; + b += c.b; + a += c.a; + + return *this; + } + + Color& operator+=(float f) + { + r += f; + g += f; + b += f; + + return *this; + } + + Color& operator-=(const Color& c) + { + r -= c.r; + g -= c.g; + b -= c.b; + a -= c.a; + + return *this; + } + + Color& operator-=(float f) + { + r -= f; + g -= f; + b -= f; + + return *this; + } + Color& operator*=(const Color& c) { r *= c.r; @@ -95,6 +163,25 @@ struct Color return *this; } + Color& operator/=(const Color& c) + { + r /= c.r; + g /= c.g; + b /= c.b; + a /= c.a; + + return *this; + } + + Color& operator/=(float f) + { + r /= f; + g /= f; + b /= f; + + return *this; + } + bool operator==(const Color& other) const { return this->r == other.r diff --git a/source/common/threading/BackgroundQueue.cpp b/source/common/threading/BackgroundQueue.cpp new file mode 100644 index 000000000..11e1b2c74 --- /dev/null +++ b/source/common/threading/BackgroundQueue.cpp @@ -0,0 +1,402 @@ +#include +#include "BackgroundQueue.hpp" +#include "BackgroundQueuePool.hpp" + +std::function BackgroundQueue::NOP; + +static void SetThreadName(const std::string& name) +{ + // TODO! +} + +BackgroundQueue::Job::Job() + : m_runFunction(nullptr), + m_callbackFunction(nullptr), + m_priority(TOP_PRIORITY) +{ +} + +BackgroundQueue::Job::Job(const std::function& run, const std::function& callback, int priority) + : m_runFunction(run), + m_callbackFunction(callback), + m_priority(priority) +{ +} + +BackgroundQueue::Job::~Job() +{ + clear(); +} + +bool BackgroundQueue::Job::canRun() const +{ + return m_runFunction != nullptr; +} + +bool BackgroundQueue::Job::run() +{ + return m_runFunction(); +} + +bool BackgroundQueue::Job::hasCallback() const +{ + return m_callbackFunction != nullptr; +} + +const std::function& BackgroundQueue::Job::getCallback() const +{ + return m_callbackFunction; +} + +int BackgroundQueue::Job::getPriority() const +{ + return m_priority; +} + +void BackgroundQueue::Job::clear() +{ + m_runFunction = nullptr; + m_callbackFunction = nullptr; + m_priority = TOP_PRIORITY; +} + +void BackgroundQueue::Job::_move(Job& other) +{ + m_runFunction = other.m_runFunction; + other.m_runFunction = nullptr; + + m_callbackFunction = other.m_callbackFunction; + other.m_callbackFunction = nullptr; + + m_priority = other.m_priority; +} + +template<> +struct std::less +{ + bool operator()(const BackgroundQueue::Job& left, const BackgroundQueue::Job& right) const + { + return left.getPriority() < right.getPriority(); + } +}; + +BackgroundQueue::BackgroundQueue(const std::string& name, bool async) + : m_name(name), + m_async(async), + m_jobQueue(nullptr), + m_callbackQueue(nullptr), + m_semaphore(nullptr) +{ + _start(); +} + +BackgroundQueue::~BackgroundQueue() +{ + stop(); + + delete m_jobQueue; + delete m_callbackQueue; + delete m_semaphore; +} + +const std::string& BackgroundQueue::getName() +{ + return m_name; +} + +void BackgroundQueue::resume() +{ + _setState(QS_RUNNING); +} + +bool BackgroundQueue::_pauseQueueJobFunction() +{ + _setState(QS_PAUSING); + return true; +} + +void BackgroundQueue::pause() +{ + std::function pauseFunc = std::bind(&BackgroundQueue::_pauseQueueJobFunction, this); + queue(pauseFunc, NOP, 0); + + while (getState() != QS_PAUSED) + { + std::this_thread::sleep_for(std::chrono::nanoseconds(15000000)); + } +} + +bool BackgroundQueue::_stopQueueJobFunction() +{ + _setState(QS_STOPPED); + return true; +} + +void BackgroundQueue::stop() +{ + if (!m_async) + return; + + if (getState() == QS_STOPPED) + return; + + if (getState() == QS_PAUSED) + { + _setState(QS_STOPPED); + } + else + { + std::function stopFunc = std::bind(&BackgroundQueue::_stopQueueJobFunction, this); + queue(stopFunc, NOP, 0); + + // MATT: i added this in myself, it would instantly kill the thread otherwise + while (getState() != QS_STOPPED) + { + std::this_thread::sleep_for(std::chrono::nanoseconds(15000000)); + } + } + + if (m_thread.native_handle() != nullptr) + m_thread.join(); + + _resetData(); +} + +static bool _SyncJobFunction(Semaphore* semaphore) +{ + semaphore->notify(); + return true; +} + +void BackgroundQueue::sync() +{ + do + { + Semaphore semaphore; + + std::function syncFunc = std::bind(_SyncJobFunction, &semaphore); + queue(syncFunc, NOP, TOP_PRIORITY); + + semaphore.wait(); + } while (_processCallbacks()); +} + +void BackgroundQueue::flush() +{ + if (_workerThread()) + { + _resetData(); + } + else + { + pause(); + _resetData(); + resume(); + } +} + +bool BackgroundQueue::processNext() +{ + if (_processNextCallback()) + return true; + + if (!m_async) + { + if (_processNextCoroutine()) + return true; + } + + return false; +} + +void BackgroundQueue::queue(Job& job) +{ + if (_workerThread()) + m_localJobQueue.push_back(job); + else + m_jobQueue->enqueue(job); + + m_semaphore->notify(); +} + +void BackgroundQueue::queue(const std::function& runFunction, const std::function& callbackFunction, int priority) +{ + if (_workerThread()) + m_localJobQueue.push_back(Job(runFunction, callbackFunction, priority)); + else + m_jobQueue->enqueue(runFunction, callbackFunction, priority); + + m_semaphore->notify(); +} + +void BackgroundQueue::queueCallback(const std::function& callbackFunction) +{ + m_callbackQueue->enqueue(callbackFunction); +} + +BackgroundQueue::State BackgroundQueue::getState() +{ + return m_state.load(std::memory_order_acquire); +} + +void BackgroundQueue::_setState(State state) +{ + m_state.store(state, std::memory_order_release); +} + +bool BackgroundQueue::_workerThread() const +{ + return std::this_thread::get_id() == m_threadId; +} + +void BackgroundQueue::_start() +{ + _resetData(); + _setState(QS_RUNNING); + + if (m_async) + { + std::thread thread(&BackgroundQueue::_processingThreadLogic, this); + m_thread.swap(thread); + } + else + { + SetThreadName(m_name); + m_threadId = std::this_thread::get_id(); + BackgroundQueuePool::getInstance()._setLocal(*this); + } +} + +void BackgroundQueue::_resetData() +{ + m_localJobQueue.clear(); + m_jobPriorityQueue.clear(); + + delete m_callbackQueue; + m_callbackQueue = new LocklessPipe>(); + + delete m_jobQueue; + m_jobQueue = new LocklessPipe(); + + delete m_semaphore; + m_semaphore = new Semaphore(); + + m_currentJob.clear(); +} + +bool BackgroundQueue::_tryPopLocal(Job& job) +{ + if (m_localJobQueue.empty()) + return false; + + job = m_localJobQueue.front(); + m_localJobQueue.pop_front(); + + return true; +} + +bool BackgroundQueue::_tryPopReal(Job& job) +{ + if (m_async) + { + if (m_jobQueue->try_dequeue(job)) + return true; + } + + return _tryPopLocal(job); +} + +void BackgroundQueue::_tryPop() +{ + if (!m_async) + { + _tryPopReal(m_currentJob); + return; + } + + Job job; + while (_tryPopReal(job)) + { + m_jobPriorityQueue.push(job); + } + + if (m_jobPriorityQueue.empty()) + { + m_semaphore->wait(); + } + else + { + m_jobPriorityQueue.popInto(m_currentJob); + } +} + +bool BackgroundQueue::_processCallbacks() +{ + if (getState() == QS_PAUSED || getState() == QS_PAUSING) + return false; + + bool processed = false; + while (_processNextCallback()) + processed = true; + + return processed; +} + +void BackgroundQueue::_processingThreadLogic() +{ + SetThreadName(m_name); + m_threadId = std::this_thread::get_id(); + BackgroundQueuePool::getInstance()._setLocal(*this); + + while (getState() != QS_STOPPED) + { + if (getState() == QS_RUNNING) + { + _processNextCoroutine(); + } + else if (getState() == QS_PAUSING) + { + _setState(QS_PAUSED); + } + else if (getState() == QS_PAUSED) + { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + } +} + +bool BackgroundQueue::_processNextCallback() +{ + std::function callback; + if (m_callbackQueue->try_dequeue(callback)) + { + callback(); + return true; + } + + return false; +} + +bool BackgroundQueue::_processNextCoroutine() +{ + if (!m_currentJob.canRun()) + { + _tryPop(); + if (!m_currentJob.canRun()) + return false; + } + + if (m_currentJob.run()) + { + if (m_currentJob.hasCallback()) + m_callbackQueue->enqueue(m_currentJob.getCallback()); + } + else + { + queue(m_currentJob); + } + + m_currentJob.clear(); + m_coroutineProcessCounter++; + return true; +} diff --git a/source/common/threading/BackgroundQueue.hpp b/source/common/threading/BackgroundQueue.hpp new file mode 100644 index 000000000..56f49dd20 --- /dev/null +++ b/source/common/threading/BackgroundQueue.hpp @@ -0,0 +1,122 @@ +#pragma once +#include +#include +#include +#include "compat/LegacyCPP.hpp" +#include "common/threading/Semaphore.hpp" +#include "common/threading/LocklessPipe.hpp" +#include "common/MovePriorityQueue.hpp" + +class BackgroundQueue +{ +public: + static const int TOP_PRIORITY = INT32_MAX; + +public: + class Job + { + private: + std::function m_runFunction; + std::function m_callbackFunction; + int m_priority; + + public: + Job(); + Job(const std::function& run, const std::function& callback, int priority); + MC_CTOR_MOVE(Job); + + ~Job(); + + public: + bool canRun() const; + bool run(); + + bool hasCallback() const; + const std::function& getCallback() const; + + int getPriority() const; + + void clear(); + + MC_FUNC_MOVE(Job); + + private: + void _move(Job& other); + }; + +public: + static std::function NOP; + +public: + enum State + { + QS_STOPPED, + QS_RUNNING, + QS_PAUSING, + QS_PAUSED + }; + +private: + bool m_async; + std::string m_name; + std::thread m_thread; + std::thread::id m_threadId; + Job m_currentJob; + std::atomic m_state; + Semaphore* m_semaphore; + int m_coroutineProcessCounter; + LocklessPipe* m_jobQueue; + LocklessPipe>* m_callbackQueue; + std::deque m_localJobQueue; + MovePriorityQueue m_jobPriorityQueue; + +private: + // disable copying + BackgroundQueue(const BackgroundQueue&); + BackgroundQueue& operator=(const BackgroundQueue&); + +public: + BackgroundQueue(const std::string& name, bool async); + ~BackgroundQueue(); + +public: + const std::string& getName(); + + void resume(); + void pause(); + void stop(); + + void sync(); + void flush(); + + bool processNext(); + + void queue(Job& job); + void queue(const std::function& runFunction, const std::function& callbackFunction, int priority); + + void queueCallback(const std::function& callbackFunction); + + State getState(); + +private: + bool _workerThread() const; + + void _setState(State state); + + void _start(); + + void _resetData(); + + bool _tryPopLocal(Job& job); + bool _tryPopReal(Job& job); + void _tryPop(); + + bool _processCallbacks(); + bool _processNextCallback(); + bool _processNextCoroutine(); + + void _processingThreadLogic(); + + bool _pauseQueueJobFunction(); + bool _stopQueueJobFunction(); +}; diff --git a/source/common/threading/BackgroundQueuePool.cpp b/source/common/threading/BackgroundQueuePool.cpp new file mode 100644 index 000000000..3f3fbebc5 --- /dev/null +++ b/source/common/threading/BackgroundQueuePool.cpp @@ -0,0 +1,199 @@ +#include +#include "BackgroundQueuePool.hpp" +#include "BackgroundQueue.hpp" +#include "common/Utils.hpp" + +BackgroundQueuePool* BackgroundQueuePool::instance = nullptr; + +BackgroundQueuePool::RolePool::RolePool() + : m_counter(0) +{ +} + +BackgroundQueuePool::RolePool::~RolePool() +{ + for (std::vector::iterator iter = m_queues.begin(); iter != m_queues.end(); iter++) + { + delete (*iter); + } +} + +void BackgroundQueuePool::RolePool::add(BackgroundQueue& queue) +{ + m_queues.push_back(&queue); +} + +BackgroundQueue& BackgroundQueuePool::RolePool::get() +{ + m_counter++; + return *m_queues[m_counter % size()]; +} + +size_t BackgroundQueuePool::RolePool::size() const +{ + return m_queues.size(); +} + +const std::vector& BackgroundQueuePool::RolePool::getQueues() const +{ + return m_queues; +} + +BackgroundQueuePool::BackgroundQueuePool() + : m_state(PS_NORMAL), + m_nextWorkerIndex(0) +{ +} + +BackgroundQueuePool::~BackgroundQueuePool() +{ + for (std::vector::iterator iter = m_workers.begin(); iter != m_workers.end(); iter++) + { + BackgroundQueue* queue = *iter; + queue->stop(); + delete queue; + } +} + +void BackgroundQueuePool::assign(QueueRole role, BackgroundQueue& queue) +{ + m_rolePools[role].add(queue); +} + +BackgroundQueue& BackgroundQueuePool::getFor(int role) +{ + return m_rolePools[role].get(); +} + +BackgroundQueue& BackgroundQueuePool::getFor(QueueRole role) +{ + return m_rolePools[role].get(); +} + +BackgroundQueue& BackgroundQueuePool::getMain() +{ + return getFor(QR_MAIN); +} + +const std::vector& BackgroundQueuePool::getQueuesFor(QueueRole role) const +{ + return m_rolePools[role].getQueues(); +} + +size_t BackgroundQueuePool::count(QueueRole role) const +{ + return m_rolePools[role].size(); +} + +void BackgroundQueuePool::processCoroutines() +{ + switch (m_state) + { + case PS_NORMAL: + _runCoroutines(DBL_MAX); + break; + + case PS_THROTTLED: + _runCoroutines(0.2); + break; + } +} + +void BackgroundQueuePool::setMainThreadHasPriority(bool value) +{ + m_state = value ? PS_NORMAL : PS_THROTTLED; +} + +bool BackgroundQueuePool::_runCoroutines(double timeCap) +{ + double startTime = getTimeS(); + + size_t nonWorkCount = 0; + while (true) + { + while (!m_workers[m_nextWorkerIndex]->processNext()) + { + nonWorkCount++; + m_nextWorkerIndex = (m_nextWorkerIndex + 1) % m_workers.size(); + + if (nonWorkCount >= m_workers.size()) + return true; + } + + double currentTime = getTimeS(); + if ((currentTime - startTime) >= timeCap) + return false; + } +} + +void BackgroundQueuePool::_setLocal(BackgroundQueue& queue) +{ + m_threadQueues[std::this_thread::get_id()] = &queue; +} + +BackgroundQueue& BackgroundQueuePool::_addWorker(const std::string& name, bool async) +{ + m_workers.push_back(new BackgroundQueue(name, async)); + return *m_workers.back(); +} + +void BackgroundQueuePool::_start(int hardwareConcurrency) +{ + assert(hardwareConcurrency > 0); + + BackgroundQueue& mainWorker = _addWorker("Main Thread", false); + assign(QR_MAIN, mainWorker); + + if (hardwareConcurrency > 1) + { + for (int i = 1; i <= hardwareConcurrency; i++) + { + char name[16]; + sprintf_s(name, "Streaming %d", i); + + BackgroundQueue& streamingWorker = _addWorker(name, true); + assign(QR_STREAMING, streamingWorker); + } + } + else + { + // use the main worker for streaming + assign(QR_STREAMING, mainWorker); + } + + BackgroundQueue& ioWorker = _addWorker("IO Thread", true); + assign(QR_IO, ioWorker); +} + +BackgroundQueue* BackgroundQueuePool::getForThread(std::thread::id threadId) +{ + std::unordered_map::const_iterator iter = getInstance().m_threadQueues.find(threadId); + if (iter != getInstance().m_threadQueues.end()) + return iter->second; + + return nullptr; +} + +BackgroundQueue* BackgroundQueuePool::getLocal() +{ + return getForThread(std::this_thread::get_id()); +} + +void BackgroundQueuePool::start(int hardwareConcurrency) +{ + assert(!instance); + instance = new BackgroundQueuePool(); + instance->_start(hardwareConcurrency); +} + +void BackgroundQueuePool::stop() +{ + delete instance; + instance = nullptr; +} + +BackgroundQueuePool& BackgroundQueuePool::getInstance() +{ + assert(instance); + return *instance; +} diff --git a/source/common/threading/BackgroundQueuePool.hpp b/source/common/threading/BackgroundQueuePool.hpp new file mode 100644 index 000000000..29b60a6c4 --- /dev/null +++ b/source/common/threading/BackgroundQueuePool.hpp @@ -0,0 +1,102 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include "common/threading/BackgroundQueue.hpp" + +class BackgroundQueuePool +{ + friend class BackgroundQueue; + +private: + enum State + { + PS_NORMAL, + PS_THROTTLED + }; + +public: + enum QueueRole + { + QR_STREAMING, + QR_IO, + QR_MAIN, + QR_COUNT + }; + +protected: + class RolePool + { + private: + size_t m_counter; + std::vector m_queues; + + public: + RolePool(); + ~RolePool(); + + public: + void add(BackgroundQueue& queue); + BackgroundQueue& get(); + size_t size() const; + const std::vector& getQueues() const; + }; + +protected: + RolePool m_rolePools[QR_COUNT]; + size_t m_nextWorkerIndex; + std::unordered_map m_threadQueues; + State m_state; + std::vector m_workers; + +private: + // disable copying + BackgroundQueuePool(const BackgroundQueuePool&); + BackgroundQueuePool& operator=(const BackgroundQueuePool&); + +protected: + BackgroundQueuePool(); +public: + ~BackgroundQueuePool(); + +public: + void assign(QueueRole role, BackgroundQueue& queue); + + BackgroundQueue& getFor(int role); + BackgroundQueue& getFor(QueueRole role); + BackgroundQueue& getMain(); + const std::vector& getQueuesFor(QueueRole role) const; + size_t count(QueueRole role) const; + + void processCoroutines(); + + void setMainThreadHasPriority(bool value); + +protected: + bool _runCoroutines(double timeCap); + + void _setLocal(BackgroundQueue& queue); + + BackgroundQueue& _addWorker(const std::string& name, bool async); + void _start(int hardwareConcurrency); + +public: + static BackgroundQueue* getForThread(std::thread::id threadId); + static BackgroundQueue* getLocal(); + + static void start(int hardwareConcurrency); + static void stop(); + + static BackgroundQueue& GetFor(QueueRole role) + { + return getInstance().getFor(role); + } + + static BackgroundQueuePool& getInstance(); + +private: + static BackgroundQueuePool* instance; +}; diff --git a/source/common/threading/LocklessPipe.hpp b/source/common/threading/LocklessPipe.hpp new file mode 100644 index 000000000..036c685c5 --- /dev/null +++ b/source/common/threading/LocklessPipe.hpp @@ -0,0 +1,279 @@ +#pragma once +#include +#include + +// A circular, lockless queue +// This is thread-safe as long as there is one consumer and one producer +template +class LocklessPipe +{ +private: + // Starting node items size + static const int START_SIZE = 16; + +private: + // this is required because of how limited older C++ templating was + template + struct ArgHolder1 + { + private: + Arg1& m_arg1; + + public: + ArgHolder1(Arg1& arg1) + : m_arg1(arg1) + { + } + + void create_at(void* block) + { + new (block) T(m_arg1); + } + }; + + template + struct ArgHolder2 + { + private: + Arg1& m_arg1; + Arg2& m_arg2; + + public: + ArgHolder2(Arg1& arg1, Arg2& arg2) + : m_arg1(arg1), m_arg2(arg2) + { + } + + void create_at(void* block) + { + new (block) T(m_arg1, m_arg2); + } + }; + + template + struct ArgHolder3 + { + private: + Arg1& m_arg1; + Arg2& m_arg2; + Arg3& m_arg3; + + public: + ArgHolder3(Arg1& arg1, Arg2& arg2, Arg3& arg3) + : m_arg1(arg1), m_arg2(arg2), m_arg3(arg3) + { + } + + void create_at(void* block) + { + new (block) T(m_arg1, m_arg2, m_arg3); + } + }; + + class Node + { + public: + std::atomic m_readIndex; + + std::atomic m_writeIndex; + + Node* m_nextNode; + size_t m_sizeMask; + char* m_items; + + public: + Node(size_t numItems) + : m_readIndex(0), + m_writeIndex(0), + m_nextNode(this), + m_sizeMask(numItems - 1), + m_items(new char[sizeof(T) * numItems]) + { + } + + ~Node() + { + size_t last = m_writeIndex.load(std::memory_order_relaxed); + for (size_t i = m_readIndex.load(std::memory_order_relaxed); i < last; i++) + { + T& item = get_at(i); + item.~T(); + } + + delete[] m_items; + } + + T& get_at(size_t index) const + { + char& p = m_items[sizeof(T) * index]; + return reinterpret_cast(p); + } + + template + void copy_to(ArgHolder& argHolder, size_t index) + { + void* p = reinterpret_cast(&m_items[sizeof(T) * index]); + argHolder.create_at(p); + } + + size_t next_index(size_t index) const + { + return (index + 1) & m_sizeMask; + } + }; + +private: + std::atomic m_head; + + std::atomic m_tail; + size_t m_lastAssignedSize; + +private: + // disable copying + LocklessPipe(const LocklessPipe&); + LocklessPipe& operator=(const LocklessPipe&); + +public: + LocklessPipe() + : m_lastAssignedSize(START_SIZE) + { + Node* node = new Node(START_SIZE); + m_head.store(node, std::memory_order_relaxed); + m_tail.store(node, std::memory_order_relaxed); + } + + ~LocklessPipe() + { + Node* head = m_head.load(std::memory_order_relaxed); + Node* currentNode = head; + do + { + for (size_t i = currentNode->m_readIndex; i != currentNode->m_writeIndex; i = currentNode->next_index(i)) + { + T& item = currentNode->get_at(i); + item.~T(); + } + + Node* nextNode = currentNode->m_nextNode; + delete currentNode; + currentNode = nextNode; + } while (currentNode != head); + } + +public: + template + bool enqueue(Arg1& arg1) + { + ArgHolder1 holder(arg1); + return enqueue_internal(holder); + } + + template + bool enqueue(Arg1& arg1, Arg2& arg2) + { + ArgHolder2 holder(arg1, arg2); + return enqueue_internal(holder); + } + + template + bool enqueue(Arg1& arg1, Arg2& arg2, Arg3& arg3) + { + ArgHolder3 holder(arg1, arg2, arg3); + return enqueue_internal(holder); + } + +private: + // force inline so the compiler doesnt actually create the argholder struct + template + __forceinline bool enqueue_internal(ArgHolder& argHolder) + { + Node* node = m_tail.load(std::memory_order_relaxed); + size_t writeIndex = node->m_writeIndex.load(std::memory_order_relaxed); + size_t nextWriteIndex = node->next_index(writeIndex); + size_t readIndex = node->m_readIndex.load(std::memory_order_acquire); + + // check if the tail node has any capacity left + // if the next write index is the same as the read index, that indicates that we no longer have any capacity left at this node + if (nextWriteIndex == readIndex) + { + // check if the next node is at the head + // we will likely run out of capacity if we enqueue in the same node as the consumer + if (node->m_nextNode == m_head.load(std::memory_order_acquire)) + { + // we need a new node + // increase the amount of items stored in this node + // with a max determined by "MaxItemsSize" + size_t newNumItems = m_lastAssignedSize; + if (MaxItemsSize > newNumItems) + newNumItems *= 2; + + Node* newNode = new Node(newNumItems); + if (!newNode) + return false; + + newNode->m_nextNode = node->m_nextNode; + node->m_nextNode = newNode; + m_tail.store(newNode, std::memory_order_relaxed); + m_lastAssignedSize = newNumItems; + + // now add the item + newNode->copy_to(argHolder, 0); + newNode->m_writeIndex.store(1, std::memory_order_release); + + return true; + } + else + { + // the consumer is not here, so we're free to write here + // advance to the next node + node = node->m_nextNode; + writeIndex = node->m_writeIndex.load(std::memory_order_relaxed); + nextWriteIndex = node->next_index(writeIndex); + m_tail.store(node, std::memory_order_relaxed); + } + } + + node->copy_to(argHolder, writeIndex); + node->m_writeIndex.store(nextWriteIndex, std::memory_order_release); + + return true; + } + +public: + template + bool try_dequeue(Type& item) + { + Node* node = m_head.load(std::memory_order_relaxed); + size_t readIndex = node->m_readIndex.load(std::memory_order_relaxed); + size_t writeIndex = node->m_writeIndex.load(std::memory_order_acquire); + + // check if the head node is empty + if (readIndex == writeIndex) + { + // are we the final node? (tail) + if (node == node->m_nextNode) + return false; + + // advance head to the next node + node = node->m_nextNode; + m_head.store(node, std::memory_order_release); + + readIndex = node->m_readIndex.load(std::memory_order_relaxed); + writeIndex = node->m_writeIndex.load(std::memory_order_acquire); + + // is this node too empty? + if (readIndex == writeIndex) + return false; // give up, there aren't any further items + } + + T& poppedItem = node->get_at(readIndex); + item = Type(poppedItem); // copy over + + poppedItem.~T(); // we no longer have a need for this + + size_t nextReadIndex = node->next_index(readIndex); + node->m_readIndex.store(nextReadIndex, std::memory_order_release); + + return true; + } +}; diff --git a/source/common/threading/Semaphore.cpp b/source/common/threading/Semaphore.cpp new file mode 100644 index 000000000..681f19523 --- /dev/null +++ b/source/common/threading/Semaphore.cpp @@ -0,0 +1,28 @@ +#include "Semaphore.hpp" + +Semaphore::Semaphore() + : m_count(0) +{ +} + +void Semaphore::notify() +{ + m_mutex.lock(); + + m_count++; + m_condition.notify_one(); + + m_mutex.unlock(); +} + +void Semaphore::wait() +{ + std::unique_lock lock(m_mutex); + + do + { + m_condition.wait(lock); + } while (m_count.load(std::memory_order_acquire) == 0); + + m_count--; +} diff --git a/source/common/threading/Semaphore.hpp b/source/common/threading/Semaphore.hpp new file mode 100644 index 000000000..75fe5592b --- /dev/null +++ b/source/common/threading/Semaphore.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +#include + +class Semaphore +{ +private: + std::mutex m_mutex; + std::condition_variable m_condition; + std::atomic m_count; + +public: + // NOTE: boolean ctor removed because it did nothing + Semaphore(); + void notify(); + void wait(); +}; diff --git a/source/common/threading/ThreadLocal.hpp b/source/common/threading/ThreadLocal.hpp new file mode 100644 index 000000000..daaa6ea80 --- /dev/null +++ b/source/common/threading/ThreadLocal.hpp @@ -0,0 +1,95 @@ +#pragma once +#include +#include +#include +#include +#include + +template +class ThreadLocal +{ +private: + std::function m_creatorFunction; + std::set m_pool; + std::mutex m_creatorMutex; + DWORD m_key; + +private: + // disable copy constructors + ThreadLocal(const ThreadLocal&); + ThreadLocal& operator=(const ThreadLocal&); + +private: + static T* _Create() + { + return new T(); + } + +public: + ThreadLocal() + : m_creatorFunction(std::function(_Create)), + m_key(TlsAlloc()) + { + assert(m_key); + } + + ThreadLocal(const std::function& creator) + : m_creatorFunction(creator), + m_key(TlsAlloc()) + { + assert(m_key); + } + + ~ThreadLocal() + { + BOOL result = TlsFree(m_key); + assert(result == TRUE); + + for (typename std::set::iterator iter = m_pool.begin(); iter != m_pool.end(); iter++) + delete (*iter); + } + +private: + T* _get() const + { + return reinterpret_cast(TlsGetValue(m_key)); + } + +public: + T& getLocal() + { + T* storedPtr = _get(); + if (storedPtr) + return *storedPtr; + + std::lock_guard lock(m_creatorMutex); + + T* ptr = m_creatorFunction(); + BOOL result = TlsSetValue(m_key, ptr); + assert(result == TRUE); + + m_pool.insert(ptr); + return *ptr; + } + + T* getLocalPtr() + { + return &getLocal(); + } + + void resetLocal() + { + T* storedPtr = _get(); + if (!storedPtr) + return; + + std::lock_guard lock(m_creatorMutex); + + typename std::set::iterator iter = std::find(m_pool.begin(), m_pool.end(), storedPtr); + if (iter != m_pool.end()) + m_pool.erase(iter); + + TlsSetValue(m_key, nullptr); + delete storedPtr; + } +}; diff --git a/source/nbt/ListTag.cpp b/source/nbt/ListTag.cpp index 341bff268..33f45fe02 100644 --- a/source/nbt/ListTag.cpp +++ b/source/nbt/ListTag.cpp @@ -60,7 +60,7 @@ void ListTag::add(Tag* tag) m_list.push_back(tag); } -float ListTag::getFloat(unsigned int index) const +float ListTag::getFloat(size_t index) const { if (index < m_list.size() && index >= 0 @@ -75,7 +75,7 @@ float ListTag::getFloat(unsigned int index) const } } -int32_t ListTag::getInt32(unsigned int index) const +int32_t ListTag::getInt32(size_t index) const { if (index < m_list.size() && index >= 0 @@ -90,7 +90,7 @@ int32_t ListTag::getInt32(unsigned int index) const } } -const std::string& ListTag::getString(unsigned int index) const +const std::string& ListTag::getString(size_t index) const { if (index >= m_list.size()) return Util::EMPTY_STRING; @@ -104,7 +104,7 @@ const std::string& ListTag::getString(unsigned int index) const return ((StringTag*)m_list[index])->m_data; } -const CompoundTag* ListTag::getCompound(unsigned int index) const +const CompoundTag* ListTag::getCompound(size_t index) const { if (index < m_list.size() && index >= 0 diff --git a/source/nbt/ListTag.hpp b/source/nbt/ListTag.hpp index 2aca55c4c..99948db02 100644 --- a/source/nbt/ListTag.hpp +++ b/source/nbt/ListTag.hpp @@ -54,11 +54,12 @@ class ListTag : public Tag void load(IDataInput& dis) override; std::string toString() const override; + size_t size() const { return m_list.size(); } void add(Tag* tag); - float getFloat(unsigned int index) const; - int32_t getInt32(unsigned int index) const; - const std::string& getString(unsigned int index) const; - const CompoundTag* getCompound(unsigned int index) const; + float getFloat(size_t index) const; + int32_t getInt32(size_t index) const; + const std::string& getString(size_t index) const; + const CompoundTag* getCompound(size_t index) const; Tag* copy() const override; ListTag* copyList() const; void deleteChildren() override; diff --git a/source/network/packets/ChunkDataPacket.cpp b/source/network/packets/ChunkDataPacket.cpp index 59ddcb5bf..5c0837a38 100644 --- a/source/network/packets/ChunkDataPacket.cpp +++ b/source/network/packets/ChunkDataPacket.cpp @@ -39,8 +39,8 @@ void ChunkDataPacket::write(RakNet::BitStream& bs) int idx = ((i & 0xF) << 11) | (((i >> 4) << 7) + (y * 16)); //write the tile data - m_data.Write((const char*) &m_pChunk->m_pBlockData[idx], 16 * sizeof(TileID)); - m_data.Write((const char*) &m_pChunk->m_tileData.m_data[idx >> 1], 8); + m_data.Write((const char*) &m_pChunk->getTiles()[idx], 16 * sizeof(TileID)); + m_data.Write((const char*) &m_pChunk->getTileData().m_array[idx >> 1], 8); } } } diff --git a/source/network/packets/LevelDataPacket.cpp b/source/network/packets/LevelDataPacket.cpp index 95ba56029..63106c490 100644 --- a/source/network/packets/LevelDataPacket.cpp +++ b/source/network/packets/LevelDataPacket.cpp @@ -40,7 +40,7 @@ void LevelDataPacket::write(RakNet::BitStream& bs) bs2.Write(chunkSepMagic); RakNet::BitStream bs3; - LevelChunk* pChunk = m_pLevel->getChunk(chunkPos); + LevelChunk* pChunk = m_pLevel->getDimension(DIMENSION_OVERWORLD)->getChunkSource()->getOrLoadChunk(chunkPos, ChunkSource::LOAD_NONE); ChunkDataPacket cdp(chunkPos, pChunk); cdp.write(bs3); diff --git a/source/server/ServerPlayer.cpp b/source/server/ServerPlayer.cpp index c48af8dd7..1eac8f976 100644 --- a/source/server/ServerPlayer.cpp +++ b/source/server/ServerPlayer.cpp @@ -12,8 +12,8 @@ #include "world/inventory/ChestMenu.hpp" #include "world/level/Level.hpp" -ServerPlayer::ServerPlayer(Level* pLevel, GameType playerGameType) - : Player(pLevel, playerGameType) +ServerPlayer::ServerPlayer(Level& level, GameType playerGameType) + : Player(level, playerGameType) { m_lastHealth = -999; // -99999999 on Java m_containerId = 0; diff --git a/source/server/ServerPlayer.hpp b/source/server/ServerPlayer.hpp index ddc2b7d53..6bb6adab3 100644 --- a/source/server/ServerPlayer.hpp +++ b/source/server/ServerPlayer.hpp @@ -4,7 +4,7 @@ class ServerPlayer : public Player, public ContainerListener { public: - ServerPlayer(Level* pLevel, GameType playerGameType); + ServerPlayer(Level& Level, GameType playerGameType); protected: void _nextContainerCounter(); diff --git a/source/server/ServerSideNetworkHandler.cpp b/source/server/ServerSideNetworkHandler.cpp index 8824d6560..07505a9ec 100644 --- a/source/server/ServerSideNetworkHandler.cpp +++ b/source/server/ServerSideNetworkHandler.cpp @@ -11,12 +11,9 @@ #include "GameMods.hpp" #include "network/MinecraftPackets.hpp" #include "world/entity/MobFactory.hpp" +#include "world/level/TileSource.hpp" #include "ServerPlayer.hpp" -// How frequently SetTimePackets are sent, in seconds. -// b1.3 sends every second. 0.2.1 seems to send every 12. -#define NETWORK_TIME_SEND_FREQUENCY 12 - // This lets you make the server shut up and not log events in the debug console. //#define VERBOSE_SERVER @@ -98,7 +95,7 @@ void ServerSideNetworkHandler::onDisconnect(const RakNet::RakNetGUID& guid) pPlayer->m_bForceRemove = true; // remove it from our world - m_pLevel->removeEntity(pPlayer); + m_pLevel->removeEntity((Entity*&)pPlayer); } else if ((pPlayer = getPendingPlayerByGUID(guid))) { @@ -148,7 +145,7 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, LoginPacke } #endif - ServerPlayer* pPlayer = new ServerPlayer(m_pLevel, m_pLevel->getLevelData()->getGameType()); + ServerPlayer* pPlayer = new ServerPlayer(*m_pLevel, m_pLevel->getLevelData()->getGameType()); pPlayer->m_guid = guid; pPlayer->m_name = std::string(packet->m_userName.C_String()); @@ -218,15 +215,20 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ReadyPacke #if NETWORK_PROTOCOL_VERSION >= 3 // send the connecting player info about all entities in the world - for (size_t i = 0; i < m_pLevel->m_entities.size(); i++) + for (Level::DimensionVector::iterator it = m_pLevel->m_dimensions.begin(); it != m_pLevel->m_dimensions.end(); it++) { - Entity* entity = m_pLevel->m_entities[i]; - if (canReplicateEntity(entity)) + Dimension& dimension = **it; + const Dimension::EntityIdMap_t& entityIdMap = dimension.getEntityIdMap(); + for (Dimension::EntityIdMap_t::const_iterator it = entityIdMap.begin(); it != entityIdMap.end(); it++) { - AddMobPacket packet(*((Mob*)entity)); - bs.Reset(); - packet.write(bs); - m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false); + const Entity* entity = it->second; + if (canReplicateEntity(entity)) + { + AddMobPacket packet(*((Mob*)entity)); + bs.Reset(); + packet.write(bs); + m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false); + } } } #endif @@ -320,14 +322,16 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlaceBlock Facing::Name face = (Facing::Name)packet->m_face; TileData data = packet->m_data; - if (!m_pLevel->mayPlace(tileId, pos, true)) + TileSource& tileSource = pMob->getTileSource(); + + if (!tileSource.mayPlace(tileId, pos, face, pMob, true)) return; - if (m_pLevel->setTileAndData(pos, tileId, data)) + if (tileSource.setTile(pos, tileId, data)) { Tile* pTile = Tile::tiles[tileId]; - pTile->setPlacedOnFace(m_pLevel, pos, face); - pTile->setPlacedBy(m_pLevel, pos, pMob); + pTile->setPlacedOnFace(&tileSource, pos, face); + pTile->setPlacedBy(&tileSource, pos, pMob); const Tile::SoundType* pSound = pTile->m_pSound; m_pLevel->playSound(pos + 0.5f, "step." + pSound->m_name, 0.5f * (pSound->volume + 1.0f), pSound->pitch * 0.8f); @@ -348,13 +352,15 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, RemoveBloc pPlayer->swing(); + TileSource& source = pPlayer->getTileSource(); + TilePos pos = packet->m_pos; - Tile* pTile = Tile::tiles[m_pLevel->getTile(pos)]; - int auxValue = m_pLevel->getData(pos); + Tile* pTile = Tile::tiles[source.getTile(pos)]; + TileData auxValue = source.getData(pos); - m_pMinecraft->m_pParticleEngine->destroyEffect(pos); + m_pMinecraft->m_pParticleEngine->destroyEffect(pPlayer, pos); - bool setTileResult = m_pLevel->setTile(pos, TILE_AIR); + bool setTileResult = source.setTile(pos, TILE_AIR); if (pTile && setTileResult) { const Tile::SoundType* pSound = pTile->m_pSound; @@ -367,14 +373,14 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, RemoveBloc ItemStack tileItem(pTile, 1, auxValue); if (pTile == Tile::grass || !pPlayer->m_pInventory->hasUnlimitedResource(tileItem)) { - pTile->spawnResources(m_pLevel, pos, auxValue); + pTile->spawnResources(&source, pos, auxValue); } #else - pTile->spawnResources(m_pLevel, pos, auxValue); + pTile->spawnResources(&source, pos, auxValue); #endif } - pTile->destroy(m_pLevel, pos, auxValue); + pTile->destroy(&source, pos, auxValue); // redistribute the packet only if needed redistributePacket(packet, guid); @@ -446,18 +452,20 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, UseItemPac if (!pEntity->isPlayer()) return; + TileSource& tileSource = pPlayer->getTileSource(); + bool onTile = packet->m_tileFace != 255; if (onTile) { - Tile* pTile = Tile::tiles[m_pLevel->getTile(packet->m_tilePos)]; + Tile* pTile = Tile::tiles[tileSource.getTile(packet->m_tilePos)]; if (pTile) { if (pTile == Tile::invisible_bedrock) return; // Interface with tile instead of using item - if (pTile->use(m_pLevel, packet->m_tilePos, pPlayer)) + if (pTile->use(packet->m_tilePos, pPlayer)) { pPlayer->swing(); return; @@ -470,11 +478,11 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, UseItemPac if (onTile) { - packet->m_item.useOn(pPlayer, m_pLevel, packet->m_tilePos, (Facing::Name)packet->m_tileFace); + packet->m_item.useOn(pPlayer, packet->m_tilePos, (Facing::Name)packet->m_tileFace); } else { - packet->m_item.use(m_pLevel, pPlayer); + packet->m_item.use(pPlayer); } pPlayer->swing(); @@ -513,7 +521,10 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, RequestChu return; } - LevelChunk* pChunk = m_pLevel->getChunk(packet->m_chunkPos); + Dimension& overworld = *m_pLevel->getDimension(DIMENSION_OVERWORLD); + TileSource& tileSource = *overworld.getTileSource(); + + LevelChunk* pChunk = tileSource.getChunk(packet->m_chunkPos); if (!pChunk) { LOG_E("No chunk at %d, %d", packet->m_chunkPos.x, packet->m_chunkPos.z); @@ -521,7 +532,7 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, RequestChu } // @NOTE: this allows the client to request empty chunks. Is that okay? - ChunkDataPacket cdp(pChunk->m_chunkPos, pChunk); + ChunkDataPacket cdp(pChunk->getPos(), pChunk); RakNet::BitStream bs; cdp.write(bs); @@ -669,10 +680,12 @@ void ServerSideNetworkHandler::tileBrightnessChanged(const TilePos& pos) void ServerSideNetworkHandler::tileChanged(const TilePos& pos) { + TileSource& tileSource = *m_pLevel->getDimension(DIMENSION_OVERWORLD)->getTileSource(); + UpdateBlockPacket ubp; ubp.m_pos = pos; - ubp.m_tileTypeId = m_pLevel->getTile(pos); - ubp.m_data = m_pLevel->getData(pos); + ubp.m_tileTypeId = tileSource.getTile(pos); + ubp.m_data = tileSource.getData(pos); RakNet::BitStream bs; ubp.write(bs); @@ -680,14 +693,6 @@ void ServerSideNetworkHandler::tileChanged(const TilePos& pos) m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::AddressOrGUID(), true); } -void ServerSideNetworkHandler::timeChanged(uint32_t time) -{ - if ((time % (20 * NETWORK_TIME_SEND_FREQUENCY)) == 0) - { - m_pRakNetInstance->send(new SetTimePacket(time)); - } -} - void ServerSideNetworkHandler::entityAdded(Entity* entity) { if (!canReplicateEntity(entity)) @@ -977,7 +982,7 @@ void ServerSideNetworkHandler::commandTP(OnlinePlayer* player, const std::vector if (!_checkPermissions(player)) return; - Vec3 pos = player->m_pPlayer->getPos(1.0f); + Vec3 pos = player->m_pPlayer->getPos(); std::stringstream ss; if (parms[0] != "~") @@ -1002,7 +1007,7 @@ void ServerSideNetworkHandler::commandTP(OnlinePlayer* player, const std::vector ss.clear(); player->m_pPlayer->setPos(pos); - pos = player->m_pPlayer->getPos(1.0f); + pos = player->m_pPlayer->getPos(); ss << "Teleported to " << pos.x << ", " << pos.y << ", " << pos.z; @@ -1032,7 +1037,7 @@ void ServerSideNetworkHandler::commandSummon(OnlinePlayer* player, const std::ve const EntityTypeDescriptor* descriptor = EntityTypeDescriptor::GetByEntityTypeName(entityName); if (descriptor != nullptr) { - Vec3 pos = player->m_pPlayer->getPos(1.0f); + Vec3 pos = player->m_pPlayer->getPos(); pos.y -= player->m_pPlayer->m_heightOffset + player->m_pPlayer->m_ySlideOffset; if (parmsSize >= 4) @@ -1072,7 +1077,7 @@ void ServerSideNetworkHandler::commandSummon(OnlinePlayer* player, const std::ve for (int i = 0; i++ < amount;) { - Mob* mob = MobFactory::CreateMob(descriptor->getEntityType().getId(), m_pLevel); + Mob* mob = MobFactory::CreateMob(descriptor->getEntityType().getId(), player->m_pPlayer->getTileSource()); if (mob == nullptr) { ss << "Unable to summon object"; diff --git a/source/server/ServerSideNetworkHandler.hpp b/source/server/ServerSideNetworkHandler.hpp index 725ed7054..f356510da 100644 --- a/source/server/ServerSideNetworkHandler.hpp +++ b/source/server/ServerSideNetworkHandler.hpp @@ -69,7 +69,6 @@ class ServerSideNetworkHandler : public NetEventCallback, public LevelListener // Overridden from LevelListener void tileBrightnessChanged(const TilePos& pos) override; void tileChanged(const TilePos& pos) override; - void timeChanged(uint32_t time) override; void entityAdded(Entity* entity) override; void entityRemoved(Entity* entity) override; void levelEvent(const LevelEvent& event) override; diff --git a/source/world/Facing.cpp b/source/world/Facing.cpp new file mode 100644 index 000000000..f84b1d6ec --- /dev/null +++ b/source/world/Facing.cpp @@ -0,0 +1,20 @@ +#include "world/Facing.hpp" +#include "world/level/TilePos.hpp" + +Facing::Name Facing::DIRECTIONS[COUNT] = { + Facing::DOWN, + Facing::UP, + Facing::NORTH, + Facing::SOUTH, + Facing::WEST, + Facing::EAST +}; + +TilePos Facing::DIRECTION[COUNT] = { + TilePos(0, -1, 0), // DOWN + TilePos(0, 1, 0), // UP + TilePos(0, 0, -1), // NORTH + TilePos(0, 0, 1), // SOUTH + TilePos(-1, 0, 0), // WEST + TilePos(1, 0, 0) // EAST +}; diff --git a/source/world/Facing.hpp b/source/world/Facing.hpp index 740f1ce37..1e8a18507 100644 --- a/source/world/Facing.hpp +++ b/source/world/Facing.hpp @@ -1,5 +1,7 @@ #pragma once +struct TilePos; + class Facing { public: @@ -10,6 +12,11 @@ class Facing NORTH, // -Z SOUTH, // +Z WEST, // -X - EAST // +X + EAST, // +X + COUNT }; + +public: + static Name DIRECTIONS[COUNT]; + static TilePos DIRECTION[COUNT]; }; diff --git a/source/world/entity/Animal.cpp b/source/world/entity/Animal.cpp index 734ce8319..b0ceccd6b 100644 --- a/source/world/entity/Animal.cpp +++ b/source/world/entity/Animal.cpp @@ -8,8 +8,9 @@ #include "Animal.hpp" #include "world/level/Level.hpp" #include "nbt/CompoundTag.hpp" +#include "world/level/TileSource.hpp" -Animal::Animal(Level* pLevel) : PathfinderMob(pLevel) +Animal::Animal(TileSource& source) : PathfinderMob(source) { field_BB4 = 0; m_age = 0; @@ -49,7 +50,7 @@ bool Animal::canSpawn() { TilePos pos(m_pos.x, m_hitbox.min.y, m_pos.z); - if (m_pLevel->getTile(pos.below()) != Tile::grass->m_ID || m_pLevel->getRawBrightness(pos) < 8) + if (m_tileSource->getTile(pos.below()) != Tile::grass->m_ID || m_tileSource->getRawBrightness(pos) < 8) return false; return PathfinderMob::canSpawn(); @@ -69,11 +70,11 @@ int Animal::getAmbientSoundInterval() const float Animal::getWalkTargetValue(const TilePos& pos) const { // Animals would rather walk on grass. - if (m_pLevel->getTile(pos.below()) == Tile::grass->m_ID) + if (m_tileSource->getTile(pos.below()) == Tile::grass->m_ID) return 10.0f; // Animals will avoid dark areas. - return m_pLevel->getBrightness(pos) - 0.5f; + return m_tileSource->getBrightness(pos) - 0.5f; } /*bool Animal::hurt(Entity* pCulprit, int damage) diff --git a/source/world/entity/Animal.hpp b/source/world/entity/Animal.hpp index 7d1873b89..98040973d 100644 --- a/source/world/entity/Animal.hpp +++ b/source/world/entity/Animal.hpp @@ -12,7 +12,7 @@ class Animal : public PathfinderMob { public: - Animal(Level* pLevel); + Animal(TileSource& source); void addAdditionalSaveData(CompoundTag& tag) const override; void readAdditionalSaveData(const CompoundTag& tag) override; void aiStep() override; diff --git a/source/world/entity/Arrow.cpp b/source/world/entity/Arrow.cpp index b9f4c7090..738817cde 100644 --- a/source/world/entity/Arrow.cpp +++ b/source/world/entity/Arrow.cpp @@ -1,6 +1,7 @@ #include "Arrow.hpp" #include "Mob.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "nbt/CompoundTag.hpp" const unsigned int Arrow::ARROW_BASE_DAMAGE = 4; @@ -22,25 +23,25 @@ void Arrow::_init() m_owner = nullptr; } -Arrow::Arrow(Level* pLevel) : Entity(pLevel) +Arrow::Arrow(TileSource& source) : Entity(source) { _init(); } -Arrow::Arrow(Level* pLevel, const Vec3& pos) : Entity(pLevel) +Arrow::Arrow(TileSource& source, const Vec3& pos) : Entity(source) { _init(); setPos(pos); } -Arrow::Arrow(Level* pLevel, Mob* pMob) : Entity(pLevel) +Arrow::Arrow(Mob& mob) : Entity(*mob.m_tileSource) { _init(); - m_owner = pMob; + m_owner = &mob; m_bIsPlayerOwned = m_owner->isPlayer(); - moveTo(Vec3(pMob->m_pos.x, pMob->m_pos.y + pMob->getHeadHeight(), pMob->m_pos.z), Vec2(pMob->m_rot.y, pMob->m_rot.x)); + moveTo(Vec3(mob.m_pos.x, mob.m_pos.y + mob.getHeadHeight(), mob.m_pos.z), Vec2(mob.m_rot.y, mob.m_rot.x)); m_pos.x -= Mth::cos(m_rot.y / 180.0f * M_PI) * 0.16f; m_pos.y -= 0.1f; @@ -101,7 +102,7 @@ void Arrow::tick() if (m_bInGround) { - if (m_pLevel->getTile(m_tilePos) == m_lastTile) + if (m_tileSource->getTile(m_tilePos) == m_lastTile) { ++m_life; if (m_life == 1200) @@ -124,21 +125,21 @@ void Arrow::tick() ++m_flightTime; } - Vec3 future_pos = m_pos + m_vel; - HitResult hit_result = m_pLevel->clip(m_pos, future_pos); - if (hit_result.isHit()) + Vec3 futurePos = m_pos + m_vel; + HitResult hitResult = m_tileSource->clip(m_pos, futurePos, false, true); + if (hitResult.isHit()) { - future_pos = hit_result.m_hitPos; + futurePos = hitResult.m_hitPos; } - Entity* hit_ent = nullptr; + Entity* hitEnt = nullptr; AABB hitbox = m_hitbox; hitbox.expand(m_vel.x, m_vel.y, m_vel.z).grow(1.0f); - EntityVector entities = m_pLevel->getEntities(this, hitbox); + const std::vector& entities = m_tileSource->getEntities(this, hitbox); float max_dist = 0.0f; constexpr float var10 = 0.3f; - for (EntityVector::iterator it = entities.begin(); it != entities.end(); it++) + for (std::vector::const_iterator it = entities.begin(); it != entities.end(); it++) { Entity* ent = *it; if (ent->isPickable() && (ent != m_owner || m_flightTime >= 5)) @@ -146,29 +147,29 @@ void Arrow::tick() AABB aabb = ent->m_hitbox; aabb.grow(var10); // these Vec3's are copied in the TilePos::clip fn, so no need to create them over and over like in b1.2 - HitResult hit = aabb.clip(m_pos, future_pos); + HitResult hit = aabb.clip(m_pos, futurePos); if (hit.isHit()) { float distance = m_pos.distanceTo(hit.m_hitPos); if (distance < max_dist || max_dist == 0.0f) { - hit_ent = ent; + hitEnt = ent; max_dist = distance; } } } } - if (hit_ent != nullptr) + if (hitEnt != nullptr) { - hit_result = HitResult(hit_ent); + hitResult = HitResult(hitEnt); } - if (hit_result.isHit()) + if (hitResult.isHit()) { - if (hit_result.m_pEnt != nullptr) + if (hitResult.m_pEnt != nullptr) { - if (hit_result.m_pEnt->hurt(m_owner, ARROW_BASE_DAMAGE)) + if (hitResult.m_pEnt->hurt(m_owner, ARROW_BASE_DAMAGE)) { m_pLevel->playSound(this, "random.drr", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f)); remove(); @@ -183,9 +184,9 @@ void Arrow::tick() } else { - m_tilePos = hit_result.m_tilePos; - m_lastTile = m_pLevel->getTile(m_tilePos); - m_vel = hit_result.m_hitPos - m_pos; + m_tilePos = hitResult.m_tilePos; + m_lastTile = m_tileSource->getTile(m_tilePos); + m_vel = hitResult.m_hitPos - m_pos; m_pos -= (m_vel / m_pos.length() * 0.05f); m_pLevel->playSound(this, "random.drr", 1.0f, 1.2f / (sharedRandom.nextFloat() * 0.2f + 0.9f)); m_bInGround = true; diff --git a/source/world/entity/Arrow.hpp b/source/world/entity/Arrow.hpp index 5a08fc1da..b1fd52d0d 100644 --- a/source/world/entity/Arrow.hpp +++ b/source/world/entity/Arrow.hpp @@ -11,9 +11,9 @@ class Arrow : public Entity void _init(); public: - Arrow(Level* pLevel); - Arrow(Level* pLevel, const Vec3& pos); - Arrow(Level* pLevel, Mob* pMob); + Arrow(TileSource& source); + Arrow(TileSource& source, const Vec3& pos); + Arrow(Mob& mob); private: void _lerpMotion(const Vec3& vel); diff --git a/source/world/entity/Chicken.cpp b/source/world/entity/Chicken.cpp index 4a7754eec..586e393b9 100644 --- a/source/world/entity/Chicken.cpp +++ b/source/world/entity/Chicken.cpp @@ -8,7 +8,7 @@ #include "Chicken.hpp" #include "world/level/Level.hpp" -Chicken::Chicken(Level* pLevel) : Animal(pLevel) +Chicken::Chicken(TileSource& source) : Animal(source) { m_pDescriptor = &EntityTypeDescriptor::chicken; m_renderType = RENDER_CHICKEN; diff --git a/source/world/entity/Chicken.hpp b/source/world/entity/Chicken.hpp index 2cf658c94..9672f15b5 100644 --- a/source/world/entity/Chicken.hpp +++ b/source/world/entity/Chicken.hpp @@ -20,7 +20,7 @@ class Chicken : public Animal int m_eggTime; public: - Chicken(Level* pLevel); + Chicken(TileSource& source); public: std::string getAmbientSound() const override { return "mob.chicken"; } @@ -33,5 +33,5 @@ class Chicken : public Animal void addAdditionalSaveData(CompoundTag& tag) const override; void readAdditionalSaveData(const CompoundTag& tag) override; - Entity* getBreedOffspring(Animal* pOther) { return new Chicken(m_pLevel); } + Entity* getBreedOffspring(Animal* pOther) { return new Chicken(*m_tileSource); } }; diff --git a/source/world/entity/Cow.cpp b/source/world/entity/Cow.cpp index 1514d7fe7..b083ada8b 100644 --- a/source/world/entity/Cow.cpp +++ b/source/world/entity/Cow.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "Cow.hpp" -Cow::Cow(Level* pLevel) : Animal(pLevel) +Cow::Cow(TileSource& source) : Animal(source) { m_pDescriptor = &EntityTypeDescriptor::cow; m_renderType = RENDER_COW; diff --git a/source/world/entity/Cow.hpp b/source/world/entity/Cow.hpp index 1a000117d..88a8fa4a1 100644 --- a/source/world/entity/Cow.hpp +++ b/source/world/entity/Cow.hpp @@ -12,7 +12,7 @@ class Cow : public Animal { public: - Cow(Level* pLevel); + Cow(TileSource& source); public: std::string getAmbientSound() const override { return "mob.cow"; }; @@ -24,5 +24,5 @@ class Cow : public Animal void addAdditionalSaveData(CompoundTag& tag) const override; void readAdditionalSaveData(const CompoundTag& tag) override; - Entity* getBreedOffspring(Animal* pOther) { return new Cow(m_pLevel); } + Entity* getBreedOffspring(Animal* pOther) { return new Cow(*m_tileSource); } }; diff --git a/source/world/entity/Creeper.cpp b/source/world/entity/Creeper.cpp index 5046ff694..be2644d56 100644 --- a/source/world/entity/Creeper.cpp +++ b/source/world/entity/Creeper.cpp @@ -1,6 +1,6 @@ #include "world/entity/Creeper.hpp" -Creeper::Creeper(Level* pLevel) : Monster(pLevel) +Creeper::Creeper(TileSource& source) : Monster(source) { m_pDescriptor = &EntityTypeDescriptor::creeper; m_renderType = RENDER_CREEPER; diff --git a/source/world/entity/Creeper.hpp b/source/world/entity/Creeper.hpp index fe8478790..6c531afdd 100644 --- a/source/world/entity/Creeper.hpp +++ b/source/world/entity/Creeper.hpp @@ -8,7 +8,7 @@ class Creeper : public Monster { public: - Creeper(Level* pLevel); + Creeper(TileSource& source); public: void tick() override; diff --git a/source/world/entity/Entity.cpp b/source/world/entity/Entity.cpp index 69626c536..606b0eb43 100644 --- a/source/world/entity/Entity.cpp +++ b/source/world/entity/Entity.cpp @@ -11,6 +11,7 @@ #include "common/Logger.hpp" #include "nbt/CompoundTag.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "Player.hpp" @@ -65,11 +66,24 @@ void Entity::_init() m_pDescriptor = &EntityTypeDescriptor::unknown; } -Entity::Entity(Level* pLevel) +Entity::Entity(Level& level) + : m_tileSource(nullptr), + m_pLevel(&level) +{ + _init(); + + m_EntityID = ++entityCounter; + setPos(Vec3::ZERO); + + m_entityData.define(DATA_SHARED_FLAGS_ID, 0); +} + +Entity::Entity(TileSource& tileSource) + : m_tileSource(&tileSource), + m_pLevel(&tileSource.getLevel()) { _init(); - m_pLevel = pLevel; m_EntityID = ++entityCounter; setPos(Vec3::ZERO); @@ -110,6 +124,11 @@ void Entity::removed() m_bRemoved = true; } +const Vec3& Entity::getPos() const +{ + return m_pos; +} + void Entity::setPos(const Vec3& pos) { m_pos = pos; @@ -162,7 +181,7 @@ void Entity::move(const Vec3& pos) bool validSneaking = m_bOnGround && isSneaking(); if (validSneaking) { - for (float dx = 0.05f; newPos.x != 0.0f && m_pLevel->getCubes(this, AABB(m_hitbox).move(newPos.x, -1.0f, 0.0f))->size() == 0; cPosX = newPos.x) + for (float dx = 0.05f; newPos.x != 0.0f && m_tileSource->fetchAABBs(AABB(m_hitbox).move(newPos.x, -1.0f, 0.0f), true).size() == 0; cPosX = newPos.x) { if (newPos.x < dx && newPos.x >= -dx) newPos.x = 0.0; @@ -172,7 +191,7 @@ void Entity::move(const Vec3& pos) newPos.x += dx; } - for (float dz = 0.05f; newPos.z != 0.0f && m_pLevel->getCubes(this, AABB(m_hitbox).move(0.0f, -1.0f, newPos.z))->size() == 0; cPosZ = newPos.z) + for (float dz = 0.05f; newPos.z != 0.0f && m_tileSource->fetchAABBs(AABB(m_hitbox).move(0.0f, -1.0f, newPos.z), true).size() == 0; cPosZ = newPos.z) { if (newPos.z < dz && newPos.z >= -dz) newPos.z = 0.0f; @@ -183,10 +202,10 @@ void Entity::move(const Vec3& pos) } } - AABBVector* cubes = m_pLevel->getCubes(this, AABB(m_hitbox).expand(newPos.x, newPos.y, newPos.z)); + std::vector& cubes = m_tileSource->fetchAABBs(AABB(m_hitbox).expand(newPos.x, newPos.y, newPos.z), true); - for (size_t i = 0; i < cubes->size(); ++i) - newPos.y = cubes->at(i).clipYCollide(m_hitbox, newPos.y); + for (size_t i = 0; i < cubes.size(); ++i) + newPos.y = cubes.at(i).clipYCollide(m_hitbox, newPos.y); m_hitbox.move(0.0f, newPos.y, 0.0f); if (!m_bSlide && cPosY != newPos.y) @@ -194,15 +213,15 @@ void Entity::move(const Vec3& pos) bool lastsOnGround = m_bOnGround || (cPosY != newPos.y && cPosY < 0.0); - for (size_t i = 0; i < cubes->size(); ++i) - newPos.x = cubes->at(i).clipXCollide(m_hitbox, newPos.x); + for (size_t i = 0; i < cubes.size(); ++i) + newPos.x = cubes.at(i).clipXCollide(m_hitbox, newPos.x); m_hitbox.move(newPos.x, 0.0f, 0.0f); if (!m_bSlide && cPosX != newPos.x) newPos = Vec3::ZERO; - for (size_t i = 0; i < cubes->size(); ++i) - newPos.z = cubes->at(i).clipZCollide(m_hitbox, newPos.z); + for (size_t i = 0; i < cubes.size(); ++i) + newPos.z = cubes.at(i).clipZCollide(m_hitbox, newPos.z); m_hitbox.move(0.0f, 0.0f, newPos.z); if (!m_bSlide && cPosZ != newPos.z) @@ -216,24 +235,24 @@ void Entity::move(const Vec3& pos) newPos.z = cPosZ; AABB oldHit = m_hitbox; m_hitbox = lastHit; - cubes = m_pLevel->getCubes(this, AABB(m_hitbox).expand(cPosX, newPos.y, cPosZ)); + cubes = m_tileSource->fetchAABBs(AABB(m_hitbox).expand(cPosX, newPos.y, cPosZ), true); - for (size_t i = 0; i < cubes->size(); ++i) - newPos.y = cubes->at(i).clipYCollide(m_hitbox, newPos.y); + for (size_t i = 0; i < cubes.size(); ++i) + newPos.y = cubes.at(i).clipYCollide(m_hitbox, newPos.y); m_hitbox.move(0.0f, newPos.y, 0.0f); if (!m_bSlide && cPosY != newPos.y) newPos = Vec3::ZERO; - for (size_t i = 0; i < cubes->size(); ++i) - newPos.x = cubes->at(i).clipXCollide(m_hitbox, newPos.x); + for (size_t i = 0; i < cubes.size(); ++i) + newPos.x = cubes.at(i).clipXCollide(m_hitbox, newPos.x); m_hitbox.move(newPos.x, 0.0f, 0.0f); if (!m_bSlide && cPosX != newPos.x) newPos = Vec3::ZERO; - for (size_t i = 0; i < cubes->size(); ++i) - newPos.z = cubes->at(i).clipZCollide(m_hitbox, newPos.z); + for (size_t i = 0; i < cubes.size(); ++i) + newPos.z = cubes.at(i).clipZCollide(m_hitbox, newPos.z); m_hitbox.move(0.0f, 0.0f, newPos.z); if (!m_bSlide && cPosZ != newPos.z) @@ -275,9 +294,9 @@ void Entity::move(const Vec3& pos) { m_walkDist = float(m_walkDist + Mth::sqrt(diffX * diffX + diffZ * diffZ) * 0.6f); TilePos tp(m_pos.x, m_pos.y - 0.2f - m_heightOffset, m_pos.z); - TileID i = m_pLevel->getTile(tp); + TileID i = m_tileSource->getTile(tp); - if (m_pLevel->getTile(tp.below()) == Tile::fence->m_ID) + if (m_tileSource->getTile(tp.below()) == Tile::fence->m_ID) i = Tile::fence->m_ID; if (m_walkDist > m_nextStep && i > 0) @@ -286,7 +305,7 @@ void Entity::move(const Vec3& pos) const Tile::SoundType* sound = nullptr; // vol is * 0.15f in Java, is quiet for whatever reason, so bumping to 0.20f - if (m_pLevel->getTile(tp.above()) == Tile::topSnow->m_ID) + if (m_tileSource->getTile(tp.above()) == Tile::topSnow->m_ID) { sound = Tile::topSnow->m_pSound; } @@ -298,7 +317,7 @@ void Entity::move(const Vec3& pos) if (sound != nullptr) m_pLevel->playSound(this, "step." + sound->m_name, sound->volume * 0.20f, sound->pitch); - Tile::tiles[i]->stepOn(m_pLevel, tp, this); + Tile::tiles[i]->stepOn(m_tileSource, tp, this); } } @@ -306,21 +325,21 @@ void Entity::move(const Vec3& pos) TilePos maxPos(m_hitbox.max - 0.001f); TilePos tilePos; - if (m_pLevel->hasChunksAt(minPos, TilePos(maxPos))) + if (m_tileSource->hasChunksAt(minPos, TilePos(maxPos))) { for (tilePos.x = minPos.x; tilePos.x <= maxPos.x; tilePos.x++) for (tilePos.y = minPos.y; tilePos.y <= maxPos.y; tilePos.y++) for (tilePos.z = minPos.z; tilePos.z <= maxPos.z; tilePos.z++) { - TileID tileID = m_pLevel->getTile(tilePos); + TileID tileID = m_tileSource->getTile(tilePos); if (tileID > 0) - Tile::tiles[tileID]->entityInside(m_pLevel, tilePos, this); + Tile::tiles[tileID]->entityInside(m_tileSource, tilePos, this); } } bool bIsInWater = isInWater(); - if (m_pLevel->containsFireTile(AABB(minPos, maxPos))) + if (m_tileSource->containsFireTile(AABB(minPos, maxPos))) { burn(1); @@ -584,11 +603,9 @@ bool Entity::isFree(const Vec3& off) const AABB aabb = m_hitbox; aabb.move(off); - AABBVector* pCubes = m_pLevel->getCubes(this, aabb); - if (!pCubes) - return false; + std::vector& pCubes = m_tileSource->fetchAABBs(aabb, true); - return !m_pLevel->containsAnyLiquid(aabb); + return !m_tileSource->containsAnyLiquid(aabb); } bool Entity::isFree(const Vec3& off, float expand) const @@ -597,16 +614,14 @@ bool Entity::isFree(const Vec3& off, float expand) const aabb.move(off); aabb.grow(expand, expand, expand); - AABBVector* pCubes = m_pLevel->getCubes(this, aabb); - if (!pCubes) - return false; + std::vector& pCubes = m_tileSource->fetchAABBs(aabb, true); - return !m_pLevel->containsAnyLiquid(aabb); + return !m_tileSource->containsAnyLiquid(aabb); } bool Entity::isInWall() const { - return m_pLevel->isSolidTile(TilePos(m_pos.x, m_pos.y + getHeadHeight(), m_pos.z)); + return m_tileSource->isSolidBlockingTile(TilePos(m_pos.x, m_pos.y + getHeadHeight(), m_pos.z)); } bool Entity::isInWater() @@ -620,18 +635,18 @@ bool Entity::isInLava() const { AABB aabb = m_hitbox; aabb.grow(-0.1f, -0.4f, -0.1f); - return m_pLevel->containsMaterial(aabb, Material::lava); + return m_tileSource->containsMaterial(aabb, Material::lava); } bool Entity::isUnderLiquid(Material* pMtl) const { TilePos tilePos(m_pos.x, m_pos.y + getHeadHeight(), m_pos.z); - Tile* pTile = Tile::tiles[m_pLevel->getTile(tilePos)]; + Tile* pTile = Tile::tiles[m_tileSource->getTile(tilePos)]; if (!pTile || pTile->m_pMaterial != pMtl) return false; - TileData data = m_pLevel->getData(tilePos); + TileData data = m_tileSource->getData(tilePos); int level = data <= 7 ? data + 1 : 1; return float(tilePos.y) < float(tilePos.y + 1) - (float(level) / 9.0f - 0.11111f); @@ -644,14 +659,13 @@ float Entity::getBrightness(float f) const TilePos tileMin(m_hitbox.min); TilePos tileMax(m_hitbox.max); - if (!m_pLevel->hasChunksAt(tileMin, tileMax)) + if (!m_tileSource->hasChunksAt(tileMin, tileMax)) return 0; - return Mth::Max(m_minBrightness, m_pLevel->getBrightness(tilePos)); + return Mth::Max(m_minBrightness, m_tileSource->getBrightness(tilePos)); } -// renamed to getInterpolatedPosition in 0.12.1 -Vec3 Entity::getPos(float f) const +Vec3 Entity::getInterpolatedPosition(float f) const { if (f == 1.0f) return m_pos; @@ -663,8 +677,7 @@ Vec3 Entity::getPos(float f) const ); } -// renamed to getInterpolatedRotation in 0.12.1 -Vec2 Entity::getRot(float f) const +Vec2 Entity::getInterpolatedRotation(float f) const { return Vec2( Mth::Lerp(m_oRot.x, m_rot.x, f), @@ -793,11 +806,11 @@ void Entity::animateHurt() ItemEntity* Entity::spawnAtLocation(const ItemStack& itemStack, float y) { - ItemEntity *itemEntity = new ItemEntity(m_pLevel, Vec3(m_pos.x, m_pos.y + y, m_pos.z), itemStack); + ItemEntity* itemEntity = new ItemEntity(getTileSource(), Vec3(m_pos.x, m_pos.y + y, m_pos.z), itemStack); // @TODO: not sure what this does, or is for itemEntity->m_oPos.x = 10; m_pLevel->addEntity(itemEntity); - + return itemEntity; } @@ -868,10 +881,10 @@ void Entity::resetPos(bool respawn) { setPos(m_pos); - AABBVector* pCubes = m_pLevel->getCubes(this, m_hitbox); + std::vector& pCubes = m_tileSource->fetchAABBs(m_hitbox, true); // if we aren't inside any tiles, great! - if (!pCubes->size()) + if (pCubes.size() == 0) break; m_pos.y += 1.0f; @@ -1043,6 +1056,11 @@ EntityType::ID Entity::getEncodeId() const return getDescriptor().getEntityType().getId(); } +Dimension* Entity::getDimension() const +{ + return getLevel().getDimension(getDimensionId()); +} + bool Entity::operator==(const Entity& other) const { return m_EntityID == other.m_EntityID; diff --git a/source/world/entity/Entity.hpp b/source/world/entity/Entity.hpp index 3780cb7b1..10b177bc6 100644 --- a/source/world/entity/Entity.hpp +++ b/source/world/entity/Entity.hpp @@ -12,7 +12,6 @@ #include "world/phys/Vec3.hpp" #include "world/phys/Vec2.hpp" #include "world/phys/AABB.hpp" -#include "world/level/Dimension.hpp" #include "world/level/Material.hpp" #include "world/level/levelgen/chunk/ChunkPos.hpp" #include "world/tile/Tile.hpp" @@ -24,6 +23,9 @@ class Level; class Player; class ItemStack; class ItemEntity; +class TileSource; +class Dimension; +enum DimensionId; struct EntityPos { @@ -63,6 +65,7 @@ class Entity public: typedef int32_t ID; typedef int32_t AuxValue; + typedef std::vector Vector; public: class EventType { @@ -116,7 +119,8 @@ class Entity void _init(); public: Entity() { _init(); } - Entity(Level*); + Entity(Level& level); + Entity(TileSource& tileSource); virtual ~Entity(); protected: @@ -127,6 +131,7 @@ class Entity virtual void reset(); virtual void setLevel(Level*); virtual void removed(); + virtual const Vec3& getPos() const; virtual void setPos(const Vec3& pos); virtual void remove(); virtual void move(const Vec3& posIn); @@ -153,8 +158,8 @@ class Entity virtual float getShadowHeightOffs() const { return m_bbHeight / 2.0f; } virtual float getBrightness(float f) const; virtual DimensionId getDimensionId() const { return m_dimensionId; } - virtual Vec3 getPos(float f) const; - virtual Vec2 getRot(float f) const; + virtual Vec3 getInterpolatedPosition(float f) const; + virtual Vec2 getInterpolatedRotation(float f) const; virtual Vec3 getViewVector(float f) const; virtual AuxValue getAuxValue() const; virtual void setAuxValue(AuxValue value); @@ -217,10 +222,13 @@ class Entity //virtual void defineSynchedData(); EntityType::ID getEncodeId() const; Entity::ID hashCode() const { return m_EntityID; } + Dimension* getDimension() const; const EntityTypeDescriptor& getDescriptor() const { return *m_pDescriptor; } SynchedEntityData& getEntityData() { return m_entityData; } const SynchedEntityData& getEntityData() const { return m_entityData; } + Level& getLevel() const { return *m_pLevel; } + TileSource& getTileSource() const { return *m_tileSource; } bool operator==(const Entity& other) const; @@ -248,6 +256,7 @@ class Entity DimensionId m_dimensionId; bool m_bBlocksBuilding; Level* m_pLevel; + TileSource* m_tileSource; Vec3 m_oPos; // "o" in Java or "xo" "yo" "zo" Vec3 m_vel; Vec2 m_rot; diff --git a/source/world/entity/EntityFactory.cpp b/source/world/entity/EntityFactory.cpp index 85acaa8e0..25c6d9709 100644 --- a/source/world/entity/EntityFactory.cpp +++ b/source/world/entity/EntityFactory.cpp @@ -19,9 +19,9 @@ //ENT(THROWN_EGG, ThrownEgg) //ENT(PAINTING, Painting) -#define ENT(enumType, classType) case EntityType::enumType: return new classType(level); +#define ENT(enumType, classType) case EntityType::enumType: return new classType(source); -Entity* EntityFactory::CreateEntity(EntityType::ID entityType, Level* level) +Entity* EntityFactory::CreateEntity(EntityType::ID entityType, TileSource& source) { switch (entityType) { @@ -32,7 +32,7 @@ Entity* EntityFactory::CreateEntity(EntityType::ID entityType, Level* level) } } -Entity* EntityFactory::LoadEntity(const CompoundTag& tag, Level* level) +Entity* EntityFactory::LoadEntity(const CompoundTag& tag, TileSource& source) { EntityType::ID entityTypeId = (EntityType::ID)tag.getInt32("id"); if (entityTypeId < 0) @@ -52,11 +52,11 @@ Entity* EntityFactory::LoadEntity(const CompoundTag& tag, Level* level) if (entityTypeDescriptor->hasCategory(EntityCategories::MOB)) { - entity = MobFactory::CreateMob(entityTypeId, level); + entity = MobFactory::CreateMob(entityTypeId, source); } else { - entity = EntityFactory::CreateEntity(entityTypeId, level); + entity = EntityFactory::CreateEntity(entityTypeId, source); } if (entity) diff --git a/source/world/entity/EntityFactory.hpp b/source/world/entity/EntityFactory.hpp index fb8e48591..cf90fa101 100644 --- a/source/world/entity/EntityFactory.hpp +++ b/source/world/entity/EntityFactory.hpp @@ -6,6 +6,6 @@ class EntityFactory { public: - static Entity* CreateEntity(EntityType::ID entityType, Level* level); - static Entity* LoadEntity(const CompoundTag& tag, Level* level); + static Entity* CreateEntity(EntityType::ID entityType, TileSource& source); + static Entity* LoadEntity(const CompoundTag& tag, TileSource& source); }; diff --git a/source/world/entity/FallingTile.cpp b/source/world/entity/FallingTile.cpp index 602d84bd1..b9b786571 100644 --- a/source/world/entity/FallingTile.cpp +++ b/source/world/entity/FallingTile.cpp @@ -8,11 +8,12 @@ #include "FallingTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "nbt/CompoundTag.hpp" #define DATA_TILE_ID (20) -void FallingTile::_init(Level*, const Vec3& pos, int id) +void FallingTile::_init(const Vec3& pos, int id) { m_renderType = RENDER_FALLING_TILE; m_pDescriptor = &EntityTypeDescriptor::fallingTile; @@ -30,14 +31,14 @@ void FallingTile::_init(Level*, const Vec3& pos, int id) m_vel = Vec3::ZERO; } -FallingTile::FallingTile(Level* level) : Entity(level) +FallingTile::FallingTile(TileSource& source) : Entity(source) { - _init(level, Vec3::ZERO, TILE_AIR); + _init(Vec3::ZERO, TILE_AIR); } -FallingTile::FallingTile(Level* level, const Vec3& pos, int id) : Entity(level) +FallingTile::FallingTile(TileSource& source, const Vec3& pos, int id) : Entity(source) { - _init(level, pos, id); + _init(pos, id); } void FallingTile::_defineEntityData() @@ -72,12 +73,12 @@ void FallingTile::tick() // if we're inside one of our own tiles, clear it. // Assumes we started there - if (m_pLevel->getTile(tilePos) == getTile()) - m_pLevel->setTile(tilePos, TILE_AIR); + if (m_tileSource->getTile(tilePos) == getTile()) + m_tileSource->setTile(tilePos, TILE_AIR); if (!m_bOnGround) { - if (m_time > 100 && !m_pLevel->m_bIsClientSide) + if (m_time > 100 && !m_tileSource->getLevelConst().m_bIsClientSide) { spawnAtLocation(getTile(), 1); remove(); @@ -90,9 +91,7 @@ void FallingTile::tick() m_vel.z *= 0.7f; m_vel.y *= -0.5f; remove(); - if (m_pLevel->mayPlace(getTile(), tilePos, true)) - m_pLevel->setTile(tilePos, getTile()); - else + if (!Tile::tiles[getTile()]->tryToPlace(m_tileSource, tilePos, 0)) spawnAtLocation(getTile(), 1); } diff --git a/source/world/entity/FallingTile.hpp b/source/world/entity/FallingTile.hpp index 620e02756..62ba9c233 100644 --- a/source/world/entity/FallingTile.hpp +++ b/source/world/entity/FallingTile.hpp @@ -13,11 +13,11 @@ class FallingTile : public Entity { private: - void _init(Level*, const Vec3& pos, int id); + void _init(const Vec3& pos, int id); public: - FallingTile(Level*); - FallingTile(Level*, const Vec3& pos, int id); + FallingTile(TileSource& source); + FallingTile(TileSource& source, const Vec3& pos, int id); private: void _defineEntityData(); @@ -31,7 +31,6 @@ class FallingTile : public Entity int getTile() const; void setTile(int id); - Level* getLevel() { return m_pLevel; } public: int m_time; diff --git a/source/world/entity/ItemEntity.cpp b/source/world/entity/ItemEntity.cpp index cdbbfe312..2a85d5206 100644 --- a/source/world/entity/ItemEntity.cpp +++ b/source/world/entity/ItemEntity.cpp @@ -8,6 +8,7 @@ #include "ItemEntity.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "nbt/CompoundTag.hpp" void ItemEntity::_init(const ItemStack& itemStack) @@ -97,7 +98,7 @@ void ItemEntity::tick() m_oPos = m_pos; m_vel.y -= 0.04f; - if (m_pLevel->getMaterial(m_pos) == Material::lava) + if (m_tileSource->getMaterial(m_pos) == Material::lava) { // give it a small bounce upwards m_vel.y = 0.2f; @@ -114,7 +115,7 @@ void ItemEntity::tick() if (m_bOnGround) { dragFactor = 0.588f; - TileID tile = m_pLevel->getTile(TilePos(Mth::floor(m_pos.x), Mth::floor(m_hitbox.min.y) - 1, Mth::floor(m_pos.z))); + TileID tile = m_tileSource->getTile(TilePos(Mth::floor(m_pos.x), Mth::floor(m_hitbox.min.y) - 1, Mth::floor(m_pos.z))); if (tile > 0) dragFactor = Tile::tiles[tile]->m_friction * 0.98f; } @@ -161,15 +162,15 @@ void ItemEntity::checkInTile(const Vec3& pos) { TilePos flPos = pos; - if (!Tile::solid[m_pLevel->getTile(pos)]) + if (!Tile::solid[m_tileSource->getTile(pos)]) return; - bool solidXN = Tile::solid[m_pLevel->getTile(flPos.west())]; - bool solidXP = Tile::solid[m_pLevel->getTile(flPos.east())]; - bool solidYN = Tile::solid[m_pLevel->getTile(flPos.below())]; - bool solidYP = Tile::solid[m_pLevel->getTile(flPos.above())]; - bool solidZN = Tile::solid[m_pLevel->getTile(flPos.north())]; - bool solidZP = Tile::solid[m_pLevel->getTile(flPos.south())]; + bool solidXN = Tile::solid[m_tileSource->getTile(flPos.west())]; + bool solidXP = Tile::solid[m_tileSource->getTile(flPos.east())]; + bool solidYN = Tile::solid[m_tileSource->getTile(flPos.below())]; + bool solidYP = Tile::solid[m_tileSource->getTile(flPos.above())]; + bool solidZN = Tile::solid[m_tileSource->getTile(flPos.north())]; + bool solidZP = Tile::solid[m_tileSource->getTile(flPos.south())]; float mindist = 9999.0f; int mindir = -1; diff --git a/source/world/entity/ItemEntity.hpp b/source/world/entity/ItemEntity.hpp index 061ab2517..d270414a1 100644 --- a/source/world/entity/ItemEntity.hpp +++ b/source/world/entity/ItemEntity.hpp @@ -16,8 +16,8 @@ class ItemEntity : public Entity void _init(const ItemStack& itemStack = ItemStack::EMPTY); void _init(const ItemStack& itemStack, const Vec3& pos); public: - ItemEntity(Level* level) : Entity(level) { _init(); } - ItemEntity(Level* level, const Vec3& pos, const ItemStack& itemStack) : Entity(level) { _init(itemStack, pos); } + ItemEntity(TileSource& source) : Entity(source) { _init(); } + ItemEntity(TileSource& source, const Vec3& pos, const ItemStack& itemStack) : Entity(source) { _init(itemStack, pos); } ~ItemEntity(); void burn(int damage) override; diff --git a/source/world/entity/Mob.cpp b/source/world/entity/Mob.cpp index b09886270..956ea847f 100644 --- a/source/world/entity/Mob.cpp +++ b/source/world/entity/Mob.cpp @@ -12,6 +12,7 @@ #include "network/RakNetInstance.hpp" #include "network/packets/MoveEntityPacket_PosRot.hpp" #include "network/packets/SetEntityMotionPacket.hpp" +#include "world/level/TileSource.hpp" void Mob::_init() { @@ -58,16 +59,11 @@ void Mob::_init() m_bSwinging = false; m_swingTime = 0; m_ambientSoundTime = 0; -} - -Mob::Mob(Level* pLevel) : Entity(pLevel) -{ - _init(); m_texture = "/mob/pig.png"; m_class = ""; - m_bBlocksBuilding = true; + m_bBlocksBuilding = true; m_rotA = (Mth::random() + 1.0f) * 0.01f; setPos(m_pos); @@ -76,6 +72,16 @@ Mob::Mob(Level* pLevel) : Entity(pLevel) m_footSize = 0.5f; } +Mob::Mob(TileSource& source) : Entity(source) +{ + _init(); +} + +Mob::Mob(Level& level) : Entity(level) +{ + _init(); +} + Mob::~Mob() { } @@ -463,7 +469,7 @@ void Mob::causeFallDamage(float level) hurt(nullptr, x); - TileID tileId = m_pLevel->getTile(TilePos(m_pos.x, m_pos.y - 0.2f - m_heightOffset, m_pos.z)); + TileID tileId = m_tileSource->getTile(TilePos(m_pos.x, m_pos.y - 0.2f - m_heightOffset, m_pos.z)); if (tileId > 0) { const Tile::SoundType* pSound = Tile::tiles[tileId]->m_pSound; @@ -533,14 +539,14 @@ void Mob::knockback(Entity* pEnt, int a, float x, float z) bool Mob::onLadder() const { #ifdef ENH_NEW_LADDER_BEHAVIOR - return m_pLevel->getTile(TilePos(m_pos.x, m_hitbox.min.y, m_pos.z)) == Tile::ladder->m_ID; + return m_tileSource->getTile(TilePos(m_pos.x, m_hitbox.min.y, m_pos.z)) == Tile::ladder->m_ID; #else TilePos tilePos = TilePos(m_pos.x, m_hitbox.min.y, m_pos.z); //@INFO: Pre Beta 1.5 stair behaviour return - m_pLevel->getTile(tilePos) == Tile::ladder->m_ID || - m_pLevel->getTile(tilePos.above()) == Tile::ladder->m_ID; + m_tileSource->getTile(tilePos) == Tile::ladder->m_ID || + m_tileSource->getTile(tilePos.above()) == Tile::ladder->m_ID; #endif } @@ -583,11 +589,13 @@ void Mob::heal(int health) HitResult Mob::pick(float f1, float f2) { - Vec3 pos = getPos(f2); + Vec3 pos = getInterpolatedPosition(f2); Vec3 view = getViewVector(f2); Vec3 limit = pos + view * f1; - return m_pLevel->clip(pos, limit); + + HitResult result = m_tileSource->clip(pos, limit); + return result; } void Mob::travel(const Vec2& pos) @@ -619,7 +627,7 @@ void Mob::travel(const Vec2& pos) else { float _x1; - TileID tile = m_pLevel->getTile(TilePos(m_pos.x, m_hitbox.min.y - 1, m_pos.z)); + TileID tile = m_tileSource->getTile(TilePos(m_pos.x, m_hitbox.min.y - 1, m_pos.z)); if (tile <= 0) _x1 = 0.546f; else @@ -639,7 +647,7 @@ void Mob::travel(const Vec2& pos) else { - TileID tile = m_pLevel->getTile(TilePos(m_pos.x, m_hitbox.min.y - 1, m_pos.z)); + TileID tile = m_tileSource->getTile(TilePos(m_pos.x, m_hitbox.min.y - 1, m_pos.z)); if (tile <= 0) dragFactor = 0.546f; else @@ -707,7 +715,8 @@ bool Mob::canSee(Entity* pEnt) const Vec3 v2 = pEnt->m_pos; v2.y += pEnt->getHeadHeight(); - return m_pLevel->clip(v1, v2).m_hitType == HitResult::NONE; + HitResult result = m_tileSource->clip(v1, v2); + return result.m_hitType == HitResult::NONE; } void Mob::updateWalkAnim() @@ -755,8 +764,8 @@ void Mob::aiStep() AABB aabb = m_hitbox; aabb.grow(0.2f, 0.2f, 0.2f); - EntityVector ents = m_pLevel->getEntities(this, aabb); - for (EntityVector::iterator it = ents.begin(); it != ents.end(); it++) + const std::vector& ents = m_tileSource->getEntities(this, aabb); + for (std::vector::const_iterator it = ents.begin(); it != ents.end(); it++) { Entity* pEnt = *it; if (pEnt->isPushable()) @@ -790,7 +799,7 @@ void Mob::lookAt(Entity* pEnt, float a3, float a4) bool Mob::canSpawn() { - return m_pLevel->getCubes(this, m_hitbox)->empty(); + return m_tileSource->fetchAABBs(m_hitbox, true).empty(); } float Mob::getAttackAnim(float f) const diff --git a/source/world/entity/Mob.hpp b/source/world/entity/Mob.hpp index ef91d1366..3b4a4b73b 100644 --- a/source/world/entity/Mob.hpp +++ b/source/world/entity/Mob.hpp @@ -16,7 +16,8 @@ class Mob : public Entity void _init(); public: - Mob(Level* pLevel); + Mob(TileSource& source); + Mob(Level& level); virtual ~Mob(); protected: diff --git a/source/world/entity/MobFactory.cpp b/source/world/entity/MobFactory.cpp index ec6e12518..1d80713e8 100644 --- a/source/world/entity/MobFactory.cpp +++ b/source/world/entity/MobFactory.cpp @@ -22,7 +22,7 @@ ENT(SPIDER, Spider) \ //ENT(PIG_ZOMBIE, PigZombie) -#define ENT(enumType, classType) case EntityType::enumType: return new classType(level); +#define ENT(enumType, classType) case EntityType::enumType: return new classType(source); // format: ID, spawnrate std::map monsterList; @@ -31,7 +31,7 @@ std::map waterCreatureList; std::map nullCreatureList; std::map*> mobListsByCategory; -Mob* MobFactory::CreateMob(EntityType::ID entityType, Level *level) +Mob* MobFactory::CreateMob(EntityType::ID entityType, TileSource& source) { switch (entityType) { diff --git a/source/world/entity/MobFactory.hpp b/source/world/entity/MobFactory.hpp index 037898e68..529d37654 100644 --- a/source/world/entity/MobFactory.hpp +++ b/source/world/entity/MobFactory.hpp @@ -9,6 +9,6 @@ class MobFactory { public: static void initMobLists(); - static Mob* CreateMob(EntityType::ID entityType, Level *level); + static Mob* CreateMob(EntityType::ID entityType, TileSource& source); static const std::map& GetMobListOfCategory(const EntityCategories& category); }; diff --git a/source/world/entity/MobSpawner.cpp b/source/world/entity/MobSpawner.cpp index 2344b5dde..5ddddd31b 100644 --- a/source/world/entity/MobSpawner.cpp +++ b/source/world/entity/MobSpawner.cpp @@ -1,17 +1,18 @@ #include "world/entity/MobSpawner.hpp" #include "world/entity/MobFactory.hpp" +#include "world/level/TileSource.hpp" #define MOB_SPAWNER_HOSTILE_BRIGHTNESS 7 #define MOB_SPAWNER_FRIENDLY_BRIGHTNESS 9 -void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) +void MobSpawner::tick(TileSource& source, bool allowHostile, bool allowFriendly) { if (!allowHostile && !allowFriendly) return; chunksToPoll.clear(); - for (std::vector::const_iterator it = level.m_players.begin(); it != level.m_players.end(); ++it) + for (std::vector::const_iterator it = source.getLevelConst().m_players.begin(); it != source.getLevelConst().m_players.end(); ++it) { const Player* player = *it; int cx = Mth::floor(player->m_pos.x / 16.0f); @@ -26,6 +27,8 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) } } + Level& level = source.getLevel(); + for (unsigned int i = 0; i < MobCategory::allCount; i++) { const MobCategory& category = *MobCategory::all[i]; @@ -33,15 +36,15 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) bool isFriendly = category.isFriendly(); // good mobs don't spawn after dark, otherwise they will crowd around torches like beta - if (!level.isDay() && isFriendly) + if (!source.getDimensionConst().isDay() && isFriendly) continue; if ((isFriendly && !allowFriendly) || (!isFriendly && !allowHostile)) continue; - // maximum of this mob type - if (level.getEntityCount(baseType) > static_cast(category.getMaxInstancesPerChunk() * static_cast(chunksToPoll.size()) / 256)) - continue; + // TODO + //if (level.getEntityCount(baseType) > static_cast(category.getMaxInstancesPerChunk() * static_cast(chunksToPoll.size()) / 256)) + // continue; for (std::set::iterator it = chunksToPoll.begin(); it != chunksToPoll.end(); ++it) { @@ -71,9 +74,9 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) } } - TilePos tpos = getRandomPosWithin(level, pos.x * 16, pos.z * 16); + TilePos tpos = getRandomPosWithin(source, pos.x * 16, pos.z * 16); - if (level.isSolidTile(tpos) || level.getMaterial(tpos) != category.getSpawnPositionMaterial()) + if (source.isSolidBlockingTile(tpos) || source.getMaterial(tpos) != category.getSpawnPositionMaterial()) continue; int spawned = 0; @@ -90,10 +93,10 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) tp.y += level.m_random.nextInt(1) - level.m_random.nextInt(1); tp.z += level.m_random.nextInt(6) - level.m_random.nextInt(6); - if (!IsSpawnPositionOk(category, level, tp)) + if (!IsSpawnPositionOk(category, source, tp)) continue; - int lightLevel = level.getRawBrightness(tp); + Brightness_t lightLevel = source.getRawBrightness(tp); if (isFriendly) { if (lightLevel < MOB_SPAWNER_FRIENDLY_BRIGHTNESS) @@ -115,7 +118,7 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) if (dPos.lengthSqr() < 576.0f) continue; - Mob* entity = MobFactory::CreateMob(entityID, &level); + Mob* entity = MobFactory::CreateMob(entityID, source); if (!entity) break; @@ -125,7 +128,7 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) { ++spawned; level.addEntity(entity); - FinalizeMobSettings(entity, level, pPos); + FinalizeMobSettings(entity, source, pPos); if (spawned >= entity->getMaxSpawnClusterSize()) { spawned = -1; @@ -138,15 +141,15 @@ void MobSpawner::tick(Level& level, bool allowHostile, bool allowFriendly) } } -TilePos MobSpawner::getRandomPosWithin(Level& level, int chunkX, int chunkZ) +TilePos MobSpawner::getRandomPosWithin(TileSource& source, int chunkX, int chunkZ) { - int px = level.m_random.nextInt(16) + chunkX; - int py = level.m_random.nextInt(128); - int pz = level.m_random.nextInt(16) + chunkZ; + int px = source.getLevel().m_random.nextInt(16) + chunkX; + int py = source.getLevel().m_random.nextInt(128); + int pz = source.getLevel().m_random.nextInt(16) + chunkZ; return TilePos(px, py, pz); } -bool MobSpawner::AddMob(Level& level, Mob *mob, const Vec3& pos, const Vec2& rot) +bool MobSpawner::AddMob(TileSource& source, Mob *mob, const Vec3& pos, const Vec2& rot) { if (!mob) return false; @@ -155,33 +158,33 @@ bool MobSpawner::AddMob(Level& level, Mob *mob, const Vec3& pos, const Vec2& rot return false; mob->moveTo(pos, rot); - level.addEntity(mob); - FinalizeMobSettings(mob, level, pos); + source.getLevel().addEntity(mob); + FinalizeMobSettings(mob, source, pos); return true; } -bool MobSpawner::IsSpawnPositionOk(const MobCategory& category, Level& level, const TilePos& pos) +bool MobSpawner::IsSpawnPositionOk(const MobCategory& category, TileSource& source, const TilePos& pos) { if (category.getSpawnPositionMaterial() == Material::water) - return level.getMaterial(pos)->isLiquid() && !level.isSolidTile(pos.above()); + return source.getMaterial(pos)->isLiquid() && !source.isSolidBlockingTile(pos.above()); - return level.isSolidTile(pos.below()) && !level.isSolidTile(pos) && !level.getMaterial(pos)->isLiquid() && !level.isSolidTile(pos.above()); + return source.isSolidBlockingTile(pos.below()) && !source.isSolidBlockingTile(pos) && !source.getMaterial(pos)->isLiquid() && !source.isSolidBlockingTile(pos.above()); } -void MobSpawner::FinalizeMobSettings(Mob *mob, Level& level, const Vec3& pos) +void MobSpawner::FinalizeMobSettings(Mob *mob, TileSource& source, const Vec3& pos) { if (!mob) return; //mob->finalizeMobSpawn(); - MakeBabyMob(mob, level); + MakeBabyMob(mob, source); } -void MobSpawner::MakeBabyMob(Mob *mob, Level& level) +void MobSpawner::MakeBabyMob(Mob *mob, TileSource& source) { - level.m_random.setSeed(0x5deea8f); + source.getLevel().m_random.setSeed(0x5deea8f); if (mob->isBaby()) return; @@ -190,7 +193,7 @@ void MobSpawner::MakeBabyMob(Mob *mob, Level& level) } -void MobSpawner::PostProcessSpawnMobs(Level& level, Biome& biome, const Vec3& pos) +void MobSpawner::PostProcessSpawnMobs(TileSource& source, Biome& biome, const Vec3& pos) { // empty (0.7.1) } \ No newline at end of file diff --git a/source/world/entity/MobSpawner.hpp b/source/world/entity/MobSpawner.hpp index fd29acaf3..c5c64a056 100644 --- a/source/world/entity/MobSpawner.hpp +++ b/source/world/entity/MobSpawner.hpp @@ -9,21 +9,22 @@ #include "world/level/levelgen/chunk/LevelChunk.hpp" #include "world/level/levelgen/chunk/ChunkSource.hpp" #include "world/level/storage/LevelStorageSource.hpp" -#include "world/level/storage/LevelSource.hpp" #include "world/level/storage/LevelData.hpp" #include "world/level/path/PathFinder.hpp" +class Biome; + class MobSpawner { private: - static bool IsSpawnPositionOk(const MobCategory& category, Level& level, const TilePos& pos); - static void FinalizeMobSettings(Mob* mob, Level& level, const Vec3& pos); - static void MakeBabyMob(Mob* mob, Level& level); - static void PostProcessSpawnMobs(Level& level, Biome& biome, const Vec3& pos); - static bool AddMob(Level& level, Mob* mob, const Vec3& pos, const Vec2& rot = Vec2::ZERO); + static bool IsSpawnPositionOk(const MobCategory& category, TileSource& source, const TilePos& pos); + static void FinalizeMobSettings(Mob* mob, TileSource& source, const Vec3& pos); + static void MakeBabyMob(Mob* mob, TileSource& source); + static void PostProcessSpawnMobs(TileSource& source, Biome& biome, const Vec3& pos); + static bool AddMob(TileSource& source, Mob* mob, const Vec3& pos, const Vec2& rot = Vec2::ZERO); public: - TilePos getRandomPosWithin(Level& level, int chunkX, int chunkZ); - void tick(Level& level, bool allowHostile, bool allowFriendly); + TilePos getRandomPosWithin(TileSource& source, int chunkX, int chunkZ); + void tick(TileSource& source, bool allowHostile, bool allowFriendly); private: std::set chunksToPoll; diff --git a/source/world/entity/MobSpawnerData.hpp b/source/world/entity/MobSpawnerData.hpp new file mode 100644 index 000000000..525f7c06c --- /dev/null +++ b/source/world/entity/MobSpawnerData.hpp @@ -0,0 +1,6 @@ +#pragma once + +class MobSpawnerData +{ + // TODO +}; diff --git a/source/world/entity/Monster.cpp b/source/world/entity/Monster.cpp index 5df63f72a..7aa479097 100644 --- a/source/world/entity/Monster.cpp +++ b/source/world/entity/Monster.cpp @@ -1,6 +1,7 @@ #include "world/entity/Monster.hpp" +#include "world/level/TileSource.hpp" -Monster::Monster(Level* pLevel) : PathfinderMob(pLevel) +Monster::Monster(TileSource& source) : PathfinderMob(source) { m_health = 20; m_attackDamage = 2; @@ -66,7 +67,7 @@ void Monster::checkHurtTarget(Entity* pEnt, float f) float Monster::getWalkTargetValue(const TilePos& pos) const { - float brightness = m_pLevel->getBrightness(pos); + float brightness = m_tileSource->getBrightness(pos); return 0.5f - brightness; } @@ -75,11 +76,11 @@ bool Monster::canSpawn() { TilePos pos(m_pos.x, m_hitbox.min.y, m_pos.z); - if (m_pLevel->getBrightness(LightLayer::Sky, pos) > m_random.nextInt(30)) + if (m_tileSource->getBrightness(LightLayer::Sky, pos) > m_random.nextInt(30)) { return false; } - else if (m_pLevel->getBrightness(pos) <= m_random.nextInt(8)) + else if (m_tileSource->getBrightness(pos) <= m_random.nextInt(8)) { return PathfinderMob::canSpawn(); } diff --git a/source/world/entity/Monster.hpp b/source/world/entity/Monster.hpp index 2502c3e48..c09d8740a 100644 --- a/source/world/entity/Monster.hpp +++ b/source/world/entity/Monster.hpp @@ -6,7 +6,7 @@ class Monster : public PathfinderMob { public: - Monster(Level* pLevel); + Monster(TileSource& source); void aiStep() override; void tick() override; diff --git a/source/world/entity/PathfinderMob.cpp b/source/world/entity/PathfinderMob.cpp index 94a3eec11..bb07356c8 100644 --- a/source/world/entity/PathfinderMob.cpp +++ b/source/world/entity/PathfinderMob.cpp @@ -10,7 +10,7 @@ #define MAX_TURN (30.0f) -PathfinderMob::PathfinderMob(Level* pLevel) : Mob(pLevel) +PathfinderMob::PathfinderMob(TileSource& source) : Mob(source) { m_pAttackTarget = nullptr; m_bHoldGround = false; diff --git a/source/world/entity/PathfinderMob.hpp b/source/world/entity/PathfinderMob.hpp index 33b8d7b96..70975afb4 100644 --- a/source/world/entity/PathfinderMob.hpp +++ b/source/world/entity/PathfinderMob.hpp @@ -13,7 +13,7 @@ class PathfinderMob : public Mob { public: - PathfinderMob(Level* pLevel); + PathfinderMob(TileSource& source); virtual Entity* getAttackTarget(); virtual void setAttackTarget(Entity*); diff --git a/source/world/entity/Pig.cpp b/source/world/entity/Pig.cpp index 153163f49..d48616c31 100644 --- a/source/world/entity/Pig.cpp +++ b/source/world/entity/Pig.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "Pig.hpp" -Pig::Pig(Level* pLevel) : Animal(pLevel) +Pig::Pig(TileSource& source) : Animal(source) { m_pDescriptor = &EntityTypeDescriptor::pig; m_renderType = RENDER_PIG; diff --git a/source/world/entity/Pig.hpp b/source/world/entity/Pig.hpp index c617da1a6..262ccbdfd 100644 --- a/source/world/entity/Pig.hpp +++ b/source/world/entity/Pig.hpp @@ -12,7 +12,7 @@ class Pig : public Animal { public: - Pig(Level* pLevel); + Pig(TileSource& source); public: std::string getAmbientSound() const override { return "mob.pig"; }; @@ -24,5 +24,5 @@ class Pig : public Animal bool hasSaddle() const { return false; } void setSaddle(bool b); - Entity* getBreedOffspring(Animal* pOther) { return new Pig(m_pLevel); } + Entity* getBreedOffspring(Animal* pOther) { return new Pig(*m_tileSource); } }; diff --git a/source/world/entity/Player.cpp b/source/world/entity/Player.cpp index 7f689513d..a79c35c79 100644 --- a/source/world/entity/Player.cpp +++ b/source/world/entity/Player.cpp @@ -18,7 +18,7 @@ void Player::_init() m_oBob = 0.0f; m_bob = 0.0f; m_dmgSpill = 0; - m_dimension = 0; + m_dimension = DIMENSION_OVERWORLD; m_bFlying = false; m_jumpTriggerTime = 0; m_destroyingBlock = false; @@ -27,7 +27,7 @@ void Player::_init() m_abilities.bInvulnerable = false; } -Player::Player(Level* pLevel, GameType playerGameType) : Mob(pLevel) +Player::Player(Level& level, GameType playerGameType) : Mob(level) { _init(); m_pDescriptor = &EntityTypeDescriptor::player; @@ -233,9 +233,10 @@ void Player::aiStep() AABB scanAABB = m_hitbox; scanAABB.grow(1, 1, 1); - EntityVector ents = m_pLevel->getEntities(this, scanAABB); + std::vector ents; + m_pLevel->getEntities(this->getDimensionId(), this->getDescriptor().getEntityType(), scanAABB, ents); - for (EntityVector::iterator it = ents.begin(); it != ents.end(); it++) + for (std::vector::iterator it = ents.begin(); it != ents.end(); it++) { Entity* pEnt = *it; if (pEnt->m_bRemoved) @@ -317,7 +318,7 @@ void Player::readAdditionalSaveData(const CompoundTag& tag) if (tag.contains("Inventory")) m_pInventory->load(*tag.getList("Inventory")); - m_dimension = tag.getInt32("Dimension"); + m_dimension = (DimensionId)tag.getInt32("Dimension"); //m_sleepTimer = tag.getInt32("SleepTimer"); if (tag.contains("SpawnX") && tag.contains("SpawnY") && tag.contains("SpawnZ")) { @@ -528,7 +529,7 @@ void Player::drop(const ItemStack& item, bool randomly) if (item.isEmpty()) return; - ItemEntity* pItemEntity = new ItemEntity(m_pLevel, Vec3(m_pos.x, m_pos.y - 0.3f + getHeadHeight(), m_pos.z), item); + ItemEntity* pItemEntity = new ItemEntity(*m_tileSource, Vec3(m_pos.x, m_pos.y - 0.3f + getHeadHeight(), m_pos.z), item); pItemEntity->m_throwTime = 40; if (randomly) diff --git a/source/world/entity/Player.hpp b/source/world/entity/Player.hpp index c75ff8831..2c8ddaaa5 100644 --- a/source/world/entity/Player.hpp +++ b/source/world/entity/Player.hpp @@ -18,6 +18,7 @@ #define C_PLAYER_FLAG_USING_ITEM (4) class Inventory; // in case we're included from Inventory.hpp +class Dimension; class Player : public Mob { @@ -35,7 +36,7 @@ class Player : public Mob void _init(); public: - Player(Level* pLevel, GameType gameType); + Player(Level& level, GameType gameType); virtual ~Player(); protected: @@ -132,7 +133,7 @@ class Player : public Mob float m_bob; int m_dmgSpill; std::string m_name; - int m_dimension; + DimensionId m_dimension; RakNet::RakNetGUID m_guid; bool m_bFlying; TilePos m_respawnPos; diff --git a/source/world/entity/PrimedTnt.cpp b/source/world/entity/PrimedTnt.cpp index b75c4fa85..51987410d 100644 --- a/source/world/entity/PrimedTnt.cpp +++ b/source/world/entity/PrimedTnt.cpp @@ -22,7 +22,7 @@ void PrimedTnt::_init() m_bMakeStepSound = false; } -PrimedTnt::PrimedTnt(Level* level, const Vec3& pos) : Entity(level) +PrimedTnt::PrimedTnt(TileSource& source, const Vec3& pos) : Entity(source) { _init(); setPos(pos); diff --git a/source/world/entity/PrimedTnt.hpp b/source/world/entity/PrimedTnt.hpp index 7a84a8faa..dc2c11a7f 100644 --- a/source/world/entity/PrimedTnt.hpp +++ b/source/world/entity/PrimedTnt.hpp @@ -15,8 +15,8 @@ class PrimedTnt : public Entity private: void _init(); public: - PrimedTnt(Level* level) : Entity(level) { _init(); } - PrimedTnt(Level* level, const Vec3& pos); + PrimedTnt(TileSource& source) : Entity(source) { _init(); } + PrimedTnt(TileSource& source, const Vec3& pos); public: float getShadowHeightOffs() const override; diff --git a/source/world/entity/Rocket.cpp b/source/world/entity/Rocket.cpp index f1a321fe1..fce52c53a 100644 --- a/source/world/entity/Rocket.cpp +++ b/source/world/entity/Rocket.cpp @@ -10,7 +10,7 @@ #include "Player.hpp" #include "world/level/Level.hpp" -Rocket::Rocket(Level* level, const Vec3& pos) : Entity(level) +Rocket::Rocket(TileSource& source, const Vec3& pos) : Entity(source) { m_lifetime = 80; m_renderType = RENDER_ROCKET; diff --git a/source/world/entity/Rocket.hpp b/source/world/entity/Rocket.hpp index 1cef87bcb..f9273ede0 100644 --- a/source/world/entity/Rocket.hpp +++ b/source/world/entity/Rocket.hpp @@ -16,7 +16,7 @@ class Player; class Rocket : public Entity { public: - Rocket(Level*, const Vec3& pos); + Rocket(TileSource& source, const Vec3& pos); public: float getShadowHeightOffs() const override; diff --git a/source/world/entity/Sheep.cpp b/source/world/entity/Sheep.cpp index 43a13bd9e..adac8b8ec 100644 --- a/source/world/entity/Sheep.cpp +++ b/source/world/entity/Sheep.cpp @@ -25,7 +25,7 @@ const Color Sheep::COLOR[] = { const unsigned int Sheep::COLOR_COUNT = sizeof(Sheep::COLOR) / (sizeof(float) * 3); -Sheep::Sheep(Level* pLevel) : Animal(pLevel) +Sheep::Sheep(TileSource& source) : Animal(source) { m_pDescriptor = &EntityTypeDescriptor::sheep; m_renderType = RENDER_SHEEP; diff --git a/source/world/entity/Sheep.hpp b/source/world/entity/Sheep.hpp index d36cfa66a..fe5d50510 100644 --- a/source/world/entity/Sheep.hpp +++ b/source/world/entity/Sheep.hpp @@ -10,7 +10,7 @@ class Sheep : public Animal static const unsigned int COLOR_COUNT; // NumColors on PE, stupid name public: - Sheep(Level* pLevel); + Sheep(TileSource& source); private: void _defineEntityData(); @@ -23,7 +23,7 @@ class Sheep : public Animal void addAdditionalSaveData(CompoundTag& tag) const override; void readAdditionalSaveData(const CompoundTag& tag) override; - Entity* getBreedOffspring(Animal* pOther) { return new Sheep(m_pLevel); } + Entity* getBreedOffspring(Animal* pOther) { return new Sheep(*m_tileSource); } int getColor() const; void setColor(int); diff --git a/source/world/entity/Skeleton.cpp b/source/world/entity/Skeleton.cpp index 84ce64d2d..9c56b0815 100644 --- a/source/world/entity/Skeleton.cpp +++ b/source/world/entity/Skeleton.cpp @@ -1,6 +1,7 @@ #include "Skeleton.hpp" +#include "world/level/TileSource.hpp" -Skeleton::Skeleton(Level* pLevel) : Monster(pLevel) +Skeleton::Skeleton(TileSource& source) : Monster(source) { m_pDescriptor = &EntityTypeDescriptor::skeleton; m_renderType = RENDER_SKELETON; @@ -9,11 +10,11 @@ Skeleton::Skeleton(Level* pLevel) : Monster(pLevel) void Skeleton::aiStep() { - if (m_pLevel->isDay()) + if (m_tileSource->getDimensionConst().isDay()) { float brightness = getBrightness(1.0f); if (brightness > 0.5f - && m_pLevel->canSeeSky(this->m_pos) + && m_tileSource->canSeeSky(this->m_pos) && m_random.nextFloat() * 30.0f < (brightness - 0.4f) * 2.0f) { this->m_fireTicks = 300; @@ -31,7 +32,7 @@ void Skeleton::checkHurtTarget(Entity* ent, float f) float delta_z = ent->m_pos.z - m_pos.z; if (m_attackTime == 0) { - Arrow* arrow = new Arrow(m_pLevel, this); + Arrow* arrow = new Arrow(*this); arrow->m_pos.y += 1; float var8 = ent->m_pos.y - 0.2f - arrow->m_pos.y; float var10 = Mth::sqrt(delta_x * delta_x + delta_z * delta_z) * 0.2f; diff --git a/source/world/entity/Skeleton.hpp b/source/world/entity/Skeleton.hpp index a4fc548c4..d7546ab30 100644 --- a/source/world/entity/Skeleton.hpp +++ b/source/world/entity/Skeleton.hpp @@ -9,7 +9,7 @@ class Skeleton : public Monster static ItemStack bow; public: - Skeleton(Level* pLevel); + Skeleton(TileSource& source); public: std::string getAmbientSound() const override { return "mob.skeleton"; } diff --git a/source/world/entity/Spider.cpp b/source/world/entity/Spider.cpp index ea5e492e1..427c1125f 100644 --- a/source/world/entity/Spider.cpp +++ b/source/world/entity/Spider.cpp @@ -1,6 +1,6 @@ #include "Spider.hpp" -Spider::Spider(Level* pLevel) : Monster(pLevel) +Spider::Spider(TileSource& source) : Monster(source) { m_pDescriptor = &EntityTypeDescriptor::spider; m_renderType = RENDER_SPIDER; diff --git a/source/world/entity/Spider.hpp b/source/world/entity/Spider.hpp index 4ecc268ee..ae47f1490 100644 --- a/source/world/entity/Spider.hpp +++ b/source/world/entity/Spider.hpp @@ -5,7 +5,7 @@ class Spider : public Monster { public: - Spider(Level* pLevel); + Spider(TileSource& source); public: std::string getAmbientSound() const override { return "mob.spider"; } diff --git a/source/world/entity/TripodCamera.cpp b/source/world/entity/TripodCamera.cpp index 460bdfb9c..5eb6114b9 100644 --- a/source/world/entity/TripodCamera.cpp +++ b/source/world/entity/TripodCamera.cpp @@ -12,7 +12,7 @@ #define C_TIMER 80 -TripodCamera::TripodCamera(Level* level, Player* player, const Vec3& pos) : Mob(level) +TripodCamera::TripodCamera(TileSource& source, Player* player, const Vec3& pos) : Mob(source) { m_countdown = C_TIMER; m_bActivated = false; diff --git a/source/world/entity/TripodCamera.hpp b/source/world/entity/TripodCamera.hpp index cdf8ade07..bf1cb02f2 100644 --- a/source/world/entity/TripodCamera.hpp +++ b/source/world/entity/TripodCamera.hpp @@ -16,7 +16,7 @@ class Player; class TripodCamera : public Mob { public: - TripodCamera(Level*, Player*, const Vec3& pos); + TripodCamera(TileSource&, Player*, const Vec3& pos); float getShadowHeightOffs() const override { return 0.0f; } bool interact(Player* player) override; diff --git a/source/world/entity/Zombie.cpp b/source/world/entity/Zombie.cpp index 3021d8eda..cb61dc76e 100644 --- a/source/world/entity/Zombie.cpp +++ b/source/world/entity/Zombie.cpp @@ -1,6 +1,7 @@ #include "Zombie.hpp" +#include "world/level/TileSource.hpp" -Zombie::Zombie(Level* pLevel) : Monster(pLevel) +Zombie::Zombie(TileSource& source) : Monster(source) { m_pDescriptor = &EntityTypeDescriptor::zombie; m_renderType = RENDER_ZOMBIE; @@ -11,11 +12,11 @@ Zombie::Zombie(Level* pLevel) : Monster(pLevel) void Zombie::aiStep() { - if (m_pLevel->isDay()) + if (m_tileSource->getDimensionConst().isDay()) { float var1 = getBrightness(1.0f); if (var1 > 0.5f - && m_pLevel->canSeeSky(this->m_pos) + && m_tileSource->canSeeSky(this->m_pos) && m_random.nextFloat() * 30.0f < (var1 - 0.4f) * 2.0f) { this->m_fireTicks = 300; diff --git a/source/world/entity/Zombie.hpp b/source/world/entity/Zombie.hpp index f3c2c43b2..89e0ef71e 100644 --- a/source/world/entity/Zombie.hpp +++ b/source/world/entity/Zombie.hpp @@ -5,7 +5,7 @@ class Zombie : public Monster { public: - Zombie(Level* pLevel); + Zombie(TileSource& source); public: std::string getAmbientSound() const override { return "mob.zombie"; } diff --git a/source/world/gamemode/CreativeMode.cpp b/source/world/gamemode/CreativeMode.cpp index 5b3d62645..4a7113010 100644 --- a/source/world/gamemode/CreativeMode.cpp +++ b/source/world/gamemode/CreativeMode.cpp @@ -20,7 +20,7 @@ CreativeMode::CreativeMode(Minecraft* pMC, Level& level) : GameMode(pMC, level), bool CreativeMode::destroyBlock(Player* player, const TilePos& pos, Facing::Name face) { - _level.extinguishFire(player, pos, face); + _level.extinguishFire(player->getTileSource(), pos, face); return GameMode::destroyBlock(player, pos, face); } diff --git a/source/world/gamemode/GameMode.cpp b/source/world/gamemode/GameMode.cpp index ebd400e05..4d95c462f 100644 --- a/source/world/gamemode/GameMode.cpp +++ b/source/world/gamemode/GameMode.cpp @@ -9,6 +9,7 @@ #include "GameMode.hpp" #include "client/app/Minecraft.hpp" #include "network/packets/RemoveBlockPacket.hpp" +#include "world/level/TileSource.hpp" GameMode::GameMode(Minecraft* pMinecraft, Level& level) : _level(level), @@ -33,15 +34,17 @@ bool GameMode::startDestroyBlock(Player* player, const TilePos& pos, Facing::Nam bool GameMode::destroyBlock(Player* player, const TilePos& pos, Facing::Name face) { - Tile* oldTile = Tile::tiles[_level.getTile(pos)]; + TileSource& source = player->getTileSource(); + + Tile* oldTile = Tile::tiles[source.getTile(pos)]; if (!oldTile) return false; - m_pMinecraft->m_pParticleEngine->destroyEffect(pos); + m_pMinecraft->m_pParticleEngine->destroyEffect(player, pos); - int tileData = _level.getData(pos); + TileData tileData = source.getData(pos); oldTile->playerWillDestroy(player, pos, face); - bool changed = _level.setTile(pos, TILE_AIR); + bool changed = source.setTile(pos, TILE_AIR); if (!changed) return false; @@ -49,7 +52,7 @@ bool GameMode::destroyBlock(Player* player, const TilePos& pos, Facing::Name fac _level.playSound(pos + 0.5f, "step." + oldTile->m_pSound->m_name, (oldTile->m_pSound->volume * 0.5f) + 0.5f, oldTile->m_pSound->pitch * 0.8f); - oldTile->destroy(&_level, pos, tileData); + oldTile->destroy(&source, pos, tileData); if (m_pMinecraft->isOnline()) { @@ -98,9 +101,9 @@ float GameMode::getEntityReachDistance() const return 5.0f; } -LocalPlayer* GameMode::createPlayer(Level* pLevel) +LocalPlayer* GameMode::createPlayer(Level& level) { - return new LocalPlayer(m_pMinecraft, pLevel, m_pMinecraft->m_pUser, pLevel->getDefaultGameType(), _level.m_pDimension->m_id); + return new LocalPlayer(m_pMinecraft, level, m_pMinecraft->m_pUser, level.getDefaultGameType(), level.getDimension(DIMENSION_OVERWORLD)->getId()); } void GameMode::initPlayer(Player* pPlayer) @@ -141,12 +144,13 @@ void GameMode::handleCloseInventory(int a, Player* player) } } -bool GameMode::useItem(Player* player, Level* level, ItemStack& item) +bool GameMode::useItem(Player* player, ItemStack& item) { + Level& level = player->getLevel(); int oldCount = item.m_count; - ItemStack* result = item.use(level, player); + ItemStack* result = item.use(player); - if (level->m_bIsClientSide) + if (level.m_bIsClientSide) { _level.m_pRakNetInstance->send(new UseItemPacket(TilePos::ZERO, 255, player->m_EntityID, item)); } @@ -157,27 +161,30 @@ bool GameMode::useItem(Player* player, Level* level, ItemStack& item) return true; } -bool GameMode::useItemOn(Player* player, Level* level, ItemStack& item, const TilePos& pos, Facing::Name face) +bool GameMode::useItemOn(Player* player, ItemStack& item, const TilePos& pos, Facing::Name face) { + Level& level = player->getLevel(); // Sending this packet regardless is intentional. PE does this, Java does this. - if (level->m_bIsClientSide) + if (level.m_bIsClientSide) { _level.m_pRakNetInstance->send(new UseItemPacket(pos, face, player->m_EntityID, item)); } - TileID tile = level->getTile(pos); + TileSource& source = player->getTileSource(); + + TileID tile = source.getTile(pos); if (tile == Tile::invisible_bedrock->m_ID) return false; bool success = false; - if (tile > 0 && Tile::tiles[tile]->use(level, pos, player)) + if (tile > 0 && Tile::tiles[tile]->use(pos, player)) { success = true; } else if (!item.isEmpty()) { - success = item.useOn(player, level, pos, face); + success = item.useOn(player, pos, face); } return success; diff --git a/source/world/gamemode/GameMode.hpp b/source/world/gamemode/GameMode.hpp index 8b0b58bcd..532215d0a 100644 --- a/source/world/gamemode/GameMode.hpp +++ b/source/world/gamemode/GameMode.hpp @@ -33,10 +33,10 @@ class GameMode // Used to be called getPickRange virtual float getBlockReachDistance() const; virtual float getEntityReachDistance() const; - virtual bool useItem(Player* player, Level* level, ItemStack& item); - virtual bool useItemOn(Player*, Level*, ItemStack&, const TilePos& pos, Facing::Name face); + virtual bool useItem(Player* player, ItemStack& item); + virtual bool useItemOn(Player*, ItemStack&, const TilePos& pos, Facing::Name face); virtual void releaseUsingItem(Player* player); - virtual LocalPlayer* createPlayer(Level*); + virtual LocalPlayer* createPlayer(Level&); virtual void initPlayer(Player*); virtual void adjustPlayer(Player*); virtual bool canHurtPlayer(); diff --git a/source/world/gamemode/SurvivalMode.cpp b/source/world/gamemode/SurvivalMode.cpp index e7040e001..77128362a 100644 --- a/source/world/gamemode/SurvivalMode.cpp +++ b/source/world/gamemode/SurvivalMode.cpp @@ -10,6 +10,7 @@ #include "GameMods.hpp" #include "client/app/Minecraft.hpp" #include "network/packets/RemoveBlockPacket.hpp" +#include "world/level/TileSource.hpp" SurvivalMode::SurvivalMode(Minecraft* pMC, Level& level) : GameMode(pMC, level), m_destroyingPos(-1, -1, -1), @@ -37,14 +38,16 @@ bool SurvivalMode::startDestroyBlock(Player* player, const TilePos& pos, Facing: if (!item.isEmpty() && item.getItem() == Item::bow) return true; - TileID tile = _level.getTile(pos); + TileSource& source = player->getTileSource(); + + TileID tile = source.getTile(pos); if (tile <= 0) return false; if (m_destroyProgress == 0.0f) { - Tile::tiles[tile]->attack(&_level, pos, player); + Tile::tiles[tile]->attack(&source, pos, player); } if (Tile::tiles[tile]->getDestroyProgress(player) >= 1.0f) @@ -57,8 +60,10 @@ bool SurvivalMode::startDestroyBlock(Player* player, const TilePos& pos, Facing: bool SurvivalMode::destroyBlock(Player* player, const TilePos& pos, Facing::Name face) { - TileID tile = _level.getTile(pos); - int data = _level.getData(pos); + TileSource& source = player->getTileSource(); + + TileID tile = source.getTile(pos); + int data = source.getData(pos); bool changed = GameMode::destroyBlock(player, pos, face); @@ -80,10 +85,10 @@ bool SurvivalMode::destroyBlock(Player* player, const TilePos& pos, Facing::Name ItemStack tileItem(tile, 1, data); if (tile == TILE_GRASS || !player->m_pInventory->hasUnlimitedResource(tileItem)) { - Tile::tiles[tile]->playerDestroy(&_level, player, pos, data); + Tile::tiles[tile]->playerDestroy(&source, player, pos, data); } #else - Tile::tiles[tile]->playerDestroy(&_level, player, pos, data); + Tile::tiles[tile]->playerDestroy(&source, player, pos, data); #endif } @@ -107,7 +112,9 @@ bool SurvivalMode::continueDestroyBlock(Player* player, const TilePos& pos, Faci return false; } - TileID tile = _level.getTile(m_destroyingPos); + TileSource& source = player->getTileSource(); + + TileID tile = source.getTile(m_destroyingPos); if (!tile) return false; @@ -162,20 +169,20 @@ void SurvivalMode::render(float f) } } -bool SurvivalMode::useItemOn(Player* player, Level* level, ItemStack& item, const TilePos& pos, Facing::Name face) +bool SurvivalMode::useItemOn(Player* player, ItemStack& item, const TilePos& pos, Facing::Name face) { #ifdef MOD_POCKET_SURVIVAL if (item.isEmpty()) - return GameMode::useItemOn(player, level, item, pos, face); + return GameMode::useItemOn(player, item, pos, face); bool unlimited = player->m_pInventory->hasUnlimitedResource(item); int oldCount = item.m_count; - bool result = GameMode::useItemOn(player, level, item, pos, face); + bool result = GameMode::useItemOn(player, item, pos, face); if (unlimited) item.m_count = oldCount; return result; #else - return GameMode::useItemOn(player, level, item, pos, face); + return GameMode::useItemOn(player, item, pos, face); #endif } diff --git a/source/world/gamemode/SurvivalMode.hpp b/source/world/gamemode/SurvivalMode.hpp index d0bb9c4c5..2a47c1b67 100644 --- a/source/world/gamemode/SurvivalMode.hpp +++ b/source/world/gamemode/SurvivalMode.hpp @@ -23,7 +23,7 @@ class SurvivalMode : public GameMode void render(float f) override; float getBlockReachDistance() const override { return 4.0f; } // 4.0f on Java, 5.0f until 0.10.0-0.12.1 float getEntityReachDistance() const override { return 3.0f; } - bool useItemOn(Player*, Level*, ItemStack&, const TilePos& pos, Facing::Name face) override; + bool useItemOn(Player*, ItemStack&, const TilePos& pos, Facing::Name face) override; bool isCreativeType() const override { return false; } bool isSurvivalType() const override { return true; } void initPlayer(Player*) override; diff --git a/source/world/inventory/CraftingMenu.cpp b/source/world/inventory/CraftingMenu.cpp index aeb9d016b..fe94ee5e8 100644 --- a/source/world/inventory/CraftingMenu.cpp +++ b/source/world/inventory/CraftingMenu.cpp @@ -3,6 +3,7 @@ #include "ResultSlot.hpp" #include "world/item/crafting/Recipes.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" CraftingMenu::CraftingMenu(Inventory* inventory, const TilePos& tilePos, Level* level) : ContainerMenu(Container::CRAFTING) @@ -61,7 +62,7 @@ void CraftingMenu::removed(Player* player) bool CraftingMenu::stillValid(Player* player) const { - if (m_pLevel->getTile(m_pos) != Tile::craftingTable->m_ID) + if (player->getTileSource().getTile(m_pos) != Tile::craftingTable->m_ID) return false; else return !(player->distanceToSqr(Vec3(m_pos.x + 0.5f, m_pos.y + 0.5f, m_pos.z + 0.5f)) > 64.0f); diff --git a/source/world/item/BowItem.cpp b/source/world/item/BowItem.cpp index 53ebdce5d..0736c28a5 100644 --- a/source/world/item/BowItem.cpp +++ b/source/world/item/BowItem.cpp @@ -8,13 +8,15 @@ BowItem::BowItem(int id) : Item(id) m_maxStackSize = 1; } -ItemStack* BowItem::use(ItemStack* inst, Level* level, Mob* user) const +ItemStack* BowItem::use(ItemStack* inst, Mob* user) const { + Level& level = user->getLevel(); + if (!user->isPlayer() || static_cast(user)->isCreative() || static_cast(user)->m_pInventory->removeResource(Item::arrow->m_itemID)) { - level->playSound(user, "random.bow", 1.0f, 1.0f / (level->m_random.nextFloat() * 0.4f + 0.8f)); - if (!level->m_bIsClientSide) { - level->addEntity(new Arrow(level, user)); + level.playSound(user, "random.bow", 1.0f, 1.0f / (level.m_random.nextFloat() * 0.4f + 0.8f)); + if (!level.m_bIsClientSide) { + level.addEntity(new Arrow(*user)); } } diff --git a/source/world/item/BowItem.hpp b/source/world/item/BowItem.hpp index b6e67a36b..dbb6bfdf2 100644 --- a/source/world/item/BowItem.hpp +++ b/source/world/item/BowItem.hpp @@ -8,5 +8,5 @@ class BowItem : public Item BowItem(int id); public: - ItemStack* use(ItemStack* inst, Level* level, Mob* user) const override; + ItemStack* use(ItemStack* inst, Mob* user) const override; }; diff --git a/source/world/item/CameraItem.cpp b/source/world/item/CameraItem.cpp index 126cd290b..671fd3da9 100644 --- a/source/world/item/CameraItem.cpp +++ b/source/world/item/CameraItem.cpp @@ -18,11 +18,13 @@ CameraItem::CameraItem(int id) : Item(id) { } -ItemStack* CameraItem::use(ItemStack* inst, Level* level, Mob* user) const +ItemStack* CameraItem::use(ItemStack* inst, Mob* user) const { + Level& level = user->getLevel(); + #ifndef ORIGINAL_CODE // prevent players from using this in multiplayer, to prevent a desync of entity IDs - if (level->m_bIsClientSide) + if (level.m_bIsClientSide) return inst; #endif @@ -30,6 +32,6 @@ ItemStack* CameraItem::use(ItemStack* inst, Level* level, Mob* user) const return inst; Player* player = static_cast(user); - level->addEntity(new TripodCamera(level, player, player->m_pos)); + level.addEntity(new TripodCamera(user->getTileSource(), player, player->m_pos)); return inst; } diff --git a/source/world/item/CameraItem.hpp b/source/world/item/CameraItem.hpp index 37979e55d..288e2ca12 100644 --- a/source/world/item/CameraItem.hpp +++ b/source/world/item/CameraItem.hpp @@ -15,5 +15,5 @@ class CameraItem : public Item CameraItem(int id); public: - ItemStack* use(ItemStack* inst, Level* level, Mob* user) const override; + ItemStack* use(ItemStack* inst, Mob* user) const override; }; diff --git a/source/world/item/DoorItem.cpp b/source/world/item/DoorItem.cpp index 64d76fbe3..1690e42df 100644 --- a/source/world/item/DoorItem.cpp +++ b/source/world/item/DoorItem.cpp @@ -10,6 +10,7 @@ #include "world/level/Level.hpp" #include "world/entity/Player.hpp" #include "world/tile/Tile.hpp" +#include "world/level/TileSource.hpp" DoorItem::DoorItem(int id, Material* pMtl) : Item(id) { @@ -18,13 +19,15 @@ DoorItem::DoorItem(int id, Material* pMtl) : Item(id) m_pMaterial = pMtl; } -bool DoorItem::useOn(ItemStack* inst, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool DoorItem::useOn(ItemStack* inst, Player* player, const TilePos& pos, Facing::Name face) const { if (face != Facing::UP) return false; + TileSource& source = player->getTileSource(); + Tile* pTile = m_pMaterial == Material::wood ? Tile::door_wood : Tile::door_iron; - if (!pTile->mayPlace(level, pos.above())) + if (!pTile->mayPlace(&source, pos.above())) return false; int faceDir = Mth::floor((((player->m_rot.x + 180.0f) * 4.0f) / 360.0f) - 0.5f) & 3; @@ -51,23 +54,21 @@ bool DoorItem::useOn(ItemStack* inst, Player* player, Level* level, const TilePo } // For polish, make sure the hinge is attached to the "correct" block - int solid1 = level->isSolidTile(TilePos(pos.x - offsetX, pos.y + 1, pos.z - offsetZ)); - int solid2 = level->isSolidTile(TilePos(pos.x - offsetX, pos.y + 2, pos.z - offsetZ)); - int solid3 = level->isSolidTile(TilePos(pos.x + offsetX, pos.y + 1, pos.z + offsetZ)); - int solid4 = level->isSolidTile(TilePos(pos.x + offsetX, pos.y + 2, pos.z + offsetZ)); - int equal5 = level->getTile(TilePos(pos.x - offsetX, pos.y + 1, pos.z - offsetZ)) == pTile->m_ID || - level->getTile(TilePos(pos.x - offsetX, pos.y + 2, pos.z - offsetZ)) == pTile->m_ID; - int equal6 = level->getTile(TilePos(pos.x + offsetX, pos.y + 1, pos.z + offsetZ)) == pTile->m_ID || - level->getTile(TilePos(pos.x + offsetX, pos.y + 2, pos.z + offsetZ)) == pTile->m_ID; + int solid1 = source.isSolidBlockingTile(TilePos(pos.x - offsetX, pos.y + 1, pos.z - offsetZ)); + int solid2 = source.isSolidBlockingTile(TilePos(pos.x - offsetX, pos.y + 2, pos.z - offsetZ)); + int solid3 = source.isSolidBlockingTile(TilePos(pos.x + offsetX, pos.y + 1, pos.z + offsetZ)); + int solid4 = source.isSolidBlockingTile(TilePos(pos.x + offsetX, pos.y + 2, pos.z + offsetZ)); + int equal5 = source.getTile(TilePos(pos.x - offsetX, pos.y + 1, pos.z - offsetZ)) == pTile->m_ID || + source.getTile(TilePos(pos.x - offsetX, pos.y + 2, pos.z - offsetZ)) == pTile->m_ID; + int equal6 = source.getTile(TilePos(pos.x + offsetX, pos.y + 1, pos.z + offsetZ)) == pTile->m_ID || + source.getTile(TilePos(pos.x + offsetX, pos.y + 2, pos.z + offsetZ)) == pTile->m_ID; if ((equal5 && !equal6) || solid2 + solid1 < solid4 + solid3) faceDir = 4 + ((faceDir - 1) & 3); // congratulations! You can now have a door. - level->setTile(pos.above(), pTile->m_ID); - level->setData(pos.above(), faceDir); - level->setTile(TilePos(pos.x, pos.y + 2, pos.z), pTile->m_ID); - level->setData(TilePos(pos.x, pos.y + 2, pos.z), faceDir + 8); + source.setTileAndData(pos.above(), FullTile(pTile->m_ID, faceDir)); + source.setTileAndData(TilePos(pos.x, pos.y + 2, pos.z), FullTile(pTile->m_ID, faceDir + 8)); inst->m_count--; return true; } diff --git a/source/world/item/DoorItem.hpp b/source/world/item/DoorItem.hpp index cc880c3f0..98ec4e44b 100644 --- a/source/world/item/DoorItem.hpp +++ b/source/world/item/DoorItem.hpp @@ -15,7 +15,7 @@ class DoorItem : public Item DoorItem(int id, Material* pMtl); public: - bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const override; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; public: Material* m_pMaterial; diff --git a/source/world/item/DyePowderItem.cpp b/source/world/item/DyePowderItem.cpp index 8fc71685c..1435b42d8 100644 --- a/source/world/item/DyePowderItem.cpp +++ b/source/world/item/DyePowderItem.cpp @@ -7,6 +7,7 @@ #include "world/tile/CropsTile.hpp" #include "world/tile/ClothTile.hpp" #include "world/entity/EntityType.hpp" +#include "world/level/TileSource.hpp" #include "DyeColor.hpp" DyePowderItem::DyePowderItem(int itemID) : Item(itemID) @@ -31,23 +32,26 @@ std::string DyePowderItem::getDescriptionId(ItemStack* item) const return Item::getDescriptionId() + "." + DyeColor::IDS[item->getAuxValue()]; } -bool DyePowderItem::useOn(ItemStack* item, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool DyePowderItem::useOn(ItemStack* item, Player* player, const TilePos& pos, Facing::Name face) const { // Aux value 15 is bonemeal if (item->getAuxValue() == 15) { - TileID tile = level->getTile(pos); + TileSource& source = player->getTileSource(); + Level& level = player->getLevel(); + + TileID tile = source.getTile(pos); if (tile == Tile::sapling->m_ID) { - (static_cast(Tile::sapling))->growTree(level, pos, &level->m_random); + (static_cast(Tile::sapling))->growTree(&source, pos, &level.m_random); item->m_count--; return true; } if (tile == Tile::crops->m_ID) { - static_cast(Tile::crops)->growCropsToMax(level, pos); + static_cast(Tile::crops)->growCropsToMax(&source, pos); item->m_count--; return true; } diff --git a/source/world/item/DyePowderItem.hpp b/source/world/item/DyePowderItem.hpp index 4c09c0544..ca43e826f 100644 --- a/source/world/item/DyePowderItem.hpp +++ b/source/world/item/DyePowderItem.hpp @@ -11,6 +11,6 @@ class DyePowderItem : public Item int getIcon(const ItemStack*) const override; std::string getDescriptionId() const override; std::string getDescriptionId(ItemStack*) const override; - bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const override; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; void interactEnemy(ItemStack*, Mob*) const override; }; \ No newline at end of file diff --git a/source/world/item/FoodItem.cpp b/source/world/item/FoodItem.cpp index a641d9eec..3fff95083 100644 --- a/source/world/item/FoodItem.cpp +++ b/source/world/item/FoodItem.cpp @@ -6,7 +6,7 @@ FoodItem::FoodItem(int id, int nutrition) : Item(id), m_nutrition(nutrition) m_maxStackSize = 1; } -ItemStack* FoodItem::use(ItemStack* inst, Level* level, Mob* mob) const +ItemStack* FoodItem::use(ItemStack* inst, Mob* mob) const { if (mob->m_health < mob->getMaxHealth()) { diff --git a/source/world/item/FoodItem.hpp b/source/world/item/FoodItem.hpp index f9ccdacdb..f0b7e4a07 100644 --- a/source/world/item/FoodItem.hpp +++ b/source/world/item/FoodItem.hpp @@ -7,7 +7,7 @@ class FoodItem : public Item public: FoodItem(int id, int nutrition); - ItemStack* use(ItemStack*, Level*, Mob*) const override; + ItemStack* use(ItemStack*, Mob*) const override; protected: int m_nutrition; diff --git a/source/world/item/HoeItem.cpp b/source/world/item/HoeItem.cpp index 5d6191437..f8ca8a648 100644 --- a/source/world/item/HoeItem.cpp +++ b/source/world/item/HoeItem.cpp @@ -1,6 +1,7 @@ #include "HoeItem.hpp" #include "world/entity/Player.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" HoeItem::HoeItem(int id, ToolItem::Tier& tier) : Item(id) { @@ -8,36 +9,39 @@ HoeItem::HoeItem(int id, ToolItem::Tier& tier) : Item(id) m_maxDamage = tier.m_uses; } -bool HoeItem::useOn(ItemStack* inst, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool HoeItem::useOn(ItemStack* inst, Player* player, const TilePos& pos, Facing::Name face) const { - int tile = level->getTile(pos); - int below = level->getTile(pos.above()); + TileSource& source = player->getTileSource(); + Level& level = player->getLevel(); + + TileID tile = source.getTile(pos); + TileID below = source.getTile(pos.above()); if ((face == Facing::DOWN || below || tile != Tile::grass->m_ID) && tile != Tile::dirt->m_ID) return false; Tile* newTile = Tile::farmland; - level->playSound(pos + 0.5f, "step." + newTile->m_pSound->m_name, (newTile->m_pSound->volume + 1.0f) / 2.0f, newTile->m_pSound->pitch * 0.8f); + level.playSound(pos + 0.5f, "step." + newTile->m_pSound->m_name, (newTile->m_pSound->volume + 1.0f) / 2.0f, newTile->m_pSound->pitch * 0.8f); - if (level->m_bIsClientSide) + if (level.m_bIsClientSide) return true; #ifndef FEATURE_PLANT_VEGGIES - if (tile == Tile::grass->m_ID && level->m_random.nextInt(8) == 0) + if (tile == Tile::grass->m_ID && level.m_random.nextInt(8) == 0) { float spread = 0.7f; TilePos spreadPos( - level->m_random.nextFloat() * spread + (1.0f - spread) * 0.5f, + level.m_random.nextFloat() * spread + (1.0f - spread) * 0.5f, 1.2f, - level->m_random.nextFloat() * spread + (1.0f - spread) * 0.5f + level.m_random.nextFloat() * spread + (1.0f - spread) * 0.5f ); - ItemEntity* itemEntity = new ItemEntity(level, pos + spreadPos, ItemStack(Item::seeds)); + ItemEntity* itemEntity = new ItemEntity(source, pos + spreadPos, ItemStack(Item::seeds)); itemEntity->m_throwTime = 10; - level->addEntity(itemEntity); + level.addEntity(itemEntity); } #endif - level->setTile(pos, newTile->m_ID); + source.setTile(pos, newTile->m_ID); inst->hurtAndBreak(1, player); return true; } diff --git a/source/world/item/HoeItem.hpp b/source/world/item/HoeItem.hpp index d58448c5d..c82f4f151 100644 --- a/source/world/item/HoeItem.hpp +++ b/source/world/item/HoeItem.hpp @@ -7,6 +7,6 @@ class HoeItem : public Item public: HoeItem(int id, ToolItem::Tier& tier); - bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const override; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; bool isHandEquipped() const override; }; diff --git a/source/world/item/Item.cpp b/source/world/item/Item.cpp index 94b017a79..7f35f8c42 100644 --- a/source/world/item/Item.cpp +++ b/source/world/item/Item.cpp @@ -598,12 +598,7 @@ int Item::getIcon(const ItemStack* item) const return m_icon; } -bool Item::useOn(ItemStack* instance, Level* level, const TilePos& pos, Facing::Name face) const -{ - return false; -} - -bool Item::useOn(ItemStack* instance, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool Item::useOn(ItemStack* instance, Player* player, const TilePos& pos, Facing::Name face) const { return false; } @@ -613,7 +608,7 @@ float Item::getDestroySpeed(ItemStack* instance, const Tile* tile) const return 1.0f; } -ItemStack* Item::use(ItemStack* instance, Level* level, Mob* user) const +ItemStack* Item::use(ItemStack* instance, Mob* user) const { return instance; } diff --git a/source/world/item/Item.hpp b/source/world/item/Item.hpp index e2098f06c..c3ef5bf95 100644 --- a/source/world/item/Item.hpp +++ b/source/world/item/Item.hpp @@ -52,10 +52,9 @@ class Item virtual Item* setMaxStackSize(int mss); virtual Item* setIcon(int ix, int iy); virtual int getIcon(const ItemStack*) const; - virtual bool useOn(ItemStack*, Level*, const TilePos& pos, Facing::Name face) const; - virtual bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const; + virtual bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const; virtual float getDestroySpeed(ItemStack*, const Tile*) const; - virtual ItemStack* use(ItemStack*, Level*, Mob*) const; + virtual ItemStack* use(ItemStack*, Mob*) const; virtual void releaseUsing(ItemStack&, Level&, Mob&, int durationLeft) const; virtual int getMaxStackSize() const; virtual TileData getLevelDataForAuxValue(int x) const; diff --git a/source/world/item/ItemStack.cpp b/source/world/item/ItemStack.cpp index 0ced312cf..d6845de88 100644 --- a/source/world/item/ItemStack.cpp +++ b/source/world/item/ItemStack.cpp @@ -368,9 +368,9 @@ std::string ItemStack::toString() const return ss.str(); } -ItemStack* ItemStack::use(Level* level, Mob* user) +ItemStack* ItemStack::use(Mob* user) { - return getItem()->use(this, level, user); + return getItem()->use(this, user); } void ItemStack::releaseUsing(Level& level, Mob& user, int durationLeft) @@ -378,9 +378,9 @@ void ItemStack::releaseUsing(Level& level, Mob& user, int durationLeft) return getItem()->releaseUsing(*this, level, user, durationLeft); } -bool ItemStack::useOn(Player* player, Level* level, const TilePos& pos, Facing::Name face) +bool ItemStack::useOn(Player* player, const TilePos& pos, Facing::Name face) { - return getItem()->useOn(this, player, level, pos, face); + return getItem()->useOn(this, player, pos, face); } void ItemStack::onCraftedBy(Player* player, Level* level) diff --git a/source/world/item/ItemStack.hpp b/source/world/item/ItemStack.hpp index b984f3b9e..28ead2293 100644 --- a/source/world/item/ItemStack.hpp +++ b/source/world/item/ItemStack.hpp @@ -85,9 +85,9 @@ class ItemStack void setDescriptionId(const std::string&); void snap(Player*); std::string toString() const; - ItemStack* use(Level*, Mob*); + ItemStack* use(Mob*); void releaseUsing(Level&, Mob&, int durationLeft); - bool useOn(Player*, Level*, const TilePos& pos, Facing::Name face); + bool useOn(Player*, const TilePos& pos, Facing::Name face); void onCraftedBy(Player*, Level*); void onCraftedBy(Player*, Level*, int amount); diff --git a/source/world/item/RocketItem.cpp b/source/world/item/RocketItem.cpp index 978973136..db69032cc 100644 --- a/source/world/item/RocketItem.cpp +++ b/source/world/item/RocketItem.cpp @@ -8,6 +8,7 @@ #include "RocketItem.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "world/entity/Player.hpp" #include "world/entity/Rocket.hpp" @@ -15,11 +16,13 @@ RocketItem::RocketItem(int id) : Item(id) { } -bool RocketItem::useOn(ItemStack* inst, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool RocketItem::useOn(ItemStack* inst, Player* player, const TilePos& pos, Facing::Name face) const { TilePos tp(pos); + TileSource& tileSource = player->getTileSource(); + Level& level = player->getLevel(); - if (level->getTile(pos) == Tile::topSnow->m_ID) + if (tileSource.getTile(pos) == Tile::topSnow->m_ID) { face = Facing::DOWN; } @@ -31,9 +34,10 @@ bool RocketItem::useOn(ItemStack* inst, Player* player, Level* level, const Tile case Facing::SOUTH: tp.z++; break; case Facing::WEST: tp.x--; break; case Facing::EAST: tp.x++; break; + default: assert(false); return false; break; } - level->addEntity(new Rocket(level, tp + 0.5f)); + level.addEntity(new Rocket(tileSource, tp + 0.5f)); inst->m_count--; return true; diff --git a/source/world/item/RocketItem.hpp b/source/world/item/RocketItem.hpp index 6ce631bc0..a989e4ee1 100644 --- a/source/world/item/RocketItem.hpp +++ b/source/world/item/RocketItem.hpp @@ -15,5 +15,5 @@ class RocketItem : public Item RocketItem(int id); public: - bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const override; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; }; diff --git a/source/world/item/SeedItem.cpp b/source/world/item/SeedItem.cpp index 49d1ee386..91e6bcc4e 100644 --- a/source/world/item/SeedItem.cpp +++ b/source/world/item/SeedItem.cpp @@ -1,18 +1,23 @@ #include "SeedItem.hpp" #include "world/level/Level.hpp" #include "world/tile/Tile.hpp" +#include "world/level/TileSource.hpp" -SeedItem::SeedItem(int id, int place) : Item(id), m_tile(place) +SeedItem::SeedItem(int id, int place) + : Item(id) + , m_tile(place) { } -bool SeedItem::useOn(ItemStack* inst, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool SeedItem::useOn(ItemStack* inst, Player* player, const TilePos& pos, Facing::Name face) const { - int tile = level->getTile(pos); + TileSource& source = player->getTileSource(); - if (tile == Tile::farmland->m_ID && level->isEmptyTile(pos.above())) + int tile = source.getTile(pos); + + if (tile == Tile::farmland->m_ID && source.isEmptyTile(pos.above())) { - level->setTile(pos.above(), m_tile); + source.setTile(pos.above(), m_tile); --inst->m_count; return true; } diff --git a/source/world/item/SeedItem.hpp b/source/world/item/SeedItem.hpp index 733ddb205..c3f5233b7 100644 --- a/source/world/item/SeedItem.hpp +++ b/source/world/item/SeedItem.hpp @@ -7,7 +7,7 @@ class SeedItem : public Item public: SeedItem(int id, int place); - virtual bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; public: int m_tile; }; diff --git a/source/world/item/TileItem.cpp b/source/world/item/TileItem.cpp index b997927c0..5a83eae29 100644 --- a/source/world/item/TileItem.cpp +++ b/source/world/item/TileItem.cpp @@ -11,6 +11,7 @@ #include "network/packets/PlaceBlockPacket.hpp" #include "world/level/Level.hpp" #include "world/tile/Tile.hpp" +#include "world/level/TileSource.hpp" TileItem::TileItem(int id) : Item(id) { @@ -29,11 +30,14 @@ std::string TileItem::getDescriptionId(ItemStack* instance) const return Tile::tiles[m_tile]->getDescriptionId(); } -bool TileItem::useOn(ItemStack* instance, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool TileItem::useOn(ItemStack* instance, Player* player, const TilePos& pos, Facing::Name face) const { + TileSource& source = player->getTileSource(); + Level& level = player->getLevel(); + TilePos tp(pos); - if (level->getTile(pos) == Tile::topSnow->m_ID) + if (source.getTile(pos) == Tile::topSnow->m_ID) { face = Facing::DOWN; } @@ -45,31 +49,32 @@ bool TileItem::useOn(ItemStack* instance, Player* player, Level* level, const Ti case Facing::SOUTH: tp.z++; break; case Facing::WEST: tp.x--; break; case Facing::EAST: tp.x++; break; + default: assert(false); return false; break; } if (instance->m_count == 0) return false; - if (!level->mayPlace(m_tile, tp, false)) + if (!source.mayPlace(m_tile, tp, face, player, false, nullptr)) return false; Tile* pTile = Tile::tiles[m_tile]; - if (!level->setTileAndData(tp, m_tile, getLevelDataForAuxValue(instance->getAuxValue()))) + if (!source.setTileAndData(tp, FullTile(m_tile, getLevelDataForAuxValue(instance->getAuxValue())))) return true; - Tile::tiles[m_tile]->setPlacedOnFace(level, tp, face); - Tile::tiles[m_tile]->setPlacedBy(level, tp, player); + Tile::tiles[m_tile]->setPlacedOnFace(&source, tp, face); + Tile::tiles[m_tile]->setPlacedBy(&source, tp, player); - level->playSound( + level.playSound( Vec3(tp) + 0.5f, "step." + pTile->m_pSound->m_name, (pTile->m_pSound->volume + 1.0f) * 0.5f, pTile->m_pSound->pitch * 0.8f ); - if (level->m_pRakNetInstance) - level->m_pRakNetInstance->send(new PlaceBlockPacket(player->m_EntityID, tp, (TileID)m_tile, face, instance->getAuxValue())); + if (level.m_pRakNetInstance) + level.m_pRakNetInstance->send(new PlaceBlockPacket(player->m_EntityID, tp, (TileID)m_tile, face, instance->getAuxValue())); player->useItem(*instance); return true; diff --git a/source/world/item/TileItem.hpp b/source/world/item/TileItem.hpp index 5a135d9b5..7880c6ebb 100644 --- a/source/world/item/TileItem.hpp +++ b/source/world/item/TileItem.hpp @@ -17,7 +17,7 @@ class TileItem : public Item public: std::string getDescriptionId() const override; std::string getDescriptionId(ItemStack*) const override; - bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const override; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; public: int m_tile; diff --git a/source/world/item/TilePlanterItem.cpp b/source/world/item/TilePlanterItem.cpp index b4c7e6679..790c73559 100644 --- a/source/world/item/TilePlanterItem.cpp +++ b/source/world/item/TilePlanterItem.cpp @@ -9,17 +9,20 @@ #include "TilePlanterItem.hpp" #include "world/level/Level.hpp" #include "world/tile/Tile.hpp" +#include "world/level/TileSource.hpp" TilePlanterItem::TilePlanterItem(int id, int place) : Item(id) { m_tile = Tile::tiles[place]->m_ID; } -bool TilePlanterItem::useOn(ItemStack* instance, Player* player, Level* level, const TilePos& pos, Facing::Name face) const +bool TilePlanterItem::useOn(ItemStack* instance, Player* player, const TilePos& pos, Facing::Name face) const { + TileSource& source = player->getTileSource(); + TilePos tp(pos); - if (level->getTile(pos) == Tile::topSnow->m_ID) + if (source.getTile(pos) == Tile::topSnow->m_ID) { face = Facing::DOWN; } @@ -31,20 +34,20 @@ bool TilePlanterItem::useOn(ItemStack* instance, Player* player, Level* level, c case Facing::SOUTH: tp.z++; break; case Facing::WEST: tp.x--; break; case Facing::EAST: tp.x++; break; + default: assert(false); return false; break; } if (!instance->m_count) return false; - // why? - if (!level->mayPlace(m_tile, tp, false)) + if (!source.mayPlace(m_tile, tp, face, player)) return true; - if (!level->setTile(tp, m_tile)) + if (!source.setTile(tp, m_tile)) return true; - Tile::tiles[m_tile]->setPlacedOnFace(level, tp, face); - Tile::tiles[m_tile]->setPlacedBy(level, tp, player); + Tile::tiles[m_tile]->setPlacedOnFace(&source, tp, face); + Tile::tiles[m_tile]->setPlacedBy(&source, tp, player); instance->m_count--; return true; diff --git a/source/world/item/TilePlanterItem.hpp b/source/world/item/TilePlanterItem.hpp index baff23129..f886c5b56 100644 --- a/source/world/item/TilePlanterItem.hpp +++ b/source/world/item/TilePlanterItem.hpp @@ -15,7 +15,7 @@ class TilePlanterItem : public Item TilePlanterItem(int id, int place); public: - bool useOn(ItemStack*, Player*, Level*, const TilePos& pos, Facing::Name face) const override; + bool useOn(ItemStack*, Player*, const TilePos& pos, Facing::Name face) const override; public: int m_tile; diff --git a/source/world/level/Brightness.hpp b/source/world/level/Brightness.hpp new file mode 100644 index 000000000..e94c07dd4 --- /dev/null +++ b/source/world/level/Brightness.hpp @@ -0,0 +1,12 @@ +#pragma once +#include + +// int8 to prevent overflow issues +typedef int8_t Brightness_t; + +class Brightness +{ +public: + static constexpr Brightness_t MIN = 0; + static constexpr Brightness_t MAX = 15; +}; diff --git a/source/world/level/Dimension.cpp b/source/world/level/Dimension.cpp index 458f539ae..31d394caa 100644 --- a/source/world/level/Dimension.cpp +++ b/source/world/level/Dimension.cpp @@ -8,59 +8,181 @@ #include "Dimension.hpp" #include "GameMods.hpp" -#include "world/level/levelgen/chunk/TestChunkSource.hpp" -#include "world/level/levelgen/chunk/RandomLevelSource.hpp" -#include "world/level/levelgen/chunk/ChunkCache.hpp" +#include "world/entity/MobSpawner.hpp" #include "world/level/levelgen/biome/BiomeSource.hpp" #include "world/level/levelgen/chunk/ChunkSource.hpp" +#include "world/level/TileSource.hpp" #include "Level.hpp" +#include "world/level/levelgen/chunk/MainChunkSource.hpp" +#include "world/level/levelgen/chunk/NetworkChunkSource.hpp" +#include "world/level/levelgen/chunk/WorldLimitChunkSource.hpp" +#include "world/level/levelgen/chunk/RandomLevelSource.hpp" + #define C_TIMEOFDAY_SCALE_JAVA 24000 #define C_TIMEOFDAY_SCALE_POCKET 14400 #define C_TIMEOFDAY_SCALE C_TIMEOFDAY_SCALE_JAVA -Dimension* Dimension::createNew(DimensionId type) +Dimension::Dimension(Level& level, DimensionId dimensionId) + : m_level(level) + , m_biomeSource(nullptr) // TODO: nuke + , m_bFoggy(false) + , m_bUltraWarm(false) + , m_hasCeiling(false) + , m_dimensionId(dimensionId) + , m_chunkSource(nullptr) + , m_tileSource(nullptr) +{ + m_level.addListener(this); +} + +Dimension::~Dimension() +{ + m_level.removeListener(*this); + delete m_biomeSource; +} + +ChunkSource* Dimension::_getGenerator(GeneratorType type) +{ + switch (type) + { + case GENERATOR_OVERWORLD: + case GENERATOR_OVERWORLD_LIMITED: + return new RandomLevelSource(&m_level, this, m_level.getSeed()); + default: + return nullptr; + } +} + +void Dimension::init() +{ + GeneratorType generatorType = GENERATOR_OVERWORLD_LIMITED; + + // incase we initialise again + delete m_chunkSource; + + if (!m_level.m_bIsClientSide) + { + ChunkSource* generator = _getGenerator(generatorType); + m_chunkSource = new MainChunkSource(std::unique_ptr(generator)); + } + else + { + m_chunkSource = new NetworkChunkSource(&m_level, this); + } + + if (generatorType == GENERATOR_OVERWORLD_LIMITED) + { + m_chunkSource = new WorldLimitChunkSource(std::unique_ptr(m_chunkSource), m_level.getLevelData()->getLimitedWorldOrigin()); + } + + delete m_tileSource; + m_tileSource = new TileSource(m_level, *this, *m_chunkSource, true, false); + updateLightRamp(); +} + +void Dimension::tick() +{ + m_level.m_pMobSpawner->tick(*getTileSource(), m_level.m_difficulty > 0, true); + //getChunkSource()->tick(); + + for (EntityIdMap_t::iterator it = m_entityIdMap.begin(); it != m_entityIdMap.end(); it++) + { + Entity* pEnt = it->second; + + if (!pEnt->m_bRemoved) + { + pEnt->m_posPrev = pEnt->m_pos; + pEnt->m_oRot = pEnt->m_rot; + + if (pEnt->m_bInAChunk) + pEnt->tick(); + } + else if (!pEnt->isPlayer() || pEnt->m_bForceRemove) + { + m_entityIdMap.erase(it); + + m_level.entityRemoved(pEnt); + delete pEnt; + } + } +} + +Dimension* Dimension::createNew(DimensionId type, Level& level) { switch (type) { case DIMENSION_OVERWORLD: - return new Dimension; - /*case DIMENSION_NETHER: - return new HellDimension;*/ - default: // type not supported + return new NormalDimension(level); + default: return nullptr; } } -Vec3 Dimension::getFogColor(float a, float b) const +Color Dimension::getFogColor(float a, float b) const { float x1 = cosf(a * M_PI * 2.0f); float x2 = x1 * 2 + 0.5f; if (x2 < 0.0f) - return Vec3(0.045176f, 0.050824f, 0.09f); - - Vec3 v; - v.z = 1; + return Color(0.045176f, 0.050824f, 0.09f, 1.0f); + Color color; + color.a = 1.0f; if (x2 <= 1.0f) { float p = (x2 * 0.94f) + 0.06f; - v.x = p * 0.75294f; - v.y = p * 0.84706f; - v.z = (x2 * 0.91f) + 0.09f; + color.r = p * 0.75294f; + color.g = p * 0.84706f; + color.b = (x2 * 0.91f) + 0.09f; } else { - v.x = 0.75294f; - v.y = 0.84706f; + color.r = 0.75294f; + color.g = 0.84706f; + color.b = 1.0f; } - return v; + return color; +} + +Color Dimension::getFogColor(float f) const +{ + return getFogColor(getTimeOfDay(f), f); +} + +Color Dimension::getSkyColor(const Entity& entity, float f) const +{ + Color color; + color.a = 1.0f; + + float fTODCosAng = Mth::cos(getSunAngle(f)); + + color.b = 2 * fTODCosAng + 0.5f; + if (color.b < 0.0f) + color.b = 0.0f; + if (color.b > 1.0f) + color.b = 1.0f; + + // @NOTE: Unused result. In JE, it tries to get the biome that the player is standing in. + //Mth::floor(entity.m_pos.x); + //Mth::floor(entity.m_pos.z); + + color.r = color.b * 0.6f; + color.g = color.r; + + return color; +} + +float Dimension::getSunAngle(float f) const +{ + return 2 * float(M_PI) * getTimeOfDay(f); } -const float* Dimension::getSunriseColor(float a, float b) +Color Dimension::getSunriseColor(float a, float b) const { + Color sunriseColor; + float radial = 0.4f; float dot = Mth::cos(a * M_PI * 2.0f) - 0.125f; // * 2.0f + 0.5f; float center = -0.0f; @@ -70,40 +192,17 @@ const float* Dimension::getSunriseColor(float a, float b) float norm = (dot - center) / radial * 0.5f + 0.5f; float alpha = 1.0f - (1.0f - Mth::sin(norm * M_PI)) * 0.99f; - m_sunriseColor[0] = norm * 0.3f + 0.7f; - m_sunriseColor[1] = norm * norm * 0.7f + 0.2f; - m_sunriseColor[2] = norm * norm * 0.0f + 0.2f; - m_sunriseColor[3] = alpha * alpha; - - return m_sunriseColor; + sunriseColor.r = norm * 0.3f + 0.7f; + sunriseColor.g = norm * norm * 0.7f + 0.2f; + sunriseColor.b = norm * norm * 0.0f + 0.2f; + sunriseColor.a = alpha * alpha; } - return nullptr; -/* - - float x1 = Mth::cos(a * M_PI * 2.0f); //@BUG: Meant to use Mth::cos? - if (x1 < -0.4f || x1 > 0.4f) - return nullptr; - - float x2 = x1 / 0.4f * 0.5f + 0.5f; - float x3 = 1.0f - Mth::sin(x2); - - m_sunriseColor[0] = x2 * 0.3f + 0.7f; - m_sunriseColor[1] = (x2 * x2) * 0.7f + 0.2f; - m_sunriseColor[2] = (x2 * x2) * 0.0f + 0.2f; //@BUG: useless multiplication by 0? - m_sunriseColor[3] = ((x3 * -0.99f) + 1.0f) * ((x3 * -0.99f) + 1.0f); - return m_sunriseColor; - */ + return sunriseColor; } float Dimension::getTimeOfDay(int32_t l, float f) const { -#ifndef ENH_RUN_DAY_NIGHT_CYCLE - //@QUIRK: This is a constant. - l = 0; - f = 0; -#endif - int i = int(l % C_TIMEOFDAY_SCALE); float f1 = (float(i) + f) / float(C_TIMEOFDAY_SCALE) - 0.25f; if (f1 < 0.0f) @@ -121,6 +220,11 @@ float Dimension::getTimeOfDay(int32_t l, float f) const return f1; } +float Dimension::getTimeOfDay(float f) const +{ + return getTimeOfDay(m_level.getTime(), f); +} + void Dimension::updateLightRamp() { constexpr float var1 = 0.05f; @@ -145,64 +249,114 @@ void Dimension::updateLightRamp() } } -void Dimension::init() +bool Dimension::mayRespawn() const { - m_pBiomeSource = new BiomeSource(m_pLevel); + return true; } -void Dimension::init(Level* pLevel) +bool Dimension::isValidSpawn(const TilePos& pos) const { - m_pLevel = pLevel; - init(); - updateLightRamp(); + TileID tile = m_tileSource->getTopSolidBlock(pos, true); + if (tile == Tile::invisible_bedrock->m_ID) + return false; + +#ifndef ORIGINAL_CODE + if (tile == TILE_AIR) + return false; +#endif + + return Tile::tiles[tile]->isSolidRender(); } -Dimension::Dimension() +bool Dimension::isNaturalDimension() const { - m_pLevel = nullptr; - m_pBiomeSource = nullptr; - m_bFoggy = false; - m_bUltraWarm = false; - m_bHasCeiling = false; - m_id = 0; + return true; } -Dimension::~Dimension() +Color Dimension::getCloudColor(float f) const { - if (m_pBiomeSource) - delete m_pBiomeSource; + Color color = Color::WHITE; + + float fTODCosAng = Mth::cos(getSunAngle(f)); + + float mult = 2 * fTODCosAng + 0.5f; + if (mult < 0.0f) + mult = 0.0f; + if (mult > 1.0f) + mult = 1.0f; + + color.r = mult * 0.9f + 0.1f; + color.g = color.r; + color.b = mult * 0.85f + 0.15f; + + return color; } -bool Dimension::mayRespawn() const +float Dimension::getStarBrightness(float f) const { - return true; + float ca = Mth::cos(getSunAngle(f)); + float cb = 1.0f - (0.75f + 2 * ca); + + if (cb < 0.0f) + cb = 0.0f; + if (cb > 1.0f) + cb = 1.0f; + + return cb * cb * 0.5f; } -ChunkSource* Dimension::createRandomLevelSource() +Entity* Dimension::getEntity(Entity::ID id) const { -#ifdef MOD_USE_FLAT_WORLD - return new TestChunkSource(m_pLevel); -#else - return new RandomLevelSource(m_pLevel, m_pLevel->getSeed(), m_pLevel->getLevelData()->getGeneratorVersion()); -#endif + EntityIdMap_t::const_iterator iter = m_entityIdMap.find(id); + if (iter != m_entityIdMap.end()) + return iter->second; + + return nullptr; } -bool Dimension::isValidSpawn(const TilePos& pos) const +bool Dimension::hasEntity(Entity& entity) const { - TileID tile = m_pLevel->getTopTile(pos); - if (tile == Tile::invisible_bedrock->m_ID) - return false; + return m_entityIdMap.find(entity.hashCode()) != m_entityIdMap.end(); +} -#ifndef ORIGINAL_CODE - if (tile == 0) - return false; -#endif - - return Tile::tiles[tile]->isSolidRender(); +void Dimension::addEntity(Entity& entity) +{ + m_entityIdMap[entity.hashCode()] = &entity; } -bool Dimension::isNaturalDimension() const +bool Dimension::removeEntity(Entity& entity) { - // false in Hell - return true; + EntityIdMap_t::iterator iter = m_entityIdMap.find(entity.hashCode()); + if (iter != m_entityIdMap.end()) + { + m_entityIdMap.erase(iter); + return true; + } + + return false; +} + +Dimension::EntityIdMap_t& Dimension::getEntityIdMap() +{ + return m_entityIdMap; +} + +const Dimension::EntityIdMap_t& Dimension::getEntityIdMapConst() const +{ + return m_entityIdMap; +} + +NormalDimension::NormalDimension(Level& level) + : Dimension(level, DIMENSION_OVERWORLD) +{ +} + +void NormalDimension::init() +{ + Dimension::init(); +} + +std::string NormalDimension::getName() const +{ + return "Overworld"; } diff --git a/source/world/level/Dimension.hpp b/source/world/level/Dimension.hpp index 07742f73a..678e58689 100644 --- a/source/world/level/Dimension.hpp +++ b/source/world/level/Dimension.hpp @@ -8,10 +8,16 @@ #pragma once -#include "world/phys/Vec3.hpp" +#include +#include +#include "world/level/LevelListener.hpp" +#include "common/math/Color.hpp" +#include "world/entity/Entity.hpp" +#include "world/level/Brightness.hpp" -class Level; // if included from Level.hpp +class Level; class ChunkSource; +class TileSource; class BiomeSource; enum DimensionId @@ -23,34 +29,107 @@ enum DimensionId DIMENSION_UNKNOWN }; -class Dimension +enum GeneratorType +{ + GENERATOR_OVERWORLD_LIMITED, + GENERATOR_OVERWORLD, + GENERATOR_FLAT, + GENERATOR_NETHER, + GENERATOR_THE_END +}; + +class Dimension : public LevelListener { public: - Dimension(); + typedef std::unordered_map EntityIdMap_t; + +protected: + Level& m_level; + BiomeSource* m_biomeSource; + bool m_bFoggy; + bool m_bUltraWarm; + bool m_hasCeiling; + float m_brightnessRamp[Brightness::MAX + 1]; + DimensionId m_dimensionId; + ChunkSource* m_chunkSource; + TileSource* m_tileSource; + EntityIdMap_t m_entityIdMap; + +public: + Dimension(Level& level, DimensionId dimensionId); virtual ~Dimension(); - static Dimension* createNew(DimensionId type); - virtual Vec3 getFogColor(float, float) const; - virtual bool isNaturalDimension() const; +public: virtual void init(); + virtual void tick(); + virtual Color getFogColor(float, float) const; + virtual bool isNaturalDimension() const; virtual bool mayRespawn() const; virtual bool isValidSpawn(const TilePos& pos) const; + virtual void updateLightRamp(); + virtual std::string getName() const = 0; - const float* getSunriseColor(float, float); + bool isDay() const { return true; /*m_skyDarken <= 3;*/ } // @TODO: find this var + bool isFoggy() const { return m_bFoggy; } + Color getFogColor(float f) const; + Color getSkyColor(const Entity& entity, float f) const; + float getSunAngle(float f) const; + Color getSunriseColor(float, float) const; float getTimeOfDay(int32_t, float) const; - void init(Level* pLevel); - void updateLightRamp(); + float getTimeOfDay(float f) const; + Color getCloudColor(float f) const; + float getStarBrightness(float f) const; + + Entity* getEntity(Entity::ID id) const; + bool hasEntity(Entity& entity) const; + void addEntity(Entity& entity); + bool removeEntity(Entity& entity); + EntityIdMap_t& getEntityIdMap(); + const EntityIdMap_t& getEntityIdMapConst() const; + + DimensionId getId() const + { + return m_dimensionId; + } - ChunkSource* createRandomLevelSource(); + bool isWarm() const + { + return m_bUltraWarm; + } + + bool hasCeiling() const + { + return m_hasCeiling; + } + + float getBrightnessRamp(Brightness_t brightness) const + { + return m_brightnessRamp[brightness]; + } + + ChunkSource* getChunkSource() + { + return m_chunkSource; + } + + TileSource* getTileSource() + { + return m_tileSource; + } + +protected: + ChunkSource* _getGenerator(GeneratorType type); public: - Level* m_pLevel; - BiomeSource* m_pBiomeSource; - bool m_bFoggy; - bool m_bUltraWarm; - bool m_bHasCeiling; - float m_brightnessRamp[16]; - int m_id; - float m_sunriseColor[4]; + static Dimension* createNew(DimensionId type, Level& level); }; +class NormalDimension : public Dimension +{ +public: + NormalDimension(Level& level); + +public: + void init() override; + std::string getName() const override; +}; diff --git a/source/world/level/Explosion.cpp b/source/world/level/Explosion.cpp index 88dad14ef..2249b127e 100644 --- a/source/world/level/Explosion.cpp +++ b/source/world/level/Explosion.cpp @@ -7,8 +7,10 @@ ********************************************************************/ #include "Explosion.hpp" +#include "world/level/TileSource.hpp" -Explosion::Explosion(Level* level, Entity* entity, const Vec3& pos, float power) +Explosion::Explosion(TileSource& source, Entity* entity, const Vec3& pos, float power) + : m_tileSource(source) { field_20 = 0; @@ -17,7 +19,6 @@ Explosion::Explosion(Level* level, Entity* entity, const Vec3& pos, float power) m_pos = pos; m_power = power; m_pEntity = entity; - m_pLevel = level; assert(m_power != 0.0f); } @@ -27,6 +28,8 @@ Explosion::Explosion(Level* level, Entity* entity, const Vec3& pos, float power) void Explosion::explode() { { + Level& level = m_tileSource.getLevel(); + Vec3 vec; for (vec.x = 0; vec.x < 16; vec.x++) { @@ -40,7 +43,7 @@ void Explosion::explode() Vec3 ray = (vec / 15.0f * 2.0f - 1.0f).normalize(); - float mult = m_power * (0.7f + 0.6f * m_pLevel->m_random.nextFloat()); + float mult = m_power * (0.7f + 0.6f * level.m_random.nextFloat()); Vec3 pos(m_pos); @@ -49,7 +52,7 @@ void Explosion::explode() if (mult < 0) break; - TileID tile = m_pLevel->getTile(pos); + TileID tile = m_tileSource.getTile(pos); if (tile > 0) mult -= 0.3f * (0.3f + Tile::tiles[tile]->getExplosionResistance(m_pEntity)); @@ -81,7 +84,8 @@ void Explosion::explode() );*/ AABB aabb(m_pos - m_power - 1.0f, m_pos + m_power + 1.0f); - EntityVector ents = m_pLevel->getEntities(m_pEntity, aabb); + const std::vector& ents = m_tileSource.getEntities(m_pEntity, aabb); + for (size_t i = 0; i < ents.size(); i++) { Entity* entity = ents.at(i); @@ -93,7 +97,7 @@ void Explosion::explode() // @NOTE: They used it here, but not when normalizing the 16*16*16=4096 rays shot before... float normInv = Mth::invSqrt(delta.lengthSqr()); - float hurtPercent = m_pLevel->getSeenPercent(m_pos, entity->m_hitbox) * (1.0f - distPowerRatio); + float hurtPercent = m_tileSource.getSeenPercent(m_pos, entity->m_hitbox) * (1.0f - distPowerRatio); entity->hurt(m_pEntity, int((hurtPercent * hurtPercent + hurtPercent) / 2.0f * 8.0f * this->m_power + 1.0f)); @@ -111,16 +115,18 @@ void Explosion::explode() { TilePos tp = vec[i]; - TileID tile = m_pLevel->getTile(tp), tileBelow = m_pLevel->getTile(tp.below()); + TileID tile = m_tileSource.getTile(tp), tileBelow = m_tileSource.getTile(tp.below()); if (tile == TILE_AIR && Tile::solid[tileBelow] && m_random.nextInt(3) == 0) - m_pLevel->setTile(tp, Tile::fire->m_ID); + m_tileSource.setTile(tp, Tile::fire->m_ID); } } } void Explosion::addParticles() { - m_pLevel->playSound(m_pos, "random.explode", 4.0f, 0.7f * (1.0f + 0.2f * (m_pLevel->m_random.nextFloat() - m_pLevel->m_random.nextFloat()))); + Level& level = m_tileSource.getLevel(); + + level.playSound(m_pos, "random.explode", 4.0f, 0.7f * (1.0f + 0.2f * (level.m_random.nextFloat() - level.m_random.nextFloat()))); std::vector vec; vec.insert(vec.begin(), m_tiles.begin(), m_tiles.end()); @@ -128,15 +134,15 @@ void Explosion::addParticles() for (int i = int(vec.size() - 1); i >= 0; i--) { TilePos tp = vec[i]; - TileID tile = m_pLevel->getTile(tp); + TileID tile = m_tileSource.getTile(tp); // Spawn a particle only for every 8th tile. Weird if ((i & 0x7) == 0) { float mult; - Vec3 rp(float(tp.x) + m_pLevel->m_random.nextFloat(), - float(tp.y) + m_pLevel->m_random.nextFloat(), - float(tp.z) + m_pLevel->m_random.nextFloat()); + Vec3 rp(float(tp.x) + level.m_random.nextFloat(), + float(tp.y) + level.m_random.nextFloat(), + float(tp.z) + level.m_random.nextFloat()); Vec3 d(rp - m_pos); @@ -148,17 +154,17 @@ void Explosion::addParticles() // @HUH: Dividing by the inverse is the same as multiplying. Thanks, IDA! :) float power1 = m_power / (1.0f / dist) + 0.1f; - mult = ((m_pLevel->m_random.nextFloat() * m_pLevel->m_random.nextFloat()) + 0.3f) * (0.5f / power1); + mult = ((level.m_random.nextFloat() * level.m_random.nextFloat()) + 0.3f) * (0.5f / power1); - m_pLevel->addParticle("explode", Vec3((rp.x + m_pos.x) / 2, (rp.y + m_pos.y) / 2, (rp.z + m_pos.z) / 2), v * mult); - m_pLevel->addParticle("smoke", rp, v * mult); + level.addParticle("explode", Vec3((rp.x + m_pos.x) / 2, (rp.y + m_pos.y) / 2, (rp.z + m_pos.z) / 2), v * mult); + level.addParticle("smoke", rp, v * mult); } if (tile > 0) { - Tile::tiles[tile]->spawnResources(m_pLevel, tp, m_pLevel->getData(tp), 0.3f); - m_pLevel->setTile(tp, TILE_AIR); - Tile::tiles[tile]->wasExploded(m_pLevel, tp); + Tile::tiles[tile]->spawnResources(&m_tileSource, tp, m_tileSource.getData(tp), 0.3f); + m_tileSource.setTile(tp, TILE_AIR); + Tile::tiles[tile]->wasExploded(&m_tileSource, tp); } } diff --git a/source/world/level/Explosion.hpp b/source/world/level/Explosion.hpp index 1ea15aff8..354f02769 100644 --- a/source/world/level/Explosion.hpp +++ b/source/world/level/Explosion.hpp @@ -15,7 +15,7 @@ class Explosion { public: - Explosion(Level*, Entity*, const Vec3& pos, float power); + Explosion(TileSource&, Entity*, const Vec3& pos, float power); void addParticles(); void explode(); @@ -36,7 +36,7 @@ class Explosion bool m_bIsFiery; Entity* m_pEntity; Random m_random; - Level* m_pLevel; + TileSource& m_tileSource; }; diff --git a/source/world/level/Level.cpp b/source/world/level/Level.cpp index 7c1cb488e..b8a180c6d 100644 --- a/source/world/level/Level.cpp +++ b/source/world/level/Level.cpp @@ -16,32 +16,23 @@ #include "network/packets/EntityEventPacket.hpp" #include "network/packets/SetEntityDataPacket.hpp" #include "network/packets/ExplodePacket.hpp" -#include "world/level/levelgen/chunk/ChunkCache.hpp" +#include "network/packets/SetTimePacket.hpp" #include "world/entity/MobSpawner.hpp" +#include "world/level/TileSource.hpp" +#include "common/threading/BackgroundQueuePool.hpp" #include "Explosion.hpp" -#include "Region.hpp" -float Brightness::MIN = 0; -float Brightness::MAX = 15; - -Level::Level(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion, Dimension *pDimension) +Level::Level(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion) { - m_bInstantTicking = false; m_bIsClientSide = false; - m_bPostProcessing = false; - m_skyDarken = 0; field_30 = 0; - m_pDimension = nullptr; m_difficulty = 2; // Java has no actual default, it just always pulls from Options. Putting 2 here just so there's no chance of mobs getting despawned accidentally. m_pRakNetInstance = nullptr; - m_bCalculatingInitialSpawn = false; - m_pChunkSource = nullptr; m_pLevelStorage = pStor; m_randValue = 42184323; m_addend = 1013904223; - m_bUpdateLights = true; - field_B08 = 0; + m_processingLightUpdates = false; field_B0C = 0; m_random.setSeed(1); // initialize with a seed of 1 @@ -50,749 +41,135 @@ Level::Level(LevelStorage* pStor, const std::string& name, const LevelSettings& field_B0C = pData == nullptr; - // @BUG: leaking a Dimension*? - if (pDimension) - m_pDimension = pDimension; - else - m_pDimension = new Dimension; - if (!pData) m_pLevelData = new LevelData(settings, name, storageVersion); else m_pLevelData = pData; - m_pDimension->init(this); - m_pPathFinder = new PathFinder(); m_pMobSpawner = new MobSpawner(); - - m_pChunkSource = createChunkSource(); - updateSkyBrightness(); } Level::~Level() { - SAFE_DELETE(m_pChunkSource); - SAFE_DELETE(m_pDimension); - SAFE_DELETE(m_pPathFinder); - SAFE_DELETE(m_pMobSpawner); - - const size_t size = m_entities.size(); - for (size_t i = 0; i < size; i++) - { - Entity* pEnt = m_entities.at(i); - - //you better HOPE this is freed by Minecraft! (or a NetworkHandler) - //Really should have used shared pointers and stuff. - if (!pEnt->isPlayer()) - delete pEnt; - } - - m_entities.clear(); -} -ChunkSource* Level::createChunkSource() -{ -#ifndef MOD_USE_FLAT_WORLD - if (m_pLevelStorage) { - ChunkStorage* pChkStr = m_pLevelStorage->createChunkStorage(m_pDimension); - ChunkSource* pChkSrc = m_pDimension->createRandomLevelSource(); - return new ChunkCache(this, pChkStr, pChkSrc); + std::vector streamingQueues = BackgroundQueuePool::getInstance().getQueuesFor(BackgroundQueuePool::QR_STREAMING); + for (std::vector::iterator iter = streamingQueues.begin(); iter != streamingQueues.end(); iter++) + (*iter)->flush(); } -#endif - - LOG_I("No level data, calling dimension->createRandomLevelSource"); - return m_pDimension->createRandomLevelSource(); -} -float Level::getTimeOfDay(float f) const -{ - return m_pDimension->getTimeOfDay(getTime(), f); -} - -int Level::getSkyDarken(float f) const -{ - float x = Mth::cos(getSunAngle(f)); - float y = 1.0f - (2 * x + 0.5f); - - if (y < 0.0f) - return 0; // no darken - // 0.1.0 logic - /*if (y > 1.0f) - return 11; // full dark*/ - // 0.2.1 logic - if (y > 0.8f) - return 8; // full dark - - return int(y * 11.0f); -} - -void Level::updateSkyDarken() -{ - bool skyColorChanged = updateSkyBrightness(); - - if (skyColorChanged) - { - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) - { - LevelListener* pListener = *it; - pListener->skyColorChanged(); - } - } -} + // TODO: levellistener stuff -bool Level::updateSkyBrightness() -{ - int skyDarken = getSkyDarken(1.0f); - if (m_skyDarken != skyDarken) - { - m_skyDarken = skyDarken; - return true; - } + // TODO: player stuff - return false; -} + BackgroundQueuePool::GetFor(BackgroundQueuePool::QR_MAIN).flush(); -BiomeSource* Level::getBiomeSource() const -{ - return m_pDimension->m_pBiomeSource; + SAFE_DELETE(m_pPathFinder); + SAFE_DELETE(m_pMobSpawner); } Dimension* Level::getDimension(DimensionId type) const { - return m_pDimension; -} - -ChunkSource* Level::getChunkSource() const -{ - return m_pChunkSource; -} - -LevelChunk* Level::getChunk(const ChunkPos& pos) const -{ - return getChunkSource()->getChunk(pos); -} - -TileID Level::getTile(const TilePos& pos) const -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return 0; - - LevelChunk* pChunk = getChunk(pos); - return pChunk->getTile(pos); -} - -TileData Level::getData(const TilePos& pos) const -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return 0; - - LevelChunk* pChunk = getChunk(pos); - return pChunk->getData(pos); -} - -int Level::getBrightness(const LightLayer& ll, const TilePos& pos) const -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return ll.m_x; - - if (!hasChunk(pos)) - return 0; - - LevelChunk* pChunk = getChunk(pos); - return pChunk->getBrightness(ll, pos); -} - -float Level::getBrightness(const TilePos& pos) const -{ - return m_pDimension->m_brightnessRamp[getRawBrightness(pos)]; -} - -int Level::getRawBrightness(const TilePos& pos) const -{ - return getRawBrightness(pos, true); -} - -int Level::getRawBrightness(const TilePos& pos, bool b) const -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z) - return 15; - - // this looks like some kind of hack. - if (b && (getTile(pos) == Tile::stoneSlabHalf->m_ID || getTile(pos) == Tile::farmland->m_ID)) + for (DimensionVector::const_iterator iter = m_dimensions.begin(); iter != m_dimensions.end(); iter++) { - int b1 = getRawBrightness(pos.above(), false); - int b2 = getRawBrightness(pos.east(), false); - int b3 = getRawBrightness(pos.west(), false); - int b4 = getRawBrightness(pos.south(), false); - int b5 = getRawBrightness(pos.north(), false); - - if (b2 < b1) b2 = b1; - if (b3 < b2) b3 = b2; - if (b4 < b3) b4 = b3; - if (b5 < b4) b5 = b4; - - return b5; + Dimension* dimension = *iter; + if (dimension->getId() == type) + return dimension; } - if (pos.y < C_MIN_Y) - return 0; - - if (pos.y >= C_MAX_Y) - { - int r = 15 - m_skyDarken; - if (r < 0) - r = 0; - - return r; - } - - LevelChunk* pChunk = getChunk(pos); - return pChunk->getRawBrightness(pos, m_skyDarken); -} - -void Level::swap(const TilePos& pos1, const TilePos& pos2) -{ - TileID tile1 = getTile(pos1); - TileData data1 = getData(pos1); - TileID tile2 = getTile(pos2); - TileData data2 = getData(pos2); - - setTileAndDataNoUpdate(pos1, tile2, data2); - setTileAndDataNoUpdate(pos2, tile1, data1); - - updateNeighborsAt(pos1, tile2); - updateNeighborsAt(pos2, tile1); -} - -bool Level::isDay() const -{ - return m_skyDarken <= 3; -} - -bool Level::isEmptyTile(const TilePos& pos) const -{ - return getTile(pos) == 0; -} - -bool Level::isSolidTile(const TilePos& pos) const -{ - Tile* pTile = Tile::tiles[getTile(pos)]; - if (!pTile) return false; - - return pTile->isSolidRender(); -} - -Material* Level::getMaterial(const TilePos& pos) const -{ - Tile* pTile = Tile::tiles[getTile(pos)]; - if (!pTile) return Material::air; - - return pTile->m_pMaterial; + return nullptr; } Entity* Level::getEntity(Entity::ID id) const { - // @TODO: wtf? no map?? - - // prioritize players first. - for (std::vector::const_iterator it = m_players.begin(); it != m_players.end(); it++) + for (DimensionVector::const_iterator iter = m_dimensions.begin(); iter != m_dimensions.end(); iter++) { - Player* pEnt = *it; - if (pEnt->m_EntityID == id) - return pEnt; - } - for (std::vector::const_iterator it = m_entities.begin(); it != m_entities.end(); it++) - { - Entity* pEnt = *it; - if (pEnt->m_EntityID == id) - return pEnt; + Dimension* dimension = *iter; + Entity* entity = dimension->getEntity(id); + if (entity) + return entity; } return nullptr; } -unsigned int Level::getEntityCount(const EntityCategories& category) const -{ - EntityCategories::CategoriesMask mask = category.getCategoryMask(); - std::map::const_iterator it = m_entityCountsByCategory.find(mask); - if (it == m_entityCountsByCategory.end()) - return 0; - return it->second; -} - -const EntityVector* Level::getAllEntities() const -{ - return &m_entities; -} - -bool Level::hasChunk(const ChunkPos& pos) const +void Level::getEntities(DimensionId dimensionId, const EntityType& type, const AABB& aabb, std::vector& output) const { - return m_pChunkSource->hasChunk(pos); -} - -EntityVector Level::getEntities(Entity* pEntExclude, const AABB& aabb) const -{ - EntityVector entities = EntityVector(); - long lowerXBound = floor((aabb.min.x - 2.0f) / 16); long lowerZBound = floor((aabb.min.z - 2.0f) / 16); long upperXBound = floor((aabb.max.x + 2.0f) / 16); long upperZBound = floor((aabb.max.z + 2.0f) / 16); - for (long z = lowerZBound; z <= upperZBound; z++) - { - for (long x = lowerXBound; x <= upperXBound; x++) - { - if (!hasChunk(ChunkPos(x, z))) continue; - - LevelChunk* pChunk = getChunk(ChunkPos(x, z)); - pChunk->getEntities(pEntExclude, aabb, entities); - } - } - - return entities; -} - -void Level::setUpdateLights(bool b) -{ - m_bUpdateLights = b; -} - -bool Level::updateLights() -{ - // if more than 49 concurrent updateLights() calls? - if (field_B08 > 49) - return false; - - field_B08++; - - if (m_lightUpdates.empty()) - { - field_B08--; - return false; - } - - for (int i = 499; i; i--) - { - LightUpdate lu = *(m_lightUpdates.end() - 1); - m_lightUpdates.pop_back(); - - lu.update(this); - - if (m_lightUpdates.empty()) - { - field_B08--; - return false; - } - } - - field_B08--; - return true; -} - -bool Level::hasChunksAt(const TilePos& min, const TilePos& max) const -{ - if (min.y >= C_MAX_Y || max.y < 0) - return false; + ChunkSource* chunkSource = getDimension(dimensionId)->getChunkSource(); - ChunkPos cpMin(min), cpMax(max), cp = ChunkPos(); - for (cp.x = cpMin.x; cp.x <= cpMax.x; cp.x++) + for (int z = lowerZBound; z <= upperZBound; z++) { - for (cp.z = cpMin.z; cp.z <= cpMax.z; cp.z++) + for (int x = lowerXBound; x <= upperXBound; x++) { - if (!hasChunk(cp)) - return false; + LevelChunk* chunk = chunkSource->getAvailableChunk(ChunkPos(x, z)); + if (chunk) + chunk->getEntities(type, aabb, output); } } - return true; -} - -bool Level::hasChunksAt(const TilePos& pos, int rad) const -{ - return hasChunksAt(pos - rad, pos + rad); -} - -void Level::setBrightness(const LightLayer& ll, const TilePos& pos, int brightness) -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return; - - LevelChunk* pChunk = getChunk(pos); - pChunk->setBrightness(ll, pos, brightness); - - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) - { - LevelListener* pListener = *it; - pListener->tileBrightnessChanged(pos); - } -} - -void Level::setTime(int32_t time) -{ - _setTime(time); - - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) - { - LevelListener* pListener = *it; - pListener->timeChanged(time); - } -} - -int Level::getDirectSignal(const TilePos& pos, Facing::Name face) const -{ - TileID tile = getTile(pos); - if (!tile) return 0; - - return Tile::tiles[tile]->getDirectSignal(this, pos, face); -} - -int Level::getSignal(const TilePos& pos, Facing::Name face) const -{ - if (isSolidTile(pos)) - return hasDirectSignal(pos); - - TileID tile = getTile(pos); - if (!tile) return 0; - - return Tile::tiles[tile]->getSignal(this, pos, face); -} - -bool Level::hasDirectSignal(const TilePos& pos) const -{ - if (getDirectSignal(pos.below(), Facing::DOWN)) return true; - if (getDirectSignal(pos.above(), Facing::UP)) return true; - if (getDirectSignal(pos.north(), Facing::NORTH)) return true; - if (getDirectSignal(pos.south(), Facing::SOUTH)) return true; - if (getDirectSignal(pos.west(), Facing::WEST)) return true; - if (getDirectSignal(pos.east(), Facing::EAST)) return true; - return false; -} - -bool Level::hasNeighborSignal(const TilePos& pos) const -{ - if (getSignal(pos.below(), Facing::DOWN)) return true; - if (getSignal(pos.above(), Facing::UP)) return true; - if (getSignal(pos.north(), Facing::NORTH)) return true; - if (getSignal(pos.south(), Facing::SOUTH)) return true; - if (getSignal(pos.west(), Facing::WEST)) return true; - if (getSignal(pos.east(), Facing::EAST)) return true; - return false; -} - -bool Level::hasChunkAt(const TilePos& pos) const -{ - return hasChunk(pos); -} - -LevelChunk* Level::getChunkAt(const TilePos& pos) const -{ - return getChunk(pos); -} - -void Level::updateLight(const LightLayer& ll, const TilePos& tilePos1, const TilePos& tilePos2, bool unimportant) -{ - static int nUpdateLevels; - - if ((m_pDimension->m_bHasCeiling && &ll == &LightLayer::Sky) || !m_bUpdateLights) - return; - - nUpdateLevels++; - if (nUpdateLevels == 50) - { - nUpdateLevels--; - return; - } - - TilePos idkbro((tilePos2.x + tilePos1.x) / 2, (tilePos2.y + tilePos1.y) / 2, (tilePos2.z + tilePos1.z) / 2); - - if (!hasChunkAt(idkbro) || getChunkAt(idkbro)->isEmpty()) - { - nUpdateLevels--; - return; - } - - size_t size = m_lightUpdates.size(); - if (unimportant) + if (type == EntityType::PLAYER) { - size_t count = 5; - if (count > size) - count = size; - - for (size_t i = 0; i < count; i++) + for (std::vector::const_iterator iter = m_players.begin(); iter != m_players.end(); iter++) { - LightUpdate& update = m_lightUpdates[size - i - 1]; - if (update.m_lightLayer == &ll && update.expandToContain(tilePos1, tilePos2)) - { - nUpdateLevels--; - return; - } + Player* player = *iter; + if (player->m_hitbox.intersect(aabb)) + output.push_back(player); } } - - m_lightUpdates.push_back(LightUpdate(ll, tilePos1, tilePos2)); - - // huh?? - if (m_lightUpdates.size() > 1000000) - m_lightUpdates.clear(); - - nUpdateLevels--; } -void Level::updateLight(const LightLayer& ll, const TilePos& tilePos1, const TilePos& tilePos2) +void Level::updateLights() { - updateLight(ll, tilePos1, tilePos2, true); -} - -void Level::updateLightIfOtherThan(const LightLayer& ll, const TilePos& tilePos, int bright) -{ - if (m_pDimension->m_bHasCeiling && &ll == &LightLayer::Sky) - return; - - if (!hasChunkAt(tilePos)) - return; - - if (&ll == &LightLayer::Sky) + if (!m_lightUpdates.empty() && !m_processingLightUpdates) { - if (isSkyLit(tilePos)) - bright = 15; - } - else if (&ll == &LightLayer::Block) - { - TileID tile = getTile(tilePos); - if (bright < Tile::lightEmission[tile]) - bright = Tile::lightEmission[tile]; - } + m_processingLightUpdates = true; // NOTE: presumably meant to be here, not in PE - int oldbr = getBrightness(ll, tilePos); - if (bright != oldbr) - { - updateLight(ll, tilePos, tilePos); + BackgroundQueuePool::getInstance().getMain().queue( + std::bind(&Level::_updateLightsTask, this), + BackgroundQueue::NOP, + 1 + ); } } -bool Level::isSkyLit(const TilePos& pos) const -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y) - // there's nothing out there! - return false; - - if (pos.y >= C_MAX_Y) - return true; - - if (!hasChunk(pos)) - return false; - - return getChunk(pos)->isSkyLit(pos); -} - -bool Level::setTileAndDataNoUpdate(const TilePos& pos, TileID tile, TileData data) -{ - return setTileAndData(pos, tile, data, TileChange::UPDATE_LISTENERS); -} - -int Level::getHeightmap(const TilePos& pos) +bool Level::_updateLightsTask() { - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z) - // there's nothing out there! - return 0; - - if (!hasChunk(pos)) - return 0; - - return getChunkAt(pos)->getHeightmap(pos); -} - -void Level::lightColumnChanged(int x, int z, int y1, int y2) -{ - if (y1 > y2) + while (!m_lightUpdates.empty()) { - int tmp = y1; - y1 = y2; - y2 = tmp; + LightUpdate& update = m_lightUpdates.back(); + update.updateFast(); + m_lightUpdates.pop_back(); } - setTilesDirty(TilePos(x, y1, z), TilePos(x, y2, z)); -} - -bool Level::setDataNoUpdate(const TilePos& pos, TileData data) -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return false; - - if (!hasChunk(pos)) - return false; - - LevelChunk* pChk = getChunk(pos); - if (pChk->getData(pos) == data) - return false; // no update - - pChk->setData(pos, data); + m_processingLightUpdates = false; return true; } -bool Level::setTileNoUpdate(const TilePos& pos, TileID tile) -{ - return setTileAndDataNoUpdate(pos, tile, 0); -} - -void Level::sendTileUpdated(const TilePos& pos) -{ - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) - { - LevelListener* pListener = *it; - pListener->tileChanged(pos); - } -} - -void Level::neighborChanged(const TilePos& pos, TileID tile) -{ - if (field_30 || m_bIsClientSide) return; - - Tile* pTile = Tile::tiles[getTile(pos)]; - if (pTile) - pTile->neighborChanged(this, pos, tile); -} - -void Level::updateNeighborsAt(const TilePos& pos, TileID tile) -{ - neighborChanged(pos.west(), tile); - neighborChanged(pos.east(), tile); - neighborChanged(pos.below(), tile); - neighborChanged(pos.above(), tile); - neighborChanged(pos.north(), tile); - neighborChanged(pos.south(), tile); -} - -void Level::tileUpdated(const TilePos& pos, TileID tile) -{ - //sendTileUpdated(pos); // not in 0.7.0 - updateNeighborsAt(pos, tile); -} - -bool Level::setTileAndData(const TilePos& pos, TileID tile, TileData data, TileChange::UpdateFlags updateFlags) -{ - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return false; - - if (!hasChunk(pos)) - return false; - - LevelChunk* pChunk = getChunk(pos); - - TileChange change(updateFlags); - - TileID oldTile = TILE_AIR; - if (change.isUpdateNeighbors()) - oldTile = pChunk->getTile(pos); - - bool result = pChunk->setTileAndData(pos, tile, data); - if (result) - { - if (change.isUpdateListeners() && (!m_bIsClientSide || !change.isUpdateSilent())) - { - // Send update to level listeners - sendTileUpdated(pos); - } - if (!m_bIsClientSide && change.isUpdateNeighbors()) - { - // Update neighbors - tileUpdated(pos, oldTile); - } - } - - return result; - - /*if (setTileAndDataNoUpdate(pos, tile, data)) - { - tileUpdated(pos, tile); - return true; - } - return false;*/ -} - -bool Level::setData(const TilePos& pos, TileData data, TileChange::UpdateFlags updateFlags) +int32_t Level::setTime(int32_t time) { - //@BUG: checking x >= C_MAX_X, but not z >= C_MAX_Z. - if (pos.x < C_MIN_X || pos.z < C_MIN_Z || pos.x >= C_MAX_X || pos.z > C_MAX_Z || pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - // there's nothing out there! - return false; - - LevelChunk* pChunk = getChunk(pos); - if (!pChunk) - return false; - - TileChange change(updateFlags); + const int totalTime = 192000; - bool result = pChunk->setData(pos, data); - if (result) - { - TileID tileId = pChunk->getTile(pos); - - if (change.isUpdateListeners() && (!m_bIsClientSide || !change.isUpdateSilent())) - { - // Send update to level listeners - sendTileUpdated(pos); - } - if (!m_bIsClientSide && change.isUpdateNeighbors()) - { - // Update neighbors - tileUpdated(pos, tileId); - } - } - - return result; - - /*if (setDataNoUpdate(pos, data)) - { - tileUpdated(pos, getTile(pos)); - return true; - } - return false;*/ + int32_t newTime = time % totalTime; + m_pLevelData->setTime(newTime); + return newTime < m_lastGameTimeSync ? (totalTime - m_lastGameTimeSync + newTime) : (newTime - m_lastGameTimeSync); } -bool Level::setTile(const TilePos& pos, TileID tile, TileChange::UpdateFlags updateFlags) +void Level::_syncTime(int32_t time) { - return setTileAndData(pos, tile, 0, updateFlags); -} + if (m_bIsClientSide) + return; -void Level::setTilesDirty(const TilePos& min, const TilePos& max) -{ - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) - { - LevelListener* pListener = *it; - pListener->setTilesDirty(min, max); - } + broadcastAll(new SetTimePacket(time)); } void Level::entityAdded(Entity* pEnt) { - // @TODO: change this check (and the matching entityRemoved check) to a BST at some point. this works for now - const EntityCategories& categories = pEnt->getDescriptor().getCategories(); - for (unsigned int i = 0; i < EntityCategories::allCount; i++) - { - EntityCategories::CategoriesMask category = EntityCategories::all[i]; - if (categories.contains(category)) - m_entityCountsByCategory[category]++; - } - - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->entityAdded(pEnt); @@ -801,15 +178,7 @@ void Level::entityAdded(Entity* pEnt) void Level::entityRemoved(Entity* pEnt) { - const EntityCategories& categories = pEnt->getDescriptor().getCategories(); - for (unsigned int i = 0; i < EntityCategories::allCount; i++) - { - EntityCategories::CategoriesMask category = EntityCategories::all[i]; - if (categories.contains(category)) - m_entityCountsByCategory[category]--; - } - - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->entityRemoved(pEnt); @@ -818,59 +187,13 @@ void Level::entityRemoved(Entity* pEnt) void Level::levelEvent(const LevelEvent& event) { - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->levelEvent(event); } } -void Level::tileEvent(const TileEvent& event) -{ - TileID tile = getTile(event.pos); - if (tile > TILE_AIR) - Tile::tiles[tile]->triggerEvent(this, event); - - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) - { - LevelListener* pListener = *it; - pListener->tileEvent(event); - } -} - -AABBVector* Level::getCubes(const Entity* pEntUnused, const AABB& aabb) -{ - m_aabbs.clear(); - - long lowerX = floor(aabb.min.x); - long upperX = floor(aabb.max.x + 1); - long lowerY = floor(aabb.min.y); - long upperY = floor(aabb.max.y + 1); - long lowerZ = floor(aabb.min.z); - long upperZ = floor(aabb.max.z + 1); - - for (long x = lowerX; x <= upperX; x++) - { - for (long z = lowerZ; z <= upperZ; z++) - { - if (!hasChunkAt(TilePos(x, 64, z))) continue; - - // - 1 fixes tiles like the fence - for (long y = lowerY - 1; y <= upperY; y++) - { - // Obviously this is problematic, but using longs in our for loops rather than - // ints helps prevents crashes at extreme distances from 0,0 - TilePos tp((int)x, (int)y, (int)z); - Tile* pTile = Tile::tiles[getTile(tp)]; - if (pTile) - pTile->addAABBs(this, tp, &aabb, m_aabbs); - } - } - } - - return &m_aabbs; -} - std::vector* Level::getLightsToUpdate() { return &m_lightUpdates; @@ -922,114 +245,14 @@ Player* Level::getNearestAttackablePlayer(const Vec3& source, float maxDist, con return _getNearestPlayer(source, maxDist, true); } -bool Level::containsFireTile(const AABB& aabb) -{ - TilePos min(aabb.min), - max(aabb.max + 1); - - if (!hasChunksAt(min, max)) - return false; - - TilePos pos(min); - for (pos.x = min.x; pos.x < max.x; pos.x++) - for (pos.y = min.y; pos.y < max.y; pos.y++) - for (pos.z = min.z; pos.z < max.z; pos.z++) - { - TileID tileID = getTile(pos); - - if (tileID == Tile::fire->m_ID || tileID == Tile::lava->m_ID || tileID == Tile::calmLava->m_ID) - return true; - } - - return false; -} - -bool Level::containsAnyLiquid(const AABB& aabb) -{ - TilePos min(aabb.min), - max(aabb.max + 1); - - if (!hasChunksAt(min, max)) - return false; - - TilePos pos(min); - for (pos.x = min.x; pos.x < max.x; pos.x++) - for (pos.y = min.y; pos.y < max.y; pos.y++) - for (pos.z = min.z; pos.z < max.z; pos.z++) - { - TileID tileID = getTile(pos); - - if (Tile::tiles[tileID]) - { - if (Tile::tiles[tileID]->m_pMaterial->isLiquid()) - return true; - } - } - - return false; -} - -bool Level::containsLiquid(const AABB& aabb, const Material* pMtl) -{ - TilePos min(aabb.min), - max(aabb.max + 1); - - if (!hasChunksAt(min, max)) - return false; - - TilePos pos(min); - for (pos.x = min.x; pos.x < max.x; pos.x++) - for (pos.y = min.y; pos.y < max.y; pos.y++) - for (pos.z = min.z; pos.z < max.z; pos.z++) - { - TileID tileID = getTile(pos); - - if (!Tile::tiles[tileID] || Tile::tiles[tileID]->m_pMaterial != pMtl) - continue; - - TileData data = getData(pos); - - float height; - if (data <= 7) - height = (float(pos.y) + 1.0f) + float(data) / 8.0f; - else - height = float(pos.y + 1); - - if (aabb.min.y <= height) - return true; - } - - return false; -} - -bool Level::containsMaterial(const AABB& aabb, const Material* pMtl) -{ - TilePos min(aabb.min), - max(aabb.max + 1); - - if (!hasChunksAt(min, max)) - return false; - - TilePos pos(min); - for (pos.x = min.x; pos.x < max.x; pos.x++) - for (pos.y = min.y; pos.y < max.y; pos.y++) - for (pos.z = min.z; pos.z < max.z; pos.z++) - { - TileID tileID = getTile(pos); - - if (Tile::tiles[tileID] && Tile::tiles[tileID]->m_pMaterial == pMtl) - return true; - } - - return false; -} - bool Level::checkAndHandleWater(const AABB& aabb, const Material* pMtl, Entity* pEnt) { + TileSource* source = pEnt->m_tileSource; + TilePos min(aabb.min), max(aabb.max + 1); - if (!hasChunksAt(min, max)) + if (!source->hasChunksAt(min, max)) return false; Vec3 v; @@ -1042,15 +265,15 @@ bool Level::checkAndHandleWater(const AABB& aabb, const Material* pMtl, Entity* { for (pos.z = min.z; pos.z < max.z; pos.z++) { - Tile* pTile = Tile::tiles[getTile(pos)]; + Tile* pTile = Tile::tiles[source->getTile(pos)]; if (!pTile || pTile->m_pMaterial != pMtl) continue; - TileData data = getData(pos); + TileData data = source->getData(pos); int level = data <= 7 ? data + 1 : 1; if (float(max.y) >= float(pos.y + 1) - float(level) / 9.0f) { - pTile->handleEntityInside(this, pos, pEnt, v); + pTile->handleEntityInside(source, pos, pEnt, v); bInWater = true; } } @@ -1067,130 +290,12 @@ bool Level::checkAndHandleWater(const AABB& aabb, const Material* pMtl, Entity* const TilePos& Level::getSharedSpawnPos() const { - return m_pLevelData->getSpawn(); -} - -TileID Level::getTopTile(const TilePos& pos) const -{ - int y; - for (y = C_MAX_Y / 2 - 1; !isEmptyTile(TilePos(pos.x, y + 1, pos.z)); y++); - return getTile(TilePos(pos.x, y, pos.z)); -} - -int Level::getTopTileY(const TilePos& pos) const -{ - int y; - for (y = C_MAX_Y / 2 - 1; !isEmptyTile(TilePos(pos.x, y + 1, pos.z)); y++); - return y; -} - -int Level::getTopSolidBlock(const TilePos& tilePos) const -{ - LevelChunk* pChunk = getChunkAt(tilePos); - if (!pChunk) - return C_MAX_Y; - - TilePos pos(tilePos); - pos.y = C_MAX_Y - 1; - while (true) - { - if (!getMaterial(pos)->blocksMotion()) - break; - if (!pos.y) - return -1; - pos.y--; - } - - ChunkTilePos ctp(pos); - if (ctp.y <= C_MIN_Y) - return 0; - - while (true) - { - TileID tile = pChunk->getTile(ctp); - if (tile) - { - if (Tile::tiles[tile]->m_pMaterial->blocksMotion()) - return ctp.y + 1; - - if (Tile::tiles[tile]->m_pMaterial->isLiquid()) - break; - } - if (!--ctp.y) - return -1; - } - - return ctp.y + 1; -} - -void Level::validateSpawn() -{ - if (m_pLevelData->getYSpawn() <= 0) - m_pLevelData->setYSpawn(C_MAX_Y / 2); - - TilePos spawn(m_pLevelData->getSpawn()); -#ifndef ORIGINAL_CODE - int nAttempts = 0; -#endif - - // @TODO: fix these gotos - if (getTopTile(spawn)) - goto label_10; - - TileID tile; - - do - { - // While the spawn isn't valid - do - { - spawn.x += m_random.nextInt(8) - m_random.nextInt(8); - spawn.z += m_random.nextInt(8) - m_random.nextInt(8); - - // avoid spawning near world border - if (spawn.x < 4) spawn.x += 8; - if (spawn.z < 4) spawn.z += 8; - if (spawn.x > C_MAX_CHUNKS_X * 16 - 4) spawn.x -= 8; - if (spawn.z > C_MAX_CHUNKS_Z * 16 - 4) spawn.z -= 8; - - #ifndef ORIGINAL_CODE - nAttempts++; - if (nAttempts >= 100000) - goto _failure; - #endif - } - while (!getTopTile(spawn)); - - label_10: - tile = getTopTile(spawn); - } - while (tile == Tile::invisible_bedrock->m_ID); - - m_pLevelData->setXSpawn(spawn.x); - m_pLevelData->setZSpawn(spawn.z); - -#ifndef ORIGINAL_CODE - return; - -_failure: - - /* - m_pLevelData->m_spawnPos.x = C_MAX_CHUNKS_X * 16 / 2; - m_pLevelData->m_spawnPos.z = C_MAX_CHUNKS_X * 16 / 2; - m_pLevelData->m_spawnPos.y = C_MAX_Y; - */ - - m_pLevelData->setSpawn(TilePos(0, 32, 0)); - - LOG_W("Failed to validate spawn point, using (%d, %d, %d)", m_pLevelData->getXSpawn(), m_pLevelData->getYSpawn(), m_pLevelData->getZSpawn()); - - return; -#endif + return m_pLevelData->getSpawn(); } void Level::removeAllPendingEntityRemovals() { - Util::removeAll(m_entities, m_pendingEntityRemovals); + /*Util::removeAll(m_entities, m_pendingEntityRemovals); for (EntityVector::iterator it = m_pendingEntityRemovals.begin(); it != m_pendingEntityRemovals.end(); it++) { @@ -1203,57 +308,60 @@ void Level::removeAllPendingEntityRemovals() entityRemoved(ent); //@BUG: MEMORY LEAK -- probably leaking entities here? - } + }*/ m_pendingEntityRemovals.clear(); } -void Level::removeEntities(const EntityVector& vec) +bool Level::addEntity(std::unique_ptr entity) { - m_pendingEntityRemovals.insert(m_pendingEntityRemovals.end(), vec.begin(), vec.end()); -} + Dimension& dimension = entity->m_tileSource->getDimension(); -bool Level::removeEntity(Entity* pEnt) -{ - pEnt->remove(); + if (dimension.hasEntity(*entity)) + return false; + + LevelChunk* chunk = entity->m_tileSource->getChunk(entity->m_pos); + if (!chunk) + return false; - if (pEnt->isPlayer()) - return Util::remove(m_players, (Player*)pEnt); + Entity* entityTemp = entity.get(); - return false; + chunk->addEntity(std::move(entity)); + entityTemp->m_bInAChunk = true; + + dimension.addEntity(*entityTemp); + entityAdded(entityTemp); + + return true; } -bool Level::addEntity(Entity* pEnt) +bool Level::addEntity(Entity* entity) { - Entity* pOldEnt = getEntity(pEnt->hashCode()); - if (pOldEnt) - { - LOG_W("Entity %d already exists. Replacing...", pEnt->hashCode()); - removeEntity(pOldEnt); - } - - //@NOTE: useless Mth::floor() calls - Mth::floor(pEnt->m_pos.x / 16); - Mth::floor(pEnt->m_pos.z / 16); + return addEntity(std::unique_ptr(entity)); +} - //@NOTE: double check. Looks like someone just hacked it in - //@BUG: Camera doesn't work. This might be a side effect of having a demo mode? - //@BUG: Leaking the entity pointer. -#ifdef ORIGINAL_CODE - if (!pEnt->isPlayer()) - return false; -#endif +void Level::removeEntity(Entity& entity) +{ + // TODO: this check needs to go away from here, i need to find where this is originally called for player + if (entity.isPlayer()) + Util::remove(m_players, (Player*)&entity); - if (pEnt->isPlayer()) - { - m_players.push_back((Player*)pEnt); - } + Dimension& dimension = entity.m_tileSource->getDimension(); - m_entities.push_back(pEnt); + dimension.removeEntity(entity); + entityRemoved(&entity); +} - entityAdded(pEnt); +void Level::removeEntity(std::unique_ptr&& entity) +{ + removeEntity(*entity); + m_pendingEntityRemovals.push_back(std::move(entity)); +} - return true; +void Level::removeEntity(Entity*& entity) +{ + removeEntity(std::unique_ptr(entity)); + entity = nullptr; } void Level::loadPlayer(Player& player) @@ -1269,12 +377,8 @@ void Level::loadPlayer(Player& player) // 0.2.1 had us only adding the player if LevelData had a CompoundTag // who cares if it doesn't? - addEntity(&player); -} - -void Level::prepare() -{ - while (m_pChunkSource->tick()); + if (addEntity(std::make_unique(player))) + m_players.push_back(&player); } void Level::saveLevelData() @@ -1287,11 +391,6 @@ void Level::savePlayerData() m_pLevelStorage->savePlayerData(*m_pLevelData, m_players); } -void Level::saveAllChunks() -{ - m_pChunkSource->saveAll(); -} - void Level::saveGame() { if (m_pLevelStorage) @@ -1309,183 +408,6 @@ void Level::loadEntities() } } -void Level::sendEntityData() -{ - if (!m_pRakNetInstance) - return; - - // Inlined on 0.2.1, god bless PerfTimer - for (EntityVector::iterator it = m_entities.begin(); it != m_entities.end(); it++) - { - Entity* ent = *it; - SynchedEntityData& data = ent->getEntityData(); - if (data.isDirty()) - m_pRakNetInstance->send(new SetEntityDataPacket(ent->m_EntityID, data)); - } -} - -#ifdef ENH_IMPROVED_SAVING -void Level::saveUnsavedChunks() -{ - m_pChunkSource->saveUnsaved(); -} -#endif - -void Level::setInitialSpawn() -{ - m_bCalculatingInitialSpawn = true; - - int spawnX = C_MAX_CHUNKS_X * 16 / 2, spawnZ = C_MAX_CHUNKS_Z * 16 / 2; -#ifndef ORIGINAL_CODE - int nAttempts = 0; -#endif - - while (true) - { - if (m_pDimension->isValidSpawn(TilePos(spawnX, 64, spawnZ))) - break; - - spawnX += m_random.nextInt(32) - m_random.nextInt(32); - spawnZ += m_random.nextInt(32) - m_random.nextInt(32); - - if (spawnX < 4) spawnX += 32; - if (spawnZ < 4) spawnZ += 32; - if (spawnX >= C_MAX_CHUNKS_X * 16 - 4) spawnX -= 32; - if (spawnZ >= C_MAX_CHUNKS_Z * 16 - 4) spawnZ -= 32; - -#ifndef ORIGINAL_CODE - if (++nAttempts > 100000) - goto _failure; -#endif - } - - m_pLevelData->setSpawn(TilePos(spawnX, 64, spawnZ)); - - m_bCalculatingInitialSpawn = false; - -#ifndef ORIGINAL_CODE - return; - -_failure: - - // m_pLevelData->setSpawn(C_MAX_CHUNKS_X * 16 / 2, C_MAX_Y, C_MAX_CHUNKS_X * 16 / 2); - - m_pLevelData->setSpawn(TilePos(0, 32, 0)); - - LOG_W("Failed to validate spawn point, using (%d, %d, %d)", m_pLevelData->getXSpawn(), m_pLevelData->getYSpawn(), m_pLevelData->getZSpawn()); - - return; -#endif -} - -bool Level::canSeeSky(const TilePos& pos) const -{ - LevelChunk* pChunk = getChunk(pos); - - //@BUG: no nullptr check -#ifndef ORIGINAL_CODE - if (!pChunk) - return true; -#endif - - return pChunk->isSkyLit(pos); -} - -Vec3 Level::getSkyColor(const Entity& entity, float f) const -{ - Vec3 result; - - float fTODCosAng = Mth::cos(getSunAngle(f)); - - result.z = 2 * fTODCosAng + 0.5f; - if (result.z < 0.0f) - result.z = 0.0f; - if (result.z > 1.0f) - result.z = 1.0f; - - // @NOTE: Unused result. In JE, it tries to get the biome that the player is standing in. - //Mth::floor(entity.m_pos.x); - //Mth::floor(entity.m_pos.z); - - result.x = result.z * 0.6f; - result.y = result.x; - - return result; -} - -Vec3 Level::getFogColor(float f) const -{ - return m_pDimension->getFogColor(getTimeOfDay(f), f); -} - -Vec3 Level::getCloudColor(float f) const -{ - Vec3 result; - - float fTODCosAng = Mth::cos(getSunAngle(f)); - - float mult = 2 * fTODCosAng + 0.5f; - if (mult < 0.0f) - mult = 0.0f; - if (mult > 1.0f) - mult = 1.0f; - - result.x = mult * 0.9f + 0.1f; - result.y = result.x; - result.z = mult * 0.85f + 0.15f; - - return result; -} - -bool Level::isUnobstructed(AABB* aabb) const -{ - EntityVector entities = getEntities(nullptr, *aabb); - if (entities.size() <= 0) - return true; - - for (std::vector::iterator it = entities.begin(); it != entities.end(); it++) - { - Entity* pEnt = *it; - if (!pEnt->m_bRemoved && pEnt->m_bBlocksBuilding) - return false; - } - - return true; -} - -bool Level::mayInteract(Player* player, const TilePos& pos) const -{ - return true; -} - -bool Level::mayPlace(TileID tile, const TilePos& pos, bool b) const -{ - TileID oldTile = getTile(pos); - - Tile *pTile = Tile::tiles[tile], *pOldTile = Tile::tiles[oldTile]; - - if (pTile == nullptr) - return false; - - AABB* aabb = pTile->getAABB(this, pos); - - if (!b && aabb && !isUnobstructed(aabb)) - return false; - - if (pOldTile == Tile::water || - pOldTile == Tile::calmWater || - pOldTile == Tile::lava || - pOldTile == Tile::calmLava || - pOldTile == Tile::fire || - pOldTile == Tile::topSnow) - return true; - - if (pOldTile || tile <= 0) - return false; - - return pTile->mayPlace(this, pos); -} - void Level::broadcastAll(Packet* packet) { assert(!m_bIsClientSide); @@ -1527,317 +449,56 @@ void Level::broadcastEntityEvent(const Entity& entity, Entity::EventType::ID eve m_pRakNetInstance->send(new EntityEventPacket(entity.m_EntityID, eventId)); } -void Level::removeListener(LevelListener* listener) -{ - std::vector::iterator iter = std::find(m_levelListeners.begin(), m_levelListeners.end(), listener); - if (iter != m_levelListeners.end()) - m_levelListeners.erase(iter); -} - void Level::addListener(LevelListener* listener) { - m_levelListeners.push_back(listener); -} - -void Level::tickPendingTicks(bool b) -{ - int size = 10000; // note: 65,536 in Minecraft Java - if (size > int(m_pendingTicks.size())) - size = int(m_pendingTicks.size()); - - for (int i = 0; i < size; i++) - { - const TickNextTickData& t = *m_pendingTicks.begin(); - if (!b && t.delay > m_pLevelData->getTime()) - break; - - if (hasChunksAt(t.tilePos - 8, t.tilePos + 8)) - { - TileID tile = getTile(t.tilePos); - if (tile == t.tileId && tile > 0) - Tile::tiles[tile]->tick(this, t.tilePos, &m_random); - } - - m_pendingTicks.erase(m_pendingTicks.begin()); - } + m_listeners.push_back(listener); } -void Level::tickTiles() +void Level::removeListener(LevelListener* listener) { - m_chunksToUpdate.clear(); - - for (std::vector::iterator it = m_players.begin(); it != m_players.end(); it++) - { - Player* player = *it; - - int chkX = Mth::floor(player->m_pos.x / 16.0f); - int chkZ = Mth::floor(player->m_pos.z / 16.0f); - - for (int x = -C_TICK_DISTANCE_CHKS; x <= C_TICK_DISTANCE_CHKS; x++) - { - for (int z = -C_TICK_DISTANCE_CHKS; z <= C_TICK_DISTANCE_CHKS; z++) - { - m_chunksToUpdate.insert(ChunkPos(chkX + x, chkZ + z)); - } - } - } - - for (std::set::iterator it = m_chunksToUpdate.begin(); it != m_chunksToUpdate.end(); it++) - { - ChunkPos pos = *it; - LevelChunk* pChunk = getChunk(pos); - - for (int i = 0; i < 80; i++) - { - m_randValue = (int64_t)m_randValue * 3 + m_addend; - int rand = m_randValue >> 2; - - TilePos tilePos( - (rand) & 15, - (rand >> 16) & 127, - (rand >> 8) & 15); - - TileID tile = pChunk->getTile(tilePos); - if (Tile::shouldTick[tile]) - Tile::tiles[tile]->tick(this, tilePos + pos, &m_random); - } - } + std::vector::iterator iter = std::find(m_listeners.begin(), m_listeners.end(), listener); + if (iter != m_listeners.end()) + m_listeners.erase(iter); } -void Level::tick(Entity* pEnt, bool shouldTick) +void Level::tick() { - TilePos tilePos(pEnt->m_pos); - - if (shouldTick) - { - if (!hasChunksAt(TilePos(tilePos.x - 32, 0, tilePos.z - 32), TilePos(tilePos.x + 32, 128, tilePos.z + 32))) - { - LOG_W("Not updating entity %d because we don't have chunks around it loaded", pEnt->m_EntityID); - return; - } - - pEnt->m_posPrev = pEnt->m_pos; - pEnt->m_oRot = pEnt->m_rot; + tickEntities(); - if (pEnt->m_bInAChunk) - pEnt->tick(); - } - else - { - pEnt->m_posPrev = pEnt->m_pos; - pEnt->m_oRot = pEnt->m_rot; - } - - ChunkPos cp(pEnt->m_pos); - - if (!pEnt->m_bInAChunk || cp != pEnt->m_chunkPos) - { - // move the entity to the new chunk - if (pEnt->m_bInAChunk && hasChunk(pEnt->m_chunkPos)) - { - getChunk(pEnt->m_chunkPos)->removeEntity(pEnt); - } + tickTime(); - if (hasChunk(cp)) - { - getChunk(cp)->addEntity(pEnt); - } - else - { - pEnt->m_bInAChunk = false; - } - } - else if (pEnt->m_bInAChunk) + for (DimensionVector::iterator it = m_dimensions.begin(); it != m_dimensions.end(); it++) { - if (pEnt->m_chunkPosY != ChunkPos::ToChunkCoordinate(pEnt->m_pos.y)) - { - getChunk(cp)->updateEntity(pEnt); - } + Dimension& dimension = **it; + dimension.tick(); } -} - -void Level::tick(Entity* pEnt) -{ - tick(pEnt, true); -} - -int TICKSPERSECOND = 0; -int LASTTICKED = 0; - -void Level::tick() -{ - m_pMobSpawner->tick(*this, m_difficulty > 0, true); - m_pChunkSource->tick(); -#ifdef ENH_RUN_DAY_NIGHT_CYCLE - updateSkyDarken(); - - setTime(getTime() + 1); -#endif - - tickPendingTicks(false); - tickTiles(); - - sendEntityData(); + m_pLevelData->incrementCurrentTick(); } void Level::tickEntities() { // inlined in the original removeAllPendingEntityRemovals(); - - for (size_t i = 0; i < m_entities.size(); i++) - { - Entity* pEnt = m_entities[i]; - - if (!pEnt->m_bRemoved) - { - tick(pEnt); - } - else if (!pEnt->isPlayer() || pEnt->m_bForceRemove) - { - if (pEnt->m_bInAChunk && hasChunk(pEnt->m_chunkPos)) - getChunk(pEnt->m_chunkPos)->removeEntity(pEnt); - - m_entities.erase(m_entities.begin() + i); - i--; - - entityRemoved(pEnt); - delete pEnt; - } - } -} - -HitResult Level::clip(Vec3 v1, Vec3 v2, bool flag) const -{ - TilePos tp1(v1), tp2(v2); - int counter = 200; - while (counter-- >= 0) - { - if (tp1 == tp2) - break; - - float xd = 999.0f; - float yd = 999.0f; - float zd = 999.0f; - if (tp2.x > tp1.x) xd = (float)tp1.x + 1.0f; - if (tp2.x < tp1.x) xd = (float)tp1.x + 0.0f; - if (tp2.y > tp1.y) yd = (float)tp1.y + 1.0f; - if (tp2.y < tp1.y) yd = (float)tp1.y + 0.0f; - if (tp2.z > tp1.z) zd = (float)tp1.z + 1.0f; - if (tp2.z < tp1.z) zd = (float)tp1.z + 0.0f; - float xe = 999.0f; - float ye = 999.0f; - float ze = 999.0f; - float xl = v2.x - v1.x; - float yl = v2.y - v1.y; - float zl = v2.z - v1.z; - if (xd != 999.0f) xe = (float)(xd - v1.x) / xl; - if (yd != 999.0f) ye = (float)(yd - v1.y) / yl; - if (zd != 999.0f) ze = (float)(zd - v1.z) / zl; - int hitSide = 0; - if (xe >= ye || xe >= ze) - { - if (ye >= ze) - { - hitSide = tp2.z <= tp1.z ? Facing::SOUTH : Facing::NORTH; - v1.x = v1.x + (float)(xl * ze); - v1.y = v1.y + (float)(yl * ze); - v1.z = zd; - } - else - { - hitSide = (tp2.y <= tp1.y) ? Facing::UP : Facing::DOWN; - v1.x = v1.x + (float)(xl * ye); - v1.y = yd; - v1.z = v1.z + (float)(zl * ye); - } - } - else - { - hitSide = tp2.x <= tp1.x ? Facing::EAST : Facing::WEST; - v1.x = xd; - v1.y = v1.y + (float)(yl * xe); - v1.z = v1.z + (float)(zl * xe); - } - - Vec3 hitVec(v1); - - // Correct the hit positions for each vector - hitVec.x = (float)Mth::floor(v1.x); - tp1.x = (int)hitVec.x; - if (hitSide == Facing::EAST) - { - tp1.x--; - hitVec.x += 1.0; - } - - - hitVec.y = (float)Mth::floor(v1.y); - tp1.y = (int)hitVec.y; - if (hitSide == Facing::UP) - { - tp1.y--; - hitVec.y += 1.0; - } - - - hitVec.z = (float)Mth::floor(v1.z); - tp1.z = (int)hitVec.z; - if (hitSide == Facing::SOUTH) - { - tp1.z--; - hitVec.z += 1.0; - } - - TileID tile = getTile(tp1); - int data = getData(tp1); - Tile* pTile = Tile::tiles[tile]; - - if (tile > 0 && pTile->mayPick(data, false)) - { - HitResult hr = pTile->clip(this, tp1, v1, v2); - if (hr.isHit()) - return hr; - } - } - - return HitResult(); } -HitResult Level::clip(const Vec3& a, const Vec3& b) const +void Level::tickTime() { - return clip(a, b, false); -} - -void Level::addToTickNextTick(const TilePos& tilePos, int d, int delay) -{ - TickNextTickData tntd(tilePos, d); - if (m_bInstantTicking) - { - // @NOTE: Don't know why this check wasn't just placed at the beginning. - if (!hasChunksAt(tilePos, 8)) - return; + if (m_bIsClientSide) + return; - TileID tile = getTile(tntd.tilePos); - if (tile > 0 && tile == tntd.tileId) - Tile::tiles[tntd.tileId]->tick(this, tntd.tilePos, &m_random); - } - else + int32_t newTime = getTime() + 1; + int32_t timeSinceLastSync = setTime(newTime); + if (timeSinceLastSync > 255) { - if (!hasChunksAt(tilePos, 8)) - return; - - if (d > 0) - tntd.setDelay(delay + getTime()); - - m_pendingTicks.insert(tntd); + _syncTime(newTime); + m_lastGameTimeSync = newTime; } } void Level::takePicture(TripodCamera* pCamera, Entity* pOwner) { - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->takePicture(pCamera, pOwner); @@ -1846,7 +507,7 @@ void Level::takePicture(TripodCamera* pCamera, Entity* pOwner) void Level::addParticle(const std::string& name, const Vec3& pos, const Vec3& dir) { - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->addParticle(name, pos, dir); @@ -1855,7 +516,7 @@ void Level::addParticle(const std::string& name, const Vec3& pos, const Vec3& di void Level::playSound(Entity* entity, const std::string& name, float volume, float pitch) { - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->playSound(name, Vec3(entity->m_pos.x, entity->m_pos.y - entity->m_heightOffset, entity->m_pos.z), volume, pitch); @@ -1864,59 +525,27 @@ void Level::playSound(Entity* entity, const std::string& name, float volume, flo void Level::playSound(const Vec3& pos, const std::string& name, float a, float b) { - for (std::vector::iterator it = m_levelListeners.begin(); it != m_levelListeners.end(); it++) + for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); it++) { LevelListener* pListener = *it; pListener->playSound(name, pos, a, b); } } -void Level::animateTick(const TilePos& pos) +void Level::animateTick(Entity* entity) { - Random random; + TileSource* source = entity->m_tileSource; // frequency is 1000 on JE, 100 on PE for (int i = 0; i < 100; i++) { - TilePos aPos(pos.x + m_random.nextInt(16) - m_random.nextInt(16), - pos.y + m_random.nextInt(16) - m_random.nextInt(16), - pos.z + m_random.nextInt(16) - m_random.nextInt(16)); - TileID tile = getTile(aPos); + TilePos aPos(entity->m_pos.x + m_random.nextInt(16) - m_random.nextInt(16), + entity->m_pos.y + m_random.nextInt(16) - m_random.nextInt(16), + entity->m_pos.z + m_random.nextInt(16) - m_random.nextInt(16)); + TileID tile = source->getTile(aPos); if (tile > 0) - Tile::tiles[tile]->animateTick(this, aPos, &random); - } -} - -float Level::getSeenPercent(Vec3 vec, AABB aabb) const -{ - int raysTotal = 0, raysSeen = 0; - - float aabbSizeX = aabb.max.x - aabb.min.x; - float aabbSizeY = aabb.max.y - aabb.min.y; - float aabbSizeZ = aabb.max.z - aabb.min.z; - - // This shoots a bunch of rays from a point and checks if the rays hit something. Stuupiiiddd - for (float xi = 0.0f; xi <= 1.0f; xi += 1.0f / (1.0f + 2 * aabbSizeX)) - { - for (float yi = 0.0f; yi <= 1.0f; yi += 1.0f / (1.0f + 2 * aabbSizeY)) - { - for (float zi = 0.0f; zi <= 1.0f; zi += 1.0f / (1.0f + 2 * aabbSizeZ)) - { - Vec3 xvec; - xvec.x = aabb.min.x + xi * aabbSizeX; - xvec.y = aabb.min.y + yi * aabbSizeY; - xvec.z = aabb.min.z + zi * aabbSizeZ; - - HitResult hr = clip(xvec, vec); - if (hr.m_hitType == HitResult::NONE) - raysSeen++; - - raysTotal++; - } - } + Tile::tiles[tile]->animateTick(source, aPos, &m_random2); } - - return float (raysSeen) / float (raysTotal); } void Level::explode(Entity* entity, const Vec3& pos, float power) @@ -1926,7 +555,7 @@ void Level::explode(Entity* entity, const Vec3& pos, float power) void Level::explode(Entity* entity, const Vec3& pos, float power, bool bIsFiery) { - Explosion expl(this, entity, pos, power); + Explosion expl(entity->getTileSource(), entity, pos, power); expl.setFiery(bIsFiery); expl.explode(); expl.addParticles(); @@ -1939,40 +568,12 @@ void Level::explode(Entity* entity, const Vec3& pos, float power, bool bIsFiery) #endif } -void Level::addEntities(const EntityVector& entities) -{ - m_entities.insert(m_entities.end(), entities.begin(), entities.end()); - - for (EntityVector::iterator it = m_entities.begin(); it != m_entities.end(); it++) - { - Entity* pEnt = *it; - entityAdded(pEnt); - } -} - -// @UNUSED -void Level::ensureAdded(Entity* entity) -{ - ChunkPos chunkPos(Mth::floor(entity->m_pos.x / 16.0f), - Mth::floor(entity->m_pos.z / 16.0f)); - - // force the chunk to be resolved - ChunkPos cp; - for (cp.x = chunkPos.x - 2; cp.x <= chunkPos.x + 2; cp.x++) - for (cp.z = chunkPos.z - 2; cp.z <= chunkPos.z + 2; cp.z++) - getChunk(cp); - - EntityVector::iterator result = std::find(m_entities.begin(), m_entities.end(), entity); - if (result == m_entities.end()) - m_entities.push_back(entity); -} - -bool Level::extinguishFire(Player* player, const TilePos& pos, Facing::Name face) +bool Level::extinguishFire(TileSource& source, const TilePos& pos, Facing::Name face) { TilePos p(pos.relative(face)); - if (getTile(p) == Tile::fire->m_ID) - return setTile(p, TILE_AIR); + if (source.getTile(p) == Tile::fire->m_ID) + return source.setTile(p, TILE_AIR); return false; } @@ -1980,46 +581,31 @@ bool Level::extinguishFire(Player* player, const TilePos& pos, Facing::Name face int Level::findPath(Path* path, Entity* ent, Entity* target, float f) const { TilePos tp(ent->m_pos); - Region reg(this, tp - int(f + 16), tp + int(f + 16)); - m_pPathFinder->setLevel(®); return m_pPathFinder->findPath(*path, ent, target, f); - - // wtf? - // return 1; } int Level::findPath(Path* path, Entity* ent, const TilePos& pos, float f) const { TilePos tp(ent->m_pos); - Region reg(this, tp - int(f + 8), tp + int(f + 8)); - m_pPathFinder->setLevel(®); return m_pPathFinder->findPath(*path, ent, pos, f); - - // wtf? - // return 1; } -int Level::getLightDepth(const TilePos& pos) const +void Level::addListener(LevelListener& listener) { - return getChunk(pos)->getHeightmap(pos); + m_listeners.push_back(&listener); } -float Level::getStarBrightness(float f) const +void Level::removeListener(LevelListener& listener) { - float ca = Mth::cos(getSunAngle(f)); - float cb = 1.0f - (0.75f + 2 * ca); - - if (cb < 0.0f) - cb = 0.0f; - if (cb > 1.0f) - cb = 1.0f; - - return cb * cb * 0.5f; + Listeners::iterator it = std::find(m_listeners.begin(), m_listeners.end(), &listener); + if (it != m_listeners.end()) + m_listeners.erase(it); } -float Level::getSunAngle(float f) const +void Level::onChunkLoaded(LevelChunk& chunk) { - return (float(M_PI) * getTimeOfDay(f)) * 2; + // @TODO: this + throw std::bad_cast(); } diff --git a/source/world/level/Level.hpp b/source/world/level/Level.hpp index 993830cf6..2dbd8342a 100644 --- a/source/world/level/Level.hpp +++ b/source/world/level/Level.hpp @@ -22,13 +22,12 @@ #include "world/level/levelgen/chunk/LevelChunk.hpp" #include "world/level/levelgen/chunk/ChunkSource.hpp" #include "world/level/storage/LevelStorageSource.hpp" -#include "world/level/storage/LevelSource.hpp" #include "world/level/storage/LevelData.hpp" #include "world/level/path/PathFinder.hpp" #include "Dimension.hpp" #include "LevelListener.hpp" -#include "TickNextTickData.hpp" #include "LevelEvent.hpp" +#include "TileSourceListener.hpp" class Dimension; class Level; @@ -37,169 +36,83 @@ class RakNetInstance; class Packet; class MobSpawner; -typedef std::vector EntityVector; -typedef std::vector AABBVector; - -struct Brightness +class Level : public LevelListener, public TileSourceListener { - static float MIN, MAX; -}; +protected: + typedef std::vector Listeners; + +public: + typedef std::vector DimensionVector; -class Level : public LevelSource -{ public: - Level(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion = LEVEL_STORAGE_VERSION_DEFAULT, Dimension* pDimension = nullptr); + Level(LevelStorage* pStor, const std::string& name, const LevelSettings& settings, int storageVersion = LEVEL_STORAGE_VERSION_DEFAULT); ~Level(); private: Player* _getNearestPlayer(const Vec3&, float, bool) const; -protected: - // @NOTE: LevelListeners do NOT get updated here - void _setTime(int32_t time) { m_pLevelData->setTime(time); } - public: - // TODO - TileID getTile(const TilePos& pos) const override; - float getBrightness(const TilePos& pos) const override; - TileData getData(const TilePos& pos) const override; - Material* getMaterial(const TilePos& pos) const override; - bool isSolidTile(const TilePos& pos) const override; - - ChunkSource* getChunkSource() const; - virtual ChunkSource* createChunkSource(); - LevelChunk* getChunk(const ChunkPos& pos) const; - LevelChunk* getChunkAt(const TilePos& pos) const; - int getRawBrightness(const TilePos& pos) const; - int getRawBrightness(const TilePos& pos, bool b) const; - int getBrightness(const LightLayer&, const TilePos& pos) const; - void setBrightness(const LightLayer&, const TilePos& pos, int brightness); int getSeaLevel() const { return 63; } int getSeed() const { return m_pLevelData->getSeed(); } int32_t getTime() const { return m_pLevelData->getTime(); } - void setTime(int32_t time); + int32_t setTime(int32_t time); // Returns the time between the new time and the last synchronised time GameType getDefaultGameType() const { return m_pLevelData->getGameType(); } - int getHeightmap(const TilePos& pos); - bool isDay() const; - bool isSkyLit(const TilePos& pos) const; - bool isEmptyTile(const TilePos& pos) const; - bool hasChunkAt(const TilePos& pos) const; - bool hasChunk(const ChunkPos& pos) const; - bool hasChunksAt(const TilePos& min, const TilePos& max) const; - bool hasChunksAt(const TilePos& pos, int rad) const; - float getTimeOfDay(float f) const; - int getSkyDarken(float f) const; - void updateSkyDarken(); - bool updateSkyBrightness(); - void setUpdateLights(bool b); - bool updateLights(); - void updateLight(const LightLayer&, const TilePos& tilePos1, const TilePos& tilePos2); - void updateLight(const LightLayer&, const TilePos& tilePos1, const TilePos& tilePos2, bool); - void updateLightIfOtherThan(const LightLayer&, const TilePos& pos, int); - bool setTileAndDataNoUpdate(const TilePos& pos, TileID tile, TileData data); - bool setTileNoUpdate(const TilePos& pos, TileID tile); - bool setDataNoUpdate(const TilePos& pos, TileData data); - bool setTileAndData(const TilePos& pos, TileID tile, TileData data, TileChange::UpdateFlags updateFlags = TileChange::UPDATE_ALL); - bool setTile(const TilePos& pos, TileID tile, TileChange::UpdateFlags updateFlags = TileChange::UPDATE_ALL); - bool setData(const TilePos& pos, TileData data, TileChange::UpdateFlags updateFlags = TileChange::UPDATE_ALL); - void sendTileUpdated(const TilePos& pos); - void tileUpdated(const TilePos& pos, TileID tile); - void updateNeighborsAt(const TilePos& pos, TileID tile); - void neighborChanged(const TilePos& pos, TileID tile); - void setTilesDirty(const TilePos& min, const TilePos& max); + void updateLights(); void entityAdded(Entity* pEnt); void entityRemoved(Entity* pEnt); void levelEvent(const LevelEvent& event); - void tileEvent(const TileEvent& event); - void lightColumnChanged(int x, int z, int y1, int y2); - bool containsFireTile(const AABB&); - bool containsAnyLiquid(const AABB&); - bool containsLiquid(const AABB&, const Material *pMtl); - bool containsMaterial(const AABB&, const Material *pMtl); bool checkAndHandleWater(const AABB&, const Material* pMtl, Entity* pEnt); const TilePos& getSharedSpawnPos() const; - void validateSpawn(); - TileID getTopTile(const TilePos& pos) const; - int getTopTileY(const TilePos& pos) const; - int getTopSolidBlock(const TilePos& tilePos) const; void loadPlayer(Player&); - bool addEntity(Entity*); - bool removeEntity(Entity*); - void removeEntities(const EntityVector&); + bool addEntity(std::unique_ptr entity); + virtual bool addEntity(Entity* entity); + virtual void removeEntity(Entity& entity); + void removeEntity(std::unique_ptr&& entity); + virtual void removeEntity(Entity*& entity); void removeAllPendingEntityRemovals(); - void prepare(); void saveLevelData(); void savePlayerData(); - void saveAllChunks(); void saveGame(); void loadEntities(); - void sendEntityData(); - void setInitialSpawn(); void setSpawnPos(const TilePos& pos) { m_pLevelData->setSpawn(pos); } void setSpawnSettings(bool a, bool b) { } - bool canSeeSky(const TilePos& pos) const; - Vec3 getSkyColor(const Entity& entity, float f) const; - Vec3 getFogColor(float f) const; - Vec3 getCloudColor(float f) const; - bool isUnobstructed(AABB*) const; - bool mayInteract(Player* player, const TilePos& pos) const; - bool mayPlace(TileID tid, const TilePos& pos, bool b) const; void broadcastAll(Packet* packet); void broadcastToAllInRange(Packet* packet, const Vec3& pos, float range, Player* avoid = nullptr); void broadcastEntityEvent(const Entity& entity, Entity::EventType::ID eventId); void removeListener(LevelListener*); void addListener(LevelListener*); - void tick(Entity*, bool); - void tick(Entity*); virtual void tick(); - void tickPendingTicks(bool b); - void tickTiles(); void tickEntities(); - void addToTickNextTick(const TilePos& tilePos, int, int); + void tickTime(); void takePicture(TripodCamera* pCamera, Entity* pOwner); void addParticle(const std::string& name, const Vec3& pos, const Vec3& dir = Vec3::ZERO); void playSound(Entity*, const std::string& name, float volume = 1.0f, float pitch = 1.0f); void playSound(const Vec3& pos, const std::string& name, float volume = 1.0f, float pitch = 1.0f); - void animateTick(const TilePos& pos); - float getSeenPercent(Vec3, AABB) const; + void animateTick(Entity* entity); void explode(Entity*, const Vec3& pos, float power); void explode(Entity*, const Vec3& pos, float power, bool bIsFiery); - void addEntities(const EntityVector& entities); - void ensureAdded(Entity* entity); - bool extinguishFire(Player* player, const TilePos& pos, Facing::Name face); + bool extinguishFire(TileSource& source, const TilePos& pos, Facing::Name face); int findPath(Path* path, Entity* ent1, Entity* ent2, float f) const; int findPath(Path* path, Entity* ent, const TilePos& pos, float f) const; - int getLightDepth(const TilePos& pos) const; - float getStarBrightness(float f) const; - float getSunAngle(float f) const; - void swap(const TilePos& pos1, const TilePos& pos2); + void addListener(LevelListener& listener); + void removeListener(LevelListener& listener); - HitResult clip(const Vec3& a, const Vec3& b) const; - HitResult clip(Vec3 a, Vec3 b, bool c) const; Entity* getEntity(Entity::ID id) const; - unsigned int getEntityCount(const EntityCategories&) const; - const EntityVector* getAllEntities() const; - EntityVector getEntities(Entity* pAvoid, const AABB&) const; - BiomeSource* getBiomeSource() const override; + void getEntities(DimensionId dimensionId, const EntityType& type, const AABB& aabb, std::vector& output) const; LevelStorage* getLevelStorage() const { return m_pLevelStorage; } Dimension* getDimension(DimensionId type) const; const LevelData* getLevelData() const { return m_pLevelData; } - AABBVector* getCubes(const Entity* pEnt, const AABB& aabb); std::vector* getLightsToUpdate(); Player* getNearestPlayer(const Entity&, float) const; Player* getNearestPlayer(const Vec3& pos, float, bool) const; Player* getNearestAttackablePlayer(const Entity&, float) const; Player* getNearestAttackablePlayer(const Vec3& pos, float, const Entity*) const; - // unused redstone stuff - int getSignal(const TilePos& pos, Facing::Name face) const; - int getDirectSignal(const TilePos& pos, Facing::Name face) const; - bool hasDirectSignal(const TilePos& pos) const; - bool hasNeighborSignal(const TilePos& pos) const; + virtual void onChunkLoaded(LevelChunk& chunk); -#ifdef ENH_IMPROVED_SAVING - void saveUnsavedChunks(); -#endif +protected: + void _syncTime(int32_t time); + bool _updateLightsTask(); private: LevelData* m_pLevelData; @@ -209,33 +122,24 @@ class Level : public LevelSource int m_addend; public: - AABBVector m_aabbs; - bool m_bInstantTicking; bool m_bIsClientSide; // if the level is controlled externally by a server. - bool m_bPostProcessing; - EntityVector m_entities; + DimensionVector m_dimensions; std::vector m_players; - int m_skyDarken; uint8_t field_30; - Dimension* m_pDimension; int m_difficulty; // @TODO: Difficulty enum Random m_random; + Random m_random2; RakNetInstance* m_pRakNetInstance; - bool m_bCalculatingInitialSpawn; - std::vector m_levelListeners; - ChunkSource* m_pChunkSource; + Listeners m_listeners; LevelStorage* m_pLevelStorage; - EntityVector m_pendingEntityRemovals; - std::set m_pendingTicks; + std::vector> m_pendingEntityRemovals; std::set m_chunksToUpdate; std::vector m_lightUpdates; - bool m_bUpdateLights; - int field_B08; + bool m_processingLightUpdates; uint8_t field_B0C; int field_B10; PathFinder* m_pPathFinder; MobSpawner* m_pMobSpawner; - - std::map m_entityCountsByCategory; + int32_t m_lastGameTimeSync; }; diff --git a/source/world/level/LevelConstants.hpp b/source/world/level/LevelConstants.hpp new file mode 100644 index 000000000..b091cbb81 --- /dev/null +++ b/source/world/level/LevelConstants.hpp @@ -0,0 +1,8 @@ +#pragma once + +class LevelConstants +{ +public: + // The world size in the X and Z axis for a limited world + static const int WORLD_SIZE_XZ = 16; +}; diff --git a/source/world/level/LevelListener.hpp b/source/world/level/LevelListener.hpp index 879b8b93e..a3b7c98d4 100644 --- a/source/world/level/LevelListener.hpp +++ b/source/world/level/LevelListener.hpp @@ -13,6 +13,9 @@ #include "world/level/LevelEvent.hpp" #include "world/level/TileEvent.hpp" +class Player; +class LevelChunk; + class LevelListener { public: @@ -31,6 +34,6 @@ class LevelListener virtual void entityRemoved(Entity*) {} virtual void levelEvent(const LevelEvent& event) {} virtual void tileEvent(const TileEvent& event) {} - virtual void timeChanged(uint32_t time) {} + virtual void onNewChunkFor(Player& player, LevelChunk& chunk); }; diff --git a/source/world/level/Region.cpp b/source/world/level/Region.cpp deleted file mode 100644 index 9a7109ce6..000000000 --- a/source/world/level/Region.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "Region.hpp" - -TileID Region::getTile(const TilePos& pos) const -{ - if (pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - return TILE_AIR; - - LevelChunk* pChunk = getChunkAt(pos); - - if (pChunk == nullptr) - return TILE_AIR; - - return pChunk->getTile(pos); -} - -int Region::getRawBrightness(const TilePos& pos, bool b) const -{ - if (pos.x < C_MIN_X || pos.z < C_MIN_X || pos.x >= C_MAX_X || pos.z > C_MAX_Z) - return 15; - - if (b) - { - TileID tile = getTile(pos); - if (tile == Tile::stoneSlabHalf->m_ID || tile == Tile::farmland->m_ID) - { - int result; - - int b1 = getRawBrightness(pos.above(), false); - int b2 = getRawBrightness(pos.west(), false); - int b3 = getRawBrightness(pos.east(), false); - int b4 = getRawBrightness(pos.north(), false); - int b5 = getRawBrightness(pos.south(), false); - - result = b1; - if (result < b2) result = b2; - if (result < b3) result = b3; - if (result < b4) result = b4; - if (result < b5) result = b5; - - return result; - } - } - if (pos.y < C_MIN_Y) - { - return 0; - } - if (pos.y >= C_MAX_Y) - { - int bright = 15 - m_pLevel->m_skyDarken; - if (bright < 0) - bright = 0; - return bright; - } - - //@BUG: Unsanitized input - ChunkPos d(pos); - d -= field_4; - return field_C[d.z * field_14.x + d.x]->getRawBrightness(pos, m_pLevel->m_skyDarken); -} - -int Region::getRawBrightness(const TilePos& pos) const -{ - return getRawBrightness(pos, true); -} - -float Region::getBrightness(const TilePos& pos) const -{ - return m_pLevel->m_pDimension->m_brightnessRamp[getRawBrightness(pos)]; -} - -TileData Region::getData(const TilePos& pos) const -{ - if (pos.y < C_MIN_Y || pos.y >= C_MAX_Y) - return 0; - - ChunkPos d(pos); - d -= field_4; - return field_C[d.z * field_14.x + d.x]->getData(pos); -} - -Material* Region::getMaterial(const TilePos& pos) const -{ - TileID tile = getTile(pos); - - if (tile == TILE_AIR) - return Material::air; - - return Tile::tiles[tile]->m_pMaterial; -} - -bool Region::isSolidTile(const TilePos& pos) const -{ - Tile* pTile = Tile::tiles[getTile(pos)]; - - if (!pTile) - return false; - - return pTile->isSolidRender(); -} - -BiomeSource* Region::getBiomeSource() const -{ - return m_pLevel->getBiomeSource(); -} - -Region::~Region() -{ - delete[] field_C; -} - -Region::Region(const Level* level, const TilePos& min, const TilePos& max) -{ - m_pLevel = level; - field_4 = min; - ChunkPos cpMin(min), cpMax(max); - field_14 = (cpMax - cpMin) + 1; - -#ifndef ORIGINAL_CODE - field_C = nullptr; - - assert(field_14.x > 0); - assert(field_14.z > 0); - - if (field_14.x <= 0 || field_14.z <= 0) - return; -#endif - - /* - m_bFoggy = new LevelChunk ** [m_noEntityRenderFrames.x]; - - for (int i = 0; i < m_noEntityRenderFrames.x; i++) - { - m_bFoggy[i] = new LevelChunk * [m_noEntityRenderFrames.z]; - } - */ - - field_C = new LevelChunk * [field_14.x * field_14.z]; - //LOG_I("Region chunk-storage size: %d x %d = %d", m_noEntityRenderFrames.x, m_noEntityRenderFrames.z, m_noEntityRenderFrames.x * m_noEntityRenderFrames.z); - - // NOTE: do NOT compare cp.x with max.x directly, no automatic conversion will occur - ChunkPos cp(field_4); - for (cp.x = field_4.x; cp.x <= cpMax.x; cp.x++) - { - for (cp.z = field_4.z; cp.z <= cpMax.z; cp.z++) - { - int index = (cp.z - field_4.z) * field_14.x + (cp.x - field_4.x); - //LOG_I("Writing to region chunk-storage at: %d", index); - field_C[index] = level->getChunk(cp); - } - } -} diff --git a/source/world/level/Region.hpp b/source/world/level/Region.hpp deleted file mode 100644 index ca0101edb..000000000 --- a/source/world/level/Region.hpp +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include "Level.hpp" - -class Region : public LevelSource -{ -public: - TileID getTile(const TilePos& pos) const override; - int getRawBrightness(const TilePos& pos, bool b) const; - int getRawBrightness(const TilePos& pos) const; - float getBrightness(const TilePos& pos) const override; - TileData getData(const TilePos& pos) const override; - Material* getMaterial(const TilePos& pos) const override; - bool isSolidTile(const TilePos& pos) const override; - BiomeSource* getBiomeSource() const override; - - virtual ~Region(); - Region(const Level* level, const TilePos& min, const TilePos& max); - - // inlined in the original, but I doubt they'd actually copy paste this logic - LevelChunk* getChunkAt(const ChunkPos& pos) const - { - int indexX = pos.x - field_4.x; - int indexZ = pos.z - field_4.z; - - if (indexX < 0 || indexZ < 0 || indexX >= field_14.x || indexZ >= field_14.z) - return nullptr; - - return field_C[indexZ * field_14.x + indexX]; - } - -private: - ChunkPos field_4; - // accesses to the array are performed as follows: - // (x = 0..m_noEntityRenderFrames, z = 0..m_totalEntities) - // z * m_noEntityRenderFrames + x - LevelChunk** field_C; - const Level* m_pLevel; - ChunkPos field_14; -}; - diff --git a/source/world/level/Tick.hpp b/source/world/level/Tick.hpp new file mode 100644 index 000000000..877af4476 --- /dev/null +++ b/source/world/level/Tick.hpp @@ -0,0 +1,10 @@ +#pragma once +#include + +typedef uint64_t Tick_t; + +class Tick +{ +public: + static const Tick_t MAX = UINT64_MAX; +}; diff --git a/source/world/level/TickNextTickData.cpp b/source/world/level/TickNextTickData.cpp deleted file mode 100644 index 06ca0bfa2..000000000 --- a/source/world/level/TickNextTickData.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "TickNextTickData.hpp" - -int TickNextTickData::C; - -TickNextTickData::TickNextTickData(const TilePos& tilePos, TileID tileId) - : id(++C) //@NOTE: not C++ - , tilePos(tilePos) - , tileId(tileId) -{ -#ifndef ORIGINAL_CODE - delay = 0; -#endif -} - -int TickNextTickData::hashCode() const -{ - return tileId + ((tilePos.y + ((tilePos.z + (tilePos.x << 10)) << 7)) << 8); -} - -bool TickNextTickData::operator<(const TickNextTickData& other) const -{ - if (delay < other.delay) - return true; - if (delay > other.delay) - return false; - - return id < other.id; -} - -bool TickNextTickData::operator==(const TickNextTickData& other) const -{ - return - tilePos == other.tilePos && - tileId == other.tileId; -} diff --git a/source/world/level/TickNextTickData.hpp b/source/world/level/TickNextTickData.hpp deleted file mode 100644 index 0222de471..000000000 --- a/source/world/level/TickNextTickData.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include -#include "common/Utils.hpp" -#include "world/level/TilePos.hpp" - -struct TickNextTickData -{ - static int C; - - TickNextTickData(const TilePos& tilePos, TileID tileId); - int hashCode() const; - bool operator<(const TickNextTickData& other) const; - bool operator==(const TickNextTickData& other) const; - void setDelay(int32_t delay) { this->delay = delay; } - - int id; - TilePos tilePos; - TileID tileId; - int32_t delay; -}; - diff --git a/source/world/level/TileChange.hpp b/source/world/level/TileChange.hpp index b8b66b88f..ea325ec5c 100644 --- a/source/world/level/TileChange.hpp +++ b/source/world/level/TileChange.hpp @@ -5,17 +5,21 @@ class TileChange public: enum UpdateFlags { - UPDATE_NONE = 0 << 0, // 0 0 0 // + UPDATE_NONE = 0, - UPDATE_NEIGHBORS = 1 << 0, // 0 0 1 // - UPDATE_LISTENERS = 1 << 1, // 0 1 0 // - UPDATE_SILENT = 1 << 2, // 1 0 0 // + UPDATE_NEIGHBORS = 1 << 0, + UPDATE_LISTENERS = 1 << 1, + UPDATE_LISTENERS_SERVER_ONLY = 1 << 2, + UPDATE_UNK3 = 1 << 3, + UPDATE_UNK4 = 1 << 4, - UPDATE_ALL = UPDATE_NEIGHBORS | UPDATE_LISTENERS // the default behavior + UPDATE_ALL = UPDATE_NEIGHBORS | UPDATE_LISTENERS, + UPDATE_SERVER_ONLY = UPDATE_LISTENERS_SERVER_ONLY }; public: TileChange(UpdateFlags updateFlags = UPDATE_NONE) : m_updateFlags(updateFlags) {} + TileChange(int updateFlags) : m_updateFlags(static_cast(updateFlags)) {} bool isUpdateNeighbors() const { return (m_updateFlags & UPDATE_NEIGHBORS) != UPDATE_NONE; @@ -25,12 +29,8 @@ class TileChange return (m_updateFlags & UPDATE_LISTENERS) != UPDATE_NONE; } - bool isUpdateSilent() const { - return (m_updateFlags & UPDATE_SILENT) != UPDATE_NONE; - } - - bool isUpdateAll() const { - return (m_updateFlags & UPDATE_ALL) != UPDATE_NONE; + bool isUpdateListenersServerOnly() const { + return (m_updateFlags & UPDATE_LISTENERS_SERVER_ONLY) != UPDATE_NONE; } private: diff --git a/source/world/level/TilePos.hpp b/source/world/level/TilePos.hpp index 49f9eb7da..b91b7e61e 100644 --- a/source/world/level/TilePos.hpp +++ b/source/world/level/TilePos.hpp @@ -41,6 +41,29 @@ struct TilePos TilePos west(int steps = 1) const { return relative(Facing::WEST, steps); } TilePos east(int steps = 1) const { return relative(Facing::EAST, steps); } + int volume() const + { + return x * y * z; + } + + TilePos min(const TilePos& other) const + { + return TilePos( + x < other.x ? x : other.x, + y < other.y ? y : other.y, + z < other.z ? z : other.z + ); + } + + TilePos max(const TilePos& other) const + { + return TilePos( + x < other.x ? other.x : x, + y < other.y ? other.y : y, + z < other.z ? other.z : z + ); + } + bool operator<(const TilePos& b) const; bool operator>(const TilePos& b) const; bool operator<=(const TilePos& b) const; @@ -56,9 +79,33 @@ struct TilePos void operator*=(int i); TilePos operator-() const; TilePos operator*(int i) const; + TilePos operator*(const TilePos& other) const + { + return TilePos(x * other.x, y * other.y, z * other.z); + } Vec3 operator*(float f) const; TilePos operator/(int i) const; Vec3 operator/(float f) const; bool operator==(const TilePos& b) const; bool operator!=(const TilePos& b) const; + + int& operator[](size_t i) + { + return reinterpret_cast(this)[i]; + } + + const int& operator[](size_t i) const + { + return reinterpret_cast(this)[i]; + } + + operator int*() + { + return reinterpret_cast(this); + } + + operator const int*() const + { + return reinterpret_cast(this); + } }; diff --git a/source/world/level/TileSource.cpp b/source/world/level/TileSource.cpp new file mode 100644 index 000000000..4596ce424 --- /dev/null +++ b/source/world/level/TileSource.cpp @@ -0,0 +1,321 @@ +#include "world/level/TileSource.hpp" +#include "world/level/levelgen/chunk/ChunkSource.hpp" +#include "world/level/Level.hpp" +#include "world/level/TileSourceListener.hpp" + +TileSource::TileSource(Level& level, Dimension& dimension, ChunkSource& source, bool publicSource, bool allowUnpopulatedChunks) + : m_threadId(std::this_thread::get_id()) + , m_bAllowUnpopulatedChunks(allowUnpopulatedChunks) + , m_bPublicSource(publicSource) + , m_level(level) + , m_chunkSource(source) + , m_dimension(dimension) + , m_lastChunk(nullptr) + , m_tileTickingQueue(nullptr) +{ + if (publicSource) + { + m_listeners.push_back(&level); + + for (size_t i = 0; i < m_listeners.size(); i++) + { + m_listeners[i]->onSourceCreated(*this); + } + } +} + +void TileSource::_neighborChanged(const TilePos& neighborPos, const TilePos& originalPos, TileID tileID) +{ + if (getLevelConst().m_bIsClientSide) + return; + + // TODO +} + +void TileSource::_tileChanged(const TilePos& pos, FullTile oldTile, FullTile newTile, TileChange updateFlags) +{ + if (updateFlags.isUpdateNeighbors()) + { + updateNeighborsAt(pos, oldTile.getTypeId()); + } + + if (updateFlags.isUpdateListeners()) + { + if (!m_level.m_bIsClientSide || !updateFlags.isUpdateListenersServerOnly()) + { + fireTileChanged(pos, oldTile, newTile, updateFlags); + } + } +} + +Level& TileSource::getLevel() const +{ + return m_level; +} + +const Level& TileSource::getLevelConst() const +{ + return m_level; +} + +Dimension& TileSource::getDimension() const +{ + return m_dimension; +} + +const Dimension& TileSource::getDimensionConst() const +{ + return m_dimension; +} + +void TileSource::setTickingQueue(TileTickingQueue& queue) +{ + m_tileTickingQueue = &queue; +} + +TileTickingQueue* TileSource::getTickQueue(const TilePos& pos) +{ + if (m_tileTickingQueue) + return m_tileTickingQueue; + + LevelChunk* chunk = getChunk(pos); + if (chunk) + return &chunk->getTileTickingQueue(); + + return nullptr; +} + +LevelChunk* TileSource::getChunk(const ChunkPos& pos) +{ + if (!m_lastChunk || m_lastChunk->getPos() != pos) + { + LevelChunk* chunk = m_bAllowUnpopulatedChunks ? m_chunkSource.getGeneratedChunk(pos) : m_chunkSource.getAvailableChunk(pos); + if (chunk) + m_lastChunk = chunk; + return chunk; + } + + return m_lastChunk; +} + +LevelChunk* TileSource::getWritableChunk(const ChunkPos& pos) +{ + LevelChunk* chunk = getChunk(pos); + if (chunk) + { + if (!chunk->isReadOnly()) + return chunk; + } + + return nullptr; +} + +bool TileSource::shouldFireEvents(LevelChunk& chunk) const +{ + if (m_bAllowUnpopulatedChunks) + return false; + + return chunk.getState() == CS_POST_PROCESSED; +} + +bool TileSource::hasChunksAt(const Bounds& bounds) +{ + const Vec3Int32& min = bounds.getMin(); + const Vec3Int32& max = bounds.getMax(); + ChunkPos pos; + for (pos.z = min.z; pos.z <= max.z; pos.z++) + { + for (pos.x = min.x; pos.x <= max.x; pos.x++) + { + LevelChunk* chunk = getChunk(pos); + if (chunk) + return true; + } + } + + return false; +} + +bool TileSource::hasChunksAt(const AABB& aabb) +{ + return hasChunksAt(aabb.min * Vec3(1, 0, 1), aabb.max * Vec3(1, 0, 1)); +} + +bool TileSource::hasChunksAt(const TilePos& min, const TilePos& max) +{ + return hasChunksAt(Bounds(min, max, m_chunkSource.getChunkSide(), false)); +} + +bool TileSource::hasChunksAt(int x, int y, int z, int r) +{ + TilePos min(x - r, y, z - r); + TilePos max(x + r, y, z + r); + + return hasChunksAt(min, max); +} + +bool TileSource::hasChunksAt(const TilePos& pos, int r) +{ + return hasChunksAt(pos.x, pos.y, pos.z, r); +} + +const std::vector& TileSource::getMobsAt(EntityType entityType, const TilePos& pos) +{ + return m_chunkSource.getMobsAt(*this, entityType, pos); +} + +bool TileSource::hasNeighborSignal(int x, int y, int z) +{ + return false; +} + +void TileSource::runLightUpdates(const LightLayer& lightLayer, const TilePos& min, const TilePos& max) +{ + // TODO!! +} + +void TileSource::onChunkDiscarded(LevelChunk& chunk) +{ + if (m_lastChunk == &chunk) + clearCachedLastChunk(); +} + +void TileSource::clearCachedLastChunk() +{ + m_lastChunk = nullptr; +} + +bool TileSource::isOwnerThread() const +{ + return m_threadId == std::this_thread::get_id(); +} + +TileID TileSource::getTile(const TilePos& pos) +{ + if (pos.y >= ChunkConstants::Y_SIZE) + return TILE_AIR; + + LevelChunk* chunk = getChunk(pos); + if (!chunk) + return TILE_AIR; + + return chunk->getTile(pos); +} + +TileID TileSource::getTile(int x, int y, int z) +{ + return getTile(TilePos(x, y, z)); +} + +Tile* TileSource::getTilePtr(const TilePos& pos) +{ + return Tile::tiles[getTile(pos)]; +} + +Tile* TileSource::getTilePtr(int x, int y, int z) +{ + return getTilePtr(TilePos(x, y, z)); +} + +TileData TileSource::getData(const TilePos& pos) +{ + if (pos.y >= ChunkConstants::Y_SIZE) + return 0; + + LevelChunk* chunk = getChunk(pos); + if (!chunk) + return 0; + + return chunk->getData(pos); +} + +TileData TileSource::getData(int x, int y, int z) +{ + return getData(TilePos(x, y, z)); +} + +Brightness_t TileSource::getRawBrightness(const TilePos& pos, bool unk) +{ + TileID tile = getTile(pos); + + if (Tile::lightBlock[tile] == Brightness::MAX) + return Brightness::MIN; + + if (unk) + { + // TODO: also handle wood slabs + if (*Tile::stoneSlabHalf == tile || *Tile::farmland == tile) + { + Brightness_t brightestNeighbor = 0; + for (int i = 0; i < Facing::COUNT; i++) + { + Brightness_t neighborBrightness = getRawBrightness(pos + Facing::DIRECTION[i], false); + if (neighborBrightness > brightestNeighbor) + brightestNeighbor = neighborBrightness; + } + return brightestNeighbor; + } + } + + if (pos.y < 0) + return Brightness::MIN; + + if (pos.y > (ChunkConstants::Y_SIZE - 1)) + { + Brightness_t skyDarken = getSkyDarken(); + Brightness_t b = Brightness::MAX - skyDarken; + if (b > Brightness::MAX) + b = Brightness::MIN; // bug? + return b; + } + + const LevelChunk* chunk = getChunk(pos); + if (!chunk) + return Brightness::MAX; + + return chunk->getRawBrightness(pos, getSkyDarken()); +} + +Brightness_t TileSource::getRawBrightness(int x, int y, int z, bool unk) +{ + return getRawBrightness(TilePos(x, y, z), unk); +} + +Brightness_t TileSource::getBrightness(const LightLayer& lightLayer, const TilePos& pos) +{ + if (pos.y > (ChunkConstants::Y_SIZE - 1)) + return lightLayer.getSurrounding(); + + LevelChunk* chunk = getChunk(pos); + if (!chunk) + return Brightness::MIN; + + return chunk->getBrightness(lightLayer, pos); +} + +Brightness_t TileSource::getBrightness(const LightLayer& lightLayer, int x, int y, int z) +{ + return getBrightness(lightLayer, TilePos(x, y, z)); +} + +float TileSource::getBrightness(const TilePos& pos) +{ + return m_dimension.getBrightnessRamp(getRawBrightness(pos, true)); +} + +float TileSource::getBrightness(int x, int y, int z) +{ + return getBrightness(TilePos(x, y, z)); +} + +void TileSource::addListener(TileSourceListener& listener) +{ + m_listeners.push_back(&listener); +} + +void TileSource::removeListener(TileSourceListener& listener) +{ + Listeners::iterator it = std::find(m_listeners.begin(), m_listeners.end(), &listener); + if (it != m_listeners.end()) + m_listeners.erase(it); +} diff --git a/source/world/level/TileSource.hpp b/source/world/level/TileSource.hpp new file mode 100644 index 000000000..bb3e62af8 --- /dev/null +++ b/source/world/level/TileSource.hpp @@ -0,0 +1,170 @@ +#pragma once +#include +#include +#include "client/renderer/LightLayer.hpp" +#include "world/entity/EntityType.hpp" +#include "world/entity/MobSpawnerData.hpp" +#include "world/level/levelgen/biome/Biome.hpp" +#include "world/level/levelgen/chunk/ChunkPos.hpp" +#include "world/level/Brightness.hpp" +#include "world/level/TileChange.hpp" +#include "world/tile/Tile.hpp" + +class TileTickingQueue; +class AABB; +class LevelChunk; +class TileEntity; +class TileSourceListener; // TODO +class TileTickingQueue; +class Dimension; +class ChunkSource; +struct Bounds; + +class TileSource +{ +protected: + typedef std::vector Listeners; + +public: + TileSource(Level& level, Dimension& dimension, ChunkSource& source, bool publicSource, bool allowUnpopulatedChunks); + virtual ~TileSource(); + +protected: + void _neighborChanged(const TilePos&, const TilePos&, TileID); + void _tileChanged(const TilePos& pos, FullTile oldTile, FullTile newTile, TileChange updateFlags); + +public: + Level& getLevel() const; + const Level& getLevelConst() const; + Dimension& getDimension() const; + const Dimension& getDimensionConst() const; + ChunkSource& getChunkSource() + { + return m_chunkSource; + } + void setTickingQueue(TileTickingQueue& queue); + TileTickingQueue* getTickQueue(const TilePos& pos); + LevelChunk* getChunk(const ChunkPos& pos); + LevelChunk* getChunk(int x, int z) { return getChunk(ChunkPos(x, z)); } + LevelChunk* getWritableChunk(const ChunkPos& pos); + bool shouldFireEvents(LevelChunk& chunk) const; + bool hasChunkAt(const TilePos& pos) { return getChunk(pos) != nullptr; } + bool hasChunksAt(const Bounds& bounds); + bool hasChunksAt(const AABB& aabb); + bool hasChunksAt(const TilePos& min, const TilePos& max); + bool hasChunksAt(const TilePos& pos, int r); + bool hasChunksAt(int x, int y, int z, int r); + Brightness_t getSkyDarken() const; + const std::vector& getMobsAt(EntityType entityType, const TilePos& pos); + bool hasNeighborSignal(const TilePos& pos); // custom + bool hasNeighborSignal(int x, int y, int z); + void runLightUpdates(const LightLayer&, const TilePos&, const TilePos&); // unk type + bool isTopSolidBlocking(Tile*, uint8_t); + void onChunkDiscarded(LevelChunk& chunk); + void clearCachedLastChunk(); // unk type + void fireAreaChanged(const TilePos&, const TilePos&); // unk type + void fireTilesDirty(int, int, int, int, int, int); // unk type + void fireTileChanged(const TilePos&, FullTile, FullTile, TileChange); + void fireBrightnessChanged(const TilePos&); // unk type + void fireTileEntityRemoved(std::unique_ptr&); // unk type + void fireTileEvent(int, int, int, int, int); // unk type + void getChunkAt(const TilePos&); // unk type + void hasTile(const TilePos&); // unk type + void fireTileEntityChanged(TileEntity&); // unk type + void getChunkAt(int, int, int); // unk type + void hasTile(int, int, int); // unk type + bool isOwnerThread() const; + void getDimensionId(); // unk type + void setExtraData(const TilePos&, uint16_t); // unk type + void getExtraData(const TilePos&); // unk type + TileID getTopSolidBlock(const TilePos&, bool); + TileID getTopSolidBlock(int, int, bool); + bool canSeeSky(const TilePos&); + bool canSeeSky(int, int, int); + uint8_t getHeightmap(const TilePos&); + void getHeightmapPos(const TilePos&); // unk type + uint8_t getHeightmap(int, int); + void getTileEntity(const TilePos&); // unk type + void getTileEntity(int, int, int); // unk type + void getGrassColor(const TilePos&); // unk type + void getTopRainTilePos(const TilePos&); // unk type + void checkIsTopRainTilePos(const TilePos&); // unk type + TileID getTile(const TilePos& pos); + TileID getTile(int x, int y, int z); + Tile* getTilePtr(const TilePos& pos); + Tile* getTilePtr(int x, int y, int z); + TileData getData(const TilePos& pos); + TileData getData(int x, int y, int z); + bool isSolidBlockingTile(int, int, int); + bool isSolidBlockingTile(const TilePos&); + void isSolidRenderTile(int, int, int); // unk type + void isSolidRenderTile(const TilePos&); // unk type + bool containsMaterial(const AABB&, const Material*); + void tileEvent(int, int, int, int, int); // unk type + void tileEvent(const TilePos&, int, int); // unk type + bool containsAnyLiquid(const AABB&); + bool containsFireTile(const AABB&); + Material* getMaterial(const TilePos&); + Material* getMaterial(int, int, int); + void isWaterAt(const TilePos&); // unk type + void isIceAt(const TilePos&); // unk type + void updateNeighborsAt(const TilePos&, TileID); // unk type + bool isEmptyTile(const TilePos&); + bool isEmptyTile(int, int, int); + void findNextTopSolidTileUnder(TilePos&); // unk type + void containsAny(const TilePos&, const TilePos&); // unk type + Brightness_t getRawBrightness(const TilePos& pos, bool unk = true); + Brightness_t getRawBrightness(int x, int y, int z, bool unk = true); + Brightness_t getBrightness(const LightLayer& lightLayer, const TilePos& pos); + Brightness_t getBrightness(const LightLayer& lightLayer, int x, int y, int z); + float getBrightness(const TilePos& pos); + float getBrightness(int x, int y, int z); + void updateLightIfOtherThan(const LightLayer&, const TilePos&, Brightness_t); // unk type + void containsLiquid(const AABB&, const Material*); // unk type + void getTileAndData(const TilePos&); // unk type + void isTopSolidBlocking(const TilePos&); // unk type + void isTopSolidBlocking(int, int, int); // unk type + void getTileAndData(int, int, int); // unk type + HitResult clip(const Vec3& A, const Vec3& B, bool liquid = false, bool solidOnly = false); + float getSeenPercent(const Vec3&, const AABB&); + void getLightColor(const TilePos&, int); // unk type + Biome& getBiome(const TilePos&); + void shouldFreeze(const TilePos&, bool); // unk type + void shouldFreezeIgnoreNeighbors(const TilePos&); // unk type + void shouldThaw(const TilePos&, bool); // unk type + void isSnowTemperature(const TilePos&); // unk type + void isHumidAt(const TilePos&); // unk type + bool setTileAndData(const TilePos&, FullTile, TileChange updateFlags = TileChange::UPDATE_NONE); + bool setTileAndData(int, int, int, FullTile, TileChange updateFlags = TileChange::UPDATE_NONE); + bool setTile(const TilePos&, TileID, TileChange updateFlags = TileChange::UPDATE_NONE); // custom + bool setTile(int, int, int, TileID, TileChange updateFlags = TileChange::UPDATE_NONE); + bool setTileAndDataNoUpdate(const TilePos&, FullTile); // custom + bool setTileAndDataNoUpdate(int, int, int, FullTile); + bool setTileNoUpdate(const TilePos&, TileID); // custom + bool setTileNoUpdate(int, int, int, TileID); + void removeTile(int, int, int); // unk type + void setBrightness(const LightLayer&, const TilePos&, Brightness_t); // unk type + void setBrightness(const LightLayer&, int, int, int, Brightness_t); // unk type + void setGrassColor(int, const TilePos&, int); // unk type + void fetchCollisionShapes(Entity*, const AABB&, float*, bool); // unk type + std::vector& fetchAABBs(const AABB&, bool); // unk type + void getEntities(EntityType, const AABB&, Entity*); // unk type + void getNearestEntityOfType(Entity*, const AABB&, EntityType); // unk type + void getNearestEntityOfType(Entity*, const Vec3&, float, EntityType); // unk type + const std::vector& getEntities(Entity* except, const AABB& bb); + void isUnobstructedByEntities(const AABB&, Entity*); // unk type + bool mayPlace(TileID tileId, const TilePos& pos, Facing::Name face, Entity* placer, bool ignoreEntities = false, Entity* ignoreEntity = nullptr) { throw std::bad_cast(); } // @TODO: implement this + void addListener(TileSourceListener& listener); + void removeListener(TileSourceListener& listener); + +protected: + std::thread::id m_threadId; + bool m_bAllowUnpopulatedChunks; + bool m_bPublicSource; + Level& m_level; + ChunkSource& m_chunkSource; + Dimension& m_dimension; + Listeners m_listeners; + LevelChunk* m_lastChunk; + TileTickingQueue* m_tileTickingQueue; +}; diff --git a/source/world/level/TileSourceListener.hpp b/source/world/level/TileSourceListener.hpp new file mode 100644 index 000000000..849ee850a --- /dev/null +++ b/source/world/level/TileSourceListener.hpp @@ -0,0 +1,22 @@ +#pragma once +#include "world/tile/Tile.hpp" + +class TileSource; +class TileEntity; + +class TileSourceListener +{ +public: + virtual ~TileSourceListener() {} + +public: + void onSourceCreated(TileSource& source) {} + void onSourceDestroyed(TileSource& source) {} + void onTilesDirty(TileSource& source, int, int, int, int, int, int) {} + void onAreaChanged(TileSource& source, const TilePos&, const TilePos&) {} + void onTileChanged(TileSource& source, const TilePos&, FullTile, FullTile, int) {} + void onBrightnessChanged(TileSource& source, const TilePos& pos) { onAreaChanged(source, pos, pos); } + void onTileEntityChanged(TileSource& source, TileEntity& tileEntity) {} + void onTileEntityRemoved(TileSource& source, std::unique_ptr& tileEntity) {} + void onTileEvent(TileSource& source, int, int, int, int, int) {} +}; diff --git a/source/world/level/TileTickingQueue.cpp b/source/world/level/TileTickingQueue.cpp new file mode 100644 index 000000000..5588c58b0 --- /dev/null +++ b/source/world/level/TileTickingQueue.cpp @@ -0,0 +1,94 @@ +#include "world/level/TileTickingQueue.hpp" +#include "world/level/TileSource.hpp" +#include "nbt/CompoundTag.hpp" +#include "nbt/ListTag.hpp" + +void TileTickingQueue::_tick(TileSource& region, const TilePos& pos, TileID tileID) +{ + if (tileID == 0) + return; + + TileID expectedTileID = region.getTile(pos); + if (tileID == expectedTileID) + Tile::tiles[tileID]->tick(®ion, pos, &m_random); +} + +void TileTickingQueue::add(TileSource* region, const TilePos& pos, TileID tileID, int tickDelay) +{ + if (!region->hasChunksAt(pos - 8, pos + 8)) + return; + + if (tickDelay < 0) + { + _tick(*region, pos, tileID); + } + else + { + m_tickData.push(TickNextTickData(pos, tileID, m_currentTick + tickDelay)); + } +} + +bool TileTickingQueue::tickPendingTicks(TileSource& region, Tick_t until, int max, bool instaTick) +{ + m_instaTick = instaTick; + + bool hasTicked = false; + while (!m_tickData.empty() && m_tickData.top().m_tick <= until) + { + TickNextTickData data; + m_tickData.popInto(data); + + if (region.hasChunksAt(data.m_pos - 8, data.m_pos + 8)) + _tick(region, data.m_pos, data.m_tileID); + + hasTicked = true; + } + + m_currentTick = until; + m_instaTick = false; + + return hasTicked; +} + +void TileTickingQueue::tickAllPendingTicks(TileSource& region) +{ + while (!m_tickData.empty()) + { + tickPendingTicks(region, Tick::MAX, INT32_MAX, true); + } +} + +void TileTickingQueue::save(CompoundTag& tag) +{ + ListTag* list = new ListTag(); + + for (MovePriorityQueue::Iterator iter = m_tickData.begin(); iter != m_tickData.end(); iter++) + { + const TickNextTickData& data = *iter; + + CompoundTag* childTag = new CompoundTag(); + childTag->putInt32("x", data.m_pos.x); + childTag->putInt32("y", data.m_pos.y); + childTag->putInt32("z", data.m_pos.z); + childTag->putInt8("tileID", static_cast(data.m_tileID)); + childTag->putInt64("time", static_cast(data.m_tick)); + list->add(childTag); + } + + tag.put("tickList", list); +} + +void TileTickingQueue::load(const CompoundTag& tag) +{ + const ListTag* list = tag.getList("tickList"); + + for (size_t i = 0; i < list->size(); i++) + { + const CompoundTag* childTag = list->getCompound(i); + + TilePos pos = TilePos(childTag->getInt32("x"), childTag->getInt32("y"), childTag->getInt32("z")); + TileID tileID = static_cast(childTag->getInt8("tileID")); + Tick_t tick = static_cast(childTag->getInt64("tick")); + m_tickData.push(TickNextTickData(pos, tileID, tick)); + } +} diff --git a/source/world/level/TileTickingQueue.hpp b/source/world/level/TileTickingQueue.hpp new file mode 100644 index 000000000..feb686951 --- /dev/null +++ b/source/world/level/TileTickingQueue.hpp @@ -0,0 +1,62 @@ +#pragma once +#include "world/tile/Tile.hpp" +#include "world/level/Tick.hpp" +#include "common/MovePriorityQueue.hpp" + +class TileSource; + +struct TickNextTickData +{ +public: + TilePos m_pos; + TileID m_tileID; + Tick_t m_tick; + +public: + TickNextTickData() + : m_pos(), m_tileID(0), m_tick(0) + { + } + TickNextTickData(const TilePos& pos, TileID tileID, Tick_t tick) + : m_pos(pos), m_tileID(tileID), m_tick(tick) + { + } + +public: + bool operator<(const TickNextTickData& other) const + { + return m_tick < other.m_tick; + } + bool operator>(const TickNextTickData& other) const + { + return m_tick > other.m_tick; + } + bool operator==(const TickNextTickData& other) const + { + return m_pos == other.m_pos && m_tileID == other.m_tileID; + } +}; + +class TileTickingQueue +{ +private: + Tick_t m_currentTick; + MovePriorityQueue m_tickData; + bool m_instaTick; + Random m_random; + +public: + TileTickingQueue(); + +public: + void add(TileSource* region, const TilePos& pos, TileID tileID, int tickDelay); + + bool tickPendingTicks(TileSource& region, Tick_t until, int max, bool instaTick); + void tickAllPendingTicks(TileSource& region); + + void save(CompoundTag& tag); + void load(const CompoundTag& tag); + +private: + void _tick(TileSource& region, const TilePos& pos, TileID tileID); +}; diff --git a/source/world/level/levelgen/biome/Biome.cpp b/source/world/level/levelgen/biome/Biome.cpp index e42f87ef1..64010df6c 100644 --- a/source/world/level/levelgen/biome/Biome.cpp +++ b/source/world/level/levelgen/biome/Biome.cpp @@ -9,6 +9,8 @@ #include "Biome.hpp" #include "world/tile/Tile.hpp" +std::vector Biome::EMPTY_MOBLIST; + Biome * Biome::rainForest, * Biome::swampland, diff --git a/source/world/level/levelgen/biome/Biome.hpp b/source/world/level/levelgen/biome/Biome.hpp index dbeadc4c9..f298cb3d3 100644 --- a/source/world/level/levelgen/biome/Biome.hpp +++ b/source/world/level/levelgen/biome/Biome.hpp @@ -9,11 +9,16 @@ #pragma once #include +#include #include "world/level/levelgen/synth/PerlinNoise.hpp" #include "world/level/levelgen/feature/Feature.hpp" +#include "world/entity/MobSpawnerData.hpp" class Biome { +public: + static std::vector EMPTY_MOBLIST; + public: // Static Functions static Biome* getBiome(float hum, float temp); static void initBiomes(); diff --git a/source/world/level/levelgen/chunk/Bounds.cpp b/source/world/level/levelgen/chunk/Bounds.cpp new file mode 100644 index 000000000..d63e3f124 --- /dev/null +++ b/source/world/level/levelgen/chunk/Bounds.cpp @@ -0,0 +1,21 @@ +#include "world/level/levelgen/chunk/Bounds.hpp" +#include "world/level/levelgen/chunk/ChunkPos.hpp" + +static Vec3Int32 convertTilePos(const TilePos& pos, int sides, bool noSides) +{ + return Vec3Int32( + ChunkPos::ToChunkCoordinate(pos.x), + noSides ? 0 : (Mth::clamp(pos.y, 0, 127) / sides), + ChunkPos::ToChunkCoordinate(pos.z) + ); +} + +Bounds::Bounds(const TilePos& min, const TilePos& max, int sides, bool noSides) + : _min(convertTilePos(min, sides, noSides)), + _max(convertTilePos(max, sides, noSides)), + _sides(sides) +{ + _dimensions = _max - _min + 1; + _area = _dimensions.x * _dimensions.z; + _volume = _dimensions.x * _dimensions.y * _dimensions.z; +} diff --git a/source/world/level/levelgen/chunk/Bounds.hpp b/source/world/level/levelgen/chunk/Bounds.hpp new file mode 100644 index 000000000..646d0fdea --- /dev/null +++ b/source/world/level/levelgen/chunk/Bounds.hpp @@ -0,0 +1,136 @@ +#pragma once +#include + +#include "world/level/TilePos.hpp" +#include "world/phys/Vec3Int32.hpp" +#include "world/level/levelgen/chunk/ChunkPos.hpp" + +struct Bounds +{ +public: + struct Iterator + { + Iterator(const Bounds& bounds, int startIndex = 0) + : _pos(bounds.getMin()) + , _bounds(bounds) + , _index(startIndex) + { + } + + Iterator& operator++() + { + _index++; + + _pos.x++; + if (_pos.x > _bounds.getMax().x) + { + _pos.z++; + if (_pos.z > _bounds.getMax().z) + { + _pos.y++; + } + } + + return *this; + } + + const Vec3Int32& operator*() const + { + return _pos; + } + + const Vec3Int32& pos() const + { + return _pos; + } + + bool end() const + { + return _index == _bounds.getVolume(); + } + + int index() const + { + return _index; + } + + private: + Vec3Int32 _pos; + const Bounds& _bounds; + int _index; + }; + +public: + Bounds() : _area(0), _volume(0), _sides(0) + { + } + + // TODO: move definition to the header + Bounds(const TilePos& min, const TilePos& max, int sides, bool noSides); + + const Vec3Int32& getMin() const + { + return _min; + } + + const Vec3Int32& getMax() const + { + return _max; + } + + const Vec3Int32& getDimensions() const + { + return _dimensions; + } + + int getArea() const + { + return _area; + } + + int getVolume() const + { + return _volume; + } + + int getSides() const + { + return _sides; + } + + Vec3 getCenter() const + { + return (_min + _max) * 0.5f; + } + + bool contains(const Vec3Int32& pos) const + { + if (!isValid()) + return false; + + return pos.x >= _min.x + && pos.x <= _max.x + && pos.y >= _min.y + && pos.y <= _max.y + && pos.z >= _min.z + && pos.z <= _max.z; + } + + bool isValid() const + { + return _area > 0; + } + + Iterator begin() const + { + return Bounds::Iterator(*this); + } + +private: + Vec3Int32 _min; + Vec3Int32 _max; + Vec3Int32 _dimensions; + int _area; + int _volume; + int _sides; +}; diff --git a/source/world/level/levelgen/chunk/ChunkCache.cpp b/source/world/level/levelgen/chunk/ChunkCache.cpp deleted file mode 100644 index 937e54b22..000000000 --- a/source/world/level/levelgen/chunk/ChunkCache.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "LevelChunk.hpp" -#include "ChunkCache.hpp" -#include "world/level/Level.hpp" -#include "EmptyLevelChunk.hpp" - -ChunkCache::ChunkCache(Level* pLevel, ChunkStorage* pStor, ChunkSource* pSrc) -{ - field_4 = true; - m_pLevel = nullptr; - m_pLastChunk = nullptr; - m_lastChunkPos = ChunkPos(-999999999, -999999999); - - m_pChunkSource = pSrc; - m_pChunkStorage = pStor; - m_pLevel = pLevel; - - m_pEmptyChunk = new EmptyLevelChunk(pLevel, nullptr, ChunkPos(0, 0)); - m_pEmptyChunk->field_236 = true; - - memset(m_chunkMap, 0, sizeof(m_chunkMap)); -} - -LevelChunk* ChunkCache::create(const ChunkPos& pos) -{ - return getChunk(pos); -} - -LevelChunk* ChunkCache::getChunk(const ChunkPos& pos) -{ - // get the last chunk quickly if needed - if (m_lastChunkPos == pos) - { - if (m_pLastChunk) - return m_pLastChunk; - } - - if (pos.x < 0 || pos.z < 0 || pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return m_pEmptyChunk; - - if (!hasChunk(pos)) - { - LevelChunk* pOldChunk = m_chunkMap[pos.z][pos.x]; - if (pOldChunk) - { - pOldChunk->unload(); - save(pOldChunk); - if (m_pChunkStorage) - m_pChunkStorage->saveEntities(m_pLevel, pOldChunk); - } - - LevelChunk* pChunk = load(pos); - if (pChunk) - { - m_chunkMap[pos.z][pos.x] = pChunk; - pChunk->lightLava(); - - TilePos global(pos, 0); - for (int i = global.x, m = 0; m < 16; i++, m++) - { - for (int j = global.z, n = 0; n < 16; j++, n++) - { - int height = m_pLevel->getHeightmap(TilePos(i, 0, j)); - if (height >= 0) - { - for (int k = height; k > 0; k--) - { - m_pLevel->updateLight(LightLayer::Sky, TilePos(global.x, k, global.z), TilePos(global.x, k, global.z)); - m_pLevel->updateLight(LightLayer::Block, TilePos(global.x-1, k, global.z-1), TilePos(global.x+1, k, global.z+1)); - } - } - } - } - } - else - { - pChunk = m_pEmptyChunk; - if (m_pChunkSource) - pChunk = m_pChunkSource->getChunk(pos); - - m_chunkMap[pos.z][pos.x] = pChunk; - pChunk->lightLava(); - } - - pChunk = m_chunkMap[pos.z][pos.x]; - if (pChunk) - pChunk->load(); - - if (!pChunk->field_234 && hasChunk(ChunkPos(pos.x + 1, pos.z + 1)) && hasChunk(ChunkPos(pos.x, pos.z + 1)) && hasChunk(ChunkPos(pos.x + 1, pos.z))) - postProcess(this, pos); - - //@OVERSIGHT: redundant call twice to hasChunk(x-1, z), hasChunk(x,z-1), and hasChunk(x-1,z-1) - if (hasChunk(ChunkPos(pos.x - 1, pos.z)) && !getChunk(ChunkPos(pos.x - 1, pos.z))->field_234 && hasChunk(ChunkPos(pos.x - 1, pos.z + 1)) && hasChunk(ChunkPos(pos.x, pos.z + 1)) && hasChunk(ChunkPos(pos.x - 1, pos.z))) - postProcess(this, ChunkPos(pos.x - 1, pos.z)); - - if (hasChunk(ChunkPos(pos.x, pos.z - 1)) && !getChunk(ChunkPos(pos.x, pos.z - 1))->field_234 && hasChunk(ChunkPos(pos.x + 1, pos.z - 1)) && hasChunk(ChunkPos(pos.x + 1, pos.z)) && hasChunk(ChunkPos(pos.x, pos.z - 1))) - postProcess(this, ChunkPos(pos.x, pos.z - 1)); - - if (hasChunk(pos - 1) && !getChunk(pos - 1)->field_234 && hasChunk(pos - 1) && hasChunk(ChunkPos(pos.x, pos.z - 1)) && hasChunk(ChunkPos(pos.x - 1, pos.z))) - postProcess(this, pos - 1); - } - - m_lastChunkPos = pos; - m_pLastChunk = m_chunkMap[pos.z][pos.x]; - return m_chunkMap[pos.z][pos.x]; -} - -LevelChunk* ChunkCache::getChunkDontCreate(const ChunkPos& pos) -{ - // get the last chunk quickly if needed - if (m_lastChunkPos == pos) - { - if (m_pLastChunk) - return m_pLastChunk; - } - - if (pos.x < 0 || pos.z < 0 || pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return m_pEmptyChunk; - - if (!hasChunk(pos)) - { - LevelChunk* pOldChunk = m_chunkMap[pos.z][pos.x]; - if (pOldChunk) - { - pOldChunk->unload(); - save(pOldChunk); - if (m_pChunkStorage) - m_pChunkStorage->saveEntities(m_pLevel, pOldChunk); - } - - // create an empty chunk - LevelChunk* pChunk = m_pEmptyChunk; - if (m_pChunkSource) - pChunk = m_pChunkSource->getChunkDontCreate(pos); - - m_chunkMap[pos.z][pos.x] = pChunk; - } - - m_lastChunkPos = pos; - m_pLastChunk = m_chunkMap[pos.z][pos.x]; - return m_pLastChunk; -} - -bool ChunkCache::hasChunk(const ChunkPos& pos) -{ - if (pos.x < 0 || pos.z < 0) - return true; - - if (pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return true; - - if (m_lastChunkPos == pos) - return true; - - LevelChunk* pChunk = m_chunkMap[pos.z][pos.x]; - if (!pChunk) - return false; - - if (pChunk == m_pEmptyChunk) - return true; - - return pChunk->isAt(pos); -} - -int ChunkCache::tick() -{ - if (m_pChunkStorage) - m_pChunkStorage->tick(); - - return m_pChunkSource->tick(); -} - -void ChunkCache::postProcess(ChunkSource* pChkSrc, const ChunkPos& pos) -{ - if (pos.x < 0 || pos.z < 0 || pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return; - - LevelChunk* pChunk = getChunk(pos); - if (!pChunk->field_234) - { - pChunk->field_234 = 1; - if (m_pChunkSource) - { - m_pChunkSource->postProcess(m_pChunkSource, pos); - pChunk->clearUpdateMap(); - } - } -} - -void ChunkCache::save(LevelChunk* pChunk) -{ - if (m_pChunkStorage) - { - pChunk->field_23C = m_pLevel->getTime(); - m_pChunkStorage->save(m_pLevel, pChunk); - } -} - -void ChunkCache::saveAll() -{ - if (!m_pChunkStorage) return; - - std::vector chunksToSave; - - ChunkPos pos(0, 0); - for (pos.z = 0; pos.z < C_MAX_CHUNKS_Z; pos.z++) - { - for (pos.x = 0; pos.x < C_MAX_CHUNKS_X; pos.x++) - { - chunksToSave.push_back(m_pLevel->getChunk(pos)); - } - } - - m_pChunkStorage->saveAll(m_pLevel, chunksToSave); -} - -#ifdef ENH_IMPROVED_SAVING - -void ChunkCache::saveUnsaved() -{ - if (!m_pChunkStorage) return; - - std::vector chunksToSave; - - ChunkPos pos(0, 0); - for (pos.z = 0; pos.z < C_MAX_CHUNKS_Z; pos.z++) - { - for (pos.x = 0; pos.x < C_MAX_CHUNKS_X; pos.x++) - { - LevelChunk* pChunk = m_pLevel->getChunk(pos); - if (!pChunk->m_bUnsaved) - continue; - - chunksToSave.push_back(pChunk); - } - } - - m_pChunkStorage->saveAll(m_pLevel, chunksToSave); -} - -#endif - -bool ChunkCache::shouldSave() -{ - return true; -} - -std::string ChunkCache::gatherStats() -{ - return "ChunkCache: 1024"; -} - -ChunkCache::~ChunkCache() -{ - SAFE_DELETE(m_pChunkSource); - SAFE_DELETE(m_pEmptyChunk); - - for (int i = 0; i < C_MAX_CHUNKS_Z; i++) - for (int j = 0; j < C_MAX_CHUNKS_X; j++) - { - LevelChunk* pChk = m_chunkMap[i][j]; - if (pChk) - { - pChk->deleteBlockData(); - SAFE_DELETE(pChk); - } - } -} - -LevelChunk* ChunkCache::load(const ChunkPos& pos) -{ - if (!m_pChunkStorage) - return m_pEmptyChunk; - - if (pos.x < 0 || pos.z < 0 || pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return m_pEmptyChunk; - - LevelChunk* pChk = m_pChunkStorage->load(m_pLevel, pos); - if (pChk) - pChk->field_23C = m_pLevel->getTime(); - - return pChk; -} diff --git a/source/world/level/levelgen/chunk/ChunkCache.hpp b/source/world/level/levelgen/chunk/ChunkCache.hpp deleted file mode 100644 index 8fcdf48ea..000000000 --- a/source/world/level/levelgen/chunk/ChunkCache.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include -#include "ChunkSource.hpp" -#include "world/level/storage/ChunkStorage.hpp" -#include "world/level/Level.hpp" - -class Level; - -class ChunkCache : public ChunkSource -{ -public: - ChunkCache(Level*, ChunkStorage*, ChunkSource*); - virtual ~ChunkCache(); - - LevelChunk* create(const ChunkPos& pos) override; - LevelChunk* getChunk(const ChunkPos& pos) override; - LevelChunk* getChunkDontCreate(const ChunkPos& pos) override; - bool hasChunk(const ChunkPos& pos) override; - std::string gatherStats() override; - void postProcess(ChunkSource*, const ChunkPos& pos) override; - bool shouldSave() override; - void saveAll() override; - int tick() override; -#ifdef ENH_IMPROVED_SAVING - void saveUnsaved() override; -#endif - - LevelChunk* load(const ChunkPos& pos); - void save(LevelChunk*); - -public: - bool field_4; - LevelChunk* m_pEmptyChunk; - ChunkSource* m_pChunkSource; - ChunkStorage* m_pChunkStorage; - LevelChunk* m_chunkMap[C_MAX_CHUNKS_Z][C_MAX_CHUNKS_X]; - Level* m_pLevel; - LevelChunk* m_pLastChunk; - ChunkPos m_lastChunkPos; -}; - diff --git a/source/world/level/levelgen/chunk/ChunkConstants.hpp b/source/world/level/levelgen/chunk/ChunkConstants.hpp new file mode 100644 index 000000000..fd99f53c9 --- /dev/null +++ b/source/world/level/levelgen/chunk/ChunkConstants.hpp @@ -0,0 +1,30 @@ +#pragma once +#include "compat/LegacyCPP.hpp" + +class ChunkConstants +{ +public: + // The size of a chunk in the X and Z directions + static constexpr int XZ_SIZE = 16; + + // The size of a chunk in the Y direction + static constexpr int Y_SIZE = 128; + + // Number of tiles per row of a chunk + static constexpr int TILE_COUNT_PER_ROW = XZ_SIZE * XZ_SIZE; + + // Number of tiles in a whole chunk + static constexpr int TILE_COUNT = TILE_COUNT_PER_ROW * Y_SIZE; + + // The size of a chunk mesh in all axis + static constexpr int MESH_XYZ_SIZE = XZ_SIZE; + + // Number of tiles per row in a chunk mesh + static constexpr int MESH_TILE_COUNT_PER_ROW = MESH_XYZ_SIZE * MESH_XYZ_SIZE; + + // Number of tiles in a chunk mesh + static constexpr int MESH_TILE_COUNT = MESH_XYZ_SIZE * MESH_XYZ_SIZE * MESH_XYZ_SIZE; + + // How many meshes each chunk should be split by their Y-axis. + static constexpr int MESH_COUNT = TILE_COUNT / MESH_TILE_COUNT; +}; diff --git a/source/world/level/levelgen/chunk/ChunkPos.hpp b/source/world/level/levelgen/chunk/ChunkPos.hpp index 01135b194..56893f6c3 100644 --- a/source/world/level/levelgen/chunk/ChunkPos.hpp +++ b/source/world/level/levelgen/chunk/ChunkPos.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #ifndef __VEC3_HPP class Vec3; @@ -12,6 +13,7 @@ struct TilePos; struct ChunkPos { +public: int x, z; private: @@ -27,6 +29,12 @@ struct ChunkPos ChunkPos(const Vec3& pos) { _init(pos); } ChunkPos(const TilePos& pos) { _init(pos); } + int hashCode() const + { + // From Java + return x << 8 | z; + } + int lengthSqr() const { return x * x + z * z; @@ -41,7 +49,9 @@ struct ChunkPos ChunkPos operator-(const ChunkPos& b) const; ChunkPos operator-(int i) const; void operator+=(const ChunkPos& b); + void operator+=(int i); void operator-=(const ChunkPos& b); + void operator-=(int i); void operator*=(int i); ChunkPos operator-() const; ChunkPos operator*(int i) const; @@ -60,4 +70,20 @@ struct ChunkPos { return int(floorf(value / 16)); } + +public: + static const ChunkPos INVALID; }; + +namespace std +{ + template <> + class hash + { + public: + size_t operator()(const ChunkPos& cp) const + { + return cp.hashCode(); + } + }; +} diff --git a/source/world/level/levelgen/chunk/ChunkRefCount.cpp b/source/world/level/levelgen/chunk/ChunkRefCount.cpp new file mode 100644 index 000000000..49929ee47 --- /dev/null +++ b/source/world/level/levelgen/chunk/ChunkRefCount.cpp @@ -0,0 +1,50 @@ +#include "world/level/levelgen/chunk/ChunkRefCount.hpp" + +ChunkRefCount::ChunkRefCount() + : m_refCount(0), + m_chunk(nullptr) +{ +} + +ChunkRefCount::ChunkRefCount(LevelChunk& chunk, int refCount) + : m_refCount(refCount), + m_chunk(&chunk) +{ +} + +ChunkRefCount::ChunkRefCount(std::unique_ptr&& chunk, int refCount) + : m_refCount(refCount), + m_chunk(chunk.get()) +{ + m_chunk = nullptr; +} + +ChunkRefCount::~ChunkRefCount() +{ + delete m_chunk; +} + +LevelChunk* ChunkRefCount::get() const +{ + return m_chunk; +} + +LevelChunk* ChunkRefCount::grab() +{ + m_refCount++; + return get(); +} + +bool ChunkRefCount::release() +{ + return --m_refCount != 0; +} + +void ChunkRefCount::_move(ChunkRefCount& other) +{ + delete m_chunk; + m_chunk = other.m_chunk; + m_refCount = other.m_refCount; + other.m_chunk = nullptr; + other.m_refCount = 0; +} diff --git a/source/world/level/levelgen/chunk/ChunkRefCount.hpp b/source/world/level/levelgen/chunk/ChunkRefCount.hpp new file mode 100644 index 000000000..2cc45427b --- /dev/null +++ b/source/world/level/levelgen/chunk/ChunkRefCount.hpp @@ -0,0 +1,28 @@ +#pragma once +#include +#include "compat/LegacyCPP_Compat.hpp" + +class LevelChunk; + +class ChunkRefCount +{ +private: + int m_refCount; + LevelChunk* m_chunk; + +public: + ChunkRefCount(); + ChunkRefCount(LevelChunk& chunk, int refCount); + ChunkRefCount(std::unique_ptr&& chunk, int refCount); + MC_CTOR_MOVE(ChunkRefCount); + ~ChunkRefCount(); + +public: + MC_FUNC_MOVE(ChunkRefCount); + LevelChunk* get() const; + LevelChunk* grab(); + bool release(); + +private: + void _move(ChunkRefCount& other); +}; diff --git a/source/world/level/levelgen/chunk/ChunkSource.cpp b/source/world/level/levelgen/chunk/ChunkSource.cpp index 6f829a399..3e2236a3e 100644 --- a/source/world/level/levelgen/chunk/ChunkSource.cpp +++ b/source/world/level/levelgen/chunk/ChunkSource.cpp @@ -6,20 +6,280 @@ SPDX-License-Identifier: BSD-1-Clause ********************************************************************/ -#include "ChunkSource.hpp" +#include "world/level/levelgen/chunk/ChunkSource.hpp" +#include "world/level/levelgen/chunk/ChunkViewSource.hpp" +#include "world/level/levelgen/biome/Biome.hpp" +#include "world/level/Level.hpp" +#include "common/threading/BackgroundQueuePool.hpp" + +ChunkSource::ChunkSource(Level* level, Dimension* dimension, int chunkSide) + : m_chunkSide(chunkSide), + m_level(level), + m_dimension(dimension), + m_parent(nullptr), + m_ownedParent() +{ +} + +ChunkSource::ChunkSource(ChunkSource& parent) + : m_chunkSide(parent.m_chunkSide), + m_level(parent.m_level), + m_dimension(parent.m_dimension), + m_parent(&parent), + m_ownedParent() +{ +} + +ChunkSource::ChunkSource(std::unique_ptr parent) + : m_chunkSide(parent->m_chunkSide), + m_level(parent->m_level), + m_dimension(parent->m_dimension), + m_parent(parent.get()), + m_ownedParent(std::move(parent)) +{ +} ChunkSource::~ChunkSource() { } -void ChunkSource::saveAll() +LevelChunk* ChunkSource::getGeneratedChunk(const ChunkPos& pos) +{ + LevelChunk* chunk = getExistingChunk(pos); + if (!chunk) + return nullptr; + + if (chunk->getState() <= CS_GENERATING) + return nullptr; + + return chunk; +} + +LevelChunk* ChunkSource::getAvailableChunk(const ChunkPos& pos) +{ + LevelChunk* chunk = getExistingChunk(pos); + if (!chunk) + return nullptr; + + if (chunk->getState() <= CS_POST_PROCESSING) + return nullptr; + + return chunk; +} + +LevelChunk* ChunkSource::getAvailableChunkAt(const TilePos& tilePos) +{ + return getAvailableChunk(tilePos); +} + +LevelChunk* ChunkSource::getExistingChunk(const ChunkPos& pos) +{ + return nullptr; +} + +LevelChunk* ChunkSource::requestChunk(const ChunkPos& pos, LoadMode loadMode) +{ + if (m_parent) + return m_parent->requestChunk(pos, loadMode); + + return nullptr; +} + +bool ChunkSource::releaseChunk(LevelChunk& chunk) +{ + if (m_parent) + return m_parent->releaseChunk(chunk); + + return false; +} + +bool ChunkSource::postProcess(ChunkViewSource& chunkViewSource) +{ + return true; +} + +void ChunkSource::loadChunk(LevelChunk& chunk) +{ + if (m_parent) + return m_parent->loadChunk(chunk); +} + +bool ChunkSource::_asyncChunkTask(LevelChunk* chunk) +{ + if (chunk->tryChangeState(CS_UNLOADED, CS_GENERATING)) + loadChunk(*chunk); + + return true; +} + +void ChunkSource::_asyncChunkTaskCallback(LevelChunk* chunk) +{ + if (!releaseChunk(*chunk)) + _startPostProcessingArea(*chunk); +} + +LevelChunk* ChunkSource::getOrLoadChunk(const ChunkPos& pos, LoadMode loadMode) +{ + LevelChunk* chunk = requestChunk(pos, loadMode); + + if (!m_level || !m_level->m_bIsClientSide) + { + if (chunk && loadMode == LOAD_DEFERRED && chunk->getState() == CS_UNLOADED) + { + requestChunk(pos, LOAD_NONE); + + BackgroundQueuePool::GetFor(BackgroundQueuePool::QR_STREAMING).queue( + std::bind(&ChunkSource::_asyncChunkTask, this, chunk), + std::bind(&ChunkSource::_asyncChunkTaskCallback, this, chunk), + static_cast(_getMinPlayerDistance(*chunk)) + 16 + ); + } + } + + return chunk; +} + +void ChunkSource::postProcessMobsAt(TileSource* tileSource, int unk1, int unk2, Random& random) +{ + if (m_parent) + m_parent->postProcessMobsAt(tileSource, unk1, unk2, random); +} + +const std::vector& ChunkSource::getMobsAt(TileSource& tileSource, EntityType entityType, const TilePos& pos) { + if (m_parent) + return m_parent->getMobsAt(tileSource, entityType, pos); + return Biome::EMPTY_MOBLIST; } -#ifdef ENH_IMPROVED_SAVING -void ChunkSource::saveUnsaved() +bool ChunkSource::saveLiveChunk(LevelChunk& chunk) { + if (m_parent) + return m_parent->saveLiveChunk(chunk); + + return false; +} + +void ChunkSource::discard(std::unique_ptr& chunk) +{ + if (m_parent) + m_parent->acquireDiscarded(std::move(chunk)); +} + +void ChunkSource::discard(LevelChunk& chunk) +{ + discard(std::unique_ptr(&chunk)); + delete& chunk; // brother, what the fuck +} + +void ChunkSource::hintDiscardBatchBegin() +{ + if (m_parent) + return m_parent->hintDiscardBatchBegin(); +} + +void ChunkSource::hintDiscardBatchEnd() +{ + if (m_parent) + return m_parent->hintDiscardBatchEnd(); +} + +void ChunkSource::acquireDiscarded(std::unique_ptr&& chunk) +{ + if (m_parent) + return m_parent->acquireDiscarded(std::move(chunk)); +} + +const ChunkSource::ChunkMap_t& ChunkSource::getStoredChunks() +{ + assert(m_parent != nullptr); + return m_parent->getStoredChunks(); +} + +void ChunkSource::compact() +{ + if (m_parent) + return m_parent->compact(); +} + +void ChunkSource::waitDiscardFinished() +{ + if (m_parent) + return m_parent->waitDiscardFinished(); +} + +LevelChunk* _chunkViewGenerate(ChunkSource::LoadMode loadMode, ChunkSource* source, const Vec3Int32& pos) +{ + ChunkPos chunkPos(pos.x, pos.y, pos.z); + return source->getOrLoadChunk(chunkPos, loadMode); +} + +void _chunkViewClear(ChunkSource::LoadMode loadMode, ChunkSource* source, LevelChunk*& chunk) +{ + source->releaseChunk(*chunk); +} + +GridArea ChunkSource::getView(const TilePos& tileMin, const TilePos& tileMax, LoadMode loadMode, bool circular, const std::function& addCallback, const std::function& moveCallback) +{ + TilePos minPos(tileMin.x, 0, tileMin.z); + TilePos maxPos(tileMax.x, 0, tileMax.z); + + std::function generate = std::bind(&_chunkViewGenerate, loadMode, this, std::placeholders::_1); + std::function clearCallback = std::bind(&_chunkViewClear, loadMode, this, std::placeholders::_1); + + return GridArea(minPos, maxPos, 16, generate, clearCallback, circular, addCallback, moveCallback); +} + +GridArea ChunkSource::getView(const TilePos& pos, int spread, LoadMode loadMode, bool circular, const std::function& addCallback, const std::function& moveCallback) +{ + return getView(pos - spread, pos + spread, loadMode, circular, addCallback, moveCallback); +} + +void ChunkSource::_fireChunkLoaded(LevelChunk& chunk) +{ + if (m_level) + { + if (!m_level->m_bIsClientSide) + m_level->onChunkLoaded(chunk); + } +} + +bool ChunkSource::_asyncPostProcessingTask(LevelChunk* chunk, std::shared_ptr cvs) +{ + if (!chunk->tryChangeState(CS_GENERATED, CS_POST_PROCESSING)) + return true; + + bool success = chunk->getGenerator()->postProcess(*cvs); + if (success) + { + chunk->changeState(CS_POST_PROCESSING, CS_POST_PROCESSED); + return true; + } + else + { + chunk->changeState(CS_POST_PROCESSING, CS_GENERATED); + return false; + } +} + +void ChunkSource::_asyncPostProcessingCallback(LevelChunk* chunk, std::shared_ptr cvs) +{ + if (chunk->getState() == CS_POST_PROCESSED) + _fireChunkLoaded(*chunk); + + cvs->clear(); +} + +void ChunkSource::_startPostProcessing(LevelChunk& chunk) +{ + std::shared_ptr cvs(new ChunkViewSource(*this, LOAD_NONE)); + + cvs->move(chunk.getMinPos() - ChunkConstants::XZ_SIZE, chunk.getMaxPos() + ChunkConstants::XZ_SIZE); + BackgroundQueuePool::GetFor(BackgroundQueuePool::QR_STREAMING).queue( + std::bind(&ChunkSource::_asyncPostProcessingTask, this, &chunk, cvs), + std::bind(&ChunkSource::_asyncPostProcessingCallback, this, &chunk, cvs), + static_cast(_getMinPlayerDistance(chunk)) + 32 + ); } -#endif diff --git a/source/world/level/levelgen/chunk/ChunkSource.hpp b/source/world/level/levelgen/chunk/ChunkSource.hpp index 7647e7253..19925a339 100644 --- a/source/world/level/levelgen/chunk/ChunkSource.hpp +++ b/source/world/level/levelgen/chunk/ChunkSource.hpp @@ -8,26 +8,99 @@ #pragma once #include +#include #include "world/level/levelgen/chunk/LevelChunk.hpp" -#include "GameMods.hpp" +#include "world/level/levelgen/chunk/ChunkRefCount.hpp" +#include "world/level/levelgen/chunk/GridArea.hpp" +#include "world/entity/MobSpawnerData.hpp" +#include "world/entity/EntityType.hpp" + class Level; class LevelChunk; +class Dimension; +class Random; +class ChunkViewSource; class ChunkSource { public: + enum LoadMode + { + LOAD_NONE, + LOAD_DEFERRED + }; + + typedef std::unordered_map ChunkMap_t; + +protected: + int m_chunkSide; + Level* m_level; + Dimension* m_dimension; + ChunkSource* m_parent; + std::unique_ptr m_ownedParent; + +public: + ChunkSource(Level* level, Dimension* dimension, int chunkSide); + ChunkSource(ChunkSource& parent); + ChunkSource(std::unique_ptr parent); virtual ~ChunkSource(); - virtual bool hasChunk(const ChunkPos& pos) = 0; - virtual LevelChunk* getChunk(const ChunkPos& pos) = 0; - virtual LevelChunk* create(const ChunkPos& pos) = 0; - virtual LevelChunk* getChunkDontCreate(const ChunkPos& pos) = 0; - virtual void postProcess(ChunkSource*, const ChunkPos& pos) = 0; - virtual int tick() = 0; - virtual bool shouldSave() = 0; - virtual void saveAll(); - virtual std::string gatherStats() = 0; -#ifdef ENH_IMPROVED_SAVING - virtual void saveUnsaved(); -#endif + +public: + int getChunkSide() const + { + return m_chunkSide; + } + Level& getLevel() const + { + return *m_level; + } + const Level& getLevelConst() const + { + return *m_level; + } + Dimension& getDimension() const + { + return *m_dimension; + } + const Dimension& getDimensionConst() const + { + return *m_dimension; + } + LevelChunk* getGeneratedChunk(const ChunkPos& pos); + LevelChunk* getAvailableChunk(const ChunkPos& pos); + LevelChunk* getAvailableChunkAt(const TilePos& tilePos); + virtual LevelChunk* getExistingChunk(const ChunkPos& pos); + virtual LevelChunk* requestChunk(const ChunkPos& pos, LoadMode loadMode); + virtual bool releaseChunk(LevelChunk& chunk); + virtual bool postProcess(ChunkViewSource& chunkViewSource); + virtual void loadChunk(LevelChunk& chunk); + LevelChunk* getOrLoadChunk(const ChunkPos& pos, LoadMode loadMode); + virtual void postProcessMobsAt(TileSource* tileSource, int, int, Random& random); + virtual const std::vector& getMobsAt(TileSource& tileSource, EntityType entityType, const TilePos& pos); + virtual bool saveLiveChunk(LevelChunk& chunk); + void discard(std::unique_ptr& chunk); + void discard(LevelChunk& chunk); + virtual void hintDiscardBatchBegin(); + virtual void hintDiscardBatchEnd(); + virtual void acquireDiscarded(std::unique_ptr&& chunk); + virtual const ChunkMap_t& getStoredChunks(); + virtual void compact(); + virtual void waitDiscardFinished(); + virtual GridArea getView(const TilePos& tileMin, const TilePos& tileMax, LoadMode loadMode, bool circular, const std::function& addCallback, const std::function& moveCallback); + GridArea getView(const TilePos& pos, int spread, LoadMode loadMode, bool circular, const std::function& addCallback, const std::function& moveCallback); + +protected: + float _getMinPlayerDistance(const LevelChunk& chunk); + + void _fireChunkLoaded(LevelChunk& chunk); + + void _startPostProcessing(LevelChunk& chunk); + void _startPostProcessingArea(LevelChunk& chunk); + + bool _asyncChunkTask(LevelChunk* chunk); + void _asyncChunkTaskCallback(LevelChunk* chunk); + + bool _asyncPostProcessingTask(LevelChunk* chunk, std::shared_ptr cvs); + void _asyncPostProcessingCallback(LevelChunk* chunk, std::shared_ptr cvs); }; diff --git a/source/world/level/levelgen/chunk/ChunkTilePos.hpp b/source/world/level/levelgen/chunk/ChunkTilePos.hpp index 923a430f3..68bd74a0e 100644 --- a/source/world/level/levelgen/chunk/ChunkTilePos.hpp +++ b/source/world/level/levelgen/chunk/ChunkTilePos.hpp @@ -2,6 +2,7 @@ #include #include "world/level/TilePos.hpp" +#include "world/level/levelgen/chunk/ChunkConstants.hpp" struct ChunkTilePos { @@ -13,10 +14,25 @@ struct ChunkTilePos public: ChunkTilePos() { _init(0, 0, 0); } ChunkTilePos(uint8_t _x, uint8_t _y, uint8_t _z) { _init(_x, _y, _z); } - ChunkTilePos(const TilePos& pos) { _init(pos.x & 0xF, pos.y, pos.z & 0xF); } // & 0xF on x and y to get them to uint8_t + ChunkTilePos(const TilePos& pos) { _init(pos.x & (ChunkConstants::XZ_SIZE - 1), pos.y, pos.z & (ChunkConstants::XZ_SIZE - 1)); } - ChunkTilePos operator+(const TilePos& other) const + ChunkTilePos operator+(const ChunkTilePos& other) const { return ChunkTilePos(x + other.x, y + other.y, z + other.z); } + + TilePos operator+(const TilePos& other) const + { + return TilePos(x + other.x, y + other.y, z + other.z); + } + + int index() const + { + return (x << 11) | (z << 7) | y; + } + + int index2D() const + { + return (z << 4) | x; + } }; diff --git a/source/world/level/levelgen/chunk/ChunkViewSource.cpp b/source/world/level/levelgen/chunk/ChunkViewSource.cpp new file mode 100644 index 000000000..b8fb76cf8 --- /dev/null +++ b/source/world/level/levelgen/chunk/ChunkViewSource.cpp @@ -0,0 +1,37 @@ +#include "world/level/levelgen/chunk/ChunkViewSource.hpp" + +ChunkViewSource::ChunkViewSource(ChunkSource& parent, LoadMode parentLoadMode) + : ChunkSource(parent), + m_parentLoadMode(parentLoadMode) +{ +} + +ChunkViewSource::~ChunkViewSource() +{ +} + +LevelChunk* ChunkViewSource::getExistingChunk(const ChunkPos& pos) +{ + Vec3Int32 gridPos(pos.x, 0, pos.z); + if (m_gridArea.contains(gridPos)) + return m_gridArea.at(gridPos); + + return nullptr; +} + +void ChunkViewSource::move(const TilePos& tileMin, const TilePos& tileMax) +{ + if (m_gridArea.getBounds().getSides() != 0) + { + m_gridArea.move(tileMin, tileMax); + } + else + { + m_gridArea = m_parent->getView(tileMin, tileMax, m_parentLoadMode, false, nullptr, nullptr); + } +} + +void ChunkViewSource::clear() +{ + m_gridArea.clear(); +} diff --git a/source/world/level/levelgen/chunk/ChunkViewSource.hpp b/source/world/level/levelgen/chunk/ChunkViewSource.hpp new file mode 100644 index 000000000..0a94fb674 --- /dev/null +++ b/source/world/level/levelgen/chunk/ChunkViewSource.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "world/level/levelgen/chunk/ChunkSource.hpp" + +class ChunkViewSource : public ChunkSource +{ +protected: + LoadMode m_parentLoadMode; + GridArea m_gridArea; + +public: + ChunkViewSource(ChunkSource& parent, LoadMode parentLoadMode); + virtual ~ChunkViewSource(); + +public: + LevelChunk* getExistingChunk(const ChunkPos& pos) override; + void move(const TilePos& tileMin, const TilePos& tileMax); + void clear(); + + const Bounds& getBounds() const + { + return m_gridArea.getBounds(); + } +}; diff --git a/source/world/level/levelgen/chunk/DataLayer.cpp b/source/world/level/levelgen/chunk/DataLayer.cpp deleted file mode 100644 index b023bbb37..000000000 --- a/source/world/level/levelgen/chunk/DataLayer.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include - -#include "DataLayer.hpp" - -#include "compat/LegacyCPP.hpp" - -DataLayer::DataLayer() -{ - m_size = 0; - m_data = nullptr; -} - -DataLayer::DataLayer(unsigned int size) -{ - m_size = size; - m_data = new uint8_t[m_size]; - memset(m_data, 0, m_size); -} - -uint8_t DataLayer::get(const ChunkTilePos& pos) -{ - int index = pos.y | (pos.x << 11); - uint8_t data = m_data[(index | (pos.z << 7)) >> 1]; - - if ((index & 1) != 0) - return data >> 4; - return data & 0xF; -} - -void DataLayer::set(const ChunkTilePos& pos, uint8_t data) -{ - int index1 = pos.y | (pos.x << 11) | (pos.z << 7); - unsigned int index2 = index1 >> 1; - uint8_t v7 = data; - bool v8 = (index1 & 1) == 0; - uint8_t v9 = m_data[index2]; - uint8_t v10; - if (v8) - { - v7 = data & 0xF; - v10 = v9 & 0xF0; - } - else - { - v10 = v9 & 0xF; - } - uint8_t v11; - if (v8) - v11 = v7 | v10; - else - v11 = v10 | (16 * v7); - m_data[index2] = v11; - - /* - - data &= 0xF; - - int index = pos.y | (pos.x << 11) | (pos.z << 7); - - uint8_t& xdata = m_data[index >> 1]; - if (index & 1) - xdata = (xdata & 0x0F) | (data << 4); - else - xdata = (xdata & 0xF0) | (data); - - */ -} diff --git a/source/world/level/levelgen/chunk/DataLayer.hpp b/source/world/level/levelgen/chunk/DataLayer.hpp deleted file mode 100644 index 9c029433d..000000000 --- a/source/world/level/levelgen/chunk/DataLayer.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include - -#include "world/level/levelgen/chunk/ChunkTilePos.hpp" - -class DataLayer -{ -public: - DataLayer(); - DataLayer(unsigned int size); - -public: - uint8_t get(const ChunkTilePos& pos); - void set(const ChunkTilePos& pos, uint8_t data); - -public: - uint8_t* m_data; - unsigned int m_size; -}; diff --git a/source/world/level/levelgen/chunk/EmptyChunkSource.cpp b/source/world/level/levelgen/chunk/EmptyChunkSource.cpp new file mode 100644 index 000000000..323357934 --- /dev/null +++ b/source/world/level/levelgen/chunk/EmptyChunkSource.cpp @@ -0,0 +1,27 @@ +#include "world/level/levelgen/chunk/EmptyChunkSource.hpp" + +EmptyChunkSource::EmptyChunkSource(Level* level, Dimension* dimension) + : ChunkSource(level, dimension, 16) +{ +} + +LevelChunk* EmptyChunkSource::requestChunk(const ChunkPos& pos, LoadMode loadMode) +{ + if (loadMode == LOAD_DEFERRED) + return new LevelChunk(*m_level, *m_dimension, pos, false); + + return nullptr; +} + +bool EmptyChunkSource::postProcess(ChunkViewSource& chunkViewSource) +{ + return true; +} + +void EmptyChunkSource::loadChunk(LevelChunk& chunk) +{ + memset(chunk.getTiles(), TILE_AIR, ChunkConstants::TILE_COUNT); + chunk.setFinalized(LevelChunk::CF_DONE); + chunk.setSaved(); + chunk.changeState(CS_GENERATING, CS_POST_PROCESSED); +} diff --git a/source/world/level/levelgen/chunk/EmptyChunkSource.hpp b/source/world/level/levelgen/chunk/EmptyChunkSource.hpp new file mode 100644 index 000000000..10e2c16a1 --- /dev/null +++ b/source/world/level/levelgen/chunk/EmptyChunkSource.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "world/level/levelgen/chunk/ChunkSource.hpp" + +class EmptyChunkSource : public ChunkSource +{ +public: + EmptyChunkSource(Level* level, Dimension* dimension); + +public: + LevelChunk* requestChunk(const ChunkPos& pos, LoadMode loadMode) override; + bool postProcess(ChunkViewSource& chunkViewSource) override; + void loadChunk(LevelChunk& chunk) override; +}; diff --git a/source/world/level/levelgen/chunk/EmptyLevelChunk.cpp b/source/world/level/levelgen/chunk/EmptyLevelChunk.cpp deleted file mode 100644 index 749baa4af..000000000 --- a/source/world/level/levelgen/chunk/EmptyLevelChunk.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "EmptyLevelChunk.hpp" -#include "world/tile/Tile.hpp" - -EmptyLevelChunk::EmptyLevelChunk(Level* pLevel, TileID* pBlockData, const ChunkPos& pos) - :LevelChunk(pLevel, pBlockData, pos) -{ -} - -int EmptyLevelChunk::getHeightmap(const ChunkTilePos& pos) -{ - return 0; -} - -void EmptyLevelChunk::recalcHeightmap() -{ - -} - -void EmptyLevelChunk::recalcHeightmapOnly() -{ - -} - -int EmptyLevelChunk::getRawBrightness(const ChunkTilePos& pos, int skySubtract) -{ - return 7; -} - -void EmptyLevelChunk::addEntity(Entity*) -{ - -} - -void EmptyLevelChunk::removeEntity(Entity*) -{ - -} - -void EmptyLevelChunk::removeEntity(Entity*, int vec) -{ - -} - -void EmptyLevelChunk::updateEntity(Entity* pEnt) -{ - -} - -bool EmptyLevelChunk::isSkyLit(const ChunkTilePos& pos) -{ - return false; -} - -void EmptyLevelChunk::lightLava() -{ - -} - -void EmptyLevelChunk::recalcBlockLights() -{ - -} - -void EmptyLevelChunk::skyBrightnessChanged() -{ - -} - -void EmptyLevelChunk::load() -{ - -} - -void EmptyLevelChunk::unload() -{ - -} - -void EmptyLevelChunk::markUnsaved() -{ - -} - -TileID EmptyLevelChunk::getTile(const ChunkTilePos& pos) -{ - return Tile::invisible_bedrock->m_ID; -} - -bool EmptyLevelChunk::setTile(const ChunkTilePos& pos, TileID tile) -{ - return true; -} - -bool EmptyLevelChunk::setTileAndData(const ChunkTilePos& pos, TileID tile, TileData data) -{ - return true; -} - -TileData EmptyLevelChunk::getData(const ChunkTilePos& pos) -{ - return 0; -} - -bool EmptyLevelChunk::setData(const ChunkTilePos& pos, TileData data) -{ - return false; -} - -void EmptyLevelChunk::recalcHeight(const ChunkTilePos& pos) -{ - -} - -bool EmptyLevelChunk::isEmpty() -{ - return true; -} diff --git a/source/world/level/levelgen/chunk/EmptyLevelChunk.hpp b/source/world/level/levelgen/chunk/EmptyLevelChunk.hpp deleted file mode 100644 index 15a781617..000000000 --- a/source/world/level/levelgen/chunk/EmptyLevelChunk.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include "LevelChunk.hpp" - -//@OVERSIGHT: Why the hell is EmptyLevelChunk derived from the WHOLE of LevelChunk?! -class EmptyLevelChunk : public LevelChunk -{ -public: - EmptyLevelChunk(Level*, TileID* pBlockData, const ChunkPos& pos); - - int getHeightmap(const ChunkTilePos& pos) override; - void recalcHeightmap() override; - void recalcHeightmapOnly() override; - int getRawBrightness(const ChunkTilePos& pos, int skySubtract) override; - void addEntity(Entity*) override; - void removeEntity(Entity*) override; - void removeEntity(Entity*, int vec) override; - void updateEntity(Entity* pEnt) override; - bool isSkyLit(const ChunkTilePos& pos) override; - void lightLava() override; - void recalcBlockLights() override; - void skyBrightnessChanged() override; - void load() override; - void unload() override; - void markUnsaved() override; - TileID getTile(const ChunkTilePos& pos) override; - bool setTile(const ChunkTilePos& pos, TileID tile) override; - bool setTileAndData(const ChunkTilePos& pos, TileID tile, TileData data) override; - TileData getData(const ChunkTilePos& pos) override; - bool setData(const ChunkTilePos& pos, TileData data) override; - void recalcHeight(const ChunkTilePos& pos) override; - bool isEmpty() override; -}; diff --git a/source/world/level/levelgen/chunk/GridArea.hpp b/source/world/level/levelgen/chunk/GridArea.hpp new file mode 100644 index 000000000..d13ca59bd --- /dev/null +++ b/source/world/level/levelgen/chunk/GridArea.hpp @@ -0,0 +1,235 @@ +#pragma once +#include +#include +#include "world/level/levelgen/chunk/Bounds.hpp" +#include "world/level/levelgen/chunk/ChunkPos.hpp" + +template +class GridArea +{ +public: + GridArea() + : m_circular(false) + { + } + + GridArea( + const TilePos& min, + const TilePos& max, + int sides, + const std::function& generate, + const std::function& clearCallback, + bool circular, + const std::function& addCallback, + const std::function& moveCallback) + : m_generate(generate), + m_clearCallback(clearCallback), + m_addCallback(addCallback), + m_moveCallback(moveCallback), + m_bounds(min, max, sides, false), + m_circular(circular) + { + m_chunks.resize(m_bounds.getVolume()); + + if (m_generate) + _fill(); + } + + MC_CTOR_MOVE(GridArea); + + ~GridArea() + { + clear(); + } + +public: + void move(const TilePos& tileMin, const TilePos& tileMax) + { + Bounds newBounds(tileMin, tileMax, m_bounds.getSides(), false); + + m_newChunks.resize(newBounds.getVolume()); + + _moveOldChunks(newBounds); + + if (m_clearCallback) + { + _callback(m_moveCallback); + _callback(m_clearCallback); + } + + m_bounds = newBounds; + m_chunks = m_newChunks; + + if (m_generate) + _fill(); + } + + void clear() + { + _callback(m_clearCallback); + + m_bounds = Bounds(); + m_chunks.clear(); + } + + const T& at(const Vec3Int32& pos) const + { + assert(contains(pos)); + return m_chunks[_getChunkIndex(m_bounds, pos)]; + } + + bool contains(const Vec3Int32& pos) const + { + if (m_chunks.empty()) + return false; + + return m_bounds.contains(pos); + } + + const Bounds& getBounds() const + { + return m_bounds; + } + + bool empty() const + { + return m_chunks.empty(); + } + + MC_FUNC_MOVE(GridArea); + +private: + static int _getChunkIndex(const Bounds& bounds, const Vec3Int32& pos) + { + return (pos.x - bounds.getMin().x) + bounds.getDimensions().x * (pos.z - bounds.getMin().z) + bounds.getArea() * (pos.y - bounds.getMin().y); + } + + void _callback(const std::function& callback) + { + if (callback) + { + for (typename std::vector::iterator iter = m_chunks.begin(); iter != m_chunks.end(); iter++) + { + T& chunk = *iter; + if (chunk) + callback(chunk); + } + } + } + + void _fill() + { + Bounds::Iterator iter = m_bounds.begin(); + + if (m_circular) + { + float radius = m_bounds.getDimensions().x * 0.5f - 0.45f; + Vec3 center = m_bounds.getCenter(); + + while (!iter.end()) + { + int index = iter.index(); + const Vec3Int32& pos = iter.pos(); + + T& chunk = m_chunks[index]; + if (!chunk) + { + if ((radius * radius) > center.distanceToSqr(pos.toVec3())) + { + chunk = m_generate(pos); + + if (m_addCallback) + m_addCallback(chunk); + } + } + + ++iter; + } + } + else + { + while (!iter.end()) + { + int index = iter.index(); + const Vec3Int32& pos = iter.pos(); + + T& chunk = m_chunks[index]; + if (!chunk) + { + chunk = m_generate(pos); + + if (m_addCallback) + m_addCallback(chunk); + } + + ++iter; + } + } + } + + void _moveOldChunks(const Bounds& newBounds) + { + Bounds::Iterator iter = m_bounds.begin(); + + if (m_circular) + { + float radius = m_bounds.getDimensions().x * 0.5f - 0.45f; + Vec3 center = m_bounds.getCenter(); + + while (!iter.end()) + { + int index = iter.index(); + const Vec3Int32& pos = iter.pos(); + + T& chunk = m_chunks[index]; + if (chunk) + { + if (newBounds.contains(pos) && (radius * radius) > center.distanceToSqr(Vec3(pos.x, pos.y, pos.z))) + { + m_newChunks[_getChunkIndex(newBounds, pos)] = chunk; + m_chunks[index] = nullptr; + } + } + + ++iter; + } + } + else + { + while (!iter.end()) + { + int index = iter.index(); + const Vec3Int32& pos = iter.pos(); + + T& chunk = m_chunks[index]; + if (chunk) + { + if (newBounds.contains(pos)) + { + m_newChunks[_getChunkIndex(newBounds, pos)] = chunk; + m_chunks[index] = nullptr; + } + } + + ++iter; + } + } + } + + void _move(GridArea& other) + { + clear(); + + // TODO: the rest + } + +private: + std::function m_clearCallback; + std::function m_generate; + std::function m_addCallback; + std::function m_moveCallback; + Bounds m_bounds; + std::vector m_chunks; + std::vector m_newChunks; + bool m_circular; +}; diff --git a/source/world/level/levelgen/chunk/LevelChunk.cpp b/source/world/level/levelgen/chunk/LevelChunk.cpp index 3e36167dd..25f74e2eb 100644 --- a/source/world/level/levelgen/chunk/LevelChunk.cpp +++ b/source/world/level/levelgen/chunk/LevelChunk.cpp @@ -9,912 +9,335 @@ #include "common/Logger.hpp" #include "world/level/Level.hpp" #include "world/phys/AABB.hpp" - -bool LevelChunk::touchedSky = false; - -LevelChunk::~LevelChunk() -{ - SAFE_DELETE_ARRAY(m_lightBlk.m_data); - SAFE_DELETE_ARRAY(m_lightSky.m_data); - SAFE_DELETE_ARRAY(m_tileData.m_data); -} - -CONSTEXPR int MakeBlockDataIndex(const ChunkTilePos& pos) -{ - return (pos.x << 11) | (pos.z << 7) | pos.y; -} - -CONSTEXPR int MakeHeightMapIndex(const ChunkTilePos& pos) -{ - return pos.x | (pos.z * 16); -} - -// Temp function for checking oob accesses into levelchunks -void CheckPosition(const ChunkTilePos& pos) -{ - assert(pos.x >= 0 && pos.y >= 0 && pos.z >= 0 && pos.x < 16 && pos.z < 16 && pos.y < 128); -} - -void LevelChunk::_init() -{ - field_4 = 0; - m_bLoaded = false; - m_chunkPos = TilePos(0, 0, 0); - field_234 = 0; - m_bUnsaved = false; - field_236 = 0; - field_237 = 0; - field_238 = 0; - field_23C = 0; - m_pBlockData = nullptr; -} - -LevelChunk::LevelChunk(Level* pLevel, const ChunkPos& pos) -{ - _init(); - - m_pLevel = pLevel; - m_chunkPos = TilePos(pos, 0); - - init(); -} - -LevelChunk::LevelChunk(Level* pLevel, TileID* pData, const ChunkPos& pos) -{ - _init(); - - m_pLevel = pLevel; - - // The game will blow its brains out if this if statement is executed - // I have not the slightest idea as to why... - /*if (pData) - {*/ - field_4 = 16 * 16 * 128; - m_tileData = DataLayer(16 * 16 * 128 / 2); - //Space saving measure: Store 2 blocks' light field instead of only one block's, per byte. - m_lightSky = DataLayer(16 * 16 * 128 / 2); - m_lightBlk = DataLayer(16 * 16 * 128 / 2); - - m_pBlockData = pData; - //} - - m_chunkPos = TilePos(pos, 0); - - init(); -} - -void LevelChunk::init() -{ - field_234 = 0; - m_bUnsaved = false; - field_237 = 0; - field_238 = 0; - field_23C = 0; - memset(m_heightMap, 0, sizeof m_heightMap); - memset(m_updateMap, 0, sizeof m_updateMap); +#include "world/level/TileSource.hpp" +#include "world/level/levelgen/biome/Biome.hpp" + +LevelChunk::LevelChunk(Level& level, Dimension& dimension, const ChunkPos& pos, bool readOnly) + : m_level(level), + m_dimension(dimension), + m_posMin(pos), + m_posMax(TilePos(pos) + TilePos(ChunkConstants::XZ_SIZE, ChunkConstants::Y_SIZE, ChunkConstants::XZ_SIZE) - 1), + m_pos(pos), + m_readOnly(readOnly), + m_biomeDirtyTicks(INT32_MIN), + m_terrainDirtyTicks(INT32_MIN), + m_tileEntityDirtyTicks(INT32_MIN), + m_entityDirtyTicks(INT32_MIN) +{ + memset(m_tiles, TILE_AIR, sizeof(m_tiles)); + memset(m_heightMap, 0, sizeof(m_heightMap)); + memset(m_unk85876, 0, sizeof(m_unk85876)); } -void LevelChunk::unload() +LevelChunk::~LevelChunk() { - m_bLoaded = false; } -bool LevelChunk::isAt(const ChunkPos& pos) +uint8_t LevelChunk::getHeightmap(const ChunkTilePos& pos) const { - return m_chunkPos == pos; -} + AssertPos(pos); -int LevelChunk::getHeightmap(const ChunkTilePos& pos) -{ - CheckPosition(pos); - return m_heightMap[MakeHeightMapIndex(pos)]; + return m_heightMap[pos.index2D()]; } void LevelChunk::recalcHeightmap() { - int x1 = 127; - - ChunkTilePos pos(0, 0, 0); - - for (pos.x = 0; pos.x < 16; pos.x++) + for (int x = 0; x < ChunkConstants::XZ_SIZE; x++) { - for (pos.z = 0; pos.z < 16; pos.z++) + for (int z = 0; x < ChunkConstants::XZ_SIZE; z++) { - int index1 = MakeBlockDataIndex(pos); - int index2 = 126; + ChunkTilePos chunkTilePos(x, 0, z); + + m_unk85876[chunkTilePos.index2D()] = -999; - int x2 = 0; - while (!Tile::lightBlock[m_pBlockData[index1 + index2]]) + // find the top most y-pos where there is a light blocking tile underneath { - if (index2-- == 0) + uint8_t y; + for (y = ChunkConstants::Y_SIZE - 1; y > 0; y--) { - x2 = 0; - goto label_7; + TileID tile = getTile(ChunkTilePos(x, static_cast(y - 1), z)); + if (Tile::lightBlock[tile] != 0) + break; } - } - x2 = index2 + 1; - label_7: - if (x1 >= x2) - x1 = x2; - m_heightMap[MakeHeightMapIndex(pos)] = x2; + m_heightMap[chunkTilePos.index2D()] = y; + } - if (!m_pLevel->m_pDimension->m_bHasCeiling) + if (!m_dimension.hasCeiling()) { - int x4 = 15; - for (int x3 = 127; x3 > 0; x3--) + Brightness_t brightness = Brightness::MAX; + for (int y = ChunkConstants::Y_SIZE - 1; y > 0; y--) { - x4 -= Tile::lightBlock[m_pBlockData[index1 + x3]]; - if (x4 <= 0) + ChunkTilePos pos(x, y, z); + TileID tile = getTile(pos); + brightness -= Tile::lightBlock[tile]; + if (brightness <= 0) break; - m_lightSky.set(ChunkTilePos(pos.x, x3, pos.z), x4); + m_lightSky.set(pos, brightness); } } } } - - field_228 = x1; - - for (int i = 0; i < 16; i++) - { - for (int j = 0; j < 16; j++) - { - lightGaps(ChunkTilePos(i, 0, j)); - } - } } -void LevelChunk::recalcHeightmapOnly() +int LevelChunk::getBrightness(const LightLayer& lightLayer, const ChunkTilePos& pos) const { - int x1 = 127; - - ChunkTilePos pos(0, 0, 0); - for (pos.x = 0; pos.x < 16; pos.x++) - { - for (pos.z = 0; pos.z < 16; pos.z++) - { - int index1 = MakeBlockDataIndex(pos); - int index2 = 126; + AssertPos(pos); - int x2 = 0; - while (!Tile::lightBlock[m_pBlockData[index1 + index2]]) - { - if (index2-- == 0) - { - x2 = 0; - goto label_7; - } - } - - x2 = index2 + 1; - label_7: - if (x1 >= x2) - x1 = x2; - m_heightMap[MakeHeightMapIndex(pos)] = x2; - } - } + if (lightLayer == LightLayer::Sky) + return m_lightSky.get(pos); + else if (lightLayer == LightLayer::Block) + return m_lightBlock.get(pos); - field_228 = x1; + return Brightness::MIN; } -void LevelChunk::lightGaps(const ChunkTilePos& pos) +void LevelChunk::setBrightness(const LightLayer& lightLayer, const ChunkTilePos& pos, Brightness_t brightness) { - ChunkTilePos coords = pos + m_chunkPos; - CheckPosition(pos); - uint8_t heightMap = getHeightmap(pos); - coords.y = heightMap; - - // @TODO: coords.direction() - lightGap(TilePos(coords.x - 1, coords.y, coords.z), heightMap); - lightGap(TilePos(coords.x + 1, coords.y, coords.z), heightMap); - lightGap(TilePos(coords.x, coords.y, coords.z - 1), heightMap); - lightGap(TilePos(coords.x, coords.y, coords.z + 1), heightMap); -} + AssertPos(pos); -void LevelChunk::lightGap(const TilePos& pos, uint8_t heightMap) -{ - // @BUG: This is flawed. getHeightmap calls getChunk which creates another chunk and calls this over - // and over again, creating a stack overflow. Since the level is limited a stack overflow is only - // possible on devices with really tight stacks. - uint8_t currHeightMap = m_pLevel->getHeightmap(pos); - if (currHeightMap > heightMap) - { - m_pLevel->updateLight(LightLayer::Sky, TilePos(pos.x, heightMap, pos.z), TilePos(pos.x, currHeightMap, pos.z)); - return; - } - if (currHeightMap < heightMap) - { - m_pLevel->updateLight(LightLayer::Sky, TilePos(pos.x, currHeightMap, pos.z), TilePos(pos.x, heightMap, pos.z)); - return; - } + if (lightLayer == LightLayer::Sky) + m_lightSky.set(pos, brightness); + else if (lightLayer == LightLayer::Block) + m_lightBlock.set(pos, brightness); } -int LevelChunk::getBrightness(const LightLayer& ll, const ChunkTilePos& pos) +Brightness_t LevelChunk::getRawBrightness(const ChunkTilePos& pos, Brightness_t skyDampen) const { - CheckPosition(pos); - - // why the hell is it doing it like that. - if (&ll == &LightLayer::Sky) - { - return m_lightSky.get(pos); - } - - if (&ll == &LightLayer::Block) - { - return m_lightBlk.get(pos); - } + Brightness_t skyBrightness = static_cast(m_lightSky.get(pos)); + if (skyBrightness > skyDampen) + skyBrightness -= skyDampen; + else + skyBrightness = Brightness::MIN; - return 0; + Brightness_t blockBrightness = static_cast(m_lightBlock.get(pos)); + return skyBrightness > blockBrightness ? skyBrightness : blockBrightness; } -void LevelChunk::setBrightness(const LightLayer& ll, const ChunkTilePos& pos, int brightness) +bool LevelChunk::isSkyLit(const ChunkTilePos& pos) const { - CheckPosition(pos); - // why the hell is it doing it like that. - if (&ll == &LightLayer::Sky) - { - m_lightSky.set(pos, brightness); + AssertPos(pos); - return; - } - - if (&ll == &LightLayer::Block) - { - m_lightBlk.set(pos, brightness); - - return; - } + return m_heightMap[pos.index2D()] <= pos.y; } -int LevelChunk::getRawBrightness(const ChunkTilePos& pos, int skySubtract) +void LevelChunk::recalcBlockLights() { - CheckPosition(pos); - //int bitIdx = MakeBlockDataIndex(pos); - //int index = bitIdx >> 1, offs = bitIdx & 1; - - uint8_t bSky = m_lightSky.get(pos); - if (bSky > 0) - touchedSky = true; - - int br = bSky - skySubtract; - - uint8_t bBlk = m_lightBlk.get(pos); - // if it's smaller than 0 it'll probably sort itself out - if (br < bBlk) - br = bBlk; - - return br; } -void LevelChunk::addEntity(Entity* pEnt) +void LevelChunk::addEntity(std::unique_ptr entity) { - assert(pEnt != nullptr); // Cannot add a null entity - field_238 = 1; - - int yCoord = ChunkPos::ToChunkCoordinate(pEnt->m_pos.y); - if (yCoord < 0) yCoord = 0; - if (yCoord > 7) yCoord = 7; - pEnt->m_bInAChunk = true; - pEnt->m_chunkPos = m_chunkPos; - pEnt->m_chunkPosY = yCoord; - - m_entities[yCoord].push_back(pEnt); + entity->m_chunkPos = m_pos; + m_entities.push_back(std::move(entity)); + _resetDirtyCounter(m_entityDirtyTicks, 0); } -void LevelChunk::updateEntity(Entity* pEnt) +bool LevelChunk::removeEntity(Entity& entity) { - assert(pEnt != nullptr); - assert(pEnt->m_bInAChunk); - assert(pEnt->m_chunkPos == m_chunkPos); - - int newYCoord = ChunkPos::ToChunkCoordinate(pEnt->m_pos.y); - if (newYCoord < 0) newYCoord = 0; - if (newYCoord > 7) newYCoord = 7; - - int oldYCoord = pEnt->m_chunkPosY; - if (oldYCoord == newYCoord) - { - return; - } - - if (oldYCoord < 0 || oldYCoord > 7) + std::vector>::iterator iter = m_entities.begin(); + std::vector>::iterator end = m_entities.end(); + for (; iter != end; iter++) { - assert(false); - return; + if (iter->get() == &entity) + break; } - std::vector& oldTerrainLayer = m_entities[oldYCoord]; - std::vector& newTerrainLayer = m_entities[newYCoord]; - - std::vector::iterator it = std::find(oldTerrainLayer.begin(), oldTerrainLayer.end(), pEnt); - if (it != oldTerrainLayer.end()) - { - oldTerrainLayer.erase(it); - } - else - { - assert(false); - } - - assert(std::find(newTerrainLayer.begin(), newTerrainLayer.end(), pEnt) == newTerrainLayer.end()); - newTerrainLayer.push_back(pEnt); - pEnt->m_chunkPosY = newYCoord; -} - -void LevelChunk::clearUpdateMap() -{ - memset(m_updateMap, 0, sizeof m_updateMap); - m_bUnsaved = 0; -} - -void LevelChunk::deleteBlockData() -{ - if (m_pBlockData) - delete[] m_pBlockData; - - m_pBlockData = nullptr; -} - -void LevelChunk::removeEntity(Entity* pEnt) -{ - removeEntity(pEnt, pEnt->m_chunkPosY); -} + if (iter == end) + return false; -void LevelChunk::removeEntity(Entity* pEnt, int vec) -{ - if (vec < 0) vec = 0; - if (vec > 7) vec = 7; + iter->release(); - std::vector::iterator it = std::find(m_entities[vec].begin(), m_entities[vec].end(), pEnt); + std::iter_swap(iter, end - 1); + m_entities.pop_back(); - if (it != m_entities[vec].end()) - m_entities[vec].erase(it); - /*else - assert(false);*/ // The chunk doesn't contain this entity + _resetDirtyCounter(m_entityDirtyTicks, 0); + return true; } -bool LevelChunk::isSkyLit(const ChunkTilePos& pos) +void LevelChunk::moveEntity(std::unique_ptr& entity) { - CheckPosition(ChunkTilePos(pos.x, 64, pos.z)); - - return m_heightMap[MakeHeightMapIndex(pos)] <= pos.y; + m_entities.push_back(std::move(entity)); + _resetDirtyCounter(m_entityDirtyTicks, 0); } -void LevelChunk::lightLava() +void LevelChunk::getEntities(Entity* blacklistedEntity, const AABB& aabb, std::vector& output) const { + for (std::vector>::const_iterator iter = m_entities.begin(); iter != m_entities.end(); iter++) + { + Entity* entity = iter->get(); + if (entity == blacklistedEntity) + continue; + if (entity->m_hitbox.intersect(aabb)) + output.push_back(entity); + } } -void LevelChunk::recalcBlockLights() +void LevelChunk::getEntities(const EntityType& type, const AABB& aabb, std::vector& output) const { + for (std::vector>::const_iterator iter = m_entities.begin(); iter != m_entities.end(); iter++) + { + Entity* entity = iter->get(); + if (entity->getDescriptor().isType(type)) + continue; + if (entity->m_hitbox.intersect(aabb)) + output.push_back(entity); + } } -void LevelChunk::recalcHeight(const ChunkTilePos& pos) +FullTile LevelChunk::setTileAndData(const ChunkTilePos& pos, FullTile tile, TileSource* issuingSource) { - CheckPosition(ChunkTilePos(pos.x, 64, pos.z)); - - uint8_t& hmap = m_heightMap[MakeHeightMapIndex(pos)]; - - int index = MakeBlockDataIndex(ChunkTilePos(pos.x, 0, pos.z)); - - int x1 = hmap; - if (x1 < pos.y) - x1 = pos.y; - - if (x1 > 0) + FullTile oldTile = getTileAndData(pos); + if (oldTile != tile) { - while (!Tile::lightBlock[m_pBlockData[x1 - 1 + index]] && x1) - { - --x1; - } - } + if (pos.y >= (m_unk85876[pos.index2D()] - 1)) + m_unk85876[pos.index2D()] = -999; - if (x1 != hmap) - { - m_pLevel->lightColumnChanged(pos.x, pos.z, x1, hmap); - hmap = x1; - if (field_228 <= x1) - { - int x6 = 127; - ChunkTilePos pos(0, 0, 0); - for (pos.x = 0; pos.x < 16; pos.x++) - { - for (pos.z = 0; pos.z < 16; pos.z++) - { - int x = m_heightMap[MakeHeightMapIndex(pos)]; - if (x6 >= x) - x6 = x; - } - } + bool tileChanged = oldTile.getType() != tile.getType(); - field_228 = x6; - } - else + if (tileChanged) { - field_228 = x1; + _removeCallbacks(pos, oldTile.getTypeId(), tile.getTypeId(), issuingSource); + m_tiles[pos.index()] = tile.getTypeId(); } - int globalX = pos.x + 16 * m_chunkPos.x; - int globalZ = pos.z + 16 * m_chunkPos.z; - if (hmap <= x1) - { - m_pLevel->updateLight(LightLayer::Sky, TilePos(globalX, hmap, globalZ), TilePos(globalX, x1, globalZ)); + m_tileData.set(pos, tile.data); - if (hmap < x1) - { - for (int i = 0; i < x1 - hmap; i++) - { - m_lightSky.set(ChunkTilePos(pos.x, i, pos.z), 0); - } - } - } - else + if (tileChanged) { - for (int i = 0; i < hmap; i++) - { - m_lightSky.set(ChunkTilePos(pos.x, i, pos.z), 15); - } - } - - int x2 = x1; - int x3 = 15; - while (x3 > 0 && x2 > 0) - { - TileID tile = getTile(ChunkTilePos(pos.x, --x2, pos.z)); - - int x4 = Tile::lightBlock[tile]; - if (!x4) - x4 = 1; //@HUH: what is this? - - int x5 = x3 - x4; - - x3 = x5; - if (x3 < 0) - x3 = 0; - - m_lightSky.set(ChunkTilePos(pos.x, x2, pos.z), x3); + _placeCallbacks(pos, oldTile.getTypeId(), tile.getTypeId(), issuingSource); } - if (x2 > 0) - { - for (; x2 > 0; x2--) - { - if (Tile::lightBlock[getTile(ChunkTilePos(pos.x, x2 - 1, pos.z))]) - break; - } - } - - if (x2 != x1) - { - m_pLevel->updateLight(LightLayer::Sky, TilePos(globalX - 1, x2, globalZ - 1), TilePos(globalX + 1, x1, globalZ + 1)); - } + _resetDirtyCounter(m_terrainDirtyTicks, 0); } -} -void LevelChunk::skyBrightnessChanged() -{ - -} - -void LevelChunk::load() -{ - m_bLoaded = true; + return oldTile; } -bool LevelChunk::shouldSave(bool b) +bool LevelChunk::setData(const ChunkTilePos& pos, TileData data) { - if (field_236) - return false; - - if (!b) + if (m_tileData.set(pos, data)) { - if (field_238) - { - if (field_23C + 599 < m_pLevel->getTime()) - return true; - } - - return m_bUnsaved; + _resetDirtyCounter(m_terrainDirtyTicks, 0); + return true; } - if (!field_238 || m_pLevel->getTime() == field_23C) - return m_bUnsaved; - - return true; -} - -void LevelChunk::markUnsaved() -{ - m_bUnsaved = true; + return false; } -TileID LevelChunk::getTile(const ChunkTilePos& pos) +Biome* LevelChunk::getBiome(const ChunkTilePos& pos) { - CheckPosition(pos); - - TileID tileId = m_pBlockData[MakeBlockDataIndex(pos)]; - if (Tile::tiles[tileId]) - return tileId; - else - return TILE_AIR; + //return Biome::getBiome(m_biomes[pos.index2D()].m_biomeId); // todo: add method to getBiome + throw std::bad_cast(); } -int LevelChunk::countEntities() +uint32_t LevelChunk::getGrassColor(const ChunkTilePos& pos) { - int n = 0; - for (int i = 0; i < 8; i++) - n += int(m_entities[i].size()); - return n; + BiomeChunkData& data = m_biomes[pos.index2D()]; + return (data.m_grassRed << 16) | (data.m_grassGreen << 8) | data.m_grassBlue; } -void LevelChunk::getEntities(Entity* pEntExclude, const AABB& aabb, std::vector& out) +void LevelChunk::deferLightEmitter(const TilePos& pos) { - int lowerBound = int(floorf((aabb.min.y - 2.0f) / 16.0f)); - int upperBound = int(floorf((aabb.max.y + 2.0f) / 16.0f)); - - if (lowerBound < 0) lowerBound = 0; - if (upperBound > 7) upperBound = 7; - - for (int b = lowerBound; b <= upperBound; b++) - { - for (std::vector::iterator it = m_entities[b].begin(); it != m_entities[b].end(); it++) - { - Entity* ent = *it; - if (ent == pEntExclude) continue; - - if (!aabb.intersect(ent->m_hitbox)) continue; - - out.push_back(ent); - } - } -} - -bool LevelChunk::setTile(const ChunkTilePos& pos, TileID tile) -{ - CheckPosition(pos); - - int index = MakeBlockDataIndex(pos); - - TileID oldTile = m_pBlockData[index]; - - uint8_t height = m_heightMap[MakeHeightMapIndex(pos)]; - - if (oldTile == tile) - return false; - - TilePos tilePos(m_chunkPos, pos.y); - tilePos.x += pos.x; - tilePos.z += pos.z; - m_pBlockData[index] = tile; - if (oldTile) - { - Tile::tiles[oldTile]->onRemove(m_pLevel, tilePos); - } - - // clear the data value of the block - m_tileData.set(pos, 0); - - if (Tile::lightBlock[tile]) - { - if (height <= pos.y) - recalcHeight(ChunkTilePos(pos.x, pos.y + 1, pos.z)); - } - else if (height - 1 == pos.y) - { - recalcHeight(pos); - } - - m_pLevel->updateLight(LightLayer::Sky, tilePos, tilePos); - m_pLevel->updateLight(LightLayer::Block, tilePos, tilePos); - - lightGaps(pos); - if (tile) - { - if (!m_pLevel->m_bIsClientSide) - Tile::tiles[tile]->onPlace(m_pLevel, tilePos); - } - - m_bUnsaved = true; - m_updateMap[MakeHeightMapIndex(pos)] |= 1 << (pos.y >> 4); - - return true; + std::lock_guard lock(m_deferredLightMutex); + m_deferredLightEmitterPositions.push_back(pos); } -bool LevelChunk::setTileAndData(const ChunkTilePos& pos, TileID tile, TileData data) +void LevelChunk::tick(Player* player, Tick_t tick) { - CheckPosition(pos); - - int index = MakeBlockDataIndex(pos); - - TileID oldTile = m_pBlockData[index]; - - uint8_t height = m_heightMap[MakeHeightMapIndex(pos)]; + if (m_readOnly) + return; - if (oldTile == tile) + if (m_finalization <= CF_NEEDS_POPULATION) { - // make sure we're at least updating the data. If not, simply return false - if (getData(pos) == data) - return false; + // TODO + m_finalization = CF_DONE; } - - TilePos tilePos(m_chunkPos, pos.y); - tilePos.x += pos.x; - tilePos.z += pos.z; - m_pBlockData[index] = tile; - if (oldTile && Tile::tiles[oldTile]) + else if (false) { - Tile::tiles[oldTile]->onRemove(m_pLevel, tilePos); + // TODO: handle m_pendingEntitiesSerialized } - - // update the data value of the block - m_tileData.set(pos, data); - - if (m_pLevel->m_pDimension->m_bHasCeiling) + else if (player->getLevel().m_bIsClientSide) { - m_pLevel->updateLight(LightLayer::Block, tilePos, tilePos); - lightGaps(pos); - } - if (Tile::lightBlock[tile]) - { - if (height <= pos.y) - recalcHeight(ChunkTilePos(pos.x, pos.y + 1, pos.z)); - } - else if (height - 1 == pos.y) - { - recalcHeight(pos); } - - m_pLevel->updateLight(LightLayer::Sky, tilePos, tilePos); - m_pLevel->updateLight(LightLayer::Block, tilePos, tilePos); - - lightGaps(pos); - if (tile) + else { - if (!m_pLevel->m_bIsClientSide) - Tile::tiles[tile]->onPlace(m_pLevel, tilePos); + tickBlocks(player); + // TODO } - m_bUnsaved = true; - m_updateMap[MakeHeightMapIndex(pos)] |= 1 << (pos.y >> 4); - - return true; + m_currentTick = tick; } -TileData LevelChunk::getData(const ChunkTilePos& pos) -{ - CheckPosition(pos); +static int RandomTickPositionValue = 42184323; - return m_tileData.get(pos); -} - -bool LevelChunk::setData(const ChunkTilePos& pos, TileData data) +void LevelChunk::tickBlocks(Player* player) { - CheckPosition(pos); - - if (m_tileData.get(pos) == data) - return false; + Level& level = player->getLevel(); + TileSource& source = player->getTileSource(); - m_tileData.set(pos, data); - - return true; -} - -// seems to set block data in 8192 block (4*16*128) chunks for some reason ? -// This function appears to be unused, and is completely removed as of 0.9.2 -void LevelChunk::setBlocks(uint8_t* pData, int y) -{ - LOG_I("LevelChunk::setBlocks"); - for (int i = 0; i < 8192; i++) + for (int i = 0; i < 20; i++) { - m_pBlockData[8192 * y + i] = pData[i]; - } + RandomTickPositionValue = 3 * RandomTickPositionValue + 1013904223; + ChunkTilePos pos( + (RandomTickPositionValue >> 2) & (ChunkConstants::XZ_SIZE - 1), + (RandomTickPositionValue >> 18) & (ChunkConstants::Y_SIZE - 1), + (RandomTickPositionValue >> 10) & (ChunkConstants::XZ_SIZE - 1) + ); - int x1 = 4 * y; - int x2 = 4 * (y + 1); - if (4 * y < x2) - { - for (int x3 = 4 * y; x3 < x2; x3++) + TileID tile = getTile(pos); + if (Tile::shouldTick[tile]) { - for (int j = 0; j < 16; j++) - { - recalcHeight(ChunkTilePos(x3, 0, j)); - } + TilePos absolutePos = pos + m_posMin; + Tile::tiles[tile]->tick(&source, absolutePos, &level.m_random); } } - - TilePos tilePos(m_chunkPos, 0); - tilePos.x += x1; - TilePos tilePos2 = tilePos; - tilePos.x += 4; - tilePos.y = 128; - tilePos.x += 16; - - m_pLevel->updateLight(LightLayer::Sky, tilePos, tilePos2); - m_pLevel->updateLight(LightLayer::Block, tilePos, tilePos2); - m_pLevel->setTilesDirty(tilePos, tilePos2); } -// This function appears to be unused, and is completely removed as of 0.9.2 -int LevelChunk::setBlocksAndData(uint8_t* pData, int a3, int a4, int a5, int a6, int a7, int a8, int a9) +void LevelChunk::_placeCallbacks(const ChunkTilePos& pos, TileID oldTileID, TileID newTileID, TileSource* issuingSource) { - LOG_I("LevelChunk::setBlocksAndData"); - - if (a3 >= a6) - { - recalcHeightmapOnly(); - return a9; - } - - // load the tile IDs - int x2 = a7 - a4; - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; - - uint8_t* src = &pData[a9]; - - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* dst = &m_pBlockData[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3))]; - memcpy(dst, src, x2 * sizeof(TileID)); - src += x2 * sizeof(TileID); - a9 += x2 * sizeof(TileID); - } - } - - recalcHeightmapOnly(); - - int x5 = x2 / 2; - - // load the tile data - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; - - uint8_t* src = &pData[a9]; - - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* dst = &m_tileData.m_data[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3)) >> 1]; - memcpy(dst, src, x5); - src += x5; - a9 += x5; - } - } - - // load the block lights - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; - - uint8_t* src = &pData[a9]; - - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* dst = &m_lightBlk.m_data[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3)) >> 1]; - memcpy(dst, src, x5); - src += x5; - a9 += x5; - } - } - - // load the sky lights - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; + TilePos absolutePos = pos + m_posMin; - uint8_t* src = &pData[a9]; + // TODO - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* dst = &m_lightSky.m_data[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3)) >> 1]; - memcpy(dst, src, x5); - src += x5; - a9 += x5; - } - } - - return a9; + // TODO: tileentity stuff } -// This function appears to be unused, and is completely removed as of 0.9.2 -int LevelChunk::getBlocksAndData(uint8_t* pData, int a3, int a4, int a5, int a6, int a7, int a8, int a9) +void LevelChunk::_removeCallbacks(const ChunkTilePos&, TileID, TileID, TileSource*) { - if (a3 >= a6) - { - recalcHeightmapOnly(); - return a9; - } - - // load the tile IDs - int x2 = a7 - a4; - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; - - uint8_t* dst = &pData[a9]; - - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* src = &m_pBlockData[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3))]; - memcpy(dst, src, x2 * sizeof(TileID)); - dst += x2 * sizeof(TileID); - a9 += x2 * sizeof(TileID); - } - } - - recalcHeightmapOnly(); - - int x5 = x2 / 2; - - // load the tile data - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; - - uint8_t* dst = &pData[a9]; - - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* src = &m_tileData.m_data[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3)) >> 1]; - memcpy(dst, src, x5); - dst += x5; - a9 += x5; - } - } - - // load the block lights - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; - - uint8_t* dst = &pData[a9]; - - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* src = &m_lightBlk.m_data[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3)) >> 1]; - memcpy(dst, src, x5); - dst += x5; - a9 += x5; - } - } - - // load the sky lights - for (int x1 = a3; x1 < a6; x1++) - { - if (a5 >= a8) continue; + // TODO: tileentity stuff +} - uint8_t* dst = &pData[a9]; +void LevelChunk::_lightGap(TileSource& source, const TilePos& pos) +{ + uint8_t heightmap = source.getHeightmap(pos); - for (int x3 = a5; x3 < a8; x3++) - { - uint8_t* src = &m_lightSky.m_data[MakeBlockDataIndex(ChunkTilePos(x1, a4, x3)) >> 1]; - memcpy(dst, src, x5); - dst += x5; - a9 += x5; - } - } + TilePos min(pos.x, std::min(pos.y, static_cast(heightmap)), pos.z); + TilePos max(pos.x, std::max(pos.y, static_cast(heightmap)), pos.z); - return a9; + source.runLightUpdates(LightLayer::Sky, min, max); } -// This function appears to be unused, and is completely removed as of 0.9.2 -Random LevelChunk::getRandom(int32_t l) +void LevelChunk::_lightGaps(TileSource& source, const ChunkTilePos& pos) { - Random random; - - int levelSeed = m_pLevel->getSeed(); - int chunkSeed = m_chunkPos.x * (4987142 * m_chunkPos.x + 5947611) + m_chunkPos.z * (4392871 * m_chunkPos.z + 389711); + TilePos absolutePos = pos + m_posMin; + AssertPos(absolutePos); - random.init_genrand((levelSeed + chunkSeed) ^ l); + absolutePos.y = getHeightmap(pos); - return random; + _lightGap(source, absolutePos - TilePos(1, 0, 0)); + _lightGap(source, absolutePos + TilePos(1, 0, 0)); + _lightGap(source, absolutePos - TilePos(0, 0, 1)); + _lightGap(source, absolutePos + TilePos(0, 0, 1)); } -bool LevelChunk::isEmpty() +LevelChunk::NibbleTileArray& LevelChunk::getLight(const LightLayer& lightLayer) { - return false; + if (lightLayer == LightLayer::Sky) + return m_lightSky; + else + return m_lightBlock; } diff --git a/source/world/level/levelgen/chunk/LevelChunk.hpp b/source/world/level/levelgen/chunk/LevelChunk.hpp index f25faf097..df0cfa28d 100644 --- a/source/world/level/levelgen/chunk/LevelChunk.hpp +++ b/source/world/level/levelgen/chunk/LevelChunk.hpp @@ -11,89 +11,298 @@ #include #include #include +#include +#include +#include +#include "world/level/levelgen/chunk/ChunkPos.hpp" +#include "world/level/levelgen/chunk/ChunkTilePos.hpp" +#include "world/level/TileTickingQueue.hpp" #include "common/Random.hpp" #include "common/Utils.hpp" #include "client/renderer/LightLayer.hpp" -#include "world/level/levelgen/chunk/ChunkPos.hpp" -#include "world/level/levelgen/chunk/ChunkTilePos.hpp" -#include "world/level/levelgen/chunk/DataLayer.hpp" +#include "world/level/levelgen/chunk/ChunkConstants.hpp" +#include "world/tile/Tile.hpp" class Level; +class Dimension; class AABB; class Entity; +class ChunkSource; +class Biome; + +// someone else is doing it +class TileEntity +{ + +}; + +struct BiomeChunkData +{ + uint8_t m_biomeId; + uint8_t m_grassRed; + uint8_t m_grassGreen; + uint8_t m_grassBlue; +}; + +enum ChunkState +{ + CS_UNLOADED, + CS_GENERATING, + CS_GENERATED, + CS_POST_PROCESSING, + CS_POST_PROCESSED, + CS_CHECKING_FOR_REPLACEMENT_DATA, + CS_NEEDS_LIGHTING, + CS_LIGHTING, + CS_LOADED +}; + + +// TODO: CHECK THIS +// TODO: MOVE THIS TO CHUNKTILEPOS.CPP +template <> +struct std::hash +{ + size_t operator()(const ChunkTilePos& k) const + { + return ((std::hash()(k.y) + ^ (std::hash()(k.z) << 1)) >> 1) + ^ (std::hash()(k.x) << 1); + } +}; class LevelChunk { -private: - void _init(); +public: + enum Finalization + { + CF_NEEDS_INSTA_TICKING, + CF_NEEDS_POPULATION, + CF_DONE + }; + +public: + struct NibbleTileArray + { + public: + uint8_t m_array[ChunkConstants::TILE_COUNT / 2]; + + public: + uint8_t get(const ChunkTilePos& pos) const + { + uint8_t byte = m_array[pos.index() >> 1]; + + if ((pos.y & 1) == 0) + { + // get low bits + return byte & 0xF; + } + else + { + // get high bits + return byte >> 4; + } + } + + bool set(const ChunkTilePos& pos, uint8_t value) + { + int index = pos.index() >> 1; + uint8_t byte = m_array[index]; + + if ((pos.y & 1) == 0) + { + // low bits + if ((byte & 0xF) != value) + { + m_array[index] = (value & 0xF) | (byte & 0xF0); + return true; + } + } + else + { + // high bits + if ((byte >> 4) != value) + { + m_array[index] = (value << 4) | (byte & 0xF); + return true; + } + } + + return false; + } + + size_t getSize() const { return ChunkConstants::TILE_COUNT / 2; } + }; + protected: - LevelChunk() { _init(); } + Level& m_level; + Dimension& m_dimension; + TilePos m_posMin; + TilePos m_posMax; + ChunkPos m_pos; + bool m_readOnly; + ChunkSource* m_generator; + std::mutex m_deferredLightMutex; + std::vector m_deferredLightEmitterPositions; + std::string m_pendingEntitiesSerialized; + std::atomic m_state; + Tick_t m_currentTick; + TileTickingQueue m_tileTickingQueue; + TileID m_tiles[ChunkConstants::TILE_COUNT]; + NibbleTileArray m_tileData; + NibbleTileArray m_lightSky; + NibbleTileArray m_lightBlock; + BiomeChunkData m_biomes[ChunkConstants::TILE_COUNT_PER_ROW]; + uint8_t m_heightMap[ChunkConstants::TILE_COUNT_PER_ROW]; + //std::unordered_map m_biomeStates; + Finalization m_finalization; + int m_biomeDirtyTicks; + int m_terrainDirtyTicks; + int m_tileEntityDirtyTicks; + int m_entityDirtyTicks; + int16_t m_unk85876[ChunkConstants::TILE_COUNT_PER_ROW]; + std::vector> m_entities; + std::unordered_map> m_tileEntities; + public: - LevelChunk(Level*, const ChunkPos& pos); - LevelChunk(Level*, TileID* pBlockData, const ChunkPos& pos); - virtual ~LevelChunk(); - - void init(); - - void lightGap(const TilePos& pos, uint8_t heightMap); - void lightGaps(const ChunkTilePos& pos); - void deleteBlockData(); - void clearUpdateMap(); - - virtual bool isAt(const ChunkPos& pos); - virtual int getHeightmap(const ChunkTilePos& pos); - virtual void recalcHeightmap(); - virtual void recalcHeightmapOnly(); - virtual int getBrightness(const LightLayer& ll, const ChunkTilePos& pos); - virtual void setBrightness(const LightLayer& ll, const ChunkTilePos& pos, int brightness); - virtual int getRawBrightness(const ChunkTilePos& pos, int skySubtract); - virtual void addEntity(Entity*); - virtual void removeEntity(Entity*); - virtual void removeEntity(Entity*, int vec); - virtual void updateEntity(Entity* pEnt); - virtual bool isSkyLit(const ChunkTilePos& pos); - virtual void lightLava(); - virtual void recalcBlockLights(); - virtual void skyBrightnessChanged(); - virtual void load(); - virtual void unload(); - virtual bool shouldSave(bool b); - virtual void markUnsaved(); - virtual int countEntities(); - virtual void getEntities(Entity* pEntExclude, const AABB&, std::vector& out); - virtual TileID getTile(const ChunkTilePos& pos); - virtual bool setTile(const ChunkTilePos& pos, TileID tile); - virtual bool setTileAndData(const ChunkTilePos& pos, TileID tile, TileData data); - virtual TileData getData(const ChunkTilePos& pos); - virtual bool setData(const ChunkTilePos& pos, TileData data); - virtual void setBlocks(uint8_t* pData, int y); - virtual int getBlocksAndData(uint8_t* pData, int, int, int, int, int, int, int); - virtual int setBlocksAndData(uint8_t* pData, int, int, int, int, int, int, int); - virtual Random getRandom(int32_t l); - virtual void recalcHeight(const ChunkTilePos& pos); - virtual bool isEmpty(); - //... + LevelChunk(Level& level, Dimension& dimension, const ChunkPos& pos, bool readOnly = false); + ~LevelChunk(); public: - static bool touchedSky; + bool isAt(const ChunkPos& pos) const + { + return m_pos == pos; + } + bool isAt(int x, int z) const + { + return isAt(ChunkPos(x, z)); + } + uint8_t getHeightmap(const ChunkTilePos& pos) const; + void recalcHeightmap(); + int getBrightness(const LightLayer& lightLayer, const ChunkTilePos& pos) const; + void setBrightness(const LightLayer& lightLayer, const ChunkTilePos& pos, Brightness_t brightness); + Brightness_t getRawBrightness(const ChunkTilePos& pos, Brightness_t skyDampen) const; + bool isSkyLit(const ChunkTilePos& pos) const; + void recalcBlockLights(); + size_t countEntities() const + { + return m_entities.size(); + } + void addEntity(std::unique_ptr entity); + bool removeEntity(Entity& entity); + void moveEntity(std::unique_ptr& entity); + void getEntities(Entity* blacklistedEntity, const AABB& aabb, std::vector& output) const; + void getEntities(const EntityType& type, const AABB& aabb, std::vector& output) const; + const ChunkPos& getPos() const + { + return m_pos; + } + const TilePos& getMinPos() const + { + return m_posMin; + } + const TilePos& getMaxPos() const + { + return m_posMax; + } + TileID getTile(const ChunkTilePos& pos) const + { + return m_tiles[pos.index()]; + } + TileData getData(const ChunkTilePos& pos) const + { + return m_tileData.get(pos); + } + FullTile getTileAndData(const ChunkTilePos& pos) const + { + return FullTile(getTile(pos), getData(pos)); + } + bool setData(const ChunkTilePos& pos, TileData data); + FullTile setTileAndData(const ChunkTilePos& pos, FullTile tile, TileSource* issuingSource); // Returns the old tile and data at the position + Biome* getBiome(const ChunkTilePos& pos); + uint32_t getGrassColor(const ChunkTilePos& pos); + + void tick(Player* player, Tick_t tick); + void tickBlocks(Player* player); + + bool isReadOnly() const + { + return m_readOnly; + } + + TileTickingQueue& getTileTickingQueue() + { + return m_tileTickingQueue; + } + + TileID* getTiles() + { + return m_tiles; + } + + NibbleTileArray& getTileData() + { + return m_tileData; + } + + void setGenerator(ChunkSource& generator) + { + m_generator = &generator; + } + + ChunkSource* getGenerator() + { + return m_generator; + } + + // TODO: determine if this should be const + NibbleTileArray& getLight(const LightLayer& lightLayer); + + ChunkState getState() const + { + return m_state.load(std::memory_order_acquire); + } + + void setFinalized(Finalization); + void changeState(ChunkState, ChunkState); + bool tryChangeState(ChunkState, ChunkState); + + void deferLightEmitter(const TilePos& pos); + + void setSaved(); + +protected: + void _resetDirtyCounter(int& dirtyCounter, int to); + + void _placeCallbacks(const ChunkTilePos&, TileID, TileID, TileSource*); + void _removeCallbacks(const ChunkTilePos&, TileID, TileID, TileSource*); + + void _lightGap(TileSource& source, const TilePos& pos); + void _lightGaps(TileSource& source, const ChunkTilePos& pos); + +protected: + static void AssertPos(const ChunkTilePos& pos) + { + assert(pos.x >= 0 && pos.y >= 0 && pos.z >= 0 && pos.x < ChunkConstants::XZ_SIZE && pos.z < ChunkConstants::XZ_SIZE && pos.y < ChunkConstants::Y_SIZE); + } public: int field_4; bool m_bLoaded; Level* m_pLevel; - DataLayer m_tileData; - DataLayer m_lightSky; - DataLayer m_lightBlk; - uint8_t m_heightMap[256]; + //DataLayer m_tileData_OLD; + //DataLayer m_lightSky_OLD; + //DataLayer m_lightBlk; + //uint8_t m_heightMap_OLD[256]; uint8_t m_updateMap[256]; int field_228; - ChunkPos m_chunkPos; + ChunkPos m_chunkPos_OLD; uint8_t field_234; bool m_bUnsaved; uint8_t field_236; uint8_t field_237; int field_238; int field_23C; - TileID* m_pBlockData; - std::vector m_entities[128 / 16]; + //TileID* m_pBlockData; + //std::vector m_entities_OLD[128 / 16]; }; diff --git a/source/world/level/levelgen/chunk/MainChunkSource.cpp b/source/world/level/levelgen/chunk/MainChunkSource.cpp new file mode 100644 index 000000000..138a10a4a --- /dev/null +++ b/source/world/level/levelgen/chunk/MainChunkSource.cpp @@ -0,0 +1,63 @@ +#include "world/level/levelgen/chunk/MainChunkSource.hpp" + +MainChunkSource::MainChunkSource(std::unique_ptr parent) + : ChunkSource(std::move(parent)) +{ +} + +MainChunkSource::~MainChunkSource() +{ +} + +LevelChunk* MainChunkSource::getExistingChunk(const ChunkPos& pos) +{ + ChunkMap_t::const_iterator iter = m_chunks.find(pos); + if (iter != m_chunks.end()) + return iter->second.get(); + + return nullptr; +} + +LevelChunk* MainChunkSource::requestChunk(const ChunkPos& pos, LoadMode loadMode) +{ + ChunkMap_t::iterator iter = m_chunks.find(pos); + if (iter != m_chunks.end()) + return iter->second.grab(); + + LevelChunk* chunk = m_parent->requestChunk(pos, loadMode); + if (chunk) + m_chunks[pos] = ChunkRefCount(*chunk, 1); + return chunk; +} + +bool MainChunkSource::releaseChunk(LevelChunk& chunk) +{ + ChunkMap_t::iterator iter = m_chunks.find(chunk.getPos()); + if (iter == m_chunks.end()) + return false; + + if (iter->second.release()) + return false; + + m_chunks.erase(iter); + return true; +} + +void MainChunkSource::acquireDiscarded(std::unique_ptr&& chunk) +{ + ChunkMap_t::iterator iter = m_chunks.find(chunk->getPos()); + if (iter != m_chunks.end()) + { + iter->second.grab(); + chunk.release(); + } + else + { + m_chunks[chunk->getPos()] = ChunkRefCount(*chunk, 1); + } +} + +const ChunkSource::ChunkMap_t& MainChunkSource::getStoredChunks() +{ + return m_chunks; +} diff --git a/source/world/level/levelgen/chunk/MainChunkSource.hpp b/source/world/level/levelgen/chunk/MainChunkSource.hpp new file mode 100644 index 000000000..91e24af76 --- /dev/null +++ b/source/world/level/levelgen/chunk/MainChunkSource.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include "world/level/levelgen/chunk/ChunkSource.hpp" +#include "world/level/levelgen/chunk/ChunkPos.hpp" +#include "world/level/levelgen/chunk/ChunkRefCount.hpp" + +class MainChunkSource : public ChunkSource +{ +protected: + ChunkMap_t m_chunks; + +public: + MainChunkSource(std::unique_ptr parent); + virtual ~MainChunkSource(); + +public: + LevelChunk* getExistingChunk(const ChunkPos& pos) override; + LevelChunk* requestChunk(const ChunkPos& pos, LoadMode loadMode) override; + bool releaseChunk(LevelChunk& chunk) override; + void acquireDiscarded(std::unique_ptr&& chunk) override; + const ChunkMap_t& getStoredChunks() override; +}; diff --git a/source/world/level/levelgen/chunk/NetworkChunkSource.cpp b/source/world/level/levelgen/chunk/NetworkChunkSource.cpp new file mode 100644 index 000000000..1071ebdfb --- /dev/null +++ b/source/world/level/levelgen/chunk/NetworkChunkSource.cpp @@ -0,0 +1,83 @@ +#include "world/level/levelgen/chunk/NetworkChunkSource.hpp" + +LevelChunk* NetworkChunkSource::getIncomingChunk(const ChunkPos& pos) +{ + LevelChunk* existingChunk = getExistingChunk(pos); + if (existingChunk) + return existingChunk; + + LevelChunk* blankChunk = new LevelChunk(*m_level, *m_dimension, pos, false); + m_incomingChunks[pos] = std::unique_ptr(blankChunk); + + return blankChunk; +} + +LevelChunk* NetworkChunkSource::getExistingChunk(const ChunkPos& pos) +{ + ChunkMap_t::const_iterator iter = m_chunks.find(pos); + if (iter != m_chunks.end()) + return iter->second.get(); + + return nullptr; +} + +LevelChunk* NetworkChunkSource::requestChunk(const ChunkPos& pos, LoadMode loadMode) +{ + { + ChunkMap_t::iterator iter = m_chunks.find(pos); + if (iter != m_chunks.end()) + return iter->second.grab(); + } + + { + IncomingChunkMap_t::iterator iter = m_incomingChunks.find(pos); + if (iter != m_incomingChunks.end()) + { + LevelChunk* chunk = iter->second.release(); + m_chunks[iter->first] = ChunkRefCount(*chunk, 1); + m_incomingChunks.erase(iter); + return chunk; + } + } + + if (loadMode == LOAD_DEFERRED) + { + LevelChunk* chunk = new LevelChunk(*m_level, *m_dimension, pos, false); + m_chunks[pos] = ChunkRefCount(*chunk, 1); + return chunk; + } + + return nullptr; +} + +bool NetworkChunkSource::releaseChunk(LevelChunk& chunk) +{ + ChunkMap_t::iterator iter = m_chunks.find(chunk.getPos()); + if (iter == m_chunks.end()) + return false; + + if (iter->second.release()) + return false; + + m_chunks.erase(iter); + return true; +} + +void NetworkChunkSource::acquireDiscarded(std::unique_ptr&& chunk) +{ + ChunkMap_t::iterator iter = m_chunks.find(chunk->getPos()); + if (iter != m_chunks.end()) + { + iter->second.grab(); + chunk.release(); + } + else + { + m_chunks[chunk->getPos()] = ChunkRefCount(*chunk, 1); + } +} + +const ChunkSource::ChunkMap_t& NetworkChunkSource::getStoredChunks() +{ + return m_chunks; +} diff --git a/source/world/level/levelgen/chunk/NetworkChunkSource.hpp b/source/world/level/levelgen/chunk/NetworkChunkSource.hpp new file mode 100644 index 000000000..19533df39 --- /dev/null +++ b/source/world/level/levelgen/chunk/NetworkChunkSource.hpp @@ -0,0 +1,24 @@ +#pragma once +#include "world/level/levelgen/chunk/ChunkSource.hpp" + +class NetworkChunkSource : public ChunkSource +{ +protected: + typedef std::unordered_map> IncomingChunkMap_t; + +protected: + IncomingChunkMap_t m_incomingChunks; + ChunkMap_t m_chunks; + +public: + NetworkChunkSource(Level* level, Dimension* dimension); + virtual ~NetworkChunkSource(); + +public: + LevelChunk* getIncomingChunk(const ChunkPos&); + LevelChunk* getExistingChunk(const ChunkPos& pos) override; + LevelChunk* requestChunk(const ChunkPos& pos, LoadMode loadMode) override; + bool releaseChunk(LevelChunk& chunk) override; + void acquireDiscarded(std::unique_ptr&& chunk) override; + const ChunkMap_t& getStoredChunks() override; +}; diff --git a/source/world/level/levelgen/chunk/PerformanceTestChunkSource.cpp b/source/world/level/levelgen/chunk/PerformanceTestChunkSource.cpp deleted file mode 100644 index c8300be21..000000000 --- a/source/world/level/levelgen/chunk/PerformanceTestChunkSource.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "PerformanceTestChunkSource.hpp" -#include "world/level/Level.hpp" - -PerformanceTestChunkSource::PerformanceTestChunkSource() -{ - m_pLevel = nullptr; -} - -LevelChunk* PerformanceTestChunkSource::create(const ChunkPos& pos) -{ - TileID* pData = new TileID[0x8000u]; - memset(pData, 0, 0x8000u * sizeof(TileID)); - - for (int i = 0; i != 65; i++) - { - if (i > 59) - { - // alternating columns of dirt - for (int j = 0; j < 16; j += 2) - { - for (int k = 0; k < 16; k += 2) - { - pData[i | (j << 11) | (k << 7)] = 3; // dirt - } - } - } - else - { - // alternating checkerboard patterns of dirt - for (int j = (~i) & 1; j < 16; j += 2) - { - for (int k = i & 1; k < 16; k += 2) - { - pData[i | (j << 11) | (k << 7)] = 3; // dirt - } - } - } - } - - LevelChunk* pChunk = new LevelChunk(m_pLevel, pData, pos); - pChunk->recalcHeightmap(); - - return pChunk; -} - -std::string PerformanceTestChunkSource::gatherStats() -{ - return "PerformanceTestChunkSource"; -} - -// this sucks because it creates a new chunk every call to this function... -LevelChunk* PerformanceTestChunkSource::getChunk(const ChunkPos& pos) -{ - return create(pos); -} - -LevelChunk* PerformanceTestChunkSource::getChunkDontCreate(const ChunkPos& pos) -{ - TileID* pData = new TileID[0x8000u]; - memset(pData, 0, 0x8000u * sizeof(TileID)); - - LevelChunk* pChunk = new LevelChunk(m_pLevel, pData, pos); - return pChunk; -} - -bool PerformanceTestChunkSource::hasChunk(const ChunkPos& pos) -{ - return true; -} - -void PerformanceTestChunkSource::postProcess(ChunkSource* a, const ChunkPos& pos) -{ - -} - -bool PerformanceTestChunkSource::shouldSave() -{ - return false; -} - -int PerformanceTestChunkSource::tick() -{ - return 0; -} - diff --git a/source/world/level/levelgen/chunk/PerformanceTestChunkSource.hpp b/source/world/level/levelgen/chunk/PerformanceTestChunkSource.hpp deleted file mode 100644 index dedb8519b..000000000 --- a/source/world/level/levelgen/chunk/PerformanceTestChunkSource.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include -#include "ChunkSource.hpp" -class Level; - -class PerformanceTestChunkSource : public ChunkSource -{ -public: - PerformanceTestChunkSource(); - LevelChunk* create(const ChunkPos& pos) override; - LevelChunk* getChunk(const ChunkPos& pos) override; - LevelChunk* getChunkDontCreate(const ChunkPos& pos) override; - bool hasChunk(const ChunkPos& pos) override; - std::string gatherStats() override; - void postProcess(ChunkSource*, const ChunkPos& pos) override; - bool shouldSave() override; - int tick() override; - -public: - Level* m_pLevel; -}; diff --git a/source/world/level/levelgen/chunk/PlayerChunkSource.cpp b/source/world/level/levelgen/chunk/PlayerChunkSource.cpp new file mode 100644 index 000000000..3c276e53f --- /dev/null +++ b/source/world/level/levelgen/chunk/PlayerChunkSource.cpp @@ -0,0 +1,60 @@ +#include "world/level/levelgen/chunk/PlayerChunkSource.hpp" +#include "world/level/Level.hpp" +#include "world/entity/Player.hpp" + +static void PlayerChunkViewAdd(PlayerChunkSource* source, LevelChunk*& chunk) +{ + if (chunk->getState() == CS_POST_PROCESSED) + source->getLevel().onNewChunkFor(source->getPlayer(), *chunk); +} + +void PlayerChunkSource::suspend() +{ + m_suspended = true; + + m_parent->hintDiscardBatchBegin(); + m_gridArea.clear(); + m_parent->hintDiscardBatchEnd(); +} + +void PlayerChunkSource::centerAt(const Vec3& pos, float updateThresholdDistance) +{ + if (m_suspended) + return; + + if (updateThresholdDistance > 0.0f) + return; + + if (m_lastCenterPos.distanceToSqr(pos) < (updateThresholdDistance * updateThresholdDistance)) + return; + + TilePos tilePos = pos; + if (!m_gridArea.empty()) + { + TilePos minPos = tilePos - m_radius; + TilePos maxPos = tilePos + m_radius; + + m_parent->hintDiscardBatchBegin(); + m_gridArea.move(minPos, maxPos); + m_parent->hintDiscardBatchEnd(); + + m_lastCenterPos = Vec3(pos.x, 0, pos.z); + } + else + { + std::function addCallback = std::bind(&PlayerChunkViewAdd, this, std::placeholders::_1); + + m_gridArea = getView(tilePos, m_radius, m_parentLoadMode, true, addCallback, nullptr); + } +} + +void PlayerChunkSource::center(float updateThresholdDistance) +{ + centerAt(m_player->m_pos, updateThresholdDistance); +} + +void PlayerChunkSource::setRadius(int radius) +{ + m_radius = radius; + center(0.0f); +} diff --git a/source/world/level/levelgen/chunk/PlayerChunkSource.hpp b/source/world/level/levelgen/chunk/PlayerChunkSource.hpp new file mode 100644 index 000000000..92ed807d9 --- /dev/null +++ b/source/world/level/levelgen/chunk/PlayerChunkSource.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "world/level/levelgen/chunk/ChunkViewSource.hpp" + +class Player; + +class PlayerChunkSource : public ChunkViewSource +{ +protected: + Player* m_player; + int m_radius; + bool m_suspended; + Vec3 m_lastCenterPos; + +public: + PlayerChunkSource(Player& player, ChunkSource& parentSource, int radius); + virtual ~PlayerChunkSource(); + +public: + void suspend(); + void centerAt(const Vec3& pos, float updateThresholdDistance = 16.0f); + void center(float updateThresholdDistance = 16.0f); + void setRadius(int radius); + + Player& getPlayer() + { + return *m_player; + } +}; diff --git a/source/world/level/levelgen/chunk/PostprocessingManager.cpp b/source/world/level/levelgen/chunk/PostprocessingManager.cpp new file mode 100644 index 000000000..ff1784bed --- /dev/null +++ b/source/world/level/levelgen/chunk/PostprocessingManager.cpp @@ -0,0 +1,71 @@ +#include +#include +#include "world/level/levelgen/chunk/PostprocessingManager.hpp" + +PostprocessingManager PostprocessingManager::instance; + +PostprocessingManager::PostprocessingManager() + : m_canLock(std::thread::hardware_concurrency() > 2) // We don't want to lock if we don't have multiple streaming threads running +{ +} + +PostprocessingManager::ScopedLock PostprocessingManager::tryLock(const ChunkPos& pos) +{ + assert(pos != ChunkPos::INVALID); + + if (!m_canLock) + return ScopedLock(pos); + + std::lock_guard lock(m_mutex); + + const ChunkPos minPos = pos - 1; + const ChunkPos maxPos = pos + 1; + + if (!m_lockedPositions.empty()) + { + for (int x = minPos.x; x <= maxPos.x; x++) + { + for (int z = minPos.z; z <= maxPos.z; z++) + { + ChunkPos pos(x, z); + if (m_lockedPositions.find(pos) != m_lockedPositions.end()) + return ScopedLock(ChunkPos::INVALID); + } + } + } + + for (int x = minPos.x; x <= maxPos.x; x++) + { + for (int z = minPos.z; z <= maxPos.z; z++) + { + ChunkPos pos(x, z); + m_lockedPositions.insert(pos); + } + } + + return ScopedLock(pos); +} + +void PostprocessingManager::_release(const ChunkPos& pos) +{ + assert(pos != ChunkPos::INVALID); + + if (!m_canLock) + return; + + std::lock_guard lock(m_mutex); + + const ChunkPos minPos = pos - 1; + const ChunkPos maxPos = pos + 1; + + for (int x = minPos.x; x <= maxPos.x; x++) + { + for (int z = minPos.z; z <= maxPos.z; z++) + { + ChunkPos pos(x, z); + std::set::iterator iter = m_lockedPositions.find(pos); + assert(iter != m_lockedPositions.end()); + m_lockedPositions.erase(iter); + } + } +} diff --git a/source/world/level/levelgen/chunk/PostprocessingManager.hpp b/source/world/level/levelgen/chunk/PostprocessingManager.hpp new file mode 100644 index 000000000..bf4c0e291 --- /dev/null +++ b/source/world/level/levelgen/chunk/PostprocessingManager.hpp @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include +#include "world/level/levelgen/chunk/ChunkPos.hpp" +#include "compat/LegacyCPP.hpp" + +class PostprocessingManager +{ +public: + class ScopedLock; + friend class ScopedLock; + +private: + static PostprocessingManager instance; + +public: + static PostprocessingManager& getInstance() + { + return instance; + } + +protected: + bool m_canLock; + std::mutex m_mutex; + std::set m_lockedPositions; + +public: + PostprocessingManager(); + +public: + ScopedLock tryLock(const ChunkPos&); + +protected: + void _release(const ChunkPos&); + +public: + class ScopedLock + { + friend class PostprocessingManager; + + protected: + ChunkPos m_lockedPosition; + + private: + // disable the copy operator + ScopedLock& operator=(const ScopedLock&); + + protected: + ScopedLock(const ChunkPos& pos) + : m_lockedPosition(pos) + { + } + + public: + MC_CTOR_MOVE(ScopedLock); + ~ScopedLock() + { + if (isValid()) + instance._release(m_lockedPosition); + } + + public: + bool isValid() const + { + return m_lockedPosition != ChunkPos::INVALID; + } + + protected: + void _move(ScopedLock& other) + { + m_lockedPosition = other.m_lockedPosition; + other.m_lockedPosition = ChunkPos::INVALID; + } + }; +}; diff --git a/source/world/level/levelgen/chunk/RandomLevelSource.cpp b/source/world/level/levelgen/chunk/RandomLevelSource.cpp index 54fc6bc0e..ef558b230 100644 --- a/source/world/level/levelgen/chunk/RandomLevelSource.cpp +++ b/source/world/level/levelgen/chunk/RandomLevelSource.cpp @@ -11,13 +11,49 @@ #include "common/Logger.hpp" #include "world/level/Level.hpp" #include "world/tile/SandTile.hpp" +#include "world/level/levelgen/chunk/PostprocessingManager.hpp" +#include "world/level/levelgen/chunk/ChunkViewSource.hpp" +#include "world/level/TileSource.hpp" const float RandomLevelSource::SNOW_CUTOFF = 0.5f; const float RandomLevelSource::SNOW_SCALE = 0.3f; float g_timeSpentInPostProcessing = 0; -RandomLevelSource::RandomLevelSource(Level* level, int32_t seed, int version) : +struct RandomLevelSource::ThreadData +{ +private: + Random m_random; + BiomeSource m_biomeSource; + +public: + ThreadData(Level* level) + : m_random(), + m_biomeSource(level) + { + } + +public: + Random& getRandom() + { + return m_random; + } + + BiomeSource& getBiomeSource() + { + return m_biomeSource; + } + +public: + static ThreadData* Create(Level* level) + { + return new ThreadData(level); + } +}; + +RandomLevelSource::RandomLevelSource(Level* level, Dimension* dimension, uint32_t seed) : + ChunkSource(level, dimension, 16), + m_threadData(std::bind(&RandomLevelSource::ThreadData::Create, level)), m_random(seed), m_perlinNoise1(&m_random, 16), m_perlinNoise2(&m_random, 16), @@ -26,8 +62,7 @@ RandomLevelSource::RandomLevelSource(Level* level, int32_t seed, int version) : m_perlinNoise5(&m_random, 4), m_perlinNoise6(&m_random, 10), m_perlinNoise7(&m_random, 16), - m_perlinNoise8(&m_random, 8), - m_pLevel(level) + m_perlinNoise8(&m_random, 8) { field_4 = false; field_19F0 = 1.0f; @@ -49,95 +84,75 @@ RandomLevelSource::RandomLevelSource(Level* level, int32_t seed, int version) : } field_7280 = new float[1024]; - - Random random = m_random; - LOG_I("random.get : %d", random.genrand_int32() >> 1); - (void)random; // compiler will sometimes warn about unused variable if this isn't here } -// @BUG: Potential collisions. -inline int GetChunkHash(const ChunkPos& pos) +LevelChunk* RandomLevelSource::requestChunk(const ChunkPos& pos, LoadMode loadMode) { - int v6 = (pos.z & 0x7FFF) | ((pos.x & 0x7FFF) << 16) | (pos.x & 0x80000000), v7; - if (pos.z >= 0) - v7 = 0; - else - v7 = 0x8000; + if (loadMode == LOAD_DEFERRED) + return new LevelChunk(*m_level, *m_dimension, pos, false); - return v6 | v7; + return nullptr; } -LevelChunk* RandomLevelSource::getChunk(const ChunkPos& pos) +void RandomLevelSource::loadChunk(LevelChunk& chunk) { - int hashCode = GetChunkHash(pos); - std::map::iterator iter = m_chunks.find(hashCode); - if (iter != m_chunks.end()) - return iter->second; + ThreadData& threadData = m_threadData.getLocal(); - // have to generate the chunk - m_random.init_genrand(341872712 * pos.x + 132899541 * pos.z); + threadData.getRandom().init_genrand(341872712 * chunk.getPos().x + 132899541 * chunk.getPos().z); - TileID* pLevelData = new TileID[32768]; - - LevelChunk* pChunk = new LevelChunk(m_pLevel, pLevelData, pos); - m_chunks.insert(std::pair(hashCode, pChunk)); - - Biome** pBiomeBlock = m_pLevel->getBiomeSource()->getBiomeBlock(TilePos(pos, 0), 16, 16); - prepareHeights(pos, pLevelData, nullptr, m_pLevel->getBiomeSource()->field_4); - buildSurfaces(pos, pLevelData, pBiomeBlock); - pChunk->recalcHeightmap(); + Biome** pBiomeBlock = threadData.getBiomeSource().getBiomeBlock(TilePos(chunk.getPos(), 0), 16, 16); + prepareHeights(&chunk, threadData.getBiomeSource().field_4); + buildSurfaces(&chunk); // @NOTE: Java Edition Beta 1.6 uses the m_largeCaveFeature. #ifdef FEATURE_CAVES m_largeCaveFeature.apply(this, m_pLevel, tilePos.x, tilePos.z, pLevelData, 0); #endif - return pChunk; + chunk.recalcHeightmap(); + chunk.setGenerator(*this); + chunk.setSaved(); + chunk.changeState(CS_GENERATING, CS_GENERATED); } -LevelChunk* RandomLevelSource::getChunkDontCreate(const ChunkPos& pos) +void RandomLevelSource::postProcessMobsAt(TileSource* tileSource, int, int, Random& random) { - int hashCode = GetChunkHash(pos); - std::map::iterator iter = m_chunks.find(hashCode); - if (iter != m_chunks.end()) - return iter->second; - - // have to create the chunk. Create an empty one - - TileID* pLevelData = new TileID[32768]; - memset (pLevelData, 0, sizeof *pLevelData * 32768); - - LevelChunk* pChunk = new LevelChunk(m_pLevel, pLevelData, pos); - m_chunks.insert(std::pair(hashCode, pChunk)); - - return pChunk; + // TODO } -float* RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5, int a6, int a7, int a8) +static const int HEIGHTS_SIZE_X = 5; +static const int HEIGHTS_SIZE_Y = 17; +static const int HEIGHTS_SIZE_Z = 5; + +void RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5) { - if (fptr == nullptr) - { - fptr = new float[a6 * a7 * a8]; - } + ThreadData& threadData = m_threadData.getLocal(); - float* bsf4 = m_pLevel->getBiomeSource()->field_4; - float* bsf8 = m_pLevel->getBiomeSource()->field_8; + float* bsf4 = threadData.getBiomeSource().field_4; + float* bsf8 = threadData.getBiomeSource().field_8; constexpr float C_MAGIC_1 = 684.412f; - field_7E90 = m_perlinNoise6.getRegion(field_7E90, a3, a5, a6, a8, 1.121f, 1.121f, 0.5f); - field_7E94 = m_perlinNoise7.getRegion(field_7E94, a3, a5, a6, a8, 200.0f, 200.0f, 0.5f); - field_7E84 = m_perlinNoise3.getRegion(field_7E84, float(a3), float(a4), float(a5), a6, a7, a8, 8.5552f, 4.2776f, 8.5552f); - field_7E88 = m_perlinNoise1.getRegion(field_7E88, float(a3), float(a4), float(a5), a6, a7, a8, C_MAGIC_1, C_MAGIC_1, C_MAGIC_1); - field_7E8C = m_perlinNoise2.getRegion(field_7E8C, float(a3), float(a4), float(a5), a6, a7, a8, C_MAGIC_1, C_MAGIC_1, C_MAGIC_1); + // TODO: calculate the size beforehand instead of doing this + float* perlinData1 = nullptr; + float* perlinData2 = nullptr; + float* perlinData3 = nullptr; + float* perlinData4 = nullptr; + float* perlinData5 = nullptr; + + perlinData1 = m_perlinNoise6.getRegion(perlinData1, a3, a5, float(HEIGHTS_SIZE_X), float(HEIGHTS_SIZE_Z), 1.121f, 1.121f, 0.5f); + perlinData2 = m_perlinNoise7.getRegion(perlinData2, a3, a5, float(HEIGHTS_SIZE_X), float(HEIGHTS_SIZE_Z), 200.0f, 200.0f, 0.5f); + perlinData3 = m_perlinNoise3.getRegion(perlinData3, float(a3), float(a4), float(a5), float(HEIGHTS_SIZE_X), float(HEIGHTS_SIZE_Y), float(HEIGHTS_SIZE_Z), 8.5552f, 4.2776f, 8.5552f); + perlinData4 = m_perlinNoise1.getRegion(perlinData4, float(a3), float(a4), float(a5), float(HEIGHTS_SIZE_X), float(HEIGHTS_SIZE_Y), float(HEIGHTS_SIZE_Z), C_MAGIC_1, C_MAGIC_1, C_MAGIC_1); + perlinData5 = m_perlinNoise2.getRegion(perlinData5, float(a3), float(a4), float(a5), float(HEIGHTS_SIZE_X), float(HEIGHTS_SIZE_Y), float(HEIGHTS_SIZE_Z), C_MAGIC_1, C_MAGIC_1, C_MAGIC_1); int k1 = 0; int l1 = 0; - int i2 = 16 / a6; - for (int j2 = 0; j2 < a6; j2++) + int i2 = 16 / HEIGHTS_SIZE_X; + for (int j2 = 0; j2 < HEIGHTS_SIZE_X; j2++) { int k2 = j2 * i2 + i2 / 2; - for (int l2 = 0; l2 < a8; l2++) + for (int l2 = 0; l2 < HEIGHTS_SIZE_Z; l2++) { int i3 = l2 * i2 + i2 / 2; float d2 = bsf4[k2 * 16 + i3]; @@ -146,11 +161,11 @@ float* RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5, int a6 d4 *= d4; d4 *= d4; d4 = 1.0f - d4; - float d5 = (field_7E90[l1] + 256.0f) / 512.0f; + float d5 = (perlinData1[l1] + 256.0f) / 512.0f; d5 *= d4; if (d5 > 1.0f) d5 = 1.0f; - float d6 = field_7E94[l1] / 8000.0f; + float d6 = perlinData2[l1] / 8000.0f; if (d6 < 0.0f) { d6 = -d6 * 0.3f; @@ -174,10 +189,10 @@ float* RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5, int a6 if (d5 < 0.0f) d5 = 0.0f; d5 += 0.5f; - d6 = (d6 * (float)a7) / 16.0f; - float d7 = (float)a7 / 2.0f + d6 * 4.0f; + d6 = (d6 * (float)HEIGHTS_SIZE_Y) / 16.0f; + float d7 = (float)HEIGHTS_SIZE_Y / 2.0f + d6 * 4.0f; l1++; - for (int j3 = 0; j3 < a7; j3++) + for (int j3 = 0; j3 < HEIGHTS_SIZE_Y; j3++) { float d8 = 0.0f; float d9 = (((float)j3 - d7) * 12.0f) / d5; @@ -185,9 +200,9 @@ float* RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5, int a6 { d9 *= 4.0f; } - float d10 = field_7E88[k1] / 512.0f; - float d11 = field_7E8C[k1] / 512.0f; - float d12 = (field_7E84[k1] / 10.0f + 1.0f) / 2.0f; + float d10 = perlinData4[k1] / 512.0f; + float d11 = perlinData5[k1] / 512.0f; + float d12 = (perlinData3[k1] / 10.0f + 1.0f) / 2.0f; if (d12 < 0.0f) d8 = d10; else if (d12 > 1.0f) @@ -195,9 +210,9 @@ float* RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5, int a6 else d8 = d10 + (d11 - d10) * d12; d8 -= d9; - if (j3 > a7 - 4) + if (j3 > HEIGHTS_SIZE_Y - 4) { - float d13 = (float)(j3 - (a7 - 4)) / 3.0f; + float d13 = (float)(j3 - (HEIGHTS_SIZE_Y - 4)) / 3.0f; d8 = d8 * (1.0f - d13) + -10.0f * d13; } fptr[k1] = d8; @@ -208,27 +223,34 @@ float* RandomLevelSource::getHeights(float* fptr, int a3, int a4, int a5, int a6 } - return fptr; + delete perlinData1; + delete perlinData2; + delete perlinData3; + delete perlinData4; + delete perlinData5; } -void RandomLevelSource::prepareHeights(const ChunkPos& pos, TileID* tiles, void* huh, float* fptr) +void RandomLevelSource::prepareHeights(LevelChunk* chunk, float* biomeData) { - field_7280 = getHeights(field_7280, pos.x * 4, 0, pos.z * 4, 5, 17, 5); + float heightData[HEIGHTS_SIZE_X * HEIGHTS_SIZE_Y * HEIGHTS_SIZE_Z]; + getHeights(heightData, chunk->getPos().x * 4, 0, chunk->getPos().z * 4); + + TileID* tiles = chunk->getTiles(); - for (int i = 0; i < 4; i++) + for (int i = 0; i <= HEIGHTS_SIZE_X; i++) { - for (int j = 0; j < 4; j++) + for (int j = 0; j <= HEIGHTS_SIZE_Z; j++) { - for (int k = 0; k < 16; k++) + for (int k = 0; k <= HEIGHTS_SIZE_Y; k++) { - float v24 = field_7280[85 * i + 17 * j + k]; - float v23 = field_7280[85 * i + 17 + 17 * j + k]; - float v22 = field_7280[85 * i + 85 + 17 * j + k]; - float v21 = field_7280[85 * i + 102 + 17 * j + k]; - float v20 = (field_7280[85 * i + 1 + 17 * j + k] - v24) * 0.125f; - float v19 = (field_7280[85 * i + 18 + 17 * j + k] - v23) * 0.125f; - float v18 = (field_7280[85 * i + 86 + 17 * j + k] - v22) * 0.125f; - float v17 = (field_7280[85 * i + 103 + 17 * j + k] - v21) * 0.125f; + float v24 = heightData[85 * i + 17 * j + k]; + float v23 = heightData[85 * i + 17 + 17 * j + k]; + float v22 = heightData[85 * i + 85 + 17 * j + k]; + float v21 = heightData[85 * i + 102 + 17 * j + k]; + float v20 = (heightData[85 * i + 1 + 17 * j + k] - v24) * 0.125f; + float v19 = (heightData[85 * i + 18 + 17 * j + k] - v23) * 0.125f; + float v18 = (heightData[85 * i + 86 + 17 * j + k] - v22) * 0.125f; + float v17 = (heightData[85 * i + 103 + 17 * j + k] - v21) * 0.125f; for (int l = 0; l < 8; l++) { float v15 = v24; @@ -242,14 +264,14 @@ void RandomLevelSource::prepareHeights(const ChunkPos& pos, TileID* tiles, void* TileID tile = TILE_AIR; if (8 * k + l < 64) { - if (fptr[64 * i + 16 * m + 4 * j + n] < 0.5f && 8 * k + l == 63) + if (biomeData[64 * i + 16 * m + 4 * j + n] < 0.5f && 8 * k + l == 63) tile = Tile::ice->m_ID; else tile = Tile::calmWater->m_ID; } if (v11 > 0.0f) tile = Tile::rock->m_ID; - + tiles[v12] = tile; v12 += 128; v11 = v11 + (v14 - v15) * 0.25f; @@ -267,12 +289,20 @@ void RandomLevelSource::prepareHeights(const ChunkPos& pos, TileID* tiles, void* } } -void RandomLevelSource::buildSurfaces(const ChunkPos& pos, TileID* tiles, Biome** biomes) +void RandomLevelSource::buildSurfaces(LevelChunk* chunk) { - //return; - m_perlinNoise4.getRegion(field_7284, float(pos.x) * 16.0f, float(pos.z) * 16.0f, 0.0f, 16, 16, 1, 1.0f / 32.0f, 1.0f / 32.0f, 1.0f); - m_perlinNoise4.getRegion(field_7684, float(pos.x) * 16.0f, 109.01f, float(pos.z) * 16.0f, 16, 1, 16, 1.0f / 32.0f, 1.0f, 1.0f / 32.0f); - m_perlinNoise5.getRegion(field_7A84, float(pos.x) * 16.0f, float(pos.z) * 16.0f, 0.0f, 16, 16, 1, 1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f); + ThreadData& threadData = m_threadData.getLocal(); + + TileID* tiles = chunk->getTiles(); + Biome** biomes = threadData.getBiomeSource().getBiomeBlock(TilePos(chunk->getPos(), 0), 16, 16); + + float perlinData1[256]; + float perlinData2[256]; + float perlinData3[256]; + + m_perlinNoise4.getRegion(perlinData1, float(chunk->getPos().x) * 16.0f, float(chunk->getPos().z) * 16.0f, 0.0f, 16, 16, 1, 1.0f / 32.0f, 1.0f / 32.0f, 1.0f); + m_perlinNoise4.getRegion(perlinData2, float(chunk->getPos().x) * 16.0f, 109.01f, float(chunk->getPos().z) * 16.0f, 16, 1, 16, 1.0f / 32.0f, 1.0f, 1.0f / 32.0f); + m_perlinNoise5.getRegion(perlinData3, float(chunk->getPos().x) * 16.0f, float(chunk->getPos().z) * 16.0f, 0.0f, 16, 16, 1, 1.0f / 16.0f, 1.0f / 16.0f, 1.0f / 16.0f); // @NOTE: Again, extracted from Java Beta 1.6. Probably accurate constexpr int byte0 = 64; @@ -282,9 +312,9 @@ void RandomLevelSource::buildSurfaces(const ChunkPos& pos, TileID* tiles, Biome* for (int l = 0; l < 16; l++) { Biome* pBiome = biomes[k + l * 16]; - bool flag = field_7284[k + l * 16] + m_random.nextFloat() * 0.2f > 0.0f; - bool flag1 = field_7684[k + l * 16] + m_random.nextFloat() * 0.2f > 3.0f; - int i1 = (int)(field_7A84[k + l * 16] / 3.0f + 3.0f + m_random.nextFloat() * 0.25f); + bool flag = perlinData1[k + l * 16] + m_random.nextFloat() * 0.2f > 0.0f; + bool flag1 = perlinData2[k + l * 16] + m_random.nextFloat() * 0.2f > 3.0f; + int i1 = (int)(perlinData3[k + l * 16] / 3.0f + 3.0f + m_random.nextFloat() * 0.25f); int j1 = -1; TileID byte1 = pBiome->field_20; @@ -359,100 +389,113 @@ void RandomLevelSource::buildSurfaces(const ChunkPos& pos, TileID* tiles, Biome* } } -void RandomLevelSource::postProcess(ChunkSource* src, const ChunkPos& pos) +bool RandomLevelSource::postProcess(ChunkViewSource& chunkViewSource) { - m_pLevel->m_bPostProcessing = true; + LevelChunk* chunk = getExistingChunk(ChunkPos(chunkViewSource.getBounds().getMin().x + 1, chunkViewSource.getBounds().getMin().z + 1)); + assert(chunk); + + PostprocessingManager::ScopedLock lock = PostprocessingManager::getInstance().tryLock(chunk->getPos()); + if (!lock.isValid()) + return false; + + ThreadData& threadData = m_threadData.getLocal(); + Random& random = threadData.getRandom(); + + TileSource source(chunkViewSource.getLevel(), chunkViewSource.getDimension(), chunkViewSource, false, true); + + TileTickingQueue tileTickingQueue; + source.setTickingQueue(tileTickingQueue); + SandTile::instaFall = true; - - TilePos tp = TilePos(pos, 0); + + TilePos tp = TilePos(chunk->getPos(), 0); //LOG_I("Post-Processing %d, %d", pos.x, pos.z); - Biome* pBiome = m_pLevel->getBiomeSource()->getBiome(tp + 16); - int32_t seed = m_pLevel->getSeed(); + Biome* pBiome = threadData.getBiomeSource().getBiome(tp + 16); - m_random.setSeed(seed); - int32_t x1 = 1 + 2 * (m_random.nextInt() / 2); - int32_t x2 = 1 + 2 * (m_random.nextInt() / 2); - m_random.setSeed((int32_t(pos.x) * x1 + int32_t(pos.z) * x2) ^ seed); + random.setSeed(m_level->getSeed()); + int32_t x1 = 1 + 2 * (random.nextInt() / 2); + int32_t x2 = 1 + 2 * (random.nextInt() / 2); + random.setSeed((int32_t(chunk->getPos().x) * x1 + int32_t(chunk->getPos().z) * x2) ^ m_level->getSeed()); // @NOTE: I can't put the random calls _in_ the argument list - args are evaluated right to left I believe for (int i = 0; i < 10; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - ClayFeature(Tile::clay->m_ID, 32).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + ClayFeature(Tile::clay->m_ID, 32).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } - + // Start of ore generation for (int i = 0; i < 20; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - OreFeature(Tile::dirt->m_ID, 32).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + OreFeature(Tile::dirt->m_ID, 32).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 10; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - OreFeature(Tile::gravel->m_ID, 32).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + OreFeature(Tile::gravel->m_ID, 32).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 20; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - OreFeature(Tile::coalOre->m_ID, 16).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + OreFeature(Tile::coalOre->m_ID, 16).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 20; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(64); - int zo = m_random.nextInt(16); - OreFeature(Tile::ironOre->m_ID, 8).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(64); + int zo = random.nextInt(16); + OreFeature(Tile::ironOre->m_ID, 8).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 2; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(32); - int zo = m_random.nextInt(16); - OreFeature(Tile::goldOre->m_ID, 8).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(32); + int zo = random.nextInt(16); + OreFeature(Tile::goldOre->m_ID, 8).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 8; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(16); - int zo = m_random.nextInt(16); - OreFeature(Tile::redStoneOre->m_ID, 7).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(16); + int zo = random.nextInt(16); + OreFeature(Tile::redStoneOre->m_ID, 7).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 1; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(16); - int zo = m_random.nextInt(16); - OreFeature(Tile::emeraldOre->m_ID, 7).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(16); + int zo = random.nextInt(16); + OreFeature(Tile::emeraldOre->m_ID, 7).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } for (int i = 0; i < 1; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(16) + m_random.nextInt(16); - int zo = m_random.nextInt(16); - OreFeature(Tile::lapisOre->m_ID, 6).place(m_pLevel, &m_random, TilePos(tp.x + xo, yo, tp.z + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(16) + random.nextInt(16); + int zo = random.nextInt(16); + OreFeature(Tile::lapisOre->m_ID, 6).place(&source, &random, TilePos(tp.x + xo, yo, tp.z + zo)); } // End of ore generation // Start of tree generation float t1 = m_perlinNoise8.getValue(float(tp.x) / 2.0f, float(tp.z) / 2.0f); - float t2 = m_random.nextFloat(); + float t2 = random.nextFloat(); int t3 = int((4.0f + t2 * 4.0f + t1 * 0.125f) / 3.0f); int treeCount = 0; - if (m_random.nextInt(10) == 0) + if (random.nextInt(10) == 0) treeCount++; if (pBiome == Biome::forest) @@ -479,73 +522,73 @@ void RandomLevelSource::postProcess(ChunkSource* src, const ChunkPos& pos) for (int i = 0; i < treeCount; i++) { TilePos rng; - rng.x = m_random.nextInt(16) + tp.x + 8; - rng.z = m_random.nextInt(16) + tp.z + 8; - rng.y = m_pLevel->getHeightmap(rng); + rng.x = random.nextInt(16) + tp.x + 8; + rng.z = random.nextInt(16) + tp.z + 8; + rng.y = source.getHeightmap(rng); - Feature* pTreeFeature = pBiome->getTreeFeature(&m_random); + Feature* pTreeFeature = pBiome->getTreeFeature(&random); if (pTreeFeature) { pTreeFeature->init(1.0f, 1.0f, 1.0f); - pTreeFeature->place(m_pLevel, &m_random, rng); + pTreeFeature->place(&source, &random, rng); delete pTreeFeature; } } for (int i = 0; i < 2; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - FlowerFeature(Tile::flower->m_ID).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + FlowerFeature(Tile::flower->m_ID).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } - if (m_random.nextInt(2) == 0) + if (random.nextInt(2) == 0) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - FlowerFeature(Tile::rose->m_ID).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + FlowerFeature(Tile::rose->m_ID).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } - if (m_random.nextInt(4) == 0) + if (random.nextInt(4) == 0) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - FlowerFeature(Tile::mushroom1->m_ID).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + FlowerFeature(Tile::mushroom1->m_ID).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } - if (m_random.nextInt(8) == 0) + if (random.nextInt(8) == 0) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - FlowerFeature(Tile::mushroom2->m_ID).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + FlowerFeature(Tile::mushroom2->m_ID).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } for (int i = 0; i < 10; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - ReedsFeature().place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + ReedsFeature().place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } for (int i = 0; i < 50; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(m_random.nextInt(120) + 8); - int zo = m_random.nextInt(16); - SpringFeature(Tile::water->m_ID).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(random.nextInt(120) + 8); + int zo = random.nextInt(16); + SpringFeature(Tile::water->m_ID).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } for (int i = 0; i < 20; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(m_random.nextInt(m_random.nextInt(112) + 8) + 8); - int zo = m_random.nextInt(16); - SpringFeature(Tile::lava->m_ID).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(random.nextInt(random.nextInt(112) + 8) + 8); + int zo = random.nextInt(16); + SpringFeature(Tile::lava->m_ID).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } int vegetationCount = 0; @@ -555,18 +598,18 @@ void RandomLevelSource::postProcess(ChunkSource* src, const ChunkPos& pos) for (int i = 0; i < vegetationCount; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - CactusFeature().place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + CactusFeature().place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } - if (m_random.nextInt(32) == 0) + if (random.nextInt(32) == 0) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - PumpkinFeature().place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + PumpkinFeature().place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } #ifdef FEATURE_PLANT_VEGGIES vegetationCount = 0; @@ -590,14 +633,14 @@ void RandomLevelSource::postProcess(ChunkSource* src, const ChunkPos& pos) { TileData data = 1; - if (pBiome == Biome::rainForest && m_random.nextInt(3) != 0) + if (pBiome == Biome::rainForest && random.nextInt(3) != 0) { data = 2; } - TilePos o(m_random.nextInt(16), - m_random.nextInt(128), - m_random.nextInt(16)); - VegetationFeature(Tile::tallGrass->id, data).place(m_pLevel, &m_random, TilePos(tp.x + 8 + o.x, o.y, tp.z + 8 + o.z)); + TilePos o(random.nextInt(16), + random.nextInt(128), + random.nextInt(16)); + VegetationFeature(Tile::tallGrass->m_ID, data).place(&source, &random, TilePos(tp.x + 8 + o.x, o.y, tp.z + 8 + o.z)); } vegetationCount = 0; @@ -607,13 +650,13 @@ void RandomLevelSource::postProcess(ChunkSource* src, const ChunkPos& pos) for (int i = 0; i < vegetationCount; i++) { - int xo = m_random.nextInt(16); - int yo = m_random.nextInt(128); - int zo = m_random.nextInt(16); - VegetationFeature(Tile::deadBush->id, 0, 4).place(m_pLevel, &m_random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); + int xo = random.nextInt(16); + int yo = random.nextInt(128); + int zo = random.nextInt(16); + VegetationFeature(Tile::deadBush->m_ID, 0, 4).place(&source, &random, TilePos(tp.x + 8 + xo, yo, tp.z + 8 + zo)); } #endif - float* tempBlock = m_pLevel->getBiomeSource()->getTemperatureBlock(tp.x + 8, tp.z + 8, 16, 16); + float* tempBlock = threadData.getBiomeSource().getTemperatureBlock(tp.x + 8, tp.z + 8, 16, 16); for (int j19 = tp.x + 8; j19 < tp.x + 8 + 16; j19++) { for (int j22 = tp.z + 8; j22 < tp.z + 8 + 16; j22++) @@ -621,47 +664,29 @@ void RandomLevelSource::postProcess(ChunkSource* src, const ChunkPos& pos) int i24 = j19 - (tp.x + 8); int j25 = j22 - (tp.z + 8); - int tsb = m_pLevel->getTopSolidBlock(TilePos(j19, 0, j22)); - + int tsb = source.getTopSolidBlock(j19, j22, false); + if (SNOW_CUTOFF > (tempBlock[i24 * 16 + j25] - SNOW_SCALE * (float(tsb - 64) / 64.0f))) { - if (tsb >= 0 && tsb < C_MAX_Y && m_pLevel->isEmptyTile(TilePos(j19, tsb, j22))) + if (tsb >= 0 && tsb < C_MAX_Y && source.isEmptyTile(j19, tsb, j22)) { - if (m_pLevel->getMaterial(TilePos(j19, tsb - 1, j22))->blocksMotion() && - m_pLevel->getMaterial(TilePos(j19, tsb - 1, j22)) != Material::ice) + Material* material = source.getMaterial(TilePos(j19, tsb - 1, j22)); + + if (material->blocksMotion() && + material != Material::ice) { - m_pLevel->setTile(TilePos(j19, tsb, j22), Tile::topSnow->m_ID); + source.setTile(j19, tsb, j22, Tile::topSnow->m_ID); } } } } } - SandTile::instaFall = false; - m_pLevel->m_bPostProcessing = false; -} + tileTickingQueue.tickAllPendingTicks(source); -int RandomLevelSource::tick() -{ - return 0; -} + SandTile::instaFall = false; -bool RandomLevelSource::shouldSave() -{ - return true; -} + chunk->setSaved(); -bool RandomLevelSource::hasChunk(const ChunkPos& pos) -{ return true; } - -LevelChunk* RandomLevelSource::create(const ChunkPos& pos) -{ - return getChunk(pos); -} - -std::string RandomLevelSource::gatherStats() -{ - return "RandomLevelSource"; -} diff --git a/source/world/level/levelgen/chunk/RandomLevelSource.hpp b/source/world/level/levelgen/chunk/RandomLevelSource.hpp index 94047a18d..7bd0a2234 100644 --- a/source/world/level/levelgen/chunk/RandomLevelSource.hpp +++ b/source/world/level/levelgen/chunk/RandomLevelSource.hpp @@ -8,40 +8,36 @@ #pragma once -// @NOTE: This class appears to reference a mythical "std::hashtable", but I couldn't find any traces of it. -// I doubt they used C++11 (since it came out in 2011), but this is weird... -// We'll use std::unordered_map instead. - -#include -#include "ChunkSource.hpp" +#include "world/level/levelgen/chunk/ChunkSource.hpp" #include "world/level/levelgen/synth/PerlinNoise.hpp" #include "world/level/levelgen/biome/BiomeSource.hpp" #include "world/level/levelgen/feature/Feature.hpp" #include "world/level/levelgen/feature/LargeCaveFeature.hpp" +#include "common/threading/ThreadLocal.hpp" class RandomLevelSource : public ChunkSource { +private: + struct ThreadData; + public: - RandomLevelSource(Level*, int32_t seed, int); - int tick() override; - bool shouldSave() override; - bool hasChunk(const ChunkPos& pos) override; - LevelChunk* create(const ChunkPos& pos) override; - LevelChunk* getChunk(const ChunkPos& pos) override; - LevelChunk* getChunkDontCreate(const ChunkPos& pos) override; - std::string gatherStats() override; - void postProcess(ChunkSource*, const ChunkPos& pos) override; + RandomLevelSource(Level* level, Dimension* dimension, uint32_t seed); - float* getHeights(float*, int, int, int, int, int, int); - void prepareHeights(const ChunkPos& pos, TileID*, void*, float*); - void buildSurfaces (const ChunkPos& pos, TileID*, Biome**); - + LevelChunk* requestChunk(const ChunkPos& pos, LoadMode loadMode) override; + bool postProcess(ChunkViewSource& chunkViewSource) override; + void loadChunk(LevelChunk& chunk) override; + void postProcessMobsAt(TileSource* tileSource, int, int, Random& random) override; + void getHeights(float* fptr, int a3, int a4, int a5); + void prepareHeights(LevelChunk* chunk, float* biomeData); + void buildSurfaces(LevelChunk* chunk); + public: + ThreadLocal m_threadData; bool field_4; LargeCaveFeature m_largeCaveFeature; int field_9D8[1024]; - std::map m_chunks; + ChunkMap_t m_chunks; float field_19F0; Random m_random; PerlinNoise m_perlinNoise1; @@ -52,7 +48,6 @@ class RandomLevelSource : public ChunkSource PerlinNoise m_perlinNoise6; PerlinNoise m_perlinNoise7; PerlinNoise m_perlinNoise8; - Level* m_pLevel; float* field_7280; float field_7284[256]; float field_7684[256]; diff --git a/source/world/level/levelgen/chunk/TestChunkSource.cpp b/source/world/level/levelgen/chunk/TestChunkSource.cpp deleted file mode 100644 index d0f5bde69..000000000 --- a/source/world/level/levelgen/chunk/TestChunkSource.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "TestChunkSource.hpp" -#include "world/level/Level.hpp" -#include "EmptyLevelChunk.hpp" - -TestChunkSource::TestChunkSource(Level* pLevel) -{ - m_pLevel = pLevel; - memset(m_chunkMap, 0, sizeof m_chunkMap); - - m_pEmptyChunk = new EmptyLevelChunk(pLevel, nullptr, ChunkPos(0,0)); - - m_lastChunkPos = ChunkPos(-99999, -99999); - m_pLastChunk = m_pEmptyChunk; -} - -TestChunkSource::~TestChunkSource() -{ - for (int z = 0; z < C_MAX_CHUNKS_Z; z++) - { - for (int x = 0; x < C_MAX_CHUNKS_X; x++) - { - if (m_chunkMap[z][x]) - delete m_chunkMap[z][x]; - } - } -} - -LevelChunk* TestChunkSource::generateChunk(const ChunkPos& pos) -{ - //@NOTE: This gets called a dangerous amount of recursions (for the entire damn world!) - // We really should fix this... - - if (pos.x < 0 || pos.z < 0 || pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return nullptr; - - if (m_chunkMap[pos.z][pos.x]) - return m_chunkMap[pos.z][pos.x]; - - TileID* pData = new TileID[0x8000u]; - memset(pData, 0, 0x8000u * sizeof(TileID)); - - for (int i = 0; i != 66; i++) - { - for (int j = 0; j < 16; j++) - { - for (int k = 0; k < 16; k++) - { - TileID* p = &pData[i | (j << 11) | (k << 7)]; - - if (i == 0) - *p = TILE_BEDROCK; - //else if (j == 0 || k == 0) - // *p = TILE_AIR; - else if (i == 65) { - /*if (rand() % 10 == 0) - *p = TILE_ROSE; - else if (rand() % 10 == 0) - *p = TILE_FLOWER; - else if (rand() % 10 == 0) - *p = TILE_TOPSNOW;*/ - } - else if (i > 64) - *p = TILE_AIR; - else if (i == 64) { - //if ((j + k) % 2 == 0) - *p = TILE_GRASS; - } - else if (i > 60) - *p = TILE_DIRT; - else if (i > 3) - *p = TILE_STONE; - else - *p = TILE_STONEBRICK; - - // generate a hole at (128,0,128) for testing - //if (i == 0 && j == 0 && k == 0 && x == 8 && z == 8) - // *p = TILE_WOOD; - } - } - } - - LevelChunk* pChunk = new LevelChunk(m_pLevel, pData, pos); - - m_chunkMap[pos.z][pos.x] = pChunk; - - /* - // block light updates during level generation - bool bOldState = m_pLevel->m_bUpdateLights; - m_pLevel->m_bUpdateLights = false; - - // encode this chunk's X/Z coordinate by setting bits in it - pChunk->setTile(0, 65, 0, TILE_WOOD); - pChunk->setTile(0, 65, 1, TILE_STONE); - pChunk->setTile(3+1, 65, 0, (x & (1 << 0)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(2+1, 65, 0, (x & (1 << 1)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(1+1, 65, 0, (x & (1 << 2)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(0+1, 65, 0, (x & (1 << 3)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(3+1, 65, 1, (z & (1 << 0)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(2+1, 65, 1, (z & (1 << 1)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(1+1, 65, 1, (z & (1 << 2)) ? TILE_STONEBRICK : TILE_BEDROCK); - pChunk->setTile(0+1, 65, 1, (z & (1 << 3)) ? TILE_STONEBRICK : TILE_BEDROCK); - - m_pLevel->m_bUpdateLights = bOldState; - - pChunk->setBrightness(LightLayer::Block, 0, 0, 0, 3); - pChunk->setBrightness(LightLayer::Block, 0, 1, 0, 4); - pChunk->setBrightness(LightLayer::Block, 0, 2, 0, 5); - pChunk->setBrightness(LightLayer::Block, 0, 3, 0, 6); - int br1 = pChunk->getBrightness(LightLayer::Block, 0, 0, 0); - int br2 = pChunk->getBrightness(LightLayer::Block, 0, 1, 0); - int br3 = pChunk->getBrightness(LightLayer::Block, 0, 2, 0); - int br4 = pChunk->getBrightness(LightLayer::Block, 0, 3, 0); - assert(br1 == 3); - assert(br2 == 4); - assert(br3 == 5); - assert(br4 == 6); - */ - - pChunk->recalcHeightmap(); - - return pChunk; -} - -LevelChunk* TestChunkSource::create(const ChunkPos& pos) -{ - if (m_lastChunkPos == pos) - return m_pLastChunk; - - LevelChunk* pChk = generateChunk(pos); - if (!pChk) - pChk = m_pEmptyChunk; - - m_lastChunkPos = pos; - m_pLastChunk = pChk; - - return pChk; -} - -std::string TestChunkSource::gatherStats() -{ - return "TestChunkSource"; -} - -LevelChunk* TestChunkSource::getChunk(const ChunkPos& pos) -{ - return create(pos); -} - -LevelChunk* TestChunkSource::getChunkDontCreate(const ChunkPos& pos) -{ - if (pos.x < 0 || pos.z < 0 || pos.x >= C_MAX_CHUNKS_X || pos.z >= C_MAX_CHUNKS_Z) - return nullptr; - - if (m_chunkMap[pos.z][pos.x]) - return m_chunkMap[pos.z][pos.x]; - - TileID* pData = new TileID[0x8000u]; - memset(pData, 0, 0x8000u * sizeof(TileID)); - - m_chunkMap[pos.z][pos.x] = new LevelChunk(m_pLevel, pData, pos); - m_pLastChunk = m_chunkMap[pos.z][pos.x]; - m_lastChunkPos = pos; - - return m_chunkMap[pos.z][pos.x]; -} - -bool TestChunkSource::hasChunk(const ChunkPos& pos) -{ - return true; -} - -void TestChunkSource::postProcess(ChunkSource* a, const ChunkPos& pos) -{ - -} - -bool TestChunkSource::shouldSave() -{ - return false; -} - -int TestChunkSource::tick() -{ - return 0; -} - diff --git a/source/world/level/levelgen/chunk/TestChunkSource.hpp b/source/world/level/levelgen/chunk/TestChunkSource.hpp deleted file mode 100644 index d58d9897c..000000000 --- a/source/world/level/levelgen/chunk/TestChunkSource.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include -#include "ChunkSource.hpp" - -class Level; - -class TestChunkSource : public ChunkSource -{ -public: - TestChunkSource(Level*); - virtual ~TestChunkSource(); - - LevelChunk* generateChunk(const ChunkPos& pos); - LevelChunk* create(const ChunkPos& pos) override; - LevelChunk* getChunk(const ChunkPos& pos) override; - LevelChunk* getChunkDontCreate(const ChunkPos& pos) override; - bool hasChunk(const ChunkPos& pos) override; - std::string gatherStats() override; - void postProcess(ChunkSource*, const ChunkPos& pos) override; - bool shouldSave() override; - int tick() override; - -public: - Level* m_pLevel; - - LevelChunk* m_chunkMap[C_MAX_CHUNKS_Z][C_MAX_CHUNKS_X]; - LevelChunk* m_pEmptyChunk; - LevelChunk* m_pLastChunk; - ChunkPos m_lastChunkPos; -}; diff --git a/source/world/level/levelgen/chunk/WorldLimitChunkSource.cpp b/source/world/level/levelgen/chunk/WorldLimitChunkSource.cpp new file mode 100644 index 000000000..3b68e2765 --- /dev/null +++ b/source/world/level/levelgen/chunk/WorldLimitChunkSource.cpp @@ -0,0 +1,55 @@ +#include "world/level/levelgen/chunk/WorldLimitChunkSource.hpp" +#include "world/level/levelgen/chunk/LevelChunk.hpp" +#include "world/tile/Tile.hpp" +#include "world/level/LevelConstants.hpp" + +static Bounds GetWorldSizeBounds(const TilePos& limitOrigin) +{ + ChunkPos minPos(limitOrigin); + minPos -= (LevelConstants::WORLD_SIZE_XZ / 2); + ChunkPos maxPos(limitOrigin); + maxPos += (LevelConstants::WORLD_SIZE_XZ / 2) - 1; + + return Bounds(minPos, maxPos, 16, true); +} + +WorldLimitChunkSource::WorldLimitChunkSource(std::unique_ptr parent, const TilePos& limitOrigin) + : ChunkSource(std::move(parent)), + m_bounds(GetWorldSizeBounds(limitOrigin)) +{ + m_outOfBoundsChunk = new LevelChunk(*m_level, *m_dimension, ChunkPos::INVALID, false); + memset(m_outOfBoundsChunk->getTiles(), Tile::invisible_bedrock->m_ID, ChunkConstants::TILE_COUNT); + m_outOfBoundsChunk->changeState(CS_UNLOADED, CS_POST_PROCESSED); + + // load all chunks for fun + Bounds::Iterator iter = m_bounds.begin(); + while (!iter.end()) + { + ChunkPos pos(iter.pos().x, iter.pos().z); + m_chunks.push_back(requestChunk(pos, LOAD_DEFERRED)); + } +} + +LevelChunk* WorldLimitChunkSource::getExistingChunk(const ChunkPos& pos) +{ + if (m_bounds.contains(Vec3Int32(pos.x, 0, pos.z))) + return m_parent->getExistingChunk(pos); + else + return m_outOfBoundsChunk; +} + +LevelChunk* WorldLimitChunkSource::requestChunk(const ChunkPos& pos, LoadMode loadMode) +{ + if (m_bounds.contains(Vec3Int32(pos.x, 0, pos.z))) + return m_parent->requestChunk(pos, loadMode); + else + return m_outOfBoundsChunk; +} + +bool WorldLimitChunkSource::releaseChunk(LevelChunk& chunk) +{ + if (&chunk == m_outOfBoundsChunk) + return false; + + return m_parent->releaseChunk(chunk); +} diff --git a/source/world/level/levelgen/chunk/WorldLimitChunkSource.hpp b/source/world/level/levelgen/chunk/WorldLimitChunkSource.hpp new file mode 100644 index 000000000..81d57db80 --- /dev/null +++ b/source/world/level/levelgen/chunk/WorldLimitChunkSource.hpp @@ -0,0 +1,19 @@ +#pragma once +#include "world/level/levelgen/chunk/ChunkSource.hpp" + +class WorldLimitChunkSource : public ChunkSource +{ +protected: + Bounds m_bounds; + std::vector m_chunks; + LevelChunk* m_outOfBoundsChunk; + +public: + WorldLimitChunkSource(std::unique_ptr parent, const TilePos& limitOrigin); + virtual ~WorldLimitChunkSource(); + +public: + LevelChunk* getExistingChunk(const ChunkPos& pos) override; + LevelChunk* requestChunk(const ChunkPos& pos, LoadMode loadMode) override; + bool releaseChunk(LevelChunk& chunk) override; +}; diff --git a/source/world/level/levelgen/feature/BirchFeature.cpp b/source/world/level/levelgen/feature/BirchFeature.cpp index 7fad27a6a..013eb2bdc 100644 --- a/source/world/level/levelgen/feature/BirchFeature.cpp +++ b/source/world/level/levelgen/feature/BirchFeature.cpp @@ -7,9 +7,9 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool BirchFeature::place(Level* level, Random* random, const TilePos& pos) +bool BirchFeature::place(TileSource* source, Random* random, const TilePos& pos) { if (pos.y <= C_MIN_Y) return false; @@ -40,7 +40,7 @@ bool BirchFeature::place(Level* level, Random* random, const TilePos& pos) break; } - TileID tile = level->getTile(tp); + TileID tile = source->getTile(tp); // other trees can overlap with this one, apparently if (tile != TILE_AIR && tile != Tile::leaves->m_ID) @@ -56,7 +56,7 @@ bool BirchFeature::place(Level* level, Random* random, const TilePos& pos) if (!bCanPlace) return false; - TileID tileBelow = level->getTile(pos.below()); + TileID tileBelow = source->getTile(pos.below()); // If grass or dirt aren't below us, we can't possibly grow! if (tileBelow != Tile::grass->m_ID && tileBelow != Tile::dirt->m_ID) @@ -66,7 +66,7 @@ bool BirchFeature::place(Level* level, Random* random, const TilePos& pos) if (pos.y >= C_MAX_Y - treeHeight) return false; - level->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); + source->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); int upperY = pos.y + treeHeight; int lowerY = pos.y + treeHeight - 3; @@ -87,9 +87,9 @@ bool BirchFeature::place(Level* level, Random* random, const TilePos& pos) for (tp.z = pos.z - c1; tp.z <= pos.z + c1; tp.z++, c4++) { - if ((abs(tp.x - pos.x) != c1 || abs(tp.z - pos.z) != c1 || (random->nextInt(2) != 0 && diff != 0)) && !Tile::solid[level->getTile(TilePos(tp.x, i, tp.z))]) + if ((abs(tp.x - pos.x) != c1 || abs(tp.z - pos.z) != c1 || (random->nextInt(2) != 0 && diff != 0)) && !Tile::solid[source->getTile(TilePos(tp.x, i, tp.z))]) { - level->setTileAndDataNoUpdate(TilePos(tp.x, i, tp.z), Tile::leaves->m_ID, 2); + source->setTileAndDataNoUpdate(TilePos(tp.x, i, tp.z), FullTile(Tile::leaves->m_ID, 2)); } } } @@ -98,11 +98,11 @@ bool BirchFeature::place(Level* level, Random* random, const TilePos& pos) for (int i = 0; i < treeHeight; i++) { //int y1 = i + pos.y; - TileID tile = level->getTile(TilePos(pos.x, pos.y + i, pos.z)); + TileID tile = source->getTile(TilePos(pos.x, pos.y + i, pos.z)); if (tile && tile != Tile::leaves->m_ID) continue; - level->setTileAndDataNoUpdate(TilePos(pos.x, pos.y + i, pos.z), Tile::treeTrunk->m_ID, 2); + source->setTileAndDataNoUpdate(TilePos(pos.x, pos.y + i, pos.z), FullTile(Tile::treeTrunk->m_ID, 2)); } return true; diff --git a/source/world/level/levelgen/feature/CactusFeature.cpp b/source/world/level/levelgen/feature/CactusFeature.cpp index dc2681d69..6230aa80b 100644 --- a/source/world/level/levelgen/feature/CactusFeature.cpp +++ b/source/world/level/levelgen/feature/CactusFeature.cpp @@ -1,7 +1,7 @@ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool CactusFeature::place(Level* level, Random* random, const TilePos& pos) +bool CactusFeature::place(TileSource* source, Random* random, const TilePos& pos) { TilePos tp; for (int var6 = 0; var6 < 10; ++var6) @@ -9,15 +9,15 @@ bool CactusFeature::place(Level* level, Random* random, const TilePos& pos) tp.x = pos.x + random->nextInt(8) - random->nextInt(8); tp.y = pos.y + random->nextInt(4) - random->nextInt(4); tp.z = pos.z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(tp)) + if (source->isEmptyTile(tp)) { int var10 = 1 + random->nextInt(random->nextInt(3) + 1); for (int var11 = 0; var11 < var10; ++var11) { TilePos above = tp.above(var11); - if (Tile::cactus->canSurvive(level, above)) + if (Tile::cactus->canSurvive(source, above)) { - level->setTileNoUpdate(above, Tile::cactus->m_ID); + source->setTileNoUpdate(above, Tile::cactus->m_ID); } } } diff --git a/source/world/level/levelgen/feature/ClayFeature.cpp b/source/world/level/levelgen/feature/ClayFeature.cpp index 291b76697..316b31d0f 100644 --- a/source/world/level/levelgen/feature/ClayFeature.cpp +++ b/source/world/level/levelgen/feature/ClayFeature.cpp @@ -8,6 +8,7 @@ #include "Feature.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" ClayFeature::ClayFeature(TileID id, int count) { @@ -15,9 +16,9 @@ ClayFeature::ClayFeature(TileID id, int count) m_count = count; } -bool ClayFeature::place(Level* level, Random* random, const TilePos& pos) +bool ClayFeature::place(TileSource* source, Random* random, const TilePos& pos) { - if (level->getMaterial(pos) != Material::water) + if (source->getMaterial(pos) != Material::water) { return false; } @@ -66,8 +67,8 @@ bool ClayFeature::place(Level* level, Random* random, const TilePos& pos) if (d12 * d12 + d13 * d13 + d14 * d14 >= 1.0f) continue; - if (level->getTile(tp) == Tile::sand->m_ID) - level->setTileNoUpdate(tp, m_ID); + if (source->getTile(tp) == Tile::sand->m_ID) + source->setTileAndData(tp, FullTile(m_ID, 0), TileChange::UPDATE_LISTENERS); } } } diff --git a/source/world/level/levelgen/feature/FancyTreeFeature.cpp b/source/world/level/levelgen/feature/FancyTreeFeature.cpp index 64cbdb1b3..b19c11b55 100644 --- a/source/world/level/levelgen/feature/FancyTreeFeature.cpp +++ b/source/world/level/levelgen/feature/FancyTreeFeature.cpp @@ -1,5 +1,6 @@ #include "Feature.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include struct FoliageCoord @@ -8,10 +9,10 @@ struct FoliageCoord }; // Static array definition for axis conversion -const uint8_t FancyTreeFeature::axisConversionArray[] = {2, 0, 0, 1, 2, 1}; +static uint8_t AxisConversionArray[] = {2, 0, 0, 1, 2, 1}; FancyTreeFeature::FancyTreeFeature() : - m_pLevel(NULL), + m_tileSource(NULL), m_origin(), m_height(0), m_trunkHeight(0), @@ -29,7 +30,7 @@ FancyTreeFeature::~FancyTreeFeature() { } -int& FancyTreeFeature::getAxisCoord(TilePos& pos, uint8_t axis) +static int& GetAxisCoord(TilePos& pos, uint8_t axis) { switch (axis) { @@ -40,7 +41,7 @@ int& FancyTreeFeature::getAxisCoord(TilePos& pos, uint8_t axis) } } -int FancyTreeFeature::getAxisCoord(const TilePos& pos, uint8_t axis) +static int GetAxisCoord(const TilePos& pos, uint8_t axis) { switch (axis) { @@ -128,18 +129,18 @@ void FancyTreeFeature::generateBranchesAndTrunk() } } -void FancyTreeFeature::crossection(int x, int y, int z, float radius, uint8_t majorAxis, int blockId) +void FancyTreeFeature::crossection(int x, int y, int z, float radius, uint8_t majorAxis, TileID tileId) { int radiusRounded = static_cast(radius + 0.618f); - uint8_t axis2 = axisConversionArray[majorAxis]; - uint8_t axis3 = axisConversionArray[majorAxis + 3]; + uint8_t axis2 = AxisConversionArray[majorAxis]; + uint8_t axis3 = AxisConversionArray[majorAxis + 3]; TilePos center(x, y, z); TilePos currentPos = center; for (int dx = -radiusRounded; dx <= radiusRounded; ++dx) { - getAxisCoord(currentPos, axis2) = getAxisCoord(center, axis2) + dx; + GetAxisCoord(currentPos, axis2) = GetAxisCoord(center, axis2) + dx; for (int dz = -radiusRounded; dz <= radiusRounded; ++dz) { @@ -149,12 +150,12 @@ void FancyTreeFeature::crossection(int x, int y, int z, float radius, uint8_t ma if (distance <= radius) { - getAxisCoord(currentPos, axis3) = getAxisCoord(center, axis3) + dz; - int tileId = m_pLevel->getTile(currentPos); + GetAxisCoord(currentPos, axis3) = GetAxisCoord(center, axis3) + dz; + TileID currentTileId = m_tileSource->getTile(currentPos); - if (tileId == TILE_AIR || tileId == TILE_LEAVES) + if (currentTileId == TILE_AIR || currentTileId == TILE_LEAVES) { - m_pLevel->setTileNoUpdate(currentPos, blockId); + m_tileSource->setTileNoUpdate(currentPos, tileId); } } } @@ -204,35 +205,35 @@ void FancyTreeFeature::foliageCluster(int x, int y, int z) } } -void FancyTreeFeature::limb(const TilePos& start, const TilePos& end, int blockId) +void FancyTreeFeature::limb(const TilePos& start, const TilePos& end, TileID tileId) { TilePos delta(end.x - start.x, end.y - start.y, end.z - start.z); uint8_t majorAxis = 0; if (Mth::abs(delta.y) > Mth::abs(delta.x)) majorAxis = 1; - if (Mth::abs(delta.z) > Mth::abs(getAxisCoord(delta, majorAxis))) majorAxis = 2; + if (Mth::abs(delta.z) > Mth::abs(GetAxisCoord(delta, majorAxis))) majorAxis = 2; - int majorDelta = getAxisCoord(delta, majorAxis); + int majorDelta = GetAxisCoord(delta, majorAxis); if (majorDelta != 0) { - uint8_t axis2 = axisConversionArray[majorAxis]; - uint8_t axis3 = axisConversionArray[majorAxis + 3]; + uint8_t axis2 = AxisConversionArray[majorAxis]; + uint8_t axis3 = AxisConversionArray[majorAxis + 3]; int step = (majorDelta > 0) ? 1 : -1; - float ratio1 = static_cast(getAxisCoord(delta, axis2)) / static_cast(majorDelta); - float ratio2 = static_cast(getAxisCoord(delta, axis3)) / static_cast(majorDelta); + float ratio1 = static_cast(GetAxisCoord(delta, axis2)) / static_cast(majorDelta); + float ratio2 = static_cast(GetAxisCoord(delta, axis3)) / static_cast(majorDelta); TilePos currentPos; int endCounter = majorDelta + step; for (int counter = 0; counter != endCounter; counter += step) { - getAxisCoord(currentPos, majorAxis) = static_cast(Mth::floor(static_cast(getAxisCoord(start, majorAxis) + counter) + 0.5f)); - getAxisCoord(currentPos, axis2) = static_cast(Mth::floor(static_cast(getAxisCoord(start, axis2)) + static_cast(counter) * ratio1 + 0.5f)); - getAxisCoord(currentPos, axis3) = static_cast(Mth::floor(static_cast(getAxisCoord(start, axis3)) + static_cast(counter) * ratio2 + 0.5f)); + GetAxisCoord(currentPos, majorAxis) = static_cast(Mth::floor(static_cast(GetAxisCoord(start, majorAxis) + counter) + 0.5f)); + GetAxisCoord(currentPos, axis2) = static_cast(Mth::floor(static_cast(GetAxisCoord(start, axis2)) + static_cast(counter) * ratio1 + 0.5f)); + GetAxisCoord(currentPos, axis3) = static_cast(Mth::floor(static_cast(GetAxisCoord(start, axis3)) + static_cast(counter) * ratio2 + 0.5f)); - m_pLevel->setTileNoUpdate(currentPos, blockId); + m_tileSource->setTileNoUpdate(currentPos, tileId); } } } @@ -259,38 +260,38 @@ void FancyTreeFeature::makeTrunk() } } -int FancyTreeFeature::checkLine(TilePos& startPos, TilePos& endPos) +int FancyTreeFeature::checkLine(const TilePos& startPos, const TilePos& endPos) { - TilePos delta(endPos.x - startPos.x, endPos.y - startPos.y, endPos.z - startPos.z); + TilePos delta = endPos - startPos; uint8_t majorAxisIdx = 0; if (Mth::abs(delta.y) > Mth::abs(delta.x)) majorAxisIdx = 1; - if (Mth::abs(delta.z) > Mth::abs(getAxisCoord(delta, majorAxisIdx))) majorAxisIdx = 2; + if (Mth::abs(delta.z) > Mth::abs(GetAxisCoord(delta, majorAxisIdx))) majorAxisIdx = 2; - int majorDelta = getAxisCoord(delta, majorAxisIdx); + int majorDelta = GetAxisCoord(delta, majorAxisIdx); if (majorDelta == 0) { return -1; } - uint8_t axis2 = axisConversionArray[majorAxisIdx]; - uint8_t axis3 = axisConversionArray[majorAxisIdx + 3]; + uint8_t axis2 = AxisConversionArray[majorAxisIdx]; + uint8_t axis3 = AxisConversionArray[majorAxisIdx + 3]; int step = (majorDelta > 0) ? 1 : -1; - float ratio1 = static_cast(getAxisCoord(delta, axis2)) / static_cast(majorDelta); - float ratio2 = static_cast(getAxisCoord(delta, axis3)) / static_cast(majorDelta); + float ratio1 = static_cast(GetAxisCoord(delta, axis2)) / static_cast(majorDelta); + float ratio2 = static_cast(GetAxisCoord(delta, axis3)) / static_cast(majorDelta); TilePos currentPos; int endCounter = majorDelta + step; for (int counter = 0; counter != endCounter; counter += step) { - getAxisCoord(currentPos, majorAxisIdx) = getAxisCoord(startPos, majorAxisIdx) + counter; - getAxisCoord(currentPos, axis2) = static_cast(Mth::floor(static_cast(getAxisCoord(startPos, axis2)) + static_cast(counter) * ratio1)); - getAxisCoord(currentPos, axis3) = static_cast(Mth::floor(static_cast(getAxisCoord(startPos, axis3)) + static_cast(counter) * ratio2)); + GetAxisCoord(currentPos, majorAxisIdx) = GetAxisCoord(startPos, majorAxisIdx) + counter; + GetAxisCoord(currentPos, axis2) = static_cast(Mth::floor(static_cast(GetAxisCoord(startPos, axis2)) + static_cast(counter) * ratio1)); + GetAxisCoord(currentPos, axis3) = static_cast(Mth::floor(static_cast(GetAxisCoord(startPos, axis3)) + static_cast(counter) * ratio2)); - int tileId = m_pLevel->getTile(currentPos); + TileID tileId = m_tileSource->getTile(currentPos); if (tileId != TILE_AIR && tileId != TILE_LEAVES) { return Mth::abs(counter); @@ -300,11 +301,11 @@ int FancyTreeFeature::checkLine(TilePos& startPos, TilePos& endPos) return -1; } -bool FancyTreeFeature::checkLocation() +bool FancyTreeFeature::checkLocation(TileSource* source) { TilePos basePos(m_origin); TilePos topPos = m_origin.above(m_height - 1); - int groundTileId = m_pLevel->getTile(m_origin.below()); + TileID groundTileId = source->getTile(m_origin.below()); if (groundTileId != 2 && groundTileId != 3) { @@ -338,9 +339,9 @@ void FancyTreeFeature::init(float density, float widthScale, float foliageDensit m_foliageDensity = foliageDensity; } -bool FancyTreeFeature::place(Level* level, Random* random, const TilePos& pos) +bool FancyTreeFeature::place(TileSource* source, Random* random, const TilePos& pos) { - m_pLevel = level; + m_tileSource = source; m_rnd.setSeed(random->nextLong()); m_origin = pos; @@ -349,7 +350,7 @@ bool FancyTreeFeature::place(Level* level, Random* random, const TilePos& pos) m_height = 5 + m_rnd.nextInt(m_heightVariance); } - if (!checkLocation()) + if (!checkLocation(source)) { return false; } diff --git a/source/world/level/levelgen/feature/Feature.hpp b/source/world/level/levelgen/feature/Feature.hpp index ea9c6b54f..e0677805f 100644 --- a/source/world/level/levelgen/feature/Feature.hpp +++ b/source/world/level/levelgen/feature/Feature.hpp @@ -13,38 +13,38 @@ #include "common/Utils.hpp" #include "world/level/TilePos.hpp" -class Level; +class TileSource; class Feature { public: virtual ~Feature(); - virtual bool place(Level*, Random*, const TilePos& pos) = 0; + virtual bool place(TileSource*, Random*, const TilePos& pos) = 0; virtual void init(float, float, float); }; class TreeFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; }; class BirchFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; }; class SpruceFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; }; class PineFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; }; class FancyTreeFeature : public Feature @@ -53,26 +53,21 @@ class FancyTreeFeature : public Feature FancyTreeFeature(); virtual ~FancyTreeFeature(); void generateBranchesAndTrunk(); - void crossection(int x, int y, int z, float radius, uint8_t majorAxis, int blockId); + void crossection(int x, int y, int z, float radius, uint8_t majorAxis, TileID tileId); float treeShape(int offset); float foliageShape(int layerOffset); void foliageCluster(int x, int y, int z); - void limb(const TilePos& start, const TilePos& end, int blockId); + void limb(const TilePos& start, const TilePos& end, TileID tileId); bool trimBranches(int heightOffset); void makeTrunk(); - int checkLine(TilePos& startPos, TilePos& endPos); - bool checkLocation(); + int checkLine(const TilePos& startPos, const TilePos& endPos); + bool checkLocation(TileSource* source); void init(float density, float widthScale, float foliageDensity) override; - bool place(Level*, Random*, const TilePos& pos) override; - - // Helper methods for axis-based coordinate access - static int& getAxisCoord(TilePos& pos, uint8_t axis); - static int getAxisCoord(const TilePos& pos, uint8_t axis); + bool place(TileSource*, Random*, const TilePos& pos) override; private: - static const uint8_t axisConversionArray[6]; Random m_rnd; - Level* m_pLevel; + TileSource* m_tileSource; TilePos m_origin; int m_height; int m_trunkHeight; @@ -89,7 +84,7 @@ class FlowerFeature : public Feature { public: FlowerFeature(TileID id); - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; private: TileID m_ID; @@ -99,7 +94,7 @@ class SpringFeature : public Feature { public: SpringFeature(TileID id); - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; private: TileID m_ID; @@ -109,7 +104,7 @@ class ClayFeature : public Feature { public: ClayFeature(TileID id, int count); - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; private: TileID m_ID; @@ -120,7 +115,7 @@ class OreFeature : public Feature { public: OreFeature(TileID id, int count); - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; private: TileID m_ID; @@ -130,14 +125,14 @@ class OreFeature : public Feature class ReedsFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; }; class VegetationFeature : public Feature { public: VegetationFeature(TileID id, TileData data, int count = 128); - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; private: TileID m_ID; @@ -148,11 +143,13 @@ class VegetationFeature : public Feature class CactusFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; + bool place(TileSource*, Random*, const TilePos& pos) override; }; class PumpkinFeature : public Feature { public: - bool place(Level*, Random*, const TilePos& pos) override; -}; \ No newline at end of file + bool place(TileSource*, Random*, const TilePos& pos) override; +}; + + diff --git a/source/world/level/levelgen/feature/FlowerFeature.cpp b/source/world/level/levelgen/feature/FlowerFeature.cpp index 583220717..c2703e95c 100644 --- a/source/world/level/levelgen/feature/FlowerFeature.cpp +++ b/source/world/level/levelgen/feature/FlowerFeature.cpp @@ -7,14 +7,14 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" FlowerFeature::FlowerFeature(TileID id) { m_ID = id; } -bool FlowerFeature::place(Level* level, Random* random, const TilePos& pos) +bool FlowerFeature::place(TileSource* source, Random* random, const TilePos& pos) { TilePos tp; @@ -24,8 +24,8 @@ bool FlowerFeature::place(Level* level, Random* random, const TilePos& pos) tp.y = pos.y + random->nextInt(4) - random->nextInt(4); tp.z = pos.z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(tp) && Tile::tiles[m_ID]->canSurvive(level, tp)) - level->setTileNoUpdate(tp, m_ID); + if (source->isEmptyTile(tp) && Tile::tiles[m_ID]->canSurvive(source, tp)) + source->setTileNoUpdate(tp, m_ID); } return true; diff --git a/source/world/level/levelgen/feature/OreFeature.cpp b/source/world/level/levelgen/feature/OreFeature.cpp index e530915e2..92219977b 100644 --- a/source/world/level/levelgen/feature/OreFeature.cpp +++ b/source/world/level/levelgen/feature/OreFeature.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" OreFeature::OreFeature(TileID id, int count) { @@ -15,7 +15,7 @@ OreFeature::OreFeature(TileID id, int count) m_count = count; } -bool OreFeature::place(Level* level, Random* random, const TilePos& pos) +bool OreFeature::place(TileSource* source, Random* random, const TilePos& pos) { float fAng = random->nextFloat() * float(M_PI); @@ -66,8 +66,8 @@ bool OreFeature::place(Level* level, Random* random, const TilePos& pos) if (distX * distX + distY * distY + distZ * distZ >= 1.0f) continue; - if (level->getTile(tp) == Tile::rock->m_ID) - level->setTileNoUpdate(tp, m_ID); + if (source->getTile(tp) == Tile::rock->m_ID) + source->setTileNoUpdate(tp, m_ID); } } } diff --git a/source/world/level/levelgen/feature/PineFeature.cpp b/source/world/level/levelgen/feature/PineFeature.cpp index 48e8db3f7..296aaa1aa 100644 --- a/source/world/level/levelgen/feature/PineFeature.cpp +++ b/source/world/level/levelgen/feature/PineFeature.cpp @@ -7,9 +7,9 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool PineFeature::place(Level* level, Random* random, const TilePos& pos) +bool PineFeature::place(TileSource* source, Random* random, const TilePos& pos) { if (pos.y <= C_MIN_Y) return false; @@ -43,7 +43,7 @@ bool PineFeature::place(Level* level, Random* random, const TilePos& pos) break; } - TileID tile = level->getTile(tp); + TileID tile = source->getTile(tp); if (tile != TILE_AIR && tile != Tile::leaves->m_ID) bCanPlace = false; } @@ -53,14 +53,14 @@ bool PineFeature::place(Level* level, Random* random, const TilePos& pos) if (!bCanPlace) return false; - TileID tileBelow = level->getTile(pos.below()); + TileID tileBelow = source->getTile(pos.below()); if (tileBelow != Tile::grass->m_ID && tileBelow != Tile::dirt->m_ID) return false; if (pos.y >= C_MAX_Y - 1 - height) return false; - level->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); + source->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); int range = 0; @@ -73,8 +73,8 @@ bool PineFeature::place(Level* level, Random* random, const TilePos& pos) for (tp.z = pos.z - range; tp.z <= pos.z + range; tp.z++) { int dz = tp.z - pos.z; - if ((abs(dx) != range || abs(dz) != range || range <= 0) && !Tile::solid[level->getTile(TilePos(tp.x, b1, tp.z))]) - level->setTileAndDataNoUpdate(TilePos(tp.x, b1, tp.z), Tile::leaves->m_ID, 1); + if ((abs(dx) != range || abs(dz) != range || range <= 0) && !Tile::solid[source->getTile(TilePos(tp.x, b1, tp.z))]) + source->setTileAndDataNoUpdate(TilePos(tp.x, b1, tp.z), FullTile(Tile::leaves->m_ID, 1)); } } @@ -95,9 +95,9 @@ bool PineFeature::place(Level* level, Random* random, const TilePos& pos) { int cy = yd + pos.y; - TileID tile = level->getTile(TilePos(pos.x, cy, pos.z)); + TileID tile = source->getTile(TilePos(pos.x, cy, pos.z)); if (tile == TILE_AIR || tile == Tile::leaves->m_ID) - level->setTileAndDataNoUpdate(TilePos(pos.x, cy, pos.z), Tile::treeTrunk->m_ID, 1); + source->setTileAndDataNoUpdate(TilePos(pos.x, cy, pos.z), FullTile(Tile::treeTrunk->m_ID, 1)); } return true; diff --git a/source/world/level/levelgen/feature/PumpkinFeature.cpp b/source/world/level/levelgen/feature/PumpkinFeature.cpp index 7e39bd3fb..8fc3da00a 100644 --- a/source/world/level/levelgen/feature/PumpkinFeature.cpp +++ b/source/world/level/levelgen/feature/PumpkinFeature.cpp @@ -1,7 +1,7 @@ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool PumpkinFeature::place(Level* level, Random* random, const TilePos& pos) +bool PumpkinFeature::place(TileSource* source, Random* random, const TilePos& pos) { TilePos actual; for (int var6 = 0; var6 < 64; ++var6) @@ -9,9 +9,9 @@ bool PumpkinFeature::place(Level* level, Random* random, const TilePos& pos) actual.x = pos.x + random->nextInt(8) - random->nextInt(8); actual.y = pos.y + random->nextInt(4) - random->nextInt(4); actual.z = pos.z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(actual) && level->getTile(actual.below()) == Tile::grass->m_ID && Tile::pumpkin->canSurvive(level, actual)) + if (source->isEmptyTile(actual) && source->getTile(actual.below()) == Tile::grass->m_ID && Tile::pumpkin->canSurvive(source, actual)) { - level->setTileAndDataNoUpdate(actual, Tile::pumpkin->m_ID, random->nextInt(4)); + source->setTileAndDataNoUpdate(actual, FullTile(Tile::pumpkin->m_ID, random->nextInt(4))); } } diff --git a/source/world/level/levelgen/feature/ReedsFeature.cpp b/source/world/level/levelgen/feature/ReedsFeature.cpp index 13d96e954..b3b2965ac 100644 --- a/source/world/level/levelgen/feature/ReedsFeature.cpp +++ b/source/world/level/levelgen/feature/ReedsFeature.cpp @@ -7,9 +7,9 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool ReedsFeature::place(Level* level, Random* random, const TilePos& pos) +bool ReedsFeature::place(TileSource* source, Random* random, const TilePos& pos) { TilePos tp(pos); @@ -18,20 +18,20 @@ bool ReedsFeature::place(Level* level, Random* random, const TilePos& pos) tp.x = pos.x + random->nextInt(4) - random->nextInt(4); tp.z = pos.z + random->nextInt(4) - random->nextInt(4); - if (!level->isEmptyTile(tp)) + if (!source->isEmptyTile(tp)) continue; - if (level->getMaterial(TilePos(tp.x - 1, tp.y - 1, tp.z)) == Material::water || - level->getMaterial(TilePos(tp.x + 1, tp.y - 1, tp.z)) == Material::water || - level->getMaterial(TilePos(tp.x, tp.y - 1, tp.z - 1)) == Material::water || - level->getMaterial(TilePos(tp.x, tp.y - 1, tp.z + 1)) == Material::water) + if (source->getMaterial(TilePos(tp.x - 1, tp.y - 1, tp.z)) == Material::water || + source->getMaterial(TilePos(tp.x + 1, tp.y - 1, tp.z)) == Material::water || + source->getMaterial(TilePos(tp.x, tp.y - 1, tp.z - 1)) == Material::water || + source->getMaterial(TilePos(tp.x, tp.y - 1, tp.z + 1)) == Material::water) { int height = random->nextInt(random->nextInt(3) + 1) + 2; for (int y1 = 0; y1 < height; y1++) { - if (Tile::reeds->canSurvive(level, TilePos(tp.x, tp.y + y1, tp.z))) + if (Tile::reeds->canSurvive(source, TilePos(tp.x, tp.y + y1, tp.z))) { - level->setTileNoUpdate(TilePos(tp.x, tp.y + y1, tp.z), Tile::reeds->m_ID); + source->setTileNoUpdate(TilePos(tp.x, tp.y + y1, tp.z), Tile::reeds->m_ID); } } } diff --git a/source/world/level/levelgen/feature/SpringFeature.cpp b/source/world/level/levelgen/feature/SpringFeature.cpp index 40090e0d0..a8dedde3b 100644 --- a/source/world/level/levelgen/feature/SpringFeature.cpp +++ b/source/world/level/levelgen/feature/SpringFeature.cpp @@ -7,44 +7,42 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" SpringFeature::SpringFeature(TileID id) { m_ID = id; } -bool SpringFeature::place(Level* level, Random* random, const TilePos& pos) +bool SpringFeature::place(TileSource* source, Random* random, const TilePos& pos) { - if (level->getTile(pos.above()) != Tile::rock->m_ID) + if (source->getTile(pos.above()) != Tile::rock->m_ID) return false; - if (level->getTile(pos.below()) != Tile::rock->m_ID) + if (source->getTile(pos.below()) != Tile::rock->m_ID) return false; - if (level->getTile(pos) && level->getTile(pos) != Tile::rock->m_ID) + if (source->getTile(pos) && source->getTile(pos) != Tile::rock->m_ID) return false; int nRockTiles = 0; int nEmptyTiles = 0; - if (level->getTile(pos.west()) == Tile::rock->m_ID) nRockTiles++; - if (level->getTile(pos.east()) == Tile::rock->m_ID) nRockTiles++; - if (level->getTile(pos.north()) == Tile::rock->m_ID) nRockTiles++; - if (level->getTile(pos.south()) == Tile::rock->m_ID) nRockTiles++; + if (source->getTile(pos.west()) == Tile::rock->m_ID) nRockTiles++; + if (source->getTile(pos.east()) == Tile::rock->m_ID) nRockTiles++; + if (source->getTile(pos.north()) == Tile::rock->m_ID) nRockTiles++; + if (source->getTile(pos.south()) == Tile::rock->m_ID) nRockTiles++; - if (level->isEmptyTile(pos.west())) nEmptyTiles++; - if (level->isEmptyTile(pos.east())) nEmptyTiles++; - if (level->isEmptyTile(pos.north())) nEmptyTiles++; - if (level->isEmptyTile(pos.south())) nEmptyTiles++; + if (source->isEmptyTile(pos.west())) nEmptyTiles++; + if (source->isEmptyTile(pos.east())) nEmptyTiles++; + if (source->isEmptyTile(pos.north())) nEmptyTiles++; + if (source->isEmptyTile(pos.south())) nEmptyTiles++; if (nEmptyTiles != 1) return true; if (nRockTiles != 3) return true; - level->setTile(pos, m_ID); + source->setTile(pos, m_ID); - level->m_bInstantTicking = true; - Tile::tiles[m_ID]->tick(level, pos, random); - level->m_bInstantTicking = false; + Tile::tiles[m_ID]->tick(source, pos, random); return true; } diff --git a/source/world/level/levelgen/feature/SpruceFeature.cpp b/source/world/level/levelgen/feature/SpruceFeature.cpp index 56bce2e8a..b899dcbb2 100644 --- a/source/world/level/levelgen/feature/SpruceFeature.cpp +++ b/source/world/level/levelgen/feature/SpruceFeature.cpp @@ -7,9 +7,9 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool SpruceFeature::place(Level* level, Random* random, const TilePos& pos) +bool SpruceFeature::place(TileSource* source, Random* random, const TilePos& pos) { if (pos.y <= C_MIN_Y) return false; @@ -39,7 +39,7 @@ bool SpruceFeature::place(Level* level, Random* random, const TilePos& pos) break; } - TileID tile = level->getTile(TilePos(cx, cy, cz)); + TileID tile = source->getTile(TilePos(cx, cy, cz)); if (tile != TILE_AIR && tile != Tile::leaves->m_ID) bCanPlace = false; } @@ -49,14 +49,14 @@ bool SpruceFeature::place(Level* level, Random* random, const TilePos& pos) if (!bCanPlace) return false; - TileID tileBelow = level->getTile(pos.below()); + TileID tileBelow = source->getTile(pos.below()); if (tileBelow != Tile::grass->m_ID && tileBelow != Tile::dirt->m_ID) return false; if (pos.y >= C_MAX_Y - 1 - height) return false; - level->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); + source->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); int range = random->nextInt(2); int b2 = 1, b3 = 0; @@ -71,8 +71,8 @@ bool SpruceFeature::place(Level* level, Random* random, const TilePos& pos) for (tp.z = pos.z - range; tp.z <= pos.z + range; tp.z++) { int dz = tp.z - pos.z; - if ((abs(dx) != range || abs(dz) != range || range <= 0) && !Tile::solid[level->getTile(TilePos(tp.x, b1, tp.z))]) - level->setTileAndDataNoUpdate(TilePos(tp.x, b1, tp.z), Tile::leaves->m_ID, 1); + if ((abs(dx) != range || abs(dz) != range || range <= 0) && !Tile::solid[source->getTile(TilePos(tp.x, b1, tp.z))]) + source->setTileAndDataNoUpdate(TilePos(tp.x, b1, tp.z), FullTile(Tile::leaves->m_ID, 1)); } } @@ -95,9 +95,9 @@ bool SpruceFeature::place(Level* level, Random* random, const TilePos& pos) { int cy = yd + pos.y; - TileID tile = level->getTile(TilePos(pos.x, cy, pos.z)); + TileID tile = source->getTile(TilePos(pos.x, cy, pos.z)); if (tile == TILE_AIR || tile == Tile::leaves->m_ID) - level->setTileAndDataNoUpdate(TilePos(pos.x, cy, pos.z), Tile::treeTrunk->m_ID, 1); + source->setTileAndDataNoUpdate(TilePos(pos.x, cy, pos.z), FullTile(Tile::treeTrunk->m_ID, 1)); } return true; diff --git a/source/world/level/levelgen/feature/TreeFeature.cpp b/source/world/level/levelgen/feature/TreeFeature.cpp index 731bd2b39..6730adb83 100644 --- a/source/world/level/levelgen/feature/TreeFeature.cpp +++ b/source/world/level/levelgen/feature/TreeFeature.cpp @@ -7,9 +7,9 @@ ********************************************************************/ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -bool TreeFeature::place(Level* level, Random* random, const TilePos& pos) +bool TreeFeature::place(TileSource* source, Random* random, const TilePos& pos) { if (pos.y <= C_MIN_Y) return false; @@ -40,7 +40,7 @@ bool TreeFeature::place(Level* level, Random* random, const TilePos& pos) break; } - TileID tile = level->getTile(tp); + TileID tile = source->getTile(tp); // other trees can overlap with this one, apparently if (tile != TILE_AIR && tile != Tile::leaves->m_ID) @@ -56,7 +56,7 @@ bool TreeFeature::place(Level* level, Random* random, const TilePos& pos) if (!bCanPlace) return false; - TileID tileBelow = level->getTile(pos.below()); + TileID tileBelow = source->getTile(pos.below()); // If grass or dirt aren't below us, we can't possibly grow! if (tileBelow != Tile::grass->m_ID && tileBelow != Tile::dirt->m_ID) @@ -66,7 +66,7 @@ bool TreeFeature::place(Level* level, Random* random, const TilePos& pos) if (pos.y >= C_MAX_Y - treeHeight) return false; - level->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); + source->setTileNoUpdate(pos.below(), Tile::dirt->m_ID); int upperY = pos.y + treeHeight; int lowerY = pos.y + treeHeight - 3; @@ -87,9 +87,9 @@ bool TreeFeature::place(Level* level, Random* random, const TilePos& pos) for (tp.z = pos.z - c1; tp.z <= pos.z + c1; tp.z++, c4++) { - if ((abs(tp.x - pos.x) != c1 || abs(tp.z - pos.z) != c1 || (random->nextInt(2) != 0 && diff != 0)) && !Tile::solid[level->getTile(tp)]) + if ((abs(tp.x - pos.x) != c1 || abs(tp.z - pos.z) != c1 || (random->nextInt(2) != 0 && diff != 0)) && !Tile::solid[source->getTile(tp)]) { - level->setTileNoUpdate(tp, Tile::leaves->m_ID); + source->setTileNoUpdate(tp, Tile::leaves->m_ID); } } } @@ -99,11 +99,11 @@ bool TreeFeature::place(Level* level, Random* random, const TilePos& pos) { TilePos t(pos); t.y += y; - TileID tile = level->getTile(t); + TileID tile = source->getTile(t); if (tile && tile != Tile::leaves->m_ID) continue; - level->setTileNoUpdate(t, Tile::treeTrunk->m_ID); + source->setTileNoUpdate(t, Tile::treeTrunk->m_ID); } return true; diff --git a/source/world/level/levelgen/feature/VegetationFeature.cpp b/source/world/level/levelgen/feature/VegetationFeature.cpp index 29ac36085..5a07f26d6 100644 --- a/source/world/level/levelgen/feature/VegetationFeature.cpp +++ b/source/world/level/levelgen/feature/VegetationFeature.cpp @@ -1,5 +1,5 @@ #include "Feature.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" VegetationFeature::VegetationFeature(TileID id, TileData data, int count) { @@ -8,24 +8,23 @@ VegetationFeature::VegetationFeature(TileID id, TileData data, int count) m_count = count; } -bool VegetationFeature::place(Level* level, Random* random, const TilePos& pos) +bool VegetationFeature::place(TileSource* source, Random* random, const TilePos& pos) { TilePos bPos(pos); TilePos tp; while (true) { - int var11 = level->getTile(bPos); - if ((var11 != 0 && var11 != Tile::leaves->m_ID) || bPos.y <= 0) + TileID currentTile = source->getTile(bPos); + if ((currentTile != TILE_AIR && currentTile != Tile::leaves->m_ID) || bPos.y <= 0) { for (int var7 = 0; var7 < m_count; ++var7) { tp.x = bPos.x + random->nextInt(8) - random->nextInt(8); tp.y = bPos.y + random->nextInt(4) - random->nextInt(4); tp.z = bPos.z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(tp) && Tile::tiles[m_ID]->canSurvive(level, tp)) + if (source->isEmptyTile(tp) && Tile::tiles[m_ID]->canSurvive(source, tp)) { - if (m_data) level->setTileAndDataNoUpdate(tp, m_ID, m_data); - else level->setTileNoUpdate(tp, m_ID); + source->setTileAndDataNoUpdate(tp, FullTile(m_ID, m_data)); } } diff --git a/source/world/level/path/PathFinder.cpp b/source/world/level/path/PathFinder.cpp index dd8e53553..11cdcb7d8 100644 --- a/source/world/level/path/PathFinder.cpp +++ b/source/world/level/path/PathFinder.cpp @@ -9,6 +9,7 @@ #include "world/level/Level.hpp" #include "world/tile/DoorTile.hpp" #include "world/entity/Entity.hpp" +#include "world/level/TileSource.hpp" static int dword_1CD868; static int dword_1CD870; @@ -25,7 +26,6 @@ CONSTEXPR int MakeNodeHash(const TilePos& pos) PathFinder::PathFinder() { - m_pLevel = nullptr; m_nodeCount = 0; m_bEntityIsDoorBreaker = false; } @@ -42,6 +42,8 @@ PathFinder::~PathFinder() // @TODO: return NodeType int PathFinder::isFree(Entity* pEntity, const TilePos& pos, const Node* node) { + TileSource& source = pEntity->getTileSource(); + TilePos tp(pos); for (tp.x = pos.x; tp.x < pos.x + node->tilePos.x; tp.x++) @@ -50,7 +52,7 @@ int PathFinder::isFree(Entity* pEntity, const TilePos& pos, const Node* node) { for (tp.z = pos.z; tp.z < pos.z + node->tilePos.z; tp.z++) { - TileID id = m_pLevel->getTile(tp); + TileID id = source.getTile(tp); if (id <= 0) continue; @@ -58,7 +60,7 @@ int PathFinder::isFree(Entity* pEntity, const TilePos& pos, const Node* node) { if (id != Tile::door_wood->m_ID || !m_bEntityIsDoorBreaker) { - if (!DoorTile::isOpen(m_pLevel->getData(tp))) + if (!DoorTile::isOpen(source.getData(tp))) return 0; // 4 on 0.2.1 } @@ -260,6 +262,8 @@ bool PathFinder::findPath(Path& path, Entity* pEntity, const Vec3& pos, float d) m_nodeCount = 0; // not treating spillover btw? or what + TileSource& source = pEntity->getTileSource(); + Node* node1 = getNode(pEntity->m_hitbox.min); TilePos tp(pos.x - (pEntity->m_bbWidth / 2), @@ -268,14 +272,14 @@ bool PathFinder::findPath(Path& path, Entity* pEntity, const Vec3& pos, float d) Node* node2 = nullptr; // Not present in b1.2_02 - if (!m_pLevel->getTile(tp.below())) + if (!source.getTile(tp.below())) { TilePos tp2(tp), tp3(pos + (0.5f * pEntity->m_bbWidth)); for (tp2.x = tp.x; tp2.x <= tp3.x; tp2.x++) { for (tp2.z = tp.z; tp2.z <= tp3.y; tp2.z++) { - if (m_pLevel->getTile(TilePos(tp2.x, tp2.y - 1, tp2.z))) + if (source.getTile(TilePos(tp2.x, tp2.y - 1, tp2.z))) { node2 = getNode(tp2); break; // breaking out of the tp2.z loop only. Intended to break out of tp2.x too? diff --git a/source/world/level/path/PathFinder.hpp b/source/world/level/path/PathFinder.hpp index d41f85b1a..f6a45772c 100644 --- a/source/world/level/path/PathFinder.hpp +++ b/source/world/level/path/PathFinder.hpp @@ -13,7 +13,7 @@ #include "BinaryHeap.hpp" #include "world/level/TilePos.hpp" -class LevelSource; +class TileSource; class Entity; #define MAX_NODE_COUNT (2048) @@ -36,17 +36,11 @@ class PathFinder bool findPath(Path&, Entity*, const Entity*, float); bool findPath(Path&, Entity*, const TilePos& tilePos, float); - void setLevel(LevelSource* pLevel) - { - m_pLevel = pLevel; - } - private: Node* new_Node(const TilePos& pos); bool reconstructPath(Path& path, Node* node2); private: - LevelSource* m_pLevel; BinaryHeap m_binaryHeap; NodeMap m_nodeMap; Node m_nodeReserve[MAX_NODE_COUNT]; diff --git a/source/world/level/storage/ExternalFileLevelStorage.cpp b/source/world/level/storage/ExternalFileLevelStorage.cpp index 18b1e297c..aa47e88aa 100644 --- a/source/world/level/storage/ExternalFileLevelStorage.cpp +++ b/source/world/level/storage/ExternalFileLevelStorage.cpp @@ -164,7 +164,7 @@ void ExternalFileLevelStorage::tick() { for (cp.x = 0; cp.x < C_MAX_CHUNKS_X; cp.x++) { - LevelChunk* pChunk = m_pLevel->getChunk(cp); + LevelChunk* pChunk = m_pLevel->getDimension(DIMENSION_OVERWORLD)->getChunkSource()->getAvailableChunkAt(cp); if (!pChunk || !pChunk->m_bUnsaved) continue; @@ -240,13 +240,13 @@ LevelChunk* ExternalFileLevelStorage::load(Level* level, const ChunkPos& pos) TileID* pData = new TileID[16 * 16 * 128]; pBitStream->Read((char*)pData, 16 * 16 * 128 * sizeof(TileID)); - LevelChunk* pChunk = new LevelChunk(level, pData, pos); - pBitStream->Read((char*)pChunk->m_tileData.m_data, 16 * 16 * 128 / 2); + LevelChunk* pChunk = new LevelChunk(*level, *level->getDimension(DIMENSION_OVERWORLD), pos); + pBitStream->Read((char*)pChunk->getTiles(), 16 * 16 * 128 / 2); if (m_storageVersion >= 1) { - pBitStream->Read((char*)pChunk->m_lightSky.m_data, 16 * 16 * 128 / 2); - pBitStream->Read((char*)pChunk->m_lightBlk.m_data, 16 * 16 * 128 / 2); + pBitStream->Read((char*)pChunk->getLight(LightLayer::Sky).m_array, 16 * 16 * 128 / 2); + pBitStream->Read((char*)pChunk->getLight(LightLayer::Block).m_array, 16 * 16 * 128 / 2); } pBitStream->Read((char*)pChunk->m_updateMap, sizeof pChunk->m_updateMap); @@ -323,6 +323,8 @@ void ExternalFileLevelStorage::loadEntities(Level* level, LevelChunk* chunk) const ListTag* entitiesTag = tag->getList("Entities"); if (entitiesTag) { + TileSource& tileSource = *level->getDimension(DIMENSION_OVERWORLD)->getTileSource(); + const std::vector& entities = entitiesTag->rawView(); for (std::vector::const_iterator it = entities.begin(); it != entities.end(); it++) { @@ -330,7 +332,7 @@ void ExternalFileLevelStorage::loadEntities(Level* level, LevelChunk* chunk) if (!betterTag || betterTag->getId() != Tag::TAG_TYPE_COMPOUND) continue; - Entity* entity = EntityFactory::LoadEntity(*(CompoundTag*)betterTag, level); + Entity* entity = EntityFactory::LoadEntity(*(CompoundTag*)betterTag, tileSource); if (entity) level->addEntity(entity); } @@ -358,23 +360,23 @@ void ExternalFileLevelStorage::save(Level* level, LevelChunk* chunk) SAFE_DELETE(m_pRegionFile); m_pRegionFile = nullptr; - LOG_W("Not saving :( (x: %d z: %d)", chunk->m_chunkPos.x, chunk->m_chunkPos.z); + LOG_W("Not saving :( (x: %d z: %d)", chunk->getPos().x, chunk->getPos().z); return; } RakNet::BitStream bs; - bs.Write((const char*)chunk->m_pBlockData, 16 * 16 * 128 * sizeof(TileID)); - bs.Write((const char*)chunk->m_tileData.m_data, chunk->m_tileData.m_size); + bs.Write((const char*)chunk->getTiles(), 16 * 16 * 128 * sizeof(TileID)); + bs.Write((const char*)chunk->getTileData().m_array, chunk->getTileData().getSize()); if (m_pLevelData->getStorageVersion() >= 1) { - bs.Write((const char*)chunk->m_lightSky.m_data, chunk->m_lightSky.m_size); - bs.Write((const char*)chunk->m_lightBlk.m_data, chunk->m_lightBlk.m_size); + bs.Write((const char*)chunk->getLight(LightLayer::Sky).m_array, chunk->getLight(LightLayer::Sky).getSize()); + bs.Write((const char*)chunk->getLight(LightLayer::Block).m_array, chunk->getLight(LightLayer::Block).getSize()); } bs.Write((const char*)chunk->m_updateMap, sizeof chunk->m_updateMap); - m_pRegionFile->writeChunk(chunk->m_chunkPos, bs); + m_pRegionFile->writeChunk(chunk->getPos(), bs); } void ExternalFileLevelStorage::saveEntities(Level* level, LevelChunk* chunk) @@ -383,16 +385,20 @@ void ExternalFileLevelStorage::saveEntities(Level* level, LevelChunk* chunk) //getTimeS(); ListTag* entitiesTag = new ListTag(); - const EntityVector* entities = level->getAllEntities(); - for (EntityVector::const_iterator it = entities->begin(); it != entities->end(); it++) + for (Level::DimensionVector::iterator it = level->m_dimensions.begin(); it != level->m_dimensions.end(); it++) { - const Entity* entity = *it; - CompoundTag* tag = new CompoundTag(); + Dimension& dimension = **it; + const Dimension::EntityIdMap_t& entityIdMap = dimension.getEntityIdMap(); + for (Dimension::EntityIdMap_t::const_iterator it = entityIdMap.begin(); it != entityIdMap.end(); it++) + { + const Entity* entity = it->second; + CompoundTag* tag = new CompoundTag(); - if (!entity->save(*tag)) - continue; + if (!entity->save(*tag)) + continue; - entitiesTag->add(tag); + entitiesTag->add(tag); + } } CompoundTag tag = CompoundTag(); diff --git a/source/world/level/storage/LevelData.cpp b/source/world/level/storage/LevelData.cpp index b79b591e5..96a09b50c 100644 --- a/source/world/level/storage/LevelData.cpp +++ b/source/world/level/storage/LevelData.cpp @@ -144,9 +144,20 @@ void LevelData::loadTagData(CompoundTag& tag) setSeed(tag.getInt64("RandomSeed")); setGameType((GameType)tag.getInt32("GameType")); - setXSpawn(tag.getInt32("SpawnX")); - setYSpawn(tag.getInt32("SpawnY")); - setZSpawn(tag.getInt32("SpawnZ")); + m_spawnPos.x = tag.getInt32("SpawnX"); + m_spawnPos.y = tag.getInt32("SpawnY"); + m_spawnPos.z = tag.getInt32("SpawnZ"); + + if (tag.contains("LimitedWorldOriginX")) + { + m_limitedWorldOrigin.x = tag.getInt32("LimitedWorldOriginX"); + m_limitedWorldOrigin.y = tag.getInt32("LimitedWorldOriginY"); + m_limitedWorldOrigin.z = tag.getInt32("LimitedWorldOriginZ"); + } + else + { + m_limitedWorldOrigin = TilePos(128, 64, 128); + } setTime(tag.getInt64("Time")); _setLastPlayed(tag.getInt64("LastPlayed")); @@ -172,9 +183,9 @@ void LevelData::writeTagData(CompoundTag& levelTag, CompoundTag* playerTag) cons tag.putInt64("RandomSeed", getSeed()); tag.putInt32("GameType", getGameType()); - tag.putInt32("SpawnX", getXSpawn()); - tag.putInt32("SpawnY", getYSpawn()); - tag.putInt32("SpawnZ", getZSpawn()); + tag.putInt32("SpawnX", m_spawnPos.x); + tag.putInt32("SpawnY", m_spawnPos.y); + tag.putInt32("SpawnZ", m_spawnPos.z); tag.putInt64("Time", getTime()); tag.putInt64("SizeOnDisk", getSizeOnDisk()); diff --git a/source/world/level/storage/LevelData.hpp b/source/world/level/storage/LevelData.hpp index 4b45f625f..d07c8970f 100644 --- a/source/world/level/storage/LevelData.hpp +++ b/source/world/level/storage/LevelData.hpp @@ -12,6 +12,7 @@ #include "BitStream.h" #include "world/phys/Vec3.hpp" #include "world/item/Inventory.hpp" +#include "world/level/Tick.hpp" #define LEVEL_STORAGE_VERSION_DEFAULT 2 @@ -76,22 +77,21 @@ struct LevelData int32_t getSeed() const { return m_seed; } void setSeed(int32_t seed) { m_seed = seed; } - int getXSpawn() const { return m_spawnPos.x; } - void setXSpawn(int xSpawn) { m_spawnPos.x = xSpawn; } - int getYSpawn() const { return m_spawnPos.y; } - void setYSpawn(int ySpawn) { m_spawnPos.y = ySpawn; } - int getZSpawn() const { return m_spawnPos.z; } - void setZSpawn(int zSpawn) { m_spawnPos.z = zSpawn; } - const TilePos& getSpawn() const { return m_spawnPos; } void setSpawn(const TilePos& pos) { m_spawnPos = pos; } + const TilePos& getLimitedWorldOrigin() const { return m_limitedWorldOrigin; } + void setLimitedWorldOrigin(const TilePos& pos) { m_limitedWorldOrigin = pos; } + int32_t getTime() const { return m_time; } void setTime(int32_t time) { m_time = time; } int32_t getSizeOnDisk() const { return m_sizeOnDisk; } void setSizeOnDisk(int32_t sizeOnDisk) { m_sizeOnDisk = sizeOnDisk; } + Tick_t getCurrentTick() const { return m_currentTick; } + void incrementCurrentTick() { m_currentTick++; } + const CompoundTag* getLoadedPlayerTag() const { return m_playerTag; } void setLoadedPlayerTag(CompoundTag* playerTag); void setPlayerTag(const CompoundTag* playerTag); @@ -123,9 +123,11 @@ struct LevelData std::string m_levelName; int32_t m_seed; TilePos m_spawnPos; + TilePos m_limitedWorldOrigin; int32_t m_time; int32_t m_lastPlayed; int32_t m_sizeOnDisk; + Tick_t m_currentTick; CompoundTag* m_playerTag; int m_dimensionId; GameType m_gameType; diff --git a/source/world/level/storage/LevelSource.cpp b/source/world/level/storage/LevelSource.cpp deleted file mode 100644 index 9eb5ca12c..000000000 --- a/source/world/level/storage/LevelSource.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#include "LevelSource.hpp" - -LevelSource::~LevelSource() -{ -} diff --git a/source/world/level/storage/LevelSource.hpp b/source/world/level/storage/LevelSource.hpp deleted file mode 100644 index 97cc026b2..000000000 --- a/source/world/level/storage/LevelSource.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/******************************************************************** - Minecraft: Pocket Edition - Decompilation Project - Copyright (C) 2023 iProgramInCpp - - The following code is licensed under the BSD 1 clause license. - SPDX-License-Identifier: BSD-1-Clause - ********************************************************************/ - -#pragma once - -#include "common/Utils.hpp" -#include "world/level/Material.hpp" -#include "world/level/levelgen/biome/BiomeSource.hpp" - -class LevelSource -{ -public: - virtual ~LevelSource(); - virtual TileID getTile(const TilePos& pos) const = 0; - virtual float getBrightness(const TilePos& pos) const = 0; - virtual TileData getData(const TilePos& pos) const = 0; - virtual Material* getMaterial(const TilePos& pos) const = 0; - virtual bool isSolidTile(const TilePos& pos) const = 0; - virtual BiomeSource* getBiomeSource() const = 0; -}; - diff --git a/source/world/particle/BubbleParticle.cpp b/source/world/particle/BubbleParticle.cpp index 96642b64a..e39515327 100644 --- a/source/world/particle/BubbleParticle.cpp +++ b/source/world/particle/BubbleParticle.cpp @@ -8,9 +8,10 @@ #include "Particle.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" -BubbleParticle::BubbleParticle(Level* level, const Vec3& pos, const Vec3& dir) : - Particle(level, pos, dir) +BubbleParticle::BubbleParticle(TileSource& source, const Vec3& pos, const Vec3& dir) : + Particle(source, pos, dir) { m_rCol = m_gCol = m_bCol = 1.0f; m_tex = PTI_BUBBLE; @@ -32,7 +33,7 @@ void BubbleParticle::tick() m_vel *= 0.85f; - if (m_pLevel->getMaterial(m_pos) != Material::water) + if (m_tileSource->getMaterial(m_pos) != Material::water) remove(); m_lifetime--; diff --git a/source/world/particle/ExplodeParticle.cpp b/source/world/particle/ExplodeParticle.cpp index daef2b0e7..e4a46e29c 100644 --- a/source/world/particle/ExplodeParticle.cpp +++ b/source/world/particle/ExplodeParticle.cpp @@ -8,8 +8,8 @@ #include "Particle.hpp" -ExplodeParticle::ExplodeParticle(Level* level, const Vec3& pos, const Vec3& dir) : - Particle(level, pos, dir) +ExplodeParticle::ExplodeParticle(TileSource& source, const Vec3& pos, const Vec3& dir) : + Particle(source, pos, dir) { m_vel.x = dir.x + 0.05f * (2.0f * Mth::random() - 1.0f); m_vel.y = dir.y + 0.05f * (2.0f * Mth::random() - 1.0f); diff --git a/source/world/particle/FlameParticle.cpp b/source/world/particle/FlameParticle.cpp index 5b7428dcd..afe442d63 100644 --- a/source/world/particle/FlameParticle.cpp +++ b/source/world/particle/FlameParticle.cpp @@ -8,8 +8,8 @@ #include "Particle.hpp" -FlameParticle::FlameParticle(Level* level, const Vec3& pos, const Vec3& dir) : - Particle(level, pos, dir) +FlameParticle::FlameParticle(TileSource& source, const Vec3& pos, const Vec3& dir) : + Particle(source, pos, dir) { m_oSize = 0.0f; diff --git a/source/world/particle/LavaParticle.cpp b/source/world/particle/LavaParticle.cpp index 8a29fbf0d..493ae7059 100644 --- a/source/world/particle/LavaParticle.cpp +++ b/source/world/particle/LavaParticle.cpp @@ -9,8 +9,8 @@ #include "Particle.hpp" #include "world/level/Level.hpp" -LavaParticle::LavaParticle(Level* level, const Vec3& pos) : - Particle(level, pos, Vec3::ZERO) +LavaParticle::LavaParticle(TileSource& source, const Vec3& pos) : + Particle(source, pos, Vec3::ZERO) { m_oSize = 0.0f; diff --git a/source/world/particle/Particle.cpp b/source/world/particle/Particle.cpp index 07118b116..7c05c5b80 100644 --- a/source/world/particle/Particle.cpp +++ b/source/world/particle/Particle.cpp @@ -26,7 +26,7 @@ void Particle::_init() m_bMakeStepSound = false; } -Particle::Particle(Level* level, const Vec3& pos, const Vec3& dir) : Entity(level) +Particle::Particle(TileSource& source, const Vec3& pos, const Vec3& dir) : Entity(source) { _init(); diff --git a/source/world/particle/Particle.hpp b/source/world/particle/Particle.hpp index 0f9996e7d..d9f3a020d 100644 --- a/source/world/particle/Particle.hpp +++ b/source/world/particle/Particle.hpp @@ -32,7 +32,7 @@ class Particle : public Entity void _init(); public: Particle() { _init(); } - Particle(Level*, const Vec3& pos, const Vec3& dir); + Particle(TileSource& source, const Vec3& pos, const Vec3& dir); virtual void render(Tesselator& t, float f, float xa, float ya, float za, float xa2, float za2); virtual int getParticleTexture(); @@ -65,8 +65,8 @@ class TerrainParticle : public Particle private: void _init(Tile* tile); public: - TerrainParticle(Level*, const Vec3& pos, Tile*); - TerrainParticle(Level*, const Vec3& pos, const Vec3& dir, Tile*); + TerrainParticle(TileSource& source, const Vec3& pos, Tile*); + TerrainParticle(TileSource& source, const Vec3& pos, const Vec3& dir, Tile*); void render(Tesselator&, float, float, float, float, float, float) override; int getParticleTexture() override; @@ -79,14 +79,14 @@ class TerrainParticle : public Particle class BubbleParticle : public Particle { public: - BubbleParticle(Level*, const Vec3& pos, const Vec3& dir); + BubbleParticle(TileSource& source, const Vec3& pos, const Vec3& dir); void tick() override; }; class SmokeParticle : public Particle { public: - SmokeParticle(Level*, const Vec3& pos, const Vec3& dir, float a9); + SmokeParticle(TileSource& source, const Vec3& pos, const Vec3& dir, float a9); void tick() override; void render(Tesselator&, float, float, float, float, float, float) override; @@ -97,7 +97,7 @@ class SmokeParticle : public Particle class RedDustParticle : public Particle { public: - RedDustParticle(Level*, const Vec3& pos, const Vec3& dir); + RedDustParticle(TileSource& source, const Vec3& pos, const Vec3& dir); void tick() override; void render(Tesselator&, float, float, float, float, float, float) override; @@ -108,14 +108,14 @@ class RedDustParticle : public Particle class ExplodeParticle : public Particle { public: - ExplodeParticle(Level*, const Vec3& pos, const Vec3& dir); + ExplodeParticle(TileSource& source, const Vec3& pos, const Vec3& dir); void tick() override; }; class FlameParticle : public Particle { public: - FlameParticle(Level*, const Vec3& pos, const Vec3& dir); + FlameParticle(TileSource& source, const Vec3& pos, const Vec3& dir); void tick() override; void render(Tesselator&, float, float, float, float, float, float) override; float getBrightness(float f) const override; @@ -127,7 +127,7 @@ class FlameParticle : public Particle class LavaParticle : public Particle { public: - LavaParticle(Level*, const Vec3& pos); + LavaParticle(TileSource& source, const Vec3& pos); void tick() override; void render(Tesselator&, float, float, float, float, float, float) override; float getBrightness(float f) const override; diff --git a/source/world/particle/ParticleEngine.cpp b/source/world/particle/ParticleEngine.cpp index c10e18fdc..eb5e10c09 100644 --- a/source/world/particle/ParticleEngine.cpp +++ b/source/world/particle/ParticleEngine.cpp @@ -9,6 +9,7 @@ #include #include "ParticleEngine.hpp" #include "client/renderer/renderer/RenderMaterialGroup.hpp" +#include "world/level/TileSource.hpp" ParticleEngine::Materials::Materials() { @@ -60,9 +61,11 @@ std::string ParticleEngine::countParticles() return ss.str(); } -void ParticleEngine::crack(const TilePos& tilePos, Facing::Name face) +void ParticleEngine::crack(Entity* entity, const TilePos& tilePos, Facing::Name face) { - TileID tileID = m_pLevel->getTile(tilePos); + TileSource& source = entity->getTileSource(); + + TileID tileID = source.getTile(tilePos); if (!tileID) return; Tile* pTile = Tile::tiles[tileID]; @@ -106,12 +109,14 @@ void ParticleEngine::crack(const TilePos& tilePos, Facing::Name face) break; } - add((new TerrainParticle(m_pLevel, pos, pTile))->init(tilePos, face)->setPower(0.2f)->scale(0.6f)); + add((new TerrainParticle(source, pos, pTile))->init(tilePos, face)->setPower(0.2f)->scale(0.6f)); } -void ParticleEngine::destroyEffect(const TilePos& pos) +void ParticleEngine::destroyEffect(Entity* entity, const TilePos& pos) { - TileID tileID = m_pLevel->getTile(pos); + TileSource& source = entity->getTileSource(); + + TileID tileID = source.getTile(pos); if (!tileID) return; float timeS = getTimeS(); @@ -131,7 +136,7 @@ void ParticleEngine::destroyEffect(const TilePos& pos) vec1.y - float(pos.y) - 0.5f, vec1.z - float(pos.z) - 0.5f); - add((new TerrainParticle(m_pLevel, vec1, vec2, pTile))->init(pos)); + add((new TerrainParticle(source, vec1, vec2, pTile))->init(pos)); } } } diff --git a/source/world/particle/ParticleEngine.hpp b/source/world/particle/ParticleEngine.hpp index 3ca4a0515..c114669dd 100644 --- a/source/world/particle/ParticleEngine.hpp +++ b/source/world/particle/ParticleEngine.hpp @@ -29,8 +29,8 @@ class ParticleEngine void add(Particle*); std::string countParticles(); - void crack(const TilePos& tilePos, Facing::Name face); - void destroyEffect(const TilePos& pos); + void crack(Entity* entity, const TilePos& tilePos, Facing::Name face); + void destroyEffect(Entity* entity, const TilePos& pos); void render(const Entity& camera, float f); void renderLit(const Entity& camera, float a); void tick(); diff --git a/source/world/particle/RedDustParticle.cpp b/source/world/particle/RedDustParticle.cpp index 076b32019..de3f9eeff 100644 --- a/source/world/particle/RedDustParticle.cpp +++ b/source/world/particle/RedDustParticle.cpp @@ -8,8 +8,8 @@ #include "Particle.hpp" -RedDustParticle::RedDustParticle(Level* level, const Vec3& pos, const Vec3& dir) : - Particle(level, pos, Vec3::ZERO) +RedDustParticle::RedDustParticle(TileSource& source, const Vec3& pos, const Vec3& dir) : + Particle(source, pos, Vec3::ZERO) { m_oSize = 0.0f; diff --git a/source/world/particle/SmokeParticle.cpp b/source/world/particle/SmokeParticle.cpp index cb058b633..c534e5f81 100644 --- a/source/world/particle/SmokeParticle.cpp +++ b/source/world/particle/SmokeParticle.cpp @@ -8,8 +8,8 @@ #include "Particle.hpp" -SmokeParticle::SmokeParticle(Level* level, const Vec3& pos, const Vec3& dir, float a9) : - Particle(level, pos, Vec3::ZERO) +SmokeParticle::SmokeParticle(TileSource& source, const Vec3& pos, const Vec3& dir, float a9) : + Particle(source, pos, Vec3::ZERO) { m_oSize = 0.0f; diff --git a/source/world/particle/TerrainParticle.cpp b/source/world/particle/TerrainParticle.cpp index 5acfe2561..508838051 100644 --- a/source/world/particle/TerrainParticle.cpp +++ b/source/world/particle/TerrainParticle.cpp @@ -18,14 +18,14 @@ void TerrainParticle::_init(Tile* tile) m_size *= 0.5f; } -TerrainParticle::TerrainParticle(Level* level, const Vec3& pos, Tile* tile) : - Particle(level, pos, Vec3::ZERO) +TerrainParticle::TerrainParticle(TileSource& source, const Vec3& pos, Tile* tile) : + Particle(source, pos, Vec3::ZERO) { _init(tile); } -TerrainParticle::TerrainParticle(Level* level, const Vec3& pos, const Vec3& dir, Tile* tile) : - Particle(level, pos, dir) +TerrainParticle::TerrainParticle(TileSource& source, const Vec3& pos, const Vec3& dir, Tile* tile) : + Particle(source, pos, dir) { _init(tile); } @@ -36,12 +36,12 @@ TerrainParticle* TerrainParticle::init(const TilePos& tilePos, Facing::Name face face = Facing::DOWN; #endif - m_tex = m_pTile->getTexture(m_pLevel, tilePos, face); + m_tex = m_pTile->getTexture(m_tileSource, tilePos, face); if (m_pTile == Tile::grass && face != Facing::UP) return this; - int color = m_pTile->getColor(m_pLevel, tilePos); + int color = m_pTile->getColor(m_tileSource, tilePos); m_rCol *= float(GET_RED(color)) / 255.0f; m_gCol *= float(GET_GREEN(color)) / 255.0f; m_bCol *= float(GET_BLUE(color)) / 255.0f; diff --git a/source/world/phys/AABB.hpp b/source/world/phys/AABB.hpp index b0dc12a58..f7ce6cdf0 100644 --- a/source/world/phys/AABB.hpp +++ b/source/world/phys/AABB.hpp @@ -18,6 +18,7 @@ class AABB AABB(); AABB(Vec3 min, Vec3 max); + AABB(Vec3, float); // TODO!!! AABB(float minX, float minY, float minZ, float maxX, float maxY, float maxZ); public: diff --git a/source/world/phys/Vec3Int32.hpp b/source/world/phys/Vec3Int32.hpp new file mode 100644 index 000000000..aaf0f6782 --- /dev/null +++ b/source/world/phys/Vec3Int32.hpp @@ -0,0 +1,155 @@ +/******************************************************************** + Minecraft: Pocket Edition - Decompilation Project + Copyright (C) 2023 iProgramInCpp + + The following code is licensed under the BSD 1 clause license. + SPDX-License-Identifier: BSD-1-Clause + ********************************************************************/ + +#pragma once + +#include "common/Mth.hpp" +#include "compat/LegacyCPP.hpp" +#include "world/phys/Vec3.hpp" + +// TODO: Rename to `Pos` +struct Vec3Int32 +{ +public: + int x, y, z; + +public: + Vec3Int32() : x(0), y(0), z(0) { } + Vec3Int32(int xyz) : x(xyz), y(xyz), z(xyz) { } + Vec3Int32(int x, int y, int z) : x(x), y(y), z(z) { } + + Vec3 toVec3() const + { + return Vec3(static_cast(x), static_cast(y), static_cast(z)); + } + + float distanceTo(const Vec3Int32& b) const + { + return Mth::sqrt(float(distanceToSqr(b))); + } + + int distanceToSqr(const Vec3Int32& b) const + { + return (*this - b).lengthSqr(); + } + + int lengthSqr() const + { + return x * x + y * y + z * z; + } + + float length() const + { + return Mth::sqrt(float(lengthSqr())); + } + + Vec3Int32 operator+(const Vec3Int32& b) const + { + return Vec3Int32(x + b.x, y + b.y, z + b.z); + } + + Vec3Int32 operator-(const Vec3Int32& b) const + { + return Vec3Int32(x - b.x, y - b.y, z - b.z); + } + + Vec3Int32 operator*(const Vec3Int32& b) const + { + return Vec3Int32(x * b.x, y * b.y, z * b.z); + } + + void operator+=(const Vec3Int32& b) + { + x += b.x; + y += b.y; + z += b.z; + } + + void operator-=(const Vec3Int32& b) + { + (*this) += -b; + } + + void operator+=(int f) + { + x += f; + y += f; + z += f; + } + + void operator-=(int f) + { + x -= f; + y -= f; + z -= f; + } + + void operator*=(int f) + { + x *= f; + y *= f; + z *= f; + } + + void operator/=(int f) + { + x /= f; + y /= f; + z /= f; + } + + Vec3Int32 operator-() const + { + return Vec3Int32(-x, -y, -z); + } + + Vec3Int32 operator-(int f) const + { + return Vec3Int32(x - f, y - f, z - f); + } + + Vec3 operator-(float f) const + { + return Vec3(x - f, y - f, z - f); + } + + Vec3Int32 operator*(int f) const + { + return Vec3Int32(x * f, y * f, z * f); + } + + Vec3 operator*(float f) const + { + return Vec3(x * f, y * f, z * f); + } + + Vec3Int32 operator/(int f) const + { + return Vec3Int32(x / f, y / f, z / f); + } + + Vec3 operator/(float f) const + { + return Vec3(x / f, y / f, z / f); + } + + bool operator==(const Vec3Int32& b) const + { + return x == b.x && + y == b.y && + z == b.z; + } + + bool operator!=(const Vec3Int32& b) const + { + return x != b.x && + y != b.y && + z != b.z; + } +}; + diff --git a/source/world/tile/Bush.cpp b/source/world/tile/Bush.cpp index 78f2b7a6e..b9bcf0280 100644 --- a/source/world/tile/Bush.cpp +++ b/source/world/tile/Bush.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "Bush.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" Bush::Bush(TileID id, int texture) : Tile(id, Material::plant) { @@ -32,41 +32,41 @@ bool Bush::isSolidRender() const return false; } -bool Bush::mayPlace(const Level* level, const TilePos& pos) const +bool Bush::mayPlace(TileSource* source, const TilePos& pos) const { - TileID tile = level->getTile(pos.below()); + TileID tile = source->getTile(pos.below()); return tile == Tile::grass->m_ID || tile == Tile::dirt->m_ID || tile == Tile::farmland->m_ID; } -bool Bush::canSurvive(const Level* level, const TilePos& pos) const +bool Bush::canSurvive(TileSource* source, const TilePos& pos) const { - if (level->getRawBrightness(pos) <= 7 && !level->canSeeSky(pos)) + if (source->getRawBrightness(pos) <= 7 && !source->canSeeSky(pos)) return false; - return mayPlace(level, pos); + return mayPlace(source, pos); } -void Bush::checkAlive(Level* level, const TilePos& pos) +void Bush::checkAlive(TileSource* source, const TilePos& pos) { - if (!canSurvive(level, pos)) + if (!canSurvive(source, pos)) { - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); } } -void Bush::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void Bush::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - return checkAlive(level, pos); + return checkAlive(source, pos); } -void Bush::tick(Level* level, const TilePos& pos, Random* random) +void Bush::tick(TileSource* source, const TilePos& pos, Random* random) { - checkAlive(level, pos); + checkAlive(source, pos); } -AABB* Bush::getAABB(const Level* level, const TilePos& pos) +AABB* Bush::getAABB(TileSource* source, const TilePos& pos) { return nullptr; } diff --git a/source/world/tile/Bush.hpp b/source/world/tile/Bush.hpp index d23d5b80a..9dc6b821d 100644 --- a/source/world/tile/Bush.hpp +++ b/source/world/tile/Bush.hpp @@ -15,16 +15,14 @@ class Bush : public Tile public: Bush(TileID id, int texture); -public: - bool canSurvive(const Level*, const TilePos& pos) const override; - AABB* getAABB(const Level*, const TilePos& pos) override; + bool canSurvive(TileSource*, const TilePos& pos) const override; + AABB* getAABB(TileSource*, const TilePos& pos) override; eRenderShape getRenderShape() const override; bool isCubeShaped() const override; bool isSolidRender() const override; - bool mayPlace(const Level*, const TilePos& pos) const override; - void tick(Level*, const TilePos& pos, Random*) override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + void tick(TileSource*, const TilePos& pos, Random*) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; -public: - void checkAlive(Level*, const TilePos& pos); + void checkAlive(TileSource*, const TilePos& pos); }; diff --git a/source/world/tile/CactusTile.cpp b/source/world/tile/CactusTile.cpp index a81fe345c..22846ddfd 100644 --- a/source/world/tile/CactusTile.cpp +++ b/source/world/tile/CactusTile.cpp @@ -1,5 +1,5 @@ #include "CactusTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" CactusTile::CactusTile(int id, int texture) : Tile(id, texture, Material::cactus) { @@ -7,40 +7,40 @@ CactusTile::CactusTile(int id, int texture) : Tile(id, texture, Material::cactus setTicking(true); } -AABB* CactusTile::getAABB(const Level* pLevel, const TilePos& pos) +AABB* CactusTile::getAABB(TileSource* source, const TilePos& pos) { - AABB* aabb = Tile::getAABB(pLevel, pos); + AABB* aabb = Tile::getAABB(source, pos); aabb->max.y -= 1.0f / 16.0f; return aabb; } -bool CactusTile::mayPlace(const Level* level, const TilePos& pos) const +bool CactusTile::mayPlace(TileSource* source, const TilePos& pos) const { - return Tile::mayPlace(level, pos) && canSurvive(level, pos); + return Tile::mayPlace(source, pos) && canSurvive(source, pos); } -bool CactusTile::canSurvive(const Level* level, const TilePos& pos) const +bool CactusTile::canSurvive(TileSource* source, const TilePos& pos) const { for (int i = Facing::NORTH; i <= Facing::EAST; ++i) { - if (level->getMaterial(pos.relative((Facing::Name)i))->isSolid()) + if (source->getMaterial(pos.relative((Facing::Name)i))->isSolid()) { return false; } } - TileID tile = level->getTile(pos.below()); + TileID tile = source->getTile(pos.below()); return tile == Tile::sand->m_ID || tile == m_ID; } -void CactusTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void CactusTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - if (!canSurvive(level, pos)) + if (!canSurvive(source, pos)) { - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); } } @@ -59,37 +59,36 @@ eRenderShape CactusTile::getRenderShape() const return SHAPE_CACTUS; } -void CactusTile::tick(Level* level, const TilePos& pos, Random* random) +void CactusTile::tick(TileSource* source, const TilePos& pos, Random* random) { TilePos above = pos.above(); - if (level->isEmptyTile(pos.above())) + if (source->isEmptyTile(pos.above())) { int height; - for (height = 1; level->getTile(pos.below(height)) == m_ID; ++height) + for (height = 1; source->getTile(pos.below(height)) == m_ID; ++height) { } if (height < 3) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (data == 15) { - level->setTile(above, m_ID); - level->setData(pos, 0); + source->setTileAndData(above, FullTile(m_ID, 0)); } else { - level->setData(pos, data + 1); + source->setTileAndData(pos, FullTile(m_ID, data + 1)); } } } } -void CactusTile::updateShape(const LevelSource* level, const TilePos& pos) +void CactusTile::updateShape(TileSource* source, const TilePos& pos) { setShape(0.0625, 0, 0.0625, 0.9375, 1, 0.9375); } -void CactusTile::entityInside(Level* level, const TilePos& pos, Entity* entity) const +void CactusTile::entityInside(TileSource* source, const TilePos& pos, Entity* entity) const { entity->hurt(nullptr, 1); } diff --git a/source/world/tile/CactusTile.hpp b/source/world/tile/CactusTile.hpp index 20a31abff..515252e78 100644 --- a/source/world/tile/CactusTile.hpp +++ b/source/world/tile/CactusTile.hpp @@ -6,17 +6,15 @@ class CactusTile : public Tile { public: CactusTile(int id, int texture); - -public: - AABB* getAABB(const Level* pLevel, const TilePos& pos) override; - bool mayPlace(const Level*, const TilePos& pos) const override; - bool canSurvive(const Level* level, const TilePos& pos) const override; - void neighborChanged(Level* level, const TilePos& pos, TileID tile) override; + AABB* getAABB(TileSource* source, const TilePos& pos) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + bool canSurvive(TileSource* source, const TilePos& pos) const override; + void neighborChanged(TileSource* source, const TilePos& pos, TileID tile) override; bool isSolidRender() const override; bool isCubeShaped() const override; eRenderShape getRenderShape() const override; - void tick(Level*, const TilePos& pos, Random*) override; - void entityInside(Level*, const TilePos& pos, Entity*) const override; + void tick(TileSource*, const TilePos& pos, Random*) override; + void entityInside(TileSource*, const TilePos& pos, Entity*) const override; int getTexture(Facing::Name face) const override; - void updateShape(const LevelSource* level, const TilePos& pos) override; + void updateShape(TileSource* source, const TilePos& pos) override; }; diff --git a/source/world/tile/CraftingTableTile.cpp b/source/world/tile/CraftingTableTile.cpp index f6cd821ab..19ade33a3 100644 --- a/source/world/tile/CraftingTableTile.cpp +++ b/source/world/tile/CraftingTableTile.cpp @@ -1,17 +1,19 @@ #include "CraftingTableTile.hpp" +#include "world/entity/Player.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" CraftingTableTile::CraftingTableTile(TileID id) : Tile(id, TEXTURE_WORKBENCH_SIDE_1, Material::wood) { } -bool CraftingTableTile::use(Level* level, const TilePos& pos, Player* player) +bool CraftingTableTile::use(const TilePos& pos, Player* player) { if (player->isSneaking() && !player->getSelectedItem().isEmpty()) { return false; } - if (level->m_bIsClientSide) + if (player->getLevel().m_bIsClientSide) { return true; } diff --git a/source/world/tile/CraftingTableTile.hpp b/source/world/tile/CraftingTableTile.hpp index 41a30127a..819d14388 100644 --- a/source/world/tile/CraftingTableTile.hpp +++ b/source/world/tile/CraftingTableTile.hpp @@ -6,8 +6,6 @@ class CraftingTableTile : public Tile { public: CraftingTableTile(TileID id); - -public: - bool use(Level*, const TilePos& pos, Player*) override; + bool use(const TilePos& pos, Player*) override; int getTexture(Facing::Name face) const override; }; \ No newline at end of file diff --git a/source/world/tile/CropsTile.cpp b/source/world/tile/CropsTile.cpp index cb361a031..a6aee1e79 100644 --- a/source/world/tile/CropsTile.cpp +++ b/source/world/tile/CropsTile.cpp @@ -1,5 +1,6 @@ #include "CropsTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" CropsTile::CropsTile(int id, int texture) : Bush(id, texture) { @@ -21,38 +22,38 @@ eRenderShape CropsTile::getRenderShape() const return SHAPE_CROPS; } -void CropsTile::tick(Level* level, const TilePos& pos, Random* random) +void CropsTile::tick(TileSource* source, const TilePos& pos, Random* random) { - Bush::tick(level, pos, random); + Bush::tick(source, pos, random); // Too dark - if (level->getRawBrightness(pos.above()) < 9) + if (source->getRawBrightness(pos.above()) < 9) return; - int growthStage = level->getData(pos); + TileData growthStage = source->getData(pos); // Fully grown if (growthStage >= 7) return; - float growthRate = getGrowthRate(level, pos); + float growthRate = getGrowthRate(source, pos); if (random->nextInt((int)(100.0f / growthRate)) == 0) { - level->setData(pos, growthStage + 1); + source->setTileAndData(pos, FullTile(m_ID, growthStage + 1)); } } -float CropsTile::getGrowthRate(Level* level, const TilePos& pos) +float CropsTile::getGrowthRate(TileSource* source, const TilePos& pos) { float rate = 1.0f; - TileID north = level->getTile(pos.north()); - TileID south = level->getTile(pos.south()); - TileID west = level->getTile(pos.west()); - TileID east = level->getTile(pos.east()); - TileID nw = level->getTile(pos + TilePos(-1, 0, -1)); - TileID ne = level->getTile(pos + TilePos(1, 0, -1)); - TileID se = level->getTile(pos + TilePos(1, 0, 1)); - TileID sw = level->getTile(pos + TilePos(-1, 0, 1)); + TileID north = source->getTile(pos.north()); + TileID south = source->getTile(pos.south()); + TileID west = source->getTile(pos.west()); + TileID east = source->getTile(pos.east()); + TileID nw = source->getTile(pos + TilePos(-1, 0, -1)); + TileID ne = source->getTile(pos + TilePos(1, 0, -1)); + TileID se = source->getTile(pos + TilePos(1, 0, 1)); + TileID sw = source->getTile(pos + TilePos(-1, 0, 1)); bool hor = west == m_ID || east == m_ID; bool vert = north == m_ID || south == m_ID; @@ -63,12 +64,12 @@ float CropsTile::getGrowthRate(Level* level, const TilePos& pos) { for (tp.z = pos.z; tp.z <= pos.z + 1; ++tp.z) { - TileID closeTile = level->getTile(tp); + TileID closeTile = source->getTile(tp); float rateInfluence = 0.0f; if (closeTile == Tile::farmland->m_ID) { rateInfluence = 1.0f; - if (level->getData(tp) > 0) + if (source->getData(tp) > 0) { rateInfluence = 3.0f; } @@ -91,9 +92,9 @@ float CropsTile::getGrowthRate(Level* level, const TilePos& pos) return rate; } -void CropsTile::growCropsToMax(Level* level, const TilePos& pos) +void CropsTile::growCropsToMax(TileSource* source, const TilePos& pos) { - level->setData(pos, 7); + source->setTileAndData(pos, FullTile(m_ID, 7)); } int CropsTile::getResource(TileData data, Random* random) const @@ -101,52 +102,55 @@ int CropsTile::getResource(TileData data, Random* random) const return (data == 7) ? Item::wheat->m_itemID : -1; } -void CropsTile::spawnResources(Level* level, const TilePos& pos, TileData data) +void CropsTile::spawnResources(TileSource* source, const TilePos& pos, TileData data) { - Bush::spawnResources(level, pos, data); + Bush::spawnResources(source, pos, data); - if (level->m_bIsClientSide) + Level& level = source->getLevel(); + if (level.m_bIsClientSide) return; for (int i = 0; i < 3; i++) { - if (level->m_random.nextInt(15) > data) + if (level.m_random.nextInt(15) > data) continue; - Vec3 deviation((level->m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, - (level->m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, - (level->m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f); + Vec3 deviation((level.m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, + (level.m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, + (level.m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f); ItemStack item(Item::seeds, 1, getSpawnResourcesAuxValue(data)); - ItemEntity* pEntity = new ItemEntity(level, pos + deviation, item); + ItemEntity* pEntity = new ItemEntity(*source, pos + deviation, item); pEntity->m_throwTime = 10; - level->addEntity(pEntity); + level.addEntity(pEntity); } } -void CropsTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void CropsTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - if (level->getTile(pos.below()) != Tile::farmland->m_ID) + if (source->getTile(pos.below()) != Tile::farmland->m_ID) { - level->setTile(pos, TILE_AIR); + source->setTile(pos, TILE_AIR); + + Level& level = source->getLevel(); float spread = 0.7f; TilePos spreadPos( - level->m_random.nextFloat() * spread + (1.0f - spread) * 0.5f, + level.m_random.nextFloat() * spread + (1.0f - spread) * 0.5f, 1.2f, - level->m_random.nextFloat() * spread + (1.0f - spread) * 0.5f + level.m_random.nextFloat() * spread + (1.0f - spread) * 0.5f ); - ItemEntity* itemEntity = new ItemEntity(level, pos.above() + spreadPos, ItemStack(Item::seeds)); + ItemEntity* itemEntity = new ItemEntity(*source, pos.above() + spreadPos, ItemStack(Item::seeds)); itemEntity->m_throwTime = 10; - level->addEntity(itemEntity); + level.addEntity(itemEntity); } } -void CropsTile::updateShape(const LevelSource* level, const TilePos& pos) +void CropsTile::updateShape(TileSource* source, const TilePos& pos) { setShape(0, 0, 0, 1, 0.25f, 1); } diff --git a/source/world/tile/CropsTile.hpp b/source/world/tile/CropsTile.hpp index 529b46754..f207969da 100644 --- a/source/world/tile/CropsTile.hpp +++ b/source/world/tile/CropsTile.hpp @@ -11,14 +11,14 @@ class CropsTile : public Bush bool isSolidRender() const override; bool isCubeShaped() const override; eRenderShape getRenderShape() const override; - void tick(Level*, const TilePos& pos, Random*) override; + void tick(TileSource*, const TilePos& pos, Random*) override; int getTexture(Facing::Name face, TileData data) const override; - void updateShape(const LevelSource* level, const TilePos& pos) override; - void spawnResources(Level*, const TilePos& pos, TileData data) override; - void neighborChanged(Level* level, const TilePos& pos, TileID tile); + void updateShape(TileSource* source, const TilePos& pos) override; + void spawnResources(TileSource*, const TilePos& pos, TileData data) override; + void neighborChanged(TileSource* source, const TilePos& pos, TileID tile); public: - float getGrowthRate(Level* level, const TilePos& pos); - void growCropsToMax(Level* level, const TilePos& pos); + float getGrowthRate(TileSource* source, const TilePos& pos); + void growCropsToMax(TileSource* source, const TilePos& pos); int getResource(TileData, Random*) const override; }; \ No newline at end of file diff --git a/source/world/tile/DeadBush.cpp b/source/world/tile/DeadBush.cpp index 39b7f9907..e807a98dd 100644 --- a/source/world/tile/DeadBush.cpp +++ b/source/world/tile/DeadBush.cpp @@ -1,13 +1,13 @@ #include "DeadBush.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" DeadBush::DeadBush(int id, int texture) : Bush(id, texture) { } -bool DeadBush::mayPlace(const Level* level, const TilePos& pos) const +bool DeadBush::mayPlace(TileSource* source, const TilePos& pos) const { - TileID tile = level->getTile(pos.below()); + TileID tile = source->getTile(pos.below()); return tile == Tile::sand->m_ID; } diff --git a/source/world/tile/DeadBush.hpp b/source/world/tile/DeadBush.hpp index b7225b1f2..1450c02b2 100644 --- a/source/world/tile/DeadBush.hpp +++ b/source/world/tile/DeadBush.hpp @@ -9,5 +9,5 @@ class DeadBush : public Bush public: int getResource(TileData, Random*) const override; - bool mayPlace(const Level*, const TilePos& pos) const override; + bool mayPlace(TileSource*, const TilePos& pos) const override; }; diff --git a/source/world/tile/DoorTile.cpp b/source/world/tile/DoorTile.cpp index 62f80d263..19fffc77e 100644 --- a/source/world/tile/DoorTile.cpp +++ b/source/world/tile/DoorTile.cpp @@ -8,6 +8,7 @@ #include "DoorTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "world/item/Item.hpp" DoorTile::DoorTile(int ID, Material* pMtl) : Tile(ID, pMtl) @@ -21,40 +22,41 @@ DoorTile::DoorTile(int ID, Material* pMtl) : Tile(ID, pMtl) Tile::setShape(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); } -bool DoorTile::use(Level* level, const TilePos& pos, Player* player) +bool DoorTile::use(const TilePos& pos, Player* player) { // well, you know, iron doors can't be opened by right clicking if (m_pMaterial == Material::metal) return true; - TileData data = level->getData(pos); + TileSource& source = player->getTileSource(); + + TileData data = source.getData(pos); // if we're the top tile if (data & 8) { - if (level->getTile(pos.below()) == m_ID) - use(level, pos.below(), player); + if (source.getTile(pos.below()) == m_ID) + use(pos.below(), player); } else { data ^= 4; - if (level->getTile(pos.above()) == m_ID) - level->setData(pos.above(), data + 8); + if (source.getTile(pos.above()) == m_ID) + source.setTileAndData(pos.above(), FullTile(m_ID, data + 8), TileChange::UPDATE_ALL | TileChange::UPDATE_UNK3); - level->setData(pos, data); + source.setTileAndData(pos, FullTile(m_ID, data), TileChange::UPDATE_ALL | TileChange::UPDATE_UNK3); - // @BUG: marking the wrong tiles as dirty? No problem because setData sends an update immediately anyways - level->setTilesDirty(pos.below(), pos); + // there is a fireTileChanged call here, but setTileAndData should already be calling that - level->levelEvent(LevelEvent(LevelEvent::SOUND_DOOR, pos, 0, player)); + player->getLevel().levelEvent(LevelEvent(LevelEvent::SOUND_DOOR, pos, 0, player)); } return true; } -void DoorTile::attack(Level* level, const TilePos& pos, Player* player) +void DoorTile::attack(TileSource* source, const TilePos& pos, Player* player) { - use(level, pos, player); + use(pos, player); } // @HUH: This function has NO references to itself. Not even in the vtable of the tile. @@ -65,17 +67,17 @@ bool DoorTile::blocksLight() const return false; } -HitResult DoorTile::clip(const Level* level, const TilePos& pos, Vec3 v1, Vec3 v2) +HitResult DoorTile::clip(TileSource* source, const TilePos& pos, Vec3 v1, Vec3 v2) { // @NOTE: Tile::clip calls updateShape too. So this is redundant - updateShape(level, pos); - return Tile::clip(level, pos, v1, v2); + updateShape(source, pos); + return Tile::clip(source, pos, v1, v2); } -AABB* DoorTile::getAABB(const Level* level, const TilePos& pos) +AABB* DoorTile::getAABB(TileSource* source, const TilePos& pos) { - updateShape(level, pos); - return Tile::getAABB(level, pos); + updateShape(source, pos); + return Tile::getAABB(source, pos); } int DoorTile::getDir(TileData data) const @@ -124,10 +126,10 @@ int DoorTile::getTexture(Facing::Name face, TileData data) const return idx; } -AABB DoorTile::getTileAABB(const Level* level, const TilePos& pos) +AABB DoorTile::getTileAABB(TileSource* source, const TilePos& pos) { - updateShape(level, pos); - return Tile::getTileAABB(level, pos); + updateShape(source, pos); + return Tile::getTileAABB(source, pos); } bool DoorTile::isCubeShaped() const @@ -140,9 +142,9 @@ bool DoorTile::isSolidRender() const return false; } -bool DoorTile::mayPlace(const Level* level, const TilePos& pos) const +bool DoorTile::mayPlace(TileSource* source, const TilePos& pos) const { - return pos.y <= 126 && level->isSolidTile(pos.below()) && Tile::mayPlace(level, pos) && Tile::mayPlace(level, pos.above()); + return pos.y <= 126 && source->isSolidBlockingTile(pos.below()) && Tile::mayPlace(source, pos) && Tile::mayPlace(source, pos.above()); } void DoorTile::setShape(int dir) @@ -166,28 +168,29 @@ void DoorTile::setShape(int dir) } } -void DoorTile::updateShape(const LevelSource* level, const TilePos& pos) +void DoorTile::updateShape(TileSource* source, const TilePos& pos) { - setShape(getDir(level->getData(pos))); + setShape(getDir(source->getData(pos))); } -void DoorTile::setOpen(Level* level, const TilePos& pos, bool bOpen) +void DoorTile::setOpen(TileSource* source, const TilePos& pos, bool bOpen) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (isTop(data)) { - if (level->getTile(pos.below()) == m_ID) - setOpen(level, pos.below(), bOpen); + if (source->getTile(pos.below()) == m_ID) + setOpen(source, pos.below(), bOpen); return; } - if (isOpen(level->getData(pos)) != bOpen) + if (isOpen(source->getData(pos)) != bOpen) { - if (level->getTile(pos.above()) == m_ID) - level->setData(pos.above(), (data ^ 4) + 8); + if (source->getTile(pos.above()) == m_ID) + source->setTileAndData(pos.above(), FullTile(m_ID, (data ^ 4) + 8), TileChange::UPDATE_ALL | TileChange::UPDATE_UNK3); + + source->setTileAndData(pos, FullTile(m_ID, data ^ 4), TileChange::UPDATE_ALL | TileChange::UPDATE_UNK3); - level->setData(pos, data ^ 4); - level->setTilesDirty(pos.below(), pos); + // there is a fireTileChanged call here, but setTileAndData should already be calling that std::string snd; if (Mth::random() < 0.5f) @@ -195,52 +198,53 @@ void DoorTile::setOpen(Level* level, const TilePos& pos, bool bOpen) else snd = "random.door_close"; - level->playSound(Vec3(pos) + 0.5f, snd, 1.0f, 0.9f + 0.1f * level->m_random.nextFloat()); + Level& level = source->getLevel(); + level.playSound(Vec3(pos) + 0.5f, snd, 1.0f, 0.9f + 0.1f * level.m_random.nextFloat()); } } -void DoorTile::neighborChanged(Level* level, const TilePos& pos, TileID newTile) +void DoorTile::neighborChanged(TileSource* source, const TilePos& pos, TileID newTile) { - int isTop = level->getData(pos) & 8; + int isTop = source->getData(pos) & 8; if (isTop) { - if (level->getTile(pos.below()) != m_ID) + if (source->getTile(pos.below()) != m_ID) { - level->setTile(pos, TILE_AIR); - spawnResources(level, pos, level->getData(pos)); + source->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); } if (newTile > 0) { if (Tile::tiles[newTile]->isSignalSource()) - neighborChanged(level, pos.below(), newTile); + neighborChanged(source, pos.below(), newTile); } return; } - if (level->getTile(pos.above()) != m_ID) + if (source->getTile(pos.above()) != m_ID) { - level->setTile(pos, TILE_AIR); + source->setTile(pos, TILE_AIR); isTop = 1; } - if (!level->isSolidTile(pos.below())) + if (!source->isSolidBlockingTile(pos.below())) { - level->setTile(pos, TILE_AIR); - if (level->getTile(pos.above()) == m_ID) + source->setTile(pos, TILE_AIR); + if (source->getTile(pos.above()) == m_ID) { - level->setTile(pos.above(), TILE_AIR); - spawnResources(level, pos, level->getData(pos)); + source->setTile(pos.above(), TILE_AIR); + spawnResources(source, pos, source->getData(pos)); } } if (!isTop && newTile > 0 && Tile::tiles[newTile]->isSignalSource()) { bool bOpen = false; - if (level->hasNeighborSignal(pos) || level->hasNeighborSignal(pos.above())) + if (source->hasNeighborSignal(pos) || source->hasNeighborSignal(pos.above())) bOpen = true; - setOpen(level, pos, bOpen); + setOpen(source, pos, bOpen); } } diff --git a/source/world/tile/DoorTile.hpp b/source/world/tile/DoorTile.hpp index 778eec2fa..5a8ec5894 100644 --- a/source/world/tile/DoorTile.hpp +++ b/source/world/tile/DoorTile.hpp @@ -15,24 +15,23 @@ class DoorTile : public Tile public: DoorTile(int ID, Material*); -public: - void attack(Level*, const TilePos& pos, Player*) override; - bool use(Level*, const TilePos& pos, Player*) override; - HitResult clip(const Level*, const TilePos& pos, Vec3, Vec3) override; - AABB* getAABB(const Level*, const TilePos& pos) override; + void attack(TileSource*, const TilePos& pos, Player*) override; + bool use(const TilePos& pos, Player*) override; + HitResult clip(TileSource*, const TilePos& pos, Vec3, Vec3) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; eRenderShape getRenderShape() const override; int getResource(TileData data, Random*) const override; int getTexture(Facing::Name face, TileData data) const override; - AABB getTileAABB(const Level*, const TilePos& pos) override; + AABB getTileAABB(TileSource*, const TilePos& pos) override; bool isCubeShaped() const override; bool isSolidRender() const override; - bool mayPlace(const Level*, const TilePos& pos) const override; - void updateShape(const LevelSource*, const TilePos& pos) override; - void neighborChanged(Level*, const TilePos& pos, TileID newTile) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + void updateShape(TileSource*, const TilePos& pos) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID newTile) override; bool blocksLight() const; int getDir(TileData data) const; - void setOpen(Level*, const TilePos& pos, bool bOpen); + void setOpen(TileSource*, const TilePos& pos, bool bOpen); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverloaded-virtual" diff --git a/source/world/tile/FarmTile.cpp b/source/world/tile/FarmTile.cpp index 47b41c417..1fe7cffd1 100644 --- a/source/world/tile/FarmTile.cpp +++ b/source/world/tile/FarmTile.cpp @@ -8,6 +8,7 @@ #include "FarmTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" FarmTile::FarmTile(TileID id, Material* c) : Tile(id, c) { @@ -18,7 +19,7 @@ FarmTile::FarmTile(TileID id, Material* c) : Tile(id, c) setLightBlock(255); } -AABB* FarmTile::getAABB(const Level*, const TilePos& pos) +AABB* FarmTile::getAABB(TileSource*, const TilePos& pos) { // a full block m_aabbReturned = AABB( @@ -61,7 +62,7 @@ bool FarmTile::isSolidRender() const return false; } -bool FarmTile::isNearWater(Level* level, const TilePos& pos) +bool FarmTile::isNearWater(TileSource* source, const TilePos& pos) { TilePos waterPos = TilePos(); @@ -71,7 +72,7 @@ bool FarmTile::isNearWater(Level* level, const TilePos& pos) { for (waterPos.z = pos.z - 4; waterPos.z <= pos.z + 4; waterPos.z++) { - if (level->getMaterial(waterPos) == Material::water) + if (source->getMaterial(waterPos) == Material::water) return true; } } @@ -80,41 +81,41 @@ bool FarmTile::isNearWater(Level* level, const TilePos& pos) return false; } -bool FarmTile::isUnderCrops(Level* level, const TilePos& pos) +bool FarmTile::isUnderCrops(TileSource* source, const TilePos& pos) { - return level->getTile(pos.above()) == Tile::crops->m_ID; + return source->getTile(pos.above()) == Tile::crops->m_ID; } -void FarmTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void FarmTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - if (level->getMaterial(pos.above())->isSolid()) - level->setTile(pos, Tile::dirt->m_ID); + if (source->getMaterial(pos.above())->isSolid()) + source->setTile(pos, Tile::dirt->m_ID); } -void FarmTile::stepOn(Level* level, const TilePos& pos, Entity* pEnt) +void FarmTile::stepOn(TileSource* source, const TilePos& pos, Entity* pEnt) { - if (level->m_random.genrand_int32() % 4 == 0) - level->setTile(pos, Tile::dirt->m_ID); + if (source->getLevel().m_random.genrand_int32() % 4 == 0) + source->setTile(pos, Tile::dirt->m_ID); } -void FarmTile::tick(Level* level, const TilePos& pos, Random* random) +void FarmTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->m_bIsClientSide) + if (source->getLevelConst().m_bIsClientSide) return; if (random->nextInt(5) != 0) return; - if (isNearWater(level, pos)/* && !level->isRainingAt(pos.above())*/) + if (isNearWater(source, pos)/* && !level->isRainingAt(pos.above())*/) { - level->setData(pos, 7); + source->setTileAndData(pos, FullTile(m_ID, 7)); return; } - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (data > 0) - level->setData(pos, data - 1); - else if (!isUnderCrops(level, pos)) - level->setTile(pos, Tile::dirt->m_ID); + source->setTileAndData(pos, FullTile(m_ID, data - 1)); + else if (!isUnderCrops(source, pos)) + source->setTile(pos, Tile::dirt->m_ID); } diff --git a/source/world/tile/FarmTile.hpp b/source/world/tile/FarmTile.hpp index c1246d6b0..15d05e1a2 100644 --- a/source/world/tile/FarmTile.hpp +++ b/source/world/tile/FarmTile.hpp @@ -15,16 +15,15 @@ class FarmTile : public Tile public: FarmTile(TileID ID, Material*); -public: - AABB* getAABB(const Level*, const TilePos& pos) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; int getResource(TileData, Random*) const override; int getTexture(Facing::Name face, TileData data) const override; bool isCubeShaped() const override; bool isSolidRender() const override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - void stepOn(Level* level, const TilePos& pos, Entity* pEnt) override; - void tick(Level* level, const TilePos& pos, Random* random) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + void stepOn(TileSource* source, const TilePos& pos, Entity* pEnt) override; + void tick(TileSource* source, const TilePos& pos, Random* random) override; - bool isNearWater(Level* level, const TilePos& pos); - bool isUnderCrops(Level* level, const TilePos& pos); + bool isNearWater(TileSource* source, const TilePos& pos); + bool isUnderCrops(TileSource* source, const TilePos& pos); }; diff --git a/source/world/tile/FenceTile.cpp b/source/world/tile/FenceTile.cpp index 45ea35037..2504e6a25 100644 --- a/source/world/tile/FenceTile.cpp +++ b/source/world/tile/FenceTile.cpp @@ -7,21 +7,21 @@ ********************************************************************/ #include "FenceTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" FenceTile::FenceTile(int a, int b) : Tile(a, b, Material::wood) { } -bool FenceTile::mayPlace(const Level* level, const TilePos& pos) const +bool FenceTile::mayPlace(TileSource* source, const TilePos& pos) const { TilePos below = pos.below(); - return level->getTile(below) == m_ID || (Tile::mayPlace(level, pos) && level->getMaterial(below)->isSolid()); + return source->getTile(below) == m_ID || (Tile::mayPlace(source, pos) && source->getMaterial(below)->isSolid()); } -AABB* FenceTile::getAABB(const Level* pLevel, const TilePos& pos) +AABB* FenceTile::getAABB(TileSource* source, const TilePos& pos) { - AABB* rAABB = Tile::getAABB(pLevel, pos); + AABB* rAABB = Tile::getAABB(source, pos); rAABB->max.y += 0.5f; return rAABB; } diff --git a/source/world/tile/FenceTile.hpp b/source/world/tile/FenceTile.hpp index bf73b74e4..5387a399f 100644 --- a/source/world/tile/FenceTile.hpp +++ b/source/world/tile/FenceTile.hpp @@ -6,10 +6,8 @@ class FenceTile : public Tile { public: FenceTile(int id, int texture); - -public: - bool mayPlace(const Level*, const TilePos& pos) const override; - AABB* getAABB(const Level* pLevel, const TilePos& pos) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + AABB* getAABB(TileSource* source, const TilePos& pos) override; bool isSolidRender() const override; bool isCubeShaped() const override; eRenderShape getRenderShape() const override; diff --git a/source/world/tile/FireTile.cpp b/source/world/tile/FireTile.cpp index 3687ad013..6f6a012db 100644 --- a/source/world/tile/FireTile.cpp +++ b/source/world/tile/FireTile.cpp @@ -8,6 +8,8 @@ #include "FireTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/TileTickingQueue.hpp" FireTile::FireTile(int ID, int texture) : Tile(ID, texture, Material::fire) { @@ -53,7 +55,7 @@ bool FireTile::isCubeShaped() const return false; } -AABB* FireTile::getAABB(const Level* level, const TilePos& pos) +AABB* FireTile::getAABB(TileSource* source, const TilePos& pos) { return nullptr; } @@ -68,79 +70,81 @@ int FireTile::getTickDelay() const return 10; } -void FireTile::animateTick(Level* level, const TilePos& pos, Random* random) +void FireTile::animateTick(TileSource* source, const TilePos& pos, Random* random) { + Level& level = source->getLevel(); + // @TODO: Mark Tile::fire as FireTile* instead of Tile* FireTile* pFireTile = (FireTile*)Tile::fire; - if (level->isSolidTile(pos.below()) || pFireTile->canBurn(level, pos.below())) + if (source->isSolidBlockingTile(pos.below()) || pFireTile->canBurn(source, pos.below())) { for (int i = 0; i < 3; i++) { - level->addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y) + random->nextFloat() * 0.5f + 0.5f, float(pos.z) + random->nextFloat())); + level.addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y) + random->nextFloat() * 0.5f + 0.5f, float(pos.z) + random->nextFloat())); } return; } - if (pFireTile->canBurn(level, pos.west())) - level->addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat() * 0.1f, float(pos.y) + random->nextFloat(), float(pos.z) + random->nextFloat())); - if (pFireTile->canBurn(level, pos.east())) - level->addParticle("largesmoke", Vec3(float(pos.x + 1) - random->nextFloat() * 0.1f, float(pos.y) + random->nextFloat(), float(pos.z) + random->nextFloat())); - if (pFireTile->canBurn(level, pos.north())) - level->addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y) + random->nextFloat(), float(pos.z) + random->nextFloat() * 0.1f)); - if (pFireTile->canBurn(level, pos.south())) - level->addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y) + random->nextFloat(), float(pos.z + 1) - random->nextFloat() * 0.1f)); - if (pFireTile->canBurn(level, pos.above())) - level->addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y + 1) - random->nextFloat() * 0.1f, float(pos.z) + random->nextFloat())); + if (pFireTile->canBurn(source, pos.west())) + level.addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat() * 0.1f, float(pos.y) + random->nextFloat(), float(pos.z) + random->nextFloat())); + if (pFireTile->canBurn(source, pos.east())) + level.addParticle("largesmoke", Vec3(float(pos.x + 1) - random->nextFloat() * 0.1f, float(pos.y) + random->nextFloat(), float(pos.z) + random->nextFloat())); + if (pFireTile->canBurn(source, pos.north())) + level.addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y) + random->nextFloat(), float(pos.z) + random->nextFloat() * 0.1f)); + if (pFireTile->canBurn(source, pos.south())) + level.addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y) + random->nextFloat(), float(pos.z + 1) - random->nextFloat() * 0.1f)); + if (pFireTile->canBurn(source, pos.above())) + level.addParticle("largesmoke", Vec3(float(pos.x) + random->nextFloat(), float(pos.y + 1) - random->nextFloat() * 0.1f, float(pos.z) + random->nextFloat())); } -void FireTile::checkBurn(Level* level, const TilePos& pos, int thing, Random* random) +void FireTile::checkBurn(TileSource* source, const TilePos& pos, int thing, Random* random) { - if (m_burnOdds[level->getTile(pos)] > int(random->nextInt(thing))) + if (m_burnOdds[source->getTile(pos)] > int(random->nextInt(thing))) { - TileID tid = level->getTile(pos); + TileID tid = source->getTile(pos); TileID newTile = m_ID; if (random->nextInt(2)) newTile = TILE_AIR; - level->setTile(pos, newTile); + source->setTile(pos, newTile); if (tid == Tile::tnt->m_ID) - Tile::tnt->destroy(level, pos, 0); + Tile::tnt->destroy(source, pos, 0); } } -int FireTile::getFireOdds(const Level* level, const TilePos& pos) +int FireTile::getFireOdds(TileSource* source, const TilePos& pos) { - if (!level->isEmptyTile(pos)) + if (!source->isEmptyTile(pos)) return 0; - int odds = m_igniteOdds[level->getTile(pos.east())], o; + int odds = m_igniteOdds[source->getTile(pos.east())], o; if (odds < 0) odds = 0; - o = m_igniteOdds[level->getTile(pos.west())]; + o = m_igniteOdds[source->getTile(pos.west())]; if (odds < o) odds = o; - o = m_igniteOdds[level->getTile(pos.below())]; + o = m_igniteOdds[source->getTile(pos.below())]; if (odds < o) odds = o; - o = m_igniteOdds[level->getTile(pos.above())]; + o = m_igniteOdds[source->getTile(pos.above())]; if (odds < o) odds = o; - o = m_igniteOdds[level->getTile(pos.north())]; + o = m_igniteOdds[source->getTile(pos.north())]; if (odds < o) odds = o; - o = m_igniteOdds[level->getTile(pos.south())]; + o = m_igniteOdds[source->getTile(pos.south())]; if (odds < o) odds = o; return odds; } -bool FireTile::isValidFireLocation(const Level* level, const TilePos& pos) const +bool FireTile::isValidFireLocation(TileSource* source, const TilePos& pos) const { - if (canBurn(level, pos.east())) return true; - if (canBurn(level, pos.west())) return true; - if (canBurn(level, pos.below())) return true; - if (canBurn(level, pos.above())) return true; - if (canBurn(level, pos.north())) return true; - if (canBurn(level, pos.south())) return true; + if (canBurn(source, pos.east())) return true; + if (canBurn(source, pos.west())) return true; + if (canBurn(source, pos.below())) return true; + if (canBurn(source, pos.above())) return true; + if (canBurn(source, pos.north())) return true; + if (canBurn(source, pos.south())) return true; return false; } @@ -149,67 +153,67 @@ bool FireTile::mayPick() const return false; } -bool FireTile::mayPlace(const Level* level, const TilePos& pos) const +bool FireTile::mayPlace(TileSource* source, const TilePos& pos) const { // @NOTE: This is useless as you usually don't 'place' fire. - if (level->isSolidTile(pos.below())) + if (source->isSolidBlockingTile(pos.below())) return true; - return isValidFireLocation(level, pos); + return isValidFireLocation(source, pos); } -void FireTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void FireTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - if (!level->isSolidTile(pos.below()) && !isValidFireLocation(level, pos)) - level->setTile(pos, TILE_AIR); + if (!source->isSolidBlockingTile(pos.below()) && !isValidFireLocation(source, pos)) + source->setTile(pos, TILE_AIR); } -void FireTile::onPlace(Level* level, const TilePos& pos) +void FireTile::onPlace(TileSource* source, const TilePos& pos) { // @NOTE: Unused return result - level->getTile(pos.below()); + source->getTile(pos.below()); - if (!level->isSolidTile(pos.below()) && !isValidFireLocation(level, pos)) + if (!source->isSolidBlockingTile(pos.below()) && !isValidFireLocation(source, pos)) { - level->setTile(pos, TILE_AIR); + source->setTile(pos, TILE_AIR); return; } - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); } -void FireTile::tick(Level* level, const TilePos& pos, Random* random) +void FireTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->getTile(pos.below()) == Tile::netherrack->m_ID) + if (source->getTile(pos.below()) == Tile::netherrack->m_ID) { - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); return; } - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (data <= 14) { - level->setData(pos, data + 1); - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->setTileAndData(pos, FullTile(this, data + 1)); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); } - if (isValidFireLocation(level, pos)) + if (isValidFireLocation(source, pos)) { - if (m_igniteOdds[level->getTile(pos.below())] <= 0 && data == 15 && !random->nextInt(4)) + if (m_igniteOdds[source->getTile(pos.below())] <= 0 && data == 15 && !random->nextInt(4)) { // just go out - level->setTile(pos, TILE_AIR); + source->setTile(pos, TILE_AIR); return; } if (data > 2 && (data & 1) == 0) { - checkBurn(level, pos.east(), 300, random); - checkBurn(level, pos.west(), 300, random); - checkBurn(level, pos.below(), 250, random); - checkBurn(level, pos.above(), 250, random); - checkBurn(level, pos.north(), 300, random); - checkBurn(level, pos.south(), 300, random); + checkBurn(source, pos.east(), 300, random); + checkBurn(source, pos.west(), 300, random); + checkBurn(source, pos.below(), 250, random); + checkBurn(source, pos.above(), 250, random); + checkBurn(source, pos.north(), 300, random); + checkBurn(source, pos.south(), 300, random); TilePos tp(pos.north()); for (tp.x = pos.x - 1; tp.x <= pos.x + 1; tp.x++) @@ -223,25 +227,30 @@ void FireTile::tick(Level* level, const TilePos& pos, Random* random) continue; int thing2 = pos.y + 1 >= tp.y ? 100 : thing; - int odds = getFireOdds(level, tp); + int odds = getFireOdds(source, tp); if (odds > 0 && odds >= int(random->nextInt(thing2))) - level->setTile(tp, m_ID); + source->setTile(tp, m_ID); } } } } if (data == 15) { - checkBurn(level, pos.east(), 1, random); - checkBurn(level, pos.west(), 1, random); - checkBurn(level, pos.below(), 1, random); - checkBurn(level, pos.above(), 1, random); - checkBurn(level, pos.north(), 1, random); - checkBurn(level, pos.south(), 1, random); + checkBurn(source, pos.east(), 1, random); + checkBurn(source, pos.west(), 1, random); + checkBurn(source, pos.below(), 1, random); + checkBurn(source, pos.above(), 1, random); + checkBurn(source, pos.north(), 1, random); + checkBurn(source, pos.south(), 1, random); } } - else if (!level->isSolidTile(pos.below()) || data > 3) + else if (!source->isSolidBlockingTile(pos.below()) || data > 3) { - level->setTile(pos, TILE_AIR); + source->setTile(pos, TILE_AIR); } } + +bool FireTile::canBurn(TileSource* source, const TilePos& pos) const +{ + return m_igniteOdds[source->getTile(pos)] > 0; +} diff --git a/source/world/tile/FireTile.hpp b/source/world/tile/FireTile.hpp index 5521717fc..06e123f56 100644 --- a/source/world/tile/FireTile.hpp +++ b/source/world/tile/FireTile.hpp @@ -15,29 +15,24 @@ class FireTile : public Tile public: FireTile(int ID, int texture); -public: - AABB* getAABB(const Level*, const TilePos& pos) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; eRenderShape getRenderShape() const override; bool isCubeShaped() const override; bool isSolidRender() const override; int getResourceCount(Random*) const override; int getTickDelay() const override; bool mayPick() const override; - bool mayPlace(const Level*, const TilePos& pos) const override; - void animateTick(Level*, const TilePos& pos, Random*) override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - void onPlace(Level*, const TilePos& pos) override; - void tick(Level*, const TilePos& pos, Random*) override; - - void checkBurn(Level*, const TilePos& pos, int, Random*); - int getFireOdds(const Level*, const TilePos& pos); - bool isValidFireLocation(const Level*, const TilePos& pos) const; - - // @NOTE: This is inlined in V0.1.0 but not V0.7.1 - inline bool canBurn(const LevelSource* level, const TilePos& pos) const - { - return m_igniteOdds[level->getTile(pos)] > 0; - } + bool mayPlace(TileSource*, const TilePos& pos) const override; + void animateTick(TileSource*, const TilePos& pos, Random*) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + void onPlace(TileSource*, const TilePos& pos) override; + void tick(TileSource*, const TilePos& pos, Random*) override; + + void checkBurn(TileSource*, const TilePos& pos, int, Random*); + int getFireOdds(TileSource*, const TilePos& pos); + bool isValidFireLocation(TileSource*, const TilePos& pos) const; + + bool canBurn(TileSource* source, const TilePos& pos) const; public: int m_igniteOdds[C_MAX_TILES]; diff --git a/source/world/tile/GrassTile.cpp b/source/world/tile/GrassTile.cpp index 4ddfde505..be67b49f9 100644 --- a/source/world/tile/GrassTile.cpp +++ b/source/world/tile/GrassTile.cpp @@ -8,6 +8,7 @@ #include "GrassTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "client/renderer/PatchManager.hpp" const Color GrassTile::DEFAULT_COLOR = Color(0.25f, 0.60f, 0.25f); @@ -19,7 +20,7 @@ GrassTile::GrassTile(TileID id, Material* c) : Tile(id, c) setTicking(true); } -int GrassTile::getColor(const LevelSource* levelSource, const TilePos& pos) const +int GrassTile::getColor(TileSource* source, const TilePos& pos) const { if (GetPatchManager()->IsGrassTinted()) { @@ -47,7 +48,7 @@ int GrassTile::getTexture(Facing::Name face) const } } -int GrassTile::getTexture(const LevelSource* level, const TilePos& pos, Facing::Name face) const +int GrassTile::getTexture(TileSource* source, const TilePos& pos, Facing::Name face) const { switch (face) { @@ -59,39 +60,39 @@ int GrassTile::getTexture(const LevelSource* level, const TilePos& pos, Facing:: break; } - Material* pMat = level->getMaterial(pos.above()); + Material* pMat = source->getMaterial(pos.above()); if (pMat == Material::topSnow || pMat == Material::snow) return TEXTURE_GRASS_SIDE_SNOW; return TEXTURE_GRASS_SIDE; } -void GrassTile::tick(Level* level, const TilePos& pos, Random* random) +void GrassTile::tick(TileSource* source, const TilePos& pos, Random* random) { // Controls the spread/death of grass. // It's like a full on automata of sorts. :) - if (level->m_bIsClientSide) + if (source->getLevelConst().m_bIsClientSide) return; - if (level->getRawBrightness(pos.above()) <= 3 && - level->getMaterial(pos.above())->blocksLight()) + if (source->getRawBrightness(pos.above()) <= 3 && + source->getMaterial(pos.above())->blocksLight()) { // grass death if (random->genrand_int32() % 4 == 0) - level->setTile(pos, Tile::dirt->m_ID); + source->setTile(pos, Tile::dirt->m_ID); } - else if (level->getRawBrightness(pos.above()) > 8) + else if (source->getRawBrightness(pos.above()) > 8) { TilePos tp(pos.x - 1 + random->nextInt(3), pos.y - 3 + random->nextInt(5), pos.z - 1 + random->nextInt(3)); - if (level->getTile(tp) == Tile::dirt->m_ID && - level->getRawBrightness(tp.above()) > 3 && - !level->getMaterial(tp.above())->blocksLight()) + if (source->getTile(tp) == Tile::dirt->m_ID && + source->getRawBrightness(tp.above()) > 3 && + !source->getMaterial(tp.above())->blocksLight()) { - //@NOTE: not this->id - level->setTile(tp, Tile::grass->m_ID); + //@NOTE: not this->m_ID + source->setTile(tp, Tile::grass->m_ID); } } } diff --git a/source/world/tile/GrassTile.hpp b/source/world/tile/GrassTile.hpp index b169c70f2..690a8caba 100644 --- a/source/world/tile/GrassTile.hpp +++ b/source/world/tile/GrassTile.hpp @@ -20,8 +20,8 @@ class GrassTile : public Tile public: int getResource(TileData, Random*) const override; - int getColor(const LevelSource*, const TilePos& pos) const override; + int getColor(TileSource*, const TilePos& pos) const override; int getTexture(Facing::Name face) const override; - int getTexture(const LevelSource*, const TilePos& pos, Facing::Name face) const override; - void tick(Level*, const TilePos& pos, Random*) override; + int getTexture(TileSource*, const TilePos& pos, Facing::Name face) const override; + void tick(TileSource*, const TilePos& pos, Random*) override; }; diff --git a/source/world/tile/HalfTransparentTile.cpp b/source/world/tile/HalfTransparentTile.cpp index f77b807dd..b85e969bc 100644 --- a/source/world/tile/HalfTransparentTile.cpp +++ b/source/world/tile/HalfTransparentTile.cpp @@ -8,6 +8,7 @@ #include "HalfTransparentTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" HalfTransparentTile::HalfTransparentTile(int a, int b, Material* c) : Tile(a, b, c) { @@ -19,10 +20,10 @@ bool HalfTransparentTile::isSolidRender() const return false; } -bool HalfTransparentTile::shouldRenderFace(const LevelSource* level, const TilePos& pos, Facing::Name face) const +bool HalfTransparentTile::shouldRenderFace(TileSource* source, const TilePos& pos, Facing::Name face) const { - if (m_bAllowSame || level->getTile(pos) != m_ID) - return Tile::shouldRenderFace(level, pos, face); + if (m_bAllowSame || source->getTile(pos) != m_ID) + return Tile::shouldRenderFace(source, pos, face); return m_bAllowSame; } diff --git a/source/world/tile/HalfTransparentTile.hpp b/source/world/tile/HalfTransparentTile.hpp index 48bccf297..19106a676 100644 --- a/source/world/tile/HalfTransparentTile.hpp +++ b/source/world/tile/HalfTransparentTile.hpp @@ -17,7 +17,7 @@ class HalfTransparentTile : public Tile public: virtual bool isSolidRender() const override; - virtual bool shouldRenderFace(const LevelSource*, const TilePos& pos, Facing::Name face) const override; + virtual bool shouldRenderFace(TileSource*, const TilePos& pos, Facing::Name face) const override; private: bool m_bAllowSame; diff --git a/source/world/tile/IceTile.cpp b/source/world/tile/IceTile.cpp index 9904c6e74..b4c23c965 100644 --- a/source/world/tile/IceTile.cpp +++ b/source/world/tile/IceTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "IceTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" IceTile::IceTile(int a, int b, Material* c) : HalfTransparentTile(a, b, c) { @@ -21,21 +21,21 @@ int IceTile::getResourceCount(Random* pRandom) const return 0; } -void IceTile::onRemove(Level* level, const TilePos& pos) +void IceTile::onRemove(TileSource* source, const TilePos& pos) { - Material* pMtlBelow = level->getMaterial(pos.below()); + Material* pMtlBelow = source->getMaterial(pos.below()); if (pMtlBelow->blocksMotion() || pMtlBelow->isLiquid()) { - level->setTile(pos, Tile::water->m_ID); + source->setTile(pos, Tile::water->m_ID); } } -void IceTile::tick(Level* level, const TilePos& pos, Random* random) +void IceTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->getBrightness(LightLayer::Block, pos) <= 11 - Tile::lightBlock[m_ID]) + if (source->getBrightness(LightLayer::Block, pos) <= 11 - Tile::lightBlock[m_ID]) return; - spawnResources(level, pos, level->getData(pos)); + spawnResources(source, pos, source->getData(pos)); - level->setTile(pos, Tile::calmWater->m_ID); + source->setTile(pos, Tile::calmWater->m_ID); } diff --git a/source/world/tile/IceTile.hpp b/source/world/tile/IceTile.hpp index 47fc17f26..ed707197e 100644 --- a/source/world/tile/IceTile.hpp +++ b/source/world/tile/IceTile.hpp @@ -17,6 +17,6 @@ class IceTile : public HalfTransparentTile public: int getResourceCount(Random*) const override; - void onRemove(Level*, const TilePos& pos) override; - void tick(Level*, const TilePos& pos, Random*) override; + void onRemove(TileSource*, const TilePos& pos) override; + void tick(TileSource*, const TilePos& pos, Random*) override; }; diff --git a/source/world/tile/LadderTile.cpp b/source/world/tile/LadderTile.cpp index c900367cf..359065f7b 100644 --- a/source/world/tile/LadderTile.cpp +++ b/source/world/tile/LadderTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "LadderTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" LadderTile::LadderTile(int ID, int texture) : Tile(ID, texture, Material::decoration) { @@ -34,9 +34,9 @@ bool LadderTile::isSolidRender() const return false; } -AABB* LadderTile::getAABB(const Level* level, const TilePos& pos) +AABB* LadderTile::getAABB(TileSource* source, const TilePos& pos) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); switch (data) { case 2: @@ -53,12 +53,12 @@ AABB* LadderTile::getAABB(const Level* level, const TilePos& pos) break; } - return Tile::getAABB(level, pos); + return Tile::getAABB(source, pos); } -AABB LadderTile::getTileAABB(const Level* level, const TilePos& pos) +AABB LadderTile::getTileAABB(TileSource* source, const TilePos& pos) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); switch (data) { case 2: @@ -75,38 +75,38 @@ AABB LadderTile::getTileAABB(const Level* level, const TilePos& pos) break; } - return Tile::getTileAABB(level, pos); + return Tile::getTileAABB(source, pos); } -void LadderTile::setPlacedOnFace(Level* level, const TilePos& pos, Facing::Name face) +void LadderTile::setPlacedOnFace(TileSource* source, const TilePos& pos, Facing::Name face) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); - if ((data == 0 || face == Facing::NORTH) && level->isSolidTile(pos.south())) data = 2; - if ((data == 0 || face == Facing::SOUTH) && level->isSolidTile(pos.north())) data = 3; - if ((data == 0 || face == Facing::WEST) && level->isSolidTile(pos.east())) data = 4; - if ((data == 0 || face == Facing::EAST) && level->isSolidTile(pos.west())) data = 5; + if ((data == 0 || face == Facing::NORTH) && source->isSolidBlockingTile(pos.south())) data = 2; + if ((data == 0 || face == Facing::SOUTH) && source->isSolidBlockingTile(pos.north())) data = 3; + if ((data == 0 || face == Facing::WEST) && source->isSolidBlockingTile(pos.east())) data = 4; + if ((data == 0 || face == Facing::EAST) && source->isSolidBlockingTile(pos.west())) data = 5; - level->setData(pos, data); - assert(level->getData(pos) == data); + source->setTileAndData(pos, FullTile(m_ID, data)); + assert(source->getData(pos) == data); } -void LadderTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void LadderTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); switch (data) { case 2: - if (level->isSolidTile(pos.south())) return; + if (source->isSolidBlockingTile(pos.south())) return; break; case 3: - if (level->isSolidTile(pos.north())) return; + if (source->isSolidBlockingTile(pos.north())) return; break; case 4: - if (level->isSolidTile(pos.east())) return; + if (source->isSolidBlockingTile(pos.east())) return; break; case 5: - if (level->isSolidTile(pos.west())) return; + if (source->isSolidBlockingTile(pos.west())) return; break; case 0: // hasn't decided on anything right now? @@ -117,15 +117,15 @@ void LadderTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) break; } - spawnResources(level, pos, data); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, data); + source->setTile(pos, TILE_AIR); } -bool LadderTile::mayPlace(const Level* level, const TilePos& pos) const +bool LadderTile::mayPlace(TileSource* source, const TilePos& pos) const { return - level->isSolidTile(pos.west()) || - level->isSolidTile(pos.east()) || - level->isSolidTile(pos.north()) || - level->isSolidTile(pos.south()); + source->isSolidBlockingTile(pos.west()) || + source->isSolidBlockingTile(pos.east()) || + source->isSolidBlockingTile(pos.north()) || + source->isSolidBlockingTile(pos.south()); } diff --git a/source/world/tile/LadderTile.hpp b/source/world/tile/LadderTile.hpp index 2be02853b..8c1042e89 100644 --- a/source/world/tile/LadderTile.hpp +++ b/source/world/tile/LadderTile.hpp @@ -20,9 +20,9 @@ class LadderTile : public Tile bool isSolidRender() const override; eRenderShape getRenderShape() const override; int getResourceCount(Random* random) const override; - AABB* getAABB(const Level*, const TilePos& pos) override; - AABB getTileAABB(const Level*, const TilePos& pos) override; - void setPlacedOnFace(Level*, const TilePos& pos, Facing::Name face) override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - bool mayPlace(const Level*, const TilePos& pos) const override; + AABB* getAABB(TileSource*, const TilePos& pos) override; + AABB getTileAABB(TileSource*, const TilePos& pos) override; + void setPlacedOnFace(TileSource*, const TilePos& pos, Facing::Name face) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; }; diff --git a/source/world/tile/LeafTile.cpp b/source/world/tile/LeafTile.cpp index 59842c6a2..d248abb9a 100644 --- a/source/world/tile/LeafTile.cpp +++ b/source/world/tile/LeafTile.cpp @@ -8,6 +8,7 @@ #include "LeafTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "client/renderer/PatchManager.hpp" #define C_REQUIRED_WOOD_RANGE 4 @@ -36,9 +37,9 @@ LeafTile::~LeafTile() delete[] m_checkBuffer; } -void LeafTile::_tickDecayOld(Level* level, const TilePos& pos) +void LeafTile::_tickDecayOld(TileSource* source, const TilePos& pos) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); if ((data & C_UPDATE_LEAF_BIT) == 0) return; @@ -47,7 +48,7 @@ void LeafTile::_tickDecayOld(Level* level, const TilePos& pos) if (!m_checkBuffer) m_checkBuffer = new int[C_RANGE * C_RANGE * C_RANGE]; - if (level->hasChunksAt(pos - (C_REQUIRED_WOOD_RANGE + 1), pos + (C_REQUIRED_WOOD_RANGE + 1))) + if (source->hasChunksAt(pos - (C_REQUIRED_WOOD_RANGE + 1), pos + (C_REQUIRED_WOOD_RANGE + 1))) { TilePos curr(pos); // @TODO: get rid of magic values @@ -61,7 +62,7 @@ void LeafTile::_tickDecayOld(Level* level, const TilePos& pos) { curr.z = pos.z - C_REQUIRED_WOOD_RANGE; - TileID tile = level->getTile(curr); + TileID tile = source->getTile(curr); if (tile == Tile::treeTrunk->m_ID) m_checkBuffer[0x18C + i + j + k] = 0; else if (tile == Tile::leaves->m_ID) @@ -109,15 +110,15 @@ void LeafTile::_tickDecayOld(Level* level, const TilePos& pos) } if (m_checkBuffer[0x4210] < 0) - die(level, pos); + die(source, pos); else - level->setDataNoUpdate(pos, data & ~C_UPDATE_LEAF_BIT); // equates to -5 + source->setTileAndDataNoUpdate(pos, FullTile(m_ID, data & ~C_UPDATE_LEAF_BIT)); // equates to -5 } } -void LeafTile::_tickDecay(Level* level, const TilePos& pos) +void LeafTile::_tickDecay(TileSource* source, const TilePos& pos) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); if ((data & C_UPDATE_LEAF_BIT) == 0) return; @@ -128,7 +129,7 @@ void LeafTile::_tickDecay(Level* level, const TilePos& pos) if (!m_checkBuffer) m_checkBuffer = new int[C_RANGE * C_RANGE * C_RANGE]; - if (level->hasChunksAt(pos - (C_REQUIRED_WOOD_RANGE + 1), pos + (C_REQUIRED_WOOD_RANGE + 1))) + if (source->hasChunksAt(pos - (C_REQUIRED_WOOD_RANGE + 1), pos + (C_REQUIRED_WOOD_RANGE + 1))) { TilePos curr(pos); for (int i2 = -C_REQUIRED_WOOD_RANGE; i2 <= C_REQUIRED_WOOD_RANGE; i2++) @@ -140,7 +141,7 @@ void LeafTile::_tickDecay(Level* level, const TilePos& pos) for (int k = -C_REQUIRED_WOOD_RANGE; k <= C_REQUIRED_WOOD_RANGE; k++) { curr.z = pos.z + k; - TileID tile = level->getTile(curr); + TileID tile = source->getTile(curr); m_checkBuffer[(i2 + k1) * j1 + (j + k1) * C_RANGE + k + k1] = tile == Tile::treeTrunk->m_ID ? 0 : tile == Tile::leaves->m_ID ? -2 : -1; } } @@ -181,18 +182,18 @@ void LeafTile::_tickDecay(Level* level, const TilePos& pos) } if (m_checkBuffer[k1 * j1 + k1 * C_RANGE + k1] < 0) - die(level, pos); + die(source, pos); else - level->setDataNoUpdate(pos, data & ~C_UPDATE_LEAF_BIT); + source->setTileAndDataNoUpdate(pos, FullTile(m_ID, data & ~C_UPDATE_LEAF_BIT)); } -void LeafTile::die(Level* level, const TilePos& pos) +void LeafTile::die(TileSource* source, const TilePos& pos) { - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); } -int LeafTile::getColor(const LevelSource* level, const TilePos& pos) const +int LeafTile::getColor(TileSource* source, const TilePos& pos) const { if (GetPatchManager()->IsGrassTinted()) { @@ -215,13 +216,13 @@ bool LeafTile::isSolidRender() const return !m_bTransparent; } -void LeafTile::stepOn(Level* level, const TilePos& pos, Entity* entity) +void LeafTile::stepOn(TileSource* source, const TilePos& pos, Entity* entity) { } -void LeafTile::onRemove(Level* level, const TilePos& pos) +void LeafTile::onRemove(TileSource* source, const TilePos& pos) { - if (!level->hasChunksAt(pos - 2, pos + 2)) + if (!source->hasChunksAt(pos - 2, pos + 2)) return; TilePos o(-1, -1, -1); @@ -231,21 +232,21 @@ void LeafTile::onRemove(Level* level, const TilePos& pos) { for (o.z = -1; o.z < 2; o.z++) { - TileID tile = level->getTile(pos + o); + TileID tile = source->getTile(pos + o); if (tile != Tile::leaves->m_ID) continue; - level->setDataNoUpdate(pos + o, level->getData(pos + o) | C_UPDATE_LEAF_BIT); + source->setTileAndDataNoUpdate(pos + o, FullTile(m_ID, source->getData(pos + o) | C_UPDATE_LEAF_BIT)); } } } } -void LeafTile::tick(Level* level, const TilePos& pos, Random* random) +void LeafTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->m_bIsClientSide) + if (source->getLevelConst().m_bIsClientSide) return; - _tickDecay(level, pos); + _tickDecay(source, pos); } int LeafTile::getResource(TileData data, Random* random) const diff --git a/source/world/tile/LeafTile.hpp b/source/world/tile/LeafTile.hpp index 2cfda1b69..88851c613 100644 --- a/source/world/tile/LeafTile.hpp +++ b/source/world/tile/LeafTile.hpp @@ -20,20 +20,22 @@ class LeafTile : public TransparentTile ~LeafTile(); private: - void _tickDecayOld(Level* level, const TilePos& pos); // circa 0.1.0 - void _tickDecay(Level* level, const TilePos& pos); /// circa b1.7.3 + void _tickDecayOld(TileSource* level, const TilePos& pos); // circa 0.1.0 + void _tickDecay(TileSource* level, const TilePos& pos); /// circa b1.7.3 public: - int getColor(const LevelSource*, const TilePos& pos) const override; + int getColor(TileSource*, const TilePos& pos) const override; int getTexture(Facing::Name face, TileData data) const override; bool isSolidRender() const override; - void onRemove(Level*, const TilePos& pos) override; - void stepOn(Level*, const TilePos& pos, Entity*) override; - void tick(Level*, const TilePos& pos, Random*) override; + void onRemove(TileSource*, const TilePos& pos) override; + void stepOn(TileSource*, const TilePos& pos, Entity*) override; + void tick(TileSource*, const TilePos& pos, Random*) override; int getResource(TileData data, Random* random) const override; int getSpawnResourcesAuxValue(int x) const override; - void die(Level*, const TilePos& pos); + void die(TileSource*, const TilePos& pos); + + static bool isDeepLeafTile(TileSource&, const TilePos&); public: int* m_checkBuffer; diff --git a/source/world/tile/LiquidTile.cpp b/source/world/tile/LiquidTile.cpp index f6314e4f8..809f2ecbe 100644 --- a/source/world/tile/LiquidTile.cpp +++ b/source/world/tile/LiquidTile.cpp @@ -8,6 +8,7 @@ #include "LiquidTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" LiquidTile::LiquidTile(int id, Material* pMtl) : Tile(id, pMtl == Material::lava ? TEXTURE_LAVA : TEXTURE_WATER, pMtl) { @@ -19,73 +20,73 @@ LiquidTile::LiquidTile(int id, Material* pMtl) : Tile(id, pMtl == Material::lava setTicking(true); } -void LiquidTile::animateTick(Level* level, const TilePos& pos, Random* random) +void LiquidTile::animateTick(TileSource* source, const TilePos& pos, Random* random) { if (m_pMaterial == Material::water) { if (!random->nextInt(64)) // @BUG: Return value unused. - level->getData(pos); + source->getData(pos); } // @BUG: Redundant check for isSolidTile? - if (m_pMaterial == Material::lava && level->getMaterial(pos.above()) == Material::air && !level->isSolidTile(pos.above()) && !random->nextInt(3)) + if (m_pMaterial == Material::lava && source->getMaterial(pos.above()) == Material::air && !source->isSolidBlockingTile(pos.above()) && !random->nextInt(3)) { - level->addParticle("lava", Vec3(pos.x + random->nextFloat(), pos.y + m_aabb.max.y, pos.z + random->nextFloat())); + source->getLevel().addParticle("lava", Vec3(pos.x + random->nextFloat(), pos.y + m_aabb.max.y, pos.z + random->nextFloat())); } } -void LiquidTile::fizz(Level* level, const TilePos& pos) +void LiquidTile::fizz(TileSource* source, const TilePos& pos) { for (int i = 0; i < 8; i++) { - level->addParticle("largesmoke", Vec3(pos.x + Mth::random(), pos.y + 1.2f, pos.z + Mth::random())); + source->getLevel().addParticle("largesmoke", Vec3(pos.x + Mth::random(), pos.y + 1.2f, pos.z + Mth::random())); } } -AABB* LiquidTile::getAABB(const Level*, const TilePos& pos) +AABB* LiquidTile::getAABB(TileSource* source, const TilePos& pos) { return nullptr; } -float LiquidTile::getBrightness(const LevelSource* level, const TilePos& pos) const +float LiquidTile::getBrightness(TileSource* source, const TilePos& pos) const { - float b1 = level->getBrightness(pos); - float b2 = level->getBrightness(pos.above()); + float b1 = source->getBrightness(pos); + float b2 = source->getBrightness(pos.above()); if (b1 <= b2) b1 = b2; return b1; } -int LiquidTile::getColor(const LevelSource* level, const TilePos& pos) const +int LiquidTile::getColor(TileSource* source, const TilePos& pos) const { return 0x999999FF; } -int LiquidTile::getDepth(Level* level, const TilePos& pos) +int LiquidTile::getDepth(TileSource* source, const TilePos& pos) { - if (level->getMaterial(pos) != m_pMaterial) + if (source->getMaterial(pos) != m_pMaterial) return -1; - return level->getData(pos); + return source->getData(pos); } -int LiquidTile::getRenderedDepth(const LevelSource* level, const TilePos& pos) const +int LiquidTile::getRenderedDepth(TileSource* source, const TilePos& pos) const { - if (level->getMaterial(pos) != m_pMaterial) + if (source->getMaterial(pos) != m_pMaterial) return -1; - int res = level->getData(pos); + int res = source->getData(pos); if (res > 7) res = 0; return res; } -Vec3 LiquidTile::getFlow(const LevelSource* level, const TilePos& pos) const +Vec3 LiquidTile::getFlow(TileSource* source, const TilePos& pos) const { Vec3 result; - int depthLocal = getRenderedDepth(level, pos); + int depthLocal = getRenderedDepth(source, pos); for (int i = 0; i < 4; i++) { TilePos check(pos); @@ -97,13 +98,13 @@ Vec3 LiquidTile::getFlow(const LevelSource* level, const TilePos& pos) const case 3: check.z++; break; } - int depthCheck = getRenderedDepth(level, check); + int depthCheck = getRenderedDepth(source, check); if (depthCheck < 0) { - if (level->getMaterial(check)->blocksMotion()) + if (source->getMaterial(check)->blocksMotion()) continue; - depthCheck = getRenderedDepth(level, TilePos(check.x, check.y - 1, check.z)); + depthCheck = getRenderedDepth(source, TilePos(check.x, check.y - 1, check.z)); if (depthCheck >= 0) { int mult = depthCheck - (depthLocal - 8); @@ -121,16 +122,16 @@ Vec3 LiquidTile::getFlow(const LevelSource* level, const TilePos& pos) const } } - if (level->getData(pos) >= 8) + if (source->getData(pos) >= 8) { - if (shouldRenderFace(level, pos.north(), Facing::NORTH) || - shouldRenderFace(level, pos.south(), Facing::SOUTH) || - shouldRenderFace(level, pos.west(), Facing::WEST) || - shouldRenderFace(level, pos.east(), Facing::EAST) || - shouldRenderFace(level, pos.above().north(), Facing::NORTH) || - shouldRenderFace(level, pos.above().south(), Facing::SOUTH) || - shouldRenderFace(level, pos.above().west(), Facing::WEST) || - shouldRenderFace(level, pos.above().east(), Facing::EAST)) + if (shouldRenderFace(source, pos.north(), Facing::NORTH) || + shouldRenderFace(source, pos.south(), Facing::SOUTH) || + shouldRenderFace(source, pos.west(), Facing::WEST) || + shouldRenderFace(source, pos.east(), Facing::EAST) || + shouldRenderFace(source, pos.above().north(), Facing::NORTH) || + shouldRenderFace(source, pos.above().south(), Facing::SOUTH) || + shouldRenderFace(source, pos.above().west(), Facing::WEST) || + shouldRenderFace(source, pos.above().east(), Facing::EAST)) { result = result.normalize() + Vec3(0, -6, 0); } @@ -154,13 +155,13 @@ int LiquidTile::getResourceCount(Random* random) const return 0; } -float LiquidTile::getSlopeAngle(const LevelSource* level, const TilePos& pos, const Material* pMtl) +float LiquidTile::getSlopeAngle(TileSource* source, const TilePos& pos, const Material* pMtl) { Vec3 vec; if (pMtl == Material::water) - vec = ((LiquidTile*)Tile::water)->getFlow(level, pos); + vec = ((LiquidTile*)Tile::water)->getFlow(source, pos); if (pMtl == Material::lava) - vec = ((LiquidTile*)Tile::lava)->getFlow(level, pos); + vec = ((LiquidTile*)Tile::lava)->getFlow(source, pos); if (vec.x == 0 && vec.z == 0) return -1000.0f; @@ -192,9 +193,9 @@ int LiquidTile::getTickDelay() const return 0; } -void LiquidTile::handleEntityInside(Level* level, const TilePos& pos, const Entity* pEnt, Vec3& vec) +void LiquidTile::handleEntityInside(TileSource* source, const TilePos& pos, const Entity* pEnt, Vec3& vec) { - vec += getFlow(level, pos); + vec += getFlow(source, pos); } bool LiquidTile::isCubeShaped() const @@ -215,49 +216,49 @@ bool LiquidTile::mayPick(TileData data, bool b) const return data == 0; } -void LiquidTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void LiquidTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - updateLiquid(level, pos); + updateLiquid(source, pos); } -void LiquidTile::onPlace(Level* level, const TilePos& pos) +void LiquidTile::onPlace(TileSource* source, const TilePos& pos) { - updateLiquid(level, pos); + updateLiquid(source, pos); } -bool LiquidTile::shouldRenderFace(const LevelSource* level, const TilePos& pos, Facing::Name face) const +bool LiquidTile::shouldRenderFace(TileSource* source, const TilePos& pos, Facing::Name face) const { - Material* pMtl = level->getMaterial(pos); + Material* pMtl = source->getMaterial(pos); if (pMtl == m_pMaterial || pMtl == Material::ice) return false; if (face == Facing::UP) return true; - return Tile::shouldRenderFace(level, pos, face); + return Tile::shouldRenderFace(source, pos, face); } -void LiquidTile::tick(Level*, const TilePos& pos, Random* random) +void LiquidTile::tick(TileSource* source, const TilePos& pos, Random* random) { } -void LiquidTile::updateLiquid(Level* level, const TilePos& pos) +void LiquidTile::updateLiquid(TileSource* source, const TilePos& pos) { - if (level->getTile(pos) != m_ID) + if (source->getTile(pos) != m_ID) return; if (m_pMaterial != Material::lava) // such interactions do not apply to water return; - if (level->getMaterial(pos.north()) == Material::water || - level->getMaterial(pos.south()) == Material::water || - level->getMaterial(pos.west()) == Material::water || - level->getMaterial(pos.east()) == Material::water || - level->getMaterial(pos.above()) == Material::water) + if (source->getMaterial(pos.north()) == Material::water || + source->getMaterial(pos.south()) == Material::water || + source->getMaterial(pos.west()) == Material::water || + source->getMaterial(pos.east()) == Material::water || + source->getMaterial(pos.above()) == Material::water) { Tile* newTile; - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (data == 0) { @@ -266,7 +267,7 @@ void LiquidTile::updateLiquid(Level* level, const TilePos& pos) else if (data > 4) { // @NOTE: huh? - fizz(level, pos); + fizz(source, pos); return; } else @@ -274,8 +275,8 @@ void LiquidTile::updateLiquid(Level* level, const TilePos& pos) newTile = Tile::stoneBrick; } - level->setTile(pos, newTile->m_ID); + source->setTile(pos, newTile->m_ID); - fizz(level, pos); + fizz(source, pos); } } diff --git a/source/world/tile/LiquidTile.hpp b/source/world/tile/LiquidTile.hpp index 24d8f2788..889bb0832 100644 --- a/source/world/tile/LiquidTile.hpp +++ b/source/world/tile/LiquidTile.hpp @@ -15,34 +15,32 @@ class LiquidTile : public Tile public: LiquidTile(int ID, Material*); -public: - void onPlace(Level*, const TilePos& pos) override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - void tick(Level*, const TilePos& pos, Random* random) override; - void animateTick(Level*, const TilePos& pos, Random* random) override; - AABB* getAABB(const Level*, const TilePos& pos) override; - float getBrightness(const LevelSource*, const TilePos& pos) const override; + void onPlace(TileSource*, const TilePos& pos) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + void tick(TileSource*, const TilePos& pos, Random* random) override; + void animateTick(TileSource*, const TilePos& pos, Random* random) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; + float getBrightness(TileSource*, const TilePos& pos) const override; eRenderShape getRenderShape() const override; int getResource(TileData, Random*) const override; int getResourceCount(Random*) const override; int getTexture(Facing::Name face) const override; int getTexture(Facing::Name face, TileData data) const override; int getTickDelay() const override; - void handleEntityInside(Level*, const TilePos& pos, const Entity*, Vec3&) override; + void handleEntityInside(TileSource*, const TilePos& pos, const Entity*, Vec3&) override; bool isCubeShaped() const override; bool isSolidRender() const override; bool mayPick(TileData data, bool b) const override; - bool shouldRenderFace(const LevelSource*, const TilePos& pos, Facing::Name face) const override; + bool shouldRenderFace(TileSource*, const TilePos& pos, Facing::Name face) const override; - void updateLiquid(Level*, const TilePos& pos); - void fizz(Level*, const TilePos& pos); - int getColor(const LevelSource*, const TilePos& pos) const override; - int getDepth(Level*, const TilePos& pos); - int getRenderedDepth(const LevelSource*, const TilePos& pos) const; - Vec3 getFlow(const LevelSource*, const TilePos& pos) const; + void updateLiquid(TileSource*, const TilePos& pos); + void fizz(TileSource*, const TilePos& pos); + int getColor(TileSource*, const TilePos& pos) const override; + int getDepth(TileSource*, const TilePos& pos); + int getRenderedDepth(TileSource*, const TilePos& pos) const; + Vec3 getFlow(TileSource*, const TilePos& pos) const; -public: - static float getSlopeAngle(const LevelSource*, const TilePos& pos, const Material* pMtl); + static float getSlopeAngle(TileSource*, const TilePos& pos, const Material* pMtl); // @NOTE: This is inlined in minecraftcpp static float getWaterVolume(TileData data) diff --git a/source/world/tile/LiquidTileDynamic.cpp b/source/world/tile/LiquidTileDynamic.cpp index cd8eeded8..5e4b5d010 100644 --- a/source/world/tile/LiquidTileDynamic.cpp +++ b/source/world/tile/LiquidTileDynamic.cpp @@ -8,6 +8,8 @@ #include "LiquidTileDynamic.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/TileTickingQueue.hpp" constexpr bool g_bDisableSponges = true; // disable sponges for now @@ -15,7 +17,7 @@ LiquidTileDynamic::LiquidTileDynamic(int id, Material* pMtl) : LiquidTile(id, pM { } -bool LiquidTileDynamic::checkSpongesNearby(Level* level, const TilePos& pos) +bool LiquidTileDynamic::checkSpongesNearby(TileSource* source, const TilePos& pos) { // NOTE: I imagine this could get slow. So you can disable it if (g_bDisableSponges) @@ -27,7 +29,7 @@ bool LiquidTileDynamic::checkSpongesNearby(Level* level, const TilePos& pos) { for (int oz = -2; oz <= 2; oz++) { - if (level->getTile(TilePos(pos.x + ox, pos.y + oy, pos.z + oz)) == Tile::sponge->m_ID) + if (source->getTile(TilePos(pos.x + ox, pos.y + oy, pos.z + oz)) == Tile::sponge->m_ID) return true; } } @@ -36,15 +38,15 @@ bool LiquidTileDynamic::checkSpongesNearby(Level* level, const TilePos& pos) return false; } -bool LiquidTileDynamic::isWaterBlocking(Level* level, const TilePos& pos) +bool LiquidTileDynamic::isWaterBlocking(TileSource* source, const TilePos& pos) { - TileID tile = level->getTile(pos); + TileID tile = source->getTile(pos); if (tile == Tile::reeds->m_ID) return true; if (!g_bDisableSponges) { - if (checkSpongesNearby(level, pos)) + if (checkSpongesNearby(source, pos)) return true; } @@ -54,16 +56,16 @@ bool LiquidTileDynamic::isWaterBlocking(Level* level, const TilePos& pos) return Tile::tiles[tile]->m_pMaterial->isSolid(); } -bool LiquidTileDynamic::canSpreadTo(Level* level, const TilePos& pos) +bool LiquidTileDynamic::canSpreadTo(TileSource* source, const TilePos& pos) { - Material* pMtl = level->getMaterial(pos); + Material* pMtl = source->getMaterial(pos); if (pMtl == m_pMaterial || pMtl == Material::lava) return false; - return !isWaterBlocking(level, pos); + return !isWaterBlocking(source, pos); } -int LiquidTileDynamic::getSlopeDistance(Level* level, const TilePos& pos, int depth, int a7) +int LiquidTileDynamic::getSlopeDistance(TileSource* source, const TilePos& pos, int depth, int a7) { int cost = 1000; @@ -81,20 +83,20 @@ int LiquidTileDynamic::getSlopeDistance(Level* level, const TilePos& pos, int de case 3: check.z++; break; } - if (isWaterBlocking(level, check)) + if (isWaterBlocking(source, check)) continue; - if (level->getMaterial(check) == m_pMaterial && - level->getData(check) == 0) + if (source->getMaterial(check) == m_pMaterial && + source->getData(check) == 0) continue; - if (!isWaterBlocking(level, TilePos(check.x, check.y - 1, check.z))) + if (!isWaterBlocking(source, TilePos(check.x, check.y - 1, check.z))) return depth; if (depth >= 4) continue; - int otherCost = getSlopeDistance(level, check, depth + 1, i); + int otherCost = getSlopeDistance(source, check, depth + 1, i); if (cost > otherCost) cost = otherCost; } @@ -102,7 +104,7 @@ int LiquidTileDynamic::getSlopeDistance(Level* level, const TilePos& pos, int de return cost; } -bool* LiquidTileDynamic::getSpread(Level* level, const TilePos& pos) +bool* LiquidTileDynamic::getSpread(TileSource* source, const TilePos& pos) { for (int i = 0; i < 4; i++) { @@ -126,15 +128,15 @@ bool* LiquidTileDynamic::getSpread(Level* level, const TilePos& pos) break; } - if (isWaterBlocking(level, chk)) + if (isWaterBlocking(source, chk)) continue; - if (level->getMaterial(chk) == m_pMaterial && - level->getData(chk) == 0) + if (source->getMaterial(chk) == m_pMaterial && + source->getData(chk) == 0) continue; - if (isWaterBlocking(level, TilePos(chk.x, chk.y - 1, chk.z))) - field_74[i] = getSlopeDistance(level, chk, 1, i); + if (isWaterBlocking(source, TilePos(chk.x, chk.y - 1, chk.z))) + field_74[i] = getSlopeDistance(source, chk, 1, i); else field_74[i] = 0; } @@ -154,49 +156,49 @@ bool* LiquidTileDynamic::getSpread(Level* level, const TilePos& pos) return field_70; } -void LiquidTileDynamic::onPlace(Level* level, const TilePos& pos) +void LiquidTileDynamic::onPlace(TileSource* source, const TilePos& pos) { - updateLiquid(level, pos); + updateLiquid(source, pos); - if (level->getTile(pos) == m_ID) + if (source->getTile(pos) == m_ID) { - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); } } -void LiquidTileDynamic::setStatic(Level* level, const TilePos& pos) +void LiquidTileDynamic::setStatic(TileSource* source, const TilePos& pos) { - TileData data = level->getData(pos); - level->setTileAndDataNoUpdate(pos, m_ID + 1, data); - level->setTilesDirty(pos, pos); - level->sendTileUpdated(pos); + TileData data = source->getData(pos); + source->setTileAndDataNoUpdate(pos, FullTile(m_ID + 1, data)); + //level->setTilesDirty(pos, pos); + //level->sendTileUpdated(pos); } -void LiquidTileDynamic::trySpreadTo(Level* level, const TilePos& pos, TileData data) +void LiquidTileDynamic::trySpreadTo(TileSource* source, const TilePos& pos, TileData data) { - if (!canSpreadTo(level, pos)) + if (!canSpreadTo(source, pos)) return; - TileID tile = level->getTile(pos); + TileID tile = source->getTile(pos); if (tile > 0) { if (m_pMaterial == Material::lava) { - fizz(level, pos); + fizz(source, pos); } else { - Tile::tiles[tile]->spawnResources(level, pos, level->getData(pos)); + Tile::tiles[tile]->spawnResources(source, pos, source->getData(pos)); } } - level->setTileAndData(pos, m_ID, data); + source->setTileAndData(pos, FullTile(m_ID, data)); } // @NOTE: This is inlined in PE. -int LiquidTileDynamic::getSmallestDepth(Level* level, const TilePos& pos, int oldDepth) +int LiquidTileDynamic::getSmallestDepth(TileSource* source, const TilePos& pos, int oldDepth) { - int depth = getDepth(level, pos); + int depth = getDepth(source, pos); if (depth < 0) return oldDepth; @@ -209,11 +211,11 @@ int LiquidTileDynamic::getSmallestDepth(Level* level, const TilePos& pos, int ol return oldDepth >= 0 && depth >= oldDepth ? oldDepth : depth; } -void LiquidTileDynamic::tick(Level* level, const TilePos& pos, Random* random) +void LiquidTileDynamic::tick(TileSource* source, const TilePos& pos, Random* random) { - int depth = getDepth(level, pos); + int depth = getDepth(source, pos); int speed; - if (m_pMaterial != Material::lava || level->m_pDimension->m_bUltraWarm) + if (m_pMaterial != Material::lava || source->getDimensionConst().isWarm()) speed = 1; else speed = 2; @@ -226,18 +228,18 @@ void LiquidTileDynamic::tick(Level* level, const TilePos& pos, Random* random) field_6C = 0; depthMax = -100; - depthMax = getSmallestDepth(level, pos.west(), depthMax); - depthMax = getSmallestDepth(level, pos.east(), depthMax); - depthMax = getSmallestDepth(level, pos.north(), depthMax); - depthMax = getSmallestDepth(level, pos.south(), depthMax); + depthMax = getSmallestDepth(source, pos.west(), depthMax); + depthMax = getSmallestDepth(source, pos.east(), depthMax); + depthMax = getSmallestDepth(source, pos.north(), depthMax); + depthMax = getSmallestDepth(source, pos.south(), depthMax); newData = speed + depthMax; if (newData > 7 || newData < 0) newData = -1; - if (getDepth(level, pos.above()) >= 0) + if (getDepth(source, pos.above()) >= 0) { - int depthUp = getDepth(level, pos.above()); + int depthUp = getDepth(source, pos.above()); if (depthUp >= 8) newData = depthUp; else @@ -246,13 +248,13 @@ void LiquidTileDynamic::tick(Level* level, const TilePos& pos, Random* random) if (field_6C >= 2 && m_pMaterial == Material::water) { - if (level->isSolidTile(pos.below())) + if (source->isSolidBlockingTile(pos.below())) { newData = 0; } - else if (m_pMaterial == level->getMaterial(pos.below())) + else if (m_pMaterial == source->getMaterial(pos.below())) { - if (!level->getData(pos.below())) + if (source->getData(pos.below()) == 0) newData = 0; } } @@ -268,36 +270,36 @@ void LiquidTileDynamic::tick(Level* level, const TilePos& pos, Random* random) depth = newData; if (depth < 0) { - level->setTile(pos, 0); + source->setTile(pos, 0); } else { - level->setData(pos, depth); - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->setTileAndData(pos, FullTile(m_ID, depth)); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); } } else if (flag) { - setStatic(level, pos); + setStatic(source, pos); } } else { - setStatic(level, pos); + setStatic(source, pos); } - if (canSpreadTo(level, pos.below())) + if (canSpreadTo(source, pos.below())) { if (depth < 8) depth += 8; - level->setTileAndData(pos.below(), m_ID, depth); + source->setTileAndData(pos.below(), FullTile(m_ID, depth)); return; } - if (depth >= 0 && (depth == 0 || isWaterBlocking(level, pos.below()))) + if (depth >= 0 && (depth == 0 || isWaterBlocking(source, pos.below()))) { - bool* bSpread = getSpread(level, pos); + bool* bSpread = getSpread(source, pos); TileData data = depth + speed; if (depth >= 8) @@ -306,9 +308,9 @@ void LiquidTileDynamic::tick(Level* level, const TilePos& pos, Random* random) if (data >= 8) return; - if (bSpread[0]) trySpreadTo(level, pos.west(), data); - if (bSpread[1]) trySpreadTo(level, pos.east(), data); - if (bSpread[2]) trySpreadTo(level, pos.north(), data); - if (bSpread[3]) trySpreadTo(level, pos.south(), data); + if (bSpread[0]) trySpreadTo(source, pos.west(), data); + if (bSpread[1]) trySpreadTo(source, pos.east(), data); + if (bSpread[2]) trySpreadTo(source, pos.north(), data); + if (bSpread[3]) trySpreadTo(source, pos.south(), data); } } diff --git a/source/world/tile/LiquidTileDynamic.hpp b/source/world/tile/LiquidTileDynamic.hpp index 2718f5ec3..a5027340f 100644 --- a/source/world/tile/LiquidTileDynamic.hpp +++ b/source/world/tile/LiquidTileDynamic.hpp @@ -15,16 +15,15 @@ class LiquidTileDynamic : public LiquidTile public: LiquidTileDynamic(int id, Material* pMtl); -public: - void onPlace(Level*, const TilePos& pos) override; - void tick(Level*, const TilePos& pos, Random*) override; + void onPlace(TileSource*, const TilePos& pos) override; + void tick(TileSource*, const TilePos& pos, Random*) override; - bool checkSpongesNearby(Level*, const TilePos& pos); - bool isWaterBlocking(Level*, const TilePos& pos); - bool canSpreadTo(Level*, const TilePos& pos); - int getSlopeDistance(Level*, const TilePos& pos, int depth, int); - bool* getSpread(Level*, const TilePos& pos); - void setStatic(Level*, const TilePos& pos); - void trySpreadTo(Level*, const TilePos& pos, TileData data); - int getSmallestDepth(Level*, const TilePos& pos, int oldDepth); + bool checkSpongesNearby(TileSource*, const TilePos& pos); + bool isWaterBlocking(TileSource*, const TilePos& pos); + bool canSpreadTo(TileSource*, const TilePos& pos); + int getSlopeDistance(TileSource*, const TilePos& pos, int depth, int); + bool* getSpread(TileSource*, const TilePos& pos); + void setStatic(TileSource*, const TilePos& pos); + void trySpreadTo(TileSource*, const TilePos& pos, TileData data); + int getSmallestDepth(TileSource*, const TilePos& pos, int oldDepth); }; diff --git a/source/world/tile/LiquidTileStatic.cpp b/source/world/tile/LiquidTileStatic.cpp index 1e63112ce..d7ba8eca4 100644 --- a/source/world/tile/LiquidTileStatic.cpp +++ b/source/world/tile/LiquidTileStatic.cpp @@ -7,7 +7,8 @@ ********************************************************************/ #include "LiquidTileStatic.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/TileTickingQueue.hpp" LiquidTileStatic::LiquidTileStatic(int id, Material* pMtl) : LiquidTile(id, pMtl) { @@ -16,28 +17,26 @@ LiquidTileStatic::LiquidTileStatic(int id, Material* pMtl) : LiquidTile(id, pMtl setTicking(true); } -bool LiquidTileStatic::isFlammable(Level* level, const TilePos& pos) +bool LiquidTileStatic::isFlammable(TileSource* source, const TilePos& pos) { - return level->getMaterial(pos)->isFlammable(); + return source->getMaterial(pos)->isFlammable(); } -void LiquidTileStatic::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void LiquidTileStatic::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - updateLiquid(level, pos); - if (level->getTile(pos) == m_ID) - setDynamic(level, pos); + updateLiquid(source, pos); + if (source->getTile(pos) == m_ID) + setDynamic(source, pos); } -void LiquidTileStatic::setDynamic(Level* level, const TilePos& pos) +void LiquidTileStatic::setDynamic(TileSource* source, const TilePos& pos) { - level->field_30 = true; - level->setTileAndDataNoUpdate(pos, m_ID - 1, level->getData(pos)); - level->setTilesDirty(pos, pos); - level->addToTickNextTick(pos, m_ID - 1, getTickDelay()); - level->field_30 = false; + source->setTileAndDataNoUpdate(pos, FullTile(m_ID - 1, source->getData(pos))); + //level->setTilesDirty(pos, pos); + source->getTickQueue(pos)->add(source, pos, m_ID - 1, getTickDelay()); } -void LiquidTileStatic::tick(Level* level, const TilePos& pos, Random* random) +void LiquidTileStatic::tick(TileSource* source, const TilePos& pos, Random* random) { if (m_pMaterial != Material::lava) return; @@ -49,21 +48,21 @@ void LiquidTileStatic::tick(Level* level, const TilePos& pos, Random* random) tp.x += random->genrand_int32() % 3 - 1; tp.z += random->genrand_int32() % 3 - 1; - TileID tile = level->getTile(tp.above()); + TileID tile = source->getTile(tp.above()); if (tile) { if (tiles[tile]->m_pMaterial->blocksMotion()) return; } else if ( - isFlammable(level, TilePos(tp.x - 1, tp.y + 1, tp.z)) || - isFlammable(level, TilePos(tp.x + 1, tp.y + 1, tp.z)) || - isFlammable(level, TilePos(tp.x, tp.y + 1, tp.z - 1)) || - isFlammable(level, TilePos(tp.x, tp.y + 1, tp.z + 1)) || - isFlammable(level, tp) || - isFlammable(level, TilePos(tp.x, tp.y + 2, tp.z))) + isFlammable(source, TilePos(tp.x - 1, tp.y + 1, tp.z)) || + isFlammable(source, TilePos(tp.x + 1, tp.y + 1, tp.z)) || + isFlammable(source, TilePos(tp.x, tp.y + 1, tp.z - 1)) || + isFlammable(source, TilePos(tp.x, tp.y + 1, tp.z + 1)) || + isFlammable(source, tp) || + isFlammable(source, TilePos(tp.x, tp.y + 2, tp.z))) { - level->setTile(tp.above(), Tile::fire->m_ID); + source->setTile(tp.above(), Tile::fire->m_ID); return; } diff --git a/source/world/tile/LiquidTileStatic.hpp b/source/world/tile/LiquidTileStatic.hpp index f8ee4ab8c..b62a6aa85 100644 --- a/source/world/tile/LiquidTileStatic.hpp +++ b/source/world/tile/LiquidTileStatic.hpp @@ -15,10 +15,9 @@ class LiquidTileStatic : public LiquidTile public: LiquidTileStatic(int id, Material* pMtl); -public: - void neighborChanged(Level* level, const TilePos& pos, TileID tile) override; - void tick(Level* level, const TilePos& pos, Random* random) override; + void neighborChanged(TileSource* source, const TilePos& pos, TileID tile) override; + void tick(TileSource* source, const TilePos& pos, Random* random) override; - bool isFlammable(Level*, const TilePos& pos); - void setDynamic(Level*, const TilePos& pos); + bool isFlammable(TileSource*, const TilePos& pos); + void setDynamic(TileSource*, const TilePos& pos); }; diff --git a/source/world/tile/PumpkinTile.cpp b/source/world/tile/PumpkinTile.cpp index c9481e442..f0e5fe96c 100644 --- a/source/world/tile/PumpkinTile.cpp +++ b/source/world/tile/PumpkinTile.cpp @@ -1,5 +1,6 @@ #include "PumpkinTile.hpp" -#include "world/level/Level.hpp" +#include "world/entity/Mob.hpp" +#include "world/level/TileSource.hpp" PumpkinTile::PumpkinTile(TileID id, bool lantern) : Tile(id, TEXTURE_PUMPKIN_TOP, Material::vegetable), m_bLantern(lantern) { @@ -23,7 +24,7 @@ int PumpkinTile::getTexture(Facing::Name face) const } } -void PumpkinTile::setPlacedBy(Level* level, const TilePos& pos, Mob* mob) +void PumpkinTile::setPlacedBy(TileSource* source, const TilePos& pos, Mob* mob) { int rot = Mth::floor(0.5f + (mob->m_rot.x * 4.0f / 360.0f)) & 3; @@ -37,5 +38,5 @@ void PumpkinTile::setPlacedBy(Level* level, const TilePos& pos, Mob* mob) case 3: data = 1; break; } - level->setData(pos, data); + source->setTileAndData(pos, FullTile(m_ID, data)); } diff --git a/source/world/tile/PumpkinTile.hpp b/source/world/tile/PumpkinTile.hpp index 166726adb..7cd32b685 100644 --- a/source/world/tile/PumpkinTile.hpp +++ b/source/world/tile/PumpkinTile.hpp @@ -10,7 +10,7 @@ class PumpkinTile : public Tile public: int getTexture(Facing::Name face, TileData data) const override; int getTexture(Facing::Name face) const override; - void setPlacedBy(Level*, const TilePos& pos, Mob*) override; + void setPlacedBy(TileSource*, const TilePos& pos, Mob*) override; public: bool m_bLantern; diff --git a/source/world/tile/RedStoneOreTile.cpp b/source/world/tile/RedStoneOreTile.cpp index 40f12c04e..ec4e8cca2 100644 --- a/source/world/tile/RedStoneOreTile.cpp +++ b/source/world/tile/RedStoneOreTile.cpp @@ -8,6 +8,7 @@ #include "RedStoneOreTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" RedStoneOreTile::RedStoneOreTile(TileID id, int texture, bool bLit) : Tile(id, texture, Material::stone) { @@ -31,45 +32,47 @@ int RedStoneOreTile::getSpawnResourcesAuxValue(int x) const return 0; } -int RedStoneOreTile::poofParticles(Level* level, const TilePos& pos) +int RedStoneOreTile::poofParticles(TileSource* source, const TilePos& pos) { + Level& level = source->getLevel(); + for (int i = 0; i < 6; i++) { - Vec3 o(float(pos.x) + level->m_random.nextFloat(), - float(pos.y) + level->m_random.nextFloat(), - float(pos.z) + level->m_random.nextFloat()); + Vec3 o(float(pos.x) + level.m_random.nextFloat(), + float(pos.y) + level.m_random.nextFloat(), + float(pos.z) + level.m_random.nextFloat()); switch (i) { case Facing::DOWN: - if (!level->isSolidTile(pos.above())) + if (!source->isSolidBlockingTile(pos.above())) o.y = float(pos.y + 1) + 0.0625f; break; case Facing::UP: - if (!level->isSolidTile(pos.below())) + if (!source->isSolidBlockingTile(pos.below())) o.y = float(pos.y) - 0.0625f; break; case Facing::NORTH: - if (!level->isSolidTile(pos.south())) + if (!source->isSolidBlockingTile(pos.south())) o.z = float(pos.z + 1) + 0.0625f; break; case Facing::SOUTH: - if (!level->isSolidTile(pos.north())) + if (!source->isSolidBlockingTile(pos.north())) o.z = float(pos.z) - 0.0625f; break; case Facing::WEST: - if (!level->isSolidTile(pos.east())) + if (!source->isSolidBlockingTile(pos.east())) o.x = float(pos.x + 1) + 0.0625f; break; case Facing::EAST: - if (!level->isSolidTile(pos.west())) + if (!source->isSolidBlockingTile(pos.west())) o.x = float(pos.x) - 0.0625f; break; } if (o.x < float(pos.x) || float(pos.x + 1) < o.x || o.y < 0.0f || float(pos.y + 1) < o.y || o.z < float(pos.z) || float(pos.z + 1) < o.z) { - level->addParticle("reddust", o); + level.addParticle("reddust", o); } } @@ -77,40 +80,40 @@ int RedStoneOreTile::poofParticles(Level* level, const TilePos& pos) return 1300; } -void RedStoneOreTile::animateTick(Level* level, const TilePos& pos, Random* random) +void RedStoneOreTile::animateTick(TileSource* source, const TilePos& pos, Random* random) { if (m_bLit) - poofParticles(level, pos); + poofParticles(source, pos); } -void RedStoneOreTile::tick(Level* level, const TilePos& pos, Random* random) +void RedStoneOreTile::tick(TileSource* source, const TilePos& pos, Random* random) { if (m_ID == Tile::redStoneOre_lit->m_ID) - level->setTile(pos, Tile::redStoneOre->m_ID); + source->setTile(pos, Tile::redStoneOre->m_ID); } -void RedStoneOreTile::interact(Level* level, const TilePos& pos) +void RedStoneOreTile::interact(TileSource* source, const TilePos& pos) { - poofParticles(level, pos); + poofParticles(source, pos); if (m_ID == Tile::redStoneOre->m_ID) - level->setTile(pos, Tile::redStoneOre_lit->m_ID); + source->setTile(pos, Tile::redStoneOre_lit->m_ID); } -void RedStoneOreTile::attack(Level* level, const TilePos& pos, Player* player) +void RedStoneOreTile::attack(TileSource* source, const TilePos& pos, Player* player) { - interact(level, pos); + interact(source, pos); } -bool RedStoneOreTile::use(Level* level, const TilePos& pos, Player* player) +bool RedStoneOreTile::use(const TilePos& pos, Player* player) { - interact(level, pos); - return Tile::use(level, pos, player); + interact(&player->getTileSource(), pos); + return Tile::use(pos, player); } -void RedStoneOreTile::stepOn(Level* level, const TilePos& pos, Entity* entity) +void RedStoneOreTile::stepOn(TileSource* source, const TilePos& pos, Entity* entity) { - interact(level, pos); + interact(source, pos); } int RedStoneOreTile::getTickDelay() const diff --git a/source/world/tile/RedStoneOreTile.hpp b/source/world/tile/RedStoneOreTile.hpp index 7c85d8c02..b871336de 100644 --- a/source/world/tile/RedStoneOreTile.hpp +++ b/source/world/tile/RedStoneOreTile.hpp @@ -20,14 +20,14 @@ class RedStoneOreTile : public Tile int getResourceCount(Random*) const override; int getSpawnResourcesAuxValue(int) const override; int getTickDelay() const override; - void animateTick(Level*, const TilePos& pos, Random*) override; - void tick(Level*, const TilePos& pos, Random*) override; - void attack(Level*, const TilePos& pos, Player*) override; - bool use(Level*, const TilePos& pos, Player*) override; - void stepOn(Level*, const TilePos& pos, Entity*) override; + void animateTick(TileSource*, const TilePos& pos, Random*) override; + void tick(TileSource*, const TilePos& pos, Random*) override; + void attack(TileSource*, const TilePos& pos, Player*) override; + bool use(const TilePos& pos, Player*) override; + void stepOn(TileSource*, const TilePos& pos, Entity*) override; - int poofParticles(Level*, const TilePos& pos); - void interact(Level*, const TilePos& pos); + int poofParticles(TileSource*, const TilePos& pos); + void interact(TileSource*, const TilePos& pos); public: bool m_bLit; diff --git a/source/world/tile/ReedTile.cpp b/source/world/tile/ReedTile.cpp index fbbf60fc5..20569a0d5 100644 --- a/source/world/tile/ReedTile.cpp +++ b/source/world/tile/ReedTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "ReedTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" ReedTile::ReedTile(TileID id) : Tile(id, Material::plant) { @@ -32,9 +32,9 @@ bool ReedTile::isSolidRender() const return false; } -bool ReedTile::mayPlace(const Level* level, const TilePos& pos) const +bool ReedTile::mayPlace(TileSource* source, const TilePos& pos) const { - TileID tileBelow = level->getTile(pos.below()); + TileID tileBelow = source->getTile(pos.below()); if (tileBelow == m_ID) return true; @@ -44,56 +44,56 @@ bool ReedTile::mayPlace(const Level* level, const TilePos& pos) const return false; return - level->getMaterial(pos.below().west()) == Material::water || - level->getMaterial(pos.below().east()) == Material::water || - level->getMaterial(pos.below().north()) == Material::water || - level->getMaterial(pos.below().south()) == Material::water; + source->getMaterial(pos.below().west()) == Material::water || + source->getMaterial(pos.below().east()) == Material::water || + source->getMaterial(pos.below().north()) == Material::water || + source->getMaterial(pos.below().south()) == Material::water; } -bool ReedTile::canSurvive(const Level* level, const TilePos& pos) const +bool ReedTile::canSurvive(TileSource* source, const TilePos& pos) const { - return mayPlace(level, pos); + return mayPlace(source, pos); } -void ReedTile::checkAlive(Level* level, const TilePos& pos) +void ReedTile::checkAlive(TileSource* source, const TilePos& pos) { - if (!canSurvive(level, pos)) + if (!canSurvive(source, pos)) { - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); } } -void ReedTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void ReedTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - return checkAlive(level, pos); + return checkAlive(source, pos); } -void ReedTile::tick(Level* level, const TilePos& pos, Random* random) +void ReedTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (!level->isEmptyTile(pos)) + if (!source->isEmptyTile(pos)) return; int height; - for (height = 1; level->getTile(TilePos(pos.x, pos.y - height, pos.z)) == m_ID; height++); + for (height = 1; source->getTile(TilePos(pos.x, pos.y - height, pos.z)) == m_ID; height++); if (height <= 2) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (data == 15) { - level->setTile(pos.above(), m_ID); - level->setData(pos, 0); + source->setTileAndData(pos.above(), FullTile(m_ID, 0)); + source->setTileAndData(pos, FullTile(m_ID, 0)); } else { - level->setData(pos, data + 1); + source->setTileAndData(pos, FullTile(m_ID, data + 1)); } } } -AABB* ReedTile::getAABB(const Level* level, const TilePos& pos) +AABB* ReedTile::getAABB(TileSource* source, const TilePos& pos) { return nullptr; } diff --git a/source/world/tile/ReedTile.hpp b/source/world/tile/ReedTile.hpp index 2f9b5a339..5df2e7a71 100644 --- a/source/world/tile/ReedTile.hpp +++ b/source/world/tile/ReedTile.hpp @@ -15,16 +15,15 @@ class ReedTile : public Tile public: ReedTile(TileID id); -public: - bool canSurvive(const Level*, const TilePos& pos) const override; - AABB* getAABB(const Level*, const TilePos& pos) override; + bool canSurvive(TileSource*, const TilePos& pos) const override; + AABB* getAABB(TileSource*, const TilePos& pos) override; eRenderShape getRenderShape() const override; bool isCubeShaped() const override; bool isSolidRender() const override; - bool mayPlace(const Level*, const TilePos& pos) const override; - void tick(Level*, const TilePos& pos, Random*) override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + void tick(TileSource*, const TilePos& pos, Random*) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; int getResource(TileData data, Random*) const override; - void checkAlive(Level*, const TilePos& pos); + void checkAlive(TileSource*, const TilePos& pos); }; diff --git a/source/world/tile/RocketLauncherTile.cpp b/source/world/tile/RocketLauncherTile.cpp index 5977c1584..df182fcdf 100644 --- a/source/world/tile/RocketLauncherTile.cpp +++ b/source/world/tile/RocketLauncherTile.cpp @@ -7,6 +7,8 @@ ********************************************************************/ #include "RocketLauncherTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/TileTickingQueue.hpp" #include "world/entity/Rocket.hpp" RocketLauncherTile::RocketLauncherTile(TileID id) : Tile(id, 16*14+2, Material::wood) @@ -20,7 +22,7 @@ int RocketLauncherTile::getTexture(Facing::Name face, TileData data) const return data == 1 ? 16*14+3 : 16*14+2; } -AABB* RocketLauncherTile::getAABB(const Level*, const TilePos& pos) +AABB* RocketLauncherTile::getAABB(TileSource*, const TilePos& pos) { return nullptr; } @@ -40,26 +42,29 @@ bool RocketLauncherTile::isSolidRender() const return false; } -bool RocketLauncherTile::use(Level* level, const TilePos& pos, Player* player) +bool RocketLauncherTile::use(const TilePos& pos, Player* player) { - if (level->getData(pos) == 1) + TileSource& source = player->getTileSource(); + + if (source.getData(pos) == 1) return true; - level->setData(pos, 1); + source.setTileAndData(pos, FullTile(m_ID, 1)); // spawn a rocket - level->addEntity(new Rocket(level, Vec3(pos) + 0.5f)); + Level& level = player->getLevel(); + level.addEntity(std::make_unique(source, Vec3(pos) + 0.5f)); // add a tick so that the rocket launcher will reset - level->addToTickNextTick(pos, m_ID, 10); + source.getTickQueue(pos)->add(&source, pos, m_ID, 10); return true; } -void RocketLauncherTile::tick(Level* level, const TilePos& pos, Random* random) +void RocketLauncherTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->getData(pos) != 1) + if (source->getData(pos) != 1) return; - level->setData(pos, 0); + source->setTileAndData(pos, FullTile(m_ID, 0)); } diff --git a/source/world/tile/RocketLauncherTile.hpp b/source/world/tile/RocketLauncherTile.hpp index 4de5899a2..3477a035b 100644 --- a/source/world/tile/RocketLauncherTile.hpp +++ b/source/world/tile/RocketLauncherTile.hpp @@ -17,10 +17,10 @@ class RocketLauncherTile : public Tile public: int getTexture(Facing::Name face, TileData data) const override; - AABB* getAABB(const Level*, const TilePos& pos) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; eRenderShape getRenderShape() const override; bool isCubeShaped() const override; bool isSolidRender() const override; - bool use(Level* pLevel, const TilePos& pos, Player* player) override; - void tick(Level*, const TilePos& pos, Random*) override; + bool use(const TilePos& pos, Player* player) override; + void tick(TileSource*, const TilePos& pos, Random*) override; }; diff --git a/source/world/tile/SandTile.cpp b/source/world/tile/SandTile.cpp index b5c2db192..17b9faf71 100644 --- a/source/world/tile/SandTile.cpp +++ b/source/world/tile/SandTile.cpp @@ -8,6 +8,7 @@ #include "SandTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "world/entity/FallingTile.hpp" //@NOTE: True for now @@ -26,45 +27,46 @@ int SandTile::getTickDelay() const return 3; } -void SandTile::checkSlide(Level* level, const TilePos& pos) +void SandTile::checkSlide(TileSource* source, const TilePos& pos) { //TileID tile = level->getTile(pos.below()); - if (!isFree(level, pos.below())) + if (!isFree(source, pos.below())) // standing on something, don't fall return; if (pos.y <= 0) return; - if (SandTile::instaFall || !level->hasChunksAt(TilePos(pos.x - 32, pos.y - 32, pos.z - 32), TilePos(pos.x + 32, pos.y + 32, pos.z + 32))) + if (SandTile::instaFall || !source->hasChunksAt(TilePos(pos.x - 32, pos.y - 32, pos.z - 32), TilePos(pos.x + 32, pos.y + 32, pos.z + 32))) { - level->setTile(pos, 0); + source->setTile(pos, TILE_AIR); int y2; for (y2 = pos.y - 1; y2 >= 0; y2--) { - if (!isFree(level, TilePos(pos.x, y2, pos.z))) + if (!isFree(source, TilePos(pos.x, y2, pos.z))) break; } if (y2 > -1) - level->setTile(TilePos(pos.x, y2 + 1, pos.z), m_ID); + source->setTile(TilePos(pos.x, y2 + 1, pos.z), m_ID); } else { // The original code attempts to spawn a falling tile entity, but it fails since it's not a player. // The falling sand tile #if defined(ORIGINAL_CODE) || defined(ENH_ALLOW_SAND_GRAVITY) - level->addEntity(new FallingTile(level, Vec3(float(pos.x) + 0.5f, float(pos.y) + 0.5f, float(pos.z) + 0.5f), m_ID)); + Level& level = source->getLevel(); + level.addEntity(new FallingTile(*source, Vec3(float(pos.x) + 0.5f, float(pos.y) + 0.5f, float(pos.z) + 0.5f), m_ID)); #endif } } -bool SandTile::isFree(Level* level, const TilePos& pos) +bool SandTile::isFree(TileSource* source, const TilePos& pos) { - TileID tile = level->getTile(pos); - if (!tile) + TileID tile = source->getTile(pos); + if (tile == TILE_AIR) return true; if (tile == Tile::fire->m_ID) @@ -79,25 +81,25 @@ bool SandTile::isFree(Level* level, const TilePos& pos) return false; } -void SandTile::tick(Level* level, const TilePos& pos, Random* random) +void SandTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->m_bIsClientSide) + if (source->getLevelConst().m_bIsClientSide) return; - checkSlide(level, pos); + checkSlide(source, pos); } -void SandTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void SandTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { #ifdef ENH_ALLOW_SAND_GRAVITY - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); #endif } -void SandTile::onPlace(Level* level, const TilePos& pos) +void SandTile::onPlace(TileSource* source, const TilePos& pos) { #ifdef ENH_ALLOW_SAND_GRAVITY - level->addToTickNextTick(pos, m_ID, getTickDelay()); + source->getTickQueue(pos)->add(source, pos, m_ID, getTickDelay()); #endif } diff --git a/source/world/tile/SandTile.hpp b/source/world/tile/SandTile.hpp index b953d6425..2519ab9c1 100644 --- a/source/world/tile/SandTile.hpp +++ b/source/world/tile/SandTile.hpp @@ -17,14 +17,14 @@ class SandTile : public Tile public: int getTickDelay() const override; - void tick(Level* level, const TilePos& pos, Random* random) override; - void neighborChanged(Level* level, const TilePos& pos, TileID tile) override; - void onPlace(Level* level, const TilePos& pos) override; + void tick(TileSource* source, const TilePos& pos, Random* random) override; + void neighborChanged(TileSource* source, const TilePos& pos, TileID tile) override; + void onPlace(TileSource* source, const TilePos& pos) override; - void checkSlide(Level* level, const TilePos& pos); + void checkSlide(TileSource* source, const TilePos& pos); public: - static bool isFree(Level* level, const TilePos& pos); + static bool isFree(TileSource* source, const TilePos& pos); public: static bool instaFall; diff --git a/source/world/tile/Sapling.cpp b/source/world/tile/Sapling.cpp index 4ce78bf9f..86bafcf78 100644 --- a/source/world/tile/Sapling.cpp +++ b/source/world/tile/Sapling.cpp @@ -7,7 +7,8 @@ ********************************************************************/ #include "Sapling.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" +#include "world/level/levelgen/feature/Feature.hpp" Sapling::Sapling(TileID id, int texture) : Bush(id, texture) { @@ -19,25 +20,25 @@ int Sapling::getTexture(Facing::Name face, TileData data) const return data == 1 ? 63 : (data == 2 ? 79 : Bush::getTexture(face, data)); } -void Sapling::tick(Level* level, const TilePos& pos, Random* random) +void Sapling::tick(TileSource* source, const TilePos& pos, Random* random) { - Bush::tick(level, pos, random); + Bush::tick(source, pos, random); - if (level->getRawBrightness(pos) > 8 && random->nextInt(7) == 0) + if (source->getRawBrightness(pos, true) > 8 && random->nextInt(7) == 0) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); if (data & 8) - growTree(level, pos, random); + growTree(source, pos, random); else - level->setDataNoUpdate(pos, data | 8); + source->setTileAndDataNoUpdate(pos, FullTile(m_ID, data | 8)); } } -void Sapling::growTree(Level* level, const TilePos& pos, Random* random) +void Sapling::growTree(TileSource* source, const TilePos& pos, Random* random) { - TileData data = level->getData(pos) & 3; - level->setTileNoUpdate(pos, TILE_AIR); + TileData data = source->getData(pos) & 3; + source->setTileNoUpdate(pos, TILE_AIR); TreeFeature treeFeature; @@ -53,8 +54,8 @@ void Sapling::growTree(Level* level, const TilePos& pos, Random* random) break; } - if (!pFeature->place(level, random, pos)) - level->setTileNoUpdate(pos, m_ID); + if (!pFeature->place(source, random, pos)) + source->setTileNoUpdate(pos, m_ID); } int Sapling::getSpawnResourcesAuxValue(int x) const diff --git a/source/world/tile/Sapling.hpp b/source/world/tile/Sapling.hpp index 6fc345c03..eda74158c 100644 --- a/source/world/tile/Sapling.hpp +++ b/source/world/tile/Sapling.hpp @@ -17,8 +17,8 @@ class Sapling : public Bush public: int getTexture(Facing::Name face, TileData data) const override; - void tick(Level*, const TilePos& pos, Random*) override; + void tick(TileSource*, const TilePos& pos, Random*) override; int getSpawnResourcesAuxValue(int x) const override; - void growTree(Level*, const TilePos& pos, Random*); + void growTree(TileSource*, const TilePos& pos, Random*); }; diff --git a/source/world/tile/SoulSandTile.cpp b/source/world/tile/SoulSandTile.cpp index 91cc8f72f..17c42c43f 100644 --- a/source/world/tile/SoulSandTile.cpp +++ b/source/world/tile/SoulSandTile.cpp @@ -1,19 +1,19 @@ #include "SoulSandTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" SoulSandTile::SoulSandTile(int id, int texture) : Tile(id, texture, Material::sand) { } -void SoulSandTile::entityInside(Level* level, const TilePos& pos, Entity* entity) const +void SoulSandTile::entityInside(TileSource* source, const TilePos& pos, Entity* entity) const { entity->m_vel.x *= 0.4; entity->m_vel.z *= 0.4; } -AABB* SoulSandTile::getAABB(const Level* pLevel, const TilePos& pos) +AABB* SoulSandTile::getAABB(TileSource* source, const TilePos& pos) { - AABB* rAABB = Tile::getAABB(pLevel, pos); + AABB* rAABB = Tile::getAABB(source, pos); rAABB->max.y -= 2 / 16.0; return rAABB; } diff --git a/source/world/tile/SoulSandTile.hpp b/source/world/tile/SoulSandTile.hpp index d49127af7..b88d91350 100644 --- a/source/world/tile/SoulSandTile.hpp +++ b/source/world/tile/SoulSandTile.hpp @@ -8,6 +8,6 @@ class SoulSandTile : public Tile SoulSandTile(int id, int texture); public: - void entityInside(Level* level, const TilePos& pos, Entity* entity) const override; - AABB* getAABB(const Level* pLevel, const TilePos& pos) override; + void entityInside(TileSource* source, const TilePos& pos, Entity* entity) const override; + AABB* getAABB(TileSource* source, const TilePos& pos) override; }; diff --git a/source/world/tile/SpongeTile.cpp b/source/world/tile/SpongeTile.cpp index d3802f46c..a9ffd700d 100644 --- a/source/world/tile/SpongeTile.cpp +++ b/source/world/tile/SpongeTile.cpp @@ -7,13 +7,13 @@ ********************************************************************/ #include "SpongeTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" SpongeTile::SpongeTile(TileID id, int texture) : Tile(id, texture, Material::sponge) { } -void SpongeTile::onPlace(Level* level, const TilePos& pos) +void SpongeTile::onPlace(TileSource* source, const TilePos& pos) { // get rid of all water in a 5x5 cube around this TilePos o; @@ -23,17 +23,17 @@ void SpongeTile::onPlace(Level* level, const TilePos& pos) { for (o.z = -2; o.z <= 2; o.z++) { - if (level->getTile(pos + o) == Tile::water->m_ID || - level->getTile(pos + o) == Tile::calmWater->m_ID) + if (source->getTile(pos + o) == Tile::water->m_ID || + source->getTile(pos + o) == Tile::calmWater->m_ID) { - level->setTile(pos + o, TILE_AIR); + source->setTile(pos + o, TILE_AIR); } } } } } -void SpongeTile::destroy(Level* level, const TilePos& pos, TileData data) +void SpongeTile::destroy(TileSource* source, const TilePos& pos, TileData data) { // give an update to all water around us TilePos o; @@ -43,10 +43,11 @@ void SpongeTile::destroy(Level* level, const TilePos& pos, TileData data) { for (o.z = -3; o.z <= 3; o.z++) { - if (level->getTile(pos + o) == Tile::water->m_ID || - level->getTile(pos + o) == Tile::calmWater->m_ID) + if (source->getTile(pos + o) == Tile::water->m_ID || + source->getTile(pos + o) == Tile::calmWater->m_ID) { - level->neighborChanged(pos + o, TILE_AIR); + // TODO + //level->neighborChanged(pos + o, TILE_AIR); } } } diff --git a/source/world/tile/SpongeTile.hpp b/source/world/tile/SpongeTile.hpp index d1e78701e..a1dfdff46 100644 --- a/source/world/tile/SpongeTile.hpp +++ b/source/world/tile/SpongeTile.hpp @@ -16,6 +16,6 @@ class SpongeTile : public Tile SpongeTile(TileID ID, int texture); public: - void onPlace(Level*, const TilePos& pos) override; - void destroy(Level*, const TilePos& pos, TileData data) override; + void onPlace(TileSource*, const TilePos& pos) override; + void destroy(TileSource*, const TilePos& pos, TileData data) override; }; diff --git a/source/world/tile/StairTile.cpp b/source/world/tile/StairTile.cpp index a715e5939..92021463c 100644 --- a/source/world/tile/StairTile.cpp +++ b/source/world/tile/StairTile.cpp @@ -8,6 +8,7 @@ #include "StairTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" // @NOTE: All this work for some stairs; damn @@ -24,41 +25,41 @@ StairTile::StairTile(int id, Tile* pTile) : Tile(id, pTile->m_TextureFrame, pTil setSoundType(*pTile->m_pSound); } -void StairTile::addAABBs(const Level* level, const TilePos& pos, const AABB* aabb, std::vector& out) +void StairTile::addAABBs(TileSource* source, const TilePos& pos, const AABB* aabb, std::vector& out) { - int data = level->getData(pos); + TileData data = source->getData(pos); switch (data) { case 0: { setShape(0.0f, 0.0f, 0.0f, 0.5f, 0.5f, 1.0f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); setShape(0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); break; } case 1: { setShape(0.0f, 0.0f, 0.0f, 0.5f, 1.0f, 1.0f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); setShape(0.5f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); break; } case 2: { setShape(0.0f, 0.0f, 0.0f, 1.0f, 0.5f, 0.5f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); setShape(0.0f, 0.0f, 0.5f, 1.0f, 1.0f, 1.0f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); break; } case 3: { setShape(0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); setShape(0.0f, 0.0f, 0.5f, 1.0f, 0.5f, 1.0f); - Tile::addAABBs(level, pos, aabb, out); + Tile::addAABBs(source, pos, aabb, out); break; } } @@ -81,24 +82,24 @@ eRenderShape StairTile::getRenderShape() const return SHAPE_STAIRS; } -void StairTile::addLights(Level* level, const TilePos& pos) +void StairTile::addLights(TileSource* source, const TilePos& pos) { - m_pParent->addLights(level, pos); + m_pParent->addLights(source, pos); } -void StairTile::animateTick(Level* level, const TilePos& pos, Random* random) +void StairTile::animateTick(TileSource* source, const TilePos& pos, Random* random) { - m_pParent->animateTick(level, pos, random); + m_pParent->animateTick(source, pos, random); } -void StairTile::updateShape(const LevelSource* level, const TilePos& pos) +void StairTile::updateShape(TileSource* source, const TilePos& pos) { setShape(0, 0, 0, 1, 1, 1); } -float StairTile::getBrightness(const LevelSource* level, const TilePos& pos) const +float StairTile::getBrightness(TileSource* source, const TilePos& pos) const { - return m_pParent->getBrightness(level, pos); + return m_pParent->getBrightness(source, pos); } int StairTile::getTexture(Facing::Name face) const @@ -111,14 +112,14 @@ int StairTile::getTexture(Facing::Name face, TileData data) const return m_pParent->getTexture(face, data); } -int StairTile::getTexture(const LevelSource* level, const TilePos& pos, Facing::Name face) const +int StairTile::getTexture(TileSource* source, const TilePos& pos, Facing::Name face) const { - return m_pParent->getTexture(level, pos, face); + return m_pParent->getTexture(source, pos, face); } -AABB StairTile::getTileAABB(const Level* level, const TilePos& pos) +AABB StairTile::getTileAABB(TileSource* source, const TilePos& pos) { - return m_pParent->getTileAABB(level, pos); + return m_pParent->getTileAABB(source, pos); } bool StairTile::mayPick() const @@ -131,9 +132,9 @@ bool StairTile::mayPick(TileData data, bool b) const return m_pParent->mayPick(data, b); } -bool StairTile::mayPlace(const Level* level, const TilePos& pos) const +bool StairTile::mayPlace(TileSource* source, const TilePos& pos) const { - return m_pParent->mayPlace(level, pos); + return m_pParent->mayPlace(source, pos); } int StairTile::getTickDelay() const @@ -141,25 +142,25 @@ int StairTile::getTickDelay() const return m_pParent->getTickDelay(); } -void StairTile::tick(Level* level, const TilePos& pos, Random* random) +void StairTile::tick(TileSource* source, const TilePos& pos, Random* random) { - m_pParent->tick(level, pos, random); + m_pParent->tick(source, pos, random); } -void StairTile::destroy(Level* level, const TilePos& pos, TileData data) +void StairTile::destroy(TileSource* source, const TilePos& pos, TileData data) { - m_pParent->destroy(level, pos, data); + m_pParent->destroy(source, pos, data); } -void StairTile::onPlace(Level* level, const TilePos& pos) +void StairTile::onPlace(TileSource* source, const TilePos& pos) { - neighborChanged(level, pos, Facing::DOWN); - m_pParent->onPlace(level, pos); + neighborChanged(source, pos, Facing::DOWN); + m_pParent->onPlace(source, pos); } -void StairTile::onRemove(Level* level, const TilePos& pos) +void StairTile::onRemove(TileSource* source, const TilePos& pos) { - m_pParent->onRemove(level, pos); + m_pParent->onRemove(source, pos); } float StairTile::getExplosionResistance(Entity* entity) const @@ -167,27 +168,27 @@ float StairTile::getExplosionResistance(Entity* entity) const return m_pParent->getExplosionResistance(entity); } -void StairTile::wasExploded(Level* level, const TilePos& pos) +void StairTile::wasExploded(TileSource* source, const TilePos& pos) { - return m_pParent->wasExploded(level, pos); + return m_pParent->wasExploded(source, pos); } -Tile::RenderLayer StairTile::getRenderLayer() const +Tile::RenderLayer StairTile::getRenderLayer(TileSource* source, const TilePos& pos) const { - return m_pParent->getRenderLayer(); + return m_pParent->getRenderLayer(source, pos); } -bool StairTile::use(Level* level, const TilePos& pos, Player* player) +bool StairTile::use(const TilePos& pos, Player* player) { - return m_pParent->use(level, pos, player); + return m_pParent->use(pos, player); } -void StairTile::stepOn(Level* level, const TilePos& pos, Entity* entity) +void StairTile::stepOn(TileSource* source, const TilePos& pos, Entity* entity) { - m_pParent->stepOn(level, pos, entity); + m_pParent->stepOn(source, pos, entity); } -void StairTile::setPlacedBy(Level* level, const TilePos& pos, Mob* mob) +void StairTile::setPlacedBy(TileSource* source, const TilePos& pos, Mob* mob) { int rot = Mth::floor(0.5f + (mob->m_rot.x * 4.0f / 360.0f)) & 3; @@ -200,20 +201,20 @@ void StairTile::setPlacedBy(Level* level, const TilePos& pos, Mob* mob) case 2: data = 3; break; } - level->setData(pos, data); + source->setTileAndData(pos, FullTile(m_ID, data)); } -void StairTile::prepareRender(Level* level, const TilePos& pos) +void StairTile::prepareRender(TileSource* source, const TilePos& pos) { - return m_pParent->prepareRender(level, pos); + return m_pParent->prepareRender(source, pos); } -void StairTile::attack(Level* level, const TilePos& pos, Player* player) +void StairTile::attack(TileSource* source, const TilePos& pos, Player* player) { - m_pParent->attack(level, pos, player); + m_pParent->attack(source, pos, player); } -void StairTile::handleEntityInside(Level* level, const TilePos& pos, const Entity* entity, Vec3& vec) +void StairTile::handleEntityInside(TileSource* source, const TilePos& pos, const Entity* entity, Vec3& vec) { - m_pParent->handleEntityInside(level, pos, entity, vec); + m_pParent->handleEntityInside(source, pos, entity, vec); } diff --git a/source/world/tile/StairTile.hpp b/source/world/tile/StairTile.hpp index 2787872fe..f18dc29e3 100644 --- a/source/world/tile/StairTile.hpp +++ b/source/world/tile/StairTile.hpp @@ -16,37 +16,37 @@ class StairTile : public Tile StairTile(int ID, Tile* pParent); public: - void addAABBs(const Level*, const TilePos& pos, const AABB*, std::vector&) override; + void addAABBs(TileSource*, const TilePos& pos, const AABB*, std::vector&) override; bool isSolidRender() const override; bool isCubeShaped() const override; eRenderShape getRenderShape() const override; // Just overloads to forward to parent tile. - void addLights(Level*, const TilePos& pos) override; - void animateTick(Level*, const TilePos& pos, Random*) override; - void updateShape(const LevelSource*, const TilePos& pos) override; - float getBrightness(const LevelSource*, const TilePos& pos) const override; + void addLights(TileSource*, const TilePos& pos) override; + void animateTick(TileSource*, const TilePos& pos, Random*) override; + void updateShape(TileSource*, const TilePos& pos) override; + float getBrightness(TileSource*, const TilePos& pos) const override; int getTexture(Facing::Name face) const override; int getTexture(Facing::Name face, TileData data) const override; - int getTexture(const LevelSource*, const TilePos& pos, Facing::Name face) const override; - AABB getTileAABB(const Level*, const TilePos& pos) override; + int getTexture(TileSource*, const TilePos& pos, Facing::Name face) const override; + AABB getTileAABB(TileSource*, const TilePos& pos) override; bool mayPick() const override; bool mayPick(TileData data, bool) const override; - bool mayPlace(const Level*, const TilePos& pos) const override; + bool mayPlace(TileSource*, const TilePos& pos) const override; int getTickDelay() const override; - void tick(Level*, const TilePos& pos, Random*) override; - void destroy(Level*, const TilePos& pos, TileData data) override; - void onPlace(Level*, const TilePos& pos) override; - void onRemove(Level*, const TilePos& pos) override; + void tick(TileSource*, const TilePos& pos, Random*) override; + void destroy(TileSource*, const TilePos& pos, TileData data) override; + void onPlace(TileSource*, const TilePos& pos) override; + void onRemove(TileSource*, const TilePos& pos) override; float getExplosionResistance(Entity*) const override; - void wasExploded(Level*, const TilePos& pos) override; - RenderLayer getRenderLayer() const override; - bool use(Level*, const TilePos& pos, Player*) override; - void stepOn(Level*, const TilePos& pos, Entity*) override; - void setPlacedBy(Level*, const TilePos& pos, Mob*) override; - void prepareRender(Level*, const TilePos& pos) override; - void attack(Level*, const TilePos& pos, Player*) override; - void handleEntityInside(Level*, const TilePos& pos, const Entity*, Vec3&) override; + void wasExploded(TileSource*, const TilePos& pos) override; + RenderLayer getRenderLayer(TileSource*, const TilePos&) const override; + bool use(const TilePos& pos, Player*) override; + void stepOn(TileSource*, const TilePos& pos, Entity*) override; + void setPlacedBy(TileSource*, const TilePos& pos, Mob*) override; + void prepareRender(TileSource*, const TilePos& pos) override; + void attack(TileSource*, const TilePos& pos, Player*) override; + void handleEntityInside(TileSource*, const TilePos& pos, const Entity*, Vec3&) override; public: Tile* m_pParent; diff --git a/source/world/tile/StoneSlabTile.cpp b/source/world/tile/StoneSlabTile.cpp index ced2f2332..b5f445f54 100644 --- a/source/world/tile/StoneSlabTile.cpp +++ b/source/world/tile/StoneSlabTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "StoneSlabTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" StoneSlabTile::StoneSlabTile(int id, bool full) : Tile(id, TEXTURE_STONE_SLAB_TOP, Material::stone) { @@ -75,34 +75,34 @@ int StoneSlabTile::getTexture(Facing::Name face, TileData data) const } } -void StoneSlabTile::onPlace(Level* level, const TilePos& pos) +void StoneSlabTile::onPlace(TileSource* source, const TilePos& pos) { - TileID tileBelow = level->getTile(pos.below()); - int tileHereData = level->getData(pos); + TileID tileBelow = source->getTile(pos.below()); + int tileHereData = source->getData(pos); // If there's a stone slab below us, set us to air and combine us into the lower slab block - if (tileHereData == level->getData(pos.below()) && tileBelow == Tile::stoneSlabHalf->m_ID) + if (tileHereData == source->getData(pos.below()) && tileBelow == Tile::stoneSlabHalf->m_ID) { - level->setTile(pos, TILE_AIR); - level->setTileAndData(pos.below(), Tile::stoneSlab->m_ID, tileHereData); + source->setTile(pos, TILE_AIR); + source->setTileAndData(pos.below(), FullTile(Tile::stoneSlab->m_ID, tileHereData)); } } -bool StoneSlabTile::shouldRenderFace(const LevelSource* level, const TilePos& pos, Facing::Name face) const +bool StoneSlabTile::shouldRenderFace(TileSource* source, const TilePos& pos, Facing::Name face) const { if (this != Tile::stoneSlabHalf) // @BUG: Missing return? In JE this is true too - Tile::shouldRenderFace(level, pos, face); + Tile::shouldRenderFace(source, pos, face); if (face == Facing::UP) return true; - if (!Tile::shouldRenderFace(level, pos, face)) + if (!Tile::shouldRenderFace(source, pos, face)) return false; if (face == Facing::DOWN) return true; - return level->getTile(pos) != m_ID; + return source->getTile(pos) != m_ID; } diff --git a/source/world/tile/StoneSlabTile.hpp b/source/world/tile/StoneSlabTile.hpp index b8010a6f5..4a9c2f332 100644 --- a/source/world/tile/StoneSlabTile.hpp +++ b/source/world/tile/StoneSlabTile.hpp @@ -32,8 +32,8 @@ class StoneSlabTile : public Tile int getSpawnResourcesAuxValue(int) const override; int getTexture(Facing::Name face) const override; int getTexture(Facing::Name face, TileData data) const override; - void onPlace(Level*, const TilePos& pos) override; - bool shouldRenderFace(const LevelSource*, const TilePos& pos, Facing::Name face) const override; + void onPlace(TileSource*, const TilePos& pos) override; + bool shouldRenderFace(TileSource*, const TilePos& pos, Facing::Name face) const override; bool m_bFull; }; diff --git a/source/world/tile/TallGrass.cpp b/source/world/tile/TallGrass.cpp index f339bd31e..f3afc48f5 100644 --- a/source/world/tile/TallGrass.cpp +++ b/source/world/tile/TallGrass.cpp @@ -1,5 +1,5 @@ #include "TallGrass.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "client/renderer/PatchManager.hpp" #include #include @@ -19,7 +19,7 @@ int TallGrass::getResource(TileData data, Random* random) const return random->nextInt(8) == 0 ? Item::seeds->m_itemID : 0; } -int TallGrass::getColor(const LevelSource* levelSource, const TilePos& pos) const +int TallGrass::getColor(TileSource* source, const TilePos& pos) const { if (GetPatchManager()->IsGrassTinted()) { @@ -28,9 +28,9 @@ int TallGrass::getColor(const LevelSource* levelSource, const TilePos& pos) cons return 0xFFFFFF; } -int TallGrass::getTexture(const LevelSource* level, const TilePos& pos, Facing::Name face) const +int TallGrass::getTexture(TileSource* source, const TilePos& pos, Facing::Name face) const { - TileData data = level->getData(pos); + TileData data = source->getData(pos); return data == 1 ? m_TextureFrame : (data == 2 ? m_TextureFrame + 16 + 1 : (data == 0 ? m_TextureFrame + 16 : m_TextureFrame)); } diff --git a/source/world/tile/TallGrass.hpp b/source/world/tile/TallGrass.hpp index beddc39d9..52e5d3946 100644 --- a/source/world/tile/TallGrass.hpp +++ b/source/world/tile/TallGrass.hpp @@ -10,7 +10,7 @@ class TallGrass : public Bush public: int getResource(TileData, Random*) const override; bool isValidGrowTile(const TileID tile) const; - int getColor(const LevelSource*, const TilePos& pos) const override; - int getTexture(const LevelSource* level, const TilePos& pos, Facing::Name face) const override; + int getColor(TileSource*, const TilePos& pos) const override; + int getTexture(TileSource* level, const TilePos& pos, Facing::Name face) const override; eRenderShape getRenderShape() const override; }; diff --git a/source/world/tile/Tile.cpp b/source/world/tile/Tile.cpp index 861449de6..5e3969bda 100644 --- a/source/world/tile/Tile.cpp +++ b/source/world/tile/Tile.cpp @@ -8,6 +8,7 @@ #include "common/Logger.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "world/item/TileItem.hpp" #include "world/entity/ItemEntity.hpp" #include "world/item/AuxTileItem.hpp" @@ -89,11 +90,12 @@ std::string Tile::TILE_DESCRIPTION_PREFIX = "tile."; Tile* Tile::tiles [C_MAX_TILES]; -int Tile::lightBlock [C_MAX_TILES]; -int Tile::lightEmission[C_MAX_TILES]; +Brightness_t Tile::lightBlock [C_MAX_TILES]; +Brightness_t Tile::lightEmission[C_MAX_TILES]; bool Tile::shouldTick [C_MAX_TILES]; bool Tile::solid [C_MAX_TILES]; bool Tile::translucent [C_MAX_TILES]; +float Tile::translucency [C_MAX_TILES]; bool Tile::isEntityTile [C_MAX_TILES]; @@ -243,7 +245,7 @@ bool Tile::isSignalSource() const return false; } -Tile::RenderLayer Tile::getRenderLayer() const +Tile::RenderLayer Tile::getRenderLayer(TileSource*, const TilePos&) const { return m_renderLayer; } @@ -837,25 +839,25 @@ TileID Tile::TransformToValidBlockId(TileID tileId) return TransformToValidBlockId(tileId, TilePos::ZERO); } -void Tile::updateShape(const LevelSource* a, const TilePos& pos) +void Tile::updateShape(TileSource* source, const TilePos& pos) { } -void Tile::addLights(Level* p, const TilePos& pos) +void Tile::addLights(TileSource* source, const TilePos& pos) { } -float Tile::getBrightness(const LevelSource* pSrc, const TilePos& pos) const +float Tile::getBrightness(TileSource* source, const TilePos& pos) const { - return pSrc->getBrightness(pos); + return source->getBrightness(pos); } -int Tile::getColor(const LevelSource* pSrc, const TilePos& pos) const +int Tile::getColor(TileSource* source, const TilePos& pos) const { return 0xFFFFFF; // White } -AABB* Tile::getAABB(const Level* pLevel, const TilePos& pos) +AABB* Tile::getAABB(TileSource* source, const TilePos& pos) { Vec3 offset(pos); @@ -863,15 +865,15 @@ AABB* Tile::getAABB(const Level* pLevel, const TilePos& pos) return &m_aabbReturned; } -AABB Tile::getTileAABB(const Level* pLevel, const TilePos& pos) +AABB Tile::getTileAABB(TileSource* source, const TilePos& pos) { Vec3 offset(pos); return AABB(offset + m_aabb.min, offset + m_aabb.max); } -void Tile::addAABBs(const Level* pLevel, const TilePos& pos, const AABB* aabb, std::vector& out) +void Tile::addAABBs(TileSource* source, const TilePos& pos, const AABB* aabb, std::vector& out) { - AABB* pTileAABB = getAABB(pLevel, pos); + AABB* pTileAABB = getAABB(source, pos); if (pTileAABB && pTileAABB->intersect(*aabb)) { @@ -879,7 +881,7 @@ void Tile::addAABBs(const Level* pLevel, const TilePos& pos, const AABB* aabb, s } } -bool Tile::shouldRenderFace(const LevelSource* pSrc, const TilePos& pos, Facing::Name face) const +bool Tile::shouldRenderFace(TileSource* source, const TilePos& pos, Facing::Name face) const { //if ((y | x | z) > C_MAX_CHUNKS_Z * 16) // return false; @@ -909,9 +911,12 @@ bool Tile::shouldRenderFace(const LevelSource* pSrc, const TilePos& pos, Facing: case Facing::UP: if (m_aabb.max.y < 1.0f) return true; break; + default: + assert(false); + return false; } - Tile* pTile = Tile::tiles[pSrc->getTile(pos)]; + Tile* pTile = Tile::tiles[source->getTile(pos)]; if (!pTile) return true; @@ -921,52 +926,52 @@ bool Tile::shouldRenderFace(const LevelSource* pSrc, const TilePos& pos, Facing: return !pTile->isSolidRender(); } -int Tile::getTexture(const LevelSource* pSrc, const TilePos& pos, Facing::Name face) const +int Tile::getTexture(TileSource* source, const TilePos& pos, Facing::Name face) const { - return getTexture(face, pSrc->getData(pos)); + return getTexture(face, source->getData(pos)); } -bool Tile::canSurvive(const Level* pLevel, const TilePos& pos) const +bool Tile::canSurvive(TileSource* source, const TilePos& pos) const { return true; } // returns if we can place over the tile -bool Tile::mayPlace(const Level* pLevel, const TilePos& pos) const +bool Tile::mayPlace(TileSource* source, const TilePos& pos) const { - TileID tile = pLevel->getTile(pos); + TileID tile = source->getTile(pos); if (!tile) return true; // we can definitely place something over air return Tile::tiles[tile]->m_pMaterial->isLiquid(); } -void Tile::tick(Level* pLevel, const TilePos& pos, Random* pRandom) +void Tile::tick(TileSource* source, const TilePos& pos, Random* random) { } -void Tile::animateTick(Level* pLevel, const TilePos& pos, Random* pRandom) +void Tile::animateTick(TileSource* source, const TilePos& pos, Random* pRandom) { } -void Tile::destroy(Level* pLevel, const TilePos& pos, TileData data) +void Tile::destroy(TileSource* source, const TilePos& pos, TileData data) { } -void Tile::neighborChanged(Level* pLevel, const TilePos& pos, TileID tile) +void Tile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { } -void Tile::onPlace(Level* pLevel, const TilePos& pos) +void Tile::onPlace(TileSource* source, const TilePos& pos) { } -void Tile::onRemove(Level* pLevel, const TilePos& pos) +void Tile::onRemove(TileSource* source, const TilePos& pos) { } @@ -995,9 +1000,9 @@ bool Tile::containsZ(const Vec3& v) && v.y <= m_aabb.max.y; } -HitResult Tile::clip(const Level* level, const TilePos& pos, Vec3 vec1, Vec3 vec2) +HitResult Tile::clip(TileSource* source, const TilePos& pos, Vec3 vec1, Vec3 vec2) { - updateShape(level, pos); + updateShape(source, pos); Vec3 clipMinX, clipMinY, clipMinZ; Vec3 clipMaxX, clipMaxY, clipMaxZ; @@ -1061,32 +1066,32 @@ HitResult Tile::clip(const Level* level, const TilePos& pos, Vec3 vec1, Vec3 vec return HitResult(pos, collType, *pVec + pos); } -int Tile::getSignal(const LevelSource* pLevel, const TilePos& pos) const +int Tile::getSignal(TileSource* source, const TilePos& pos) const { return 0; } -int Tile::getSignal(const LevelSource* pLevel, const TilePos& pos, Facing::Name face) const +int Tile::getSignal(TileSource* source, const TilePos& pos, Facing::Name face) const { return 0; } -int Tile::getDirectSignal(const Level* pLevel, const TilePos& pos, Facing::Name face) const +int Tile::getDirectSignal(TileSource* source, const TilePos& pos, Facing::Name face) const { return 0; } -void Tile::triggerEvent(Level* pLevel, const TileEvent& event) +void Tile::triggerEvent(TileSource* source, const TileEvent& event) { } -void Tile::entityInside(Level* pLevel, const TilePos& pos, Entity* pEnt) const +void Tile::entityInside(TileSource* source, const TilePos& pos, Entity* pEnt) const { } -void Tile::handleEntityInside(Level* pLevel, const TilePos& pos, const Entity* pEnt, Vec3& vec) +void Tile::handleEntityInside(TileSource* source, const TilePos& pos, const Entity* pEnt, Vec3& vec) { } @@ -1105,39 +1110,41 @@ float Tile::getDestroyProgress(Player* player) const return player->getDestroySpeed(this) / m_hardness / 30.0f; } -void Tile::spawnResources(Level* pLevel, const TilePos& pos, TileData data) +void Tile::spawnResources(TileSource* source, const TilePos& pos, TileData data) { - return spawnResources(pLevel, pos, data, 1.0f); + return spawnResources(source, pos, data, 1.0f); } -void Tile::spawnResources(Level* pLevel, const TilePos& pos, TileData data, float fChance) +void Tile::spawnResources(TileSource* source, const TilePos& pos, TileData data, float fChance) { - if (pLevel->m_bIsClientSide) + Level& level = source->getLevel(); + if (level.m_bIsClientSide) return; - int count = getResourceCount(&pLevel->m_random); + int count = getResourceCount(&level.m_random); for (int i = 0; i < count; i++) { - if (pLevel->m_random.nextFloat() > fChance) + if (level.m_random.nextFloat() > fChance) continue; - int id = getResource(data, &pLevel->m_random); + int id = getResource(data, &level.m_random); if (id <= 0) continue; - Vec3 o((pLevel->m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, - (pLevel->m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, - (pLevel->m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f); + Vec3 o((level.m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, + (level.m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f, + (level.m_random.nextFloat() * 0.7f) + (1.0f - 0.7f) * 0.5f); ItemStack item(id, 1, getSpawnResourcesAuxValue(data)); - ItemEntity* pEntity = new ItemEntity(pLevel, Vec3(pos) + o, item); - pEntity->m_throwTime = 10; - pLevel->addEntity(pEntity); + std::unique_ptr entity(new ItemEntity(*source, Vec3(pos) + o, item)); + entity->m_throwTime = 10; + + level.addEntity(std::move(entity)); } } -int Tile::spawnBurnResources(Level*, float, float, float) +int Tile::spawnBurnResources(TileSource* source, float, float, float) { return 0; } @@ -1147,44 +1154,44 @@ float Tile::getExplosionResistance(Entity* entity) const return m_blastResistance / 5.0f; } -void Tile::wasExploded(Level* pLevel, const TilePos& pos) +void Tile::wasExploded(TileSource* source, const TilePos& pos) { } -bool Tile::use(Level* pLevel, const TilePos& pos, Player* player) +bool Tile::use(const TilePos& pos, Player* player) { return false; } -void Tile::stepOn(Level* pLevel, const TilePos& pos, Entity* entity) +void Tile::stepOn(TileSource* source, const TilePos& pos, Entity* entity) { } -void Tile::setPlacedOnFace(Level* pLevel, const TilePos& pos, Facing::Name face) +void Tile::setPlacedOnFace(TileSource* source, const TilePos& pos, Facing::Name face) { } -void Tile::setPlacedBy(Level* pLevel, const TilePos& pos, Mob* mob) +void Tile::setPlacedBy(TileSource* source, const TilePos& pos, Mob* mob) { } -void Tile::prepareRender(Level* pLevel, const TilePos& pos) +void Tile::prepareRender(TileSource* source, const TilePos& pos) { } -void Tile::attack(Level* pLevel, const TilePos& pos, Player* player) +void Tile::attack(TileSource* source, const TilePos& pos, Player* player) { } -void Tile::playerDestroy(Level* level, Player* player, const TilePos& pos, TileData data) +void Tile::playerDestroy(TileSource* source, Player* player, const TilePos& pos, TileData data) { - spawnResources(level, pos, data); + spawnResources(source, pos, data); } void Tile::playerWillDestroy(Player* player, const TilePos& pos, TileData data) diff --git a/source/world/tile/Tile.hpp b/source/world/tile/Tile.hpp index 310c33c54..c8ecb7d83 100644 --- a/source/world/tile/Tile.hpp +++ b/source/world/tile/Tile.hpp @@ -12,23 +12,24 @@ #include #include "common/Random.hpp" +#include "common/Utils.hpp" #include "world/item/Tool.hpp" #include "world/phys/AABB.hpp" -#include "world/level/storage/LevelSource.hpp" #include "world/level/Material.hpp" #include "world/entity/Entity.hpp" -#include "world/level/levelgen/chunk/LevelChunk.hpp" #include "world/Facing.hpp" #include "world/level/TilePos.hpp" #include "world/level/TileEvent.hpp" #include "world/phys/Vec3.hpp" #include "world/phys/HitResult.hpp" +#include "world/level/Brightness.hpp" class Level; class Entity; class Mob; class Player; class LiquidTile; +class TileSource; class Tile { @@ -42,8 +43,9 @@ class Tile RENDER_LAYER_ALPHATEST, RENDER_LAYER_SEASONS_OPAQUE, RENDER_LAYER_SEASONS_OPTIONAL_ALPHATEST, + RENDER_LAYER_ALPHATEST_SINGLE_SIDE, RENDER_LAYERS_MIN = RENDER_LAYER_DOUBLE_SIDED, - RENDER_LAYERS_MAX = RENDER_LAYER_SEASONS_OPTIONAL_ALPHATEST, + RENDER_LAYERS_MAX = RENDER_LAYER_ALPHATEST_SINGLE_SIDE, RENDER_LAYERS_COUNT }; struct SoundType @@ -62,58 +64,59 @@ class Tile #pragma GCC diagnostic ignored "-Woverloaded-virtual" virtual Tile* setShape(float, float, float, float, float, float); #pragma GCC diagnostic pop - virtual void updateShape(const LevelSource*, const TilePos& pos); + virtual void updateShape(TileSource*, const TilePos& pos); virtual void updateDefaultShape(); - virtual void addLights(Level*, const TilePos& pos); - virtual float getBrightness(const LevelSource*, const TilePos& pos) const; - virtual bool shouldRenderFace(const LevelSource*, const TilePos& pos, Facing::Name face) const; + virtual void addLights(TileSource*, const TilePos& pos); + virtual float getBrightness(TileSource*, const TilePos& pos) const; + virtual bool shouldRenderFace(TileSource*, const TilePos& pos, Facing::Name face) const; virtual int getTexture(Facing::Name face) const; virtual int getTexture(Facing::Name face, TileData data) const; - virtual int getTexture(const LevelSource*, const TilePos& pos, Facing::Name face) const; - virtual AABB* getAABB(const Level*, const TilePos& pos); - virtual void addAABBs(const Level*, const TilePos& pos, const AABB*, std::vector&); - virtual AABB getTileAABB(const Level*, const TilePos& pos); + virtual int getTexture(TileSource*, const TilePos& pos, Facing::Name face) const; + virtual AABB* getAABB(TileSource*, const TilePos& pos); + virtual void addAABBs(TileSource*, const TilePos& pos, const AABB*, std::vector&); + virtual AABB getTileAABB(TileSource*, const TilePos& pos); virtual bool isSolidRender() const; virtual bool mayPick() const; virtual bool mayPick(TileData, bool) const; - virtual bool mayPlace(const Level*, const TilePos& pos) const; + virtual bool mayPlace(TileSource*, const TilePos& pos) const; + virtual bool tryToPlace(TileSource*, const TilePos&, TileData); virtual int getTickDelay() const; - virtual void tick(Level*, const TilePos& pos, Random*); - virtual void animateTick(Level*, const TilePos& pos, Random*); - virtual void destroy(Level*, const TilePos& pos, TileData data); - virtual void neighborChanged(Level*, const TilePos& pos, TileID tile); - virtual void onPlace(Level*, const TilePos& pos); - virtual void onRemove(Level*, const TilePos& pos); + virtual void tick(TileSource* source, const TilePos& pos, Random* random); + virtual void animateTick(TileSource*, const TilePos& pos, Random*); + virtual void destroy(TileSource*, const TilePos& pos, TileData data); + virtual void neighborChanged(TileSource*, const TilePos& pos, TileID tile); + virtual void onPlace(TileSource*, const TilePos& pos); + virtual void onRemove(TileSource*, const TilePos& pos); virtual int getResource(TileData, Random*) const; virtual int getResourceCount(Random*) const; virtual float getDestroyProgress(Player*) const; - virtual void spawnResources(Level*, const TilePos& pos, TileData data); - virtual void spawnResources(Level*, const TilePos& pos, TileData data, float); - virtual int spawnBurnResources(Level*, float, float, float); + virtual void spawnResources(TileSource*, const TilePos& pos, TileData data); + virtual void spawnResources(TileSource*, const TilePos& pos, TileData data, float); + virtual int spawnBurnResources(TileSource*, float, float, float); virtual float getExplosionResistance(Entity*) const; - virtual HitResult clip(const Level*, const TilePos& pos, Vec3, Vec3); - virtual void wasExploded(Level*, const TilePos& pos); - virtual RenderLayer getRenderLayer() const; - virtual bool use(Level*, const TilePos& pos, Player*); - virtual void stepOn(Level*, const TilePos& pos, Entity*); - virtual void setPlacedOnFace(Level*, const TilePos& pos, Facing::Name face); - virtual void setPlacedBy(Level*, const TilePos& pos, Mob*); - virtual void prepareRender(Level*, const TilePos& pos); - virtual void attack(Level*, const TilePos& pos, Player*); - virtual void handleEntityInside(Level*, const TilePos& pos, const Entity*, Vec3&); - virtual int getColor(const LevelSource*, const TilePos& pos) const; + virtual HitResult clip(TileSource*, const TilePos& pos, Vec3, Vec3); + virtual void wasExploded(TileSource*, const TilePos& pos); + virtual RenderLayer getRenderLayer(TileSource*, const TilePos&) const; + virtual bool use(const TilePos& pos, Player*); + virtual void stepOn(TileSource*, const TilePos& pos, Entity*); + virtual void setPlacedOnFace(TileSource*, const TilePos& pos, Facing::Name face); + virtual void setPlacedBy(TileSource*, const TilePos& pos, Mob*); + virtual void prepareRender(TileSource*, const TilePos& pos); + virtual void attack(TileSource*, const TilePos& pos, Player*); + virtual void handleEntityInside(TileSource*, const TilePos& pos, const Entity*, Vec3&); + virtual int getColor(TileSource*, const TilePos& pos) const; virtual bool isSignalSource() const; - virtual int getSignal(const LevelSource*, const TilePos& pos) const; - virtual int getSignal(const LevelSource*, const TilePos& pos, Facing::Name face) const; - virtual int getDirectSignal(const Level*, const TilePos& pos, Facing::Name face) const; - virtual void entityInside(Level*, const TilePos& pos, Entity*) const; - virtual void playerDestroy(Level*, Player*, const TilePos& pos, TileData data); + virtual int getSignal(TileSource*, const TilePos& pos) const; + virtual int getSignal(TileSource*, const TilePos& pos, Facing::Name face) const; + virtual int getDirectSignal(TileSource*, const TilePos& pos, Facing::Name face) const; + virtual void entityInside(TileSource*, const TilePos& pos, Entity*) const; + virtual void playerDestroy(TileSource*, Player*, const TilePos& pos, TileData data); virtual void playerWillDestroy(Player*, const TilePos& pos, TileData data); - virtual bool canSurvive(const Level*, const TilePos& pos) const; + virtual bool canSurvive(TileSource*, const TilePos& pos) const; virtual std::string getName() const; virtual std::string getDescriptionId() const; virtual Tile* setDescriptionId(std::string const&); - virtual void triggerEvent(Level*, const TileEvent& event); + virtual void triggerEvent(TileSource*, const TileEvent& event); virtual Tile* setSoundType(Tile::SoundType const&); virtual Tile* setLightBlock(int); virtual Tile* setLightEmission(float); @@ -121,6 +124,7 @@ class Tile virtual Tile* setDestroyTime(float); virtual Tile* setTicking(bool); virtual int getSpawnResourcesAuxValue(int) const; + virtual bool isSeasonTinted() const; Tile* setToolTypes(unsigned int toolMask); Tile* setToolLevel(int toolLevel); Tile* setToolTypesAndLevel(unsigned int toolMask, int toolLevel = 0); @@ -139,6 +143,31 @@ class Tile bool containsY(const Vec3&); bool containsZ(const Vec3&); + bool isSolid() const + { + return solid[m_ID]; + } + + bool operator==(const Tile& other) const + { + return m_ID == other.m_ID; + } + + bool operator==(TileID id) const + { + return m_ID == id; + } + + bool operator!=(const Tile& other) const + { + return m_ID != other.m_ID; + } + + bool operator!=(TileID id) const + { + return m_ID != id; + } + public: // static functions static void initTiles(); static void teardownTiles(); @@ -159,11 +188,12 @@ class Tile SOUND_SAND, SOUND_SILENT; static Tile* tiles [C_MAX_TILES]; - static int lightBlock [C_MAX_TILES]; - static int lightEmission[C_MAX_TILES]; + static Brightness_t lightBlock [C_MAX_TILES]; + static Brightness_t lightEmission[C_MAX_TILES]; static bool shouldTick [C_MAX_TILES]; static bool solid [C_MAX_TILES]; static bool translucent [C_MAX_TILES]; + static float translucency [C_MAX_TILES]; static bool isEntityTile [C_MAX_TILES]; // TODO @@ -290,4 +320,14 @@ class FullTile public: TileID getTypeId() const { return _tileType->m_ID; } Tile* getType() const { return _tileType; } + + bool operator==(const FullTile& other) const + { + return _tileType == other._tileType && data == other.data; + } + + bool operator!=(const FullTile& other) const + { + return _tileType != other._tileType || data != other.data; + } }; diff --git a/source/world/tile/TntTile.cpp b/source/world/tile/TntTile.cpp index db244e552..735e473e0 100644 --- a/source/world/tile/TntTile.cpp +++ b/source/world/tile/TntTile.cpp @@ -8,6 +8,7 @@ #include "TntTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" #include "world/entity/PrimedTnt.hpp" TntTile::TntTile(int id, int texture) : Tile(id, texture, Material::explosive) @@ -33,27 +34,30 @@ int TntTile::getTexture(Facing::Name face) const } } -void TntTile::destroy(Level* level, const TilePos& pos, TileData data) +void TntTile::destroy(TileSource* source, const TilePos& pos, TileData data) { // prevent players from using this in multiplayer, to prevent a desync of player IDs - if (level->m_bIsClientSide) return; + Level& level = source->getLevel(); + if (level.m_bIsClientSide) return; - level->addEntity(new PrimedTnt(level, Vec3(pos) + 0.5f)); + level.addEntity(std::make_unique(*source, Vec3(pos) + 0.5f)); } -void TntTile::wasExploded(Level* level, const TilePos& pos) +void TntTile::wasExploded(TileSource* source, const TilePos& pos) { - PrimedTnt* tnt = new PrimedTnt(level, Vec3(pos) + 0.5f); - tnt->m_fuseTimer = level->m_random.nextInt(tnt->m_fuseTimer / 4) + tnt->m_fuseTimer / 8; - level->addEntity(tnt); + Level& level = source->getLevel(); + + PrimedTnt* tnt = new PrimedTnt(*source, Vec3(pos) + 0.5f); + tnt->m_fuseTimer = level.m_random.nextInt(tnt->m_fuseTimer / 4) + tnt->m_fuseTimer / 8; + level.addEntity(tnt); } -void TntTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void TntTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { // @NOTE: Unused redstone - if (tile > 0 && Tile::tiles[tile]->isSignalSource() && level->hasNeighborSignal(pos)) + if (tile > 0 && Tile::tiles[tile]->isSignalSource() && source->hasNeighborSignal(pos)) { - destroy(level, pos, 0); - level->setTile(pos, TILE_AIR); + destroy(source, pos, 0); + source->setTile(pos, TILE_AIR); } } diff --git a/source/world/tile/TntTile.hpp b/source/world/tile/TntTile.hpp index 40e77b168..5dead22c5 100644 --- a/source/world/tile/TntTile.hpp +++ b/source/world/tile/TntTile.hpp @@ -18,7 +18,7 @@ class TntTile : public Tile public: int getResourceCount(Random*) const override; int getTexture(Facing::Name face) const override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - void destroy(Level*, const TilePos& pos, TileData data) override; - void wasExploded(Level*, const TilePos& pos) override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + void destroy(TileSource*, const TilePos& pos, TileData data) override; + void wasExploded(TileSource*, const TilePos& pos) override; }; diff --git a/source/world/tile/TopSnowTile.cpp b/source/world/tile/TopSnowTile.cpp index b974b308b..36f0f9652 100644 --- a/source/world/tile/TopSnowTile.cpp +++ b/source/world/tile/TopSnowTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "TopSnowTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" TopSnowTile::TopSnowTile(TileID id, int b, Material* c) : Tile(id, b, c) { @@ -15,7 +15,7 @@ TopSnowTile::TopSnowTile(TileID id, int b, Material* c) : Tile(id, b, c) setTicking(true); } -AABB* TopSnowTile::getAABB(const Level*, const TilePos& pos) +AABB* TopSnowTile::getAABB(TileSource* source, const TilePos& pos) { return nullptr; } @@ -40,47 +40,47 @@ int TopSnowTile::getResourceCount(Random* random) const return 0; } -bool TopSnowTile::mayPlace(const Level* level, const TilePos& pos) const +bool TopSnowTile::mayPlace(TileSource* source, const TilePos& pos) const { - TileID tile = level->getTile(pos.below()); + TileID tile = source->getTile(pos.below()); if (!tile || !Tile::tiles[tile]->isSolidRender()) return false; - return level->getMaterial(pos.below())->blocksMotion(); + return source->getMaterial(pos.below())->blocksMotion(); } -bool TopSnowTile::checkCanSurvive(Level* level, const TilePos& pos) +bool TopSnowTile::checkCanSurvive(TileSource* source, const TilePos& pos) { - if (mayPlace(level, pos)) + if (mayPlace(source, pos)) return true; - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); return false; } -void TopSnowTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void TopSnowTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - checkCanSurvive(level, pos); + checkCanSurvive(source, pos); } -bool TopSnowTile::shouldRenderFace(const LevelSource* level, const TilePos& pos, Facing::Name face) const +bool TopSnowTile::shouldRenderFace(TileSource* source, const TilePos& pos, Facing::Name face) const { if (face == Facing::UP) return true; - if (level->getMaterial(pos) == m_pMaterial) + if (source->getMaterial(pos) == m_pMaterial) return false; - return Tile::shouldRenderFace(level, pos, face); + return Tile::shouldRenderFace(source, pos, face); } -void TopSnowTile::tick(Level* level, const TilePos& pos, Random* random) +void TopSnowTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (level->getBrightness(LightLayer::Block, pos) > 11) + if (source->getBrightness(LightLayer::Block, pos) > 11) { - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); } } diff --git a/source/world/tile/TopSnowTile.hpp b/source/world/tile/TopSnowTile.hpp index a1f629a65..437baa64e 100644 --- a/source/world/tile/TopSnowTile.hpp +++ b/source/world/tile/TopSnowTile.hpp @@ -16,15 +16,17 @@ class TopSnowTile : public Tile TopSnowTile(TileID id, int texture, Material* pMtl); public: - AABB* getAABB(const Level*, const TilePos& pos) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; bool isCubeShaped() const override; bool isSolidRender() const override; int getResource(TileData data, Random*) const override; int getResourceCount(Random*) const override; - bool mayPlace(const Level*, const TilePos& pos) const override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - bool shouldRenderFace(const LevelSource*, const TilePos& pos, Facing::Name face) const override; - void tick(Level*, const TilePos& pos, Random*) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + bool shouldRenderFace(TileSource*, const TilePos& pos, Facing::Name face) const override; + void tick(TileSource*, const TilePos& pos, Random*) override; - bool checkCanSurvive(Level*, const TilePos& pos); + bool checkCanSurvive(TileSource*, const TilePos& pos); + + static FullTile dataIDToRecoverableFullTile(TileSource* source, const TilePos& pos, TileData tileDataID); }; diff --git a/source/world/tile/TorchTile.cpp b/source/world/tile/TorchTile.cpp index c423097e9..34874bfe0 100644 --- a/source/world/tile/TorchTile.cpp +++ b/source/world/tile/TorchTile.cpp @@ -8,6 +8,7 @@ #include "TorchTile.hpp" #include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" TorchTile::TorchTile(int ID, int texture, Material* pMtl) : Tile(ID, texture, pMtl) { @@ -15,7 +16,7 @@ TorchTile::TorchTile(int ID, int texture, Material* pMtl) : Tile(ID, texture, pM setTicking(true); } -AABB* TorchTile::getAABB(const Level*, const TilePos& pos) +AABB* TorchTile::getAABB(TileSource*, const TilePos& pos) { return nullptr; } @@ -35,57 +36,59 @@ bool TorchTile::isSolidRender() const return false; } -void TorchTile::animateTick(Level* level, const TilePos& pos, Random* random) +void TorchTile::animateTick(TileSource* source, const TilePos& pos, Random* random) { Vec3 part(pos); part += 0.5f; part.y += 0.2f; // @NOTE: Need to use addParticle("smoke") 5 times. Invalid data values don't actually generate a smoke - switch (level->getData(pos)) + Level& level = source->getLevel(); + + switch (source->getData(pos)) { case 1: part.x -= 0.27f; part.y += 0.22f; - level->addParticle("smoke", part); + level.addParticle("smoke", part); break; case 2: part.x += 0.27f; part.y += 0.22f; - level->addParticle("smoke", part); + level.addParticle("smoke", part); break; case 3: part.z -= 0.27f; part.y += 0.22f; - level->addParticle("smoke", part); + level.addParticle("smoke", part); break; case 4: part.z += 0.27f; part.y += 0.22f; - level->addParticle("smoke", part); + level.addParticle("smoke", part); break; case 5: - level->addParticle("smoke", part); + level.addParticle("smoke", part); break; } - level->addParticle("flame", part); + level.addParticle("flame", part); } -bool TorchTile::checkCanSurvive(Level* level, const TilePos& pos) +bool TorchTile::checkCanSurvive(TileSource* source, const TilePos& pos) { - if (mayPlace(level, pos)) + if (mayPlace(source, pos)) return true; - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); return false; } -HitResult TorchTile::clip(const Level* level, const TilePos& pos, Vec3 a, Vec3 b) +HitResult TorchTile::clip(TileSource* source, const TilePos& pos, Vec3 a, Vec3 b) { - switch (level->getData(pos) &7) + switch (source->getData(pos) & 7) { case 1: setShape(0.0f, 0.2f, 0.35f, 0.3f, 0.8f, 0.65f); @@ -104,92 +107,95 @@ HitResult TorchTile::clip(const Level* level, const TilePos& pos, Vec3 a, Vec3 b break; } - return Tile::clip(level, pos, a, b); + return Tile::clip(source, pos, a, b); } -bool TorchTile::mayPlace(const Level* level, const TilePos& pos) const +bool TorchTile::mayPlace(TileSource* source, const TilePos& pos) const { - if (level->isSolidTile(pos.below())) return true; - if (level->isSolidTile(pos.west())) return true; - if (level->isSolidTile(pos.east())) return true; - if (level->isSolidTile(pos.north())) return true; - if (level->isSolidTile(pos.south())) return true; + if (source->isSolidBlockingTile(pos.below())) return true; + if (source->isSolidBlockingTile(pos.west())) return true; + if (source->isSolidBlockingTile(pos.east())) return true; + if (source->isSolidBlockingTile(pos.north())) return true; + if (source->isSolidBlockingTile(pos.south())) return true; return false; } -void TorchTile::neighborChanged(Level* level, const TilePos& pos, TileID tile) +void TorchTile::neighborChanged(TileSource* source, const TilePos& pos, TileID tile) { - if (!checkCanSurvive(level, pos)) + if (!checkCanSurvive(source, pos)) return; - TileData data = level->getData(pos); + TileData data = source->getData(pos); bool flag = false; - if (!level->isSolidTile(pos.west()) && data == 1) flag = true; - if (!level->isSolidTile(pos.east()) && data == 2) flag = true; - if (!level->isSolidTile(pos.north()) && data == 3) flag = true; - if (!level->isSolidTile(pos.south()) && data == 4) flag = true; - if (!level->isSolidTile(pos.below()) && data == 5) flag = true; + if (!source->isSolidBlockingTile(pos.west()) && data == 1) flag = true; + if (!source->isSolidBlockingTile(pos.east()) && data == 2) flag = true; + if (!source->isSolidBlockingTile(pos.north()) && data == 3) flag = true; + if (!source->isSolidBlockingTile(pos.south()) && data == 4) flag = true; + if (!source->isSolidBlockingTile(pos.below()) && data == 5) flag = true; if (!flag) return; // all good - spawnResources(level, pos, level->getData(pos)); - level->setTile(pos, TILE_AIR); + spawnResources(source, pos, source->getData(pos)); + source->setTile(pos, TILE_AIR); } -void TorchTile::onPlace(Level* level, const TilePos& pos) +void TorchTile::onPlace(TileSource* source, const TilePos& pos) { - if (level->isSolidTile(pos.west())) - level->setData(pos, 1); - else if (level->isSolidTile(pos.east())) - level->setData(pos, 2); - else if (level->isSolidTile(pos.north())) - level->setData(pos, 3); - else if (level->isSolidTile(pos.south())) - level->setData(pos, 4); - else if (level->isSolidTile(pos.below())) - level->setData(pos, 5); - - checkCanSurvive(level, pos); + if (source->isSolidBlockingTile(pos.west())) + source->setTileAndData(pos, FullTile(m_ID, 1)); + else if (source->isSolidBlockingTile(pos.east())) + source->setTileAndData(pos, FullTile(m_ID, 2)); + else if (source->isSolidBlockingTile(pos.north())) + source->setTileAndData(pos, FullTile(m_ID, 3)); + else if (source->isSolidBlockingTile(pos.south())) + source->setTileAndData(pos, FullTile(m_ID, 4)); + else if (source->isSolidBlockingTile(pos.below())) + source->setTileAndData(pos, FullTile(m_ID, 5)); + + checkCanSurvive(source, pos); } -void TorchTile::setPlacedOnFace(Level* level, const TilePos& pos, Facing::Name face) +void TorchTile::setPlacedOnFace(TileSource* source, const TilePos& pos, Facing::Name face) { - TileData data = level->getData(pos); + TileData data = source->getData(pos); switch (face) { case Facing::UP: - if (level->isSolidTile(pos.below())) + if (source->isSolidBlockingTile(pos.below())) data = 5; break; case Facing::NORTH: - if (level->isSolidTile(pos.south())) + if (source->isSolidBlockingTile(pos.south())) data = 4; break; case Facing::SOUTH: - if (level->isSolidTile(pos.north())) + if (source->isSolidBlockingTile(pos.north())) data = 3; break; case Facing::WEST: - if (level->isSolidTile(pos.east())) + if (source->isSolidBlockingTile(pos.east())) data = 2; break; case Facing::EAST: - if (level->isSolidTile(pos.west())) + if (source->isSolidBlockingTile(pos.west())) data = 1; break; case Facing::DOWN: break; + default: + assert(false); + return; } - level->setData(pos, data); + source->setTileAndData(pos, FullTile(m_ID, data)); } -void TorchTile::tick(Level* level, const TilePos& pos, Random* random) +void TorchTile::tick(TileSource* source, const TilePos& pos, Random* random) { - if (!level->getData(pos)) - onPlace(level, pos); + if (!source->getData(pos)) + onPlace(source, pos); } diff --git a/source/world/tile/TorchTile.hpp b/source/world/tile/TorchTile.hpp index 3275c8add..4bdf3f15c 100644 --- a/source/world/tile/TorchTile.hpp +++ b/source/world/tile/TorchTile.hpp @@ -16,17 +16,17 @@ class TorchTile : public Tile TorchTile(int ID, int texture, Material* pMtl); public: - AABB* getAABB(const Level*, const TilePos& pos) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; bool isSolidRender() const override; bool isCubeShaped() const override; eRenderShape getRenderShape() const override; - void animateTick(Level*, const TilePos& pos, Random*) override; - HitResult clip(const Level*, const TilePos& pos, Vec3 a, Vec3 b) override; - bool mayPlace(const Level*, const TilePos& pos) const override; - void neighborChanged(Level*, const TilePos& pos, TileID tile) override; - void onPlace(Level*, const TilePos& pos) override; - void setPlacedOnFace(Level*, const TilePos& pos, Facing::Name face) override; - void tick(Level*, const TilePos& pos, Random*) override; + void animateTick(TileSource*, const TilePos& pos, Random*) override; + HitResult clip(TileSource*, const TilePos& pos, Vec3 a, Vec3 b) override; + bool mayPlace(TileSource*, const TilePos& pos) const override; + void neighborChanged(TileSource*, const TilePos& pos, TileID tile) override; + void onPlace(TileSource*, const TilePos& pos) override; + void setPlacedOnFace(TileSource*, const TilePos& pos, Facing::Name face) override; + void tick(TileSource*, const TilePos& pos, Random*) override; - bool checkCanSurvive(Level*, const TilePos& pos); + bool checkCanSurvive(TileSource*, const TilePos& pos); }; diff --git a/source/world/tile/TransparentTile.cpp b/source/world/tile/TransparentTile.cpp index 1c1d479ae..96ffb155f 100644 --- a/source/world/tile/TransparentTile.cpp +++ b/source/world/tile/TransparentTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "TransparentTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" TransparentTile::TransparentTile(int ID, int texture, Material* mtl, bool bTransparent) :Tile(ID, texture, mtl) { @@ -19,10 +19,10 @@ bool TransparentTile::isSolidRender() const return false; } -bool TransparentTile::shouldRenderFace(const LevelSource* level, const TilePos& pos, Facing::Name face) const +bool TransparentTile::shouldRenderFace(TileSource* source, const TilePos& pos, Facing::Name face) const { - if (!m_bTransparent && level->getTile(pos) == m_ID) + if (!m_bTransparent && source->getTile(pos) == m_ID) return false; - return Tile::shouldRenderFace(level, pos, face); + return Tile::shouldRenderFace(source, pos, face); } diff --git a/source/world/tile/TransparentTile.hpp b/source/world/tile/TransparentTile.hpp index 9fcbc6fd7..387b07a02 100644 --- a/source/world/tile/TransparentTile.hpp +++ b/source/world/tile/TransparentTile.hpp @@ -17,7 +17,7 @@ class TransparentTile : public Tile public: bool isSolidRender() const override; - bool shouldRenderFace(const LevelSource*, const TilePos& pos, Facing::Name face) const override; + bool shouldRenderFace(TileSource*, const TilePos& pos, Facing::Name face) const override; public: bool m_bTransparent; diff --git a/source/world/tile/TreeTile.cpp b/source/world/tile/TreeTile.cpp index 0110d3e96..5849fa025 100644 --- a/source/world/tile/TreeTile.cpp +++ b/source/world/tile/TreeTile.cpp @@ -7,7 +7,7 @@ ********************************************************************/ #include "TreeTile.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" TreeTile::TreeTile(int id) : Tile(id, Material::wood) { @@ -45,10 +45,10 @@ int TreeTile::getTexture(Facing::Name face, TileData data) const return TEXTURE_LOG_SIDE; } -void TreeTile::onRemove(Level* level, const TilePos& pos) +void TreeTile::onRemove(TileSource* source, const TilePos& pos) { // signal to nearby leaves that they should decay - if (!level->hasChunksAt(pos - 5, pos + 5)) + if (!source->hasChunksAt(pos - 5, pos + 5)) return; TilePos tp; @@ -58,14 +58,14 @@ void TreeTile::onRemove(Level* level, const TilePos& pos) { for (tp.z = -4; tp.z <= 5; tp.z++) { - TileID tid = level->getTile(pos + tp); + TileID tid = source->getTile(pos + tp); if (tid != Tile::leaves->m_ID) continue; - TileData data = level->getData(pos + tp); + TileData data = source->getData(pos + tp); if (data & 4) continue; - level->setDataNoUpdate(pos + tp, data | 8); + source->setTileAndDataNoUpdate(pos + tp, FullTile(m_ID, data | 8)); } } } diff --git a/source/world/tile/TreeTile.hpp b/source/world/tile/TreeTile.hpp index bc4b589e6..35e456132 100644 --- a/source/world/tile/TreeTile.hpp +++ b/source/world/tile/TreeTile.hpp @@ -20,5 +20,5 @@ class TreeTile : public Tile int getResourceCount(Random*) const override; int getSpawnResourcesAuxValue(int) const override; int getTexture(Facing::Name face, TileData data) const override; - void onRemove(Level*, const TilePos& pos) override; + void onRemove(TileSource*, const TilePos& pos) override; }; diff --git a/source/world/tile/Web.cpp b/source/world/tile/Web.cpp index 972ef663e..01cebe25a 100644 --- a/source/world/tile/Web.cpp +++ b/source/world/tile/Web.cpp @@ -1,5 +1,5 @@ #include "Web.hpp" -#include "world/level/Level.hpp" +#include "world/level/TileSource.hpp" Web::Web(TileID id, int texture) : Tile(id, texture, Material::web) { @@ -21,7 +21,7 @@ bool Web::isSolidRender() const return false; } -void Web::entityInside(Level*, const TilePos& pos, Entity* entity) const +void Web::entityInside(TileSource*, const TilePos& pos, Entity* entity) const { entity->m_bIsInWeb = true; } @@ -31,7 +31,7 @@ int Web::getResource(TileData data, Random* random) const return Item::string->m_itemID; } -AABB* Web::getAABB(const Level* level, const TilePos& pos) +AABB* Web::getAABB(TileSource* level, const TilePos& pos) { return nullptr; } diff --git a/source/world/tile/Web.hpp b/source/world/tile/Web.hpp index 425eab485..303ed26c0 100644 --- a/source/world/tile/Web.hpp +++ b/source/world/tile/Web.hpp @@ -8,10 +8,10 @@ class Web : public Tile Web(TileID id, int texture); public: - AABB* getAABB(const Level*, const TilePos& pos) override; + AABB* getAABB(TileSource*, const TilePos& pos) override; virtual eRenderShape getRenderShape() const override; virtual bool isCubeShaped() const override; virtual bool isSolidRender() const override; - void entityInside(Level*, const TilePos& pos, Entity*) const override; + void entityInside(TileSource*, const TilePos& pos, Entity*) const override; int getResource(TileData data, Random* random) const override; };