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