diff --git a/GameMods.hpp b/GameMods.hpp
index f3b2234c9..c025366ca 100644
--- a/GameMods.hpp
+++ b/GameMods.hpp
@@ -21,6 +21,7 @@
// Features (major changes)
//#define FEATURE_GFX_SHADERS // Loads and uses Shaders from the assets folder for rendering.
#define FEATURE_NETWORKING // Enables multi-player through RakNet
+//#define FEATURE_SERVER_INVENTORIES // Enables server-sided/server-authoritative player inventories.
// TODO: Add to the LevelSettings struct
//#define FEATURE_CAVES // Generates caves around the world.
diff --git a/game/assets/lang/en_US.lang b/game/assets/lang/en_US.lang
index c86cb0cfe..a197bb6e6 100644
--- a/game/assets/lang/en_US.lang
+++ b/game/assets/lang/en_US.lang
@@ -104,6 +104,7 @@ options.guiScale.small=Small
options.guiScale.normal=Normal
options.guiScale.large=Large
options.gamma=Gamma
+options.enableVsync=V-Sync
performance.max=Max FPS
performance.balanced=Balanced
diff --git a/platforms/android/AppPlatform_android.cpp b/platforms/android/AppPlatform_android.cpp
index 7e23bd8a8..d555cb618 100644
--- a/platforms/android/AppPlatform_android.cpp
+++ b/platforms/android/AppPlatform_android.cpp
@@ -117,6 +117,20 @@ std::string AppPlatform_android::getDateString(int time)
return std::string(buffer);
}
+void AppPlatform_android::setVSyncEnabled(bool enabled)
+{
+ EGLDisplay display = eglGetCurrentDisplay();
+ if (display == EGL_NO_DISPLAY)
+ return;
+
+ eglSwapInterval(display, enabled ? 1 : 0);
+}
+
+bool AppPlatform_android::isVSyncSwitchable() const
+{
+ return eglGetCurrentDisplay() != EGL_NO_DISPLAY;
+}
+
SoundSystem* AppPlatform_android::getSoundSystem() const
{
return m_pSoundSystem;
diff --git a/platforms/android/AppPlatform_android.hpp b/platforms/android/AppPlatform_android.hpp
index 832490e67..a4c242f56 100644
--- a/platforms/android/AppPlatform_android.hpp
+++ b/platforms/android/AppPlatform_android.hpp
@@ -29,6 +29,8 @@ class AppPlatform_android : public AppPlatform
int getScreenHeight() const override;
void showDialog(eDialogType) override;
std::string getDateString(int time) override;
+ void setVSyncEnabled(bool enabled) override;
+ bool isVSyncSwitchable() const override;
// Also add these to allow proper turning within the game.
void recenterMouse() override;
diff --git a/platforms/sdl/sdl2/main.cpp b/platforms/sdl/sdl2/main.cpp
index dc6aca02e..328067137 100644
--- a/platforms/sdl/sdl2/main.cpp
+++ b/platforms/sdl/sdl2/main.cpp
@@ -62,16 +62,11 @@ static void initGraphics()
exit(EXIT_FAILURE);
}
- // Enable V-Sync
- // Not setting this explicitly results in undefined behavior
- if (SDL_GL_SetSwapInterval(-1) == -1) // Try adaptive
+ // Vsync is controlled through the AppPlatform,
+ // default to no vsync here, let platform set it when needed
+ if (SDL_GL_SetSwapInterval(0) == -1)
{
- LOG_W("Adaptive V-Sync is not supported on this platform. Falling back to standard V-Sync...");
- // fallback to standard
- if (SDL_GL_SetSwapInterval(1) == -1)
- {
- LOG_W("Setting the swap interval for V-Sync is not supported on this platform!");
- }
+ LOG_W("Setting the swap interval is not supported on this platform!");
}
if (!mce::Platform::OGL::InitBindings())
@@ -440,6 +435,7 @@ int main(int argc, char *argv[])
// Start MCPE
g_pAppPlatform = new UsedAppPlatform(storagePath, window);
g_pAppPlatform->m_externalStorageDir = storagePath;
+ g_pAppPlatform->setVSyncEnabled(true);
g_pApp = new NinecraftApp;
g_pApp->m_pPlatform = g_pAppPlatform;
g_pApp->init();
diff --git a/platforms/windows/AppPlatform_win32.cpp b/platforms/windows/AppPlatform_win32.cpp
index 642b54473..8f5a1bb17 100644
--- a/platforms/windows/AppPlatform_win32.cpp
+++ b/platforms/windows/AppPlatform_win32.cpp
@@ -135,21 +135,6 @@ void AppPlatform_win32::showDialog(eDialogType type)
m_DialogType = type;
}
-std::string AppPlatform_win32::getDateString(int time)
-{
- time_t tt = time;
- struct tm t;
- // using the _s variant. For a different platform there's gmtime_r. This is not directly portable however.
- gmtime_s(&t, &tt);
-
- //format it with strftime
- char buf[2048];
- strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
- //strftime(buf, sizeof buf, "%a %b %d %H:%M:%S %Z %Y", &t);
-
- return std::string(buf);
-}
-
bool AppPlatform_win32::doesTextureExist(const std::string& path) const
{
return isRegularFile(path.c_str());
@@ -460,6 +445,22 @@ bool AppPlatform_win32::initGraphics(int width, int height)
return true;
}
+void AppPlatform_win32::setVSyncEnabled(bool enabled)
+{
+#if MCE_GFX_API_OGL
+ xglSwapIntervalEXT(enabled ? 1 : 0);
+#endif
+}
+
+bool AppPlatform_win32::isVSyncSwitchable() const
+{
+#if MCE_GFX_API_OGL
+ return true;
+#else
+ return false;
+#endif
+}
+
void AppPlatform_win32::createWindowSizeDependentResources(const Vec2& logicalSize, const Vec2& compositionScale)
{
#if MCE_GFX_API_D3D9
diff --git a/platforms/windows/AppPlatform_win32.hpp b/platforms/windows/AppPlatform_win32.hpp
index 1dc3bb7e0..b702b4768 100644
--- a/platforms/windows/AppPlatform_win32.hpp
+++ b/platforms/windows/AppPlatform_win32.hpp
@@ -37,7 +37,6 @@ class AppPlatform_win32 : public AppPlatform
int getScreenWidth() const override { return m_ScreenWidth; }
int getScreenHeight() const override { return m_ScreenHeight; }
void showDialog(eDialogType) override;
- std::string getDateString(int time) override;
bool doesTextureExist(const std::string& path) const override;
// From v0.1.1. Also add these to determine touch screen use within the game.
@@ -82,6 +81,8 @@ class AppPlatform_win32 : public AppPlatform
bool initGraphics(int width, int height);
void createWindowSizeDependentResources(const Vec2& logicalSize, const Vec2& compositionScale);
void swapBuffers();
+ void setVSyncEnabled(bool enabled) override;
+ bool isVSyncSwitchable() const override;
static MouseButtonType GetMouseButtonType(UINT iMsg);
static bool GetMouseButtonState(UINT iMsg, WPARAM wParam);
diff --git a/platforms/windows/main.cpp b/platforms/windows/main.cpp
index e68bd2aff..b7b090e81 100644
--- a/platforms/windows/main.cpp
+++ b/platforms/windows/main.cpp
@@ -152,6 +152,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
if (!g_AppPlatform.initGraphics(Minecraft::width, Minecraft::height))
goto _cleanup;
+ g_AppPlatform.setVSyncEnabled(true);
+
g_pApp = new NinecraftApp;
g_pApp->m_pPlatform = &g_AppPlatform;
diff --git a/platforms/xdk360/AppPlatform_xdk360.cpp b/platforms/xdk360/AppPlatform_xdk360.cpp
index daf1feec7..7ad6320ed 100644
--- a/platforms/xdk360/AppPlatform_xdk360.cpp
+++ b/platforms/xdk360/AppPlatform_xdk360.cpp
@@ -123,21 +123,6 @@ int AppPlatform_xdk360::checkLicense()
return 1;
}
-std::string AppPlatform_xdk360::getDateString(int time)
-{
- time_t tt = time;
- struct tm t;
- // using the _s variant. For a different platform there's gmtime_r. This is not directly portable however.
- gmtime_s(&t, &tt);
-
- //format it with strftime
- char buf[2048];
- strftime(buf, sizeof buf, "%b %d %Y %H:%M:%S", &t);
- //strftime(buf, sizeof buf, "%a %b %d %H:%M:%S %Z %Y", &t);
-
- return std::string(buf);
-}
-
bool AppPlatform_xdk360::isTouchscreen() const
{
return false;
diff --git a/platforms/xdk360/AppPlatform_xdk360.hpp b/platforms/xdk360/AppPlatform_xdk360.hpp
index 32d2ab85e..a72bcf740 100644
--- a/platforms/xdk360/AppPlatform_xdk360.hpp
+++ b/platforms/xdk360/AppPlatform_xdk360.hpp
@@ -24,7 +24,6 @@ class AppPlatform_xdk360 : public AppPlatform
int checkLicense() override;
int getScreenWidth() const override { return m_ScreenWidth; }
int getScreenHeight() const override { return m_ScreenHeight; }
- std::string getDateString(int time) override;
// From v0.1.1. Also add these to determine touch screen use within the game.
bool isTouchscreen() const override;
diff --git a/projects/visual-studio/Client/Client.vcxproj b/projects/visual-studio/Client/Client.vcxproj
index 9befd92b4..7cbac77c6 100644
--- a/projects/visual-studio/Client/Client.vcxproj
+++ b/projects/visual-studio/Client/Client.vcxproj
@@ -258,6 +258,7 @@
+
@@ -434,6 +435,7 @@
+
diff --git a/projects/visual-studio/Client/Client.vcxproj.filters b/projects/visual-studio/Client/Client.vcxproj.filters
index 55cd0f467..35b451268 100644
--- a/projects/visual-studio/Client/Client.vcxproj.filters
+++ b/projects/visual-studio/Client/Client.vcxproj.filters
@@ -677,6 +677,9 @@
Header Files\GUI\Screens\Inventory
+
+ Header Files\GUI\Screens\Inventory
+
@@ -1204,5 +1207,8 @@
Source Files\GUI\Screens\Inventory
+
+ Source Files\GUI\Screens\Inventory
+
\ No newline at end of file
diff --git a/projects/visual-studio/World/World.vcxproj b/projects/visual-studio/World/World.vcxproj
index dd97f7b76..f2e980d1e 100644
--- a/projects/visual-studio/World/World.vcxproj
+++ b/projects/visual-studio/World/World.vcxproj
@@ -203,7 +203,7 @@
-
+
@@ -211,7 +211,7 @@
-
+
@@ -230,6 +230,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -373,8 +388,8 @@
-
-
+
+
@@ -382,7 +397,7 @@
-
+
@@ -400,6 +415,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/projects/visual-studio/World/World.vcxproj.filters b/projects/visual-studio/World/World.vcxproj.filters
index f923baca5..6d71fb082 100644
--- a/projects/visual-studio/World/World.vcxproj.filters
+++ b/projects/visual-studio/World/World.vcxproj.filters
@@ -105,6 +105,12 @@
{3a97a5e5-77e6-43eb-9890-3fa79b287cd1}
+
+ {53363441-c079-4adf-a246-481be4b68199}
+
+
+ {9dca9e2a-e126-4598-a852-105be172d198}
+
@@ -584,9 +590,6 @@
Source Files\Level\LevelGen\Chunk
-
- Source Files
-
Source Files\Inventory
@@ -611,9 +614,6 @@
Source Files\Inventory
-
- Source Files
-
Source Files\Inventory
@@ -662,9 +662,60 @@
Source Files\Item
+
+ Source Files\Inventory
+
+
+ Source Files\Inventory
+
Source Files\Item
+
+ Source Files\Particle
+
+
+ Source Files
+
+
+ Source Files\Tile
+
+
+ Source Files\Tile
+
+
+ Source Files\Tile
+
+
+ Source Files\Tile
+
+
+ Source Files\Tile\Entity
+
+
+ Source Files\Tile\Entity
+
+
+ Source Files\Tile\Entity
+
+
+ Source Files\Tile\Entity
+
+
+ Source Files\Tile\Entity
+
+
+ Source Files\Inventory
+
+
+ Source Files\Inventory
+
+
+ Source Files\Inventory
+
+
+ Source Files\Inventory
+
@@ -1090,12 +1141,6 @@
Header Files\Level
-
- Header Files
-
-
- Header Files
-
Header Files\Inventory
@@ -1117,9 +1162,6 @@
Header Files\Inventory
-
- Header Files
-
Header Files\Inventory
@@ -1132,15 +1174,6 @@
Header Files\Item
-
- Header Files\Item
-
-
- Header Files\Item
-
-
- Header Files\Item
-
Header Files\Item
@@ -1180,5 +1213,53 @@
Header Files\Item
+
+ Header Files\Inventory
+
+
+ Header Files\Inventory
+
+
+ Header Files\Tile\Entity
+
+
+ Header Files\Tile\Entity
+
+
+ Header Files\Tile\Entity
+
+
+ Header Files\Tile\Entity
+
+
+ Header Files\Tile\Entity
+
+
+ Header Files\Tile
+
+
+ Header Files\Tile
+
+
+ Header Files\Tile
+
+
+ Header Files\Tile
+
+
+ Header Files\Inventory
+
+
+ Header Files\Inventory
+
+
+ Header Files\Inventory
+
+
+ Header Files\Inventory
+
+
+ Header Files\Inventory
+
diff --git a/projects/xcode/NBCraft.xcodeproj/project.pbxproj b/projects/xcode/NBCraft.xcodeproj/project.pbxproj
index 062801938..bf8e79643 100644
--- a/projects/xcode/NBCraft.xcodeproj/project.pbxproj
+++ b/projects/xcode/NBCraft.xcodeproj/project.pbxproj
@@ -938,6 +938,36 @@
84E1C9F02E7FDC89007D2F5D /* VegetationFeature.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E1C9ED2E7FDC89007D2F5D /* VegetationFeature.cpp */; };
84E26C952F440CD600E38DF2 /* AddEntityPacket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E26C932F440CD600E38DF2 /* AddEntityPacket.cpp */; };
84E26C962F440CD600E38DF2 /* AddEntityPacket.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E26C942F440CD600E38DF2 /* AddEntityPacket.hpp */; };
+ 84E2A3C22FBAAC3A0026780B /* FurnaceScreen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3C02FBAAC3A0026780B /* FurnaceScreen.cpp */; };
+ 84E2A3C32FBAAC3A0026780B /* FurnaceScreen.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3C12FBAAC3A0026780B /* FurnaceScreen.hpp */; };
+ 84E2A3CC2FBAAC700026780B /* ContainerContentChangeListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3C42FBAAC700026780B /* ContainerContentChangeListener.cpp */; };
+ 84E2A3CD2FBAAC700026780B /* ContainerContentChangeListener.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3C52FBAAC700026780B /* ContainerContentChangeListener.hpp */; };
+ 84E2A3CE2FBAAC700026780B /* ContainerSizeChangeListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3C62FBAAC700026780B /* ContainerSizeChangeListener.cpp */; };
+ 84E2A3CF2FBAAC700026780B /* ContainerSizeChangeListener.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3C72FBAAC700026780B /* ContainerSizeChangeListener.hpp */; };
+ 84E2A3D02FBAAC700026780B /* FurnaceMenu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3C82FBAAC700026780B /* FurnaceMenu.cpp */; };
+ 84E2A3D12FBAAC700026780B /* FurnaceMenu.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3C92FBAAC700026780B /* FurnaceMenu.hpp */; };
+ 84E2A3D22FBAAC700026780B /* FurnaceResultSlot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3CA2FBAAC700026780B /* FurnaceResultSlot.cpp */; };
+ 84E2A3D32FBAAC700026780B /* FurnaceResultSlot.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3CB2FBAAC700026780B /* FurnaceResultSlot.hpp */; };
+ 84E2A3D52FBAAC860026780B /* NoteParticle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3D42FBAAC860026780B /* NoteParticle.cpp */; };
+ 84E2A3E92FBAAD6A0026780B /* ChestTile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3D62FBAAD6A0026780B /* ChestTile.cpp */; };
+ 84E2A3EA2FBAAD6A0026780B /* ChestTile.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3D72FBAAD6A0026780B /* ChestTile.hpp */; };
+ 84E2A3EB2FBAAD6A0026780B /* ChestTileEntity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3D92FBAAD6A0026780B /* ChestTileEntity.cpp */; };
+ 84E2A3EC2FBAAD6A0026780B /* ChestTileEntity.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3DA2FBAAD6A0026780B /* ChestTileEntity.hpp */; };
+ 84E2A3ED2FBAAD6A0026780B /* FurnaceTileEntity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3DB2FBAAD6A0026780B /* FurnaceTileEntity.cpp */; };
+ 84E2A3EE2FBAAD6A0026780B /* FurnaceTileEntity.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3DC2FBAAD6A0026780B /* FurnaceTileEntity.hpp */; };
+ 84E2A3EF2FBAAD6A0026780B /* MusicTileEntity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3DD2FBAAD6A0026780B /* MusicTileEntity.cpp */; };
+ 84E2A3F02FBAAD6A0026780B /* MusicTileEntity.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3DE2FBAAD6A0026780B /* MusicTileEntity.hpp */; };
+ 84E2A3F12FBAAD6A0026780B /* TileEntity.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3DF2FBAAD6A0026780B /* TileEntity.cpp */; };
+ 84E2A3F22FBAAD6A0026780B /* TileEntity.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3E02FBAAD6A0026780B /* TileEntity.hpp */; };
+ 84E2A3F32FBAAD6A0026780B /* TileEntityType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3E12FBAAD6A0026780B /* TileEntityType.cpp */; };
+ 84E2A3F42FBAAD6A0026780B /* TileEntityType.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3E22FBAAD6A0026780B /* TileEntityType.hpp */; };
+ 84E2A3F52FBAAD6A0026780B /* EntityTile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3E32FBAAD6A0026780B /* EntityTile.cpp */; };
+ 84E2A3F62FBAAD6A0026780B /* EntityTile.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3E42FBAAD6A0026780B /* EntityTile.hpp */; };
+ 84E2A3F72FBAAD6A0026780B /* FurnaceTile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3E52FBAAD6A0026780B /* FurnaceTile.cpp */; };
+ 84E2A3F82FBAAD6A0026780B /* FurnaceTile.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3E62FBAAD6A0026780B /* FurnaceTile.hpp */; };
+ 84E2A3F92FBAAD6A0026780B /* MusicTile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3E72FBAAD6A0026780B /* MusicTile.cpp */; };
+ 84E2A3FA2FBAAD6A0026780B /* MusicTile.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 84E2A3E82FBAAD6A0026780B /* MusicTile.hpp */; };
+ 84E2A3FC2FBAAD7D0026780B /* Facing.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 84E2A3FB2FBAAD7D0026780B /* Facing.cpp */; };
84E4BFB62AE9869A0023E16A /* Logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD6282AC810620006A435 /* Logger.cpp */; };
84E4BFB82AE9869A0023E16A /* Mth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD62D2AC810620006A435 /* Mth.cpp */; };
84E4BFB92AE9869A0023E16A /* Random.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 840DD62F2AC810620006A435 /* Random.cpp */; };
@@ -2715,6 +2745,36 @@
84E1C9ED2E7FDC89007D2F5D /* VegetationFeature.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VegetationFeature.cpp; sourceTree = ""; };
84E26C932F440CD600E38DF2 /* AddEntityPacket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AddEntityPacket.cpp; sourceTree = ""; };
84E26C942F440CD600E38DF2 /* AddEntityPacket.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = AddEntityPacket.hpp; sourceTree = ""; };
+ 84E2A3C02FBAAC3A0026780B /* FurnaceScreen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FurnaceScreen.cpp; sourceTree = ""; };
+ 84E2A3C12FBAAC3A0026780B /* FurnaceScreen.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FurnaceScreen.hpp; sourceTree = ""; };
+ 84E2A3C42FBAAC700026780B /* ContainerContentChangeListener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContainerContentChangeListener.cpp; sourceTree = ""; };
+ 84E2A3C52FBAAC700026780B /* ContainerContentChangeListener.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ContainerContentChangeListener.hpp; sourceTree = ""; };
+ 84E2A3C62FBAAC700026780B /* ContainerSizeChangeListener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ContainerSizeChangeListener.cpp; sourceTree = ""; };
+ 84E2A3C72FBAAC700026780B /* ContainerSizeChangeListener.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ContainerSizeChangeListener.hpp; sourceTree = ""; };
+ 84E2A3C82FBAAC700026780B /* FurnaceMenu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FurnaceMenu.cpp; sourceTree = ""; };
+ 84E2A3C92FBAAC700026780B /* FurnaceMenu.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FurnaceMenu.hpp; sourceTree = ""; };
+ 84E2A3CA2FBAAC700026780B /* FurnaceResultSlot.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FurnaceResultSlot.cpp; sourceTree = ""; };
+ 84E2A3CB2FBAAC700026780B /* FurnaceResultSlot.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FurnaceResultSlot.hpp; sourceTree = ""; };
+ 84E2A3D42FBAAC860026780B /* NoteParticle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NoteParticle.cpp; sourceTree = ""; };
+ 84E2A3D62FBAAD6A0026780B /* ChestTile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChestTile.cpp; sourceTree = ""; };
+ 84E2A3D72FBAAD6A0026780B /* ChestTile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ChestTile.hpp; sourceTree = ""; };
+ 84E2A3D92FBAAD6A0026780B /* ChestTileEntity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChestTileEntity.cpp; sourceTree = ""; };
+ 84E2A3DA2FBAAD6A0026780B /* ChestTileEntity.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ChestTileEntity.hpp; sourceTree = ""; };
+ 84E2A3DB2FBAAD6A0026780B /* FurnaceTileEntity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FurnaceTileEntity.cpp; sourceTree = ""; };
+ 84E2A3DC2FBAAD6A0026780B /* FurnaceTileEntity.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FurnaceTileEntity.hpp; sourceTree = ""; };
+ 84E2A3DD2FBAAD6A0026780B /* MusicTileEntity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MusicTileEntity.cpp; sourceTree = ""; };
+ 84E2A3DE2FBAAD6A0026780B /* MusicTileEntity.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MusicTileEntity.hpp; sourceTree = ""; };
+ 84E2A3DF2FBAAD6A0026780B /* TileEntity.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileEntity.cpp; sourceTree = ""; };
+ 84E2A3E02FBAAD6A0026780B /* TileEntity.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TileEntity.hpp; sourceTree = ""; };
+ 84E2A3E12FBAAD6A0026780B /* TileEntityType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TileEntityType.cpp; sourceTree = ""; };
+ 84E2A3E22FBAAD6A0026780B /* TileEntityType.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TileEntityType.hpp; sourceTree = ""; };
+ 84E2A3E32FBAAD6A0026780B /* EntityTile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EntityTile.cpp; sourceTree = ""; };
+ 84E2A3E42FBAAD6A0026780B /* EntityTile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = EntityTile.hpp; sourceTree = ""; };
+ 84E2A3E52FBAAD6A0026780B /* FurnaceTile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FurnaceTile.cpp; sourceTree = ""; };
+ 84E2A3E62FBAAD6A0026780B /* FurnaceTile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = FurnaceTile.hpp; sourceTree = ""; };
+ 84E2A3E72FBAAD6A0026780B /* MusicTile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MusicTile.cpp; sourceTree = ""; };
+ 84E2A3E82FBAAD6A0026780B /* MusicTile.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MusicTile.hpp; sourceTree = ""; };
+ 84E2A3FB2FBAAD7D0026780B /* Facing.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Facing.cpp; sourceTree = ""; };
84E4BFAE2AE9854B0023E16A /* libCommon.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCommon.a; sourceTree = BUILT_PRODUCTS_DIR; };
84E635C32FAF3D8000D2C708 /* VertexBufferStateBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VertexBufferStateBase.cpp; sourceTree = ""; };
84E635C42FAF3D8000D2C708 /* VertexBufferStateBase.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = VertexBufferStateBase.hpp; sourceTree = ""; };
@@ -3798,12 +3858,8 @@
840DD6562AC810620006A435 /* world */ = {
isa = PBXGroup;
children = (
- 84E7BF2A2F286A20002D3936 /* CompoundContainer.cpp */,
- 84E7BF2B2F286A20002D3936 /* CompoundContainer.hpp */,
- 84E7BF2C2F286A20002D3936 /* Container.hpp */,
- 84E7BF2D2F286A20002D3936 /* ContainerListener.cpp */,
- 84E7BF2E2F286A20002D3936 /* ContainerListener.hpp */,
840DD6572AC810620006A435 /* entity */,
+ 84E2A3FB2FBAAD7D0026780B /* Facing.cpp */,
8477B3A82C4DC3B3004E1AC5 /* Facing.hpp */,
840DD6682AC810620006A435 /* gamemode */,
84E7BF092F286A08002D3936 /* inventory */,
@@ -4095,14 +4151,15 @@
children = (
840DD6CF2AC810620006A435 /* BubbleParticle.cpp */,
840DD6D02AC810620006A435 /* ExplodeParticle.cpp */,
- 8470AF3B2BE9B6FA00BCA54E /* FireworkParticle.hpp */,
8470AF3A2BE9B6FA00BCA54E /* FireworkParticle.cpp */,
+ 8470AF3B2BE9B6FA00BCA54E /* FireworkParticle.hpp */,
840DD6D12AC810620006A435 /* FlameParticle.cpp */,
840DD6D22AC810620006A435 /* LavaParticle.cpp */,
- 840DD6D42AC810620006A435 /* Particle.hpp */,
+ 84E2A3D42FBAAC860026780B /* NoteParticle.cpp */,
840DD6D32AC810620006A435 /* Particle.cpp */,
- 840DD6D62AC810620006A435 /* ParticleEngine.hpp */,
+ 840DD6D42AC810620006A435 /* Particle.hpp */,
840DD6D52AC810620006A435 /* ParticleEngine.cpp */,
+ 840DD6D62AC810620006A435 /* ParticleEngine.hpp */,
840DD6D72AC810620006A435 /* RedDustParticle.cpp */,
840DD6D82AC810620006A435 /* SmokeParticle.cpp */,
840DD6D92AC810620006A435 /* TerrainParticle.cpp */,
@@ -4128,32 +4185,39 @@
840DD6E12AC810620006A435 /* tile */ = {
isa = PBXGroup;
children = (
- 84B9D8A22F3BE0B200FD67C4 /* CropsTile.hpp */,
- 84B9D8A32F3BE0B200FD67C4 /* CropsTile.cpp */,
840DD6E22AC810620006A435 /* BookshelfTile.cpp */,
840DD6E32AC810620006A435 /* BookshelfTile.hpp */,
840DD6E42AC810620006A435 /* Bush.cpp */,
840DD6E52AC810620006A435 /* Bush.hpp */,
84E1C9BF2E7FDC26007D2F5D /* CactusTile.cpp */,
84E1C9C02E7FDC26007D2F5D /* CactusTile.hpp */,
+ 84E2A3D62FBAAD6A0026780B /* ChestTile.cpp */,
+ 84E2A3D72FBAAD6A0026780B /* ChestTile.hpp */,
840DD6E62AC810620006A435 /* ClayTile.cpp */,
840DD6E72AC810620006A435 /* ClayTile.hpp */,
840DD6E82AC810620006A435 /* ClothTile.cpp */,
840DD6E92AC810620006A435 /* ClothTile.hpp */,
84DED1B52F30970A004001C5 /* CraftingTableTile.cpp */,
84DED1B62F30970A004001C5 /* CraftingTableTile.hpp */,
+ 84B9D8A32F3BE0B200FD67C4 /* CropsTile.cpp */,
+ 84B9D8A22F3BE0B200FD67C4 /* CropsTile.hpp */,
84E1C9C12E7FDC26007D2F5D /* DeadBush.cpp */,
84E1C9C22E7FDC26007D2F5D /* DeadBush.hpp */,
840DD6EA2AC810620006A435 /* DirtTile.cpp */,
840DD6EB2AC810620006A435 /* DirtTile.hpp */,
840DD6EC2AC810620006A435 /* DoorTile.cpp */,
840DD6ED2AC810620006A435 /* DoorTile.hpp */,
+ 84E2A3D82FBAAD6A0026780B /* entity */,
+ 84E2A3E32FBAAD6A0026780B /* EntityTile.cpp */,
+ 84E2A3E42FBAAD6A0026780B /* EntityTile.hpp */,
840DD6EE2AC810620006A435 /* FarmTile.cpp */,
840DD6EF2AC810620006A435 /* FarmTile.hpp */,
84E1C9C32E7FDC26007D2F5D /* FenceTile.cpp */,
84E1C9C42E7FDC26007D2F5D /* FenceTile.hpp */,
840DD6F02AC810620006A435 /* FireTile.cpp */,
840DD6F12AC810620006A435 /* FireTile.hpp */,
+ 84E2A3E52FBAAD6A0026780B /* FurnaceTile.cpp */,
+ 84E2A3E62FBAAD6A0026780B /* FurnaceTile.hpp */,
840DD6F22AC810620006A435 /* GlassTile.cpp */,
840DD6F32AC810620006A435 /* GlassTile.hpp */,
84E1C9C52E7FDC26007D2F5D /* GlowstoneTile.cpp */,
@@ -4180,6 +4244,8 @@
840DD7072AC810620006A435 /* LiquidTileStatic.hpp */,
840DD7082AC810620006A435 /* MetalTile.cpp */,
840DD7092AC810620006A435 /* MetalTile.hpp */,
+ 84E2A3E72FBAAD6A0026780B /* MusicTile.cpp */,
+ 84E2A3E82FBAAD6A0026780B /* MusicTile.hpp */,
840DD70A2AC810620006A435 /* ObsidianTile.cpp */,
840DD70B2AC810620006A435 /* ObsidianTile.hpp */,
840DD70C2AC810620006A435 /* OreTile.cpp */,
@@ -5010,6 +5076,8 @@
84E022EC2F2A0211003C8FFE /* ContainerScreen.hpp */,
84DED1962F3095B8004001C5 /* CraftingScreen.cpp */,
84DED1972F3095B8004001C5 /* CraftingScreen.hpp */,
+ 84E2A3C02FBAAC3A0026780B /* FurnaceScreen.cpp */,
+ 84E2A3C12FBAAC3A0026780B /* FurnaceScreen.hpp */,
84E022ED2F2A0211003C8FFE /* InventoryScreen.cpp */,
84E022EE2F2A0211003C8FFE /* InventoryScreen.hpp */,
);
@@ -5045,6 +5113,23 @@
path = base;
sourceTree = "";
};
+ 84E2A3D82FBAAD6A0026780B /* entity */ = {
+ isa = PBXGroup;
+ children = (
+ 84E2A3D92FBAAD6A0026780B /* ChestTileEntity.cpp */,
+ 84E2A3DA2FBAAD6A0026780B /* ChestTileEntity.hpp */,
+ 84E2A3DB2FBAAD6A0026780B /* FurnaceTileEntity.cpp */,
+ 84E2A3DC2FBAAD6A0026780B /* FurnaceTileEntity.hpp */,
+ 84E2A3DD2FBAAD6A0026780B /* MusicTileEntity.cpp */,
+ 84E2A3DE2FBAAD6A0026780B /* MusicTileEntity.hpp */,
+ 84E2A3DF2FBAAD6A0026780B /* TileEntity.cpp */,
+ 84E2A3E02FBAAD6A0026780B /* TileEntity.hpp */,
+ 84E2A3E12FBAAD6A0026780B /* TileEntityType.cpp */,
+ 84E2A3E22FBAAD6A0026780B /* TileEntityType.hpp */,
+ );
+ path = entity;
+ sourceTree = "";
+ };
84E7BF092F286A08002D3936 /* inventory */ = {
isa = PBXGroup;
children = (
@@ -5052,13 +5137,26 @@
84E7BF0B2F286A08002D3936 /* ArmorSlot.hpp */,
84E022FE2F2A0245003C8FFE /* ChestMenu.cpp */,
84E022FF2F2A0245003C8FFE /* ChestMenu.hpp */,
+ 84E7BF2A2F286A20002D3936 /* CompoundContainer.cpp */,
+ 84E7BF2B2F286A20002D3936 /* CompoundContainer.hpp */,
+ 84E7BF2C2F286A20002D3936 /* Container.hpp */,
+ 84E2A3C42FBAAC700026780B /* ContainerContentChangeListener.cpp */,
+ 84E2A3C52FBAAC700026780B /* ContainerContentChangeListener.hpp */,
+ 84E7BF2D2F286A20002D3936 /* ContainerListener.cpp */,
+ 84E7BF2E2F286A20002D3936 /* ContainerListener.hpp */,
84E7BF0C2F286A08002D3936 /* ContainerMenu.cpp */,
84E7BF0D2F286A08002D3936 /* ContainerMenu.hpp */,
+ 84E2A3C62FBAAC700026780B /* ContainerSizeChangeListener.cpp */,
+ 84E2A3C72FBAAC700026780B /* ContainerSizeChangeListener.hpp */,
84DAF5732F3464B400D67310 /* ContainerType.hpp */,
84E7BF0E2F286A08002D3936 /* CraftingContainer.cpp */,
84E7BF0F2F286A08002D3936 /* CraftingContainer.hpp */,
84DED19A2F3095FD004001C5 /* CraftingMenu.cpp */,
84DED19B2F3095FD004001C5 /* CraftingMenu.hpp */,
+ 84E2A3C82FBAAC700026780B /* FurnaceMenu.cpp */,
+ 84E2A3C92FBAAC700026780B /* FurnaceMenu.hpp */,
+ 84E2A3CA2FBAAC700026780B /* FurnaceResultSlot.cpp */,
+ 84E2A3CB2FBAAC700026780B /* FurnaceResultSlot.hpp */,
84E7BF102F286A08002D3936 /* InventoryMenu.cpp */,
84E7BF112F286A08002D3936 /* InventoryMenu.hpp */,
84E7BF122F286A08002D3936 /* ResultContainer.cpp */,
@@ -5883,6 +5981,7 @@
84A2FF182DB61D440090CE3E /* SoundPathRepository.hpp in Headers */,
84EB09FB2EE2CCA8008FB007 /* TextureData.hpp in Headers */,
84B1E0302E04FD4500ED000A /* ArrowRenderer.hpp in Headers */,
+ 84E2A3C32FBAAC3A0026780B /* FurnaceScreen.hpp in Headers */,
84AA8C2B2B32F3F3003F5B82 /* LightUpdate.hpp in Headers */,
84AA8C2D2B32F3F3003F5B82 /* PatchManager.hpp in Headers */,
84AA8C2F2B32F3F3003F5B82 /* RenderChunk.hpp in Headers */,
@@ -5941,6 +6040,8 @@
84E7BF292F286A08002D3936 /* Slot.hpp in Headers */,
84E1C9DC2E7FDC26007D2F5D /* TallGrass.hpp in Headers */,
84DED1AC2F309611004001C5 /* Recipe.hpp in Headers */,
+ 84E2A3FA2FBAAD6A0026780B /* MusicTile.hpp in Headers */,
+ 84E2A3F82FBAAD6A0026780B /* FurnaceTile.hpp in Headers */,
84BF638B2AF186C8008A9995 /* Dimension.hpp in Headers */,
84BF638C2AF186C8008A9995 /* Explosion.hpp in Headers */,
84BF638D2AF186C8008A9995 /* Level.hpp in Headers */,
@@ -5958,6 +6059,7 @@
84DED1AB2F309611004001C5 /* FurnaceRecipes.hpp in Headers */,
84BF63962AF186C8008A9995 /* Feature.hpp in Headers */,
8477B3AD2C4DC3F6004E1AC5 /* TilePos.hpp in Headers */,
+ 84E2A3D32FBAAC700026780B /* FurnaceResultSlot.hpp in Headers */,
84BF63972AF186C8008A9995 /* LargeCaveFeature.hpp in Headers */,
84E7BF1B2F286A08002D3936 /* ArmorSlot.hpp in Headers */,
84E7BF252F286A08002D3936 /* ResultSlot.hpp in Headers */,
@@ -5982,8 +6084,11 @@
84BF63A42AF186C8008A9995 /* LevelStorage.hpp in Headers */,
84E1C9DA2E7FDC26007D2F5D /* SoulSandTile.hpp in Headers */,
8445E7A82D769329008DC834 /* Sheep.hpp in Headers */,
+ 84E2A3F02FBAAD6A0026780B /* MusicTileEntity.hpp in Headers */,
84DED19D2F3095FD004001C5 /* CraftingMenu.hpp in Headers */,
+ 84E2A3F22FBAAD6A0026780B /* TileEntity.hpp in Headers */,
84BF63A52AF186C8008A9995 /* LevelStorageSource.hpp in Headers */,
+ 84E2A3EA2FBAAD6A0026780B /* ChestTile.hpp in Headers */,
84BF63A62AF186C8008A9995 /* MemoryChunkStorage.hpp in Headers */,
84BF63A72AF186C8008A9995 /* MemoryLevelStorage.hpp in Headers */,
84E7BF1F2F286A08002D3936 /* CraftingContainer.hpp in Headers */,
@@ -6009,9 +6114,11 @@
84BF63B42AF186C9008A9995 /* DirtTile.hpp in Headers */,
84BF63B52AF186C9008A9995 /* DoorTile.hpp in Headers */,
84BF63B62AF186C9008A9995 /* FarmTile.hpp in Headers */,
+ 84E2A3CF2FBAAC700026780B /* ContainerSizeChangeListener.hpp in Headers */,
84DED1B82F30970A004001C5 /* CraftingTableTile.hpp in Headers */,
8445E7A62D769329008DC834 /* MobCategory.hpp in Headers */,
84BF63B72AF186C9008A9995 /* FireTile.hpp in Headers */,
+ 84E2A3D12FBAAC700026780B /* FurnaceMenu.hpp in Headers */,
84BF63B82AF186C9008A9995 /* GlassTile.hpp in Headers */,
84BF63B92AF186C9008A9995 /* GrassTile.hpp in Headers */,
84BF63BA2AF186C9008A9995 /* GravelTile.hpp in Headers */,
@@ -6039,10 +6146,13 @@
84E1C9D82E7FDC26007D2F5D /* PumpkinTile.hpp in Headers */,
84BF63CA2AF186C9008A9995 /* Sapling.hpp in Headers */,
840823DC2F4FF4B80097F6A5 /* Tool.hpp in Headers */,
+ 84E2A3CD2FBAAC700026780B /* ContainerContentChangeListener.hpp in Headers */,
+ 84E2A3EE2FBAAD6A0026780B /* FurnaceTileEntity.hpp in Headers */,
84CCBC942E61880600E251AF /* EntityFactory.hpp in Headers */,
84BF63CB2AF186C9008A9995 /* SpongeTile.hpp in Headers */,
84BF63CC2AF186C9008A9995 /* StairTile.hpp in Headers */,
84E1C9D22E7FDC26007D2F5D /* DeadBush.hpp in Headers */,
+ 84E2A3F42FBAAD6A0026780B /* TileEntityType.hpp in Headers */,
84BF63CD2AF186C9008A9995 /* StoneSlabTile.hpp in Headers */,
84BF63CE2AF186C9008A9995 /* StoneTile.hpp in Headers */,
84E7BF1D2F286A08002D3936 /* ContainerMenu.hpp in Headers */,
@@ -6064,6 +6174,7 @@
848CCB462F3A38E800031D1F /* MobSpawner.hpp in Headers */,
84AA8B792B32F3B5003F5B82 /* Animal.hpp in Headers */,
84AA8B7B2B32F3B5003F5B82 /* Chicken.hpp in Headers */,
+ 84E2A3EC2FBAAD6A0026780B /* ChestTileEntity.hpp in Headers */,
84AA8B7D2B32F3B5003F5B82 /* Cow.hpp in Headers */,
84AA8B7F2B32F3B5003F5B82 /* Creeper.hpp in Headers */,
84AA8B8B2B32F3B5003F5B82 /* Monster.hpp in Headers */,
@@ -6084,6 +6195,7 @@
8470AF2B2BE9B60A00BCA54E /* EntityType.hpp in Headers */,
8445E7A42D769329008DC834 /* EntityTypeDescriptor.hpp in Headers */,
84B9D89F2F3BE0A900FD67C4 /* ArmorItem.hpp in Headers */,
+ 84E2A3F62FBAAD6A0026780B /* EntityTile.hpp in Headers */,
84B9D8A02F3BE0A900FD67C4 /* HoeItem.hpp in Headers */,
84B9D8A12F3BE0A900FD67C4 /* SeedItem.hpp in Headers */,
8470AF2D2BE9B60A00BCA54E /* MobFactory.hpp in Headers */,
@@ -6875,6 +6987,7 @@
84B8AEFD2AF1896F008DE93D /* InvalidLicenseScreen.cpp in Sources */,
84B8AEFE2AF1896F008DE93D /* JoinGameScreen.cpp in Sources */,
844336FB2F405DCA00EB3115 /* VerticalLayout.cpp in Sources */,
+ 84E2A3C22FBAAC3A0026780B /* FurnaceScreen.cpp in Sources */,
84B8AEFF2AF1896F008DE93D /* OptionsScreen.cpp in Sources */,
84B8AF002AF1896F008DE93D /* PauseScreen.cpp in Sources */,
84B8AF012AF1896F008DE93D /* ProgressScreen.cpp in Sources */,
@@ -7058,6 +7171,7 @@
84BF63102AF18631008A9995 /* Mob.cpp in Sources */,
84BF63112AF18631008A9995 /* Player.cpp in Sources */,
8445E7A52D769329008DC834 /* MobCategory.cpp in Sources */,
+ 84E2A3ED2FBAAD6A0026780B /* FurnaceTileEntity.cpp in Sources */,
84E7BF222F286A08002D3936 /* ResultContainer.cpp in Sources */,
84BF63122AF18631008A9995 /* PrimedTnt.cpp in Sources */,
84BF63132AF18631008A9995 /* TripodCamera.cpp in Sources */,
@@ -7077,10 +7191,12 @@
84E1C9F02E7FDC89007D2F5D /* VegetationFeature.cpp in Sources */,
84BF631D2AF18631008A9995 /* TilePlanterItem.cpp in Sources */,
84BF631E2AF18631008A9995 /* Dimension.cpp in Sources */,
+ 84E2A3D22FBAAC700026780B /* FurnaceResultSlot.cpp in Sources */,
84BF631F2AF18631008A9995 /* Explosion.cpp in Sources */,
84BF63202AF18631008A9995 /* Level.cpp in Sources */,
84C6142A2F323602008AC5BE /* BowItem.cpp in Sources */,
84C6142B2F323602008AC5BE /* WeaponItem.cpp in Sources */,
+ 84E2A3F32FBAAD6A0026780B /* TileEntityType.cpp in Sources */,
84BF63212AF18631008A9995 /* Biome.cpp in Sources */,
84BF63222AF18631008A9995 /* BiomeSource.cpp in Sources */,
84BF63232AF18631008A9995 /* ChunkCache.cpp in Sources */,
@@ -7104,6 +7220,7 @@
84B1E03F2E04FD7900ED000A /* Zombie.cpp in Sources */,
84BF632E2AF18631008A9995 /* LargeFeature.cpp in Sources */,
848CCB472F3A38E800031D1F /* MobSpawner.cpp in Sources */,
+ 84E2A3D02FBAAC700026780B /* FurnaceMenu.cpp in Sources */,
84BF632F2AF18631008A9995 /* OreFeature.cpp in Sources */,
84BF63302AF18631008A9995 /* PineFeature.cpp in Sources */,
84BF63312AF18631008A9995 /* ReedsFeature.cpp in Sources */,
@@ -7113,6 +7230,7 @@
84BF63352AF18631008A9995 /* ImprovedNoise.cpp in Sources */,
84BF63362AF18631008A9995 /* PerlinNoise.cpp in Sources */,
84BF63372AF18631008A9995 /* Synth.cpp in Sources */,
+ 84E2A3F92FBAAD6A0026780B /* MusicTile.cpp in Sources */,
84B9D89C2F3BE0A900FD67C4 /* ArmorItem.cpp in Sources */,
84B9D89D2F3BE0A900FD67C4 /* HoeItem.cpp in Sources */,
84B9D89E2F3BE0A900FD67C4 /* SeedItem.cpp in Sources */,
@@ -7123,7 +7241,9 @@
84BF633B2AF18631008A9995 /* ChunkStorage.cpp in Sources */,
84E1C9EE2E7FDC89007D2F5D /* CactusFeature.cpp in Sources */,
8445E7A02D769329008DC834 /* EntityCategories.cpp in Sources */,
+ 84E2A3CE2FBAAC700026780B /* ContainerSizeChangeListener.cpp in Sources */,
84DED1AA2F309611004001C5 /* FurnaceRecipes.cpp in Sources */,
+ 84E2A3CC2FBAAC700026780B /* ContainerContentChangeListener.cpp in Sources */,
84BF633C2AF18631008A9995 /* ExternalFileLevelStorage.cpp in Sources */,
84BF633D2AF18631008A9995 /* ExternalFileLevelStorageSource.cpp in Sources */,
84E1C9D72E7FDC26007D2F5D /* PumpkinTile.cpp in Sources */,
@@ -7161,6 +7281,7 @@
84BF63512AF18631008A9995 /* HitResult.cpp in Sources */,
84BF63522AF18631008A9995 /* Vec3.cpp in Sources */,
84BF63532AF18631008A9995 /* BookshelfTile.cpp in Sources */,
+ 84E2A3F52FBAAD6A0026780B /* EntityTile.cpp in Sources */,
84E7BF1C2F286A08002D3936 /* ContainerMenu.cpp in Sources */,
84BF63542AF18631008A9995 /* Bush.cpp in Sources */,
84DED1B12F309611004001C5 /* ShapelessRecipe.cpp in Sources */,
@@ -7181,15 +7302,19 @@
84BF63602AF18631008A9995 /* InvisibleTile.cpp in Sources */,
84BF63612AF18631008A9995 /* LadderTile.cpp in Sources */,
84BF63622AF18631008A9995 /* LeafTile.cpp in Sources */,
+ 84E2A3EB2FBAAD6A0026780B /* ChestTileEntity.cpp in Sources */,
84BF63632AF18631008A9995 /* LiquidTile.cpp in Sources */,
84BF63642AF18631008A9995 /* LiquidTileDynamic.cpp in Sources */,
+ 84E2A3F72FBAAD6A0026780B /* FurnaceTile.cpp in Sources */,
84BF63652AF18631008A9995 /* LiquidTileStatic.cpp in Sources */,
84BF63662AF18631008A9995 /* MetalTile.cpp in Sources */,
84BF63672AF18631008A9995 /* ObsidianTile.cpp in Sources */,
84CCBC932E61880600E251AF /* EntityFactory.cpp in Sources */,
84BF63682AF18631008A9995 /* OreTile.cpp in Sources */,
+ 84E2A3D52FBAAC860026780B /* NoteParticle.cpp in Sources */,
84B1E0392E04FD7900ED000A /* Arrow.cpp in Sources */,
84BF63692AF18631008A9995 /* RedStoneOreTile.cpp in Sources */,
+ 84E2A3F12FBAAD6A0026780B /* TileEntity.cpp in Sources */,
84BF636A2AF18631008A9995 /* ReedTile.cpp in Sources */,
84BF636B2AF18631008A9995 /* SandStoneTile.cpp in Sources */,
84BF636C2AF18631008A9995 /* SandTile.cpp in Sources */,
@@ -7201,6 +7326,7 @@
84BF63722AF18631008A9995 /* Tile.cpp in Sources */,
84BF63732AF18631008A9995 /* TntTile.cpp in Sources */,
84E7BF1E2F286A08002D3936 /* CraftingContainer.cpp in Sources */,
+ 84E2A3E92FBAAD6A0026780B /* ChestTile.cpp in Sources */,
84BF63742AF18631008A9995 /* TopSnowTile.cpp in Sources */,
8445E7A32D769329008DC834 /* EntityTypeDescriptor.cpp in Sources */,
84BF63752AF18631008A9995 /* TorchTile.cpp in Sources */,
@@ -7225,6 +7351,7 @@
840823DA2F4FF4B80097F6A5 /* CoalItem.cpp in Sources */,
84E7BF242F286A08002D3936 /* ResultSlot.cpp in Sources */,
84E7BF202F286A08002D3936 /* InventoryMenu.cpp in Sources */,
+ 84E2A3FC2FBAAD7D0026780B /* Facing.cpp in Sources */,
84AA8B8C2B32F3B5003F5B82 /* PathfinderMob.cpp in Sources */,
84AA8B8E2B32F3B5003F5B82 /* Pig.cpp in Sources */,
84AA8B962B32F3B5003F5B82 /* WaterAnimal.cpp in Sources */,
@@ -7235,6 +7362,7 @@
8470AF2C2BE9B60A00BCA54E /* MobFactory.cpp in Sources */,
84E1C9E92E7FDC72007D2F5D /* SlabItem.cpp in Sources */,
84E7BF362F286A6A002D3936 /* ItemStack.cpp in Sources */,
+ 84E2A3EF2FBAAD6A0026780B /* MusicTileEntity.cpp in Sources */,
8470AF3C2BE9B6FA00BCA54E /* FireworkParticle.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 87a01d349..4299d1c30 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -126,6 +126,7 @@ add_library(nbcraft-core STATIC
client/gui/screens/inventory/InventoryScreen.cpp
client/gui/screens/inventory/CraftingScreen.cpp
client/gui/screens/inventory/ClassicCraftingScreen_Console.cpp
+ client/gui/screens/inventory/FurnaceScreen.cpp
client/gui/screens/inventory/ChestScreen.cpp
client/gui/components/ScrolledSelectionList.cpp
client/gui/components/AvailableGamesList.cpp
@@ -354,24 +355,29 @@ add_library(nbcraft-core STATIC
world/item/TilePlanterItem.cpp
world/item/CameraItem.cpp
world/item/TileItem.cpp
+ world/item/CoalItem.cpp
world/item/Inventory.cpp
world/item/crafting/Recipes.cpp
world/item/crafting/FurnaceRecipes.cpp
world/item/crafting/SingleInputRecipe.cpp
world/item/crafting/ShapedRecipe.cpp
world/item/crafting/ShapelessRecipe.cpp
- world/ContainerListener.cpp
+ world/inventory/ContainerListener.cpp
+ world/inventory/CompoundContainer.cpp
+ world/inventory/ContainerContentChangeListener.cpp
+ world/inventory/ContainerSizeChangeListener.cpp
world/inventory/ContainerMenu.cpp
world/inventory/InventoryMenu.cpp
world/inventory/CraftingMenu.cpp
+ world/inventory/FurnaceMenu.cpp
world/inventory/ChestMenu.cpp
world/inventory/Slot.cpp
world/inventory/ResultSlot.cpp
world/inventory/ArmorSlot.cpp
+ world/inventory/FurnaceResultSlot.cpp
world/inventory/CraftingContainer.cpp
world/inventory/ResultContainer.cpp
world/inventory/SimpleContainer.cpp
- world/CompoundContainer.cpp
world/item/DoorItem.cpp
world/item/ItemStack.cpp
world/item/RocketItem.cpp
@@ -391,6 +397,7 @@ add_library(nbcraft-core STATIC
world/item/SlabItem.cpp
world/particle/RedDustParticle.cpp
world/particle/TerrainParticle.cpp
+ world/particle/NoteParticle.cpp
world/particle/BubbleParticle.cpp
world/particle/ExplodeParticle.cpp
world/particle/ParticleEngine.cpp
@@ -426,6 +433,10 @@ add_library(nbcraft-core STATIC
world/tile/OreTile.cpp
world/tile/StairTile.cpp
world/tile/SandStoneTile.cpp
+ world/tile/EntityTile.cpp
+ world/tile/ChestTile.cpp
+ world/tile/FurnaceTile.cpp
+ world/tile/MusicTile.cpp
world/tile/FireTile.cpp
world/tile/StoneSlabTile.cpp
world/tile/LiquidTile.cpp
@@ -447,6 +458,12 @@ add_library(nbcraft-core STATIC
world/tile/Web.cpp
world/tile/FenceTile.cpp
world/tile/CraftingTableTile.cpp
+ world/tile/entity/TileEntity.cpp
+ world/tile/entity/TileEntityType.cpp
+ world/tile/entity/ChestTileEntity.cpp
+ world/tile/entity/FurnaceTileEntity.cpp
+ world/tile/entity/MusicTileEntity.cpp
+ world/Facing.cpp
renderer/GL/GL.cpp
renderer/Attribute.cpp
renderer/ConstantBufferMetaData.cpp
diff --git a/source/client/app/AppPlatform.cpp b/source/client/app/AppPlatform.cpp
index 31626e691..6c3f10e31 100644
--- a/source/client/app/AppPlatform.cpp
+++ b/source/client/app/AppPlatform.cpp
@@ -322,6 +322,15 @@ std::string AppPlatform::getExternalStoragePath(const std::string& path) const
return m_externalStorageDir + C_HOME_PATH + path;
}
+void AppPlatform::setVSyncEnabled(bool enabled)
+{
+}
+
+bool AppPlatform::isVSyncSwitchable() const
+{
+ return false;
+}
+
bool AppPlatform::hasAssetFile(const std::string& path) const
{
return isRegularFile(path.c_str());
diff --git a/source/client/app/AppPlatform.hpp b/source/client/app/AppPlatform.hpp
index 7eb44d4c1..8a68246f7 100644
--- a/source/client/app/AppPlatform.hpp
+++ b/source/client/app/AppPlatform.hpp
@@ -109,6 +109,9 @@ class AppPlatform
virtual void vibrate(int milliSeconds);
virtual bool getRecenterMouseEveryTick();
virtual std::string getClipboardText();
+ // Graphics settings
+ virtual void setVSyncEnabled(bool enabled);
+ virtual bool isVSyncSwitchable() const;
void _fireLowMemory();
void _fireAppSuspended();
diff --git a/source/client/app/Minecraft.cpp b/source/client/app/Minecraft.cpp
index 2ee8c5b2a..66336ede2 100644
--- a/source/client/app/Minecraft.cpp
+++ b/source/client/app/Minecraft.cpp
@@ -185,12 +185,12 @@ void Minecraft::_initGameModes(Level& level)
}
}
-void Minecraft::_reloadInput()
+void Minecraft::reloadInput()
{
if (m_pInputHolder)
delete m_pInputHolder;
- if (isTouchscreen())
+ if (useTouchscreen())
{
m_pInputHolder = new TouchInputHolder(this, getOptions());
}
@@ -258,7 +258,7 @@ void Minecraft::grabMouse()
// This will call grabMouse again, so why are we calling it here?
//setScreen(nullptr);
- if (useController() || isTouchscreen())
+ if (useController() || useTouchscreen())
return; // don't actually try to grab the mouse
platform()->setMouseGrabbed(true);
@@ -266,7 +266,7 @@ void Minecraft::grabMouse()
void Minecraft::recenterMouse()
{
- if (useController() || isTouchscreen())
+ if (useController() || useTouchscreen())
return;
platform()->recenterMouse();
@@ -376,9 +376,14 @@ bool Minecraft::isTouchscreen() const
return m_bIsTouchscreen;
}
+bool Minecraft::useTouchscreen() const
+{
+ return isTouchscreen() && !getOptions()->m_bUseController.get();
+}
+
bool Minecraft::useSplitControls() const
{
- return !m_bIsTouchscreen || getOptions()->m_splitControls.get();
+ return !useTouchscreen() || getOptions()->m_splitControls.get();
}
bool Minecraft::useController() const
@@ -616,17 +621,7 @@ void Minecraft::tickInput()
}
else if (getOptions()->isKey(KM_DROP, keyCode))
{
- ItemStack& item = m_pLocalPlayer->m_pInventory->getSelected();
- if (!item.isEmpty())
- {
- ItemStack itemDrop(item);
- itemDrop.m_count = 1;
-
- if (m_pLocalPlayer->isSurvival())
- item.shrink(1);
-
- m_pLocalPlayer->drop(itemDrop);
- }
+ m_pLocalPlayer->drop();
}
else if (getOptions()->isKey(KM_TOGGLEGUI, keyCode))
{
@@ -694,7 +689,7 @@ void Minecraft::tickMouse()
* This is exactly what Minecraft Java does too
**/
- if (useController() || isTouchscreen())
+ if (useController() || useTouchscreen())
return; // don't actually try to recenter the mouse
if (platform()->getRecenterMouseEveryTick()) // just for SDL1
diff --git a/source/client/app/Minecraft.hpp b/source/client/app/Minecraft.hpp
index 7d1871942..7d5b9e5d7 100644
--- a/source/client/app/Minecraft.hpp
+++ b/source/client/app/Minecraft.hpp
@@ -45,9 +45,6 @@ class Minecraft : public App
GameMode* _createGameMode(GameType gameType, Level& level);
void _initGameModes(Level& level);
-protected:
- void _reloadInput();
-
public:
int getLicenseId();
void setScreen(Screen * pScreen);
@@ -80,11 +77,13 @@ class Minecraft : public App
void handlePointerPressedButtonRelease();
void handleKeyboardClosed();
void resetInput();
+ void reloadInput();
void sendMessage(const std::string& message);
void respawnPlayer();
void freeResources(bool bCopyMap);
std::string getVersionString(const std::string& str = Util::EMPTY_STRING) const;
bool isTouchscreen() const;
+ bool useTouchscreen() const;
bool useSplitControls() const;
bool useController() const;
@@ -122,6 +121,7 @@ class Minecraft : public App
private:
// Value provided by the OS
static float _renderScaleMultiplier;
+
public:
static float getRenderScaleMultiplier() { return _renderScaleMultiplier; }
static void setRenderScaleMultiplier(float value) { _renderScaleMultiplier = value; }
diff --git a/source/client/app/NinecraftApp.cpp b/source/client/app/NinecraftApp.cpp
index f7f8294fe..45c7bc339 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/tile/entity/TileEntityType.hpp"
#include "client/player/input/GameControllerHandler.hpp"
#include "client/player/input/Multitouch.hpp"
#include "client/gui/screens/StartMenuScreen.hpp"
@@ -104,7 +105,7 @@ void NinecraftApp::_initInput()
m_bIsTouchscreen = platform()->isTouchscreen();
getOptions()->m_bUseController.set(platform()->hasGamepad());
getOptions()->loadControls();
- _reloadInput();
+ reloadInput();
}
void NinecraftApp::_updateStats()
@@ -179,10 +180,10 @@ void NinecraftApp::_initAll()
EntityTypeDescriptor::initDescriptors(); // custom
MobCategory::initMobCategories();
MobFactory::initMobLists();
+ TileEntityFactory::initTileEntities();
Tile::initTiles();
Item::initItems();
Biome::initBiomes();
- //TileEntity::initTileEntities();
}
_initOptions();
@@ -340,6 +341,7 @@ void NinecraftApp::onGraphicsReset()
void NinecraftApp::teardown()
{
+ TileEntityFactory::teardownTileEntities();
teardownRenderer();
Resource::teardownLoaders();
// Stop our SoundSystem before we nuke our sound buffers and cause it to implode
diff --git a/source/client/gui/Gui.cpp b/source/client/gui/Gui.cpp
index c7f92ea19..f3b5ed054 100644
--- a/source/client/gui/Gui.cpp
+++ b/source/client/gui/Gui.cpp
@@ -261,7 +261,7 @@ void Gui::renderSlot(int slot, int x, int y, float f)
ItemRenderer::singleton().renderGuiItem(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, item, x, y, true);
}
- //ItemRenderer::renderGuiItemDecorations(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, item, x, y);
+ //ItemRenderer::renderGuiItemDecorations(m_pMinecraft->m_pFont, m_pMinecraft->m_pTextures, item, x, y);
}
void Gui::renderSlotOverlay(int slot, int x, int y, float f)
@@ -335,7 +335,8 @@ void Gui::handleClick(int clickID, int mouseX, int mouseY)
if (slot == -1)
return;
- if (m_pMinecraft->isTouchscreen() && slot == getNumSlots() - 1)
+ // Final slot on touch opens inventory
+ if (m_pMinecraft->useTouchscreen() && slot == getNumSlots() - 1)
{
if (m_pMinecraft->getLocalPlayerGameMode()->isSurvivalType())
m_pMinecraft->setScreen(new InventoryScreen(m_pMinecraft->m_pLocalPlayer));
@@ -348,22 +349,22 @@ void Gui::handleClick(int clickID, int mouseX, int mouseY)
void Gui::handleScrollWheel(bool down)
{
- SlotID slot = m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedSlot;
+ Container::StackID stackId = m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedStackId;
int maxItems = getNumUsableSlots() - 1;
if (down)
{
- if (slot++ == maxItems)
- slot = 0;
+ if (stackId++ == maxItems)
+ stackId = 0;
}
else
{
- if (slot-- == 0)
- slot = maxItems;
+ if (stackId-- == 0)
+ stackId = maxItems;
}
- m_pMinecraft->m_pLocalPlayer->m_pInventory->selectSlot(slot);
+ m_pMinecraft->m_pLocalPlayer->m_pInventory->selectSlot(stackId);
}
void Gui::handleKeyPressed(int keyCode)
@@ -384,23 +385,23 @@ void Gui::handleKeyPressed(int keyCode)
if (slotL || slotR)
{
int maxItems = getNumSlots() - 1;
- if (m_pMinecraft->isTouchscreen())
+ if (m_pMinecraft->useTouchscreen())
maxItems--;
- SlotID* slot = &m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedSlot;
+ Container::StackID* stackId = &m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedStackId;
if (slotR)
{
- if (*slot < maxItems)
- (*slot)++;
+ if (*stackId < maxItems)
+ (*stackId)++;
else
- *slot = 0;
+ *stackId = 0;
}
else if (slotL)
{
- if (*slot > 0)
- (*slot)--;
+ if (*stackId > 0)
+ (*stackId)--;
else
- *slot = maxItems;
+ *stackId = maxItems;
}
return;
}
@@ -689,7 +690,7 @@ void Gui::renderToolBar(float f, float alpha)
Inventory* inventory = player->m_pInventory;
// selection mark
- blit(-1 - hotbarWidth / 2 + 20 * inventory->m_selectedSlot, -23, 0, 22, 24, 22, 0, 0);
+ blit(-1 - hotbarWidth / 2 + 20 * inventory->m_selectedStackId, -23, 0, 22, 24, 22, 0, 0);
// chat and pause button for mobile devices
if (mc->isTouchscreen())
@@ -706,7 +707,7 @@ void Gui::renderToolBar(float f, float alpha)
textures->loadAndBindTexture(C_BLOCKS_NAME);
- int diff = mc->isTouchscreen();
+ int diff = mc->useTouchscreen();
int slotX = -hotbarWidth / 2 + 3;
for (int i = 0; i < nSlots - diff; i++)
@@ -728,8 +729,8 @@ void Gui::renderToolBar(float f, float alpha)
field_A3C = false;
- // blit the "more items" button
- if (mc->isTouchscreen())
+ // blit the "more items" button if using touch
+ if (mc->useTouchscreen())
{
textures->loadAndBindTexture(C_TERRAIN_NAME);
blit(hotbarWidth / 2 - 19, -19, 208, 208, 16, 16, 0, 0);
@@ -747,7 +748,7 @@ int Gui::getNumSlots()
int Gui::getNumUsableSlots()
{
- return getNumSlots() - m_pMinecraft->isTouchscreen();
+ return getNumSlots() - m_pMinecraft->useTouchscreen();
}
RectangleArea Gui::getRectangleArea(bool b)
diff --git a/source/client/gui/Gui.hpp b/source/client/gui/Gui.hpp
index 9957d2f65..156f13788 100644
--- a/source/client/gui/Gui.hpp
+++ b/source/client/gui/Gui.hpp
@@ -42,6 +42,7 @@ class Gui : public GuiComponent
private:
static bool _isVignetteAvailable;
+
public:
static bool isVignetteAvailable() { return _isVignetteAvailable; }
static void setIsVignetteAvailable(bool value) { _isVignetteAvailable = value; }
diff --git a/source/client/gui/Screen.cpp b/source/client/gui/Screen.cpp
index 5c029da2b..4dd2f1922 100644
--- a/source/client/gui/Screen.cpp
+++ b/source/client/gui/Screen.cpp
@@ -399,7 +399,7 @@ void Screen::pointerPressed(const MenuPointer& pointer, MouseButtonType btn) //
{
m_pClickedElement = element;
- if (!m_pMinecraft->isTouchscreen())
+ if (!m_pMinecraft->useTouchscreen())
{
if (_useController())
m_pMinecraft->m_pSoundEngine->playUI(C_SOUND_UI_PRESS);
diff --git a/source/client/gui/ScreenChooser.cpp b/source/client/gui/ScreenChooser.cpp
index d2620083f..2ce71d3a7 100644
--- a/source/client/gui/ScreenChooser.cpp
+++ b/source/client/gui/ScreenChooser.cpp
@@ -5,6 +5,7 @@
#include "screens/PauseScreen.hpp"
#include "screens/inventory/CraftingScreen.hpp"
#include "screens/inventory/ChestScreen.hpp"
+#include "screens/inventory/FurnaceScreen.hpp"
#include "screens/OptionsScreen.hpp"
#include "screens/OptionsScreen_Console.hpp"
#include "screens/CreateWorldScreen.hpp"
@@ -53,6 +54,11 @@ void ScreenChooser::pushCraftingScreen(Player* player, const TilePos& pos)
m_pMinecraft->setScreen(new CraftingScreen(player->m_pInventory, pos, player->m_pLevel));
}
+void ScreenChooser::pushFurnaceScreen(Player* player, FurnaceTileEntity* furnace)
+{
+ m_pMinecraft->setScreen(new FurnaceScreen(player->m_pInventory, furnace));
+}
+
void ScreenChooser::pushChestScreen(Player* player, Container* container)
{
m_pMinecraft->setScreen(new ChestScreen(player->m_pInventory, container));
diff --git a/source/client/gui/ScreenChooser.hpp b/source/client/gui/ScreenChooser.hpp
index c052f6233..e78800ade 100644
--- a/source/client/gui/ScreenChooser.hpp
+++ b/source/client/gui/ScreenChooser.hpp
@@ -7,6 +7,7 @@ class Player;
class Minecraft;
class Container;
class Screen;
+class FurnaceTileEntity;
//@NOTE: This is just based on MCPE, not really a decompilation, make it accurate if necessary
class ScreenChooser
@@ -22,6 +23,7 @@ class ScreenChooser
virtual void pushOptionsScreen(Screen*);
virtual void pushProgressScreen();
virtual void pushCraftingScreen(Player*, const TilePos&); // originally pushWorkbenchScreen
+ virtual void pushFurnaceScreen(Player*, FurnaceTileEntity*);
virtual void pushChestScreen(Player*, Container*);
virtual void pushCreditsScreen(Screen*);
diff --git a/source/client/gui/components/OptionList.cpp b/source/client/gui/components/OptionList.cpp
index 062f32f5e..d85ca3378 100644
--- a/source/client/gui/components/OptionList.cpp
+++ b/source/client/gui/components/OptionList.cpp
@@ -173,14 +173,15 @@ void OptionList::initControlsMenu()
if (!m_pMinecraft->isTouchscreen())
m_items[idxSplit]->setEnabled(false);
- m_items[idxController]->setEnabled(false);
+ if (!m_pMinecraft->m_pPlatform->hasGamepad())
+ m_items[idxController]->setEnabled(false);
}
void OptionList::initVideoMenu()
{
Options* pOptions = m_pMinecraft->getOptions();
int currentIndex = -1;
- int idxPano = -1;
+ int idxPano = -1, idxVSync = -1;
OPTIONS_LIST_VIDEO_GRAPHICS;
OPTIONS_LIST_VIDEO_EXPERIMENTAL;
@@ -189,6 +190,9 @@ void OptionList::initVideoMenu()
if (!Screen::isMenuPanoramaAvailable())
m_items[idxPano]->setEnabled(false);
#endif
+
+ if (!m_pMinecraft->platform()->isVSyncSwitchable())
+ m_items[idxVSync]->setEnabled(false);
}
OptionHeader::OptionHeader(const std::string& text)
diff --git a/source/client/gui/components/SliderButton.cpp b/source/client/gui/components/SliderButton.cpp
index c51698e89..8689349f2 100644
--- a/source/client/gui/components/SliderButton.cpp
+++ b/source/client/gui/components/SliderButton.cpp
@@ -69,7 +69,7 @@ void SliderButton::renderBg(Minecraft* mc, const MenuPointer& pointer)
if (m_uiTheme == UI_CONSOLE)
{
blitSprite(texs, "gui/console/Graphics/Slider_Track.png", m_xPos, m_yPos, m_width - 2, m_height, nullptr, 0.0f, 0.0f, m_width - 2);
- blitSprite(texs, "gui/console/Graphics/Slider_Track.png", m_xPos + m_width - 2, m_yPos, 2, m_height, nullptr, 0.0f, 0.0f, 2.0f);
+ blitSprite(texs, "gui/console/Graphics/Slider_Track.png", m_xPos + m_width - 2, m_yPos, 2, m_height, nullptr, 0.0f, 0.0f, 2);
if (isSelected())
blitNineSlice(texs, "gui/slider_highlight.png", m_xPos - 3, m_yPos - 3, m_width + 6, m_height + 6, 5);
blitSprite(texs, "gui/console/Graphics/Slider_Button.png", m_xPos + int(m_value * float(m_width - 16)), m_yPos, 16, m_height);
diff --git a/source/client/gui/components/TextBox.cpp b/source/client/gui/components/TextBox.cpp
index 895de827f..711ca9c76 100644
--- a/source/client/gui/components/TextBox.cpp
+++ b/source/client/gui/components/TextBox.cpp
@@ -149,7 +149,8 @@ bool TextBox::pointerPressed(Minecraft* pMinecraft, const MenuPointer& pointer)
#ifndef HANDLE_CHARS_SEPARATELY
-char TextBox::guessCharFromKey(int key) {
+char TextBox::guessCharFromKey(int key)
+{
bool bShiftPressed = m_pParent->m_pMinecraft->platform()->shiftPressed();
char chr = '\0';
if (key >= AKEYCODE_A && key <= AKEYCODE_Z)
@@ -218,13 +219,15 @@ void TextBox::handleButtonPress(Minecraft* pMinecraft, int key)
#ifndef HANDLE_CHARS_SEPARATELY
char guess = guessCharFromKey(key);
- if (guess != '\0') {
+ if (guess != '\0')
+ {
handleTextChar(guess);
return;
}
#endif
- switch (key) {
+ switch (key)
+ {
case AKEYCODE_DEL:
{
// handled elsewhere, do not dupe
@@ -298,7 +301,8 @@ void TextBox::handleTextChar(Minecraft* pMinecraft, int k)
if (!hasFocus())
return;
- switch (k) {
+ switch (k)
+ {
case '\b': // BACKSPACE
case '\x7f': // DELETE
{
@@ -546,10 +550,13 @@ void TextBox::recalculateScroll()
}
else
{
- if (m_scrollPos == int(m_text.length())) {
+ if (m_scrollPos == int(m_text.length()))
+ {
LOG_W("Text Box Is Too Small");
break;
- } else {
+ }
+ else
+ {
m_scrollPos++;
}
}
diff --git a/source/client/gui/screens/IngameBlockSelectionScreen.hpp b/source/client/gui/screens/IngameBlockSelectionScreen.hpp
index 097af0f64..0167b1229 100644
--- a/source/client/gui/screens/IngameBlockSelectionScreen.hpp
+++ b/source/client/gui/screens/IngameBlockSelectionScreen.hpp
@@ -43,7 +43,7 @@ class IngameBlockSelectionScreen : public Screen
void keyPressed(int key) override;
private:
- SlotID m_selectedSlot;
+ Container::SlotID m_selectedSlot;
bool m_bReleased;
bool m_bClickedOnSlot;
Button m_btnCraft;
diff --git a/source/client/gui/screens/OptionsScreen_Console.cpp b/source/client/gui/screens/OptionsScreen_Console.cpp
index 934283210..ef505cdb0 100644
--- a/source/client/gui/screens/OptionsScreen_Console.cpp
+++ b/source/client/gui/screens/OptionsScreen_Console.cpp
@@ -19,9 +19,9 @@ OptionsScreen_Console::OptionsScreen_Console(Screen* screen) :
void OptionsScreen_Console::_buttonClicked(Button* btn)
{
if (btn->getId() == m_btnControls.getId())
- m_pMinecraft->setScreen(new ControlsPanelScreen(this, m_pMinecraft));
+ m_pMinecraft->setScreen(new ControlsPanelScreen(this, *m_pMinecraft));
else if (btn->getId() == m_btnSettings.getId())
- m_pMinecraft->setScreen(new SettingsPanelScreen(this, *m_pMinecraft->getOptions()));
+ m_pMinecraft->setScreen(new SettingsPanelScreen(this, *m_pMinecraft));
else if (btn->getId() == m_btnCredits.getId())
m_pMinecraft->getScreenChooser()->pushCreditsScreen(this);
else if (btn->getId() == m_btnResetToDefaults.getId())
@@ -73,9 +73,9 @@ bool OptionsScreen_Console::handleBackEvent(bool b)
#define HEADER(text) do { m_layout.m_elements.push_back(new OptionHeader_Console(text)); currentIndex++; } while (0)
#define OPTION(name) do { options.name.addGuiElement(m_layout.m_elements, m_uiTheme); currentIndex++; } while (0)
-ControlsPanelScreen::ControlsPanelScreen(Screen* parent, Minecraft* mc) : PanelScreen_Console(parent)
+ControlsPanelScreen::ControlsPanelScreen(Screen* parent, Minecraft& mc) : PanelScreen_Console(parent)
{
- Options& options = *mc->getOptions();
+ Options& options = *mc.getOptions();
int currentIndex = -1;
int idxSplit = -1, idxController = -1;
@@ -83,9 +83,10 @@ ControlsPanelScreen::ControlsPanelScreen(Screen* parent, Minecraft* mc) : PanelS
OPTIONS_LIST_CONTROLS_FEEDBACK;
OPTIONS_LIST_CONTROLS_EXPERIMENTAL;
- if (!mc->isTouchscreen())
- m_layout.m_elements[idxSplit]->setEnabled(false);
m_layout.m_elements[idxController]->setEnabled(false);
+
+ if (!mc.isTouchscreen())
+ m_layout.m_elements[idxSplit]->setEnabled(false);
}
void ControlsPanelScreen::removed()
@@ -93,10 +94,14 @@ void ControlsPanelScreen::removed()
m_pMinecraft->saveOptionsAsync();
}
-SettingsPanelScreen::SettingsPanelScreen(Screen* parent, Options& options) : PanelScreen_Console(parent)
+SettingsPanelScreen::SettingsPanelScreen(Screen* parent, Minecraft& mc) : PanelScreen_Console(parent)
{
+ m_pMinecraft = &mc;
+
int currentIndex = -1;
- int idxPano = -1;
+ int idxPano = -1, idxVSync = -1;
+
+ Options& options = *mc.getOptions();
OPTIONS_LIST_GAMEPLAY_GAME;
OPTIONS_LIST_GAMEPLAY_AUDIO;
@@ -108,6 +113,9 @@ SettingsPanelScreen::SettingsPanelScreen(Screen* parent, Options& options) : Pan
m_layout.m_elements[idxPano]->setEnabled(false);
#endif
+ if (!m_pMinecraft->platform()->isVSyncSwitchable())
+ m_layout.m_elements[idxVSync]->setEnabled(false);
+
(void)currentIndex; // compiler will warn about an unused variable sometimes if this isn't here
}
diff --git a/source/client/gui/screens/OptionsScreen_Console.hpp b/source/client/gui/screens/OptionsScreen_Console.hpp
index 3a7a3cbe7..1d2c164cb 100644
--- a/source/client/gui/screens/OptionsScreen_Console.hpp
+++ b/source/client/gui/screens/OptionsScreen_Console.hpp
@@ -6,7 +6,7 @@
class ControlsPanelScreen : public PanelScreen_Console
{
public:
- ControlsPanelScreen(Screen*, Minecraft*);
+ ControlsPanelScreen(Screen*, Minecraft&);
void removed() override;
};
@@ -14,7 +14,7 @@ class ControlsPanelScreen : public PanelScreen_Console
class SettingsPanelScreen : public PanelScreen_Console
{
public:
- SettingsPanelScreen(Screen*, Options&);
+ SettingsPanelScreen(Screen*, Minecraft&);
void render(float) override;
void removed() override;
diff --git a/source/client/gui/screens/inventory/ChestScreen.cpp b/source/client/gui/screens/inventory/ChestScreen.cpp
index 312618638..5fc0d08f4 100644
--- a/source/client/gui/screens/inventory/ChestScreen.cpp
+++ b/source/client/gui/screens/inventory/ChestScreen.cpp
@@ -6,41 +6,101 @@ ChestScreen::ChestScreen(Container* inventory, Container* container) : Container
m_pInventory(inventory),
m_pContainer(container)
{
- constexpr int defaultHeight = 222;
- constexpr int noRowHeight = defaultHeight - 108;
m_containerRows = m_pContainer->getContainerSize() / 9;
- m_imageHeight = noRowHeight + m_containerRows * 18;
+}
+
+void ChestScreen::init()
+{
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ constexpr int defaultHeight = 412;
+ constexpr int noRowHeight = defaultHeight - 126;
+ m_imageWidth = 432;
+ m_imageHeight = noRowHeight + m_containerRows * 42;
+ }
+ else
+ {
+ constexpr int defaultHeight = 222;
+ constexpr int noRowHeight = defaultHeight - 108;
+ m_imageHeight = noRowHeight + m_containerRows * 18;
+ }
+
+ ContainerScreen::init();
+
+ if (m_uiTheme == UI_CONSOLE)
+ m_topPos = Mth::Max(24, m_topPos - 48);
}
void ChestScreen::_renderLabels()
{
- m_pFont->draw(m_pContainer->getName(), 8, 6, Color::TEXT_GREY);
- m_pFont->draw(m_pInventory->getName(), 8, m_imageHeight - 96 + 2, Color::TEXT_GREY);
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ m_pFont->drawScalable(m_pContainer->getName(), 28, 20, Color::TEXT_GREY);
+ m_pFont->drawScalable(m_pInventory->getName(), 28, m_imageHeight - 234 + 8, Color::TEXT_GREY);
+ }
+ else
+ {
+ m_pFont->draw(m_pContainer->getName(), 8, 6, Color::TEXT_GREY);
+ m_pFont->draw(m_pInventory->getName(), 8, m_imageHeight - 96 + 2, Color::TEXT_GREY);
+ }
}
void ChestScreen::_renderBg(float partialTicks)
{
- m_pMinecraft->m_pTextures->loadAndBindTexture("gui/container.png");
- currentShaderColor = Color::WHITE;
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ blitNineSlice(*m_pMinecraft->m_pTextures, ScreenRenderer::PANEL_SLICES, m_leftPos, m_topPos, m_imageWidth, m_imageHeight, 32);
+ }
+ else
+ {
+ m_pMinecraft->m_pTextures->loadAndBindTexture("gui/container.png");
+ currentShaderColor = Color::WHITE;
- blit(m_leftPos, m_topPos, 0, 0, m_imageWidth, m_containerRows * 18 + 17, 0, 0);
- blit(m_leftPos, m_topPos + m_containerRows * 18 + 17, 0, 126, m_imageWidth, 96, 0, 0);
+ blit(m_leftPos, m_topPos, 0, 0, m_imageWidth, m_containerRows * 18 + 17, 0, 0);
+ blit(m_leftPos, m_topPos + m_containerRows * 18 + 17, 0, 126, m_imageWidth, 96, 0, 0);
+ }
}
SlotDisplay ChestScreen::_createSlotDisplay(const Slot& slot)
{
- constexpr int slotSize = 18;
- int rows = m_pContainer->getContainerSize() / 9;
- int verticalOffset = (rows - 4) * slotSize;
- switch (slot.m_group)
- {
- case Slot::CONTAINER:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 18 + verticalOffset + ((slot.m_slot / 9) - 1) * slotSize, slotSize);
- case Slot::INVENTORY:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 103 + verticalOffset + ((slot.m_slot / 9) - 1) * slotSize, slotSize);
- case Slot::HOTBAR:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 142, slotSize);
- default:
- return SlotDisplay();
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ constexpr int slotSize = 42;
+ int rows = m_pContainer->getContainerSize() / 9;
+ switch (slot.m_group)
+ {
+ case Slot::CONTAINER:
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 50 + (slot.m_stackId / 9) * slotSize, slotSize, true);
+ case Slot::INVENTORY:
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, (rows * 42) + 45 + (slot.m_stackId / 9) * slotSize, slotSize, true);
+ case Slot::HOTBAR:
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 226 + rows * slotSize, slotSize, true);
+ default:
+ return SlotDisplay();
+ }
}
+ else
+ {
+ constexpr int slotSize = 18;
+ int rows = m_pContainer->getContainerSize() / 9;
+ switch (slot.m_group)
+ {
+ case Slot::CONTAINER:
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 18 + (slot.m_stackId / 9) * slotSize, slotSize);
+ case Slot::INVENTORY:
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, (rows * 18) + 13 + (slot.m_stackId / 9) * slotSize, slotSize);
+ case Slot::HOTBAR:
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 89 + rows * slotSize, slotSize);
+ default:
+ return SlotDisplay();
+ }
+ }
+}
+
+void ChestScreen::renderBackground()
+{
+ if (m_uiTheme == UI_CONSOLE)
+ return;
+
+ ContainerScreen::renderBackground();
}
diff --git a/source/client/gui/screens/inventory/ChestScreen.hpp b/source/client/gui/screens/inventory/ChestScreen.hpp
index e5b4a92b8..5a9ccaf2c 100644
--- a/source/client/gui/screens/inventory/ChestScreen.hpp
+++ b/source/client/gui/screens/inventory/ChestScreen.hpp
@@ -6,12 +6,16 @@ class ChestScreen : public ContainerScreen
{
public:
ChestScreen(Container* inventory, Container* container);
+ void init() override;
protected:
void _renderLabels() override;
void _renderBg(float partialTicks) override;
SlotDisplay _createSlotDisplay(const Slot&);
+public:
+ void renderBackground() override;
+
private:
Container* m_pInventory;
Container* m_pContainer;
diff --git a/source/client/gui/screens/inventory/ClassicCraftingScreen_Console.cpp b/source/client/gui/screens/inventory/ClassicCraftingScreen_Console.cpp
index f81d568a5..54d2d2a9f 100644
--- a/source/client/gui/screens/inventory/ClassicCraftingScreen_Console.cpp
+++ b/source/client/gui/screens/inventory/ClassicCraftingScreen_Console.cpp
@@ -37,11 +37,11 @@ SlotDisplay ClassicCraftingScreen_Console::_createSlotDisplay(const Slot& slot)
case Slot::OUTPUT:
return SlotDisplay(308, 97, 64, true);
case Slot::INPUT:
- return SlotDisplay(62 + (slot.m_slot % 3) * slotSize, 64 + (slot.m_slot / 3) * slotSize, slotSize, true);
+ return SlotDisplay(62 + (slot.m_stackId % 3) * slotSize, 64 + (slot.m_stackId / 3) * slotSize, slotSize, true);
case Slot::INVENTORY:
- return SlotDisplay(28 + (slot.m_slot % 9) * slotSize, 240 + ((slot.m_slot / 9) - 1) * slotSize, slotSize, true);
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 240 + ((slot.m_stackId / 9) - 1) * slotSize, slotSize, true);
case Slot::HOTBAR:
- return SlotDisplay(28 + (slot.m_slot % 9) * slotSize, 379, slotSize, true);
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 379, slotSize, true);
default:
return SlotDisplay();
}
diff --git a/source/client/gui/screens/inventory/ContainerScreen.cpp b/source/client/gui/screens/inventory/ContainerScreen.cpp
index 46f241ead..0ce0919c9 100644
--- a/source/client/gui/screens/inventory/ContainerScreen.cpp
+++ b/source/client/gui/screens/inventory/ContainerScreen.cpp
@@ -140,7 +140,7 @@ void ContainerScreen::initMenuPointer()
{
Slot* slot = *it;
//@NOTE: Selects the first hotbar slot
- if (slot->m_slot == 0 && m_pMinecraft->m_pLocalPlayer && slot->m_pContainer == m_pMinecraft->m_pLocalPlayer->m_pInventory)
+ if (slot->m_id == 0 && m_pMinecraft->m_pLocalPlayer && slot->m_pContainer == m_pMinecraft->m_pLocalPlayer->m_pInventory)
{
_selectSlot(slot);
break;
@@ -212,16 +212,20 @@ void ContainerScreen::render(float partialTicks)
if (!name.empty())
{
int w = m_pFont->width(name);
- int tx = m_menuPointer.x - m_leftPos + 12;
- int ty = m_menuPointer.y - m_topPos - 12;
+ int tx = m_menuPointer.x - m_leftPos;
+ int ty = m_menuPointer.y - m_topPos;
if (m_uiTheme == UI_CONSOLE)
{
- blitNineSlice(*m_pMinecraft->m_pTextures, ScreenRenderer::POINTER_TEXT_PANEL_SLICES, tx - 6, ty - 6, w * 2 + 12, 28, 8);
+ tx += 10;
+ ty -= 32;
+ blitNineSlice(*m_pMinecraft->m_pTextures, ScreenRenderer::POINTER_TEXT_PANEL_SLICES, tx - 6, ty - 6, w * 2 + 12, 34, 8);
MatrixStack::Ref tooltipMatrix = MatrixStack::World.push();
- m_pFont->drawScalable(name, tx, ty, -1);
+ m_pFont->drawScalableShadow(name, tx, ty + 4, -1);
}
else
{
+ tx += 12;
+ ty -= 12;
fillGradient(tx - 3, ty - 3, tx + w + 3, ty + 8 + 3, 0xC0000000, 0xC0000000);
m_pFont->drawShadow(name, tx, ty, -1);
}
@@ -235,14 +239,14 @@ void ContainerScreen::render(float partialTicks)
void ContainerScreen::pointerPressed(const MenuPointer& pointer, MouseButtonType button)
{
Screen::pointerPressed(pointer, button);
- if (m_pMinecraft->isTouchscreen()) return;
+ if (m_pMinecraft->useTouchscreen()) return;
slotClicked(pointer, button);
}
void ContainerScreen::pointerReleased(const MenuPointer& pointer, MouseButtonType button)
{
Screen::pointerReleased(pointer, button);
- if (m_pMinecraft->isTouchscreen() && m_timeSlotDragged < 5)
+ if (m_pMinecraft->useTouchscreen() && m_timeSlotDragged < 5)
slotClicked(pointer, button);
m_timeSlotDragged = 0;
}
@@ -254,7 +258,7 @@ void ContainerScreen::handlePointerPressed(bool isPressed)
m_timeSlotDragged++;
else m_timeSlotDragged = 0;
- if (m_pMinecraft->isTouchscreen() && m_timeSlotDragged % 5 == 0)
+ if (m_pMinecraft->useTouchscreen() && m_timeSlotDragged % 5 == 0)
{
slotClicked(m_menuPointer, MOUSE_BUTTON_RIGHT);
}
@@ -266,18 +270,18 @@ void ContainerScreen::slotClicked(const MenuPointer& pointer, MouseButtonType bu
{
Slot* slot = _findSlot(pointer.x, pointer.y);
bool outside = pointer.x < m_leftPos || pointer.y < m_topPos || pointer.x >= m_leftPos + m_imageWidth || pointer.y >= m_topPos + m_imageHeight;
- int index = -1;
- if (slot) index = slot->m_index;
- if (outside) index = -999;
- if (index != -1)
- slotClicked(slot, index, button, index != -999 && quick);
+ Container::SlotID slotId = -1;
+ if (slot) slotId = slot->m_id;
+ if (outside) slotId = -999;
+ if (slotId != -1)
+ slotClicked(slot, slotId, button, slotId != -999 && quick);
}
}
-void ContainerScreen::slotClicked(Slot* slot, int index, MouseButtonType button, bool quick)
+void ContainerScreen::slotClicked(Slot* slot, Container::SlotID slotId, MouseButtonType button, bool quick)
{
_tryPlayInteractSound();
- m_pMinecraft->getLocalPlayerGameMode()->handleInventoryMouseClick(m_pMenu->m_containerId, index, button, quick, m_pMinecraft->m_pLocalPlayer);
+ m_pMinecraft->getLocalPlayerGameMode()->handleInventoryMouseClick(m_pMenu->m_containerId, slotId, button, quick, m_pMinecraft->m_pLocalPlayer);
}
void ContainerScreen::slotClicked(const MenuPointer& pointer, MouseButtonType button)
@@ -317,7 +321,7 @@ void ContainerScreen::keyPressed(int keyCode)
const SlotDisplay& ContainerScreen::getSlotDisplay(const Slot& slot) const
{
- return m_slotDisplays[slot.m_index];
+ return m_slotDisplays[slot.m_id];
}
void ContainerScreen::onClose()
@@ -369,5 +373,5 @@ bool ContainerScreen::SlotNavigation::next(int& x, int& y, bool cycle)
bool ContainerScreen::SlotNavigation::isValid(ID id)
{
Slot* hovered = m_pScreen->_findSlot();
- return !hovered || hovered->m_index != id;
+ return !hovered || hovered->m_id != id;
}
diff --git a/source/client/gui/screens/inventory/ContainerScreen.hpp b/source/client/gui/screens/inventory/ContainerScreen.hpp
index 274120153..67a7c2dd9 100644
--- a/source/client/gui/screens/inventory/ContainerScreen.hpp
+++ b/source/client/gui/screens/inventory/ContainerScreen.hpp
@@ -73,7 +73,7 @@ class ContainerScreen : public Screen
virtual void initMenuPointer() override;
virtual void slotsChanged(Container* container);
virtual void slotClicked(const MenuPointer& pointer, MouseButtonType button, bool quick);
- virtual void slotClicked(Slot* slot, int index, MouseButtonType button, bool quick);
+ virtual void slotClicked(Slot* slot, Container::SlotID slotId, MouseButtonType button, bool quick);
void slotClicked(const MenuPointer& pointer, MouseButtonType button);
public:
diff --git a/source/client/gui/screens/inventory/CraftingScreen.cpp b/source/client/gui/screens/inventory/CraftingScreen.cpp
index 3a66ffc37..f2ebbea25 100644
--- a/source/client/gui/screens/inventory/CraftingScreen.cpp
+++ b/source/client/gui/screens/inventory/CraftingScreen.cpp
@@ -32,11 +32,11 @@ SlotDisplay CraftingScreen::_createSlotDisplay(const Slot& slot)
case Slot::OUTPUT:
return SlotDisplay(124, 35);
case Slot::INPUT:
- return SlotDisplay(30 + (slot.m_slot % 3) * slotSize, 17 + (slot.m_slot / 3) * slotSize);
+ return SlotDisplay(30 + (slot.m_stackId % 3) * slotSize, 17 + (slot.m_stackId / 3) * slotSize);
case Slot::INVENTORY:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 84 + ((slot.m_slot / 9) - 1) * slotSize, slotSize);
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 84 + ((slot.m_stackId / 9) - 1) * slotSize, slotSize);
case Slot::HOTBAR:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 142, slotSize);
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 142, slotSize);
default:
return SlotDisplay();
}
diff --git a/source/client/gui/screens/inventory/FurnaceScreen.cpp b/source/client/gui/screens/inventory/FurnaceScreen.cpp
new file mode 100644
index 000000000..b28a8a18d
--- /dev/null
+++ b/source/client/gui/screens/inventory/FurnaceScreen.cpp
@@ -0,0 +1,131 @@
+#include "FurnaceScreen.hpp"
+#include "world/inventory/FurnaceMenu.hpp"
+#include "renderer/ShaderConstants.hpp"
+
+FurnaceScreen::FurnaceScreen(Inventory* inventory, FurnaceTileEntity* container)
+ : ContainerScreen(new FurnaceMenu(inventory, container))
+ , m_pInventory(inventory)
+ , m_pFurnace(container)
+{
+}
+
+void FurnaceScreen::init()
+{
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ m_imageWidth = 432;
+ m_imageHeight = 436;
+ }
+ ContainerScreen::init();
+ if (m_uiTheme == UI_CONSOLE)
+ m_topPos = Mth::Max(24, m_topPos - 48);
+}
+
+void FurnaceScreen::tick()
+{
+ ContainerScreen::tick();
+}
+
+void FurnaceScreen::_renderLabels()
+{
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ m_pFont->drawScalable(m_pFurnace->getName(), 26, 21, 0x404040);
+ m_pFont->drawScalable(m_pInventory->getName(), 26, m_imageHeight - 238 + 2, 0x404040);
+
+ m_pFont->drawScalable("Ingredient", 40, 68, 0x404040);
+ m_pFont->drawScalable("Fuel", 102, 162, 0x404040);
+ }
+ else
+ {
+ m_pFont->draw(m_pFurnace->getName(), 66, 6, 0x404040);
+ m_pFont->draw(m_pInventory->getName(), 8, m_imageHeight - 96 + 2, 0x404040);
+ }
+}
+
+void FurnaceScreen::_renderBg(float a)
+{
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ currentShaderColor = Color::WHITE;
+ blitNineSlice(*m_pMinecraft->m_pTextures, ScreenRenderer::PANEL_SLICES, m_leftPos, m_topPos, m_imageWidth, m_imageHeight, 32);
+ blitSprite(*m_pMinecraft->m_pTextures, "gui/console/Graphics/Arrow_Off.png", m_leftPos + 224, m_topPos + 100, 72, 48);
+
+ blitSprite(*m_pMinecraft->m_pTextures, "gui/console/Graphics/Flame_Off.png", m_leftPos + 147, m_topPos + 96, 48, 48);
+
+ int p;
+ if (m_pFurnace->isLit())
+ {
+ p = m_pFurnace->getLitProgress(12);
+ blitSprite(*m_pMinecraft->m_pTextures, "gui/console/Graphics/Flame_On.png", m_leftPos + 195, m_topPos + 141, -48, -(p + 2) * 3, nullptr, 0.0f, 3.0f, 48, (p + 2) * 3);
+ }
+
+ p = m_pFurnace->getBurnProgress(24);
+ blitSprite(*m_pMinecraft->m_pTextures, "gui/console/Graphics/Arrow_On.png", m_leftPos + 224, m_topPos + 100, (p + 1) * 3, 48, nullptr, 0.0f, 0.0f, (p + 1) * 3, 48);
+ //blit(m_leftPos + 79, m_topPos + 34, 176, 14, p + 1, 16, 0, 0);
+ }
+ else
+ {
+ currentShaderColor = Color::WHITE;
+
+ m_pMinecraft->m_pTextures->loadAndBindTexture("gui/furnace.png");
+
+ blit(m_leftPos, m_topPos, 0, 0, m_imageWidth, m_imageHeight, 0, 0);
+
+ int p;
+ if (m_pFurnace->isLit())
+ {
+ p = m_pFurnace->getLitProgress(12);
+ blit(m_leftPos + 56, m_topPos + 36 + 12 - p, 176, 12 - p, 14, p + 2, 0, 0);
+ }
+
+ p = m_pFurnace->getBurnProgress(24);
+ blit(m_leftPos + 79, m_topPos + 34, 176, 14, p + 1, 16, 0, 0);
+ }
+}
+
+SlotDisplay FurnaceScreen::_createSlotDisplay(const Slot& slot)
+{
+ if (m_uiTheme == UI_CONSOLE)
+ {
+ constexpr int slotSize = 42;
+ switch (slot.m_group)
+ {
+ case Slot::INPUT:
+ return SlotDisplay(154, 57 + (slot.m_stackId % 2) * ((slotSize + 5) * 2), slotSize, true);
+ case Slot::OUTPUT:
+ return SlotDisplay(312, 97, 64, true);
+ case Slot::INVENTORY:
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 230 + ((slot.m_stackId / 9) - 1) * slotSize, slotSize, true);
+ case Slot::HOTBAR:
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 369, slotSize, true);
+ default:
+ return SlotDisplay();
+ }
+ }
+ else
+ {
+ constexpr int slotSize = 18;
+ switch (slot.m_group)
+ {
+ case Slot::INPUT:
+ return SlotDisplay(56, 17 + (slot.m_stackId % 2) * (slotSize * 2), slotSize);
+ case Slot::OUTPUT:
+ return SlotDisplay(116, 35);
+ case Slot::INVENTORY:
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 84 + ((slot.m_stackId / 9) - 1) * slotSize, slotSize);
+ case Slot::HOTBAR:
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 142, slotSize);
+ default:
+ return SlotDisplay();
+ }
+ }
+}
+
+void FurnaceScreen::renderBackground()
+{
+ if (m_uiTheme == UI_CONSOLE)
+ return;
+
+ ContainerScreen::renderBackground();
+}
diff --git a/source/client/gui/screens/inventory/FurnaceScreen.hpp b/source/client/gui/screens/inventory/FurnaceScreen.hpp
new file mode 100644
index 000000000..337ea6a9c
--- /dev/null
+++ b/source/client/gui/screens/inventory/FurnaceScreen.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "ContainerScreen.hpp"
+#include "world/tile/entity/FurnaceTileEntity.hpp"
+
+class FurnaceScreen : public ContainerScreen
+{
+public:
+ FurnaceScreen(Inventory* inventory, FurnaceTileEntity* container);
+ void init() override;
+
+public:
+ void tick() override;
+
+protected:
+ void _renderLabels() override;
+ void _renderBg(float a) override;
+ SlotDisplay _createSlotDisplay(const Slot&) override;
+
+public:
+ void renderBackground() override;
+
+private:
+ Inventory* m_pInventory;
+ FurnaceTileEntity* m_pFurnace;
+};
diff --git a/source/client/gui/screens/inventory/InventoryScreen.cpp b/source/client/gui/screens/inventory/InventoryScreen.cpp
index 680aefcfc..12db8a335 100644
--- a/source/client/gui/screens/inventory/InventoryScreen.cpp
+++ b/source/client/gui/screens/inventory/InventoryScreen.cpp
@@ -25,8 +25,10 @@ void InventoryScreen::init()
void InventoryScreen::renderBackground()
{
- if (m_uiTheme != UI_CONSOLE)
- ContainerScreen::renderBackground();
+ if (m_uiTheme == UI_CONSOLE)
+ return;
+
+ ContainerScreen::renderBackground();
}
void InventoryScreen::_renderLabels()
@@ -135,16 +137,16 @@ SlotDisplay InventoryScreen::_createSlotDisplay(const Slot& slot)
case Slot::OUTPUT:
return m_pMinecraft->getOptions()->m_classicCrafting.get() ? SlotDisplay(352, 83, 54, true) : SlotDisplay();
case Slot::INPUT:
- return m_pMinecraft->getOptions()->m_classicCrafting.get() ? SlotDisplay(221 + (slot.m_slot % 2) * slotSize, 67 + (slot.m_slot / 2) * slotSize, slotSize, true) : SlotDisplay();
+ return m_pMinecraft->getOptions()->m_classicCrafting.get() ? SlotDisplay(221 + (slot.m_stackId % 2) * slotSize, 67 + (slot.m_stackId / 2) * slotSize, slotSize, true) : SlotDisplay();
case Slot::ARMOR:
{
const ArmorSlot& armorSlot = (const ArmorSlot&)slot;
return SlotDisplay(m_pMinecraft->getOptions()->m_classicCrafting.get() ? 27 : 127, 29 + (Item::SLOT_HEAD - armorSlot.m_equipmentSlot) * slotSize, slotSize, true, -1, CONSOLE_ARMOR_SLOTS[armorSlot.m_equipmentSlot]);
}
case Slot::INVENTORY:
- return SlotDisplay(28 + (slot.m_slot % 9) * slotSize, 233 + ((slot.m_slot / 9) - 1) * slotSize, slotSize, true);
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 233 + ((slot.m_stackId / 9) - 1) * slotSize, slotSize, true);
case Slot::HOTBAR:
- return SlotDisplay(28 + (slot.m_slot % 9) * slotSize, 372, slotSize, true);
+ return SlotDisplay(28 + (slot.m_stackId % 9) * slotSize, 372, slotSize, true);
default:
return SlotDisplay();
}
@@ -157,16 +159,16 @@ SlotDisplay InventoryScreen::_createSlotDisplay(const Slot& slot)
case Slot::OUTPUT:
return SlotDisplay(144, 36);
case Slot::INPUT:
- return SlotDisplay(88 + (slot.m_slot % 2) * slotSize, 26 + (slot.m_slot / 2) * slotSize);
+ return SlotDisplay(88 + (slot.m_stackId % 2) * slotSize, 26 + (slot.m_stackId / 2) * slotSize);
case Slot::ARMOR:
{
const ArmorSlot& armorSlot = (const ArmorSlot&)slot;
return SlotDisplay(8, 8 + (Item::SLOT_HEAD - armorSlot.m_equipmentSlot) * slotSize, slotSize, false, 16 * ((Item::SLOT_HEAD - armorSlot.m_equipmentSlot) + 1) - 1);
}
case Slot::INVENTORY:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 84 + ((slot.m_slot / 9) - 1) * slotSize, slotSize);
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 84 + ((slot.m_stackId / 9) - 1) * slotSize, slotSize);
case Slot::HOTBAR:
- return SlotDisplay(8 + (slot.m_slot % 9) * slotSize, 142, slotSize);
+ return SlotDisplay(8 + (slot.m_stackId % 9) * slotSize, 142, slotSize);
default:
return SlotDisplay();
}
diff --git a/source/client/model/models/SpiderModel.cpp b/source/client/model/models/SpiderModel.cpp
index a3293ecb4..677798049 100644
--- a/source/client/model/models/SpiderModel.cpp
+++ b/source/client/model/models/SpiderModel.cpp
@@ -57,7 +57,8 @@ SpiderModel::~SpiderModel()
{
}
-void SpiderModel::render(float time, float r, float bob, float yRot, float xRot, float scale) {
+void SpiderModel::render(float time, float r, float bob, float yRot, float xRot, float scale)
+{
setupAnim(time, r, bob, yRot, xRot, scale);
m_head.render(scale);
@@ -74,7 +75,8 @@ void SpiderModel::render(float time, float r, float bob, float yRot, float xRot,
m_leg7.render(scale);
}
-void SpiderModel::setupAnim(float time, float r, float bob, float yRot, float xRot, float scale) {
+void SpiderModel::setupAnim(float time, float r, float bob, float yRot, float xRot, float scale)
+{
m_head.m_rot.y = yRot / 57.295776f;
m_head.m_rot.x = xRot / 57.295776f;
diff --git a/source/client/multiplayer/MultiPlayerLevel.cpp b/source/client/multiplayer/MultiPlayerLevel.cpp
index 1890674d5..66c6bcfa4 100644
--- a/source/client/multiplayer/MultiPlayerLevel.cpp
+++ b/source/client/multiplayer/MultiPlayerLevel.cpp
@@ -13,7 +13,7 @@ void MultiPlayerLevel::tick()
for (size_t i = 0; i < 10 && i < m_reEntries.size(); i++)
{
Entity* pEntity = m_reEntries[i];
- if (std::find(m_entities.begin(), m_entities.end(), pEntity) != m_entities.end())
+ if (m_entitiesById.find(pEntity->hashCode()) == m_entitiesById.end())
{
addEntity(pEntity);
}
diff --git a/source/client/multiplayer/MultiplayerLocalPlayer.cpp b/source/client/multiplayer/MultiplayerLocalPlayer.cpp
index d4b004840..526fd0ee5 100644
--- a/source/client/multiplayer/MultiplayerLocalPlayer.cpp
+++ b/source/client/multiplayer/MultiplayerLocalPlayer.cpp
@@ -15,6 +15,14 @@ void MultiplayerLocalPlayer::reallyDrop(ItemEntity* itemEntity)
{
}
+void MultiplayerLocalPlayer::_handleOpenedContainerMenu()
+{
+ if (m_pContainerMenu)
+ m_pContainerMenu->addSlotListener(this);
+ else
+ LOG_W("Tried to add MultiplayerLocalPlayer as ContainerListener for NULL container!");
+}
+
bool MultiplayerLocalPlayer::hurt(Entity* pAttacker, int damage)
{
// Java returns false
@@ -70,10 +78,11 @@ void MultiplayerLocalPlayer::heal(int health)
{
}
+// @PARITY: From Java
+// Uncomment when we have fully server-authoritative inventories
/*void MultiplayerLocalPlayer::drop()
{
- // @PARITY: From Java
- m_pLevel->m_pRakNetInstance->send(new PlayerActionPacket(PlayerActionPacket::DROP_ITEM))
+ m_pLevel->m_pRakNetInstance->send(new PlayerActionPacket(m_EntityID, PlayerActionPacket::DROP_ITEM));
}*/
void MultiplayerLocalPlayer::hurtTo(int newHealth)
@@ -92,16 +101,14 @@ void MultiplayerLocalPlayer::hurtTo(int newHealth)
void MultiplayerLocalPlayer::die(Entity* pCulprit)
{
#if NETWORK_PROTOCOL_VERSION >= 4
- SendInventoryPacket* pPkt = new SendInventoryPacket();
- pPkt->m_entityId = m_EntityID;
- pPkt->m_bDropAll = true;
+ SendInventoryPacket* pPkt = new SendInventoryPacket(m_EntityID, true);
- uint16_t size = m_pInventory->getContainerSize();
+ Container::Size size = m_pInventory->getContainerSize();
// 0.3.0
if (size > 9)
{
- for (int i = 0; i < size; i++)
+ for (Container::StackID i = 0; i < size; i++)
{
pPkt->m_items.push_back(m_pInventory->getItem(i));
}
@@ -133,7 +140,9 @@ void MultiplayerLocalPlayer::refreshContainer(ContainerMenu* menu, const std::ve
{
}
-void MultiplayerLocalPlayer::slotChanged(ContainerMenu* menu, int index, ItemStack& item, bool isResultSlot)
+void MultiplayerLocalPlayer::slotChanged(ContainerMenu* menu, Container::SlotID slotId, Slot* slot, ItemStack& item, bool isResultSlot)
{
- // @TODO: Replicate ContainerSetSlotPacket
+#if NETWORK_PROTOCOL_VERSION >= 5
+ m_pMinecraft->m_pRakNetInstance->send(new ContainerSetSlotPacket(menu->m_containerId, slotId, item));
+#endif
}
diff --git a/source/client/multiplayer/MultiplayerLocalPlayer.hpp b/source/client/multiplayer/MultiplayerLocalPlayer.hpp
index d1a7e2bec..d635ff4a9 100644
--- a/source/client/multiplayer/MultiplayerLocalPlayer.hpp
+++ b/source/client/multiplayer/MultiplayerLocalPlayer.hpp
@@ -1,7 +1,7 @@
#pragma once
#include "client/player/LocalPlayer.hpp"
-#include "world/ContainerListener.hpp"
+#include "world/inventory/ContainerListener.hpp"
class MultiplayerLocalPlayer : public LocalPlayer, public ContainerListener
{
@@ -10,6 +10,7 @@ class MultiplayerLocalPlayer : public LocalPlayer, public ContainerListener
protected:
void reallyDrop(ItemEntity* itemEntity) override;
+ void _handleOpenedContainerMenu() override;
public:
bool hurt(Entity*, int) override;
@@ -21,7 +22,7 @@ class MultiplayerLocalPlayer : public LocalPlayer, public ContainerListener
void closeContainer() override;
void refreshContainer(ContainerMenu* menu, const std::vector& items) override;
- void slotChanged(ContainerMenu* menu, int index, ItemStack& item, bool isResultSlot) override;
+ void slotChanged(ContainerMenu* menu, Container::SlotID slotId, Slot* slot, ItemStack& item, bool isResultSlot) override;
private:
bool m_flashOnSetHealth;
diff --git a/source/client/network/ClientSideNetworkHandler.cpp b/source/client/network/ClientSideNetworkHandler.cpp
index 68f47668d..4e0b7f409 100644
--- a/source/client/network/ClientSideNetworkHandler.cpp
+++ b/source/client/network/ClientSideNetworkHandler.cpp
@@ -19,6 +19,7 @@
#include "world/entity/PrimedTnt.hpp"
#include "world/level/Explosion.hpp"
#include "world/inventory/SimpleContainer.hpp"
+#include "world/tile/entity/FurnaceTileEntity.hpp"
// This lets you make the client shut up and not log events in the debug console.
//#define VERBOSE_CLIENT
@@ -600,7 +601,12 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, PlayerE
return;
}
+#ifdef FEATURE_SERVER_INVENTORIES
+ // will need to be reworked for proper server-sided inventory support, pick the proper slot, not just any item
pPlayer->m_pInventory->pickItem(pPlayerEquipmentPkt->m_itemID, pPlayerEquipmentPkt->m_itemAuxValue, C_MAX_HOTBAR_ITEMS);
+#else
+ pPlayer->m_pInventory->setSelectedItem(ItemStack(pPlayerEquipmentPkt->m_itemID, 1, pPlayerEquipmentPkt->m_itemAuxValue));
+#endif
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& rakGuid, InteractPacket* pkt)
@@ -729,7 +735,7 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerO
pLocalPlayer->openContainer(new SimpleContainer(packet->m_size, packet->m_title.C_String()));
break;
case Container::FURNACE:
- //pLocalPlayer->openFurnace(new FurnaceTileEntity());
+ pLocalPlayer->openFurnace(new FurnaceTileEntity);
break;
case Container::DISPENSER:
//pLocalPlayer->openTrap(new DispenserTileEntity());
@@ -776,7 +782,9 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerS
if (pContainerMenu->m_containerId != packet->m_containerId)
return;
- pContainerMenu->setItem(packet->m_slot, packet->m_item);
+ pContainerMenu->m_bBroadcastChanges = false;
+ pContainerMenu->setItem(packet->m_slotId, packet->m_item);
+ pContainerMenu->m_bBroadcastChanges = true;
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerSetDataPacket* packet)
@@ -797,7 +805,9 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerS
if (pContainerMenu->m_containerId != packet->m_containerId)
return;
- pContainerMenu->setData(packet->m_slot, packet->m_value);
+ pContainerMenu->m_bBroadcastChanges = false;
+ pContainerMenu->setData(packet->m_id, packet->m_value);
+ pContainerMenu->m_bBroadcastChanges = true;
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerSetContentPacket* packet)
@@ -818,7 +828,9 @@ void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerS
if (pContainerMenu->m_containerId != packet->m_containerId)
return;
+ pContainerMenu->m_bBroadcastChanges = false;
pContainerMenu->setAll(packet->m_items);
+ pContainerMenu->m_bBroadcastChanges = true;
}
void ClientSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, LevelDataPacket* packet)
diff --git a/source/client/options/Options.cpp b/source/client/options/Options.cpp
index 726edd3e2..6c454aae0 100644
--- a/source/client/options/Options.cpp
+++ b/source/client/options/Options.cpp
@@ -45,7 +45,7 @@ void Options::_initDefaultValues()
#ifdef ORIGINAL_CODE
m_viewDistance.set(2);
m_thirdPerson.set(0);
- field_19 = 0;
+ m_bUseMouseToBreak = false;
#endif
// Force this on until we get a proper UI
@@ -99,7 +99,7 @@ Options::Options(Minecraft* mc, const std::string& folderPath) :
//, m_limitFramerate("gfx_fpslimit", "options.framerateLimit", 0, ValuesBuilder().add(performance.max").add("performance.balanced").add("performance.powersaver"))
//, m_bMipmaps("gfx_mipmaps", "options.mipmaps")
//, m_moreWorldOptions("misc_moreworldoptions", "options.moreWorldOptions", true)
- //, m_vSync("enableVsync", "options.enableVsync")
+ , m_vSync("enableVsync", "options.enableVsync", true)
{
add(m_musicVolume);
add(m_masterVolume);
@@ -128,10 +128,12 @@ Options::Options(Minecraft* mc, const std::string& folderPath) :
add(m_playerName);
add(m_debugText);
add(m_lang);
+ add(m_bUseController);
+ add(m_hudSize);
add(m_uiTheme);
add(m_logoType);
- add(m_hudSize);
add(m_classicCrafting);
+ add(m_vSync);
_initDefaultValues();
if (folderPath.empty()) return;
m_filePath = folderPath + "/options.txt";
@@ -672,6 +674,9 @@ void Options::initResourceDependentOptions()
if (!Screen::isMenuPanoramaAvailable())
m_menuPanorama.set(false);
+
+ if (!m_pMinecraft->platform()->isVSyncSwitchable())
+ m_vSync.set(true);
}
const std::string& OptionEntry::getDisplayName() const
@@ -757,6 +762,15 @@ std::string SensitivityOption::getDisplayValue() const
return get() == 0.0f ? Language::get("options.sensitivity.min") : get() == 1.0f ? Language::get("options.sensitivity.max") : Util::toString(int(get() * 200)) + "%";
}
+void ControllerOption::apply()
+{
+ // @TODO: This works but ultimately needs to be a multi-select (KBM, controller, touch) instead of a single option.
+ // Either that or figure out an automatic way to switch between them based on input like how Minecraft Bedrock does
+ // For now, I just wanted to be able to switch to controller input on mobile devices.
+ if (m_pMinecraft && m_pMinecraft->m_pInputHolder)
+ m_pMinecraft->reloadInput();
+}
+
void AOOption::apply()
{
Minecraft::useAmbientOcclusion = get();
@@ -795,6 +809,11 @@ std::string FancyGraphicsOption::getMessage() const
return Util::format(Language::get("options.value").c_str(), Language::get("options.graphics").c_str(), Language::get(get() ? "options.graphics.fancy" : "options.graphics.fast").c_str());
}
+void VsyncOption::apply()
+{
+ m_pMinecraft->platform()->setVSyncEnabled(get());
+}
+
void LogoTypeOption::apply()
{
if (m_pMinecraft->getOptions())
diff --git a/source/client/options/Options.hpp b/source/client/options/Options.hpp
index abeaa3590..9f99e457f 100644
--- a/source/client/options/Options.hpp
+++ b/source/client/options/Options.hpp
@@ -266,6 +266,14 @@ class SensitivityOption : public FloatOption
std::string getDisplayValue() const override;
};
+class ControllerOption : public BoolOption
+{
+public:
+ ControllerOption(const std::string& key, const std::string& name, bool initial = true) : BoolOption(key, name, initial) {}
+
+ void apply() override;
+};
+
class AOOption : public BoolOption
{
public:
@@ -290,6 +298,14 @@ class FancyGraphicsOption : public GraphicsOption
std::string getMessage() const override;
};
+class VsyncOption : public BoolOption
+{
+public:
+ VsyncOption(const std::string& key, const std::string& name, bool initial = true) : BoolOption(key, name, initial) {}
+
+ void apply() override;
+};
+
class GuiScaleOption : public ValuesOption
{
public:
@@ -335,6 +351,7 @@ class Options
{
public:
struct KeyBind;
+
private:
static bool _hasResourcePack(const ResourcePack& pack, ResourcePackStack& packs);
static void _tryAddResourcePack(const std::string& name, ResourcePackStack& packs);
@@ -364,6 +381,7 @@ class Options
void _initDefaultValues();
void _load();
AsyncTask _saveAsync();
+
public:
Options(Minecraft*, const std::string& folderPath = "");
@@ -425,7 +443,7 @@ class Options
GraphicsOption m_fancyGrass;
GraphicsOption m_biomeColors;
BoolOption m_splitControls;
- BoolOption m_bUseController;
+ ControllerOption m_bUseController;
BoolOption m_dynamicHand;
BoolOption m_menuPanorama;
StringOption m_lang;
@@ -433,6 +451,7 @@ class Options
LogoTypeOption m_logoType;
HUDSizeOption m_hudSize;
BoolOption m_classicCrafting;
+ VsyncOption m_vSync;
ResourcePackStack m_resourcePacks;
};
@@ -479,6 +498,7 @@ class Options
OPTION(m_viewBobbing); \
OPTION(m_anaglyphs); \
OPTION(m_blockOutlines); \
+ OPTION(m_vSync); idxVSync = currentIndex; \
OPTION(m_fancyGrass); \
OPTION(m_biomeColors); \
OPTION(m_dynamicHand); \
diff --git a/source/client/player/LocalPlayer.cpp b/source/client/player/LocalPlayer.cpp
index 9016b192c..2915304fb 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 "client/gui/screens/inventory/FurnaceScreen.hpp"
int dword_250ADC, dword_250AE0;
@@ -22,15 +23,17 @@ void LocalPlayer::_init()
// multiplayer related
m_lastSentPos = Vec3::ZERO;
m_lastSentRot = Vec2::ZERO;
+ m_lastSelectedStackId = m_pInventory->m_selectedStackId;
// multiplayer related -- end
m_renderArmRot = Vec2::ZERO;
m_lastRenderArmRot = Vec2::ZERO;
- m_lastSelectedSlot = m_pInventory->getSelectedItemId();
}
LocalPlayer::LocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, GameType playerGameType, int dimensionId) : Player(pLevel, playerGameType)
{
+ m_lastSelectedStackId = 0;
+
field_BEC = 0;
field_BF0 = Vec3::ZERO;
field_BFC = 0.0f;
@@ -42,7 +45,6 @@ LocalPlayer::LocalPlayer(Minecraft* pMinecraft, Level* pLevel, User* pUser, Game
field_C14 = 0.0f;
field_C18 = 0.0f;
field_C1C = 0.0f;
- m_lastSelectedSlot = 0;
m_pMoveInput = nullptr;
m_pMinecraft = pMinecraft;
@@ -59,7 +61,11 @@ LocalPlayer::~LocalPlayer()
void LocalPlayer::die(Entity* pCulprit)
{
#if NETWORK_PROTOCOL_VERSION >= 4
+#ifdef FEATURE_SERVER_INVENTORIES
m_pInventory->dropAll();
+#else
+ m_pInventory->dropAll(m_pLevel->m_bIsClientSide);
+#endif
#endif
Player::die(pCulprit);
@@ -132,18 +138,24 @@ void LocalPlayer::swing()
void LocalPlayer::startCrafting(const TilePos& pos)
{
m_pMinecraft->getScreenChooser()->pushCraftingScreen(this, pos);
+
+ Player::startCrafting(pos);
}
-/*void LocalPlayer::openFurnace(FurnaceTileEntity* furnace)
+void LocalPlayer::openFurnace(FurnaceTileEntity* furnace)
{
// PE 0.3.2 doesn't let you cook in creative mode
- m_pMinecraft->setScreen(new FurnaceScreen(m_pInventory, furnace));
-}*/
+ m_pMinecraft->getScreenChooser()->pushFurnaceScreen(this, furnace);
+
+ Player::openFurnace(furnace);
+}
void LocalPlayer::openContainer(Container* container)
{
// PE 0.3.2 doesn't let you open chests in creative mode
m_pMinecraft->getScreenChooser()->pushChestScreen(this, container);
+
+ Player::openContainer(container);
}
void LocalPlayer::closeContainer()
@@ -156,11 +168,15 @@ void LocalPlayer::closeContainer()
/*void LocalPlayer::openTrap(DispenserTileEntity* tileEntity)
{
m_pMinecraft->setScreen(new TrapScreen(m_pInventory, tileEntity));
+
+ Player::openTrap(tileEntity);
}*/
/*void LocalPlayer::openTextEdit(SignTileEntity* tileEntity)
{
m_pMinecraft->setScreen(new TextEditScreen(tileEntity));
+
+ Player::openTextEdit(tileEntity);
}*/
void LocalPlayer::reset()
@@ -247,6 +263,9 @@ bool LocalPlayer::isSneaking() const
void LocalPlayer::move(const Vec3& pos)
{
LocalPlayer* pLP = m_pMinecraft->m_pLocalPlayer;
+ if (!pLP)
+ return;
+
if (Minecraft::DEADMAU5_CAMERA_CHEATS && pLP == this && m_pMinecraft->getOptions()->m_flightHax.get())
{
//@HUH: Using m_pMinecraft->m_pLocalPlayer instead of this, even though they're the same
@@ -329,9 +348,9 @@ void LocalPlayer::tick()
{
sendPosition();
- if (m_lastSelectedSlot != m_pInventory->m_selectedSlot)
+ if (m_lastSelectedStackId != m_pInventory->m_selectedStackId)
{
- m_lastSelectedSlot = m_pInventory->m_selectedSlot;
+ m_lastSelectedStackId = m_pInventory->m_selectedStackId;
const ItemStack& item = m_pInventory->getSelectedItem();
m_pMinecraft->m_pRakNetInstance->send(new PlayerEquipmentPacket(m_EntityID, item.getId(), item.getAuxValue()));
}
diff --git a/source/client/player/LocalPlayer.hpp b/source/client/player/LocalPlayer.hpp
index 1eecb1288..c5dbdacff 100644
--- a/source/client/player/LocalPlayer.hpp
+++ b/source/client/player/LocalPlayer.hpp
@@ -39,7 +39,7 @@ class LocalPlayer : public Player
void setPlayerGameType(GameType gameType) override;
void swing() override;
void startCrafting(const TilePos&) override;
- //void openFurnace(FurnaceTileEntity* furnace) override;
+ void openFurnace(FurnaceTileEntity* furnace) override;
void openContainer(Container* container) override;
void closeContainer() override;
//void openTrap(DispenserTileEntity* tileEntity) override;
@@ -56,6 +56,7 @@ class LocalPlayer : public Player
// multiplayer related
Vec3 m_lastSentPos;
Vec2 m_lastSentRot;
+ Container::StackID m_lastSelectedStackId;
// multiplayer related -- end
public:
@@ -71,7 +72,6 @@ class LocalPlayer : public Player
float field_C18;
float field_C1C;
int m_nAutoJumpFrames;
- int m_lastSelectedSlot;
Minecraft* m_pMinecraft;
IMoveInput* m_pMoveInput;
Vec2 m_renderArmRot;
diff --git a/source/client/player/input/Keyboard.cpp b/source/client/player/input/Keyboard.cpp
index 562003650..0f82cc3e8 100644
--- a/source/client/player/input/Keyboard.cpp
+++ b/source/client/player/input/Keyboard.cpp
@@ -18,9 +18,8 @@ Keyboard::KeyState Keyboard::_states[KEYBOARD_STATES_SIZE];
void Keyboard::feed(KeyState state, int key)
{
// Prevent Crashes
- if (key >= KEYBOARD_STATES_SIZE || key < 0) {
+ if (key >= KEYBOARD_STATES_SIZE || key < 0)
return;
- }
_inputs.push_back(KeyboardAction(key, state));
diff --git a/source/client/renderer/Chunk.cpp b/source/client/renderer/Chunk.cpp
index 86ece3261..73d7dfaaa 100644
--- a/source/client/renderer/Chunk.cpp
+++ b/source/client/renderer/Chunk.cpp
@@ -133,6 +133,9 @@ void Chunk::rebuild()
LevelChunk::touchedSky = false;
+ std::set tmpSet(m_tileEntities.begin(), m_tileEntities.end());
+ m_tileEntities.clear();
+
for (int i = Tile::RENDER_LAYERS_MIN; i <= Tile::RENDER_LAYERS_MAX; i++)
{
m_empty[i] = true;
@@ -169,6 +172,16 @@ void Chunk::rebuild()
t.setOffset(-m_pos);
}
+ if (!layer && Tile::isEntityTile[tile])
+ {
+ /*
+ // @TODO: ADD TILE ENTITY RENDER DISPATCHER
+ TileEntity* et = region.getTileEntity(tp);
+ if (TileEntityRenderDispatcher::getInstance()->hasRenderer(et))
+ m_tileEntities.push_back(et);
+ */
+ }
+
Tile* pTile = Tile::tiles[tile];
if (layer == pTile->getRenderLayer())
@@ -201,11 +214,47 @@ void Chunk::rebuild()
break;
}
+ // get TileEntity diff and update m_globalTileEntities (renderable TileEntities) accordingly
+
+ std::set newSet(m_tileEntities.begin(), m_tileEntities.end());
+ TileEntityVector toAdd, toRemove;
+
+ std::set_difference(
+ newSet.begin(), newSet.end(),
+ tmpSet.begin(), tmpSet.end(),
+ std::back_inserter(toAdd)
+ );
+
+ std::set_difference(
+ tmpSet.begin(), tmpSet.end(),
+ newSet.begin(), newSet.end(),
+ std::back_inserter(toRemove)
+ );
+
+ // Add
+ for (TileEntityVector::iterator it = toAdd.begin(); it != toAdd.end(); ++it)
+ {
+ m_globalTileEntities.push_back(*it);
+ }
+
+ // Remove
+ for (TileEntityVector::iterator it = toRemove.begin(); it != toRemove.end(); ++it)
+ {
+ TileEntityVector::iterator f =
+ std::find(m_globalTileEntities.begin(),
+ m_globalTileEntities.end(),
+ *it);
+
+ if (f != m_globalTileEntities.end())
+ m_globalTileEntities.erase(f);
+ }
+
field_54 = LevelChunk::touchedSky;
m_bCompiled = true;
}
-Chunk::Chunk(Level* level, const TilePos& pos, int size, int lists)
+Chunk::Chunk(Level* level, TileEntityVector& tileEntities, const TilePos& pos, int size, int lists)
+ : m_globalTileEntities(tileEntities)
{
m_bOcclusionVisible = true;
m_bOcclusionQuerying = false;
diff --git a/source/client/renderer/Chunk.hpp b/source/client/renderer/Chunk.hpp
index 5f575c0d8..58d6d4793 100644
--- a/source/client/renderer/Chunk.hpp
+++ b/source/client/renderer/Chunk.hpp
@@ -15,11 +15,12 @@
class Level;
class Entity;
+class TileEntity;
class Chunk
{
public:
- Chunk(Level*, const TilePos& pos, int, int);
+ Chunk(Level*, std::vector& tileEntities, const TilePos& pos, int, int);
public:
float distanceToSqr(const Entity& entity) const;
@@ -42,6 +43,8 @@ class Chunk
public:
Level* m_pLevel;
+ std::vector& m_globalTileEntities;
+ std::vector m_tileEntities;
TilePos m_pos;
TilePos m_posS;
bool m_empty[Tile::RENDER_LAYERS_COUNT];
@@ -56,8 +59,10 @@ class Chunk
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/Font.cpp b/source/client/renderer/Font.cpp
index 6ec81196f..e66f98b6e 100644
--- a/source/client/renderer/Font.cpp
+++ b/source/client/renderer/Font.cpp
@@ -138,7 +138,8 @@ void Font::drawOutlinedString(const std::string& str, int x, int y, const Color&
for (int yi = 0; yi < 3; ++yi)
{
int t1 = translations[yi];
- if (t != 0 || t1 != 0) {
+ if (t != 0 || t1 != 0)
+ {
MatrixStack::Ref matrix = MatrixStack::World.push();
matrix->translate(Vec3(t, t1, 0));
drawScalable(str, x, y, outlineColor, scale, false);
@@ -290,7 +291,8 @@ std::vector Font::split(const std::string& text, int maxWidth)
std::istringstream iss(paragraph);
std::string word;
- while (iss >> word) {
+ while (iss >> word)
+ {
std::string testLine = currentLine.empty() ? word : currentLine + " " + word;
if (width(testLine) <= maxWidth)
diff --git a/source/client/renderer/GameRenderer.cpp b/source/client/renderer/GameRenderer.cpp
index 14450fe84..e6f3634a6 100644
--- a/source/client/renderer/GameRenderer.cpp
+++ b/source/client/renderer/GameRenderer.cpp
@@ -647,7 +647,7 @@ void GameRenderer::render(const Timer& timer)
int mouseY = -9999;
bool bMouseData = false;
- if (m_pMinecraft->isTouchscreen())
+ if (m_pMinecraft->useTouchscreen())
{
int pointerId = Multitouch::getFirstActivePointerIdExThisUpdate();
if (pointerId >= 0)
diff --git a/source/client/renderer/ItemInHandRenderer.cpp b/source/client/renderer/ItemInHandRenderer.cpp
index 0501474af..8d6b73b11 100644
--- a/source/client/renderer/ItemInHandRenderer.cpp
+++ b/source/client/renderer/ItemInHandRenderer.cpp
@@ -396,7 +396,7 @@ void ItemInHandRenderer::tick()
ItemStack& item = m_pMinecraft->m_pLocalPlayer->m_pInventory->getSelectedItem();
- bool bSameItem = m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedSlot == m_lastSlot && m_selectedItem == item;
+ bool bSameItem = m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedStackId == m_lastSlot && m_selectedItem == item;
if (item.isEmpty() && m_selectedItem.isEmpty())
bSameItem = true;
@@ -424,7 +424,7 @@ void ItemInHandRenderer::tick()
if (m_height < 0.1f)
{
m_selectedItem = ItemStack(item);
- m_lastSlot = m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedSlot;
+ m_lastSlot = m_pMinecraft->m_pLocalPlayer->m_pInventory->m_selectedStackId;
}
}
diff --git a/source/client/renderer/LevelRenderer.cpp b/source/client/renderer/LevelRenderer.cpp
index d85278176..047c061a9 100644
--- a/source/client/renderer/LevelRenderer.cpp
+++ b/source/client/renderer/LevelRenderer.cpp
@@ -617,7 +617,7 @@ void LevelRenderer::allChanged()
m_zMinChunk = 0;
m_dirtyChunks.clear();
- //m_renderableTileEntities.clear();
+ m_renderableTileEntities.clear();
m_xMaxChunk = m_xChunks;
m_yMaxChunk = m_yChunks;
@@ -638,7 +638,7 @@ void LevelRenderer::allChanged()
{
int index = (cp.z * m_yChunks + cp.y) * m_xChunks + cp.x;
- Chunk* pChunk = new Chunk(m_pLevel, cp * 16, 16, id + m_chunkLists);
+ Chunk* pChunk = new Chunk(m_pLevel, m_renderableTileEntities, cp * 16, 16, id + m_chunkLists);
if (m_bOcclusionCheck)
pChunk->m_occlusionId = 0; // m_occlusionCheckIds.get(count)
@@ -1118,7 +1118,11 @@ void LevelRenderer::setTilesDirty(const TilePos& min, const TilePos& max)
void LevelRenderer::tick()
{
- const Entity& camera = *m_pMinecraft->m_pCameraEntity;
+ const Entity* pCamera = m_pMinecraft->m_pCameraEntity;
+ if (!pCamera)
+ return;
+
+ const Entity& camera = *pCamera;
const Level& level = *m_pMinecraft->m_pLevel;
const Options& options = *m_pMinecraft->getOptions();
@@ -1137,7 +1141,7 @@ void LevelRenderer::tick()
typedef std::vector ChunkVector;
typedef ChunkVector::iterator ChunkVectorIterator;
-bool LevelRenderer::updateDirtyChunks(const Entity& camera, bool b)
+bool LevelRenderer::updateDirtyChunks(const Entity& camera, bool force)
{
constexpr int C_MAX = 3;
DirtyChunkSorter dcs(camera);
@@ -1148,7 +1152,7 @@ bool LevelRenderer::updateDirtyChunks(const Entity& camera, bool b)
for (size_t i = 0; i < pendingChunkSize; i++)
{
Chunk* pChunk = m_dirtyChunks[i];
- if (!b)
+ if (!force)
{
if (pChunk->distanceToSqr(camera) > 1024.0f)
{
@@ -1163,7 +1167,8 @@ bool LevelRenderer::updateDirtyChunks(const Entity& camera, bool b)
if (--j <= 0)
continue;
- for (int k = j; --k != 0;) {
+ for (int k = j; --k != 0;)
+ {
pChunks[k - 1] = pChunks[k];
}
@@ -1421,6 +1426,11 @@ void LevelRenderer::addParticle(const std::string& name, const Vec3& pos, const
pe->add(new SmokeParticle(m_pLevel, pos, dir, 1.0f));
return;
}
+ if (name == "note")
+ {
+ pe->add(new NoteParticle(m_pLevel, pos, dir));
+ return;
+ }
if (name == "explode")
{
pe->add(new ExplodeParticle(m_pLevel, pos, dir));
@@ -1578,12 +1588,12 @@ void LevelRenderer::renderEntities(Vec3 pos, Culler* culler, float f)
EntityRenderDispatcher::off = camera->m_posPrev + (camera->m_pos - camera->m_posPrev) * f;
- const EntityVector* pVec = m_pLevel->getAllEntities();
+ const EntityMap* pVec = m_pLevel->getAllEntities();
m_totalEntities = int(pVec->size());
- for (int i = 0; i < m_totalEntities; i++)
- {
- const Entity* entity = (*pVec)[i];
+ for (EntityMap::const_iterator it = pVec->begin(); it != pVec->end(); ++it)
+ {
+ const Entity* entity = it->second;
if (!entity->shouldRender(pos))
continue;
@@ -1599,6 +1609,16 @@ void LevelRenderer::renderEntities(Vec3 pos, Culler* culler, float f)
EntityRenderDispatcher::getInstance()->render(*entity, f);
}
}
+
+ /*
+ // @TODO: TileEntityRenderDispatcher
+ for (TileEntityVector::const_iterator it = m_renderableTileEntities.begin();
+ it != m_renderableTileEntities.end(); ++it)
+ {
+ TileEntity* tileEntity = *it;
+ TileEntityRenderDispatcher::getInstance()->render(tileEntity, f);
+ }
+ */
}
void LevelRenderer::renderShadow(const Entity& entity, const Vec3& pos, float r, float pow, float a)
diff --git a/source/client/renderer/LevelRenderer.hpp b/source/client/renderer/LevelRenderer.hpp
index 1e2fbbc60..63520dc24 100644
--- a/source/client/renderer/LevelRenderer.hpp
+++ b/source/client/renderer/LevelRenderer.hpp
@@ -223,4 +223,5 @@ class LevelRenderer : public LevelListener, public AppPlatformListener
mce::Mesh m_darkMesh;
//...
Textures* m_pTextures;
+ TileEntityVector m_renderableTileEntities;
};
diff --git a/source/client/renderer/LogoRenderer.cpp b/source/client/renderer/LogoRenderer.cpp
index 9a45e8a66..f6124f1fe 100644
--- a/source/client/renderer/LogoRenderer.cpp
+++ b/source/client/renderer/LogoRenderer.cpp
@@ -414,8 +414,10 @@ Tile* TitleTile::getRandomTile(Tile* except1, Tile* except2)
for (;;)
{
id = _random.nextInt(256);
- for (int i = 0; i < _tileBlockListSize; i++) {
- if (_tileBlockList[i] == id) {
+ for (int i = 0; i < _tileBlockListSize; i++)
+ {
+ if (_tileBlockList[i] == id)
+ {
// N.B. Air does not have a tile
id = TILE_AIR;
break;
diff --git a/source/client/renderer/ScreenRenderer.cpp b/source/client/renderer/ScreenRenderer.cpp
index d6e406953..f71b40e6a 100644
--- a/source/client/renderer/ScreenRenderer.cpp
+++ b/source/client/renderer/ScreenRenderer.cpp
@@ -121,7 +121,11 @@ void ScreenRenderer::blitSprite(Textures& textures, const std::string& texture,
void ScreenRenderer::blitSprite(Textures& textures, const TextureAtlasSprite* sprite, int x, int y, int width, int height, mce::MaterialPtr* materialPtr, float u, float v, int uvWidth, int uvHeight)
{
- if (!sprite || !sprite->m_pAtlas) return;
+ if (!sprite || !sprite->m_pAtlas)
+ {
+ assert(!"Invalid spite ptr provided to blitSprite!");
+ return;
+ }
TextureAtlas& atlas = *sprite->m_pAtlas;
diff --git a/source/client/renderer/Textures.cpp b/source/client/renderer/Textures.cpp
index 98fb53535..7d9446f7b 100644
--- a/source/client/renderer/Textures.cpp
+++ b/source/client/renderer/Textures.cpp
@@ -165,7 +165,10 @@ Textures::Textures() :
addSprite("gui/console/Graphics/Armour_Slot_Legs.png", m_guiAtlas);
addSprite("gui/console/Graphics/Armour_Slot_Feet.png", m_guiAtlas);
addSprite("gui/console/Graphics/Arrow_Off.png", m_guiAtlas);
+ addSprite("gui/console/Graphics/Arrow_On.png", m_guiAtlas);
addSprite("gui/console/Graphics/Arrow_Small_Off.png", m_guiAtlas);
+ addSprite("gui/console/Graphics/Flame_Off.png", m_guiAtlas);
+ addSprite("gui/console/Graphics/Flame_On.png", m_guiAtlas);
addSprite("gui/console/Graphics/MainMenuButton_Norm.png", m_filteredGuiAtlas);
addSprite("gui/console/Graphics/MainMenuButton_Over.png", m_filteredGuiAtlas);
addSprite("gui/console/Graphics/ListButton_Norm.png", m_filteredGuiAtlas);
diff --git a/source/client/renderer/TileRenderer.cpp b/source/client/renderer/TileRenderer.cpp
index 309961f04..77fe6d352 100644
--- a/source/client/renderer/TileRenderer.cpp
+++ b/source/client/renderer/TileRenderer.cpp
@@ -204,7 +204,7 @@ void TileRenderer::renderEast(Tile* tile, const Vec3& pos, int texture)
texV_d = C_RATIO * (texY + aabb.max.y * 16.0f - 0.01f);
}
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
if (m_ambientOcclusion)
{
@@ -281,7 +281,7 @@ void TileRenderer::renderWest(Tile* tile, const Vec3& pos, int texture)
texV_d = C_RATIO * (texY + aabb.max.y * 16.0f - 0.01f);
}
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
if (m_ambientOcclusion)
{
@@ -358,7 +358,7 @@ void TileRenderer::renderSouth(Tile* tile, const Vec3& pos, int texture)
texV_d = C_RATIO * (texY + aabb.max.y * 16.0f - 0.01f);
}
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
if (m_ambientOcclusion)
{
@@ -435,7 +435,7 @@ void TileRenderer::renderNorth(Tile* tile, const Vec3& pos, int texture)
texV_d = C_RATIO * (texY + aabb.max.y * 16.0f - 0.01f);
}
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
if (m_ambientOcclusion)
{
@@ -506,7 +506,7 @@ void TileRenderer::renderFaceDown(Tile* tile, const Vec3& pos, int texture)
texV_2 = C_RATIO * (texY + 15.99f);
}
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
if (m_ambientOcclusion)
{
@@ -577,7 +577,7 @@ void TileRenderer::renderFaceUp(Tile* tile, const Vec3& pos, int texture)
texV_2 = C_RATIO * (texY + 15.99f);
}
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
if (m_ambientOcclusion)
{
@@ -641,7 +641,7 @@ void TileRenderer::tesselateCrossTexture(const FullTile& tile, const Vec3& pos,
float x1 = cenX - 0.45f, x2 = cenX + 0.45f;
float z1 = cenZ - 0.45f, z2 = cenZ + 0.45f;
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
// face 1
t.vertexUV(x1, newY + 1, z1, texU_l, texV_u);
t.vertexUV(x1, newY + 0, z1, texU_l, texV_d);
@@ -693,7 +693,7 @@ void TileRenderer::tesselateRowTexture(Tile* tile, int data, const Vec3& pos)
float x0 = pos.x + 0.25f, x1 = pos.x + 0.75f;
float z0 = pos.z, z1 = pos.z + 1.0f;
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
t.vertexUV(x0, pos.y + 1.0, z0, u0, v0);
t.vertexUV(x0, pos.y + 0.0, z0, u0, v1);
t.vertexUV(x0, pos.y + 0.0, z1, u1, v1);
@@ -739,7 +739,7 @@ bool TileRenderer::tesselateBlockInWorld(Tile* tile, const TilePos& pos, float r
if (tile == Tile::grass)
r = g = b = 1.0f;
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
float fLightHere = tile->getBrightness(m_pTileSource, pos);
bool bDrewAnything = false;
@@ -871,7 +871,7 @@ bool TileRenderer::tesselateBlockInWorld(Tile* tile, const TilePos& pos)
bool TileRenderer::tesselateCrossInWorld(Tile* tile, const TilePos& pos)
{
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
float bright = tile->getBrightness(m_pTileSource, pos);
int color = getTileColor(tile, pos);
@@ -888,7 +888,7 @@ bool TileRenderer::tesselateCrossInWorld(Tile* tile, const TilePos& pos)
bool TileRenderer::tesselateRowInWorld(Tile* tile, const TilePos& pos)
{
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
Color color = getTileColor(tile, pos);
color.a = 1.0f;
@@ -906,7 +906,7 @@ bool TileRenderer::tesselateWaterInWorld(Tile* tile1, const TilePos& pos)
LiquidTile* tile = (LiquidTile*)tile1;
bool bRenderFaceDown, bRenderFaceUp, bRenderSides[4];
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
bRenderFaceDown = tile->shouldRenderFace(m_pTileSource, pos.above(), Facing::UP);
bRenderFaceUp = tile->shouldRenderFace(m_pTileSource, pos.below(), Facing::DOWN);
@@ -1168,7 +1168,8 @@ bool TileRenderer::tesselateFenceInWorld(Tile* tile, const TilePos& pos)
bool connectsHorizontally = tileWest || tileEast;
bool connectsVertically = tileNorth || tileSouth;
- if (!connectsHorizontally && !connectsVertically) {
+ if (!connectsHorizontally && !connectsVertically)
+ {
connectsHorizontally = true;
}
@@ -1216,7 +1217,7 @@ bool TileRenderer::tesselateFenceInWorld(Tile* tile, const TilePos& pos)
bool TileRenderer::tesselateDoorInWorld(Tile* tile, const TilePos& pos)
{
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
float fBrightHere = tile->getBrightness(m_pTileSource, pos), fBright;
int texture;
@@ -1297,7 +1298,7 @@ void TileRenderer::tesselateTorch(Tile* tile, const Vec3& pos, float a, float b)
float x2 = x1 + (float)(a * C_TOP_SKEW_RATIO);
float z2 = z1 + (float)(b * C_TOP_SKEW_RATIO);
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
// Top side (flame)
float x_1 = x2 - C_ONE_PIXEL;
@@ -1370,7 +1371,7 @@ bool TileRenderer::tesselateTorchInWorld(Tile* tile, const TilePos& pos)
if (Tile::lightEmission[tile->m_ID] > 0)
bright = 1.0f;
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
t.color(bright, bright, bright);
switch (data)
@@ -1399,7 +1400,7 @@ bool TileRenderer::tesselateLadderInWorld(Tile* tile, const TilePos& pos)
{
constexpr float C_RATIO = 1.0f / 256.0f;
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
int texture = tile->getTexture(Facing::DOWN);
@@ -1452,7 +1453,7 @@ bool TileRenderer::tesselateFireInWorld(Tile* tile, const TilePos& pos)
{
constexpr float C_RATIO = 1.0f / 256.0f;
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
int texture = tile->getTexture(Facing::DOWN);
float bright = tile->getBrightness(m_pTileSource, pos);
@@ -2690,7 +2691,7 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusion(Tile* a2, const Ti
void TileRenderer::renderTile(const FullTile& tile, const mce::MaterialPtr& material, float bright, bool preshade)
{
- Tesselator& t = Tesselator::instance;
+ Tesselator& t = m_tessellator;
Tile* tileType = tile.getType();
#ifndef ENH_SHADE_HELD_TILES
@@ -2793,7 +2794,8 @@ void TileRenderer::renderTile(const FullTile& tile, const mce::MaterialPtr& mate
float v6 = v5 * 2.0f;
for (int i = 0; i < 4; i++)
{
- switch (i) {
+ switch (i)
+ {
case 0: tileType->setShape(0.5f - v6, 0.0f, 0.0f, 0.5f + v6, 1.0f, v6 * 2.0f); break;
case 1: tileType->setShape(0.5f - v6, 0.0f, 1.0f - (v6 * 2.0f), 0.5f + v6, 1.0f, 1.0f); break;
case 2: tileType->setShape(0.5f - v5, 1.0f - v5 * 3.0f, -v5 * 2.0f, 0.5f + v5, 1.0f - v5, 1.0f + v5 * 2.0f); break;
@@ -2924,7 +2926,7 @@ bool TileRenderer::tesselateBlockInWorldWithAmbienceOcclusionV2(Tile* tile, cons
if (tile == Tile::grass)
r = g = b = 1.0f;
- //Tesselator& t = Tesselator::instance;
+ //Tesselator& t = m_tessellator;
//float fLightHere = tile->getBrightness(m_pTileSource, pos);
diff --git a/source/client/renderer/entity/ItemRenderer.cpp b/source/client/renderer/entity/ItemRenderer.cpp
index aa3d9973f..e55794ba5 100644
--- a/source/client/renderer/entity/ItemRenderer.cpp
+++ b/source/client/renderer/entity/ItemRenderer.cpp
@@ -192,7 +192,8 @@ void ItemRenderer::renderGuiItemOverlay(Font* font, Textures* textures, ItemStac
return;
// Draw damage amount
- if (item.isDamaged()) {
+ if (item.isDamaged())
+ {
int duraWidth = ceilf(13.0f - static_cast(item.getDamageValue()) * 13.0f / static_cast(item.getMaxDamage()));
int duraPercent = ceilf(255.0f - static_cast(item.getDamageValue()) * 255.0f / static_cast(item.getMaxDamage()));
@@ -207,7 +208,8 @@ void ItemRenderer::renderGuiItemOverlay(Font* font, Textures* textures, ItemStac
blitRect(t, x + 2, y + 13, duraWidth, 1, duraColor);
}
- if (item.m_count <= 1) {
+ if (item.m_count <= 1)
+ {
return;
}
diff --git a/source/client/renderer/entity/MobRenderer.cpp b/source/client/renderer/entity/MobRenderer.cpp
index 8e589c112..5039db894 100644
--- a/source/client/renderer/entity/MobRenderer.cpp
+++ b/source/client/renderer/entity/MobRenderer.cpp
@@ -90,7 +90,7 @@ void MobRenderer::render(const Entity& entity, const Vec3& pos, float rot, float
MatrixStack::Ref matrix = MatrixStack::World.push();
m_pModel->m_attackTime = getAttackAnim(mob, a);
- m_pModel->m_bRiding = false;
+ m_pModel->m_bRiding = mob.isRiding();
m_pModel->m_bIsBaby = mob.isBaby();
if (m_pArmorModel != nullptr)
diff --git a/source/client/sound/SoundData.cpp b/source/client/sound/SoundData.cpp
index e3351f418..9b325c3a9 100644
--- a/source/client/sound/SoundData.cpp
+++ b/source/client/sound/SoundData.cpp
@@ -83,11 +83,13 @@ bool SoundDesc::_load(const char* category, const char *name)
}
location.path = "sound/" + std::string(name) + ".pcm";
ret = _loadPcm(location);
- if (!ret) {
+ if (!ret)
+ {
m_codecType = AudioCodec::NONE;
LOG_W("Failed to load sound \"%s\"!", name);
return false;
- } else
+ }
+ else
return true;
}
diff --git a/source/client/sound/SoundEngine.hpp b/source/client/sound/SoundEngine.hpp
index 86fa1d0e4..7f068035e 100644
--- a/source/client/sound/SoundEngine.hpp
+++ b/source/client/sound/SoundEngine.hpp
@@ -43,6 +43,7 @@ class SoundEngine
public:
SoundSystem* m_pSoundSystem;
+
private:
SoundRepository m_sounds;
SoundPathRepository m_songs;
diff --git a/source/client/sound/SoundRepository.cpp b/source/client/sound/SoundRepository.cpp
index 32a24a2dd..17342dc52 100644
--- a/source/client/sound/SoundRepository.cpp
+++ b/source/client/sound/SoundRepository.cpp
@@ -33,7 +33,7 @@ bool SoundRepository::get(const std::string& name, SoundDesc& sd)
std::map >::iterator iter = m_repo.find(name);
if (iter == m_repo.end())
{
- LOG_E("Couldn't find a sound with id: %s", name.c_str());
+ LOG_W("Couldn't find a sound with id: %s", name.c_str());
return false;
}
diff --git a/source/client/sound/sound_list.h b/source/client/sound/sound_list.h
index e20026c34..ee6906caf 100644
--- a/source/client/sound/sound_list.h
+++ b/source/client/sound/sound_list.h
@@ -48,6 +48,12 @@ SOUND(ui, press)
SOUND(ui, scroll)
SOUND(fire, fire)
+SOUND(fire, ignite)
+SOUND_NUM(fire, fire_crackle, 1)
+SOUND_NUM(fire, fire_crackle, 2)
+SOUND_NUM(fire, fire_crackle, 3)
+SOUND_NUM(fire, fire_crackle, 4)
+SOUND_NUM(fire, fire_crackle, 5)
SOUND_NUM(damage, fallbig, 1)
SOUND_NUM(damage, fallbig, 2)
@@ -103,3 +109,9 @@ SOUND_NUM(mob, zombie, 3)
SOUND_NUM(mob, zombiehurt, 1)
SOUND_NUM(mob, zombiehurt, 2)
SOUND(mob, zombiedeath)
+
+SOUND(note, harp)
+SOUND(note, bd)
+SOUND(note, hat)
+SOUND(note, snare)
+SOUND(note, bassattack)
\ No newline at end of file
diff --git a/source/common/Logger.cpp b/source/common/Logger.cpp
index a98c4559f..d0115bc6e 100644
--- a/source/common/Logger.cpp
+++ b/source/common/Logger.cpp
@@ -15,11 +15,10 @@ Logger* Logger::singleton()
void Logger::setSingleton(Logger* logger)
{
// Stick with the first output handle we get
- if (!m_singleton) {
+ if (!m_singleton)
m_singleton = logger;
- } else {
+ else
m_singleton->print(LOG_ERR, "Logging already setup!");
- }
}
Logger::~Logger()
diff --git a/source/common/Mth.cpp b/source/common/Mth.cpp
index d3a20ddb0..5126313ab 100644
--- a/source/common/Mth.cpp
+++ b/source/common/Mth.cpp
@@ -48,13 +48,13 @@ float Mth::invSqrt(float number)
// they just stole it from Quake.
float x2, y;
- const float threehalfs = 1.5F;
+ const float threehalfs = 1.5f;
union {
float f;
int32_t i;
} un;
- x2 = number * 0.5F;
+ x2 = number * 0.5f;
un.f = number; // evil floating point bit level hacking
un.i = 0x5f3759df - ( un.i >> 1 ); // what the fuck?
y = un.f;
diff --git a/source/common/Random.cpp b/source/common/Random.cpp
index 78f7ffe04..342dc6d7b 100644
--- a/source/common/Random.cpp
+++ b/source/common/Random.cpp
@@ -35,7 +35,8 @@ void Random::setSeed(int32_t seed)
void Random::init_genrand(uint32_t s)
{
mt[0] = s & 0xffffffffUL;
- for (mti = 1; mti < N; mti++) {
+ for (mti = 1; mti < N; mti++)
+ {
mt[mti] =
(1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
@@ -65,11 +66,13 @@ uint32_t Random::genrand_int32()
if (mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
- for (kk=0;kk> 1) ^ mag01[y & 0x1UL];
}
- for (;kk> 1) ^ mag01[y & 0x1UL];
}
diff --git a/source/common/Utils.hpp b/source/common/Utils.hpp
index d5e5b397a..b955c140f 100644
--- a/source/common/Utils.hpp
+++ b/source/common/Utils.hpp
@@ -546,8 +546,6 @@ typedef uint8_t TileID;
// Rename "FullTile" to "Tile"
typedef uint8_t TileData;
-typedef uint16_t SlotID;
-
#define SAFE_DELETE(ptr) do { if (ptr) delete ptr; } while (0)
#define SAFE_DELETE_ARRAY(ptr) do { if (ptr) delete[] ptr; } while (0)
diff --git a/source/network/Packet.hpp b/source/network/Packet.hpp
index bf95f6d98..5d7a295d9 100644
--- a/source/network/Packet.hpp
+++ b/source/network/Packet.hpp
@@ -20,6 +20,7 @@
//#define NETWORK_PROTOCOL_VERSION 5 // 0.3.2
#define NETWORK_PROTOCOL_VERSION 6 // 0.3.3
//#define NETWORK_PROTOCOL_VERSION 7 // 0.4.0
+//#define NETWORK_PROTOCOL_VERSION 29 // 0.12.1
class NetEventCallback;
class Level;
diff --git a/source/network/PacketUtil.cpp b/source/network/PacketUtil.cpp
index f6000cb85..8be6f9bbe 100644
--- a/source/network/PacketUtil.cpp
+++ b/source/network/PacketUtil.cpp
@@ -1,4 +1,5 @@
#include "PacketUtil.hpp"
+#include "Packet.hpp"
#include "nbt/NbtIo.hpp"
char PacketUtil::Rot_degreesToChar(float degrees)
@@ -146,12 +147,14 @@ void PacketUtil::WriteItemStack(const ItemStack& item, RakNet::BitStream& bs, bo
int16_t itemId = item.getId();
int8_t count = item.m_count;
int16_t auxValue = item.getAuxValue();
+#if NETWORK_PROTOCOL_VERSION >= 29
if (itemId <= 0)
{
itemId = -1;
bs.Write(itemId);
return;
}
+#endif
bs.Write(itemId);
bs.Write(count);
@@ -166,8 +169,10 @@ ItemStack PacketUtil::ReadItemStack(RakNet::BitStream& bs, bool doUserData)
if (!bs.Read(itemId))
return ItemStack();
+#if NETWORK_PROTOCOL_VERSION >= 29
if (itemId == ItemStack::EMPTY.getId())
return ItemStack();
+#endif
uint8_t count;
int16_t auxValue;
diff --git a/source/network/packets/AddMobPacket.hpp b/source/network/packets/AddMobPacket.hpp
index 85c2a7dc4..391ebdd41 100644
--- a/source/network/packets/AddMobPacket.hpp
+++ b/source/network/packets/AddMobPacket.hpp
@@ -25,6 +25,7 @@ class AddMobPacket : public Packet
int32_t m_entityTypeId;
Vec3 m_pos;
Vec2 m_rot;
+
private:
SynchedEntityData m_entityData;
SynchedEntityData::ItemsArray m_unpack;
diff --git a/source/network/packets/ContainerOpenPacket.hpp b/source/network/packets/ContainerOpenPacket.hpp
index 11fc81f6c..648d6569b 100644
--- a/source/network/packets/ContainerOpenPacket.hpp
+++ b/source/network/packets/ContainerOpenPacket.hpp
@@ -2,7 +2,7 @@
#include
#include "../Packet.hpp"
-#include "world/Container.hpp"
+#include "world/inventory/Container.hpp"
class ContainerOpenPacket : public Packet
{
diff --git a/source/network/packets/ContainerSetContentPacket.cpp b/source/network/packets/ContainerSetContentPacket.cpp
index 02b5b07b5..cc1552065 100644
--- a/source/network/packets/ContainerSetContentPacket.cpp
+++ b/source/network/packets/ContainerSetContentPacket.cpp
@@ -30,7 +30,7 @@ void ContainerSetContentPacket::read(RakNet::BitStream& bs)
bs.Read(m_containerId);
int16_t size = 0;
bs.Read(size);
- m_items.resize(size);
+ m_items.reserve(size);
for (uint16_t i = 0; i < size; i++)
{
diff --git a/source/network/packets/ContainerSetDataPacket.cpp b/source/network/packets/ContainerSetDataPacket.cpp
index 976a413c3..0e2731fa9 100644
--- a/source/network/packets/ContainerSetDataPacket.cpp
+++ b/source/network/packets/ContainerSetDataPacket.cpp
@@ -1,9 +1,9 @@
#include "ContainerSetDataPacket.hpp"
#include "network/NetEventCallback.hpp"
-ContainerSetDataPacket::ContainerSetDataPacket(int8_t containerId, int16_t slot, int16_t value)
+ContainerSetDataPacket::ContainerSetDataPacket(int8_t containerId, int16_t id, int16_t value)
: m_containerId(containerId)
- , m_slot(slot)
+ , m_id(id)
, m_value(value)
{
}
@@ -17,13 +17,13 @@ void ContainerSetDataPacket::write(RakNet::BitStream& bs)
{
bs.Write((unsigned char)PACKET_CONTAINER_SET_DATA);
bs.Write(m_containerId);
- bs.Write(m_slot);
+ bs.Write(m_id);
bs.Write(m_value);
}
void ContainerSetDataPacket::read(RakNet::BitStream& bs)
{
bs.Read(m_containerId);
- bs.Read(m_slot);
+ bs.Read(m_id);
bs.Read(m_value);
}
diff --git a/source/network/packets/ContainerSetDataPacket.hpp b/source/network/packets/ContainerSetDataPacket.hpp
index e504c7cdd..629e81c4c 100644
--- a/source/network/packets/ContainerSetDataPacket.hpp
+++ b/source/network/packets/ContainerSetDataPacket.hpp
@@ -8,16 +8,16 @@ class ContainerSetDataPacket : public Packet
ContainerSetDataPacket()
{
m_containerId = 0;
- m_slot = 0;
+ m_id = 0;
m_value = 0;
}
- ContainerSetDataPacket(int8_t containerId, int16_t slot, int16_t value);
+ ContainerSetDataPacket(int8_t containerId, int16_t id, int16_t value);
void handle(const RakNet::RakNetGUID&, NetEventCallback& callback) override;
void write(RakNet::BitStream&) override;
void read(RakNet::BitStream&) override;
public:
int8_t m_containerId;
- int16_t m_slot;
+ int16_t m_id;
int16_t m_value;
};
\ No newline at end of file
diff --git a/source/network/packets/ContainerSetSlotPacket.cpp b/source/network/packets/ContainerSetSlotPacket.cpp
index b4bcf9049..bafe0f32a 100644
--- a/source/network/packets/ContainerSetSlotPacket.cpp
+++ b/source/network/packets/ContainerSetSlotPacket.cpp
@@ -2,9 +2,9 @@
#include "network/NetEventCallback.hpp"
#include "network/PacketUtil.hpp"
-ContainerSetSlotPacket::ContainerSetSlotPacket(int8_t containerId, int16_t slot, const ItemStack& item)
+ContainerSetSlotPacket::ContainerSetSlotPacket(int8_t containerId, int16_t slotId, const ItemStack& item)
: m_containerId(containerId)
- , m_slot(slot)
+ , m_slotId(slotId)
, m_item(item)
{
}
@@ -18,13 +18,13 @@ void ContainerSetSlotPacket::write(RakNet::BitStream& bs)
{
bs.Write((unsigned char)PACKET_CONTAINER_SET_SLOT);
bs.Write(m_containerId);
- bs.Write(m_slot);
+ bs.Write(m_slotId);
PacketUtil::WriteItemStack(m_item, bs, false);
}
void ContainerSetSlotPacket::read(RakNet::BitStream& bs)
{
bs.Read(m_containerId);
- bs.Read(m_slot);
+ bs.Read(m_slotId);
m_item = PacketUtil::ReadItemStack(bs, false);
}
diff --git a/source/network/packets/ContainerSetSlotPacket.hpp b/source/network/packets/ContainerSetSlotPacket.hpp
index f3e547323..86f66dd9c 100644
--- a/source/network/packets/ContainerSetSlotPacket.hpp
+++ b/source/network/packets/ContainerSetSlotPacket.hpp
@@ -9,15 +9,15 @@ class ContainerSetSlotPacket : public Packet
ContainerSetSlotPacket()
{
m_containerId = 0;
- m_slot = 0;
+ m_slotId = 0;
}
- ContainerSetSlotPacket(int8_t containerId, int16_t slot, const ItemStack& item);
+ ContainerSetSlotPacket(int8_t containerId, int16_t slotId, const ItemStack& item);
void handle(const RakNet::RakNetGUID&, NetEventCallback& callback) override;
void write(RakNet::BitStream&) override;
void read(RakNet::BitStream&) override;
public:
int8_t m_containerId;
- int16_t m_slot;
+ int16_t m_slotId;
ItemStack m_item;
};
diff --git a/source/network/packets/SendInventoryPacket.cpp b/source/network/packets/SendInventoryPacket.cpp
index 2e1888ae4..376255384 100644
--- a/source/network/packets/SendInventoryPacket.cpp
+++ b/source/network/packets/SendInventoryPacket.cpp
@@ -2,11 +2,10 @@
#include "network/NetEventCallback.hpp"
#include "network/PacketUtil.hpp"
-SendInventoryPacket::SendInventoryPacket(int32_t entityId, const std::vector& items, bool dropAll)
+SendInventoryPacket::SendInventoryPacket(int32_t entityId, bool dropAll)
: m_entityId(entityId)
- , m_items(items)
, m_count(0)
- , m_bDropAll(dropAll)
+ , m_extra(dropAll ? EXTRA_DROP_ALL : EXTRA_NONE)
{
}
@@ -17,9 +16,9 @@ void SendInventoryPacket::handle(const RakNet::RakNetGUID& guid, NetEventCallbac
void SendInventoryPacket::write(RakNet::BitStream& bs)
{
- bs.Write((unsigned char)PACKET_DROP_ITEM);
+ bs.Write((unsigned char)PACKET_SEND_INVENTORY);
bs.Write(m_entityId);
- bs.Write(m_bDropAll);
+ bs.Write(m_extra);
bs.Write((uint16_t)m_items.size());
for (size_t i = 0; i < m_items.size(); i++)
@@ -31,15 +30,14 @@ void SendInventoryPacket::write(RakNet::BitStream& bs)
void SendInventoryPacket::read(RakNet::BitStream& bs)
{
bs.Read(m_entityId);
- bs.Read(m_bDropAll);
+ bs.Read(m_extra);
bs.Read(m_count);
- // End early, processing the rest of this (like PE does) is just a recipe for disaster
- // Plus, it doesn't really matter, as PE just sends 512 empty items anyways
- /*
- m_items.resize(m_count);
+ m_count = Mth::Min(m_count, 512);
+ m_items.reserve(m_count);
+
for (uint16_t i = 0; i < m_count; i++)
{
m_items.push_back(PacketUtil::ReadItemStack(bs, false));
- }*/
+ }
}
diff --git a/source/network/packets/SendInventoryPacket.hpp b/source/network/packets/SendInventoryPacket.hpp
index 954783c76..df53b6ac8 100644
--- a/source/network/packets/SendInventoryPacket.hpp
+++ b/source/network/packets/SendInventoryPacket.hpp
@@ -7,14 +7,21 @@
class SendInventoryPacket : public Packet
{
+public:
+ enum Extra
+ {
+ EXTRA_NONE,
+ EXTRA_DROP_ALL
+ };
+
public:
SendInventoryPacket()
{
m_entityId = 0;
m_count = 0;
- m_bDropAll = false;
+ m_extra = EXTRA_NONE;
}
- SendInventoryPacket(int32_t entityId, const std::vector& items, bool dropAll = false);
+ SendInventoryPacket(int32_t entityId, bool dropAll = false);
void handle(const RakNet::RakNetGUID&, NetEventCallback& callback) override;
void write(RakNet::BitStream&) override;
@@ -23,5 +30,5 @@ class SendInventoryPacket : public Packet
int32_t m_entityId;
std::vector m_items;
uint16_t m_count;
- bool m_bDropAll;
+ uint8_t m_extra;
};
diff --git a/source/network/packets/SetEntityDataPacket.hpp b/source/network/packets/SetEntityDataPacket.hpp
index 917e42e2b..cd2b18e4a 100644
--- a/source/network/packets/SetEntityDataPacket.hpp
+++ b/source/network/packets/SetEntityDataPacket.hpp
@@ -17,9 +17,11 @@ class SetEntityDataPacket : public Packet
void write(RakNet::BitStream&) override;
void read(RakNet::BitStream&) override;
const SynchedEntityData::ItemsArray& getUnpackedData() const { return m_packedItems; }
+
public:
int32_t m_entityId;
bool m_bIsIncoming;
+
private:
SynchedEntityData::ItemsArray m_packedItems;
};
diff --git a/source/renderer/GL/GL.cpp b/source/renderer/GL/GL.cpp
index 230895f46..12ffd16ad 100644
--- a/source/renderer/GL/GL.cpp
+++ b/source/renderer/GL/GL.cpp
@@ -157,25 +157,29 @@ int glhInvertMatrixf2(float* m, float* out)
r2[3] -= m2 * s;
r3[3] -= m3 * s;
s = r0[4];
- if (s != 0.0f) {
+ if (s != 0.0f)
+ {
r1[4] -= m1 * s;
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r0[5];
- if (s != 0.0f) {
+ if (s != 0.0f)
+ {
r1[5] -= m1 * s;
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r0[6];
- if (s != 0.0f) {
+ if (s != 0.0f)
+ {
r1[6] -= m1 * s;
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r0[7];
- if (s != 0.0f) {
+ if (s != 0.0f)
+ {
r1[7] -= m1 * s;
r2[7] -= m2 * s;
r3[7] -= m3 * s;
@@ -195,22 +199,26 @@ int glhInvertMatrixf2(float* m, float* out)
r2[3] -= m2 * r1[3];
r3[3] -= m3 * r1[3];
s = r1[4];
- if (0.0f != s) {
+ if (0.0f != s)
+ {
r2[4] -= m2 * s;
r3[4] -= m3 * s;
}
s = r1[5];
- if (0.0f != s) {
+ if (0.0f != s)
+ {
r2[5] -= m2 * s;
r3[5] -= m3 * s;
}
s = r1[6];
- if (0.0f != s) {
+ if (0.0f != s)
+ {
r2[6] -= m2 * s;
r3[6] -= m3 * s;
}
s = r1[7];
- if (0.0f != s) {
+ if (0.0f != s)
+ {
r2[7] -= m2 * s;
r3[7] -= m3 * s;
}
diff --git a/source/server/ServerPlayer.cpp b/source/server/ServerPlayer.cpp
index 873c837f3..c31d4442a 100644
--- a/source/server/ServerPlayer.cpp
+++ b/source/server/ServerPlayer.cpp
@@ -1,4 +1,5 @@
#include "ServerPlayer.hpp"
+#include "common/Logger.hpp"
#include "network/packets/SetHealthPacket.hpp"
#include "network/packets/TakeItemEntityPacket.hpp"
#include "network/packets/SendInventoryPacket.hpp"
@@ -9,8 +10,11 @@
#include "network/packets/ContainerSetContentPacket.hpp"
#include "network/RakNetInstance.hpp"
#include "world/inventory/CraftingMenu.hpp"
+#include "world/inventory/FurnaceMenu.hpp"
#include "world/inventory/ChestMenu.hpp"
#include "world/level/Level.hpp"
+#include "world/tile/entity/FurnaceTileEntity.hpp"
+#include "world/inventory/Slot.hpp"
ServerPlayer::ServerPlayer(Level* pLevel, GameType playerGameType)
: Player(pLevel, playerGameType)
@@ -21,6 +25,11 @@ ServerPlayer::ServerPlayer(Level* pLevel, GameType playerGameType)
m_pInventoryMenu->addSlotListener(this);
}
+ServerPlayer::~ServerPlayer()
+{
+ doCloseContainer();
+}
+
void ServerPlayer::_nextContainerCounter()
{
m_containerId++;
@@ -33,6 +42,9 @@ void ServerPlayer::tick()
{
Player::tick();
+ if (m_pContainerMenu)
+ m_pContainerMenu->broadcastChanges();
+
if (m_health != m_lastHealth)
{
m_pLevel->m_pRakNetInstance->send(m_guid, new SetHealthPacket(m_health));
@@ -53,12 +65,14 @@ void ServerPlayer::startCrafting(const TilePos& pos)
void ServerPlayer::openContainer(Container* container)
{
+ //LOG_I("Client is opening a container");
+
_nextContainerCounter();
#if NETWORK_PROTOCOL_VERSION >= 5
m_pLevel->m_pRakNetInstance->send(
new ContainerOpenPacket(
- m_pContainerMenu->m_containerId, Container::CONTAINER,
+ m_containerId, Container::CONTAINER,
container->getName(), container->getContainerSize()
)
);
@@ -69,6 +83,8 @@ void ServerPlayer::openContainer(Container* container)
void ServerPlayer::closeContainer()
{
+ //LOG_I("Client is closing a container");
+
#if NETWORK_PROTOCOL_VERSION >= 5
m_pLevel->m_pRakNetInstance->send(new ContainerClosePacket(m_pContainerMenu->m_containerId));
#endif
@@ -76,6 +92,24 @@ void ServerPlayer::closeContainer()
doCloseContainer();
}
+void ServerPlayer::openFurnace(FurnaceTileEntity* furnace)
+{
+ //LOG_I("Client is opening a furnace");
+
+ _nextContainerCounter();
+
+#if NETWORK_PROTOCOL_VERSION >= 5
+ m_pLevel->m_pRakNetInstance->send(
+ new ContainerOpenPacket(
+ m_containerId, Container::FURNACE,
+ furnace->getName(), furnace->getContainerSize()
+ )
+ );
+#endif
+
+ setContainerMenu(new FurnaceMenu(m_pInventory, furnace));
+}
+
void ServerPlayer::take(Entity* pEnt, int count)
{
m_pLevel->m_pRakNetInstance->send(new TakeItemEntityPacket(pEnt->m_EntityID, m_EntityID));
@@ -92,12 +126,19 @@ void ServerPlayer::refreshContainer(ContainerMenu* menu, const std::vector= 5
if (!isResultSlot)
{
- m_pLevel->m_pRakNetInstance->send(new ContainerSetSlotPacket(menu->m_containerId, index, item));
+#ifndef FEATURE_SERVER_INVENTORIES
+ // @TODO: See my gripes in ContainerMenu::slotChanged
+ // But ultimately this is a bandaid for the fact that the client has authority over the inventory in PE
+ if (slot->m_group == Slot::INVENTORY || slot->m_group == Slot::HOTBAR)
+ return;
+#endif
+
+ m_pLevel->m_pRakNetInstance->send(new ContainerSetSlotPacket(menu->m_containerId, slotId, item));
}
#endif
}
@@ -113,7 +154,10 @@ void ServerPlayer::doCloseContainer()
{
if (m_pContainerMenu)
m_pContainerMenu->removed(this);
- setContainerMenu(nullptr); // m_pInventoryMenu on Java, nullptr on Pocket
+ else
+ LOG_W("Container is missing @ doCloseContainer!");
+
+ setContainerMenu(m_pInventoryMenu); // m_pInventoryMenu on Java, nullptr on Pocket
}
void ServerPlayer::setContainerMenu(ContainerMenu* menu)
@@ -121,12 +165,17 @@ void ServerPlayer::setContainerMenu(ContainerMenu* menu)
if (m_pContainerMenu == menu)
return;
- SAFE_DELETE(m_pContainerMenu);
+ if (m_pContainerMenu != m_pInventoryMenu)
+ SAFE_DELETE(m_pContainerMenu);
+
m_pContainerMenu = menu;
- if (menu)
+ // we shouldn't be changing the containerId of the InventoryMenu
+ if (menu && menu != m_pInventoryMenu)
{
m_pContainerMenu->m_containerId = m_containerId;
m_pContainerMenu->addSlotListener(this);
+ refreshContainer(m_pContainerMenu, m_pContainerMenu->cloneItems());
+ m_pContainerMenu->broadcastChanges();
}
-}
\ No newline at end of file
+}
diff --git a/source/server/ServerPlayer.hpp b/source/server/ServerPlayer.hpp
index ddc2b7d53..dc385be2b 100644
--- a/source/server/ServerPlayer.hpp
+++ b/source/server/ServerPlayer.hpp
@@ -1,10 +1,11 @@
#include "world/entity/Player.hpp"
-#include "world/ContainerListener.hpp"
+#include "world/inventory/ContainerListener.hpp"
class ServerPlayer : public Player, public ContainerListener
{
public:
ServerPlayer(Level* pLevel, GameType playerGameType);
+ ~ServerPlayer();
protected:
void _nextContainerCounter();
@@ -14,10 +15,11 @@ class ServerPlayer : public Player, public ContainerListener
void startCrafting(const TilePos& pos) override;
void openContainer(Container* container) override;
void closeContainer() override;
+ void openFurnace(FurnaceTileEntity* tileEntity);
void take(Entity* pEnt, int count) override;
void refreshContainer(ContainerMenu* menu, const std::vector& items) override;
- void slotChanged(ContainerMenu* menu, int index, ItemStack& item, bool isResultSlot) override;
+ void slotChanged(ContainerMenu* menu, Container::SlotID slotId, Slot* slot, ItemStack& item, bool isResultSlot) override;
void setContainerData(ContainerMenu* menu, int id, int value) override;
void doCloseContainer();
diff --git a/source/server/ServerSideNetworkHandler.cpp b/source/server/ServerSideNetworkHandler.cpp
index d031d9d6d..c333c9164 100644
--- a/source/server/ServerSideNetworkHandler.cpp
+++ b/source/server/ServerSideNetworkHandler.cpp
@@ -154,17 +154,36 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, LoginPacke
m_pendingPlayers[guid] = pPlayer;
- StartGamePacket sgp;
- sgp.m_seed = m_pLevel->getSeed();
- sgp.m_levelVersion = m_pLevel->getLevelData()->getStorageVersion();
- sgp.m_gameType = pPlayer->getPlayerGameType();
- sgp.m_entityId = pPlayer->m_EntityID;
- sgp.m_time = m_pLevel->getTime();
- sgp.m_pos = pPlayer->m_pos;
- sgp.m_pos.y -= pPlayer->m_heightOffset;
-
- sgp.write(bs);
- m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false);
+ // Ensure Player is spawned above-ground
+ {
+ Vec3& pos = pPlayer->m_pos;
+ while (pos.y > 0)
+ {
+ pPlayer->setPos(pos);
+ if (pPlayer->canSpawn())
+ break;
+ pos.y++;
+ }
+
+ Vec3 pos2 = pos;
+ pos2.y -= pPlayer->m_heightOffset;
+ pPlayer->moveTo(pos2, pPlayer->m_rot);
+ }
+
+ // Send StartGamePacket
+ {
+ StartGamePacket sgp;
+ sgp.m_seed = m_pLevel->getSeed();
+ sgp.m_levelVersion = m_pLevel->getLevelData()->getStorageVersion();
+ sgp.m_gameType = pPlayer->getPlayerGameType();
+ sgp.m_entityId = pPlayer->m_EntityID;
+ sgp.m_time = m_pLevel->getTime();
+ sgp.m_pos = pPlayer->m_pos;
+ sgp.m_pos.y -= pPlayer->m_heightOffset;
+
+ sgp.write(bs);
+ m_pRakNetPeer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, guid, false);
+ }
#if NETWORK_PROTOCOL_VERSION <= 2
// emulate a ReadyPacket being received
@@ -218,9 +237,9 @@ 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 (EntityMap::iterator it = m_pLevel->m_entities.begin(); it != m_pLevel->m_entities.end(); ++it)
{
- Entity* entity = m_pLevel->m_entities[i];
+ Entity* entity = it->second;
if (canReplicateEntity(entity))
{
AddMobPacket packet(*((Mob*)entity));
@@ -396,7 +415,12 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlayerEqui
return;
}
+#ifdef FEATURE_SERVER_INVENTORIES
+ // will need to be reworked for proper server-sided inventory support, pick the proper slot, not just any item
pPlayer->m_pInventory->pickItem(packet->m_itemID, packet->m_itemAuxValue, C_MAX_HOTBAR_ITEMS);
+#else
+ pPlayer->m_pInventory->setSelectedItem(ItemStack(packet->m_itemID, 1, packet->m_itemAuxValue));
+#endif
redistributePacket(packet, guid);
}
@@ -480,6 +504,23 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, UseItemPac
pPlayer->swing();
}
+// added specifically to allow Noteblocks to work, but ideally should just be a part of ServerPlayerGameMode
+bool _startDestroyBlock(Level& level, Player& player, const TilePos& pos, Facing::Name face)
+{
+ ItemStack& item = player.getSelectedItem();
+ if (!item.isEmpty() && item.getItem() == Item::bow)
+ return true;
+
+ TileID tile = level.getTile(pos);
+
+ if (tile <= 0)
+ return false;
+
+ Tile::tiles[tile]->attack(&level, pos, &player);
+
+ return true;
+}
+
void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlayerActionPacket* packet)
{
puts_ignorable("PlayerActionPacket");
@@ -494,6 +535,13 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, PlayerActi
switch (packet->m_action)
{
+ case PlayerActionPacket::START_DESTROY_BLOCK:
+ _startDestroyBlock(*m_pLevel, *pPlayer, packet->m_tilePos, packet->m_tileFace);
+ //m_pMinecraft->getPlayerGameMode(*pPlayer)->startDestroyBlock(pPlayer, packet->m_tilePos, packet->m_tileFace);
+ break;
+ case PlayerActionPacket::STOP_DESTROY_BLOCK:
+ //m_pMinecraft->getPlayerGameMode(*pPlayer)->stopDestroyBlock(pPlayer, packet->m_tilePos, packet->m_tileFace);
+ break;
case PlayerActionPacket::STOP_USING_ITEM:
pPlayer->releaseUsingItem();
break;
@@ -595,7 +643,7 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, SendInvent
pPlayer->m_pInventory->replace(packet->m_items);
- if (packet->m_bDropAll)
+ if (packet->m_extra == SendInventoryPacket::EXTRA_DROP_ALL)
pPlayer->m_pInventory->dropAll();
}
@@ -647,15 +695,26 @@ void ServerSideNetworkHandler::handle(const RakNet::RakNetGUID& guid, ContainerS
return;
ContainerMenu* pContainerMenu = pPlayer->m_pContainerMenu;
+ bool isInventory = false;
+
+ // @HACK: LocalPlayer inventory seems to always have Container ID 0
+ if (packet->m_containerId == 0)
+ {
+ pContainerMenu = pPlayer->m_pInventoryMenu;
+ isInventory = true;
+ }
+
if (!pContainerMenu)
return;
- if (pContainerMenu->m_containerId == packet->m_containerId)
+ if (pContainerMenu->m_containerId == packet->m_containerId
+ || (isInventory && packet->m_containerId == 0))
{
switch (pContainerMenu->m_containerType)
{
case Container::FURNACE:
- pContainerMenu->setItem(packet->m_slot, packet->m_item);
+ case Container::CONTAINER:
+ pContainerMenu->setItem(packet->m_slotId, packet->m_item);
break;
default:
break;
diff --git a/source/world/CompoundContainer.cpp b/source/world/CompoundContainer.cpp
deleted file mode 100644
index 80e339b90..000000000
--- a/source/world/CompoundContainer.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-#include "CompoundContainer.hpp"
-
-CompoundContainer::CompoundContainer(const std::string& name, Container* c1, Container* c2) :
- m_name(name), m_pLeftContainer(c1), m_pRightContainer(c2)
-{
-}
-
-uint16_t CompoundContainer::getContainerSize() const
-{
- return uint16_t(m_pLeftContainer->getContainerSize() + m_pRightContainer->getContainerSize());
-}
-
-std::string CompoundContainer::getName() const
-{
- return m_name;
-}
-
-ItemStack& CompoundContainer::getItem(int index)
-{
- if (index >= m_pLeftContainer->getContainerSize())
- return m_pRightContainer->getItem(index - m_pLeftContainer->getContainerSize());
- else
- return m_pLeftContainer->getItem(index);
-}
-
-ItemStack CompoundContainer::removeItem(int index, int count)
-{
- if (index >= m_pLeftContainer->getContainerSize())
- return m_pRightContainer->removeItem(index - m_pLeftContainer->getContainerSize(), count);
- else
- return m_pLeftContainer->removeItem(index, count);
-}
-
-void CompoundContainer::setItem(int index, const ItemStack& item)
-{
- if (index >= m_pLeftContainer->getContainerSize())
- m_pRightContainer->setItem(index - m_pLeftContainer->getContainerSize(), item);
- else
- m_pLeftContainer->setItem(index, item);
-}
-
-int CompoundContainer::getMaxStackSize()
-{
- return m_pLeftContainer->getMaxStackSize();
-}
-
-void CompoundContainer::setChanged()
-{
- m_pLeftContainer->setChanged();
- m_pRightContainer->setChanged();
-}
-
-bool CompoundContainer::stillValid(Player* player) const
-{
- return m_pLeftContainer->stillValid(player) && m_pRightContainer->stillValid(player);
-}
-
diff --git a/source/world/CompoundContainer.hpp b/source/world/CompoundContainer.hpp
deleted file mode 100644
index 5a4884591..000000000
--- a/source/world/CompoundContainer.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include
-#include "Container.hpp"
-
-class CompoundContainer : public Container
-{
-private:
- std::string m_name;
- Container* m_pLeftContainer;
- Container* m_pRightContainer;
-
-public:
- CompoundContainer(const std::string& name, Container* c1, Container* c2);
-
- uint16_t getContainerSize() const override;
-
- std::string getName() const override;
-
- ItemStack& getItem(int index) override;
-
- ItemStack removeItem(int index, int count) override;
-
- void setItem(int index, const ItemStack& item) override;
-
- int getMaxStackSize() override;
-
- void setChanged() override;
-
- bool stillValid(Player* player) const override;
-};
diff --git a/source/world/Container.hpp b/source/world/Container.hpp
deleted file mode 100644
index 8c18f3a6c..000000000
--- a/source/world/Container.hpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#pragma once
-
-#include "world/item/ItemStack.hpp"
-
-#define C_MAX_CONTAINER_STACK_SIZE (64)
-
-class Container
-{
-public:
- enum Type
- {
- CONTAINER,
- CRAFTING,
- FURNACE,
- DISPENSER
- };
-
-public:
- virtual uint16_t getContainerSize() const = 0;
- virtual ItemStack& getItem(int index) = 0;
- virtual ItemStack* tryGetItem(int index)
- {
- if (index >= 0 && index < getContainerSize())
- return &getItem(index);
- else
- return nullptr;
- }
- virtual ItemStack removeItem(int index, int count) = 0;
- virtual void setItem(int index, const ItemStack& item) = 0;
- virtual std::string getName() const = 0;
- virtual int getMaxStackSize()
- {
- return C_MAX_CONTAINER_STACK_SIZE;
- }
- virtual void setChanged() = 0;
- virtual bool stillValid(Player* player) const = 0;
-};
\ No newline at end of file
diff --git a/source/world/Facing.cpp b/source/world/Facing.cpp
new file mode 100644
index 000000000..0893ffc57
--- /dev/null
+++ b/source/world/Facing.cpp
@@ -0,0 +1,19 @@
+#include "Facing.hpp"
+
+const Facing::Name Facing::OPPOSITE[6] =
+{
+ Facing::UP, // DOWN -> UP
+ Facing::DOWN, // UP -> DOWN
+ Facing::SOUTH, // NORTH -> SOUTH
+ Facing::NORTH, // SOUTH -> NORTH
+ Facing::EAST, // WEST -> EAST
+ Facing::WEST // EAST -> WEST
+};
+
+const Facing::Name Facing::HORIZONTAL[4] =
+{
+ Facing::NORTH,
+ Facing::SOUTH,
+ Facing::EAST,
+ Facing::WEST
+};
\ No newline at end of file
diff --git a/source/world/Facing.hpp b/source/world/Facing.hpp
index 740f1ce37..2875da6d5 100644
--- a/source/world/Facing.hpp
+++ b/source/world/Facing.hpp
@@ -12,4 +12,6 @@ class Facing
WEST, // -X
EAST // +X
};
-};
+ static const Name OPPOSITE[6];
+ static const Name HORIZONTAL[4];
+};
\ No newline at end of file
diff --git a/source/world/entity/Creeper.cpp b/source/world/entity/Creeper.cpp
index 5046ff694..e55485e5b 100644
--- a/source/world/entity/Creeper.cpp
+++ b/source/world/entity/Creeper.cpp
@@ -76,7 +76,8 @@ void Creeper::checkHurtTarget(Entity* pEnt, float f)
{
setSwellDir(-1);
m_swell--;
- if (m_swell < 0) {
+ if (m_swell < 0)
+ {
m_swell = 0;
}
}
diff --git a/source/world/entity/Entity.cpp b/source/world/entity/Entity.cpp
index d93b8e395..dfdd6fa73 100644
--- a/source/world/entity/Entity.cpp
+++ b/source/world/entity/Entity.cpp
@@ -25,6 +25,9 @@ void Entity::_init()
m_bInAChunk = false;
m_viewScale = 1.0f;
m_dimensionId = DIMENSION_OVERWORLD;
+ m_riderId = 0;
+ m_ridingId = 0;
+ m_bRiding = false;
m_bBlocksBuilding = false;
m_pLevel = nullptr;
m_tintColor = Color::WHITE;
@@ -481,6 +484,14 @@ void Entity::tick()
void Entity::baseTick()
{
//@TODO: untangle the gotos
+ if (const Entity* riding = getRiding())
+ {
+ // if you were riding an entity and they no longer exist, stop
+ if ((!riding && m_ridingId > 0) || riding->m_bRemoved)
+ {
+ setRiding(nullptr);
+ }
+ }
m_walkDistO = m_walkDist;
m_oPos = m_pos;
@@ -757,6 +768,9 @@ void Entity::playerTouch(Player* player)
void Entity::push(Entity* bud)
{
+ if (bud == getRider() || bud == getRiding())
+ return;
+
float diffX = bud->m_pos.x - m_pos.x;
float diffZ = bud->m_pos.z - m_pos.z;
float maxDiff = Mth::absMax(diffX, diffZ);
@@ -959,6 +973,46 @@ AABB* Entity::getCollideAgainstBox(Entity* ent) const
return nullptr;
}
+void Entity::rideTick()
+{
+ Entity* riding = getRiding();
+ if (!riding || riding->m_bRemoved)
+ {
+ setRiding(nullptr);
+ return;
+ }
+
+ // we don't move
+ m_vel = Vec3::ZERO;
+
+ tick();
+
+ riding->positionRider();
+ m_rideRot.x += riding->m_rot.x - riding->m_oRot.x;
+ m_rideRot.y += riding->m_rot.y - riding->m_oRot.y;
+ while (m_rideRot.y >= 180.0f)
+ m_rideRot.y -= 360.0f;
+ while (m_rideRot.y < -180.0f)
+ m_rideRot.y += 360.0f;
+ while (m_rideRot.x >= 180.0f)
+ m_rideRot.x -= 360.0f;
+ while (m_rideRot.x < -180.0f)
+ m_rideRot.x += 360.0f;
+
+ float rotX = m_rideRot.x * 0.5f;
+ float rotY = m_rideRot.y * 0.5f;
+
+ constexpr float lookLimiter = 10.0f;
+ rotX = Mth::clamp(rotX, -lookLimiter, lookLimiter);
+ rotY = Mth::clamp(rotY, -lookLimiter, lookLimiter);
+
+ m_rideRot.x -= rotX;
+ m_rideRot.y -= rotY;
+
+ m_rot.x += rotX;
+ m_rot.y += rotY;
+}
+
void Entity::handleInsidePortal()
{
}
@@ -968,6 +1022,99 @@ void Entity::handleEntityEvent(EventType::ID eventId)
LOG_W("Unknown EntityEvent ID: %d, EntityType: %s", eventId, getDescriptor().getEntityType().getName().c_str());
}
+void Entity::positionRider()
+{
+ Entity* rider = getRider();
+ if (!rider)
+ return;
+
+ rider->setPos(Vec3(m_pos.x, m_pos.y + getRideHeight() + rider->getRidingHeight(), m_pos.z));
+}
+
+void Entity::ride(Entity* newRiding)
+{
+ m_rideRot = Vec2::ZERO;
+ Entity* oldRiding = getRiding();
+
+ // Dismount current ride if nullptr is fed in
+ if (newRiding == nullptr)
+ {
+ if (oldRiding)
+ {
+ moveTo(oldRiding->m_pos);
+ setRot(oldRiding->m_rot);
+ oldRiding->setRider(nullptr);
+ }
+
+ // Let yourself know you aren't riding anything
+ setRiding(nullptr);
+
+ return;
+ }
+
+ // Dismount if the same entity is fed in
+ if (oldRiding && oldRiding == newRiding)
+ {
+ oldRiding->setRider(nullptr);
+
+ setRiding(nullptr);
+
+ moveTo(oldRiding->m_pos);
+ setRot(oldRiding->m_rot);
+ return;
+ }
+
+ // if (this.riding != null) this.riding.rider = null;
+ if (oldRiding)
+ {
+ oldRiding->setRider(nullptr);
+ }
+
+ // if (newRiding.rider != null) newRiding.rider.riding = null;
+ // i hate this name but it's literally what it is
+ if (Entity* newRidesOldRider = newRiding->getRider())
+ {
+ setRiding(nullptr);
+ newRidesOldRider->setRider(nullptr);
+ }
+
+ setRiding(newRiding);
+ newRiding->setRider(this);
+}
+
+Entity* Entity::getRiding() const
+{
+ if (m_ridingId <= 0)
+ return nullptr;
+
+ if (Entity* riding = m_pLevel->getEntity(m_ridingId))
+ return riding;
+
+ return nullptr;
+}
+
+Entity* Entity::getRider() const
+{
+ if (m_riderId <= 0)
+ return nullptr;
+
+ if (Entity* rider = m_pLevel->getEntity(m_riderId))
+ return rider;
+
+ return nullptr;
+}
+
+void Entity::setRider(Entity* rider)
+{
+ m_riderId = (rider) ? rider->m_EntityID : 0;
+}
+
+void Entity::setRiding(Entity* riding)
+{
+ m_ridingId = (riding) ? riding->m_EntityID : 0;
+ setSharedFlag(FLAG_RIDING, riding);
+}
+
/*void Entity::thunderHit(LightningBolt* bolt)
{
burn(5);
diff --git a/source/world/entity/Entity.hpp b/source/world/entity/Entity.hpp
index ad80a24b8..df739bd14 100644
--- a/source/world/entity/Entity.hpp
+++ b/source/world/entity/Entity.hpp
@@ -119,7 +119,7 @@ class Entity
Entity(Level*);
virtual ~Entity();
-protected:
+public:
virtual bool getSharedFlag(SharedFlag flag) const;
virtual void setSharedFlag(SharedFlag flag, bool value);
virtual void playStepSound(const TilePos& pos, TileID tileId);
@@ -175,7 +175,7 @@ class Entity
virtual bool isPushable() const { return false; }
virtual bool isShootable() const { return false; }
virtual bool isOnFire() const { return m_fireTicks > 0 || getSharedFlag(FLAG_ON_FIRE); }
- virtual bool isRiding() const { return /*m_pRiding != nullptr ||*/ getSharedFlag(FLAG_RIDING); }
+ virtual bool isRiding() const { return getRiding() || getSharedFlag(FLAG_RIDING); }
virtual bool isSneaking() const { return getSharedFlag(FLAG_SNEAKING); }
virtual void setSneaking(bool value) { setSharedFlag(FLAG_SNEAKING, value); }
virtual bool isAlive() const { return m_bRemoved; }
@@ -206,9 +206,18 @@ class Entity
virtual RenderType queryEntityRenderer() const;
virtual const AABB* getCollideBox() const;
virtual AABB* getCollideAgainstBox(Entity* ent) const;
+ virtual void rideTick();
virtual void handleInsidePortal();
virtual void handleEntityEvent(EventType::ID eventId);
//virtual void thunderHit(LightningBolt*);
+ virtual void positionRider();
+ virtual void ride(Entity*);
+ virtual float getRideHeight() const { return m_bbHeight * 0.75f; }
+ virtual float getRidingHeight() const { return m_heightOffset; }
+ Entity* getRiding() const;
+ Entity* getRider() const;
+ void setRiding(Entity* ent);
+ void setRider(Entity* ent);
void load(const CompoundTag& tag);
bool save(CompoundTag& tag) const;
void saveWithoutId(CompoundTag& tag) const;
@@ -233,6 +242,10 @@ class Entity
(m_pos.z - pos.z) * (m_pos.z - pos.z);
}
+private:
+ Entity::ID m_ridingId;
+ Entity::ID m_riderId;
+
protected:
SynchedEntityData m_entityData;
bool m_bMakeStepSound;
@@ -247,12 +260,14 @@ class Entity
float m_viewScale;
//TileSource* m_pTileSource;
DimensionId m_dimensionId;
+ bool m_bRiding;
bool m_bBlocksBuilding;
Level* m_pLevel;
Vec3 m_oPos; // "o" in Java or "xo" "yo" "zo"
Vec3 m_vel;
Vec2 m_rot;
Vec2 m_oRot; // "RotO" in Java or "xRotO" "yRotO"
+ Vec2 m_rideRot;
Color m_tintColor;
AABB m_hitbox;
bool m_bOnGround;
diff --git a/source/world/entity/Mob.cpp b/source/world/entity/Mob.cpp
index e754a2fa6..e216f2d9f 100644
--- a/source/world/entity/Mob.cpp
+++ b/source/world/entity/Mob.cpp
@@ -54,7 +54,7 @@ void Mob::_init()
m_lPos = Vec3::ZERO;
m_lRot = Vec2::ZERO;
m_lastHurt = 0;
- m_pEntLookedAt = nullptr;
+ m_entLookedAtId = 0;
m_bSwinging = false;
m_swingTime = 0;
m_ambientSoundTime = 0;
@@ -760,7 +760,7 @@ void Mob::aiStep()
{
Entity* pEnt = *it;
if (pEnt->isPushable())
- pEnt->push(this);
+ pEnt->push(this);
}
}
@@ -788,6 +788,13 @@ void Mob::lookAt(Entity* pEnt, float a3, float a4)
-rotlerp(m_rot.y, x2 * 180.0f / float(M_PI), a3)));
}
+Entity* Mob::getLookingAt() const
+{
+ if (m_entLookedAtId == 0)
+ return nullptr;
+ return m_pLevel->getEntity(m_entLookedAtId);
+}
+
bool Mob::canSpawn()
{
return m_pLevel->getCubes(this, m_hitbox)->empty();
@@ -834,7 +841,7 @@ void Mob::updateAi()
Entity* nearestPlayer = m_pLevel->getNearestPlayer(*this, 8.0f);
if (nearestPlayer)
{
- m_pEntLookedAt = nearestPlayer;
+ m_entLookedAtId = nearestPlayer->m_EntityID;
m_lookTime = m_random.nextInt(20) + 10;
}
@@ -845,17 +852,18 @@ void Mob::updateAi()
}
// @TODO: we get a crash here when a Player leaves
- if (m_pEntLookedAt)
+ if (m_entLookedAtId > 0)
{
- lookAt(m_pEntLookedAt, 10.0f, getMaxHeadXRot());
+ Entity* pEnt = m_pLevel->getEntity(m_entLookedAtId);
+ lookAt(pEnt, 10.0f, getMaxHeadXRot());
// gaze timer
m_lookTime--;
// if the entity was removed, or we're too far away, or our gaze timer is up
- if (m_lookTime < 0 || m_pEntLookedAt->m_bRemoved || m_pEntLookedAt->distanceToSqr(this) > 64.0f)
+ if (m_lookTime < 0 || pEnt->m_bRemoved || pEnt->distanceToSqr(this) > 64.0f)
// stop staring
- m_pEntLookedAt = nullptr;
+ m_entLookedAtId = 0;
}
else
{
diff --git a/source/world/entity/Mob.hpp b/source/world/entity/Mob.hpp
index ef91d1366..c697a3010 100644
--- a/source/world/entity/Mob.hpp
+++ b/source/world/entity/Mob.hpp
@@ -61,9 +61,9 @@ class Mob : public Entity
virtual void updateWalkAnim();
virtual void aiStep();
virtual void lookAt(Entity* pEnt, float, float);
- virtual bool isLookingAtAnEntity() { return m_pEntLookedAt != nullptr; }
+ virtual bool isLookingAtAnEntity() { return m_entLookedAtId > 0; }
virtual bool isSlowedByLiquids() const { return true; }
- virtual Entity* getLookingAt() const { return m_pEntLookedAt; }
+ virtual Entity* getLookingAt() const;
virtual void beforeRemove() {}
virtual bool canSpawn();
virtual float getAttackAnim(float f) const;
@@ -141,7 +141,7 @@ class Mob : public Entity
Vec3 m_lPos;
Vec2 m_lRot;
int m_lastHurt;
- Entity* m_pEntLookedAt;
+ Entity::ID m_entLookedAtId;
bool m_bSwinging;
int m_swingTime;
diff --git a/source/world/entity/MobSpawner.hpp b/source/world/entity/MobSpawner.hpp
index fd29acaf3..3d7316255 100644
--- a/source/world/entity/MobSpawner.hpp
+++ b/source/world/entity/MobSpawner.hpp
@@ -24,7 +24,7 @@ class MobSpawner {
public:
TilePos getRandomPosWithin(Level& level, int chunkX, int chunkZ);
void tick(Level& level, bool allowHostile, bool allowFriendly);
-private:
+private:
std::set chunksToPoll;
};
\ No newline at end of file
diff --git a/source/world/entity/Pig.cpp b/source/world/entity/Pig.cpp
index 153163f49..9a0caa988 100644
--- a/source/world/entity/Pig.cpp
+++ b/source/world/entity/Pig.cpp
@@ -6,6 +6,8 @@
SPDX-License-Identifier: BSD-1-Clause
********************************************************************/
#include "Pig.hpp"
+#include "Player.hpp"
+#include "world/level/Level.hpp"
Pig::Pig(Level* pLevel) : Animal(pLevel)
{
@@ -15,12 +17,40 @@ Pig::Pig(Level* pLevel) : Animal(pLevel)
setSize(0.9f, 0.9f);
// some dataitem stuff
}
+
int Pig::getDeathLoot() const
{
- if (isOnFire())
- return Item::porkChop_cooked->m_itemID;
- else
- return Item::porkChop_raw->m_itemID;
+ return (isOnFire()) ?
+ Item::porkChop_cooked->m_itemID :
+ Item::porkChop_raw->m_itemID;
+}
+
+bool Pig::interact(Player* pPlayer)
+{
+ return false;
+ // @TODO: add saddles
+ /*
+ if (m_pLevel->m_bIsClientSide)
+ {
+ return false;
+ }
+
+ if (!m_bSaddled)
+ {
+ return false;
+ }
+
+ Entity* rider = getRider();
+
+ // already being ridden by someone else
+ if (rider && rider != pPlayer)
+ {
+ return false;
+ }
+
+ pPlayer->ride(this);
+ return true;
+ */
}
void Pig::setSaddle(bool b)
diff --git a/source/world/entity/Pig.hpp b/source/world/entity/Pig.hpp
index c617da1a6..d13fe87f7 100644
--- a/source/world/entity/Pig.hpp
+++ b/source/world/entity/Pig.hpp
@@ -20,7 +20,7 @@ class Pig : public Animal
std::string getHurtSound() const override { return "mob.pig"; }
int getDeathLoot() const override;
int getMaxHealth() const override { return 10; }
- bool interact(Player*) override { return false; }
+ bool interact(Player*) override;
bool hasSaddle() const { return false; }
void setSaddle(bool b);
diff --git a/source/world/entity/Player.cpp b/source/world/entity/Player.cpp
index cbeef3ab1..97f052c4f 100644
--- a/source/world/entity/Player.cpp
+++ b/source/world/entity/Player.cpp
@@ -63,8 +63,8 @@ Player::Player(Level* pLevel, GameType playerGameType) : Mob(pLevel)
Player::~Player()
{
- delete m_pInventory;
delete m_pInventoryMenu;
+ delete m_pInventory;
}
void Player::reallyDrop(ItemEntity* pEnt)
@@ -72,6 +72,10 @@ void Player::reallyDrop(ItemEntity* pEnt)
m_pLevel->addEntity(pEnt);
}
+void Player::_handleOpenedContainerMenu()
+{
+}
+
void Player::reset()
{
Mob::reset();
@@ -169,6 +173,11 @@ void Player::die(Entity* pCulprit)
if (m_name == "Notch")
drop(ItemStack(Item::apple), true);
}
+
+#ifndef FEATURE_SERVER_INVENTORIES
+ // don't drop items on the server, leave it to SendInventoryPacket
+ if (m_pLevel->m_bIsClientSide)
+#endif
#if NETWORK_PROTOCOL_VERSION <= 3
m_pInventory->dropAll(m_pLevel->m_bIsClientSide);
#endif
@@ -262,7 +271,7 @@ void Player::tick()
const ItemStack& Player::getCarriedItem() const
{
// This only gets the first row slot
- /*ItemStack* item = m_pInventory->getItem(m_pInventory->m_selectedSlot);
+ /*ItemStack* item = m_pInventory->getItem(m_pInventory->m_selectedStackId);
if (ItemStack::isNull(item))
return nullptr;
@@ -320,7 +329,8 @@ void Player::readAdditionalSaveData(const CompoundTag& tag)
m_dimension = tag.getInt32("Dimension");
//m_sleepTimer = tag.getInt32("SleepTimer");
- if (tag.contains("SpawnX") && tag.contains("SpawnY") && tag.contains("SpawnZ")) {
+ if (tag.contains("SpawnX") && tag.contains("SpawnY") && tag.contains("SpawnZ"))
+ {
setRespawnPos(TilePos( static_cast(tag.getInt32("SpawnX")),
static_cast(tag.getInt32("SpawnY")),
static_cast(tag.getInt32("SpawnZ"))));
@@ -385,7 +395,8 @@ void Player::attack(Entity* pEnt)
if (!item.isEmpty() && isMob)
{
item.hurtEnemy((Mob*)pEnt, this);
- if (item.m_count <= 0) {
+ if (item.m_count <= 0)
+ {
item.snap(this);
removeSelectedItem();
}
@@ -492,7 +503,9 @@ void Player::respawn()
void Player::rideTick()
{
-
+ Mob::rideTick();
+ m_oBob = m_bob;
+ m_bob = 0.0f;
}
void Player::setDefaultHeadHeight()
@@ -512,16 +525,11 @@ void Player::setRespawnPos(const TilePos& pos)
m_respawnPos = pos;
}
-/*void Player::drop()
+// @PARITY: From b1.2_02, doesn't exist in PE
+void Player::drop()
{
- // @PARITY: From b1.2_02, doesn't exist in PE
- // Isn't called anywhere, but is overriden in MultiplayerLocalPlayer with a PlayerActionPacket
- ItemStack* item = getSelectedItem();
- if (!item)
- return;
-
- drop(m_pInventory->removeItem(*item, 1));
-}*/
+ drop(m_pInventory->removeItem(m_pInventory->getSelectedSlotNo(), 1));
+}
void Player::drop(const ItemStack& item, bool randomly)
{
@@ -559,12 +567,12 @@ void Player::drop(const ItemStack& item, bool randomly)
void Player::startCrafting(const TilePos& pos)
{
-
+ _handleOpenedContainerMenu();
}
void Player::startStonecutting(const TilePos& pos)
{
-
+ _handleOpenedContainerMenu();
}
void Player::startDestroying()
@@ -577,6 +585,20 @@ void Player::stopDestroying()
m_destroyingBlock = false;
}
+void Player::openFurnace(FurnaceTileEntity* tileEntity)
+{
+ _handleOpenedContainerMenu();
+}
+
+void Player::openContainer(Container* container)
+{
+ _handleOpenedContainerMenu();
+}
+
+void Player::closeContainer()
+{
+}
+
void Player::touch(Entity* pEnt)
{
pEnt->playerTouch(this);
@@ -592,9 +614,11 @@ void Player::interact(Entity* pEnt)
return;
ItemStack& item = getSelectedItem();
- if (!item.isEmpty()) {
+ if (!item.isEmpty())
+ {
item.interactEnemy(static_cast(pEnt));
- if (item.m_count <= 0) {
+ if (item.m_count <= 0)
+ {
item.snap(this);
removeSelectedItem();
}
diff --git a/source/world/entity/Player.hpp b/source/world/entity/Player.hpp
index c75ff8831..06b3f7b87 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 FurnaceTileEntity;
class Player : public Mob
{
@@ -40,11 +41,12 @@ class Player : public Mob
protected:
virtual void reallyDrop(ItemEntity* pEnt);
+ virtual void _handleOpenedContainerMenu();
public:
void reset() override;
void remove() override;
- float getHeadHeight() const override { return 0.12f; /*@HUH: what ?*/ }
+ float getHeadHeight() const override { return 0.12f; }
int getMaxHealth() const override { return 20; }
bool isShootable() const override { return true; }
bool isPlayer() const override { return true; }
@@ -66,15 +68,15 @@ class Player : public Mob
void causeFallDamage(float level) override;
virtual void animateRespawn();
- //virtual void drop(); // see definition
+ virtual void drop();
virtual void drop(const ItemStack& item, bool randomly = false);
virtual void startCrafting(const TilePos& pos);
virtual void startStonecutting(const TilePos& pos);
virtual void startDestroying();
virtual void stopDestroying();
- //virtual void openFurnace(FurnaceTileEntity* tileEntity);
- virtual void openContainer(Container* container) {}
- virtual void closeContainer() {}
+ virtual void openFurnace(FurnaceTileEntity* tileEntity);
+ virtual void openContainer(Container* container);
+ virtual void closeContainer();
//virtual void openTrap(DispenserTileEntity* tileEntity);
//virtual void openTextEdit(SignTileEntity* tileEntity);
virtual bool isLocalPlayer() const { return false; }
@@ -95,7 +97,8 @@ class Player : public Mob
Dimension* getDimension() const;
void prepareCustomTextures();
void respawn();
- void rideTick();
+ void rideTick() override;
+ float getRidingHeight() const override { return m_heightOffset - 0.5f; }
void setDefaultHeadHeight();
void setRespawnPos(const TilePos& pos);
inline const Abilities& getAbilities() const { return m_abilities; }
diff --git a/source/world/entity/Spider.hpp b/source/world/entity/Spider.hpp
index 4ecc268ee..9b81aedbf 100644
--- a/source/world/entity/Spider.hpp
+++ b/source/world/entity/Spider.hpp
@@ -12,7 +12,7 @@ class Spider : public Monster
std::string getDeathSound() const override { return "mob.spiderdeath"; }
std::string getHurtSound() const override { return "mob.spider"; }
int getDeathLoot() const override { return ITEM_STRING; }
- float getRideHeight() const { return m_bbHeight * 0.75f - 0.5f; }
+ float getRideHeight() const override { return m_bbHeight * 0.75f - 0.5f; }
Entity* findAttackTarget() override;
void checkHurtTarget(Entity* ent, float var2) override;
diff --git a/source/world/gamemode/GameMode.cpp b/source/world/gamemode/GameMode.cpp
index 4f30701d8..c68b3bd5b 100644
--- a/source/world/gamemode/GameMode.cpp
+++ b/source/world/gamemode/GameMode.cpp
@@ -126,9 +126,9 @@ void GameMode::attack(Player* player, Entity* entity)
player->attack(entity);
}
-ItemStack GameMode::handleInventoryMouseClick(int containerId, int slotNum, MouseButtonType button, bool quick, Player* player)
+ItemStack GameMode::handleInventoryMouseClick(int containerId, Container::SlotID slotId, MouseButtonType button, bool quick, Player* player)
{
- return player->m_pContainerMenu->clicked(slotNum, button, quick, player);
+ return player->m_pContainerMenu->clicked(slotId, button, quick, player);
}
void GameMode::handleCloseInventory(int a, Player* player)
diff --git a/source/world/gamemode/GameMode.hpp b/source/world/gamemode/GameMode.hpp
index 8b0b58bcd..693a91713 100644
--- a/source/world/gamemode/GameMode.hpp
+++ b/source/world/gamemode/GameMode.hpp
@@ -42,7 +42,7 @@ class GameMode
virtual bool canHurtPlayer();
virtual void interact(Player*, Entity*);
virtual void attack(Player*, Entity*);
- virtual ItemStack handleInventoryMouseClick(int, int, MouseButtonType, bool, Player*);
+ virtual ItemStack handleInventoryMouseClick(int containerId, Container::SlotID slotId, MouseButtonType, bool, Player*);
virtual void handleCloseInventory(int, Player*);
virtual bool isCreativeType() const { return true; }
virtual bool isSurvivalType() const { return false; }
diff --git a/source/world/gamemode/SurvivalMode.cpp b/source/world/gamemode/SurvivalMode.cpp
index c43feb939..6e5b9a84b 100644
--- a/source/world/gamemode/SurvivalMode.cpp
+++ b/source/world/gamemode/SurvivalMode.cpp
@@ -42,6 +42,14 @@ bool SurvivalMode::startDestroyBlock(Player* player, const TilePos& pos, Facing:
if (tile <= 0)
return false;
+ // @PARITY: This is in MultiPlayerGameMode on Java, but we aren't equipped to move to that at the moment
+#if NETWORK_PROTOCOL_VERSION >= 6
+ if (m_pMinecraft->isOnlineClient())
+ {
+ m_pMinecraft->m_pRakNetInstance->send(new PlayerActionPacket(player->m_EntityID, PlayerActionPacket::START_DESTROY_BLOCK, pos, face));
+ }
+#endif
+
if (m_destroyProgress == 0.0f)
{
Tile::tiles[tile]->attack(&_level, pos, player);
@@ -128,6 +136,14 @@ bool SurvivalMode::continueDestroyBlock(Player* player, const TilePos& pos, Faci
m_destroyCooldown = 5;
m_destroyProgress = 0.0f;
m_lastDestroyProgress = 0.0f;
+
+ // @PARITY: This is in MultiPlayerGameMode on Java, but we aren't equipped to move to that at the moment
+#if NETWORK_PROTOCOL_VERSION >= 6
+ if (m_pMinecraft->isOnlineClient())
+ {
+ m_pMinecraft->m_pRakNetInstance->send(new PlayerActionPacket(player->m_EntityID, PlayerActionPacket::STOP_DESTROY_BLOCK, pos, face));
+ }
+#endif
return destroyBlock(player, m_destroyingPos, face);
}
diff --git a/source/world/inventory/ArmorSlot.hpp b/source/world/inventory/ArmorSlot.hpp
index 2b679e8d9..0e54f8ab5 100644
--- a/source/world/inventory/ArmorSlot.hpp
+++ b/source/world/inventory/ArmorSlot.hpp
@@ -1,7 +1,7 @@
#pragma once
#include "Slot.hpp"
-#include "world/Container.hpp"
+#include "Container.hpp"
class ArmorSlot : public Slot
{
diff --git a/source/world/inventory/ChestMenu.cpp b/source/world/inventory/ChestMenu.cpp
index 95a78894f..a0b061981 100644
--- a/source/world/inventory/ChestMenu.cpp
+++ b/source/world/inventory/ChestMenu.cpp
@@ -7,16 +7,18 @@ ChestMenu::ChestMenu(Container* inventory, Container* container)
{
int rows = m_pContainer->getContainerSize() / 9;
+ // Chest slots
for (int row = 0; row < rows; ++row)
{
for (int col = 0; col < 9; ++col)
- addSlot(new Slot(m_pContainer, col + row * 9));
+ addSlot(new Slot(m_pContainer, col + row * 9, Slot::CONTAINER));
}
+ // Inventory slots
for (int row = 0; row < 3; ++row)
{
for (int col = 0; col < 9; ++col)
- addSlot(new Slot(inventory, col + row * 9 + 9));
+ addSlot(new Slot(inventory, col + row * 9 + 9, Slot::INVENTORY));
}
for (int col = 0; col < 9; ++col)
@@ -30,16 +32,16 @@ bool ChestMenu::stillValid(Player* player) const
return m_pContainer->stillValid(player);
}
-ItemStack ChestMenu::quickMoveStack(int index)
+ItemStack ChestMenu::quickMoveStack(Container::SlotID slotId)
{
ItemStack item = ItemStack::EMPTY;
- Slot* slot = getSlot(index);
+ Slot* slot = getSlot(slotId);
if (slot && slot->hasItem())
{
ItemStack& slotItem = slot->getItem();
item = slotItem;
int rows = m_pContainer->getContainerSize() / 9;
- if (index < rows * 9)
+ if (slotId < rows * 9)
moveItemStackTo(slotItem, rows * 9, m_slots.size(), true);
else
moveItemStackTo(slotItem, 0, rows * 9, false);
diff --git a/source/world/inventory/ChestMenu.hpp b/source/world/inventory/ChestMenu.hpp
index ea787bea3..8206e24ba 100644
--- a/source/world/inventory/ChestMenu.hpp
+++ b/source/world/inventory/ChestMenu.hpp
@@ -1,7 +1,7 @@
#pragma once
#include "ContainerMenu.hpp"
-#include "world/Container.hpp"
+#include "Container.hpp"
#include "world/entity/Player.hpp"
class ChestMenu : public ContainerMenu
@@ -10,7 +10,7 @@ class ChestMenu : public ContainerMenu
ChestMenu(Container* inventory, Container* container);
bool stillValid(Player* player) const override;
- ItemStack quickMoveStack(int index) override;
+ ItemStack quickMoveStack(Container::SlotID slotId) override;
private:
Container* m_pContainer;
diff --git a/source/world/inventory/CompoundContainer.cpp b/source/world/inventory/CompoundContainer.cpp
new file mode 100644
index 000000000..58efc6e30
--- /dev/null
+++ b/source/world/inventory/CompoundContainer.cpp
@@ -0,0 +1,107 @@
+#include "CompoundContainer.hpp"
+
+class CompoundContainer::ChildListener : public ContainerContentChangeListener
+{
+public:
+ ChildListener(CompoundContainer* owner, int offset)
+ : m_pOwner(owner), m_offset(offset)
+ {
+ }
+
+ void containerContentChanged(Container* container, StackID stackId) override
+ {
+ if (m_pOwner)
+ m_pOwner->setContainerChanged(stackId + m_offset);
+ }
+
+private:
+ CompoundContainer* m_pOwner;
+ int m_offset;
+};
+
+CompoundContainer::CompoundContainer(const std::string& name, Container* c1, Container* c2) :
+ m_name(name), m_pLeftContainer(c1), m_pRightContainer(c2), m_pLeftListener(nullptr), m_pRightListener(nullptr)
+{
+ m_pLeftListener = new ChildListener(this, 0);
+ m_pRightListener = new ChildListener(this, m_pLeftContainer->getContainerSize());
+
+ if (m_pLeftContainer)
+ m_pLeftContainer->addContentChangeListener(m_pLeftListener);
+ if (m_pRightContainer)
+ m_pRightContainer->addContentChangeListener(m_pRightListener);
+}
+
+CompoundContainer::~CompoundContainer()
+{
+ if (m_pLeftContainer && m_pLeftListener)
+ m_pLeftContainer->removeContentChangeListener(m_pLeftListener);
+ if (m_pRightContainer && m_pRightListener)
+ m_pRightContainer->removeContentChangeListener(m_pRightListener);
+
+ delete m_pLeftListener;
+ delete m_pRightListener;
+}
+
+uint16_t CompoundContainer::getContainerSize() const
+{
+ return uint16_t(m_pLeftContainer->getContainerSize() + m_pRightContainer->getContainerSize());
+}
+
+std::string CompoundContainer::getName() const
+{
+ return m_name;
+}
+
+ItemStack& CompoundContainer::getItem(StackID index)
+{
+ if (index >= m_pLeftContainer->getContainerSize())
+ return m_pRightContainer->getItem(index - m_pLeftContainer->getContainerSize());
+ else
+ return m_pLeftContainer->getItem(index);
+}
+
+ItemStack CompoundContainer::removeItem(StackID index, int count)
+{
+ if (index >= m_pLeftContainer->getContainerSize())
+ return m_pRightContainer->removeItem(index - m_pLeftContainer->getContainerSize(), count);
+ else
+ return m_pLeftContainer->removeItem(index, count);
+}
+
+void CompoundContainer::setItem(StackID index, const ItemStack& item)
+{
+ if (index >= m_pLeftContainer->getContainerSize())
+ m_pRightContainer->setItem(index - m_pLeftContainer->getContainerSize(), item);
+ else
+ m_pLeftContainer->setItem(index, item);
+}
+
+int CompoundContainer::getMaxStackSize()
+{
+ return m_pLeftContainer->getMaxStackSize();
+}
+
+void CompoundContainer::setContainerChanged(StackID stackId)
+{
+ for (ContentChangeListeners::iterator it = m_contentChangeListeners.begin(); it != m_contentChangeListeners.end(); ++it)
+ {
+ ContainerContentChangeListener* listener = *it;
+ listener->containerContentChanged(this, stackId);
+ }
+}
+
+bool CompoundContainer::stillValid(Player* player) const
+{
+ return m_pLeftContainer->stillValid(player) && m_pRightContainer->stillValid(player);
+}
+
+void CompoundContainer::addContentChangeListener(ContainerContentChangeListener* listener)
+{
+ m_contentChangeListeners.insert(listener);
+}
+
+void CompoundContainer::removeContentChangeListener(ContainerContentChangeListener* listener)
+{
+ m_contentChangeListeners.erase(listener);
+}
+
diff --git a/source/world/inventory/CompoundContainer.hpp b/source/world/inventory/CompoundContainer.hpp
new file mode 100644
index 000000000..556fde4d2
--- /dev/null
+++ b/source/world/inventory/CompoundContainer.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include
+#include
+#include "Container.hpp"
+#include "ContainerContentChangeListener.hpp"
+
+class CompoundContainer : public Container
+{
+private:
+ class ChildListener;
+
+public:
+ CompoundContainer(const std::string& name, Container* c1, Container* c2);
+ ~CompoundContainer() override;
+
+public:
+ uint16_t getContainerSize() const override;
+ std::string getName() const override;
+ ItemStack& getItem(StackID index) override;
+ ItemStack removeItem(StackID index, int count) override;
+ void setItem(StackID index, const ItemStack& item) override;
+ int getMaxStackSize() override;
+ void setContainerChanged(StackID stackId) override;
+ bool stillValid(Player* player) const override;
+
+ void addContentChangeListener(ContainerContentChangeListener* listener) override;
+ void removeContentChangeListener(ContainerContentChangeListener* listener) override;
+
+private:
+ std::string m_name;
+ Container* m_pLeftContainer;
+ Container* m_pRightContainer;
+ ContentChangeListeners m_contentChangeListeners;
+ ChildListener* m_pLeftListener;
+ ChildListener* m_pRightListener;
+};
diff --git a/source/world/inventory/Container.hpp b/source/world/inventory/Container.hpp
new file mode 100644
index 000000000..77ac4480f
--- /dev/null
+++ b/source/world/inventory/Container.hpp
@@ -0,0 +1,60 @@
+#pragma once
+
+#include
+
+#include "world/item/ItemStack.hpp"
+
+#define C_MAX_CONTAINER_STACK_SIZE (64)
+
+class ContainerContentChangeListener;
+class ContainerSizeChangeListener;
+
+class Container
+{
+protected:
+ typedef std::set ContentChangeListeners;
+ typedef std::set SizeChangeListeners;
+
+public:
+ typedef uint16_t Size;
+ typedef int16_t SlotID;
+ typedef uint16_t StackID;
+
+public:
+ enum Type
+ {
+ CONTAINER,
+ CRAFTING,
+ FURNACE,
+ DISPENSER
+ };
+
+public:
+ virtual ~Container() {}
+
+public:
+ virtual Size getContainerSize() const = 0;
+ virtual ItemStack& getItem(StackID stackId) = 0;
+ virtual ItemStack* tryGetItem(StackID stackId)
+ {
+ if (stackId >= 0 && stackId < getContainerSize())
+ return &getItem(stackId);
+ else
+ return nullptr;
+ }
+ virtual ItemStack removeItem(StackID stackId, int count) = 0;
+ virtual void setItem(StackID stackId, const ItemStack& item) = 0;
+ virtual std::string getName() const = 0;
+ virtual int getMaxStackSize()
+ {
+ return C_MAX_CONTAINER_STACK_SIZE;
+ }
+ // Was called setChanged in Java
+ virtual void setContainerChanged(StackID stackId) = 0;
+ virtual bool stillValid(Player* player) const = 0;
+
+ virtual void addContentChangeListener(ContainerContentChangeListener* listener) {}
+ virtual void addSizeChangeListener(ContainerSizeChangeListener* listener) {}
+ virtual void removeContentChangeListener(ContainerContentChangeListener* listener) {}
+ virtual void removeSizeChangeListener(ContainerSizeChangeListener* listener) {}
+};
diff --git a/source/world/inventory/ContainerContentChangeListener.cpp b/source/world/inventory/ContainerContentChangeListener.cpp
new file mode 100644
index 000000000..bb72498aa
--- /dev/null
+++ b/source/world/inventory/ContainerContentChangeListener.cpp
@@ -0,0 +1,2 @@
+#include "ContainerContentChangeListener.hpp"
+
diff --git a/source/world/inventory/ContainerContentChangeListener.hpp b/source/world/inventory/ContainerContentChangeListener.hpp
new file mode 100644
index 000000000..80266d0fd
--- /dev/null
+++ b/source/world/inventory/ContainerContentChangeListener.hpp
@@ -0,0 +1,12 @@
+#pragma once
+#include
+#include "Container.hpp"
+
+class ContainerContentChangeListener
+{
+public:
+ virtual ~ContainerContentChangeListener() {}
+
+public:
+ virtual void containerContentChanged(Container* container, Container::StackID stackId) = 0;
+};
diff --git a/source/world/ContainerListener.cpp b/source/world/inventory/ContainerListener.cpp
similarity index 81%
rename from source/world/ContainerListener.cpp
rename to source/world/inventory/ContainerListener.cpp
index ddfc041fa..d0377bd7c 100644
--- a/source/world/ContainerListener.cpp
+++ b/source/world/inventory/ContainerListener.cpp
@@ -7,5 +7,5 @@ ContainerListener::~ContainerListener()
void ContainerListener::refreshContainerItems(ContainerMenu* menu)
{
- refreshContainer(menu, menu->copyItems());
+ refreshContainer(menu, menu->cloneItems());
}
diff --git a/source/world/ContainerListener.hpp b/source/world/inventory/ContainerListener.hpp
similarity index 69%
rename from source/world/ContainerListener.hpp
rename to source/world/inventory/ContainerListener.hpp
index a159ae5db..a1b4b34cc 100644
--- a/source/world/ContainerListener.hpp
+++ b/source/world/inventory/ContainerListener.hpp
@@ -1,9 +1,11 @@
#pragma once
#include
+#include "Container.hpp"
class ContainerMenu;
class ItemStack;
+class Slot;
class ContainerListener
{
@@ -12,6 +14,6 @@ class ContainerListener
virtual void refreshContainer(ContainerMenu* menu, const std::vector& items) {}
virtual void refreshContainerItems(ContainerMenu* menu);
- virtual void slotChanged(ContainerMenu* menu, int index, ItemStack& item, bool isResultSlot) {}
+ virtual void slotChanged(ContainerMenu* menu, Container::SlotID slotId, Slot* slot, ItemStack& item, bool isResultSlot) {}
virtual void setContainerData(ContainerMenu* menu, int id, int value) {}
};
\ No newline at end of file
diff --git a/source/world/inventory/ContainerMenu.cpp b/source/world/inventory/ContainerMenu.cpp
index bf97f4140..b2c083130 100644
--- a/source/world/inventory/ContainerMenu.cpp
+++ b/source/world/inventory/ContainerMenu.cpp
@@ -1,14 +1,15 @@
#include "ContainerMenu.hpp"
-#include "Slot.hpp"
#include "world/item/ItemStack.hpp"
#include "world/item/Inventory.hpp"
-#include "world/Container.hpp"
-#include "world/ContainerListener.hpp"
+#include "Slot.hpp"
+#include "Container.hpp"
+#include "ContainerListener.hpp"
ContainerMenu::ContainerMenu(Container::Type containerType)
: m_changeUid(0)
, m_containerId(0)
, m_containerType(containerType)
+ , m_bBroadcastChanges(true)
{
}
@@ -18,20 +19,41 @@ ContainerMenu::~ContainerMenu()
/*for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
delete (*it);*/
+ _clearSlots();
+}
+
+void ContainerMenu::_clearSlots()
+{
for (std::vector::iterator it = m_slots.begin(); it != m_slots.end(); ++it)
- delete (*it);
+ {
+ Slot* slot = *it;
+
+ // @HACK: I don't like this
+ Container* pContainer = slot->m_pContainer;
+ if (pContainer)
+ pContainer->removeContentChangeListener(this);
+
+ delete slot;
+ }
+
+ m_slots.clear();
}
void ContainerMenu::addSlot(Slot* slot)
{
- slot->m_index = m_slots.size();
+ slot->m_id = m_slots.size();
m_slots.push_back(slot);
m_lastSlots.push_back(ItemStack::EMPTY);
+
+ // @HACK: holy hack
+ Container* pContainer = slot->m_pContainer;
+ if (pContainer)
+ pContainer->addContentChangeListener(this);
}
void ContainerMenu::addSlotListener(ContainerListener* listener)
{
- m_listeners.push_back(listener);
+ m_listeners.insert(listener);
// @PARITY: Not done on PE
/*std::vector snapshot = copyItems();
@@ -41,21 +63,26 @@ void ContainerMenu::addSlotListener(ContainerListener* listener)
void ContainerMenu::sendData(int id, int value)
{
- for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
+ for (ContainerListeners::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
(*it)->setContainerData(this, id, value);
}
+void ContainerMenu::broadcastChanges(Container::SlotID slotId)
+{
+ ItemStack& current = m_slots[slotId]->getItem();
+ if (m_lastSlots[slotId] != current)
+ {
+ m_lastSlots[slotId] = ItemStack(current);
+ for (ContainerListeners::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
+ (*it)->slotChanged(this, slotId, m_slots[slotId], m_lastSlots[slotId], isResultSlot());
+ }
+}
+
void ContainerMenu::broadcastChanges()
{
for (size_t i = 0; i < m_slots.size(); ++i)
{
- ItemStack& current = m_slots[i]->getItem();
- if (m_lastSlots[i] != current)
- {
- m_lastSlots[i] = ItemStack(current);
- for (std::vector::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
- (*it)->slotChanged(this, i, m_lastSlots[i], isResultSlot());
- }
+ broadcastChanges(i);
}
}
@@ -74,48 +101,72 @@ void ContainerMenu::slotsChanged(Container*)
broadcastChanges();
}
-std::vector ContainerMenu::copyItems()
+void ContainerMenu::containerContentChanged(Container* container, Container::StackID stackId)
+{
+ // stackId is an index of an ItemStack within a specific container, but m_slots contains
+ // slots from multiple containers. We need to find which slot in m_slots corresponds
+ // to this container slot by matching both the container and the slot index.
+ for (size_t i = 0; i < m_slots.size(); ++i)
+ {
+ Slot* slot = m_slots[i];
+ if (slot->m_pContainer == container && slot->m_stackId == stackId)
+ {
+ if (m_bBroadcastChanges)
+ broadcastChanges(i);
+ return;
+ }
+ }
+}
+
+std::vector ContainerMenu::cloneItems()
{
std::vector content;
for (std::vector::iterator it = m_slots.begin(); it != m_slots.end(); ++it)
- content.push_back((*it)->getItem());
+ {
+ Slot* slot = *it;
+#ifndef FEATURE_SERVER_INVENTORIES
+ // @TODO: I really do not like this.
+ // Firstly, inventories shouldn't be owned by the client
+ // Secondly, we shouldn't be checking types directly like this
+ // Ultimately this HAS to have two different storages, one for the inventory and one for the container
+ if (slot->m_group == Slot::INVENTORY || slot->m_group == Slot::HOTBAR)
+ continue;
+#endif
+ const ItemStack& item = (*it)->getItem();
+ content.push_back(item);
+ }
return content;
}
-Slot* ContainerMenu::getSlotFor(Container* container, int index)
+Slot* ContainerMenu::getSlotFor(Container* container, Container::StackID stackId)
{
for (std::vector::iterator it = m_slots.begin(); it != m_slots.end(); ++it)
{
Slot* slot = *it;
- if (slot->isAt(container, index))
+ if (slot->isAt(container, stackId))
return slot;
}
return nullptr;
}
-Slot* ContainerMenu::getSlot(int index)
+ItemStack ContainerMenu::quickMoveStack(Container::SlotID slotId)
{
- return m_slots[index];
+ return slotId >= 0 && slotId < int(m_slots.size()) ? getSlot(slotId)->getItem() : ItemStack::EMPTY;
}
-ItemStack ContainerMenu::quickMoveStack(int index)
+void ContainerMenu::moveItemStackTo(ItemStack& item, Container::SlotID slotFrom, Container::SlotID slotTo, bool take)
{
- return index >= 0 && index < int(m_slots.size()) ? getSlot(index)->getItem() : ItemStack::EMPTY;
-}
-
-void ContainerMenu::moveItemStackTo(ItemStack& item, int slotFrom, int slotTo, bool take)
-{
- int index = slotFrom;
+ Container::SlotID slotId = slotFrom;
if (take)
- index = slotTo - 1;
+ slotId = slotTo - 1;
if (item.isStackable())
{
- while (item.m_count > 0 && ((!take && index < slotTo) || (take && index >= slotFrom)))
+ while (item.m_count > 0 && ((!take && slotId < slotTo) || (take && slotId >= slotFrom)))
{
- Slot* slot = getSlot(index);
+ Slot* slot = getSlot(slotId);
ItemStack& slotItem = slot->getItem();
if (slotItem && slotItem.getId() == item.getId() && (!item.isStackedByData() || item.getAuxValue() == slotItem.getAuxValue()))
{
@@ -135,22 +186,22 @@ void ContainerMenu::moveItemStackTo(ItemStack& item, int slotFrom, int slotTo, b
}
if (take)
- --index;
+ --slotId;
else
- ++index;
+ ++slotId;
}
}
if (item.m_count > 0)
{
if (take)
- index = slotTo - 1;
+ slotId = slotTo - 1;
else
- index = slotFrom;
+ slotId = slotFrom;
- while ((!take && index < slotTo) || (take && index >= slotFrom))
+ while ((!take && slotId < slotTo) || (take && slotId >= slotFrom))
{
- Slot* slot = getSlot(index);
+ Slot* slot = getSlot(slotId);
ItemStack& slotItem = slot->getItem();
if (!slotItem)
{
@@ -161,14 +212,14 @@ void ContainerMenu::moveItemStackTo(ItemStack& item, int slotFrom, int slotTo, b
}
if (take)
- --index;
+ --slotId;
else
- ++index;
+ ++slotId;
}
}
}
-ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, bool quickMove, Player* player)
+ItemStack ContainerMenu::clicked(Container::SlotID slotId, MouseButtonType mouseButton, bool quickMove, Player* player)
{
ItemStack result = ItemStack::EMPTY;
@@ -177,7 +228,7 @@ ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, boo
Inventory* inv = player->m_pInventory;
- if (slotIndex == -999)
+ if (slotId == -999)
{
if (!inv->getCarried().isEmpty())
{
@@ -201,24 +252,22 @@ ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, boo
{
if (quickMove)
{
- ItemStack quickMoved = quickMoveStack(slotIndex);
+ ItemStack quickMoved = quickMoveStack(slotId);
if (!quickMoved.isEmpty())
{
result = quickMoved;
- Slot* slot = getSlot(slotIndex);
+ Slot* slot = getSlot(slotId);
if (slot && slot->hasItem() && slot->getItem().m_count < quickMoved.m_count)
- clicked(slotIndex, mouseButton, quickMove, player);
+ clicked(slotId, mouseButton, quickMove, player);
}
return result;
}
- Slot* slot = getSlot(slotIndex);
+ Slot* slot = getSlot(slotId);
if (!slot)
return result;
- slot->setChanged();
-
ItemStack& slotItem = slot->getItem();
if (!slotItem.isEmpty())
@@ -259,6 +308,7 @@ ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, boo
if (carried.m_count <= slot->getMaxStackSize())
{
std::swap(carried, slotItem);
+ slot->setChanged();
}
}
else if (slotItem.getId() == carried.getId())
@@ -279,6 +329,7 @@ ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, boo
inv->setCarried(ItemStack::EMPTY);
slotItem.m_count += count;
+ slot->setChanged();
break;
}
case MOUSE_BUTTON_RIGHT:
@@ -295,6 +346,7 @@ ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, boo
inv->setCarried(ItemStack::EMPTY);
slotItem.m_count += count;
+ slot->setChanged();
break;
}
default:
@@ -325,41 +377,54 @@ ItemStack ContainerMenu::clicked(int slotIndex, MouseButtonType mouseButton, boo
return result;
}
-void ContainerMenu::setItem(int index, ItemStack item)
+void ContainerMenu::setItem(Container::SlotID slotId, ItemStack item)
{
- m_slots[index]->set(item);
+ m_slots[slotId]->set(item);
+ if (!m_bBroadcastChanges && slotId >= 0 && slotId < (int)m_lastSlots.size())
+ {
+ m_lastSlots[slotId] = ItemStack(m_slots[slotId]->getItem());
+ }
}
void ContainerMenu::setAll(const std::vector& items)
{
- for (size_t i = 0; i < items.size(); ++i)
+ size_t n = std::min(items.size(), m_slots.size());
+ for (size_t i = 0; i < n; ++i)
{
m_slots[i]->set(items[i]);
+ if (!m_bBroadcastChanges)
+ {
+ m_lastSlots[i] = ItemStack(m_slots[i]->getItem());
+ }
}
}
-void ContainerMenu::setData(int id, int value) {
+void ContainerMenu::setData(int id, int value)
+{
}
-uint16_t ContainerMenu::backup(Inventory*) {
+uint16_t ContainerMenu::backup(Inventory*)
+{
return ++m_changeUid;
}
-void ContainerMenu::deleteBackup(uint16_t) {
+void ContainerMenu::deleteBackup(uint16_t)
+{
}
-void ContainerMenu::rollbackToBackup(uint16_t) {
+void ContainerMenu::rollbackToBackup(uint16_t)
+{
}
bool ContainerMenu::isSynched(Player* player) const
{
- return unsynchedPlayers.find(player) == unsynchedPlayers.end();
+ return m_unsynchedPlayers.find(player) == m_unsynchedPlayers.end();
}
void ContainerMenu::setSynched(Player* player, bool isSynched)
{
if (isSynched)
- unsynchedPlayers.erase(player);
+ m_unsynchedPlayers.erase(player);
else
- unsynchedPlayers.insert(player);
+ m_unsynchedPlayers.insert(player);
}
diff --git a/source/world/inventory/ContainerMenu.hpp b/source/world/inventory/ContainerMenu.hpp
index f7b299806..ca1a115fc 100644
--- a/source/world/inventory/ContainerMenu.hpp
+++ b/source/world/inventory/ContainerMenu.hpp
@@ -3,37 +3,45 @@
#include
#include
#include "world/item/ItemStack.hpp"
-#include "world/Container.hpp"
#include "client/player/input/MouseDevice.hpp"
+#include "Container.hpp"
+#include "ContainerContentChangeListener.hpp"
class Player;
class Inventory;
class Slot;
class ContainerListener;
-class ContainerMenu
+class ContainerMenu : public ContainerContentChangeListener
{
+protected:
+ typedef std::set ContainerListeners;
+
public:
ContainerMenu(Container::Type containerType);
virtual ~ContainerMenu();
+protected:
+ void _clearSlots();
+
public:
void addSlot(Slot* slot);
virtual void addSlotListener(ContainerListener* listener);
void sendData(int id, int value);
+ virtual void broadcastChanges(Container::SlotID slotId);
virtual void broadcastChanges();
virtual void removed(Player* player);
virtual void slotsChanged(Container* container);
// Called getItems in PE and Java
- std::vector copyItems();
- Slot* getSlotFor(Container* container, int index);
- Slot* getSlot(int index);
- virtual ItemStack clicked(int slotIndex, MouseButtonType mouseButton, bool quickMove, Player* player);
- virtual ItemStack quickMoveStack(int index);
- virtual void moveItemStackTo(ItemStack& item, int slotFrom, int slotTo, bool take);
-
- void setItem(int slotIndex, ItemStack item);
+ std::vector cloneItems();
+ Slot* getSlotFor(Container* container, Container::StackID stackId);
+ Slot* getSlot(Container::SlotID slotId) { return m_slots[slotId]; }
+ virtual ItemStack clicked(Container::SlotID slotId, MouseButtonType mouseButton, bool quickMove, Player* player);
+ virtual ItemStack quickMoveStack(Container::SlotID slotId);
+ virtual void moveItemStackTo(ItemStack& item, Container::SlotID slotFrom, Container::SlotID slotTo, bool take);
+
+ void setItem(Container::SlotID slotId, ItemStack item);
void setAll(const std::vector& items);
virtual void setData(int id, int value);
@@ -50,14 +58,18 @@ class ContainerMenu
//Unused
virtual bool isPauseScreen() const { return false; }
+public:
+ void containerContentChanged(Container* container, Container::StackID stackId) override;
+
protected:
std::vector m_lastSlots;
uint16_t m_changeUid;
- std::vector m_listeners;
- std::set unsynchedPlayers;
+ ContainerListeners m_listeners;
+ std::set m_unsynchedPlayers;
public:
int m_containerId;
Container::Type m_containerType;
std::vector m_slots;
+ bool m_bBroadcastChanges;
};
diff --git a/source/world/inventory/ContainerSizeChangeListener.cpp b/source/world/inventory/ContainerSizeChangeListener.cpp
new file mode 100644
index 000000000..671ca58bd
--- /dev/null
+++ b/source/world/inventory/ContainerSizeChangeListener.cpp
@@ -0,0 +1 @@
+#include "ContainerSizeChangeListener.hpp"
diff --git a/source/world/inventory/ContainerSizeChangeListener.hpp b/source/world/inventory/ContainerSizeChangeListener.hpp
new file mode 100644
index 000000000..f39a00780
--- /dev/null
+++ b/source/world/inventory/ContainerSizeChangeListener.hpp
@@ -0,0 +1,12 @@
+#pragma once
+#include
+#include "Container.hpp"
+
+class ContainerSizeChangeListener
+{
+public:
+ virtual ~ContainerSizeChangeListener() {}
+
+public:
+ virtual void containerSizeChanged(Container::Size size) = 0;
+};
diff --git a/source/world/inventory/CraftingContainer.cpp b/source/world/inventory/CraftingContainer.cpp
index 548c6db7b..3e36eb922 100644
--- a/source/world/inventory/CraftingContainer.cpp
+++ b/source/world/inventory/CraftingContainer.cpp
@@ -1,9 +1,9 @@
#include "CraftingContainer.hpp"
-CraftingContainer::CraftingContainer(ContainerMenu* menu, int width, int height) :
- m_items(width * height),
- m_pMenu(menu),
- m_width(width)
+CraftingContainer::CraftingContainer(ContainerMenu* menu, int width, int height)
+ : m_items(width * height)
+ , m_pMenu(menu)
+ , m_width(width)
{
}
@@ -16,9 +16,9 @@ uint16_t CraftingContainer::getContainerSize() const
return uint16_t(m_items.size());
}
-ItemStack& CraftingContainer::getItem(int index)
+ItemStack& CraftingContainer::getItem(StackID stackId)
{
- return m_items[index];
+ return m_items[stackId];
}
const ItemStack& CraftingContainer::getItem(int x, int y)
@@ -36,11 +36,11 @@ std::string CraftingContainer::getName() const
return "Crafting";
}
-ItemStack CraftingContainer::removeItem(int index, int count)
+ItemStack CraftingContainer::removeItem(StackID stackId, int count)
{
- if (index < 0 || index >= getContainerSize()) return ItemStack::EMPTY;
+ if (stackId < 0 || stackId >= getContainerSize()) return ItemStack::EMPTY;
- ItemStack& item = m_items[index];
+ ItemStack& item = m_items[stackId];
if (item)
{
ItemStack removed;
@@ -48,13 +48,13 @@ ItemStack CraftingContainer::removeItem(int index, int count)
if (item.m_count <= count)
{
removed = item;
- m_items[index] = ItemStack::EMPTY;
+ m_items[stackId] = ItemStack::EMPTY;
}
else
{
removed = item.remove(count);
if (item.m_count == 0)
- m_items[index] = ItemStack::EMPTY;
+ m_items[stackId] = ItemStack::EMPTY;
}
m_pMenu->slotsChanged(this);
@@ -64,16 +64,16 @@ ItemStack CraftingContainer::removeItem(int index, int count)
return ItemStack::EMPTY;
}
-void CraftingContainer::setItem(int index, const ItemStack& item)
+void CraftingContainer::setItem(StackID stackId, const ItemStack& item)
{
- if (index >= 0 && index < getContainerSize())
+ if (stackId >= 0 && stackId < getContainerSize())
{
- m_items[index] = item;
+ m_items[stackId] = item;
m_pMenu->slotsChanged(this);
}
}
-void CraftingContainer::setChanged()
+void CraftingContainer::setContainerChanged(StackID stackId)
{
}
diff --git a/source/world/inventory/CraftingContainer.hpp b/source/world/inventory/CraftingContainer.hpp
index 5fecc7d91..ea8c16a4e 100644
--- a/source/world/inventory/CraftingContainer.hpp
+++ b/source/world/inventory/CraftingContainer.hpp
@@ -1,8 +1,8 @@
#pragma once
#include
-#include "world/Container.hpp"
#include "world/item/ItemStack.hpp"
+#include "Container.hpp"
#include "ContainerMenu.hpp"
class ContainerMenu;
@@ -17,15 +17,15 @@ class CraftingContainer : public Container
virtual ~CraftingContainer();
uint16_t getContainerSize() const override;
- ItemStack& getItem(int index) override;
+ ItemStack& getItem(StackID stackId) override;
const ItemStack& getItem(int x, int y);
std::string getName() const override;
- ItemStack removeItem(int index, int amount) override;
- void setItem(int index, const ItemStack& item) override;
+ ItemStack removeItem(StackID stackId, int amount) override;
+ void setItem(StackID stackId, const ItemStack& item) override;
- void setChanged() override;
+ void setContainerChanged(StackID stackId) override;
bool stillValid(Player* player) const override;
private:
diff --git a/source/world/inventory/CraftingMenu.cpp b/source/world/inventory/CraftingMenu.cpp
index aeb9d016b..cdf3ed95f 100644
--- a/source/world/inventory/CraftingMenu.cpp
+++ b/source/world/inventory/CraftingMenu.cpp
@@ -36,6 +36,9 @@ CraftingMenu::CraftingMenu(Inventory* inventory, const TilePos& tilePos, Level*
CraftingMenu::~CraftingMenu()
{
+ _clearSlots();
+
+ // clearSlots must be called before these are deleted
delete m_pCraftSlots;
delete m_pResultSlots;
}
@@ -67,19 +70,19 @@ bool CraftingMenu::stillValid(Player* player) const
return !(player->distanceToSqr(Vec3(m_pos.x + 0.5f, m_pos.y + 0.5f, m_pos.z + 0.5f)) > 64.0f);
}
-ItemStack CraftingMenu::quickMoveStack(int index)
+ItemStack CraftingMenu::quickMoveStack(Container::SlotID slotId)
{
ItemStack item = ItemStack::EMPTY;
- Slot* slot = getSlot(index);
+ Slot* slot = getSlot(slotId);
if (slot && slot->hasItem())
{
ItemStack& slotItem = slot->getItem();
item = slotItem;
- if (index == 0)
+ if (slotId == 0)
moveItemStackTo(slotItem, 10, 46, true);
- else if (index >= 10 && index < 37)
+ else if (slotId >= 10 && slotId < 37)
moveItemStackTo(slotItem, 37, 46, false);
- else if (index >= 37 && index < 46)
+ else if (slotId >= 37 && slotId < 46)
moveItemStackTo(slotItem, 10, 37, false);
else
moveItemStackTo(slotItem, 10, 46, false);
diff --git a/source/world/inventory/CraftingMenu.hpp b/source/world/inventory/CraftingMenu.hpp
index fc8e9bd83..ba0531d3a 100644
--- a/source/world/inventory/CraftingMenu.hpp
+++ b/source/world/inventory/CraftingMenu.hpp
@@ -13,7 +13,7 @@ class CraftingMenu : public ContainerMenu
void slotsChanged(Container* container) override;
void removed(Player* player) override;
bool stillValid(Player* player) const override;
- ItemStack quickMoveStack(int index) override;
+ ItemStack quickMoveStack(Container::SlotID slotId) override;
private:
const TilePos m_pos;
diff --git a/source/world/inventory/FurnaceMenu.cpp b/source/world/inventory/FurnaceMenu.cpp
new file mode 100644
index 000000000..2b5fd2e27
--- /dev/null
+++ b/source/world/inventory/FurnaceMenu.cpp
@@ -0,0 +1,107 @@
+#include "FurnaceMenu.hpp"
+#include "Slot.hpp"
+#include "FurnaceResultSlot.hpp"
+#include "ContainerListener.hpp"
+
+FurnaceMenu::FurnaceMenu(Inventory* inventory, FurnaceTileEntity* furnace)
+ : ContainerMenu(Container::FURNACE), m_furnace(furnace), m_lastCookTime(0), m_lastBurnTime(0), m_lastLitDuration(0)
+{
+ addSlot(new Slot(m_furnace, 0, Slot::INPUT));
+ addSlot(new Slot(m_furnace, 1, Slot::INPUT));
+ addSlot(new FurnaceResultSlot(inventory->m_pPlayer, m_furnace, 2));
+
+ for (int y = 0; y < 3; ++y)
+ {
+ for (int x = 0; x < 9; ++x)
+ addSlot(new Slot(inventory, x + (y + 1) * 9, Slot::INVENTORY));
+ }
+
+ for (int i = 0; i < 9; ++i)
+ {
+ addSlot(new Slot(inventory, i, Slot::HOTBAR));
+ }
+}
+
+bool FurnaceMenu::stillValid(Player* player) const
+{
+ return m_furnace->stillValid(player);
+}
+
+void FurnaceMenu::addSlotListener(ContainerListener* listener)
+{
+ ContainerMenu::addSlotListener(listener);
+ listener->setContainerData(this, 0, m_furnace->m_tickCount);
+ listener->setContainerData(this, 1, m_furnace->m_litTime);
+ listener->setContainerData(this, 2, m_furnace->m_litDuration);
+}
+
+void FurnaceMenu::broadcastChanges()
+{
+ ContainerMenu::broadcastChanges();
+
+ for (ContainerListeners::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
+ {
+ ContainerListener* listener = *it;
+
+ if (m_lastCookTime != m_furnace->m_tickCount)
+ listener->setContainerData(this, 0, m_furnace->m_tickCount);
+
+ if (m_lastBurnTime != m_furnace->m_litTime)
+ listener->setContainerData(this, 1, m_furnace->m_litTime);
+
+ if (m_lastLitDuration != m_furnace->m_litDuration)
+ listener->setContainerData(this, 2, m_furnace->m_litDuration);
+ }
+
+ m_lastCookTime = m_furnace->m_tickCount;
+ m_lastBurnTime = m_furnace->m_litTime;
+ m_lastLitDuration = m_furnace->m_litDuration;
+}
+
+void FurnaceMenu::setData(int index, int value)
+{
+ switch (index)
+ {
+ case 0:
+ m_furnace->m_tickCount = value;
+ break;
+ case 1:
+ m_furnace->m_litTime = value;
+ break;
+ case 2:
+ m_furnace->m_litDuration = value;
+ break;
+ default: break;
+ }
+}
+
+ItemStack FurnaceMenu::quickMoveStack(Container::SlotID slotId)
+{
+ ItemStack item;
+ Slot* slot = getSlot(slotId);
+ if (slot && slot->hasItem())
+ {
+ ItemStack& slotItem = slot->getItem();
+ item = slotItem.copy();
+ if (slotId == 2)
+ moveItemStackTo(slotItem, 3, 39, true);
+ else if (slotId >= 3 && slotId < 30)
+ moveItemStackTo(slotItem, 30, 39, false);
+ else if (slotId >= 30 && slotId < 39)
+ moveItemStackTo(slotItem, 3, 30, false);
+ else
+ moveItemStackTo(slotItem, 3, 39, false);
+
+ if (slotItem.m_count == 0)
+ slot->set(ItemStack::EMPTY);
+ else
+ slot->setChanged();
+
+ if (slotItem.m_count == item.m_count)
+ return ItemStack::EMPTY;
+
+ slot->onTake(slotItem);
+ }
+
+ return item;
+}
diff --git a/source/world/inventory/FurnaceMenu.hpp b/source/world/inventory/FurnaceMenu.hpp
new file mode 100644
index 000000000..2a1dd1ba0
--- /dev/null
+++ b/source/world/inventory/FurnaceMenu.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "ContainerMenu.hpp"
+#include "world/entity/Player.hpp"
+#include "world/tile/entity/FurnaceTileEntity.hpp"
+
+class FurnaceMenu : public ContainerMenu
+{
+public:
+ FurnaceMenu(Inventory* inventory, FurnaceTileEntity* container);
+
+public:
+ bool stillValid(Player* player) const override;
+ void addSlotListener(ContainerListener* listener) override;
+ void broadcastChanges() override;
+ void setData(int, int) override;
+ ItemStack quickMoveStack(Container::SlotID slotId) override;
+
+private:
+ FurnaceTileEntity* m_furnace;
+ int m_lastCookTime;
+ int m_lastBurnTime;
+ int m_lastLitDuration;
+};
diff --git a/source/world/inventory/FurnaceResultSlot.cpp b/source/world/inventory/FurnaceResultSlot.cpp
new file mode 100644
index 000000000..84d628de0
--- /dev/null
+++ b/source/world/inventory/FurnaceResultSlot.cpp
@@ -0,0 +1,19 @@
+#include "FurnaceResultSlot.hpp"
+#include "../item/Item.hpp"
+#include "world/entity/Player.hpp"
+
+FurnaceResultSlot::FurnaceResultSlot(Player* player, Container* container, int slotIndex)
+ : Slot(container, slotIndex, OUTPUT), m_pPlayer(player)
+{
+}
+
+bool FurnaceResultSlot::mayPlace(const ItemStack&) const
+{
+ return false;
+}
+
+void FurnaceResultSlot::onTake(ItemStack& inst)
+{
+ inst.onCraftedBy(m_pPlayer, m_pPlayer->m_pLevel);
+ Slot::onTake(inst);
+}
diff --git a/source/world/inventory/FurnaceResultSlot.hpp b/source/world/inventory/FurnaceResultSlot.hpp
new file mode 100644
index 000000000..912b17000
--- /dev/null
+++ b/source/world/inventory/FurnaceResultSlot.hpp
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "Slot.hpp"
+#include "Container.hpp"
+
+class FurnaceResultSlot : public Slot
+{
+public:
+ FurnaceResultSlot(Player* player, Container* container, int slotIdx);
+
+ bool mayPlace(const ItemStack&) const override;
+ void onTake(ItemStack&) override;
+
+private:
+ Player* m_pPlayer;
+};
\ No newline at end of file
diff --git a/source/world/inventory/InventoryMenu.cpp b/source/world/inventory/InventoryMenu.cpp
index 6c5d2a76f..754b391c7 100644
--- a/source/world/inventory/InventoryMenu.cpp
+++ b/source/world/inventory/InventoryMenu.cpp
@@ -42,6 +42,9 @@ InventoryMenu::InventoryMenu(Inventory* inventory, bool active)
InventoryMenu::~InventoryMenu()
{
+ _clearSlots();
+
+ // clearSlots must be called before these are deleted
delete m_pCraftSlots;
delete m_pResultSlots;
}
@@ -70,19 +73,19 @@ bool InventoryMenu::stillValid(Player* player) const
return true;
}
-ItemStack InventoryMenu::quickMoveStack(int index)
+ItemStack InventoryMenu::quickMoveStack(Container::SlotID slotId)
{
ItemStack item = ItemStack::EMPTY;
- Slot* slot = getSlot(index);
+ Slot* slot = getSlot(slotId);
if (slot && slot->hasItem())
{
ItemStack& slotItem = slot->getItem();
item = slotItem;
- if (index == 0)
+ if (slotId == 0)
moveItemStackTo(slotItem, 9, 45, true);
- else if (index >= 9 && index < 36)
+ else if (slotId >= 9 && slotId < 36)
moveItemStackTo(slotItem, 36, 45, false);
- else if (index >= 36 && index < 45)
+ else if (slotId >= 36 && slotId < 45)
moveItemStackTo(slotItem, 9, 36, false);
else
moveItemStackTo(slotItem, 9, 45, false);
diff --git a/source/world/inventory/InventoryMenu.hpp b/source/world/inventory/InventoryMenu.hpp
index 683d02083..6c8a2df1c 100644
--- a/source/world/inventory/InventoryMenu.hpp
+++ b/source/world/inventory/InventoryMenu.hpp
@@ -13,7 +13,7 @@ class InventoryMenu : public ContainerMenu
void slotsChanged(Container* container) override;
void removed(Player* player) override;
bool stillValid(Player* player) const override;
- ItemStack quickMoveStack(int index) override;
+ ItemStack quickMoveStack(Container::SlotID slotId) override;
public:
CraftingContainer* m_pCraftSlots;
diff --git a/source/world/inventory/ResultContainer.cpp b/source/world/inventory/ResultContainer.cpp
index 3f6763d53..52a6caeb3 100644
--- a/source/world/inventory/ResultContainer.cpp
+++ b/source/world/inventory/ResultContainer.cpp
@@ -13,7 +13,7 @@ uint16_t ResultContainer::getContainerSize() const
return 1;
}
-ItemStack& ResultContainer::getItem(int index)
+ItemStack& ResultContainer::getItem(StackID stackId)
{
return m_item;
}
@@ -23,24 +23,23 @@ std::string ResultContainer::getName() const
return "";
}
-ItemStack ResultContainer::removeItem(int index, int)
+ItemStack ResultContainer::removeItem(StackID stackId, int)
{
- if (index == 0)
- {
- ItemStack result = m_item;
- m_item = ItemStack::EMPTY;
- return result;
- }
- return ItemStack::EMPTY;
+ if (stackId != 0)
+ return ItemStack::EMPTY;
+
+ ItemStack result = m_item;
+ m_item = ItemStack::EMPTY;
+ return result;
}
-void ResultContainer::setItem(int index, const ItemStack& item)
+void ResultContainer::setItem(StackID stackId, const ItemStack& item)
{
- if (index == 0)
+ if (stackId == 0)
m_item = item;
}
-void ResultContainer::setChanged()
+void ResultContainer::setContainerChanged(StackID stackId)
{
}
diff --git a/source/world/inventory/ResultContainer.hpp b/source/world/inventory/ResultContainer.hpp
index a3d95dc65..9ff3b9cab 100644
--- a/source/world/inventory/ResultContainer.hpp
+++ b/source/world/inventory/ResultContainer.hpp
@@ -1,7 +1,7 @@
#pragma once
-#include "world/Container.hpp"
#include "world/item/ItemStack.hpp"
+#include "Container.hpp"
class Player;
@@ -12,14 +12,14 @@ class ResultContainer : public Container
virtual ~ResultContainer();
uint16_t getContainerSize() const override;
- ItemStack& getItem(int index) override;
+ ItemStack& getItem(StackID stackId) override;
std::string getName() const override;
- ItemStack removeItem(int index, int amount) override;
- void setItem(int index, const ItemStack& item) override;
+ ItemStack removeItem(StackID stackId, int amount) override;
+ void setItem(StackID stackId, const ItemStack& item) override;
- void setChanged() override;
+ void setContainerChanged(StackID stackId) override;
bool stillValid(Player* player) const override;
private:
diff --git a/source/world/inventory/ResultSlot.hpp b/source/world/inventory/ResultSlot.hpp
index 92dd109e6..7da681e83 100644
--- a/source/world/inventory/ResultSlot.hpp
+++ b/source/world/inventory/ResultSlot.hpp
@@ -1,7 +1,7 @@
#pragma once
#include "Slot.hpp"
-#include "world/Container.hpp"
+#include "Container.hpp"
class ResultSlot : public Slot
{
diff --git a/source/world/inventory/SimpleContainer.cpp b/source/world/inventory/SimpleContainer.cpp
index 6799cd433..2b5c0f07b 100644
--- a/source/world/inventory/SimpleContainer.cpp
+++ b/source/world/inventory/SimpleContainer.cpp
@@ -1,22 +1,24 @@
#include "SimpleContainer.hpp"
+#include "ContainerContentChangeListener.hpp"
+#include "ContainerSizeChangeListener.hpp"
-SimpleContainer::SimpleContainer(int size, const std::string& name) :
- m_items(size),
- m_name(name)
+SimpleContainer::SimpleContainer(Size size, const std::string& name)
+ : m_items(size)
+ , m_name(name)
{
}
-uint16_t SimpleContainer::getContainerSize() const
+Container::Size SimpleContainer::getContainerSize() const
{
- return uint16_t(m_items.size());
+ return (Size)(m_items.size());
}
-ItemStack& SimpleContainer::getItem(int index)
+ItemStack& SimpleContainer::getItem(StackID index)
{
return m_items[index];
}
-ItemStack SimpleContainer::removeItem(int index, int count)
+ItemStack SimpleContainer::removeItem(StackID index, int count)
{
if (!m_items[index].isEmpty())
{
@@ -25,7 +27,7 @@ ItemStack SimpleContainer::removeItem(int index, int count)
{
result = m_items[index];
m_items[index] = ItemStack::EMPTY;
- setChanged();
+ setContainerChanged(index);
return result;
}
else
@@ -34,20 +36,20 @@ ItemStack SimpleContainer::removeItem(int index, int count)
if (!m_items[index].m_count)
m_items[index] = ItemStack::EMPTY;
- setChanged();
+ setContainerChanged(index);
return result;
}
}
return ItemStack::EMPTY;
}
-void SimpleContainer::setItem(int index, const ItemStack& item)
+void SimpleContainer::setItem(StackID index, const ItemStack& item)
{
m_items[index] = item;
if (!item.isEmpty() && item.m_count > getMaxStackSize())
m_items[index].m_count = getMaxStackSize();
- setChanged();
+ setContainerChanged(index);
}
std::string SimpleContainer::getName() const
@@ -55,8 +57,13 @@ std::string SimpleContainer::getName() const
return m_name;
}
-void SimpleContainer::setChanged()
+void SimpleContainer::setContainerChanged(StackID stackId)
{
+ for (ContentChangeListeners::iterator it = m_contentChangeListeners.begin(); it != m_contentChangeListeners.end(); it++)
+ {
+ ContainerContentChangeListener* pListener = *it;
+ pListener->containerContentChanged(this, stackId);
+ }
}
bool SimpleContainer::stillValid(Player* player) const
@@ -64,7 +71,32 @@ bool SimpleContainer::stillValid(Player* player) const
return true;
}
-void SimpleContainer::load(CompoundTag& tag)
+void SimpleContainer::addContentChangeListener(ContainerContentChangeListener* listener)
+{
+ m_contentChangeListeners.insert(listener);
+}
+
+void SimpleContainer::addSizeChangeListener(ContainerSizeChangeListener* listener)
+{
+ m_sizeChangeListeners.insert(listener);
+}
+
+void SimpleContainer::removeContentChangeListener(ContainerContentChangeListener* listener)
+{
+ m_contentChangeListeners.erase(listener);
+}
+
+void SimpleContainer::removeSizeChangeListener(ContainerSizeChangeListener* listener)
+{
+ m_sizeChangeListeners.erase(listener);
+}
+
+void SimpleContainer::clear()
+{
+ std::fill(m_items.begin(), m_items.end(), ItemStack::EMPTY);
+}
+
+void SimpleContainer::load(const CompoundTag& tag)
{
clear();
const ListTag* list = tag.getList("Items");
@@ -78,14 +110,14 @@ void SimpleContainer::load(CompoundTag& tag)
{
uint8_t slot = itemTag->getInt8("Slot") & 255;
ItemStack item = ItemStack::fromTag(*itemTag);
- if (itemTag->isEmpty() && slot >= 0 && slot < m_items.size())
+ if (!itemTag->isEmpty() && slot >= 0 && slot < m_items.size())
m_items[slot] = item;
}
}
}
-void SimpleContainer::save(CompoundTag& tag)
+void SimpleContainer::save(CompoundTag& tag) const
{
ListTag* list = new ListTag;
@@ -102,8 +134,3 @@ void SimpleContainer::save(CompoundTag& tag)
tag.put("Items", list);
}
-
-void SimpleContainer::clear()
-{
- std::fill(m_items.begin(), m_items.end(), ItemStack::EMPTY);
-}
\ No newline at end of file
diff --git a/source/world/inventory/SimpleContainer.hpp b/source/world/inventory/SimpleContainer.hpp
index 2e676e564..cf11cb4ef 100644
--- a/source/world/inventory/SimpleContainer.hpp
+++ b/source/world/inventory/SimpleContainer.hpp
@@ -1,36 +1,36 @@
#pragma once
-#include "world/Container.hpp"
-#include "nbt/CompoundTag.hpp"
#include
+#include "Container.hpp"
+#include "nbt/CompoundTag.hpp"
+
class SimpleContainer : public Container
{
public:
- SimpleContainer(int size, const std::string& name);
-
- virtual uint16_t getContainerSize() const override;
-
- virtual ItemStack& getItem(int index) override;
-
- virtual ItemStack removeItem(int index, int count) override;
-
- virtual void setItem(int index, const ItemStack& item) override;
+ SimpleContainer(Size size, const std::string& name);
- virtual std::string getName() const override;
-
- virtual void setChanged() override;
-
- virtual bool stillValid(Player* player) const override;
+public:
+ Size getContainerSize() const override;
+ ItemStack& getItem(StackID index) override;
+ ItemStack removeItem(StackID index, int count) override;
+ void setItem(StackID index, const ItemStack& item) override;
+ std::string getName() const override;
+ void setContainerChanged(StackID stackId) override;
+ bool stillValid(Player* player) const override;
+ void addContentChangeListener(ContainerContentChangeListener* listener) override;
+ void addSizeChangeListener(ContainerSizeChangeListener* listener) override;
+ void removeContentChangeListener(ContainerContentChangeListener* listener) override;
+ void removeSizeChangeListener(ContainerSizeChangeListener* listener) override;
+public:
virtual void clear();
+ virtual void load(const CompoundTag& tag);
+ virtual void save(CompoundTag& tag) const;
- virtual void load(CompoundTag& tag);
- virtual void save(CompoundTag& tag);
-
-private:
+protected:
+ ContentChangeListeners m_contentChangeListeners;
+ SizeChangeListeners m_sizeChangeListeners;
std::vector m_items;
std::string m_name;
-};
-
-
+};
\ No newline at end of file
diff --git a/source/world/inventory/Slot.cpp b/source/world/inventory/Slot.cpp
index 81beb469a..26d435595 100644
--- a/source/world/inventory/Slot.cpp
+++ b/source/world/inventory/Slot.cpp
@@ -1,9 +1,9 @@
#include "Slot.hpp"
-Slot::Slot(Container* container, int slot, Group group) :
- m_pContainer(container),
- m_slot(slot),
- m_group(group)
+Slot::Slot(Container* container, Container::StackID stackId, Group group)
+ : m_pContainer(container)
+ , m_stackId(stackId)
+ , m_group(group)
{
}
@@ -18,6 +18,6 @@ bool Slot::canSync() const
void Slot::set(const ItemStack& item)
{
- m_pContainer->setItem(m_slot, item);
+ m_pContainer->setItem(m_stackId, item);
setChanged();
}
diff --git a/source/world/inventory/Slot.hpp b/source/world/inventory/Slot.hpp
index 12a033823..55ef1ae39 100644
--- a/source/world/inventory/Slot.hpp
+++ b/source/world/inventory/Slot.hpp
@@ -1,6 +1,8 @@
#pragma once
-#include "world/Container.hpp"
+#include
+
+#include "Container.hpp"
class ItemStack;
@@ -17,7 +19,7 @@ class Slot
ARMOR
};
- Slot(Container* container, int slot, Group group = CONTAINER);
+ Slot(Container* container, Container::StackID stackId, Group group = CONTAINER);
virtual ~Slot();
virtual bool canSync() const;
@@ -26,23 +28,23 @@ class Slot
virtual bool mayPlace(const ItemStack& item) const { return true; }
- virtual ItemStack& getItem() { return m_pContainer->getItem(m_slot); }
+ virtual ItemStack& getItem() { return m_pContainer->getItem(m_stackId); }
virtual bool hasItem() { return !getItem().isEmpty(); }
virtual void set(const ItemStack& item);
- virtual void setChanged() { m_pContainer->setChanged(); }
+ virtual void setChanged() { m_pContainer->setContainerChanged(m_stackId); }
virtual int getMaxStackSize() const { return m_pContainer->getMaxStackSize(); }
- virtual ItemStack remove(int count) { return m_pContainer->removeItem(m_slot, count); }
+ virtual ItemStack remove(int count) { return m_pContainer->removeItem(m_stackId, count); }
- virtual bool isAt(Container* cont, int s) { return cont == m_pContainer && s == m_slot; }
+ virtual bool isAt(Container* cont, Container::StackID stackId) { return cont == m_pContainer && stackId == m_stackId; }
public:
Container* m_pContainer;
- int m_slot;
- int m_index;
+ Container::SlotID m_id; // the position in the ContainerMenu::m_slots vector
+ Container::StackID m_stackId; // the position in the Container::m_items vector
Group m_group;
};
\ No newline at end of file
diff --git a/source/world/item/BowItem.cpp b/source/world/item/BowItem.cpp
index 53ebdce5d..5b7ef84f1 100644
--- a/source/world/item/BowItem.cpp
+++ b/source/world/item/BowItem.cpp
@@ -13,9 +13,8 @@ ItemStack* BowItem::use(ItemStack* inst, Level* level, Mob* user) const
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) {
+ if (!level->m_bIsClientSide)
level->addEntity(new Arrow(level, user));
- }
}
return inst;
diff --git a/source/world/item/CoalItem.hpp b/source/world/item/CoalItem.hpp
index b79c7d360..ce49d6b0c 100644
--- a/source/world/item/CoalItem.hpp
+++ b/source/world/item/CoalItem.hpp
@@ -9,4 +9,5 @@ class CoalItem : public Item
public:
std::string getDescriptionId(ItemStack* inst) const override;
+
};
diff --git a/source/world/item/Inventory.cpp b/source/world/item/Inventory.cpp
index 4e64e66fd..68309426d 100644
--- a/source/world/item/Inventory.cpp
+++ b/source/world/item/Inventory.cpp
@@ -4,13 +4,14 @@
#include "common/Logger.hpp"
#include "nbt/CompoundTag.hpp"
#include "network/Packet.hpp"
+#include "world/inventory/ContainerContentChangeListener.hpp"
#include "Item.hpp"
Inventory::Inventory(Player* pPlayer) : m_items(C_NUM_INVENTORY_SLOTS), m_armor(C_NUM_ARMOR_SLOTS)
{
m_pPlayer = pPlayer;
- m_selectedSlot = 0;
+ m_selectedStackId = 0;
}
Inventory::~Inventory()
@@ -120,9 +121,9 @@ void Inventory::prepareSurvivalInventory()
#endif
}
-uint16_t Inventory::getContainerSize() const
+Container::Size Inventory::getContainerSize() const
{
- return uint16_t(m_items.size() + m_armor.size());
+ return (Size)(m_items.size() + m_armor.size());
}
void Inventory::clear()
@@ -246,34 +247,34 @@ int Inventory::addResource(const ItemStack& item)
}
}
-ItemStack Inventory::removeItem(int index, int count)
+ItemStack Inventory::removeItem(StackID stackId, int count)
{
- ItemStack& item = getItem(index);
+ ItemStack& item = getItem(stackId);
if (!item.isEmpty())
{
if (item.m_count <= count)
{
ItemStack removed = item;
- setItem(index, ItemStack::EMPTY);
+ setItem(stackId, ItemStack::EMPTY);
return removed;
}
else
{
ItemStack removed = item.remove(count);
if (item.m_count == 0)
- setItem(index, ItemStack::EMPTY);
+ setItem(stackId, ItemStack::EMPTY);
return removed;
}
}
- else
- return ItemStack::EMPTY;
+
+ return ItemStack::EMPTY;
}
int Inventory::getSlot(int id)
{
- for (size_t i = 0; i < m_items.size(); ++i)
+ for (StackID i = 0; i < m_items.size(); ++i)
{
if (!m_items[i].isEmpty() && m_items[i].getId() == id)
return i;
@@ -299,7 +300,7 @@ bool Inventory::removeResource(int id)
// Doesn't exist in PE
void Inventory::tick()
{
- for (size_t i = 0; i < m_items.size(); i++)
+ for (StackID i = 0; i < m_items.size(); i++)
{
ItemStack& item = m_items[i];
@@ -307,7 +308,7 @@ void Inventory::tick()
{
if (item.m_popTime > 0)
item.m_popTime--;
- item.getItem()->inventoryTick(&item, m_pPlayer->m_pLevel, m_pPlayer, i, i == m_selectedSlot);
+ item.getItem()->inventoryTick(&item, m_pPlayer->m_pLevel, m_pPlayer, i, i == m_selectedStackId);
}
}
}
@@ -368,14 +369,15 @@ bool Inventory::hasUnlimitedResource(const ItemStack& item) const
return true;
}
-ItemStack& Inventory::getItem(int slotNo)
+ItemStack& Inventory::getItem(StackID stackId)
{
- assert(slotNo >= 0 && slotNo < getContainerSize());
+ // stackId < getContainerSize() trips when the RemotePlayer dies
+ assert(stackId >= 0 && stackId < getContainerSize());
- if (size_t(slotNo) < m_items.size())
- return m_items[slotNo];
+ if (size_t(stackId) < m_items.size())
+ return m_items[stackId];
else
- return m_armor[slotNo - m_items.size()];
+ return m_armor[stackId - m_items.size()];
}
ItemStack& Inventory::getArmor(Item::EquipmentSlot slotNo)
@@ -385,29 +387,29 @@ ItemStack& Inventory::getArmor(Item::EquipmentSlot slotNo)
ItemStack& Inventory::getSelectedItem()
{
- return getItem(m_selectedSlot);
+ return getItem(m_selectedStackId);
}
int Inventory::getSelectedItemId()
{
- return getItem(m_selectedSlot).getId();
+ return getItem(m_selectedStackId).getId();
}
-void Inventory::setItem(int index, const ItemStack& item)
+void Inventory::setItem(StackID stackId, const ItemStack& item)
{
- if ((size_t)index >= m_items.size())
+ if ((size_t)stackId >= m_items.size())
{
- m_armor[index - m_items.size()] = item;
+ m_armor[stackId - m_items.size()] = item;
}
else
{
- m_items[index] = item;
+ m_items[stackId] = item;
}
}
-void Inventory::setSelectedItem(ItemStack item)
+void Inventory::setSelectedItem(const ItemStack& item)
{
- setItem(m_selectedSlot, item);
+ setItem(m_selectedStackId, item);
}
void Inventory::setCarried(const ItemStack& carried)
@@ -425,24 +427,24 @@ void Inventory::pickItem(int itemID, int data, int maxHotBarSlot)
{
Item* selectItem = Item::items[itemID];
- if (!selectItem) return;
+ if (!selectItem && itemID != TILE_AIR) return;
for (size_t i = 0; i < m_items.size(); i++)
{
- if (!m_items[i] || m_items[i].getId() != itemID || m_items[i].getAuxValue() != data)
+ if (m_items[i].getId() != itemID || m_items[i].getAuxValue() != data)
continue;
if (i < size_t(maxHotBarSlot))
selectSlot(i);
else
- swapItems(i, m_selectedSlot);
+ swapItems(i, m_selectedStackId);
return;
}
- if (m_pPlayer->isCreative())
+ if (m_pPlayer->isCreative() && selectItem != nullptr)
{
ItemStack oldSelected = getSelected();
- setItem(m_selectedSlot, ItemStack(selectItem, 1, data));
+ setItem(m_selectedStackId, ItemStack(selectItem, 1, data));
if (!oldSelected.isEmpty()) addResource(oldSelected);
}
}
@@ -459,23 +461,23 @@ void Inventory::selectItem(int itemID, int maxHotBarSlot)
continue;
if (i < size_t(maxHotBarSlot))
- m_selectedSlot = i;
+ m_selectedStackId = i;
else
- swapItems(i, m_selectedSlot);
+ swapItems(i, m_selectedStackId);
}
}
-void Inventory::swapItems(int indexA, int indexB)
+void Inventory::swapItems(StackID stackIdA, StackID stackIdB)
{
- std::swap(getItem(indexA), getItem(indexB));
+ std::swap(getItem(stackIdA), getItem(stackIdB));
}
-void Inventory::selectSlot(int slotNo)
+void Inventory::selectSlot(StackID stackId)
{
- if (slotNo < 0 || slotNo >= C_MAX_HOTBAR_ITEMS)
+ if (stackId < 0 || stackId >= C_MAX_HOTBAR_ITEMS)
return;
- m_selectedSlot = slotNo;
+ m_selectedStackId = stackId;
}
int Inventory::getAttackDamage(Entity* pEnt)
@@ -627,3 +629,22 @@ GameType Inventory::_getGameMode() const
{
return m_pPlayer->getPlayerGameType();
}
+
+void Inventory::setContainerChanged(StackID stackId)
+{
+ for (ContentChangeListeners::iterator it = m_contentChangeListeners.begin(); it != m_contentChangeListeners.end(); ++it)
+ {
+ ContainerContentChangeListener* listener = *it;
+ listener->containerContentChanged(this, stackId);
+ }
+}
+
+void Inventory::addContentChangeListener(ContainerContentChangeListener* listener)
+{
+ m_contentChangeListeners.insert(listener);
+}
+
+void Inventory::removeContentChangeListener(ContainerContentChangeListener* listener)
+{
+ m_contentChangeListeners.erase(listener);
+}
diff --git a/source/world/item/Inventory.hpp b/source/world/item/Inventory.hpp
index 568a1e54a..29651111d 100644
--- a/source/world/item/Inventory.hpp
+++ b/source/world/item/Inventory.hpp
@@ -1,8 +1,9 @@
#pragma once
+#include
#include
-#include "world/Container.hpp"
#include "GameMods.hpp"
+#include "world/inventory/Container.hpp"
#include "world/item/ItemStack.hpp"
#include "world/entity/Player.hpp"
#include "world/gamemode/GameType.hpp"
@@ -19,13 +20,15 @@ class Player; // in case we're included from Player.hpp
class Inventory : public Container
{
+private:
+ typedef std::set ContentChangeListeners;
public:
Inventory(Player*);
virtual ~Inventory();
void prepareCreativeInventory();
void prepareSurvivalInventory();
- uint16_t getContainerSize() const override;
+ Size getContainerSize() const override;
void clear();
void replace(const std::vector& items);
@@ -38,14 +41,14 @@ class Inventory : public Container
bool add(ItemStack& item);
void tick();
- ItemStack& getItem(int slotNo) override;
+ ItemStack& getItem(StackID stackId) override;
ItemStack& getArmor(Item::EquipmentSlot slotNo);
ItemStack& getSelectedItem();
int getSelectedItemId();
- void setItem(int index, const ItemStack& item) override;
- void setSelectedItem(ItemStack item);
- ItemStack removeItem(int index, int count) override;
+ void setItem(StackID stackId, const ItemStack& item) override;
+ void setSelectedItem(const ItemStack& item);
+ ItemStack removeItem(StackID stackId, int count) override;
bool removeResource(int id);
void setCarried(const ItemStack& item);
@@ -53,8 +56,8 @@ class Inventory : public Container
void pickItem(int itemID, int data, int maxHotBarSlot);
void selectItem(int itemID, int maxHotBarSlot);
- void swapItems(int, int);
- void selectSlot(int slotNo);
+ void swapItems(StackID stackIdA, StackID stackIdB);
+ void selectSlot(StackID stackId);
int getAttackDamage(Entity*);
@@ -69,7 +72,7 @@ class Inventory : public Container
bool contains(const ItemStack&) const;
- uint16_t getSelectedSlotNo() const { return m_selectedSlot; }
+ StackID getSelectedSlotNo() const { return m_selectedStackId; }
// v0.2.0 name alias
ItemStack& getSelected() { return getSelectedItem(); }
@@ -80,9 +83,11 @@ class Inventory : public Container
return "Inventory";
}
- void setChanged() override { }
+ void setContainerChanged(StackID stackId) override;
+ void addContentChangeListener(ContainerContentChangeListener* listener) override;
+ void removeContentChangeListener(ContainerContentChangeListener* listener) override;
- bool stillValid(Player* player) const override { return true; }
+ bool stillValid(Player* player) const override { return true; }
private:
GameType _getGameMode() const;
@@ -93,11 +98,12 @@ class Inventory : public Container
public:
Player* m_pPlayer;
- SlotID m_selectedSlot;
+ StackID m_selectedStackId;
private:
ItemStack m_carried;
std::vector m_items;
std::vector m_armor;
+ ContentChangeListeners m_contentChangeListeners;
};
diff --git a/source/world/item/ItemStack.cpp b/source/world/item/ItemStack.cpp
index 0ced312cf..9ef6b1258 100644
--- a/source/world/item/ItemStack.cpp
+++ b/source/world/item/ItemStack.cpp
@@ -19,7 +19,7 @@ ItemStack::TAG_REPAIR_COST = "RepairCost",
ItemStack::TAG_ENCHANTS = "ench";
const ItemStack ItemStack::EMPTY;
-#define C_INVALID_ID -1
+#define C_INVALID_ID 0
void ItemStack::_init(int id, int count, int auxValue)
{
diff --git a/source/world/item/ItemStack.hpp b/source/world/item/ItemStack.hpp
index b984f3b9e..e51394b21 100644
--- a/source/world/item/ItemStack.hpp
+++ b/source/world/item/ItemStack.hpp
@@ -126,6 +126,7 @@ class ItemStack
public:
int16_t m_count;
int m_popTime;
+
private:
int16_t m_auxValue;
CompoundTag* m_userData;
diff --git a/source/world/item/crafting/FurnaceRecipes.cpp b/source/world/item/crafting/FurnaceRecipes.cpp
index 0c170f30d..36f99a069 100644
--- a/source/world/item/crafting/FurnaceRecipes.cpp
+++ b/source/world/item/crafting/FurnaceRecipes.cpp
@@ -1,6 +1,8 @@
#include "FurnaceRecipes.hpp"
#include "common/Logger.hpp"
+FurnaceRecipes* FurnaceRecipes::instance;
+
FurnaceRecipes::FurnaceRecipes()
{
addFurnaceRecipe(Tile::ironOre, ItemStack(Item::ironIngot));
diff --git a/source/world/item/crafting/Recipe.hpp b/source/world/item/crafting/Recipe.hpp
index 6bb7a40dd..169d83a17 100644
--- a/source/world/item/crafting/Recipe.hpp
+++ b/source/world/item/crafting/Recipe.hpp
@@ -1,6 +1,6 @@
#pragma once
-#include "world/Container.hpp"
+#include "world/inventory/Container.hpp"
class Recipe
{
diff --git a/source/world/item/crafting/Recipes.cpp b/source/world/item/crafting/Recipes.cpp
index 05f0e32c0..fe375b83b 100644
--- a/source/world/item/crafting/Recipes.cpp
+++ b/source/world/item/crafting/Recipes.cpp
@@ -120,14 +120,14 @@ Recipes::Recipes()
addOre(ItemStack(Item::dye_powder, 1, 4), Tile::lapisBlock);
// StructureRecipes
- //add(ShapedRecipeBuilder("###",
- // "# #",
- // "###", ItemStack(Tile::chest))
- // .add('#', Tile::wood));
- //add(ShapedRecipeBuilder("###",
- // "# #",
- // "###", ItemStack(Tile::furnace))
- // .add('#', Tile::stoneBrick));
+ add(ShapedRecipeBuilder("###",
+ "# #",
+ "###", ItemStack(Tile::chest))
+ .add('#', Tile::wood));
+ add(ShapedRecipeBuilder("###",
+ "# #",
+ "###", ItemStack(Tile::furnace))
+ .add('#', Tile::stoneBrick));
add(ShapedRecipeBuilder("##",
"##", ItemStack(Tile::craftingTable))
@@ -169,11 +169,11 @@ Recipes::Recipes()
// .add('#', Tile::wood)
// .add('X', Item::emerald));
- //add(ShapedRecipeBuilder("###",
- // "#X#",
- // "###", ItemStack(Tile::musicBlock, 1))
- // .add('#', Tile::wood)
- // .add('X', Item::redStone));
+ add(ShapedRecipeBuilder("###",
+ "#X#",
+ "###", ItemStack(Tile::musicBlock, 1))
+ .add('#', Tile::wood)
+ .add('X', Item::redStone));
add(ShapedRecipeBuilder("###",
"XXX",
diff --git a/source/world/level/Level.cpp b/source/world/level/Level.cpp
index f4181dfec..e3129f1d7 100644
--- a/source/world/level/Level.cpp
+++ b/source/world/level/Level.cpp
@@ -19,6 +19,7 @@
#include "network/packets/ExplodePacket.hpp"
#include "world/level/levelgen/chunk/ChunkCache.hpp"
#include "world/entity/MobSpawner.hpp"
+#include "world/tile/entity/TileEntity.hpp"
#include "Explosion.hpp"
#include "Region.hpp"
@@ -39,6 +40,8 @@ Level::Level(LevelStorage* pStor, const std::string& name, const LevelSettings&
m_bCalculatingInitialSpawn = false;
m_pChunkSource = nullptr;
m_pLevelStorage = pStor;
+ m_tileEntities = TileEntityVector();
+ m_bUpdatingTileEntities = false;
m_randValue = 42184323;
m_addend = 1013904223;
m_bUpdateLights = true;
@@ -78,10 +81,9 @@ Level::~Level()
SAFE_DELETE(m_pPathFinder);
SAFE_DELETE(m_pMobSpawner);
- const size_t size = m_entities.size();
- for (size_t i = 0; i < size; ++i)
+ for (EntityMap::iterator it = m_entities.begin(); it != m_entities.end(); it++)
{
- Entity* pEnt = m_entities[i];
+ Entity* pEnt = it->second;
//you better HOPE this is freed by Minecraft! (or a NetworkHandler)
//Really should have used shared pointers and stuff.
@@ -259,6 +261,61 @@ int Level::getRawBrightness(const TilePos& pos, bool b) const
return pChunk->getRawBrightness(pos, m_skyDarken);
}
+TileEntity* Level::getTileEntity(const TilePos& pos) const
+{
+ LevelChunk* pChunk = getChunk(pos);
+ return pChunk ? pChunk->getTileEntity(pos) : nullptr;
+}
+
+const TileEntityVector* Level::getAllTileEntities() const
+{
+ return &m_tileEntities;
+}
+
+void Level::setTileEntity(const TilePos& pos, TileEntity* tileEntity)
+{
+
+ if (tileEntity->isRemoved())
+ return;
+
+ if (m_bUpdatingTileEntities)
+ {
+ tileEntity->m_pos = pos;
+ m_pendingTileEntities.push_back(tileEntity);
+ return;
+ }
+
+ m_tileEntities.push_back(tileEntity);
+ LevelChunk* pChunk = getChunk(pos);
+ if (pChunk)
+ pChunk->setTileEntity(pos, tileEntity);
+}
+
+void Level::removeTileEntity(const TilePos& pos)
+{
+ TileEntity* tileEntity = getTileEntity(pos);
+
+ if (tileEntity == nullptr)
+ {
+ LOG_W("Tried to remove a tile entity at %d, %d, %d, but there was no tile entity there!", pos.x, pos.y, pos.z);
+ return;
+ }
+
+ // During a tile entity update, just mark it for potential removal
+ if (m_bUpdatingTileEntities)
+ {
+ tileEntity->setRemoved();
+ return;
+ }
+
+ Util::remove(m_tileEntities, tileEntity);
+
+ if (LevelChunk* pChunk = getChunk(pos))
+ {
+ pChunk->removeTileEntity(pos);
+ }
+}
+
void Level::swap(const TilePos& pos1, const TilePos& pos2)
{
TileID tile1 = getTile(pos1);
@@ -301,22 +358,18 @@ Material* Level::getMaterial(const TilePos& pos) const
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++)
{
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)
+ if (pEnt->hashCode() == id)
return pEnt;
}
+ EntityMap::const_iterator it = m_entities.find(id);
+ if (it != m_entities.end())
+ return it->second;
+
return nullptr;
}
@@ -329,7 +382,7 @@ unsigned int Level::getEntityCount(const EntityCategories& category) const
return it->second;
}
-const EntityVector* Level::getAllEntities() const
+const EntityMap* Level::getAllEntities() const
{
return &m_entities;
}
@@ -1191,11 +1244,28 @@ void Level::validateSpawn()
void Level::removeAllPendingEntityRemovals()
{
- Util::removeAll(m_entities, m_pendingEntityRemovals);
+ for (EntityVector::iterator it = m_pendingEntityRemovals.begin(); it != m_pendingEntityRemovals.end(); it++)
+ {
+ Entity* ent = *it;
+ if (m_entities.find(ent->hashCode()) != m_entities.end())
+ {
+ m_entities.erase(ent->hashCode());
+ }
+ }
for (EntityVector::iterator it = m_pendingEntityRemovals.begin(); it != m_pendingEntityRemovals.end(); it++)
{
Entity* ent = *it;
+ if (Entity* riding = ent->getRiding())
+ {
+ if (riding->m_bRemoved || riding->getRider() != ent)
+ {
+ riding->setRider(nullptr);
+ ent->setRiding(nullptr);
+ }
+ else
+ continue;
+ }
ent->removed();
LevelChunk* chunk = getChunk(ent->m_chunkPos);
@@ -1216,6 +1286,14 @@ void Level::removeEntities(const EntityVector& vec)
bool Level::removeEntity(Entity* pEnt)
{
+ // kick off rider before disappearing
+ if (Entity* rider = pEnt->getRider())
+ rider->ride(nullptr);
+
+ // kick self off mount before disappearing
+ if (Entity* mount = pEnt->getRiding())
+ mount->ride(nullptr);
+
pEnt->remove();
if (pEnt->isPlayer())
@@ -1250,7 +1328,7 @@ bool Level::addEntity(Entity* pEnt)
m_players.push_back((Player*)pEnt);
}
- m_entities.push_back(pEnt);
+ m_entities.insert(std::make_pair(pEnt->hashCode(), pEnt));
entityAdded(pEnt);
@@ -1329,9 +1407,9 @@ void Level::sendEntityData()
return;
// Inlined on 0.2.1, god bless PerfTimer
- for (EntityVector::iterator it = m_entities.begin(); it != m_entities.end(); it++)
+ for (EntityMap::iterator it = m_entities.begin(); it != m_entities.end(); it++)
{
- Entity* ent = *it;
+ Entity* ent = it->second;
SynchedEntityData& data = ent->getEntityData();
if (data.isDirty())
m_pRakNetInstance->send(new SetEntityDataPacket(ent->m_EntityID, data));
@@ -1640,7 +1718,12 @@ void Level::tick(Entity* pEnt, bool shouldTick)
pEnt->m_oRot = pEnt->m_rot;
if (pEnt->m_bInAChunk)
- pEnt->tick();
+ {
+ if (pEnt->getRiding())
+ pEnt->rideTick();
+ else
+ pEnt->tick();
+ }
}
else
{
@@ -1674,6 +1757,23 @@ void Level::tick(Entity* pEnt, bool shouldTick)
getChunk(cp)->updateEntity(pEnt);
}
}
+ if (shouldTick && pEnt->m_bInAChunk)
+ {
+ Entity* rider = pEnt->getRider();
+ // someone is riding this entity
+ if (rider)
+ {
+ if (rider->m_bRemoved || rider->getRiding() != pEnt)
+ {
+ rider->setRiding(nullptr);
+ pEnt->setRider(nullptr);
+ }
+ else
+ {
+ tick(rider);
+ }
+ }
+ }
}
void Level::tick(Entity* pEnt)
@@ -1706,26 +1806,72 @@ void Level::tickEntities()
// inlined in the original
removeAllPendingEntityRemovals();
- for (size_t i = 0; i < m_entities.size(); i++)
+ for (EntityMap::iterator it = m_entities.begin(); it != m_entities.end();)
{
- Entity* pEnt = m_entities[i];
+ Entity* pEnt = it->second;
+
+ if (Entity* riding = pEnt->getRiding())
+ {
+ if (riding->m_bRemoved || riding->getRider() != pEnt)
+ {
+ riding->setRider(nullptr);
+ pEnt->setRiding(nullptr);
+ }
+ else
+ {
+ ++it;
+ continue;
+ }
+ }
if (!pEnt->m_bRemoved)
{
tick(pEnt);
+ ++it;
+
+ continue;
}
- else if (!pEnt->isPlayer() || pEnt->m_bForceRemove)
+
+ 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--;
+ EntityMap::iterator itErase = it;
+ it++;
+ m_entities.erase(itErase);
entityRemoved(pEnt);
delete pEnt;
+
+ continue;
}
+
+ ++it;
}
+
+ m_bUpdatingTileEntities = true;
+ for (size_t i = 0; i < m_tileEntities.size(); i++)
+ {
+ TileEntity* tileEnt = m_tileEntities[i];
+
+ if (!tileEnt->isRemoved())
+ {
+ tileEnt->tick();
+ }
+ else
+ {
+ LevelChunk* ch = getChunk(tileEnt->m_pos);
+ if (ch)
+ ch->removeTileEntity(tileEnt->m_pos);
+
+ m_tileEntities.erase(m_tileEntities.begin() + i);
+ i--;
+
+ delete tileEnt;
+ }
+ }
+ m_bUpdatingTileEntities = false;
}
HitResult Level::clip(Vec3 v1, Vec3 v2, bool flag) const
@@ -1961,11 +2107,24 @@ void Level::explode(Entity* entity, const Vec3& pos, float power, bool bIsFiery)
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++)
+ for (EntityVector::const_iterator it = entities.begin(); it != entities.end(); it++)
{
Entity* pEnt = *it;
+ EntityMap::iterator result = m_entities.find(pEnt->hashCode());
+
+ if (result != m_entities.end())
+ {
+ if (result->second == pEnt)
+ {
+ LOG_W("Entity %d already exists. Skipping...", pEnt->hashCode());
+ continue;
+ }
+
+ removeEntity(result->second);
+ continue;
+ }
+
+ m_entities.insert(std::make_pair(pEnt->hashCode(), pEnt));
entityAdded(pEnt);
}
}
@@ -1982,9 +2141,9 @@ void Level::ensureAdded(Entity* entity)
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);
+ EntityMap::iterator result = m_entities.find(entity->hashCode());
if (result == m_entities.end())
- m_entities.push_back(entity);
+ m_entities.insert(std::make_pair(entity->hashCode(), entity));
}
bool Level::extinguishFire(Player* player, const TilePos& pos, Facing::Name face)
diff --git a/source/world/level/Level.hpp b/source/world/level/Level.hpp
index 19a14c8c8..f4e871e9a 100644
--- a/source/world/level/Level.hpp
+++ b/source/world/level/Level.hpp
@@ -14,6 +14,7 @@
#define _USE_MATH_DEFINES
#endif
#include
+#include