diff options
author | Tiger Wang <ziwei.tiger@hotmail.co.uk> | 2014-01-19 14:55:22 +0100 |
---|---|---|
committer | Tiger Wang <ziwei.tiger@hotmail.co.uk> | 2014-01-19 14:55:22 +0100 |
commit | 82b2290b74519ab86d6abae463cbe0c1d8ac5868 (patch) | |
tree | 98855d56f18990731d88c283c6990d98b3d26245 | |
parent | Minecart collision and general improvements (diff) | |
parent | Updated core (diff) | |
download | cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.gz cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.bz2 cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.lz cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.xz cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.tar.zst cuberite-82b2290b74519ab86d6abae463cbe0c1d8ac5868.zip |
85 files changed, 1238 insertions, 332 deletions
diff --git a/.gitignore b/.gitignore index c1a868db6..a108a9ece 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ build/ +ipch/ +Win32/ MCServer/MCServer ChunkWorxSave.ini doxy/ diff --git a/.gitmodules b/.gitmodules index 028471319..2b5596589 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "MCServer/Plugins/Core"] path = MCServer/Plugins/Core - url = git://github.com/mc-server/Core.git + url = https://github.com/mc-server/Core.git [submodule "MCServer/Plugins/ProtectionAreas"] path = MCServer/Plugins/ProtectionAreas - url = git://github.com/mc-server/ProtectionAreas.git + url = https://github.com/mc-server/ProtectionAreas.git [submodule "MCServer/Plugins/TransAPI"] path = MCServer/Plugins/TransAPI - url = git://github.com/bearbin/transapi.git + url = https://github.com/bearbin/transapi.git diff --git a/CMakeLists.txt b/CMakeLists.txt index f2ad8b364..4ddd34db3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ elseif(APPLE) #on os x clang adds pthread for us but we need to add it for gcc if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_flags_cxx("-pthread") + add_flags_cxx("-std=c++11") endif() else() # Let gcc / clang know that we're compiling a multi-threaded app: diff --git a/COMPILING.md b/COMPILING.md index 31222a5d8..eceeefee7 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -81,8 +81,8 @@ This is useful if you want to compile MCServer to use on another 32-bit machine. to your cmake command and 32 bit will be forced. -Compiling for another computer ------------------------------- +### Compiling for another computer ### + When compiling for another computer it is important to set cross compiling mode. This tells the compiler not to optimise for your machine. It can be used with debug or release mode. To enable simply add: diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 150bcf09e..b15a36a38 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -20,5 +20,6 @@ worktycho Sxw1212 tonibm19 Diusrex +structinf (xdot) Please add yourself to this list if you contribute to MCServer. diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index f8cb8ed4b..bf32ea8c2 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -1726,7 +1726,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); ForEachCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function(Command, Permission, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." }, ForEachConsoleCommand = { Params = "CallbackFn", Return = "bool", Notes = "Calls the CallbackFn function for each command that has been bound using BindConsoleCommand(). The CallbackFn has the following signature: <pre class=\"prettyprint lang-lua\">function (Command, HelpString)</pre>. If the callback returns true, the enumeration is aborted and this API function returns false; if it returns false or no value, the enumeration continues with the next command, and the API function returns true." }, Get = { Params = "", Return = "cPluginManager", Notes = "(STATIC) Returns the single instance of the plugin manager" }, - GetAllPlugins = { Params = "", Return = "table", Notes = "Returns a table (dictionary) of all plugins, [name => {{cPlugin}}] pairing." }, + GetAllPlugins = { Params = "", Return = "table", Notes = "Returns a table (dictionary) of all plugins, [name => value], where value is a valid {{cPlugin}} if the plugin is loaded, or the bool value false if the plugin is not loaded." }, GetCommandPermission = { Params = "Command", Return = "Permission", Notes = "Returns the permission needed for executing the specified command" }, GetCurrentPlugin = { Params = "", Return = "{{cPlugin}}", Notes = "Returns the {{cPlugin}} object for the calling plugin. This is the same object that the Initialize function receives as the argument." }, GetNumPlugins = { Params = "", Return = "number", Notes = "Returns the number of plugins, including the disabled ones" }, diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject decc72f3a9134d80df5e14c3f2570e1479d521c +Subproject e9695520248ef32f229162ba2b0ee6792749777 diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt index 2178705a8..f8a01a134 100644 --- a/Tools/ProtoProxy/CMakeLists.txt +++ b/Tools/ProtoProxy/CMakeLists.txt @@ -77,8 +77,8 @@ endfunction() # Include the libraries: -file(GLOB CRYPTOPP_SRC "../../lib/CryptoPP/*.cpp") -file(GLOB CRYPTOPP_HDR "../../lib/CryptoPP/*.h") +file(GLOB CRYPTOPP_SRC "../../lib/cryptopp/*.cpp") +file(GLOB CRYPTOPP_HDR "../../lib/cryptopp/*.h") flatten_files(CRYPTOPP_SRC) flatten_files(CRYPTOPP_HDR) source_group("CryptoPP" FILES ${CRYPTOPP_SRC} ${CRYPTOPP_HDR}) diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index e91b9935e..34da9b700 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -155,6 +155,32 @@ AString PrintableAbsIntTriplet(int a_X, int a_Y, int a_Z, double a_Divisor = 32) +struct sCoords +{ + int x, y, z; + + sCoords(int a_X, int a_Y, int a_Z) : x(a_X), y(a_Y), z(a_Z) {} +} ; + + + + + +struct sChunkMeta +{ + int m_ChunkX, m_ChunkZ; + short m_PrimaryBitmap; + short m_AddBitmap; + sChunkMeta(int a_ChunkX, int a_ChunkZ, short a_PrimaryBitmap, short a_AddBitmap) : + m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_PrimaryBitmap(a_PrimaryBitmap), m_AddBitmap(a_AddBitmap) + { + } +} ; + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cConnection: @@ -220,7 +246,7 @@ void cConnection::Run(void) int res = select(2, &ReadFDs, NULL, NULL, NULL); if (res <= 0) { - printf("select() failed: %d; aborting client", WSAGetLastError()); + printf("select() failed: %d; aborting client", SocketError); break; } if (FD_ISSET(m_ServerSocket, &ReadFDs)) @@ -249,12 +275,10 @@ void cConnection::Run(void) void cConnection::Log(const char * a_Format, ...) { - va_list args, argsCopy; + va_list args; va_start(args, a_Format); - va_start(argsCopy, a_Format); AString msg; - AppendVPrintf(msg, a_Format, args, argsCopy); - va_end(argsCopy); + AppendVPrintf(msg, a_Format, args); va_end(args); AString FullMsg; Printf(FullMsg, "[%5.3f] %s\n", GetRelativeTime(), msg.c_str()); @@ -276,12 +300,10 @@ void cConnection::Log(const char * a_Format, ...) void cConnection::DataLog(const void * a_Data, int a_Size, const char * a_Format, ...) { - va_list args, argsCopy; + va_list args; va_start(args, a_Format); - va_start(argsCopy, a_Format); AString msg; - AppendVPrintf(msg, a_Format, args, argsCopy); - va_end(argsCopy); + AppendVPrintf(msg, a_Format, args); va_end(args); AString FullMsg; AString Hex; @@ -323,7 +345,7 @@ bool cConnection::ConnectToServer(void) localhost.sin_addr.s_addr = htonl(0x7f000001); // localhost if (connect(m_ServerSocket, (sockaddr *)&localhost, sizeof(localhost)) != 0) { - printf("connection to server failed: %d\n", WSAGetLastError()); + printf("connection to server failed: %d\n", SocketError); return false; } Log("Connected to SERVER"); @@ -340,7 +362,7 @@ bool cConnection::RelayFromServer(void) int res = recv(m_ServerSocket, Buffer, sizeof(Buffer), 0); if (res <= 0) { - Log("Server closed the socket: %d; %d; aborting connection", res, WSAGetLastError()); + Log("Server closed the socket: %d; %d; aborting connection", res, SocketError); return false; } @@ -380,7 +402,7 @@ bool cConnection::RelayFromClient(void) int res = recv(m_ClientSocket, Buffer, sizeof(Buffer), 0); if (res <= 0) { - Log("Client closed the socket: %d; %d; aborting connection", res, WSAGetLastError()); + Log("Client closed the socket: %d; %d; aborting connection", res, SocketError); return false; } @@ -428,7 +450,7 @@ bool cConnection::SendData(SOCKET a_Socket, const char * a_Data, int a_Size, con int res = send(a_Socket, a_Data, a_Size, 0); if (res <= 0) { - Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, WSAGetLastError()); + Log("%s closed the socket: %d, %d; aborting connection", a_Peer, res, SocketError); return false; } return true; @@ -1668,12 +1690,6 @@ bool cConnection::HandleServerExplosion(void) HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, PosZ); HANDLE_SERVER_PACKET_READ(ReadBEFloat, float, Force); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, NumRecords); - struct sCoords - { - int x, y, z; - - sCoords(int a_X, int a_Y, int a_Z) : x(a_X), y(a_Y), z(a_Z) {} - } ; std::vector<sCoords> Records; Records.reserve(NumRecords); int PosXI = (int)PosX, PosYI = (int)PosY, PosZI = (int)PosZ; @@ -1868,16 +1884,6 @@ bool cConnection::HandleServerMapChunkBulk(void) // Read individual chunk metas. // Need to read them first and only then start logging (in case we don't have the full packet yet) - struct sChunkMeta - { - int m_ChunkX, m_ChunkZ; - short m_PrimaryBitmap; - short m_AddBitmap; - sChunkMeta(int a_ChunkX, int a_ChunkZ, short a_PrimaryBitmap, short a_AddBitmap) : - m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_PrimaryBitmap(a_PrimaryBitmap), m_AddBitmap(a_AddBitmap) - { - } - } ; typedef std::vector<sChunkMeta> sChunkMetas; sChunkMetas ChunkMetas; ChunkMetas.reserve(ChunkCount); @@ -1907,7 +1913,6 @@ bool cConnection::HandleServerMapChunkBulk(void) // TODO: Save the compressed data into a file for later analysis COPY_TO_CLIENT(); - Sleep(50); return true; } @@ -2857,8 +2862,8 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c int EncryptedLength = rsaEncryptor.FixedCiphertextLength(); ASSERT(EncryptedLength <= sizeof(EncryptedSecret)); rsaEncryptor.Encrypt(rng, SharedSecret, sizeof(SharedSecret), EncryptedSecret); - m_ServerEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1)); - m_ServerDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16))(Name::FeedbackSize(), 1)); + m_ServerEncryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16, true))(Name::FeedbackSize(), 1)); + m_ServerDecryptor.SetKey(SharedSecret, 16, MakeParameters(Name::IV(), ConstByteArrayParameter(SharedSecret, 16, true))(Name::FeedbackSize(), 1)); // Encrypt the nonce: byte EncryptedNonce[128]; diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h index 8424aca81..7415c9e62 100644 --- a/Tools/ProtoProxy/Globals.h +++ b/Tools/ProtoProxy/Globals.h @@ -95,6 +95,7 @@ typedef unsigned short UInt16; #define WIN32_LEAN_AND_MEAN #include <Windows.h> #include <winsock2.h> + #include <ws2tcpip.h> // Windows SDK defines min and max macros, messing up with our std::min and std::max usage #undef min @@ -104,6 +105,8 @@ typedef unsigned short UInt16; #ifdef GetFreeSpace #undef GetFreeSpace #endif // GetFreeSpace + + #define SocketError WSAGetLastError() #else #include <sys/types.h> #include <sys/stat.h> // for mkdir @@ -116,6 +119,7 @@ typedef unsigned short UInt16; #include <dirent.h> #include <errno.h> #include <iostream> + #include <unistd.h> #include <cstdio> #include <cstring> @@ -123,6 +127,14 @@ typedef unsigned short UInt16; #include <semaphore.h> #include <errno.h> #include <fcntl.h> + + typedef int SOCKET; + enum + { + INVALID_SOCKET = -1, + }; + #define closesocket close + #define SocketError errno #if !defined(ANDROID_NDK) #include <tr1/memory> #endif @@ -211,10 +223,10 @@ public: -#include "CryptoPP/randpool.h" -#include "CryptoPP/aes.h" -#include "CryptoPP/rsa.h" -#include "CryptoPP/modes.h" +#include "cryptopp/randpool.h" +#include "cryptopp/aes.h" +#include "cryptopp/rsa.h" +#include "cryptopp/modes.h" using namespace CryptoPP; diff --git a/Tools/ProtoProxy/Server.cpp b/Tools/ProtoProxy/Server.cpp index 35732764c..71b5ecb94 100644 --- a/Tools/ProtoProxy/Server.cpp +++ b/Tools/ProtoProxy/Server.cpp @@ -22,13 +22,16 @@ cServer::cServer(void) int cServer::Init(short a_ListenPort, short a_ConnectPort) { m_ConnectPort = a_ConnectPort; - WSAData wsa; - int res = WSAStartup(0x0202, &wsa); - if (res != 0) - { - printf("Cannot initialize WinSock: %d\n", res); - return res; - } + + #ifdef _WIN32 + WSAData wsa; + int res = WSAStartup(0x0202, &wsa); + if (res != 0) + { + printf("Cannot initialize WinSock: %d\n", res); + return res; + } + #endif // _WIN32 printf("Generating protocol encryption keypair...\n"); time_t CurTime = time(NULL); @@ -62,12 +65,12 @@ void cServer::Run(void) while (true) { sockaddr_in Addr; - ZeroMemory(&Addr, sizeof(Addr)); - int AddrSize = sizeof(Addr); + memset(&Addr, 0, sizeof(Addr)); + socklen_t AddrSize = sizeof(Addr); SOCKET client = accept(m_ListenSocket, (sockaddr *)&Addr, &AddrSize); if (client == INVALID_SOCKET) { - printf("accept returned an error: %d; bailing out.\n", WSAGetLastError()); + printf("accept returned an error: %d; bailing out.\n", SocketError); return; } printf("Client connected, proxying...\n"); diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 0927f2f7b..85ef1e24f 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -2911,6 +2911,14 @@ > </File> <File + RelativePath="..\src\BlockEntities\CommandBlockEntity.cpp" + > + </File> + <File + RelativePath="..\src\BlockEntities\CommandBlockEntity.h" + > + </File> + <File RelativePath="..\src\BlockEntities\DispenserEntity.cpp" > </File> diff --git a/lib/lua/CMakeLists.txt b/lib/lua/CMakeLists.txt index 02c20388d..4babae9b2 100644 --- a/lib/lua/CMakeLists.txt +++ b/lib/lua/CMakeLists.txt @@ -1,5 +1,5 @@ -cmake_minimum_required (VERSION 2.6) +cmake_minimum_required (VERSION 2.8.2) project (lua) include_directories ("${PROJECT_SOURCE_DIR}/../../src/") @@ -25,7 +25,15 @@ if (WIN32) # Output the executable into the $/MCServer folder, so that MCServer can find it: set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer) - SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES + SET_TARGET_PROPERTIES(lua PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer + ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer + ARCHIVE_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer + ARCHIVE_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer + LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer + LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer + LIBRARY_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer + LIBRARY_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer RUNTIME_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer @@ -38,6 +46,9 @@ if (WIN32) lua PROPERTIES COMPILE_FLAGS "-D_CRT_SECURE_NO_WARNINGS" ) endif() + + # NOTE: The DLL for each configuration is stored at the same place, thus overwriting each other. + # This is known, however such behavior is needed for LuaRocks - they always load "lua.dll" else() add_library(lua ${SOURCE}) endif() diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 2d0300ebf..f65aed9bb 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -31,6 +31,7 @@ $cfile "../Defines.h" $cfile "../ChatColor.h" $cfile "../ClientHandle.h" $cfile "../Entities/Entity.h" +$cfile "../Entities/Floater.h" $cfile "../Entities/Pawn.h" $cfile "../Entities/Player.h" $cfile "../Entities/Pickup.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index ebee2d697..3ebe7b294 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -14,6 +14,7 @@ #include "../WebAdmin.h" #include "../ClientHandle.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -2265,16 +2266,17 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); - tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); - tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); - tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); - tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); - tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); - tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); - tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "DoWithBlockEntityAt", tolua_DoWithXYZ<cWorld, cBlockEntity, &cWorld::DoWithBlockEntityAt>); + tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); + tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); + tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); + tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); + tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); + tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); + tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>); + tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>); tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index 5d7e4a37a..97b5c1a66 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "BlockEntity.h" #include "ChestEntity.h" +#include "CommandBlockEntity.h" #include "DispenserEntity.h" #include "DropperEntity.h" #include "EnderChestEntity.h" @@ -23,17 +24,18 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE { switch (a_BlockType) { - case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); - case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); - case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); + case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); + case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); } LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)", __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp new file mode 100644 index 000000000..ca617b04d --- /dev/null +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -0,0 +1,197 @@ + +// CommandBlockEntity.cpp + +// Implements the cCommandBlockEntity class representing a single command block in the world + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "json/json.h" +#include "CommandBlockEntity.h" +#include "../Entities/Player.h" + +#include "../CommandOutput.h" +#include "../Root.h" +#include "../Server.h" // ExecuteConsoleCommand() + + + + + +cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : + super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), + m_ShouldExecute(false), + m_IsPowered(false) +{} + + + + + + +void cCommandBlockEntity::UsedBy(cPlayer * a_Player) +{ + // Nothing to do + UNUSED(a_Player); +} + + + + + +void cCommandBlockEntity::SetCommand(const AString & a_Cmd) +{ + m_Command = a_Cmd; +} + + + + + +void cCommandBlockEntity::SetLastOutput(const AString & a_LastOut) +{ + m_LastOutput = a_LastOut; +} + + + + + +void cCommandBlockEntity::SetResult(const NIBBLETYPE a_Result) +{ + m_Result = a_Result; +} + + + + + +const AString & cCommandBlockEntity::GetCommand(void) const +{ + return m_Command; +} + + + + + +const AString & cCommandBlockEntity::GetLastOutput(void) const +{ + return m_LastOutput; +} + + + + + +NIBBLETYPE cCommandBlockEntity::GetResult(void) const +{ + return m_Result; +} + + + + + +void cCommandBlockEntity::Activate(void) +{ + m_ShouldExecute = true; +} + + + + + +void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered) +{ + if (a_IsPowered && !m_IsPowered) + { + Activate(); + } + m_IsPowered = a_IsPowered; +} + + + + + +bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + if (!m_ShouldExecute) + { + return false; + } + + m_ShouldExecute = false; + Execute(); + return true; +} + + + + + +void cCommandBlockEntity::SendTo(cClientHandle & a_Client) +{ + // Nothing needs to be sent + UNUSED(a_Client); +} + + + + + +bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value) +{ + m_Command = a_Value.get("Command", "").asString(); + + m_LastOutput = a_Value.get("LastOutput", "").asString(); + + return true; +} + + + + + +void cCommandBlockEntity::SaveToJson(Json::Value & a_Value) +{ + a_Value["Command"] = m_Command; + + a_Value["LastOutput"] = m_LastOutput; +} + + + + + +void cCommandBlockEntity::Execute() +{ + class CommandBlockOutCb : + public cCommandOutputCallback + { + cCommandBlockEntity* m_CmdBlock; + + public: + CommandBlockOutCb(cCommandBlockEntity* a_CmdBlock) : m_CmdBlock(a_CmdBlock) {} + + virtual void Out(const AString & a_Text) + { + ASSERT(m_CmdBlock != NULL); + + // Overwrite field + m_CmdBlock->SetLastOutput(a_Text); + } + } CmdBlockOutCb(this); + + LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str()); + + cServer* Server = cRoot::Get()->GetServer(); + + Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb); + + // TODO 2014-01-18 xdot: Update the signal strength. + m_Result = 0; +} + + + + diff --git a/src/BlockEntities/CommandBlockEntity.h b/src/BlockEntities/CommandBlockEntity.h new file mode 100644 index 000000000..12157670f --- /dev/null +++ b/src/BlockEntities/CommandBlockEntity.h @@ -0,0 +1,91 @@ + +// CommandBlockEntity.h + +// Declares the cCommandBlockEntity class representing a single command block in the world + + + + + +#pragma once + +#include "BlockEntity.h" + + + + + +namespace Json +{ + class Value; +} + + + + + +// tolua_begin + +class cCommandBlockEntity : + public cBlockEntity +{ + typedef cBlockEntity super; + +public: + + // tolua_end + + /// Creates a new empty command block entity + cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World); + + bool LoadFromJson( const Json::Value& a_Value ); + virtual void SaveToJson(Json::Value& a_Value ) override; + + virtual bool Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual void UsedBy(cPlayer * a_Player) override; + + void SetLastOutput(const AString & a_LastOut); + + void SetResult(const NIBBLETYPE a_Result); + + // tolua_begin + + /// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate + void SetRedstonePower(bool a_IsPowered); + + /// Sets the command block to execute a command in the next tick + void Activate(void); + + /// Sets the command + void SetCommand(const AString & a_Cmd); + + /// Retrieves stored command + const AString & GetCommand(void) const; + + /// Retrieves the last line of output generated by the command block + const AString & GetLastOutput(void) const; + + /// Retrieves the result (signal strength) of the last operation + NIBBLETYPE GetResult(void) const; + + // tolua_end + +private: + + /// Executes the associated command + void Execute(); + + bool m_ShouldExecute; + bool m_IsPowered; + + AString m_Command; + + AString m_LastOutput; + + NIBBLETYPE m_Result; +} ; // tolua_export + + + + diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index f15553968..c6643bcff 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -307,7 +307,7 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) /// Updates the current recipe, based on the current input void cFurnaceEntity::UpdateInput(void) { - if (!m_Contents.GetSlot(fsInput).IsStackableWith(m_LastInput)) + if (!m_Contents.GetSlot(fsInput).IsEqual(m_LastInput)) { // The input is different from what we had before, reset the cooking time m_TimeCooked = 0; @@ -417,7 +417,7 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const return true; } - if (!m_Contents.GetSlot(fsOutput).IsStackableWith(*m_CurrentRecipe->Out)) + if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out)) { // The output slot is blocked with something that cannot be stacked with the recipe's output return false; diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index eac59e74d..2255cad64 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -407,7 +407,7 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl m_Contents.SetSlot(i, One); return true; } - else if (m_Contents.GetSlot(i).IsStackableWith(One)) + else if (m_Contents.GetSlot(i).IsEqual(One)) { if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum)) { @@ -544,7 +544,7 @@ bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstS } for (int i = 0; i < ContentsWidth * ContentsHeight; i++) { - if (m_Contents.GetSlot(i).IsStackableWith(DestSlot)) + if (m_Contents.GetSlot(i).IsEqual(DestSlot)) { if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum)) { diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 488c58ac5..88f7c4b32 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -42,13 +42,13 @@ public: { return false; } - double rot = a_Player->GetRotation(); + double yaw = a_Player->GetYaw(); if ( (Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) ) { - a_BlockMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3; + a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3; return true; } if ( @@ -56,12 +56,12 @@ public: (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) ) { - a_BlockMeta = (rot < 0) ? 4 : 5; + a_BlockMeta = (yaw < 0) ? 4 : 5; return true; } // Single chest, get meta from rotation only - a_BlockMeta = RotationToMetaData(rot); + a_BlockMeta = RotationToMetaData(yaw); return true; } @@ -80,7 +80,7 @@ public: return; } - double rot = a_Player->GetRotation(); + double rot = a_Player->GetYaw(); // FIXME: Rename rot to yaw // Choose meta from player rotation, choose only between 2 or 3 NIBBLETYPE NewMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3; if ( diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index e7e18bac9..5a8e54eda 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -53,7 +53,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw()); return true; } diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 03a79d47d..1e86446dd 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -42,7 +42,7 @@ public: } a_BlockType = m_BlockType; - a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation()); + a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw()); return true; } diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index b7f20825d..ce9cc0c5d 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -31,7 +31,7 @@ public: a_BlockType = m_BlockType; // FIXME: Do not use cPiston class for dispenser placement! - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch()); + a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); return true; } } ; diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h index 50d8e38e0..b648248d0 100644 --- a/src/Blocks/BlockEnderchest.h +++ b/src/Blocks/BlockEnderchest.h @@ -30,7 +30,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = RotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = RotationToMetaData(a_Player->GetYaw()); return true; } diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index 6423a7cb0..779f12ee1 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -25,7 +25,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation()); + a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw()); return true; } @@ -33,7 +33,7 @@ public: virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetRotation()); + NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetYaw()); OldMetaData ^= 4; // Toggle the gate if ((OldMetaData & 1) == (NewMetaData & 1)) { diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index 5b067d7b7..693eac331 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -35,7 +35,7 @@ public: a_BlockType = m_BlockType; // FIXME: Do not use cPiston class for furnace placement! - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0); + a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0); return true; } diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp index 3e1ca1d15..88259d96e 100644 --- a/src/Blocks/BlockPiston.cpp +++ b/src/Blocks/BlockPiston.cpp @@ -60,7 +60,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta( ) { a_BlockType = m_BlockType; - a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch()); + a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch()); return true; } diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index 724241935..5187f24eb 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -86,7 +86,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation()); + a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw()); return true; } diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 1fcddd4f8..713664659 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -25,7 +25,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw()); return true; } diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index fa378e4b5..e463612f5 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -26,7 +26,7 @@ public: ) override { a_BlockType = m_BlockType; - a_BlockMeta = RotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = RotationToMetaData(a_Player->GetYaw()); switch (a_BlockFace) { case BLOCK_FACE_TOP: break; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b3af6aedd..275099540 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,10 +2,6 @@ cmake_minimum_required (VERSION 2.8.2) project (MCServer) -if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03") -endif() - include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/") include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include") diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 0735c8144..a72464ec3 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1298,6 +1298,7 @@ void cChunk::CreateBlockEntities(void) switch (BlockType) { case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENDER_CHEST: @@ -1425,6 +1426,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, switch (a_BlockType) { case E_BLOCK_CHEST: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: case E_BLOCK_ENDER_CHEST: @@ -2268,6 +2270,38 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl +bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + // The blockentity list is locked by the parent chunkmap's CS + for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2) + { + ++itr2; + if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ)) + { + continue; + } + if ((*itr)->GetBlockType() != E_BLOCK_COMMAND_BLOCK) + { + // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out + return false; + } + + // The correct block entity is here, + if (a_Callback.Item((cCommandBlockEntity *)*itr)) + { + return false; + } + return true; + } // for itr - m_BlockEntitites[] + + // Not found: + return false; +} + + + + + bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { // The blockentity list is locked by the parent chunkmap's CS diff --git a/src/Chunk.h b/src/Chunk.h index f0a50c3c4..4ac38c46c 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -40,12 +40,13 @@ class cFluidSimulatorData; class cMobCensus; class cMobSpawner; -typedef std::list<cClientHandle *> cClientHandleList; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef std::list<cClientHandle *> cClientHandleList; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; @@ -237,6 +238,9 @@ public: /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); + /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); + /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index e14090b18..5797eb453 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -1968,6 +1968,23 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot +bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + int ChunkX, ChunkZ; + int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); + if ((Chunk == NULL) && !Chunk->IsValid()) + { + return false; + } + return Chunk->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { diff --git a/src/ChunkMap.h b/src/ChunkMap.h index e688d1f93..e9d8ee30b 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -23,6 +23,7 @@ class cDropperEntity; class cDropSpenserEntity; class cFurnaceEntity; class cNoteEntity; +class cCommandBlockEntity; class cPawn; class cPickup; class cChunkDataSerializer; @@ -32,15 +33,16 @@ class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cBlockEntity> cBlockEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cDropperEntity> cDropperCallback; -typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; -typedef cItemCallback<cChunk> cChunkCallback; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cBlockEntity> cBlockEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cDropperEntity> cDropperCallback; +typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; +typedef cItemCallback<cChunk> cChunkCallback; @@ -236,6 +238,9 @@ public: /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible + /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible + /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 9348a1825..faf583fbb 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -8,6 +8,7 @@ #include "Entities/Player.h" #include "Inventory.h" #include "BlockEntities/ChestEntity.h" +#include "BlockEntities/CommandBlockEntity.h" #include "BlockEntities/SignEntity.h" #include "UI/Window.h" #include "Item.h" @@ -545,6 +546,15 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ, void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString & a_Message) { + if (a_Channel == "MC|AdvCdm") // Command block + { + const char* Data = a_Message.c_str(); + + HandleCommandBlockMessage(Data, a_Message.size()); + + return; + } + cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message); } @@ -552,6 +562,67 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString +void cClientHandle::HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length) +{ + if (a_Length < 14) + { + LOGD("Malformed MC|AdvCdm packet."); + return; + } + + cByteBuffer Buffer(a_Length); + Buffer.Write(a_Data, a_Length); + + int BlockX, BlockY, BlockZ; + + AString Command; + + char Mode; + + Buffer.ReadChar(Mode); + + switch (Mode) + { + case 0x00: + { + Buffer.ReadBEInt(BlockX); + Buffer.ReadBEInt(BlockY); + Buffer.ReadBEInt(BlockZ); + + Buffer.ReadVarUTF8String(Command); + break; + } + + default: + { + LOGD("Unhandled MC|AdvCdm packet mode."); + return; + } + } + + class cUpdateCommandBlock : + public cCommandBlockCallback + { + AString m_Command; + public: + cUpdateCommandBlock(const AString & a_Command) : m_Command(a_Command) {} + + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override + { + a_CommandBlock->SetCommand(m_Command); + return false; + } + } CmdBlockCB (Command); + + cWorld * World = m_Player->GetWorld(); + + World->DoWithCommandBlockAt(BlockX, BlockY, BlockZ, CmdBlockCB); +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", @@ -629,6 +700,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch return; } + case DIG_STATUS_DROP_STACK: + { + if (PlgMgr->CallHookPlayerTossingItem(*m_Player)) + { + // A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch) + return; + } + m_Player->TossItem(false, 64); // Toss entire slot - if there aren't enough items, the maximum will be ejected + return; + } + default: { ASSERT(!"Unhandled DIG_STATUS"); @@ -1026,7 +1108,7 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO return; } - m_Player->SetRotation (a_Rotation); + m_Player->SetYaw (a_Rotation); m_Player->SetHeadYaw (a_Rotation); m_Player->SetPitch (a_Pitch); m_Player->SetTouchGround(a_IsOnGround); @@ -1058,7 +1140,7 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_ m_Player->SetStance (a_Stance); m_Player->SetTouchGround(a_IsOnGround); m_Player->SetHeadYaw (a_Rotation); - m_Player->SetRotation (a_Rotation); + m_Player->SetYaw (a_Rotation); m_Player->SetPitch (a_Pitch); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index da2704b72..373ca9e2e 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -324,6 +324,9 @@ private: /// Handles the DIG_FINISHED dig packet: void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta); + + /// Handles the "MC|AdvCdm" plugin message + void HandleCommandBlockMessage(const char* a_Data, unsigned int a_Length); // cSocketThreads::cCallback overrides: virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client diff --git a/src/Defines.h b/src/Defines.h index cc04d8026..7a86f499e 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -85,6 +85,7 @@ enum DIG_STATUS_STARTED = 0, DIG_STATUS_CANCELLED = 1, DIG_STATUS_FINISHED = 2, + DIG_STATUS_DROP_STACK= 3, DIG_STATUS_DROP_HELD = 4, DIG_STATUS_SHOOT_EAT = 5, } ; diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 8e0d0b9a7..565c78dfd 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -263,16 +263,16 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R -void cEntity::SetRotationFromSpeed(void) +void cEntity::SetYawFromSpeed(void) { const double EPS = 0.0000001; if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS)) { // atan2() may overflow or is undefined, pick any number - SetRotation(0); + SetYaw(0); return; } - SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI); + SetYaw(atan2(m_Speed.x, m_Speed.z) * 180 / PI); } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 878e69668..91463bfd6 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -154,8 +154,7 @@ public: double GetPosX (void) const { return m_Pos.x; } double GetPosY (void) const { return m_Pos.y; } double GetPosZ (void) const { return m_Pos.z; } - const Vector3d & GetRot (void) const { return m_Rot; } - double GetRotation (void) const { return m_Rot.x; } // OBSOLETE, use GetYaw() instead + const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components double GetYaw (void) const { return m_Rot.x; } double GetPitch (void) const { return m_Rot.y; } double GetRoll (void) const { return m_Rot.z; } @@ -177,8 +176,7 @@ public: void SetPosZ (double a_PosZ); void SetPosition(double a_PosX, double a_PosY, double a_PosZ); void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); } - void SetRot (const Vector3f & a_Rot); - void SetRotation(double a_Rotation) { SetYaw(a_Rotation); } // OBSOLETE, use SetYaw() instead + void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components void SetYaw (double a_Yaw); void SetPitch (double a_Pitch); void SetRoll (double a_Roll); @@ -223,7 +221,7 @@ public: void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; } /// Sets the rotation to match the speed vector (entity goes "face-forward") - void SetRotationFromSpeed(void); + void SetYawFromSpeed(void); /// Sets the pitch to match the speed vector (entity gies "face-forward") void SetPitchFromSpeed(void); diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h index 4bbe3f352..162b74e75 100644 --- a/src/Entities/Floater.h +++ b/src/Entities/Floater.h @@ -7,21 +7,25 @@ +// tolua_begin class cFloater : public cEntity { typedef cFloater super; public: - + + //tolua_end cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, int a_PlayerID, int a_CountDownTime); virtual void SpawnOn(cClientHandle & a_Client) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - + + // tolua_begin bool CanPickup(void) const { return m_CanPickupItem; } int GetOwnerID(void) const { return m_PlayerID; } int GetAttachedMobID(void) const { return m_AttachedMobID; } + // tolua_end protected: // Position @@ -37,4 +41,4 @@ protected: // Entity IDs int m_PlayerID; int m_AttachedMobID; -} ;
\ No newline at end of file +} ; // tolua_export
\ No newline at end of file diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index ad63f848e..c8f43a3e6 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -118,6 +118,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) } } a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart + a_ClientHandle.SendEntityMetadata(*this); } @@ -212,7 +213,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) { case E_META_RAIL_ZM_ZP: // NORTHSOUTH { - SetRotation(270); + SetYaw(270); SetPosY(floor(GetPosY()) + 0.55); SetSpeedY(0); // Don't move vertically as on ground SetSpeedX(0); // Correct diagonal movement from curved rails @@ -238,7 +239,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_XM_XP: // EASTWEST { - SetRotation(180); + SetYaw(180); SetPosY(floor(GetPosY()) + 0.55); SetSpeedY(0); SetSpeedZ(0); @@ -261,7 +262,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH { - SetRotation(270); + SetYaw(270); SetSpeedX(0); if (GetSpeedZ() >= 0) @@ -283,7 +284,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH { - SetRotation(270); + SetYaw(270); SetSpeedX(0); if (GetSpeedZ() > 0) @@ -305,7 +306,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_ASCEND_XM: // ASCEND EAST { - SetRotation(180); + SetYaw(180); SetSpeedZ(0); if (GetSpeedX() >= 0) @@ -325,7 +326,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_ASCEND_XP: // ASCEND WEST { - SetRotation(180); + SetYaw(180); SetSpeedZ(0); if (GetSpeedX() > 0) @@ -345,7 +346,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST { - SetRotation(315); // Set correct rotation server side + SetYaw(315); // Set correct rotation server side SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart TestBlockCollision(a_RailMeta); @@ -357,7 +358,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST { - SetRotation(225); + SetYaw(225); SetPosY(floor(GetPosY()) + 0.55); TestBlockCollision(a_RailMeta); @@ -367,7 +368,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST { - SetRotation(135); + SetYaw(135); SetPosY(floor(GetPosY()) + 0.55); TestBlockCollision(a_RailMeta); @@ -377,7 +378,7 @@ void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) } case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST { - SetRotation(45); + SetYaw(45); SetPosY(floor(GetPosY()) + 0.55); TestBlockCollision(a_RailMeta); @@ -413,7 +414,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta) { case E_META_RAIL_ZM_ZP: // NORTHSOUTH { - SetRotation(270); + SetYaw(270); SetPosY(floor(GetPosY()) + 0.55); SetSpeedY(0); SetSpeedX(0); @@ -435,7 +436,7 @@ void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta) } case E_META_RAIL_XM_XP: // EASTWEST { - SetRotation(180); + SetYaw(180); SetPosY(floor(GetPosY()) + 0.55); SetSpeedY(0); SetSpeedZ(0); @@ -841,10 +842,12 @@ void cMinecart::Destroyed() /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cEmptyMinecart: +// cRideableMinecart: -cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) : - super(mpNone, a_X, a_Y, a_Z) +cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height) : + super(mpNone, a_X, a_Y, a_Z), + m_Content(a_Content), + m_Height(a_Height) { } @@ -852,7 +855,7 @@ cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) : -void cEmptyMinecart::OnRightClicked(cPlayer & a_Player) +void cRideableMinecart::OnRightClicked(cPlayer & a_Player) { if (m_Attachee != NULL) { diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index 1c3ea3220..a4ecb33ad 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -93,18 +93,24 @@ protected: -class cEmptyMinecart : +class cRideableMinecart : public cMinecart { typedef cMinecart super; public: - CLASS_PROTODEF(cEmptyMinecart); + CLASS_PROTODEF(cRideableMinecart); - cEmptyMinecart(double a_X, double a_Y, double a_Z); + cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height); + const cItem & GetContent(void) const {return m_Content;} + int GetBlockHeight(void) const {return m_Height;} // cEntity overrides: virtual void OnRightClicked(cPlayer & a_Player) override; +protected: + + cItem m_Content; + int m_Height; } ; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index fa6422389..c1f2456eb 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1382,16 +1382,21 @@ void cPlayer::TossItem( cItem DroppedItem(GetInventory().GetEquippedItem()); if (!DroppedItem.IsEmpty()) { - if (GetInventory().RemoveOneEquippedItem()) + char NewAmount = a_Amount; + if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount) { - DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again - Drops.push_back(DroppedItem); + NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there } + + GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount); + + DroppedItem.m_ItemCount = NewAmount; + Drops.push_back(DroppedItem); } } } double vX = 0, vY = 0, vZ = 0; - EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY); + EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); vY = -vY * 2 + 1.f; m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player } @@ -1523,7 +1528,7 @@ bool cPlayer::LoadFromDisk() Json::Value & JSON_PlayerRotation = root["rotation"]; if (JSON_PlayerRotation.size() == 3) { - SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble()); + SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble()); SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble()); SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble()); } @@ -1586,7 +1591,7 @@ bool cPlayer::SaveToDisk() JSON_PlayerPosition.append(Json::Value(GetPosZ())); Json::Value JSON_PlayerRotation; - JSON_PlayerRotation.append(Json::Value(GetRotation())); + JSON_PlayerRotation.append(Json::Value(GetYaw())); JSON_PlayerRotation.append(Json::Value(GetPitch())); JSON_PlayerRotation.append(Json::Value(GetRoll())); diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index 9e5069ba6..12ce9a303 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -206,7 +206,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve m_IsInGround(false) { SetSpeed(a_Speed); - SetRotationFromSpeed(); + SetYawFromSpeed(); SetPitchFromSpeed(); } @@ -350,7 +350,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) NewSpeed.y += m_Gravity / 20; NewSpeed *= TracerCallback.GetSlowdownCoeff(); SetSpeed(NewSpeed); - SetRotationFromSpeed(); + SetYawFromSpeed(); SetPitchFromSpeed(); // DEBUG: @@ -358,7 +358,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) m_UniqueID, GetPosX(), GetPosY(), GetPosZ(), GetSpeedX(), GetSpeedY(), GetSpeedZ(), - GetRotation(), GetPitch() + GetYaw(), GetPitch() ); } @@ -369,7 +369,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) void cProjectileEntity::SpawnOn(cClientHandle & a_Client) { // Default spawning - use the projectile kind to spawn an object: - a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch())); + a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetYaw()), ANGLE_TO_PROTO(GetPitch())); a_Client.SendEntityMetadata(*this); } @@ -402,11 +402,11 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a { SetSpeed(a_Speed); SetMass(0.1); - SetRotationFromSpeed(); + SetYawFromSpeed(); SetPitchFromSpeed(); LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), - GetRotation(), GetPitch() + GetYaw(), GetPitch() ); } diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 87c4d2c52..cfa7e9c6f 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -367,10 +367,10 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile) void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { int Seed = m_ChunkGenerator.GetSeed(); - AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); - eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")); - AStringVector Str = StringSplitAndTrim(Structures, ","); + + AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); + AStringVector Str = StringSplitAndTrim(Finishers, ","); for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr) { // Finishers, alpha-sorted: @@ -396,6 +396,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { m_FinishGens.push_back(new cFinishGenSingleBiomeSingleTopBlock(Seed, E_BLOCK_LILY_PAD, biSwampland, 4, E_BLOCK_WATER, E_BLOCK_STATIONARY_WATER)); } + else if (NoCaseCompare(*itr, "NetherClumpFoliage") == 0) + { + m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); + } else if (NoCaseCompare(*itr, "PreSimulator") == 0) { m_FinishGens.push_back(new cFinishGenPreSimulator); diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 4915e6818..02045f76a 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -13,6 +13,7 @@ #include "../Noise.h" #include "../BlockID.h" #include "../Simulator/FluidSimulator.h" // for cFluidSimulator::CanWashAway() +#include "../Simulator/FireSimulator.h" #include "../World.h" @@ -40,6 +41,125 @@ static inline bool IsWater(BLOCKTYPE a_BlockType) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFinishGenNetherClumpFoliage: + +void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc) +{ + double ChunkX = a_ChunkDesc.GetChunkX() + 0.1; // We can't devide through 0 so lets add 0.1 to all the chunk coordinates. + double ChunkZ = a_ChunkDesc.GetChunkZ() + 0.1; + + NOISE_DATATYPE Val1 = m_Noise.CubicNoise2D((float) (ChunkX * ChunkZ * 0.01f), (float) (ChunkZ / ChunkX * 0.01f)); + NOISE_DATATYPE Val2 = m_Noise.CubicNoise2D((float) (ChunkX / ChunkZ / 0.01f), (float) (ChunkZ * ChunkX / 0.01f)); + + if (Val1 < 0) + { + Val1 = -Val1; + } + + if (Val2 < 0) + { + Val2 = -Val2; + } + + int PosX, PosZ; + // Calculate PosX + if (Val1 <= 1) + { + PosX = (int) floor(Val1 * 16); + } + else + { + PosX = (int) floor(16 / Val1); + } + + // Calculate PosZ + if (Val2 <= 1) + { + PosZ = (int) floor(Val2 * 16); + } + else + { + PosZ = (int) floor(16 / Val2); + } + + for (int y = 1; y < cChunkDef::Height; y++) + { + if (a_ChunkDesc.GetBlockType(PosX, y, PosZ) != E_BLOCK_AIR) + { + continue; + } + if (!g_BlockIsSolid[a_ChunkDesc.GetBlockType(PosX, y - 1, PosZ)]) // Only place on solid blocks + { + continue; + } + + NOISE_DATATYPE BlockType = m_Noise.CubicNoise1D((float) (ChunkX * ChunkZ) / (y * 0.1f)); + if (BlockType < -0.7) + { + TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_BROWN_MUSHROOM); + } + else if (BlockType < 0) + { + TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_RED_MUSHROOM); + } + else if (BlockType < 0.7) + { + TryPlaceClump(a_ChunkDesc, PosX, y, PosZ, E_BLOCK_FIRE); + } + } +} + + + + + +void cFinishGenNetherClumpFoliage::TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block) +{ + bool IsFireBlock = a_Block == E_BLOCK_FIRE; + + for (int x = a_RelX - 4; x < a_RelX + 4; x++) + { + float xx = (float) a_ChunkDesc.GetChunkX() * cChunkDef::Width + x; + for (int z = a_RelZ - 4; z < a_RelZ + 4; z++) + { + float zz = (float) a_ChunkDesc.GetChunkZ() * cChunkDef::Width + z; + for (int y = a_RelY - 2; y < a_RelY + 2; y++) + { + if (a_ChunkDesc.GetBlockType(x, y, z) != E_BLOCK_AIR) // Don't replace non air blocks. + { + continue; + } + + BLOCKTYPE BlockBelow = a_ChunkDesc.GetBlockType(x, y - 1, z); + if (!g_BlockIsSolid[BlockBelow]) // Only place on solid blocks + { + continue; + } + + if (IsFireBlock) // don't place fire on non-forever burning blocks. + { + if (!cFireSimulator::DoesBurnForever(BlockBelow)) + { + continue; + } + } + + + NOISE_DATATYPE Val = m_Noise.CubicNoise2D(xx, zz); + if (Val < -0.70) + { + a_ChunkDesc.SetBlockType(x, y, z, a_Block); + } + } + } + } +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cFinishGenSprinkleFoliage: bool cFinishGenSprinkleFoliage::TryAddSugarcane(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ) diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index d89ffed15..2e5732929 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -47,6 +47,28 @@ protected: +class cFinishGenNetherClumpFoliage : + public cFinishGen +{ +public: + cFinishGenNetherClumpFoliage(int a_Seed) : + m_Noise(a_Seed), + m_Seed(a_Seed) + { + } + +protected: + cNoise m_Noise; + int m_Seed; + + void TryPlaceClump(cChunkDesc & a_ChunkDesc, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block); + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; +} ; + + + + + class cFinishGenSprinkleFoliage : public cFinishGen { @@ -117,6 +139,7 @@ public: { } + int GetLevel(void) const { return m_Level; } protected: int m_Level; diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index 3d30ab177..a4af706f2 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -205,6 +205,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) { m_State = wcsRecvIdle; m_HTTPServer.RequestFinished(*this, *m_CurrentRequest); + if (!m_CurrentRequest->DoesAllowKeepAlive()) + { + m_State = wcsInvalid; + m_HTTPServer.CloseConnection(*this); + return; + } delete m_CurrentRequest; m_CurrentRequest = NULL; } diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h index 00941f2ae..5b8103554 100644 --- a/src/HTTPServer/HTTPConnection.h +++ b/src/HTTPServer/HTTPConnection.h @@ -41,49 +41,52 @@ public: cHTTPConnection(cHTTPServer & a_HTTPServer); virtual ~cHTTPConnection(); - /// Sends HTTP status code together with a_Reason (used for HTTP errors) + /** Sends HTTP status code together with a_Reason (used for HTTP errors) */ void SendStatusAndReason(int a_StatusCode, const AString & a_Reason); - /// Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm + /** Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified realm */ void SendNeedAuth(const AString & a_Realm); - /// Sends the headers contained in a_Response + /** Sends the headers contained in a_Response */ void Send(const cHTTPResponse & a_Response); - /// Sends the data as the response (may be called multiple times) + /** Sends the data as the response (may be called multiple times) */ void Send(const void * a_Data, int a_Size); - /// Sends the data as the response (may be called multiple times) + /** Sends the data as the response (may be called multiple times) */ void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); } - /// Indicates that the current response is finished, gets ready for receiving another request (HTTP 1.1 keepalive) + /** Indicates that the current response is finished, gets ready for receiving another request (HTTP 1.1 keepalive) */ void FinishResponse(void); - /// Resets the connection for a new request. Depending on the state, this will send an "InternalServerError" status or a "ResponseEnd" + /** Resets the internal connection state for a new request. + Depending on the state, this will send an "InternalServerError" status or a "ResponseEnd" */ void AwaitNextRequest(void); - /// Terminates the connection; finishes any request being currently processed + /** Terminates the connection; finishes any request being currently processed */ void Terminate(void); protected: typedef std::map<AString, AString> cNameValueMap; - /// The parent webserver that is to be notified of events on this connection + /** The parent webserver that is to be notified of events on this connection */ cHTTPServer & m_HTTPServer; - /// All the incoming data until the entire request header is parsed + /** All the incoming data until the entire request header is parsed */ AString m_IncomingHeaderData; - /// Status in which the request currently is + /** Status in which the request currently is */ eState m_State; - /// Data that is queued for sending, once the socket becomes writable + /** Data that is queued for sending, once the socket becomes writable */ AString m_OutgoingData; - /// The request being currently received (valid only between having parsed the headers and finishing receiving the body) + /** The request being currently received + Valid only between having parsed the headers and finishing receiving the body. */ cHTTPRequest * m_CurrentRequest; - /// Number of bytes that remain to read for the complete body of the message to be received. Valid only in wcsRecvBody + /** Number of bytes that remain to read for the complete body of the message to be received. + Valid only in wcsRecvBody */ int m_CurrentRequestBodyRemaining; diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index ab23866e6..98627eb8e 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -72,7 +72,8 @@ cHTTPRequest::cHTTPRequest(void) : m_EnvelopeParser(*this), m_IsValid(true), m_UserData(NULL), - m_HasAuth(false) + m_HasAuth(false), + m_AllowKeepAlive(false) { } @@ -236,6 +237,10 @@ void cHTTPRequest::OnHeaderLine(const AString & a_Key, const AString & a_Value) m_HasAuth = true; } } + if ((a_Key == "Connection") && (NoCaseCompare(a_Value, "keep-alive") == 0)) + { + m_AllowKeepAlive = true; + } AddHeader(a_Key, a_Value); } diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h index 2a4c2879e..ab3338db7 100644 --- a/src/HTTPServer/HTTPMessage.h +++ b/src/HTTPServer/HTTPMessage.h @@ -35,7 +35,7 @@ public: // Force a virtual destructor in all descendants virtual ~cHTTPMessage() {}; - /// Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length + /** Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length */ void AddHeader(const AString & a_Key, const AString & a_Value); void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; } @@ -51,10 +51,10 @@ protected: cNameValueMap m_Headers; - /// Type of the content; parsed by AddHeader(), set directly by SetContentLength() + /** Type of the content; parsed by AddHeader(), set directly by SetContentLength() */ AString m_ContentType; - /// Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() + /** Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() */ int m_ContentLength; } ; @@ -76,64 +76,71 @@ public: */ int ParseHeaders(const char * a_Data, int a_Size); - /// Returns true if the request did contain a Content-Length header + /** Returns true if the request did contain a Content-Length header */ bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } - /// Returns the method used in the request + /** Returns the method used in the request */ const AString & GetMethod(void) const { return m_Method; } - /// Returns the URL used in the request + /** Returns the URL used in the request */ const AString & GetURL(void) const { return m_URL; } - /// Returns the URL used in the request, without any parameters + /** Returns the URL used in the request, without any parameters */ AString GetBareURL(void) const; - /// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)! + /** Sets the UserData pointer that is stored within this request. + The request doesn't touch this data (doesn't delete it)! */ void SetUserData(void * a_UserData) { m_UserData = a_UserData; } - /// Retrieves the UserData pointer that has been stored within this request. + /** Retrieves the UserData pointer that has been stored within this request. */ void * GetUserData(void) const { return m_UserData; } - /// Returns true if more data is expected for the request headers + /** Returns true if more data is expected for the request headers */ bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); } - /// Returns true if the request did present auth data that was understood by the parser + /** Returns true if the request did present auth data that was understood by the parser */ bool HasAuth(void) const { return m_HasAuth; } - /// Returns the username that the request presented. Only valid if HasAuth() is true + /** Returns the username that the request presented. Only valid if HasAuth() is true */ const AString & GetAuthUsername(void) const { return m_AuthUsername; } - /// Returns the password that the request presented. Only valid if HasAuth() is true + /** Returns the password that the request presented. Only valid if HasAuth() is true */ const AString & GetAuthPassword(void) const { return m_AuthPassword; } + bool DoesAllowKeepAlive(void) const { return m_AllowKeepAlive; } + protected: - /// Parser for the envelope data + /** Parser for the envelope data */ cEnvelopeParser m_EnvelopeParser; - /// True if the data received so far is parsed successfully. When false, all further parsing is skipped + /** True if the data received so far is parsed successfully. When false, all further parsing is skipped */ bool m_IsValid; - /// Bufferred incoming data, while parsing for the request line + /** Bufferred incoming data, while parsing for the request line */ AString m_IncomingHeaderData; - /// Method of the request (GET / PUT / POST / ...) + /** Method of the request (GET / PUT / POST / ...) */ AString m_Method; - /// Full URL of the request + /** Full URL of the request */ AString m_URL; - /// Data that the HTTPServer callbacks are allowed to store. + /** Data that the HTTPServer callbacks are allowed to store. */ void * m_UserData; - /// Set to true if the request contains auth data that was understood by the parser + /** Set to true if the request contains auth data that was understood by the parser */ bool m_HasAuth; - /// The username used for auth + /** The username used for auth */ AString m_AuthUsername; - /// The password used for auth + /** The password used for auth */ AString m_AuthPassword; + /** Set to true if the request indicated that it supports keepalives. + If false, the server will close the connection once the request is finished */ + bool m_AllowKeepAlive; + /** Parses the incoming data for the first line (RequestLine) Returns the number of bytes consumed, or -1 for an error diff --git a/src/Inventory.cpp b/src/Inventory.cpp index a7f77cf6d..0e1cedc85 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -83,7 +83,7 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int { NumLeft -= MaxStack; } - else if (Slot.IsStackableWith(a_ItemStack)) + else if (Slot.IsEqual(a_ItemStack)) { NumLeft -= MaxStack - Slot.m_ItemCount; } diff --git a/src/Item.cpp b/src/Item.cpp index a44515019..9170006b6 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -91,28 +91,6 @@ bool cItem::DamageItem(short a_Amount) -bool cItem::IsStackableWith(const cItem & a_OtherStack) const -{ - if (a_OtherStack.m_ItemType != m_ItemType) - { - return false; - } - if (a_OtherStack.m_ItemDamage != m_ItemDamage) - { - return false; - } - if (a_OtherStack.m_Enchantments != m_Enchantments) - { - return false; - } - - return true; -} - - - - - bool cItem::IsFullStack(void) const { return (m_ItemCount >= ItemHandler(m_ItemType)->GetMaxStackSize()); @@ -153,6 +131,14 @@ void cItem::GetJson(Json::Value & a_OutValue) const { a_OutValue["ench"] = Enchantments; } + if (!IsCustomNameEmpty()) + { + a_OutValue["Name"] = m_CustomName; + } + if (!IsLoreEmpty()) + { + a_OutValue["Lore"] = m_Lore; + } } } @@ -169,6 +155,8 @@ void cItem::FromJson(const Json::Value & a_Value) m_ItemDamage = (short)a_Value.get("Health", -1 ).asInt(); m_Enchantments.Clear(); m_Enchantments.AddFromString(a_Value.get("ench", "").asString()); + m_CustomName = a_Value.get("Name", "").asString(); + m_Lore = a_Value.get("Lore", "").asString(); } } diff --git a/src/Item.h b/src/Item.h index 64a30ade1..727965112 100644 --- a/src/Item.h +++ b/src/Item.h @@ -36,7 +36,9 @@ public: cItem(void) : m_ItemType(E_ITEM_EMPTY), m_ItemCount(0), - m_ItemDamage(0) + m_ItemDamage(0), + m_CustomName(""), + m_Lore("") { } @@ -46,12 +48,16 @@ public: short a_ItemType, char a_ItemCount = 1, short a_ItemDamage = 0, - const AString & a_Enchantments = "" + const AString & a_Enchantments = "", + const AString & a_CustomName = "", + const AString & a_Lore = "" ) : m_ItemType (a_ItemType), m_ItemCount (a_ItemCount), m_ItemDamage (a_ItemDamage), - m_Enchantments(a_Enchantments) + m_Enchantments(a_Enchantments), + m_CustomName (a_CustomName), + m_Lore (a_Lore) { if (!IsValidItem(m_ItemType)) { @@ -69,7 +75,9 @@ public: m_ItemType (a_CopyFrom.m_ItemType), m_ItemCount (a_CopyFrom.m_ItemCount), m_ItemDamage (a_CopyFrom.m_ItemDamage), - m_Enchantments(a_CopyFrom.m_Enchantments) + m_Enchantments(a_CopyFrom.m_Enchantments), + m_CustomName (a_CopyFrom.m_CustomName), + m_Lore (a_CopyFrom.m_Lore) { } @@ -80,6 +88,8 @@ public: m_ItemCount = 0; m_ItemDamage = 0; m_Enchantments.Clear(); + m_CustomName = ""; + m_Lore = ""; } @@ -96,13 +106,16 @@ public: return ((m_ItemType <= 0) || (m_ItemCount <= 0)); } - + /* Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored! + */ bool IsEqual(const cItem & a_Item) const { return ( IsSameType(a_Item) && (m_ItemDamage == a_Item.m_ItemDamage) && - (m_Enchantments == a_Item.m_Enchantments) + (m_Enchantments == a_Item.m_Enchantments) && + (m_CustomName == a_Item.m_CustomName) && + (m_Lore == a_Item.m_Lore) ); } @@ -111,7 +124,16 @@ public: { return (m_ItemType == a_Item.m_ItemType) || (IsEmpty() && a_Item.IsEmpty()); } - + + + bool IsBothNameAndLoreEmpty(void) const + { + return (m_CustomName.empty() && m_Lore.empty()); + } + + + bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); } + bool IsLoreEmpty(void) const { return (m_Lore.empty()); } /// Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items cItem CopyOne(void) const; @@ -127,9 +149,6 @@ public: inline bool IsDamageable(void) const { return (GetMaxDamage() > 0); } - /// Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored! - bool IsStackableWith(const cItem & a_OtherStack) const; - /// Returns true if the item is stacked up to its maximum stacking. bool IsFullStack(void) const; @@ -155,6 +174,8 @@ public: short m_ItemType; char m_ItemCount; short m_ItemDamage; + AString m_CustomName; + AString m_Lore; cEnchantments m_Enchantments; }; // tolua_end diff --git a/src/ItemGrid.cpp b/src/ItemGrid.cpp index d2e6b1c69..e8b58695f 100644 --- a/src/ItemGrid.cpp +++ b/src/ItemGrid.cpp @@ -226,7 +226,7 @@ int cItemGrid::HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks) NumLeft -= MaxStack; } } - else if (m_Slots[i].IsStackableWith(a_ItemStack)) + else if (m_Slots[i].IsEqual(a_ItemStack)) { NumLeft -= MaxStack - m_Slots[i].m_ItemCount; } @@ -275,7 +275,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit (a_PrioritarySlot != -1) && ( m_Slots[a_PrioritarySlot].IsEmpty() || - m_Slots[a_PrioritarySlot].IsStackableWith(a_ItemStack) + m_Slots[a_PrioritarySlot].IsEqual(a_ItemStack) ) ) { @@ -285,7 +285,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit // Scan existing stacks: for (int i = m_NumSlots - 1; i >= 0; i--) { - if (m_Slots[i].IsStackableWith(a_ItemStack)) + if (m_Slots[i].IsEqual(a_ItemStack)) { NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack); } @@ -438,7 +438,7 @@ int cItemGrid::HowManyItems(const cItem & a_Item) int res = 0; for (int i = 0; i < m_NumSlots; i++) { - if (m_Slots[i].IsStackableWith(a_Item)) + if (m_Slots[i].IsEqual(a_Item)) { res += m_Slots[i].m_ItemCount; } diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h index ab4182eea..9b7c8bff8 100644 --- a/src/Items/ItemBed.h +++ b/src/Items/ItemBed.h @@ -37,7 +37,7 @@ public: return false; } - a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetYaw()); // Check if there is empty space for the foot section: Vector3i Direction = cBlockBedHandler::MetaDataToDirection(a_BlockMeta); diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h index 3fbb7603d..3a5d1d200 100644 --- a/src/Items/ItemComparator.h +++ b/src/Items/ItemComparator.h @@ -30,7 +30,7 @@ public: ) override { a_BlockType = E_BLOCK_INACTIVE_COMPARATOR; - a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw()); return true; } } ; diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index f8eb31a49..4071f8c60 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -60,7 +60,7 @@ public: cMinecart * Minecart = NULL; switch (m_ItemType) { - case E_ITEM_MINECART: Minecart = new cEmptyMinecart (x, y, z); break; + case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break; case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break; case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break; case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break; diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h index f69f24eb8..e71c8e672 100644 --- a/src/Items/ItemRedstoneRepeater.h +++ b/src/Items/ItemRedstoneRepeater.h @@ -30,7 +30,7 @@ public: ) override { a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF; - a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw()); return true; } } ; diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h index 5ccd79e29..8c134ab83 100644 --- a/src/Items/ItemSign.h +++ b/src/Items/ItemSign.h @@ -34,7 +34,7 @@ public: { if (a_BlockFace == BLOCK_FACE_TOP) { - a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetRotation()); + a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetYaw()); a_BlockType = E_BLOCK_SIGN_POST; } else diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 76df76633..98b6c1d28 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -208,7 +208,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) Distance.Normalize(); VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch ); SetHeadYaw (Rotation); - SetRotation( Rotation ); + SetYaw( Rotation ); SetPitch( -Pitch ); } diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 48c085ae5..323a13992 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -354,8 +354,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256)); - WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -423,8 +423,8 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, WriteByte(a_RelX); WriteByte(a_RelY); WriteByte(a_RelZ); - WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256)); - WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -664,7 +664,7 @@ void cProtocol125::SendPlayerMoveLook(void) WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block WriteDouble(Player->GetPosZ()); - WriteFloat ((float)(Player->GetRotation())); + WriteFloat ((float)(Player->GetYaw())); WriteFloat ((float)(Player->GetPitch())); WriteBool (Player->IsOnGround()); Flush(); @@ -694,8 +694,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256)); - WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256)); + WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256)); + WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256)); WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); Flush(); } @@ -864,7 +864,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp WriteInt ((int)(a_Vehicle.GetPosY() * 32)); WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); - WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256)); + WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256)); WriteInt (a_VehicleSubType); if (a_VehicleSubType != 0) { @@ -897,7 +897,7 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity) WriteInt ((int)(floor(a_Entity.GetPosX() * 32))); WriteInt ((int)(floor(a_Entity.GetPosY() * 32))); WriteInt ((int)(floor(a_Entity.GetPosZ() * 32))); - WriteByte ((char)((a_Entity.GetRotation() / 360.f) * 256)); + WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256)); WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index 302d1298c..29fbb4bba 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -367,8 +367,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player) WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256)); - WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256)); + WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256)); + WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256)); WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); // Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata: WriteByte (0); // Index 0, byte (flags) @@ -421,8 +421,8 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob) WriteInt (a_Mob.GetUniqueID()); WriteByte (a_Mob.GetMobType()); WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); - WriteByte ((Byte)((a_Mob.GetRotation() / 360.f) * 256)); - WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256)); + WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256)); + WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256)); WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256)); WriteShort ((short)(a_Mob.GetSpeedX() * 400)); WriteShort ((short)(a_Mob.GetSpeedY() * 400)); diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp index 926fe6ee8..127ce9d4b 100644 --- a/src/Protocol/Protocol14x.cpp +++ b/src/Protocol/Protocol14x.cpp @@ -250,7 +250,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp WriteInt ((int)(a_Vehicle.GetPosY() * 32)); WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256)); - WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256)); + WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256)); WriteInt (a_VehicleSubType); if (a_VehicleSubType != 0) { diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 93621fcc2..5b3a79555 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -1040,7 +1040,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) if (!HandlePacket(bb, PacketType)) { // Unknown packet, already been reported, but without the length. Log the length here: - LOGWARNING("Unhandled packet: type 0x%x, length %u", PacketType, PacketLen); + LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen); #ifdef _DEBUG // Dump the packet contents into the log: @@ -1059,8 +1059,8 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) if (bb.GetReadableSpace() != 1) { // Read more or less than packet length, report as error - LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x. Read %u bytes, packet contained %u bytes", - PacketType, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen + LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes", + PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen ); ASSERT(!"Read wrong number of bytes!"); m_Client->PacketError(PacketType); @@ -1128,9 +1128,26 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) } break; } + default: + { + // Received a packet in an unknown state, report: + LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State); + + // Cannot kick the client - we don't know this state and thus the packet number for the kick packet + + // Switch to a state when all further packets are silently ignored: + m_State = 255; + return false; + } + case 255: + { + // This is the state used for "not processing packets anymore" when we receive a bad packet from a client. + // Do not output anything (the caller will do that for us), just return failure + return false; + } } // switch (m_State) - // Unknown packet type, report to the client: + // Unknown packet type, report to the ClientHandle: m_Client->PacketUnknown(a_PacketType); return false; } @@ -1668,7 +1685,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) return; } - // Load enchantments from the NBT: + // Load enchantments and custom display names from the NBT data: for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag)) { if ( @@ -1681,6 +1698,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) { a_Item.m_Enchantments.ParseFromNBT(NBT, tag); } + else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag + { + for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag)) + { + if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag + { + a_Item.m_CustomName = NBT.GetString(displaytag); + } + else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag + { + AString Lore; + + for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings + { + AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;) + } + + a_Item.m_Lore = Lore; + } + } + } } } @@ -1732,16 +1770,45 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) WriteByte (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); - if (a_Item.m_Enchantments.IsEmpty()) + if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty()) { WriteShort(-1); return; } - // Send the enchantments: + // Send the enchantments and custom names: cFastNBTWriter Writer; - const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; - a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + if (!a_Item.m_Enchantments.IsEmpty()) + { + const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; + a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName); + } + if (!a_Item.IsBothNameAndLoreEmpty()) + { + Writer.BeginCompound("display"); + if (!a_Item.IsCustomNameEmpty()) + { + Writer.AddString("Name", a_Item.m_CustomName.c_str()); + } + if (!a_Item.IsLoreEmpty()) + { + Writer.BeginList("Lore", TAG_String); + + AStringVector Decls = StringSplit(a_Item.m_Lore, "`"); + for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr) + { + if (itr->empty()) + { + // The decl is empty (two `s), ignore + continue; + } + Writer.AddString("", itr->c_str()); + } + + Writer.EndList(); + } + Writer.EndCompound(); + } Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); @@ -1823,8 +1890,23 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteInt(1); // Shaking direction, doesn't seem to affect anything WriteByte(0x73); WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer - - if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace) + + if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone) + { + cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity); + if (!RideableMinecart.GetContent().IsEmpty()) + { + WriteByte(0x54); + int Content = RideableMinecart.GetContent().m_ItemType; + Content |= RideableMinecart.GetContent().m_ItemDamage << 8; + WriteInt(Content); + WriteByte(0x55); + WriteInt(RideableMinecart.GetBlockHeight()); + WriteByte(0x56); + WriteByte(1); + } + } + else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace) { WriteByte(0x10); WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0); diff --git a/src/Server.cpp b/src/Server.cpp index 49067c17f..5280270b9 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -459,7 +459,7 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac { return; } - + // Special handling: "stop" and "restart" are built in if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0)) { diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index 469680098..e361cbf49 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -4,6 +4,7 @@ #include "RedstoneSimulator.h" #include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/NoteEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../Entities/TNTEntity.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" @@ -215,11 +216,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c { case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; + case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break; + case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break; case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: @@ -763,6 +765,29 @@ void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + class cSetPowerToCommandBlock : + public cCommandBlockCallback + { + bool m_IsPowered; + public: + cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {} + + virtual bool Item(cCommandBlockEntity * a_CommandBlock) override + { + a_CommandBlock->SetRedstonePower(m_IsPowered); + return false; + } + } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + + m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP); +} + + + + + void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) { switch (a_MyType) diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 63a5be3d3..bb2efeb8a 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -110,6 +110,8 @@ private: void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); /** Handles doords */ void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + /** Handles command blocks */ + void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /** Handles activator, detector, and powered rails */ void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /** Handles trapdoors */ @@ -166,6 +168,7 @@ private: switch (Block) { case E_BLOCK_ACTIVATOR_RAIL: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_PISTON: case E_BLOCK_STICKY_PISTON: case E_BLOCK_DISPENSER: @@ -220,6 +223,7 @@ private: case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_ACTIVE_COMPARATOR: case E_BLOCK_BLOCK_OF_REDSTONE: + case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DISPENSER: case E_BLOCK_DAYLIGHT_SENSOR: diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index e15058840..5b9a3bb0a 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -11,7 +11,7 @@ /// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2() -int CompressString(const char * a_Data, int a_Length, AString & a_Compressed) +int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor) { uLongf CompressedSize = compressBound(a_Length); @@ -19,7 +19,7 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed) // It saves us one allocation and one memcpy of the entire compressed data // It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010) a_Compressed.resize(CompressedSize); - int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, Z_DEFAULT_COMPRESSION); + int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor); if (errorcode != Z_OK) { return errorcode; diff --git a/src/StringCompression.h b/src/StringCompression.h index 459e8f568..3f4e12d2d 100644 --- a/src/StringCompression.h +++ b/src/StringCompression.h @@ -10,7 +10,7 @@ /// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2() -extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed); +extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor); /// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress() extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize); diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index a721e6b7e..bfcad3d92 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -85,10 +85,10 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA { if (DraggingItem.m_ItemType <= 0) // Empty-handed? { + DraggingItem = Slot.CopyOne(); // Obtain copy of slot to preserve lore, enchantments, etc. + DraggingItem.m_ItemCount = (char)(((float)Slot.m_ItemCount) / 2.f + 0.5f); Slot.m_ItemCount -= DraggingItem.m_ItemCount; - DraggingItem.m_ItemType = Slot.m_ItemType; - DraggingItem.m_ItemDamage = Slot.m_ItemDamage; if (Slot.m_ItemCount <= 0) { @@ -101,9 +101,12 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA cItemHandler * Handler = ItemHandler(Slot.m_ItemType); if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Handler->GetMaxStackSize())) { - Slot.m_ItemType = DraggingItem.m_ItemType; - Slot.m_ItemCount++; - Slot.m_ItemDamage = DraggingItem.m_ItemDamage; + char OldSlotCount = Slot.m_ItemCount; + + Slot = DraggingItem.CopyOne(); // See above + OldSlotCount++; + Slot.m_ItemCount = OldSlotCount; + DraggingItem.m_ItemCount--; } if (DraggingItem.m_ItemCount <= 0) @@ -226,7 +229,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ for (int i = 0; i < m_NumSlots; i++) { const cItem * Slot = GetSlot(i, a_Player); - if (!Slot->IsStackableWith(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) + if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) { // Different items continue; @@ -265,7 +268,7 @@ bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool for (int i = 0; i < NumSlots; i++) { const cItem & SlotItem = *GetSlot(i, a_Player); - if (!SlotItem.IsStackableWith(a_Dragging)) + if (!SlotItem.IsEqual(a_Dragging)) { continue; } @@ -908,7 +911,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End) } // for i - itr->second[] double vX = 0, vY = 0, vZ = 0; - EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY); + EulerToVector(-a_Player.GetYaw(), a_Player.GetPitch(), vZ, vX, vY); vY = -vY * 2 + 1.f; a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because player created } diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index ee75921d1..3ffeff7a0 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -642,7 +642,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int Area->SetSlot(LocalSlotNum, a_Player, ToStore); NumDistributed += ToStore.m_ItemCount; } - else if (AtSlot.IsStackableWith(a_Item)) + else if (AtSlot.IsEqual(a_Item)) { // Occupied, add and cap at MaxStack: int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount); diff --git a/src/World.cpp b/src/World.cpp index 2b85e4b58..8e7b6171c 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -16,6 +16,7 @@ // Entities (except mobs): #include "Entities/ExpOrb.h" #include "Entities/FallingBlock.h" +#include "Entities/Minecart.h" #include "Entities/Pickup.h" #include "Entities/Player.h" #include "Entities/TNTEntity.h" @@ -230,6 +231,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_WorldName(a_WorldName), m_IniFileName(m_WorldName + "/world.ini"), m_StorageSchema("Default"), + m_StorageCompressionFactor(6), m_IsSpawnExplicitlySet(false), m_WorldAgeSecs(0), m_TimeOfDaySecs(0), @@ -511,6 +513,7 @@ void cWorld::Start(void) } m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema); + m_StorageCompressionFactor = IniFile.GetValueSetI ("Storage", "CompressionFactor", m_StorageCompressionFactor); m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3); m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3); m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false); @@ -584,7 +587,7 @@ void cWorld::Start(void) m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1); m_Lighting.Start(this); - m_Storage.Start(this, m_StorageSchema); + m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor ); m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile); m_ChunkSender.Start(this); m_TickThread.Start(); @@ -1146,6 +1149,15 @@ bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl +bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback) +{ + return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); +} + + + + + bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4) { return m_ChunkMap->GetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4); @@ -1673,6 +1685,29 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) +int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight) +{ + cMinecart * Minecart; + switch (a_MinecartType) + { + case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break; + case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break; + case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break; + case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break; + default: + { + return -1; + } + } // switch (a_MinecartType) + Minecart->Initialize(this); + return Minecart->GetUniqueID(); +} + + + + + void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff) { UNUSED(a_InitialVelocityCoeff); @@ -2740,9 +2775,6 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp { Monster->SetPosition(a_PosX, a_PosY, a_PosZ); } - - // Because it's logical that ALL mob spawns need spawn effects, not just spawners - BroadcastSoundParticleEffect(2004, (int)a_PosX, (int)a_PosY, (int)a_PosZ, 0); return SpawnMobFinalize(Monster); } diff --git a/src/World.h b/src/World.h index 6ddb3ec86..1a7ad0cb1 100644 --- a/src/World.h +++ b/src/World.h @@ -46,12 +46,13 @@ class cMobCensus; typedef std::list< cPlayer * > cPlayerList; -typedef cItemCallback<cPlayer> cPlayerListCallback; -typedef cItemCallback<cEntity> cEntityCallback; -typedef cItemCallback<cChestEntity> cChestCallback; -typedef cItemCallback<cDispenserEntity> cDispenserCallback; -typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; -typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cPlayer> cPlayerListCallback; +typedef cItemCallback<cEntity> cEntityCallback; +typedef cItemCallback<cChestEntity> cChestCallback; +typedef cItemCallback<cDispenserEntity> cDispenserCallback; +typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cNoteEntity> cNoteBlockCallback; +typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback; @@ -374,6 +375,9 @@ public: /// Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta); + /// Spawns an minecart at the given coordinates. + int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1); + /// Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb. int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward); @@ -463,6 +467,9 @@ public: /// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp + + /// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found + bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp @@ -678,6 +685,8 @@ private: /// Name of the storage schema used to load and save chunks AString m_StorageSchema; + int m_StorageCompressionFactor; + /// The dimension of the world, used by the client to provide correct lighting scheme eDimension m_Dimension; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e5043de1f..447296c7f 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -10,6 +10,7 @@ #include "FastNBT.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -219,8 +220,23 @@ void cNBTChunkSerializer::AddJukeboxEntity(cJukeboxEntity * a_Jukebox) void cNBTChunkSerializer::AddNoteEntity(cNoteEntity * a_Note) { m_Writer.BeginCompound(""); - AddBasicTileEntity(a_Note, "Music"); - m_Writer.AddByte("note", a_Note->GetPitch()); + AddBasicTileEntity(a_Note, "Music"); + m_Writer.AddByte("note", a_Note->GetPitch()); + m_Writer.EndCompound(); +} + + + + + +void cNBTChunkSerializer::AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock) +{ + m_Writer.BeginCompound(""); + AddBasicTileEntity(a_CmdBlock, "Control"); + m_Writer.AddString("Command", a_CmdBlock->GetCommand()); + m_Writer.AddInt ("SuccessCount", a_CmdBlock->GetResult()); + m_Writer.AddString("LastOutput", a_CmdBlock->GetLastOutput()); + m_Writer.AddByte ("TrackOutput", 1); // TODO 2014-01-18 xdot: Figure out what TrackOutput is and save it. m_Writer.EndCompound(); } @@ -257,7 +273,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C m_Writer.AddDouble("", a_Entity->GetSpeedZ()); m_Writer.EndList(); m_Writer.BeginList("Rotation", TAG_Double); - m_Writer.AddDouble("", a_Entity->GetRotation()); + m_Writer.AddDouble("", a_Entity->GetYaw()); m_Writer.AddDouble("", a_Entity->GetPitch()); m_Writer.EndList(); } @@ -639,15 +655,16 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity) // Add tile-entity into NBT: switch (a_Entity->GetBlockType()) { - case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; - case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; - case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; - case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; - case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; + case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; + case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; + case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; + case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; + case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; case E_BLOCK_SIGN_POST: - case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; - case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; - case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; + case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; + case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; + case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; + case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break; default: { ASSERT(!"Unhandled block entity saved into Anvil"); diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 9d4ac208c..245b68063 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -21,6 +21,7 @@ class cEntity; class cBlockEntity; class cBoat; class cChestEntity; +class cCommandBlockEntity; class cDispenserEntity; class cDropperEntity; class cFurnaceEntity; @@ -92,6 +93,7 @@ protected: void AddJukeboxEntity (cJukeboxEntity * a_Jukebox); void AddNoteEntity (cNoteEntity * a_Note); void AddSignEntity (cSignEntity * a_Sign); + void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock); // Entities: void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName); diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 8605930b6..96a77152b 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -15,6 +15,7 @@ #include "../StringCompression.h" #include "../BlockEntities/ChestEntity.h" +#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/DispenserEntity.h" #include "../BlockEntities/DropperEntity.h" #include "../BlockEntities/FurnaceEntity.h" @@ -58,8 +59,9 @@ Since only the header is actually in the memory, this number can be high, but st /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWSSAnvil: -cWSSAnvil::cWSSAnvil(cWorld * a_World) : - super(a_World) +cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : + super(a_World), + m_CompressionFactor(a_CompressionFactor) { // Create a level.dat file for mapping tools, if it doesn't already exist: AString fnam; @@ -272,7 +274,7 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data) } Writer.Finish(); - CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data); + CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data, m_CompressionFactor); return true; } @@ -566,6 +568,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con { LoadChestFromNBT(a_BlockEntities, a_NBT, Child); } + else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0) + { + LoadCommandBlockFromNBT(a_BlockEntities, a_NBT, Child); + } else if (strncmp(a_NBT.GetData(sID), "Dropper", a_NBT.GetDataLength(sID)) == 0) { LoadDropperFromNBT(a_BlockEntities, a_NBT, Child); @@ -914,6 +920,43 @@ void cWSSAnvil::LoadSignFromNBT(cBlockEntityList & a_BlockEntities, const cParse +void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) +{ + ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); + int x, y, z; + if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z)) + { + return; + } + std::auto_ptr<cCommandBlockEntity> CmdBlock(new cCommandBlockEntity(x, y, z, m_World)); + + int currentLine = a_NBT.FindChildByName(a_TagIdx, "Command"); + if (currentLine >= 0) + { + CmdBlock->SetCommand(a_NBT.GetString(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "SuccessCount"); + if (currentLine >= 0) + { + CmdBlock->SetResult(a_NBT.GetInt(currentLine)); + } + + currentLine = a_NBT.FindChildByName(a_TagIdx, "LastOutput"); + if (currentLine >= 0) + { + CmdBlock->SetLastOutput(a_NBT.GetString(currentLine)); + } + + // TODO 2014-01-18 xdot: Figure out what TrackOutput is and parse it. + + a_BlockEntities.push_back(CmdBlock.release()); +} + + + + + void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) { if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0) @@ -1150,7 +1193,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cEmptyMinecart> Minecart(new cEmptyMinecart(0, 0, 0)); + std::auto_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx)) { return; @@ -1891,7 +1934,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N { return false; } - a_Entity.SetRotation(Rotation[0]); + a_Entity.SetYaw(Rotation[0]); a_Entity.SetRoll (Rotation[1]); return true; diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 0a7406267..5093ad083 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -47,7 +47,7 @@ class cWSSAnvil : public: - cWSSAnvil(cWorld * a_World); + cWSSAnvil(cWorld * a_World, int a_CompressionFactor); virtual ~cWSSAnvil(); protected: @@ -89,6 +89,8 @@ protected: cCriticalSection m_CS; cMCAFiles m_Files; // a MRU cache of MCA files + + int m_CompressionFactor; /// Gets chunk data from the correct file; locks file CS as needed bool GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data); @@ -129,14 +131,15 @@ protected: */ void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); - void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); - void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas); + void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadNoteFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadSignFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); + void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index e2556b96e..ea17a8ec1 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -193,7 +193,7 @@ cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk) // Load it anew: AString FileName; Printf(FileName, "%s/X%i_Z%i.pak", m_World->GetName().c_str(), LayerX, LayerZ ); - cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ); + cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ, m_CompressionFactor); if (f == NULL) { return NULL; @@ -399,8 +399,9 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En return; \ } -cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ) : +cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor) : m_FileName(a_FileName), + m_CompressionFactor(a_CompressionFactor), m_LayerX(a_LayerX), m_LayerZ(a_LayerZ), m_NumDirty(0), @@ -648,7 +649,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() // Re-compress data AString CompressedData; { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData); + int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor); if (errorcode != Z_OK) { LOGERROR("Error %d compressing data for chunk [%d, %d]", @@ -786,7 +787,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() // Re-compress data AString CompressedData; { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData); + int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor); if (errorcode != Z_OK) { LOGERROR("Error %d compressing data for chunk [%d, %d]", @@ -939,7 +940,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld // Compress the data: AString CompressedData; - int errorcode = CompressString(Data.data(), Data.size(), CompressedData); + int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor); if ( errorcode != Z_OK ) { LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ); diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h index 3223a986e..64b8d7f31 100644 --- a/src/WorldStorage/WSSCompact.h +++ b/src/WorldStorage/WSSCompact.h @@ -53,7 +53,7 @@ class cWSSCompact : public cWSSchema { public: - cWSSCompact(cWorld * a_World) : cWSSchema(a_World) {} + cWSSCompact(cWorld * a_World, int a_CompressionFactor) : cWSSchema(a_World), m_CompressionFactor(a_CompressionFactor) {} virtual ~cWSSCompact(); protected: @@ -74,7 +74,7 @@ protected: { public: - cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ); + cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor); ~cPAKFile(); bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data); @@ -95,6 +95,7 @@ protected: protected: AString m_FileName; + int m_CompressionFactor; int m_LayerX; int m_LayerZ; @@ -119,6 +120,8 @@ protected: cCriticalSection m_CS; cPAKFiles m_PAKFiles; // A MRU cache of PAK files + int m_CompressionFactor; + /// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk); diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 6aec525a8..711c8612f 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -68,11 +68,11 @@ cWorldStorage::~cWorldStorage() -bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName) +bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor ) { m_World = a_World; m_StorageSchemaName = a_StorageSchemaName; - InitSchemas(); + InitSchemas(a_StorageCompressionFactor); return super::Start(); } @@ -197,11 +197,11 @@ void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk) -void cWorldStorage::InitSchemas(void) +void cWorldStorage::InitSchemas(int a_StorageCompressionFactor) { // The first schema added is considered the default - m_Schemas.push_back(new cWSSAnvil (m_World)); - m_Schemas.push_back(new cWSSCompact (m_World)); + m_Schemas.push_back(new cWSSAnvil (m_World,a_StorageCompressionFactor)); + m_Schemas.push_back(new cWSSCompact (m_World,a_StorageCompressionFactor)); m_Schemas.push_back(new cWSSForgetful(m_World)); // Add new schemas here diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h index 06cae1717..bb189b6c9 100644 --- a/src/WorldStorage/WorldStorage.h +++ b/src/WorldStorage/WorldStorage.h @@ -76,7 +76,7 @@ public: void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ); void UnqueueSave(const cChunkCoords & a_Chunk); - bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args + bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event void WaitForFinish(void); void WaitForLoadQueueEmpty(void); @@ -126,7 +126,7 @@ protected: /// The one storage schema used for saving cWSSchema * m_SaveSchema; - void InitSchemas(void); + void InitSchemas(int a_StorageCompressionFactor); virtual void Execute(void) override; diff --git a/src/main.cpp b/src/main.cpp index 0620e0f0e..340149e0b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,9 +47,20 @@ void NonCtrlHandler(int a_Signal) case SIGSEGV: { std::signal(SIGSEGV, SIG_DFL); - LOGWARN("Segmentation fault; MCServer has crashed :("); + LOGERROR(" D: | MCServer has encountered an error and needs to close"); + LOGERROR("Details | SIGSEGV: Segmentation fault"); exit(EXIT_FAILURE); } + case SIGABRT: + #ifdef SIGABRT_COMPAT + case SIGABRT_COMPAT: + #endif + { + std::signal(a_Signal, SIG_DFL); + LOGERROR(" D: | MCServer has encountered an error and needs to close"); + LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault"); + break; + } case SIGTERM: { std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it... |