diff options
150 files changed, 3360 insertions, 2114 deletions
diff --git a/.gitignore b/.gitignore index b15b6d502..a108a9ece 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ build/ +ipch/ +Win32/ MCServer/MCServer ChunkWorxSave.ini doxy/ @@ -64,39 +66,62 @@ MCServer.dir/ *.opensdf *.sdf *.sln +*.idb #cmake output folders ZERO_CHECK.dir/ lib/cryptopp/Debug/ +lib/cryptopp/DebugProfile/ lib/cryptopp/Release/ +lib/cryptopp/ReleaseProfile/ lib/cryptopp/cryptopp.dir/ lib/expat/Debug/ +lib/expat/DebugProfile/ lib/expat/Release/ +lib/expat/ReleaseProfile/ lib/expat/expat.dir/ lib/inifile/Debug/ +lib/inifile/DebugProfile/ lib/inifile/Release/ +lib/inifile/ReleaseProfile/ lib/inifile/inifile.dir/ lib/jsoncpp/Debug/ +lib/jsoncpp/DebugProfile/ lib/jsoncpp/Release/ +lib/jsoncpp/ReleaseProfile/ lib/jsoncpp/jsoncpp.dir/ lib/lua/Debug/ +lib/lua/DebugProfile/ lib/lua/Release/ +lib/lua/ReleaseProfile/ lib/lua/lua.dir/ lib/luaexpat/Debug/ +lib/luaexpat/DebugProfile/ lib/luaexpat/Release/ +lib/luaexpat/ReleaseProfile/ lib/luaexpat/luaexpat.dir/ lib/md5/Debug/ +lib/md5/DebugProfile/ lib/md5/Release/ +lib/md5/ReleaseProfile/ lib/md5/md5.dir/ lib/sqlite/Debug/ +lib/sqlite/DebugProfile/ lib/sqlite/Release/ +lib/sqlite/ReleaseProfile/ lib/sqlite/sqlite.dir/ lib/tolua++/Debug/ +lib/tolua++/DebugProfile/ lib/tolua++/Release/ +lib/tolua++/ReleaseProfile/ lib/tolua++/tolua.dir/ lib/tolua++/tolualib.dir/ lib/zlib/Debug/ +lib/zlib/DebugProfile/ lib/zlib/Release/ +lib/zlib/ReleaseProfile/ lib/zlib/zlib.dir/ src/Debug/ +src/DebugProfile/ src/Release/ +src/ReleaseProfile/ 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 135826abc..4ddd34db3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,40 +1,30 @@ cmake_minimum_required (VERSION 2.6) -project (MCServer) -macro(add_flags FLAGS) +# Without this, the MSVC variable isn't defined for MSVC builds ( http://www.cmake.org/pipermail/cmake/2011-November/047130.html ) +enable_language(CXX C) + +macro (add_flags_lnk FLAGS) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${FLAGS}") +endmacro() + +macro(add_flags_cxx FLAGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}") - set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_PROFILE} ${FLAGS}") - set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} ${FLAGS}") endmacro() -SET(CMAKE_CXX_FLAGS_PROFILE - "${CMAKE_CXX_FLAGS_DEBUG} -pg -DNDEBUG" - CACHE STRING "Flags used by the C++ compiler during profile builds." - FORCE ) -SET(CMAKE_C_FLAGS_PROFILE - "${CMAKE_C_FLAGS_DEBUG} -pg -DNDEBUG" - CACHE STRING "Flags used by the C compiler during profile builds." - FORCE ) -SET(CMAKE_EXE_LINKER_FLAGS_PROFILE - "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -pg" - CACHE STRING "Flags used for linking binaries during profile builds." - FORCE ) -SET(CMAKE_SHARED_LINKER_FLAGS_PROFILE - "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -pg" - CACHE STRING "Flags used by the shared libraries linker during profile builds." - FORCE ) -MARK_AS_ADVANCED( - CMAKE_CXX_FLAGS_PROFILE - CMAKE_C_FLAGS_PROFILE - CMAKE_EXE_LINKER_FLAGS_PROFILE - CMAKE_SHARED_LINKER_FLAGS_PROFILE ) - # Add the preprocessor macros used for distinguishing between debug and release builds (CMake does this automatically for MSVC): if (NOT MSVC) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") @@ -45,34 +35,48 @@ endif() if(MSVC) # Make build use multiple threads under MSVC: - add_flags("/MP") + add_flags_cxx("/MP") + + # Make release builds use link-time code generation: + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") 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("-pthread") + add_flags_cxx("-pthread") + add_flags_cxx("-std=c++11") endif() else() # Let gcc / clang know that we're compiling a multi-threaded app: - add_flags("-pthread") + add_flags_cxx("-pthread") endif() -# Allow for a forced 32-bit build under 32-bit OS: + +# Allow for a forced 32-bit build under 64-bit OS: if (FORCE_32) - add_flags(-m32) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32") - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -m32") - set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -m32") - set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_PROFILE} -m32") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -m32") - set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -m32") - set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -m32") - set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_PROFILE} -m32") - set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -m32") - set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} -m32") - set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} -m32") - set(CMAKE_MODULE_LINKER_FLAGS_PROFILE "${CMAKE_MODULE_LINKER_FLAGS_PROFILE} -m32") + add_flags_cxx("-m32") + add_flags_lnk("-m32") +endif() + + +# Have the compiler generate code specifically targeted at the current machine on Linux +if(LINUX AND NOT CROSSCOMPILE) + add_flags_cxx("-march=native") +endif() + + +# Use static CRT in MSVC builds: +if (MSVC) + string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "/MDd" "/MTd" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") endif() + # Set lower warnings-level for the libraries: if (MSVC) # Remove /W3 from command line -- cannot just cancel it later with /w like in unix, MSVC produces a D9025 warning (option1 overriden by option2) @@ -87,19 +91,22 @@ else() set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -w") endif() + # Under clang, we need to disable ASM support in CryptoPP: if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_definitions(-DCRYPTOPP_DISABLE_ASM) endif() + # Under Windows, we need Lua as DLL; on *nix we need it linked statically: if (WIN32) add_definitions(-DLUA_BUILD_AS_DLL) endif() -#On Unix we use two dynamic loading libraries dl and ltdl. -#Preference is for dl on unknown systems as it is specified in POSIX -#the dynamic loader is used by lua and sqllite. + +# On Unix we use two dynamic loading libraries dl and ltdl. +# Preference is for dl on unknown systems as it is specified in POSIX +# the dynamic loader is used by lua and sqllite. if (UNIX) if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") set(DYNAMIC_LOADER ltdl) @@ -108,9 +115,71 @@ if (UNIX) endif() endif() + # The Expat library is linked in statically, make the source files aware of that: add_definitions(-DXML_STATIC) + +# Declare the flags used for profiling builds: +if (MSVC) + set (CXX_PROFILING "") + set (LNK_PROFILING "/PROFILE") +else() + set (CXX_PROFILING "-pg") + set (LNK_PROFILING "-pg") +endif() + + +# Declare the profiling configurations: +SET(CMAKE_CXX_FLAGS_DEBUGPROFILE + "${CMAKE_CXX_FLAGS_DEBUG} ${PCXX_ROFILING}" + CACHE STRING "Flags used by the C++ compiler during profile builds." + FORCE ) +SET(CMAKE_C_FLAGS_DEBUGPROFILE + "${CMAKE_C_FLAGS_DEBUG} ${CXX_PROFILING}" + CACHE STRING "Flags used by the C compiler during profile builds." + FORCE ) +SET(CMAKE_EXE_LINKER_FLAGS_DEBUGPROFILE + "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${LNK_PROFILING}" + CACHE STRING "Flags used for linking binaries during profile builds." + FORCE ) +SET(CMAKE_SHARED_LINKER_FLAGS_DEBUGPROFILE + "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${LNK_PROFILING}" + CACHE STRING "Flags used by the shared libraries linker during profile builds." + FORCE ) +MARK_AS_ADVANCED( + CMAKE_CXX_FLAGS_DEBUGPROFILE + CMAKE_C_FLAGS_DEBUGPROFILE + CMAKE_EXE_LINKER_FLAGS_DEBUGPROFILE + CMAKE_SHARED_LINKER_FLAGS_DEBUGPROFILE ) + +SET(CMAKE_CXX_FLAGS_RELEASEPROFILE + "${CMAKE_CXX_FLAGS_RELEASE} ${CXX_PROFILING}" + CACHE STRING "Flags used by the C++ compiler during profile builds." + FORCE ) +SET(CMAKE_C_FLAGS_RELEASEPROFILE + "${CMAKE_C_FLAGS_RELEASE} ${CXX_PROFILING}" + CACHE STRING "Flags used by the C compiler during profile builds." + FORCE ) +SET(CMAKE_EXE_LINKER_FLAGS_RELEASEPROFILE + "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${LNK_PROFILING}" + CACHE STRING "Flags used for linking binaries during profile builds." + FORCE ) +SET(CMAKE_SHARED_LINKER_FLAGS_RELEASEPROFILE + "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${LNK_PROFILING}" + CACHE STRING "Flags used by the shared libraries linker during profile builds." + FORCE ) +MARK_AS_ADVANCED( + CMAKE_CXX_FLAGS_RELEASEPROFILE + CMAKE_C_FLAGS_RELEASEPROFILE + CMAKE_EXE_LINKER_FLAGS_RELEASEPROFILE + CMAKE_SHARED_LINKER_FLAGS_RELEASEPROFILE ) + + +# The configuration types need to be set after their respective c/cxx/linker flags and before the project directive +set(CMAKE_CONFIGURATION_TYPES "Debug;Release;DebugProfile;ReleaseProfile" CACHE STRING "" FORCE) +project (MCServer) + # Include all the libraries: add_subdirectory(lib/inifile/) add_subdirectory(lib/jsoncpp/) @@ -126,7 +195,7 @@ add_subdirectory(lib/md5/) # Remove disabling the maximum warning level: # clang does not like a command line that reads -Wall -Wextra -w -Wall -Wextra and does not output any warnings # We do not do that for MSVC since MSVC produces an awful lot of warnings for its own STL headers; -# the important warnings will be turned on using #pragma in Globals.h +# the important warnings are turned on using #pragma in Globals.h if (NOT MSVC) string(REPLACE "-w" "" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") @@ -134,5 +203,5 @@ if (NOT MSVC) string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") endif() -add_subdirectory (src) +add_subdirectory (src) diff --git a/COMPILING.md b/COMPILING.md index e10acee98..eceeefee7 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -1,27 +1,91 @@ -COMPILING -========= +# COMPILING # -To compile MCServer on *nix, you need CMake and make, as well as a C compiler, C++ compiler and linker. +To compile MCServer from source, you need CMake and make, as well as a C compiler, C++ compiler and linker. To contribute code, you also need a Git client. -Release Mode ------------- +## Windows ## + +We use Microsoft Visual Studio for Windows compilation. It is possible to use other toolchains, but it isn't tested nor supported. Visual Studio versions 2008 Express and 2013 Express are being actively used for development, so either should work. +You can find download links for VS2008 Express here: http://stackoverflow.com/questions/15318560/visual-c-2008-express-download-link-dead +And VS2013 Express here: http://www.microsoft.com/en-us/download/details.aspx?id=40787 + +Next, you need to download and install CMake. Download from here: http://cmake.org/cmake/resources/software.html . You should download a full installation package, so that the installer will set everything up for you (especially the paths). + +To contribute your changes to the sources back to the repository, you need a Git client. Options are: +- MsysGit: http://msysgit.github.io/ +- GitHub windows client: http://windows.github.com/ +- TortoiseGit: http://code.google.com/p/tortoisegit/ + +Alternatively, if you want only to compile the source, without contributing, you can download the sources in a ZIP file directly from GitHub: https://github.com/mc-server/MCServer/archive/master.zip +If you're using Git to get the sources, use the following set of commands to set up the local workspace correctly: +``` +mkdir MCServer +cd MCServer +git clone https://github.com/mc-server/MCServer.git . +git submodule init +git submodule update +``` + +Now that you have the sources, it's time to prepare the project files for your favorite compiler. Open a command window in the folder with the sources and type in `cmake .` . This will run CMake, it will auto-detect your Visual Studio version and produce the appropriate project and solution files. + +Finally, open the newly created file, `MCServer.sln`, in your Visual Studio. + +If you want to run MCServer from within the IDE, you need to first make sure that it will be run with the correct home folder. Normally this happens automatically, but for some Visual Studio versions the process doesn't stick. Right-click on the MCServer project in the Solution Explorer tool window, and select Properties. In the dialog, navigate to Configuration properties -> Debugging in the tree on the left, then make sure the value `Working Directory` is set to `../MCServer`. If you don't do this, the server won't be able to find crafting recipes, item names or plugins. + +### Release configuration ### + +To make Visual Studio produce the version with the best performance, you will need to select a Release configuration. Go to menu Build -> Configuration Manager, and in the opened dialog, change the top left combo box (Active solution configuration) to Release. Close the dialog and build the solution. The resulting executable is called `MCServer.exe` in the `MCServer` folder. + +### Debug configuration ### + +In order to tinker with the code, you'll more than likely need to use the debugging features of the IDE. To make them the easiest to use, you should switch to the Debug configuration - this provides the highest level of information while debugging, for the price of the executable being 2 - 10 times slower. Go to menu Build -> Configuration Manager, and in the opened dialog, change the top left combo box (Active solution configuration) to Debug. Close the dialog and build the solution. The resulting executable is called `MCServer_debug.exe` in the `MCServer` folder. + +### Profiling ### + +It is possible to use an external profiler to learn more about how the code performs. You can find more information about the techniques in the article here: http://www.codeproject.com/Articles/144643/Profiling-of-C-Applications-in-Visual-Studio-for-F + +There's a script file, `MCServer/profile_run.cmd` that encapsulates most of the profiling work, have a look at the comments at the top of that script for details on how to get it to work. You'll need to change to a profiled configuration (both debug and release can be profiled). + +## Linux, MacOS, FreeBSD etc. ## + +Install git, cmake and gcc or clang, using your platform's package manager: +``` +sudo apt-get install git cmake gcc +``` + +### Getting the sources ### +``` +mkdir MCServer +cd MCServer +git clone https://github.com/mc-server/MCServer.git . +git submodule init +git submodule update +``` + +### Release Mode ### Release mode is preferred for almost all cases, it has much better speed and less console spam. However, if you are developing MCServer actively, debug mode might be better. cmake . -DCMAKE_BUILD_TYPE=RELEASE && make -Debug Mode ----------- +### Debug Mode ### Debug mode is useful if you want more debugging information about MCServer as it's running or if you want to use a debugger like GDB to debug issues and crashes. cmake . -DCMAKE_BUILD_TYPE=DEBUG && make -32 Bit Mode ------------ +### 32 Bit Mode ### This is useful if you want to compile MCServer to use on another 32-bit machine. It can be used with debug or release mode. To use 32 bit mode, simply add: -DFORCE_32=1 to your cmake command and 32 bit will be forced. + +### 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: + + -DCROSSCOMPILE=1 + +to your cmake command. diff --git a/GETTING-STARTED.md b/GETTING-STARTED.md index 66318a629..1ac6fe989 100644 --- a/GETTING-STARTED.md +++ b/GETTING-STARTED.md @@ -102,14 +102,14 @@ There are a few fairly easy issues for you to get started with, as well as some * #288 * #385 * #402 - * #388 - * #380 + * #380 + * #503 + * #491 * Clean up some of the compiler warnings. (Check [Travis CI](http://travis-ci.org/mc-server/MCServer) for a list of them.) With clang, there are over 10000 lines of warnings to clean up. **More Difficult**: * #17 - * #418 * #398 You may also want to write some plugins. They are written in lua, with excellent API documentation available via [APIDump](http://mc-server.xoft.cz/LuaAPI). The [Core](https://github.com/mc-server/Core) plugin should also help quite a bit here. diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 26537918e..bf32ea8c2 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -449,6 +449,7 @@ end GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" }, GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" }, Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" }, + SendPluginMessage = { Params = "Channel, Message", Return = "", Notes = "Sends the plugin message on the specified channel." }, SetUsername = { Params = "Name", Return = "", Notes = "Sets the username" }, SetViewDistance = { Params = "ViewDistance", Return = "", Notes = "Sets the viewdistance (number of chunks loaded for the player in each direction)" }, SendBlockChange = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sends a BlockChange packet to the client. This can be used to create fake blocks only for that player." }, @@ -706,7 +707,9 @@ end IsBoat = { Params = "", Return = "bool", Notes = "Returns true if the entity is a {{cBoat|boat}}." }, IsCrouched = { Params = "", Return = "bool", Notes = "Returns true if the entity is crouched. Always false for entities that don't support crouching." }, IsDestroyed = { Params = "", Return = "bool", Notes = "Returns true if the entity has been destroyed and is awaiting removal from the internal structures." }, + IsExpOrb = { Params = "", Return = "bool", Notes = "Returns true if the entity represents an experience orb" }, IsFallingBlock = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cFallingBlock}} entity." }, + IsFloater = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a fishing rod floater" }, IsInvisible = { Params = "", Return = "bool", Notes = "Returns true if the entity is invisible" }, IsMinecart = { Params = "", Return = "bool", Notes = "Returns true if the entity represents a {{cMinecart|minecart}}" }, IsMob = { Params = "", Return = "bool", Notes = "Returns true if the entity represents any {{cMonster|mob}}." }, @@ -767,6 +770,7 @@ end etEntity = { Notes = "No further specialization available" }, etExpOrb = { Notes = "The entity is a {{cExpOrb}}" }, etFallingBlock = { Notes = "The entity is a {{cFallingBlock}}" }, + etFloater = { Notes = "The entity is a fishing rod floater" }, etMob = { Notes = "The entity is a {{cMonster}} descendant" }, etMonster = { Notes = "The entity is a {{cMonster}} descendant" }, etMinecart = { Notes = "The entity is a {{cMinecart}} descendant" }, @@ -804,6 +808,7 @@ cFile:Delete("/usr/bin/virus.exe"); GetSize = { Params = "FileName", Return = "number", Notes = "(STATIC) Returns the size of the file, or -1 on failure." }, IsFile = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing file." }, IsFolder = { Params = "Path", Return = "bool", Notes = "(STATIC) Returns true if the specified path points to an existing folder." }, + ReadWholeFile = { Params = "FileName", Return = "string", Notes = "(STATIC) Returns the entire contents of the specified file. Returns an empty string if the file cannot be opened." }, Rename = { Params = "OrigPath, NewPath", Return = "bool", Notes = "(STATIC) Renames a file or a folder. Returns true if successful. Undefined result if NewPath already exists." }, }, }, -- cFile @@ -867,6 +872,10 @@ ValueName0=SomeOtherValue { Params = "KeyName, Comment", Return = "", Notes = "Adds a comment to be stored in the file under the specified key" }, }, AddKeyName = { Params = "KeyName", Returns = "number", Notes = "Adds a new key of the specified name. Returns the KeyID of the new key." }, + AddValue = { Params = "KeyName, ValueName, Value", Return = "", Notes = "Adds a new value of the specified name to the specified key. If another value of the same name exists in the key, both are kept (nonstandard INI file)" }, + AddValueB = { Params = "KeyName, ValueName, Value", Return = "", Notes = "Adds a new bool value of the specified name to the specified key. If another value of the same name exists in the key, both are kept (nonstandard INI file)" }, + AddValueF = { Params = "KeyName, ValueName, Value", Return = "", Notes = "Adds a new float value of the specified name to the specified key. If another value of the same name exists in the key, both are kept (nonstandard INI file)" }, + AddValueI = { Params = "KeyName, ValueName, Value", Return = "", Notes = "Adds a new integer value of the specified name to the specified key. If another value of the same name exists in the key, both are kept (nonstandard INI file)" }, CaseInsensitive = { Params = "", Return = "", Notes = "Sets key names' and value names' comparisons to case insensitive (default)." }, CaseSensitive = { Params = "", Return = "", Notes = "Sets key names and value names comparisons to case sensitive." }, Clear = { Params = "", Return = "", Notes = "Removes all the in-memory data. Note that , like all the other operations, this doesn't affect any file data." }, @@ -1562,7 +1571,7 @@ a_Player:OpenWindow(Window); { AddFoodExhaustion = { Params = "Exhaustion", Return = "", Notes = "Adds the specified number to the food exhaustion. Only positive numbers expected." }, AddToGroup = { Params = "GroupName", Return = "", Notes = "Temporarily adds the player to the specified group. The assignment is lost when the player disconnects." }, - CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." }, + CalcLevelFromXp = { Params = "XPAmount", Return = "number", Notes = "(STATIC) Returns the level which is reached with the specified amount of XP. Inverse of XpForLevel()." }, CanFly = { Return = "bool", Notes = "Returns if the player is able to fly." }, CanUseCommand = { Params = "Command", Return = "bool", Notes = "Returns true if the player is allowed to use the specified command." }, CloseWindow = { Params = "[CanRefuse]", Return = "", Notes = "Closes the currently open UI window. If CanRefuse is true (default), the window may refuse the closing." }, @@ -1579,6 +1588,7 @@ a_Player:OpenWindow(Window); GetEquippedItem = { Params = "", Return = "{{cItem}}", Notes = "Returns the item that the player is currently holding; empty item if holding nothing." }, GetEyeHeight = { Return = "number", Notes = "Returns the height of the player's eyes, in absolute coords" }, GetEyePosition = { Return = "{{Vector3d|EyePositionVector}}", Notes = "Returns the position of the player's eyes, as a {{Vector3d}}" }, + GetFloaterID = { Params = "", Return = "number", Notes = "Returns the Entity ID of the fishing hook floater that belongs to the player. Returns -1 if no floater is associated with the player. FIXME: Undefined behavior when the player has used multiple fishing rods simultanously." }, GetFoodExhaustionLevel = { Params = "", Return = "number", Notes = "Returns the food exhaustion level" }, GetFoodLevel = { Params = "", Return = "number", Notes = "Returns the food level (number of half-drumsticks on-screen)" }, GetFoodPoisonedTicksRemaining = { Params = "", Return = "", Notes = "Returns the number of ticks left for the food posoning effect" }, @@ -1603,6 +1613,7 @@ a_Player:OpenWindow(Window); HasPermission = { Params = "PermissionString", Return = "bool", Notes = "Returns true if the player has the specified permission" }, Heal = { Params = "HitPoints", Return = "", Notes = "Heals the player by the specified amount of HPs. Only positive amounts are expected. Sends a health update to the client." }, IsEating = { Params = "", Return = "bool", Notes = "Returns true if the player is currently eating the item in their hand." }, + IsFishing = { Params = "", Return = "bool", Notes = "Returns true if the player is currently fishing" }, IsFlying = { Return = "bool", Notes = "Returns true if the player is flying." }, IsGameModeAdventure = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmAdventure gamemode, or has their gamemode unset and the world is a gmAdventure world." }, IsGameModeCreative = { Params = "", Return = "bool", Notes = "Returns true if the player is in the gmCreative gamemode, or has their gamemode unset and the world is a gmCreative world." }, @@ -1630,13 +1641,14 @@ a_Player:OpenWindow(Window); SetFoodSaturationLevel = { Params = "FoodSaturationLevel", Return = "", Notes = "Sets the food saturation (overcharge of the food level)." }, SetFoodTickTimer = { Params = "FoodTickTimer", Return = "", Notes = "Sets the number of ticks past the last food-based heal or damage action; when this timer reaches 80, a new heal / damage is applied." }, SetGameMode = { Params = "{{eGameMode|NewGameMode}}", Return = "", Notes = "Sets the gamemode for the player. The new gamemode overrides the world's default gamemode, unless it is set to gmInherit." }, + SetIsFishing = { Params = "IsFishing, [FloaterEntityID]", Return = "", Notes = "Sets the 'IsFishing' flag for the player. The floater entity ID is expected for the true variant, it can be omitted when IsFishing is false. FIXME: Undefined behavior when multiple fishing rods are used simultanously" }, SetName = { Params = "Name", Return = "", Notes = "Sets the player name. This rename will NOT be visible to any players already in the server who are close enough to see this player." }, SetNormalMaxSpeed = { Params = "NormalMaxSpeed", Return = "", Notes = "Sets the normal (walking) maximum speed (as reported by the 1.6.1+ protocols)" }, SetSprint = { Params = "IsSprinting", Return = "", Notes = "Sets whether the player is sprinting or not." }, SetSprintingMaxSpeed = { Params = "SprintingMaxSpeed", Return = "", Notes = "Sets the sprinting maximum speed (as reported by the 1.6.1+ protocols)" }, SetVisible = { Params = "IsVisible", Return = "", Notes = "Sets the player visibility to other players" }, TossItem = { Params = "DraggedItem, [Amount], [CreateType], [CreateDamage]", Return = "", Notes = "FIXME: This function will be rewritten, avoid it. It tosses an item, either from the inventory, dragged in hand (while in UI window) or a newly created one." }, - XpForLevel = { Params = "XPLevel", Return = "number", Notes = "Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." }, + XpForLevel = { Params = "XPLevel", Return = "number", Notes = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." }, }, Constants = { @@ -1714,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" }, @@ -1750,6 +1762,8 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage); HOOK_PLAYER_BREAKING_BLOCK = { Notes = "Called when a player is about to break a block. A plugin may cancel the event." }, HOOK_PLAYER_BROKEN_BLOCK = { Notes = "Called after a player has broken a block." }, HOOK_PLAYER_EATING = { Notes = "Called when the player starts eating a held item. Plugins may abort the eating." }, + HOOK_PLAYER_FISHED = { Notes = "Called when the player reels the fishing rod back in, after the server decides the player's fishing reward." }, + HOOK_PLAYER_FISHING = { Notes = "Called when the player reels the fishing rod back in, plugins may alter the fishing reward." }, HOOK_PLAYER_JOINED = { Notes = "Called when the player entity has been created. It has not yet been fully initialized." }, HOOK_PLAYER_LEFT_CLICK = { Notes = "Called when the client sends the LeftClick packet." }, HOOK_PLAYER_MOVING = { Notes = "Called when the player has moved and the movement is now being applied." }, @@ -1985,6 +1999,7 @@ end Functions = { + BroadcastBlockAction = { Params = "BlockX, BlockY, BlockZ, ActionByte1, ActionByte2, BlockType, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Broadcasts the BlockAction packet to all clients who have the appropriate chunk loaded (except ExcludeClient). The contents of the packet are specified by the parameters for the call, the blocktype needn't match the actual block that is present in the world data at the specified location." }, BroadcastChat = { Params = "Message, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the Message to all players in this world, except the optional ExceptClient" }, BroadcastSoundEffect = { Params = "SoundName, X, Y, Z, Volume, Pitch, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified sound effect to all players in this world, except the optional ExceptClient" }, BroadcastSoundParticleEffect = { Params = "EffectID, X, Y, Z, EffectData, [{{cClientHandle|ExcludeClient}}]", Return = "", Notes = "Sends the specified effect to all players in this world, except the optional ExceptClient" }, @@ -2000,6 +2015,7 @@ end DoWithDropperAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper at the specified coords, calls the CallbackFunction with the {{cDropperEntity}} parameter representing the dropper. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropperEntity|DropperEntity}}, [CallbackData])</pre> The function returns false if there is no dropper, or if there is, it returns the bool value that the callback has returned." }, DoWithEntityByID = { Params = "EntityID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If an entity with the specified ID exists, calls the callback with the {{cEntity}} parameter representing the entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The function returns false if the entity was not found, and it returns the same bool value that the callback has returned if the entity was found." }, DoWithFurnaceAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a furnace at the specified coords, calls the CallbackFunction with the {{cFurnaceEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The function returns false if there is no furnace, or if there is, it returns the bool value that the callback has returned." }, + DoWithNoteBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a note block at the specified coords, calls the CallbackFunction with the {{cNoteEntity}} parameter representing the note block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cNoteEntity|NoteEntity}}, [CallbackData])</pre> The function returns false if there is no note block, or if there is, it returns the bool value that the callback has returned." }, DoWithPlayer = { Params = "PlayerName, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of the specified name (exact match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." }, FastSetBlock = { @@ -2071,6 +2087,7 @@ end QueueSetBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta, TickDelay", Return = "", Notes = "Queues the block to be set to the specified blocktype and meta after the specified amount of game ticks. Uses SetBlock() for the actual setting, so simulators are woken up and block entities are handled correctly." }, QueueTask = { Params = "TaskFunction", Return = "", Notes = "Queues the specified function to be executed in the tick thread. This is the primary means of interaction with a cWorld from the WebAdmin page handlers (see {{WebWorldThreads}}). The function signature is <pre class=\"pretty-print lang-lua\">function()</pre>All return values from the function are ignored. Note that this function is actually called *after* the QueueTask() function returns." }, RegenerateChunk = { Params = "ChunkX, ChunkZ", Return = "", Notes = "Queues the specified chunk to be re-generated, overwriting the current data. To queue a chunk for generating only if it doesn't exist, use the GenerateChunk() instead." }, + ScheduleTask = { Params = "TaskFunction, Ticks", Return = "", Notes = "Queues the specified function to be executed in the world's tick thread after a number of ticks. This enables operations to be queued for execution in the future. The function signature is <pre class=\"pretty-print lang-lua\">function({{cWorld|World}})</pre>All return values from the function are ignored." }, SendBlockTo = { Params = "BlockX, BlockY, BlockZ, {{cPlayer|Player}}", Return = "", Notes = "Sends the block at the specified coords to the specified player's client, as an UpdateBlock packet." }, SetBlock = { Params = "BlockX, BlockY, BlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block at the specified coords, replaces the block entities for the previous block type, creates a new block entity for the new block, if appropriate, and wakes up the simulators. This is the preferred way to set blocks, as opposed to FastSetBlock(), which is only to be used under special circumstances." }, SetBlockMeta = @@ -2083,6 +2100,7 @@ end SetTicksUntilWeatherChange = { Params = "NumTicks", Return = "", Notes = "Sets the number of ticks after which the weather will be changed." }, SetTimeOfDay = { Params = "TimeOfDayTicks", Return = "", Notes = "Sets the time of day, expressed as number of ticks past sunrise, in the range 0 .. 24000." }, SetWeather = { Params = "Weather", Return = "", Notes = "Sets the current weather (wSunny, wRain, wStorm) and resets the TicksUntilWeatherChange to the default value for the new weather. The normal weather-changing hooks are called for the change." }, + ShouldLavaSpawnFire = { Params = "", Return = "bool", Notes = "Returns true if the world is configured to spawn fires near lava (world.ini: [Physics].ShouldLavaSpawnFire value)" }, SpawnItemPickups = { { Params = "{{cItems|Pickups}}, X, Y, Z, FlyAwaySpeed", Return = "", Notes = "Spawns the specified pickups at the position specified. The FlyAway speed is used to initialize the random speed in which the pickups fly away from the spawn position." }, @@ -2576,7 +2594,9 @@ end DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "}, EscapeString = {Params = "string", Return = "string", Notes = "Returns a copy of the string with all quotes and backslashes escaped by a backslash"}, GetChar = {Params = "String, Pos", Return = "string", Notes = "Returns one character from the string, specified by position "}, + GetIniItemSet = { Params = "IniFile, SectionName, KeyName, DefaultValue", Return = "{{cItem}}", Notes = "Returns the item that has been read from the specified INI file value. If the value is not present in the INI file, the DefaultValue is stored in the file and parsed as the result. Returns empty item if the value cannot be parsed. " }, GetTime = {Return = "number", Notes = "Returns the current OS time, as a unix time stamp (number of seconds since Jan 1, 1970)"}, + IsBiomeNoDownfall = { Params = "Biome", Return = "bool", Notes = "Returns true if the biome is 'dry', that is, there is no precipitation during rains and storms." }, IsValidBlock = {Params = "BlockType", Return = "bool", Notes = "Returns true if BlockType is a known block type"}, IsValidItem = {Params = "ItemType", Return = "bool", Notes = "Returns true if ItemType is a known item type"}, ItemToFullString = {Params = "{{cItem|cItem}}", Return = "string", Notes = "Returns the string representation of the item, in the format 'ItemTypeText:ItemDamage * Count'"}, @@ -2588,6 +2608,7 @@ end LOGWARN = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text); OBSOLETE, use LOGWARNING() instead"}, LOGWARNING = {Params = "string", Notes = "Logs a text into the server console using 'warning' severity (red text)"}, NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"}, + NormalizeAngleDegrees = { Params = "AngleDegrees", Return = "AngleDegrees", Notes = "Returns the angle, wrapped into the [-180, +180) range." }, ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"}, StringSplit = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered."}, StringSplitAndTrim = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered. Each of the separate strings is trimmed (whitespace removed from the beginning and end of the string)"}, diff --git a/MCServer/Plugins/APIDump/APIDump.deproj b/MCServer/Plugins/APIDump/APIDump.deproj index dffe3eaee..e78974901 100644 --- a/MCServer/Plugins/APIDump/APIDump.deproj +++ b/MCServer/Plugins/APIDump/APIDump.deproj @@ -115,6 +115,9 @@ <filename>Hooks\OnPlayerUsingItem.lua</filename> </file> <file> + <filename>Hooks\OnPluginMessage.lua</filename> + </file> + <file> <filename>Hooks\OnPostCrafting.lua</filename> </file> <file> diff --git a/MCServer/Plugins/APIDump/Hooks/OnPluginMessage.lua b/MCServer/Plugins/APIDump/Hooks/OnPluginMessage.lua new file mode 100644 index 000000000..743d3bb5e --- /dev/null +++ b/MCServer/Plugins/APIDump/Hooks/OnPluginMessage.lua @@ -0,0 +1,25 @@ +return +{ + HOOK_PLUGIN_MESSAGE = + { + CalledWhen = "The server receives a plugin message from a client", + DefaultFnName = "OnPluginMessage", -- also used as pagename + Desc = [[ + A plugin may implement an OnPluginMessage() function and register it as a Hook to process plugin messages + from the players. The function is then called for every plugin message sent from any player. + ]], + Params = { + { Name = "Client", Type = "{{cClientHandle}}", Notes = "The client who sent the plugin message" }, + { Name = "Channel", Type = "string", Notes = "The channel on which the message was sent" }, + { Name = "Message", Type = "string", Notes = "The message's payload" }, + }, + Returns = [[ + If the function returns false or no value, other plugins' callbacks are called. If the function + returns true, no other callbacks are called for this event. + ]], + }, -- HOOK_CHAT +} + + + + diff --git a/MCServer/Plugins/APIDump/Hooks/OnPluginsLoaded.lua b/MCServer/Plugins/APIDump/Hooks/OnPluginsLoaded.lua index 0d5b7271e..2c8a5a2c9 100644 --- a/MCServer/Plugins/APIDump/Hooks/OnPluginsLoaded.lua +++ b/MCServer/Plugins/APIDump/Hooks/OnPluginsLoaded.lua @@ -37,12 +37,14 @@ local function SendMessageFailureFallback(a_Player, a_Message) end -- These three "variables" will hold the actual functions to call. --- By default they are initialized to the Fallback variants, but will be redirected to Core when all plugins load +-- By default they are initialized to the Fallback variants, +-- but will be redirected to Core when all plugins load SendMessage = SendMessageFallback; SendMessageSuccess = SendMessageSuccessFallback; SendMessageFailure = SendMessageFailureFallback; --- The callback tries to connect to the Core, if successful, overwrites the three functions with Core ones +-- The callback tries to connect to the Core +-- If successful, overwrites the three functions with Core ones local function OnPluginsLoaded() local CorePlugin = cPluginManager:Get():GetPlugin("Core"); if (CorePlugin == nil) then @@ -67,7 +69,10 @@ cPluginManager.AddHook(cPluginManager.HOOK_PLUGINS_LOADED, CoreMessagingPluginsL -- Usage, anywhere else in the plugin: -SendMessageFailure(a_Player, "Cannot teleport to player, the destination player " .. PlayerName .. " was not found"); +SendMessageFailure( + a_Player, + "Cannot teleport to player, the destination player " .. PlayerName .. " was not found" +); ]], }, } , -- CodeExamples diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core -Subproject c65b56767a5e59ca387a05be72ef18791baa9ae +Subproject 1d524e4e7d2b1178f2b772c95766c63c338ad71 diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index 7b43b6c20..8512fbd5f 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -966,6 +966,23 @@ end function OnPluginMessage(a_Client, a_Channel, a_Message) LOGINFO("Received a plugin message from client " .. a_Client:GetUsername() .. ": channel '" .. a_Channel .. "', message '" .. a_Message .. "'"); + + if (a_Channel == "REGISTER") then + if (a_Message:find("WECUI")) then + -- The client has WorldEditCUI mod installed, test the comm by sending a few WECUI messages: + --[[ + WECUI messages have the following generic format: + <shape>|<params> + If shape is p (cuboid selection), the params are sent individually for each corner click and have the following format: + <point-index>|<x>|<y>|<z>|<volume> + point-index is 0 or 1 (lclk / rclk) + volume is the 3D volume of the current cuboid selected (all three coords' deltas multiplied), including the edge blocks; -1 if N/A + --]] + -- Select a 51 * 51 * 51 block cuboid: + a_Client:SendPluginMessage("WECUI", "p|0|50|50|50|-1"); + a_Client:SendPluginMessage("WECUI", "p|1|100|100|100|132651"); -- 132651 = 51 * 51 * 51 + end + end end diff --git a/MCServer/Plugins/TestLuaRocks/TestLuaRocks.lua b/MCServer/Plugins/TestLuaRocks/TestLuaRocks.lua index 6e90b1ae9..4a7cd4e1e 100644 --- a/MCServer/Plugins/TestLuaRocks/TestLuaRocks.lua +++ b/MCServer/Plugins/TestLuaRocks/TestLuaRocks.lua @@ -27,7 +27,7 @@ LOG("headers: "); for k, v in pairs(headers or {}) do LOG(" " .. k .. ": " .. v); end -LOG("body length: " .. string.length(body)); +LOG("body length: " .. string.len(body)); diff --git a/MCServer/favicon.png b/MCServer/favicon.png Binary files differnew file mode 100644 index 000000000..946cce005 --- /dev/null +++ b/MCServer/favicon.png diff --git a/MCServer/profile_run.cmd b/MCServer/profile_run.cmd new file mode 100644 index 000000000..58efea64a --- /dev/null +++ b/MCServer/profile_run.cmd @@ -0,0 +1,96 @@ +@echo off +:: +:: Profiling using a MSVC standalone profiler +:: +:: See http://www.codeproject.com/Articles/144643/Profiling-of-C-Applications-in-Visual-Studio-for-F for details +:: Note that this script assumes a newer version of the tool, Performance Tools 2010, so that it is Win7-compatible +:: Download at http://www.microsoft.com/en-ca/download/details.aspx?id=23205 +:: +:: This script sets the profiler up, then starts the app, waits for it to finish and stops the profiler. +:: Then it generates all the CSV report files +:: +:: It expects the MS Performance tools installed in C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools +:: You can override this path by setting the pt environment variable prior to launching this script +:: +:: By default it will launch the release version of MCServer; set the app environment variable to another executable to run that instead. +:: Note that the app needs to be compiled with the "/PROFILE" flag in order for the profiling to work + + + + +setlocal + +:: Get the 32-bit program files folder +:: Note that in Win7 the %ProgramFiles% variable points to 32-bit program files for normal users and to 64-bit program files for elevated users +:: This script needs elevation, but the performance tools are 32-bit only +if "%programfiles(x86)%p" == "p" ( + set ProgFiles="%ProgramFiles%" +) else ( + set ProgFiles="%ProgramFiles(x86)%" +) + +:: Check that the required variables exist, provide defaults: +if %pt%n == n ( + set pt="%ProgFiles:"=%\Microsoft Visual Studio 10.0\Team Tools\Performance Tools" +) + +if %app%n == n ( + set app=MCServer_profile.exe +) + +if %outputdir%n == n ( + set outputdir=..\Profiling +) + + + + +::Create the output directory, if it didn't exist +mkdir %outputdir% + + + + + +:: Start the profiler +set outputname=profile.vsp +set output=%outputdir%\%outputname% +%pt%\vsperfcmd /start:sample /output:%output% +if errorlevel 1 goto haderror + +:: Launch the application via the profiler +%pt%\vsperfcmd /launch:%app% +if errorlevel 1 goto haderror + +:: Shut down the profiler (this command waits, until the application is terminated) +%pt%\vsperfcmd /shutdown +if errorlevel 1 goto haderror + + + + + +:: cd to outputdir, so that the reports are generated there +cd %outputdir% + +:: generate the report files (.csv) +%pt%\vsperfreport /summary:all %outputname% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols" +if errorlevel 1 goto haderror + + + + + +goto finished + + + + +:haderror +echo An error was encountered +pause + + + + +:finished diff --git a/MCServer/profile_run_debug.cmd b/MCServer/profile_run_debug.cmd new file mode 100644 index 000000000..8bf85f049 --- /dev/null +++ b/MCServer/profile_run_debug.cmd @@ -0,0 +1,5 @@ +@echo off +:: This script uses the profile_run.cmd script to run profiling on the DebugProfile executable + +set app=MCServer_debug_profile.exe +call profile_run.cmd
\ No newline at end of file diff --git a/MCServer/settings_apidump.ini b/MCServer/settings_apidump.ini new file mode 100644 index 000000000..80227a713 --- /dev/null +++ b/MCServer/settings_apidump.ini @@ -0,0 +1,30 @@ +; This settings file is used by the $/MakeLuaAPI.cmd script +; It is copied over settings.ini so that the APIDump plugin gets loaded upon server start + +[Server] +Description=MCServer - in C++! +MaxPlayers=100 +HardcoreEnabled=0 +Port=25565 +PortsIPv6= +DefaultViewDistance=10 + +[RCON] +Enabled=0 + +[Authentication] +Authenticate=1 +Server=session.minecraft.net +Address=/game/checkserver.jsp?user=%USERNAME%&serverId=%SERVERID% + +[Worlds] +; World=secondworld +DefaultWorld=world + +[Plugins] +Plugin=APIDump + +[DeadlockDetect] +Enabled=0 +IntervalSec=20 + diff --git a/MakeLuaAPI.cmd b/MakeLuaAPI.cmd index 6ea44c9fb..7054977a0 100644 --- a/MakeLuaAPI.cmd +++ b/MakeLuaAPI.cmd @@ -29,6 +29,7 @@ if "a%ftpsite%" == "a" ( :: Create the API documentation by running the server and stopping it right after it starts: cd MCServer +copy /Y settings_apidump.ini settings.ini echo stop | MCServer cd .. diff --git a/Nightbuild2008.cmd b/Nightbuild2008.cmd index f3f1ca4cb..bbaea0fb7 100644 --- a/Nightbuild2008.cmd +++ b/Nightbuild2008.cmd @@ -44,6 +44,7 @@ if "a%ftpsite%" == "a" ( :: Get the date and time into vars: +:: This is locale-dependent! For /f "tokens=2-4 delims=/. " %%a in ('date /t') do ( set MYYEAR=%%c set MYMONTH=%%b @@ -66,13 +67,11 @@ if errorlevel 1 goto haderror :: Update the external plugins to the latest revision: -cd MCServer\Plugins\Core -git pull -if errorlevel 1 goto haderror -cd ..\ProtectionAreas -git pull +git submodule update if errorlevel 1 goto haderror -cd ..\..\.. + + + :: Get the Git commit ID into an environment var For /f "tokens=1 delims=/. " %%a in ('git log -1 --oneline --no-abbrev-commit') do (set COMMITID=%%a) @@ -91,6 +90,16 @@ if exist %TAGFILE% ( + + +:: Configure the sources to use the MSVC2008 compiler: +cmake -G "Visual Studio 9 2008" . +if errorlevel 1 goto haderror + + + + + :: Update the Bindings: echo Updating Lua bindings del src\Bindings\Bindings.cpp @@ -108,15 +117,29 @@ echo Setting up VS environment... call "%VS90COMNTOOLS%\vsvars32.bat" echo Compiling MCServer... title MCS Nightbuild -start "vc" /b /wait /low /min %vc% /r vc2008\MCServer.sln "Release|Win32" +start "vc" /b /wait /low /min %vc% /r MCServer.sln "Release|Win32" if errorlevel 1 goto haderror +:: Generate the .example.ini files by running the server without any ini files: +cd MCServer +del groups.ini +del settings.ini +del webadmin.ini +echo stop | MCServer +cd .. + + :: Copy all the example ini files into the Install folder for zipping: -copy MCServer\*.example.ini Install\ +copy MCServer\groups.ini Install\groups.example.ini +copy MCServer\settings.ini Install\settings.example.ini +copy MCServer\webadmin.ini Install\webadmin.example.ini + + + :: Use 7-zip to compress the resulting files into a single file: set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID% diff --git a/Tools/BiomeVisualiser/.gitignore b/Tools/BiomeVisualiser/.gitignore index b4e15dc3c..cfbc9164c 100644 --- a/Tools/BiomeVisualiser/.gitignore +++ b/Tools/BiomeVisualiser/.gitignore @@ -1,3 +1,4 @@ Debug/ logs/ Release/ +Release profiled/ diff --git a/Tools/BiomeVisualiser/BiomeRenderer.cpp b/Tools/BiomeVisualiser/BiomeRenderer.cpp index 758eb4b48..569128a12 100644 --- a/Tools/BiomeVisualiser/BiomeRenderer.cpp +++ b/Tools/BiomeVisualiser/BiomeRenderer.cpp @@ -40,10 +40,10 @@ bool cBiomeRenderer::Render(cPixmap & a_Pixmap) int Hei = a_Pixmap.GetHeight(); // Hint the approximate view area to the biome source so that it can adjust its caches: - int MinBlockX = ( - m_OriginX) / m_Zoom; - int MaxBlockX = (Wid - m_OriginX) / m_Zoom; - int MinBlockZ = ( - m_OriginY) / m_Zoom; - int MaxBlockZ = (Hei - m_OriginY) / m_Zoom; + int MinBlockX = ( - m_OriginX) * m_Zoom; + int MaxBlockX = (Wid - m_OriginX) * m_Zoom; + int MinBlockZ = ( - m_OriginY) * m_Zoom; + int MaxBlockZ = (Hei - m_OriginY) * m_Zoom; m_Cache.HintViewArea(MinBlockX / 16 - 1, MaxBlockX / 16 + 1, MinBlockZ / 16 - 1, MaxBlockZ / 16 + 1); // Hold one current chunk of biome data: @@ -55,12 +55,12 @@ bool cBiomeRenderer::Render(cPixmap & a_Pixmap) for (int y = 0; y < Hei; y++) { - int BlockZ = (y - m_OriginY) / m_Zoom; + int BlockZ = (y - m_OriginY) * m_Zoom; int ChunkZ = (BlockZ >= 0) ? (BlockZ / 16) : ((BlockZ + 1) / 16 - 1); int RelZ = BlockZ - ChunkZ * 16; for (int x = 0; x < Wid; x++) { - int BlockX = (x - m_OriginX) / m_Zoom; + int BlockX = (x - m_OriginX) * m_Zoom; int ChunkX = (BlockX >= 0) ? (BlockX / 16) : ((BlockX + 1) / 16 - 1); int RelX = BlockX - ChunkX * 16; if ((ChunkZ != CurChunkZ) || (ChunkX != CurChunkX)) diff --git a/Tools/BiomeVisualiser/BiomeRenderer.h b/Tools/BiomeVisualiser/BiomeRenderer.h index 2590e0406..752b61811 100644 --- a/Tools/BiomeVisualiser/BiomeRenderer.h +++ b/Tools/BiomeVisualiser/BiomeRenderer.h @@ -37,6 +37,11 @@ public: void MoveViewBy(int a_OffsX, int a_OffsY); + void SetZoom(int a_NewZoom) + { + m_Zoom = a_NewZoom; + } + protected: cBiomeCache m_Cache; diff --git a/Tools/BiomeVisualiser/BiomeViewWnd.cpp b/Tools/BiomeVisualiser/BiomeViewWnd.cpp index 5c1240bc7..7fb61c062 100644 --- a/Tools/BiomeVisualiser/BiomeViewWnd.cpp +++ b/Tools/BiomeVisualiser/BiomeViewWnd.cpp @@ -67,17 +67,41 @@ void cBiomeViewWnd::InitBiomeView(void) +void cBiomeViewWnd::SetZoom(int a_NewZoom) +{ + m_Renderer.SetZoom(a_NewZoom); + Redraw(); +} + + + + + +void cBiomeViewWnd::Redraw(void) +{ + if (m_Renderer.Render(m_Pixmap)) + { + SetTimer(m_Wnd, TIMER_RERENDER, 200, NULL); + } + InvalidateRect(m_Wnd, NULL, FALSE); +} + + + + + LRESULT cBiomeViewWnd::WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lParam) { switch (a_Msg) { - case WM_CLOSE: return OnClose(); - case WM_COMMAND: return OnCommand(wParam, lParam); + case WM_CHAR: return OnChar (wParam, lParam); + case WM_CLOSE: return OnClose (); + case WM_COMMAND: return OnCommand (wParam, lParam); case WM_LBUTTONDOWN: return OnLButtonDown(wParam, lParam); case WM_LBUTTONUP: return OnLButtonUp (wParam, lParam); case WM_MOUSEMOVE: return OnMouseMove (wParam, lParam); - case WM_PAINT: return OnPaint(); - case WM_TIMER: return OnTimer(wParam); + case WM_PAINT: return OnPaint (); + case WM_TIMER: return OnTimer (wParam); } return ::DefWindowProc(a_Wnd, a_Msg, wParam, lParam); } @@ -86,6 +110,32 @@ LRESULT cBiomeViewWnd::WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lPa +LRESULT cBiomeViewWnd::OnChar(WPARAM wParam, LPARAM lParam) +{ + switch (wParam) + { + case '1': SetZoom(1); break; + case '2': SetZoom(2); break; + case '3': SetZoom(3); break; + case '4': SetZoom(4); break; + case '5': SetZoom(5); break; + case '6': SetZoom(6); break; + case '7': SetZoom(7); break; + case '8': SetZoom(8); break; + case 27: + { + // Esc pressed, exit + PostQuitMessage(0); + break; + } + } + return 0; +} + + + + + LRESULT cBiomeViewWnd::OnClose(void) { PostQuitMessage(0); @@ -126,12 +176,8 @@ LRESULT cBiomeViewWnd::OnMouseMove(WPARAM wParam, LPARAM lParam) POINT pnt; GetCursorPos(&pnt); m_Renderer.MoveViewBy(pnt.x - m_MouseDown.x, pnt.y - m_MouseDown.y); - if (m_Renderer.Render(m_Pixmap)) - { - SetTimer(m_Wnd, TIMER_RERENDER, 200, NULL); - } m_MouseDown = pnt; - InvalidateRect(m_Wnd, NULL, FALSE); + Redraw(); return 0; } diff --git a/Tools/BiomeVisualiser/BiomeViewWnd.h b/Tools/BiomeVisualiser/BiomeViewWnd.h index e3f70c7e6..70c5e38f2 100644 --- a/Tools/BiomeVisualiser/BiomeViewWnd.h +++ b/Tools/BiomeVisualiser/BiomeViewWnd.h @@ -48,9 +48,13 @@ protected: void InitBiomeView(void); + void SetZoom(int a_NewZoom); + void Redraw(void); + LRESULT WndProc(HWND a_Wnd, UINT a_Msg, WPARAM wParam, LPARAM lParam); // Message handlers: + LRESULT OnChar (WPARAM wParam, LPARAM lParam); LRESULT OnClose (void); LRESULT OnCommand (WPARAM wParam, LPARAM lParam); LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam); diff --git a/Tools/BiomeVisualiser/BiomeVisualiser.vcproj b/Tools/BiomeVisualiser/BiomeVisualiser.vcproj index e42870b13..368657938 100644 --- a/Tools/BiomeVisualiser/BiomeVisualiser.vcproj +++ b/Tools/BiomeVisualiser/BiomeVisualiser.vcproj @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="windows-1250"?> <VisualStudioProject ProjectType="Visual C++" - Version="9,00" + Version="9.00" Name="BiomeVisualiser" ProjectGUID="{6DF3D88B-AD47-45B6-B831-1BDE74F86B5C}" RootNamespace="BiomeVisualiser" @@ -273,6 +273,10 @@ > </File> <File + RelativePath=".\BiomeColors.h" + > + </File> + <File RelativePath=".\BiomeRenderer.cpp" > </File> @@ -501,10 +505,6 @@ </Filter> </Filter> </Filter> - <File - RelativePath=".\BiomeColors.h" - > - </File> </Files> <Globals> </Globals> diff --git a/Tools/ProtoProxy/.gitignore b/Tools/ProtoProxy/.gitignore index 2a38341e5..8def77d0b 100644 --- a/Tools/ProtoProxy/.gitignore +++ b/Tools/ProtoProxy/.gitignore @@ -3,3 +3,6 @@ Release Logs/ *.log *.nbt +*.sln +*.vcproj +*.vcxproj diff --git a/Tools/ProtoProxy/CMakeLists.txt b/Tools/ProtoProxy/CMakeLists.txt new file mode 100644 index 000000000..f8a01a134 --- /dev/null +++ b/Tools/ProtoProxy/CMakeLists.txt @@ -0,0 +1,153 @@ + +cmake_minimum_required (VERSION 2.6) + +project (ProtoProxy) + + + +macro(add_flags_cxx FLAGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS}") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS}") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS}") +endmacro() + + + + +# Add the preprocessor macros used for distinguishing between debug and release builds (CMake does this automatically for MSVC): +if (NOT MSVC) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DNDEBUG") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG") +endif() + + + +if(MSVC) + # Make build use multiple threads under MSVC: + add_flags_cxx("/MP") + + # Make release builds use link-time code generation: + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG") +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") + endif() +else() + # Let gcc / clang know that we're compiling a multi-threaded app: + add_flags_cxx("-pthread") +endif() + + + + +# Use static CRT in MSVC builds: +if (MSVC) + string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") + string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + string(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") + string(REPLACE "/MDd" "/MTd" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") +endif() + + + + +# Set include paths to the used libraries: +include_directories("../../lib") +include_directories("../../src") + + +function(flatten_files arg1) + set(res "") + foreach(f ${${arg1}}) + get_filename_component(f ${f} ABSOLUTE) + list(APPEND res ${f}) + endforeach() + set(${arg1} "${res}" PARENT_SCOPE) +endfunction() + + +# Include the libraries: +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}) + +file(GLOB ZLIB_SRC "../../lib/zlib/*.c") +file(GLOB ZLIB_HDR "../../lib/zlib/*.h") +flatten_files(ZLIB_SRC) +flatten_files(ZLIB_HDR) +source_group("ZLib" FILES ${ZLIB_SRC} ${ZLIB_HDR}) + + +# Include the shared files: +set(SHARED_SRC + ../../src/ByteBuffer.cpp + ../../src/StringUtils.cpp + ../../src/Log.cpp + ../../src/MCLogger.cpp +) +set(SHARED_HDR + ../../src/ByteBuffer.h + ../../src/StringUtils.h + ../../src/Log.h + ../../src/MCLogger.h +) +set(SHARED_OSS_SRC + ../../src/OSSupport/CriticalSection.cpp + ../../src/OSSupport/File.cpp + ../../src/OSSupport/IsThread.cpp + ../../src/OSSupport/Timer.cpp +) +set(SHARED_OSS_HDR + ../../src/OSSupport/CriticalSection.h + ../../src/OSSupport/File.h + ../../src/OSSupport/IsThread.h + ../../src/OSSupport/Timer.h +) +flatten_files(SHARED_SRC) +flatten_files(SHARED_HDR) +flatten_files(SHARED_OSS_SRC) +flatten_files(SHARED_OSS_HDR) +source_group("Shared" FILES ${SHARED_SRC} ${SHARED_HDR}) +source_group("Shared\\OSSupport" FILES ${SHARED_OSS_SRC} ${SHARED_OSS_HDR}) + + + +# Include the main source files: +set(SOURCES + Connection.cpp + Globals.cpp + ProtoProxy.cpp + Server.cpp +) +set(HEADERS + Connection.h + Globals.h + Server.h +) +source_group("" FILES ${SOURCES} ${HEADERS}) + +add_executable(ProtoProxy + ${SOURCES} + ${HEADERS} + ${SHARED_SRC} + ${SHARED_HDR} + ${SHARED_OSS_SRC} + ${SHARED_OSS_HDR} + ${CRYPTOPP_SRC} + ${CRYPTOPP_HDR} + ${ZLIB_SRC} + ${ZLIB_HDR} +) + diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index 10f2b4073..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)) @@ -319,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"); @@ -336,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; } @@ -376,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; } @@ -424,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; @@ -1249,7 +1275,7 @@ bool cConnection::HandleServerLoginDisconnect(void) HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Reason); Log("Received a login-disconnect packet from the server:"); Log(" Reason = \"%s\"", Reason.c_str()); - COPY_TO_SERVER(); + COPY_TO_CLIENT(); return true; } @@ -1664,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; @@ -1864,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); @@ -1903,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; } @@ -2390,12 +2399,12 @@ bool cConnection::HandleServerStatusResponse(void) { Response.assign(Response.substr(0, idx + sizeof(DescSearch) - 1) + "ProtoProxy: " + Response.substr(idx + sizeof(DescSearch) - 1)); } - cByteBuffer Packet(1000); + cByteBuffer Packet(Response.size() + 50); Packet.WriteVarInt(0); // Packet type - status response Packet.WriteVarUTF8String(Response); AString Pkt; Packet.ReadAll(Pkt); - cByteBuffer ToClient(1000); + cByteBuffer ToClient(Response.size() + 50); ToClient.WriteVarUTF8String(Pkt); CLIENTSEND(ToClient); return true; @@ -2853,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/ProtoProxy.sln b/Tools/ProtoProxy/ProtoProxy.sln deleted file mode 100644 index 1c8c1a2a7..000000000 --- a/Tools/ProtoProxy/ProtoProxy.sln +++ /dev/null @@ -1,29 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual C++ Express 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProtoProxy", "ProtoProxy.vcproj", "{EFEC8F76-1397-49A4-885B-314CB4244231}" - ProjectSection(ProjectDependencies) = postProject - {3423EC9A-52E4-4A4D-9753-EDEBC38785EF} = {3423EC9A-52E4-4A4D-9753-EDEBC38785EF} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CryptoPP", "..\..\VC2008\CryptoPP.vcproj", "{3423EC9A-52E4-4A4D-9753-EDEBC38785EF}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {EFEC8F76-1397-49A4-885B-314CB4244231}.Debug|Win32.ActiveCfg = Debug|Win32 - {EFEC8F76-1397-49A4-885B-314CB4244231}.Debug|Win32.Build.0 = Debug|Win32 - {EFEC8F76-1397-49A4-885B-314CB4244231}.Release|Win32.ActiveCfg = Release|Win32 - {EFEC8F76-1397-49A4-885B-314CB4244231}.Release|Win32.Build.0 = Release|Win32 - {3423EC9A-52E4-4A4D-9753-EDEBC38785EF}.Debug|Win32.ActiveCfg = Debug|Win32 - {3423EC9A-52E4-4A4D-9753-EDEBC38785EF}.Debug|Win32.Build.0 = Debug|Win32 - {3423EC9A-52E4-4A4D-9753-EDEBC38785EF}.Release|Win32.ActiveCfg = Release|Win32 - {3423EC9A-52E4-4A4D-9753-EDEBC38785EF}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/Tools/ProtoProxy/ProtoProxy.vcproj b/Tools/ProtoProxy/ProtoProxy.vcproj deleted file mode 100644 index 0b3c77bc5..000000000 --- a/Tools/ProtoProxy/ProtoProxy.vcproj +++ /dev/null @@ -1,279 +0,0 @@ -<?xml version="1.0" encoding="windows-1250"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="9,00" - Name="ProtoProxy" - ProjectGUID="{EFEC8F76-1397-49A4-885B-314CB4244231}" - RootNamespace="ProtoProxy" - Keyword="Win32Proj" - TargetFrameworkVersion="196613" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Debug|Win32" - OutputDirectory="$(SolutionDir)$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" - ConfigurationType="1" - CharacterSet="2" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="0" - AdditionalIncludeDirectories="../../lib;../../src" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS" - MinimalRebuild="true" - BasicRuntimeChecks="3" - RuntimeLibrary="1" - UsePrecompiledHeader="2" - PrecompiledHeaderThrough="Globals.h" - WarningLevel="3" - DebugInformationFormat="4" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="ws2_32.lib" - LinkIncremental="2" - GenerateDebugInformation="true" - SubSystem="1" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - <Configuration - Name="Release|Win32" - OutputDirectory="$(SolutionDir)$(ConfigurationName)" - IntermediateDirectory="$(ConfigurationName)" - ConfigurationType="1" - CharacterSet="2" - WholeProgramOptimization="1" - > - <Tool - Name="VCPreBuildEventTool" - /> - <Tool - Name="VCCustomBuildTool" - /> - <Tool - Name="VCXMLDataGeneratorTool" - /> - <Tool - Name="VCWebServiceProxyGeneratorTool" - /> - <Tool - Name="VCMIDLTool" - /> - <Tool - Name="VCCLCompilerTool" - Optimization="2" - EnableIntrinsicFunctions="true" - AdditionalIncludeDirectories="../../lib;../../src" - PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS" - RuntimeLibrary="0" - EnableFunctionLevelLinking="true" - UsePrecompiledHeader="2" - PrecompiledHeaderThrough="Globals.h" - WarningLevel="3" - DebugInformationFormat="3" - /> - <Tool - Name="VCManagedResourceCompilerTool" - /> - <Tool - Name="VCResourceCompilerTool" - /> - <Tool - Name="VCPreLinkEventTool" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="ws2_32.lib" - LinkIncremental="1" - GenerateDebugInformation="true" - SubSystem="1" - OptimizeReferences="2" - EnableCOMDATFolding="2" - TargetMachine="1" - /> - <Tool - Name="VCALinkTool" - /> - <Tool - Name="VCManifestTool" - /> - <Tool - Name="VCXDCMakeTool" - /> - <Tool - Name="VCBscMakeTool" - /> - <Tool - Name="VCFxCopTool" - /> - <Tool - Name="VCAppVerifierTool" - /> - <Tool - Name="VCPostBuildEventTool" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <Filter - Name="Source Files" - Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;h;hpp" - UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" - > - <File - RelativePath=".\Connection.cpp" - > - </File> - <File - RelativePath=".\Connection.h" - > - </File> - <File - RelativePath=".\Globals.cpp" - > - <FileConfiguration - Name="Debug|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="1" - /> - </FileConfiguration> - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - UsePrecompiledHeader="1" - /> - </FileConfiguration> - </File> - <File - RelativePath=".\Globals.h" - > - </File> - <File - RelativePath=".\ProtoProxy.cpp" - > - </File> - <File - RelativePath=".\Server.cpp" - > - </File> - <File - RelativePath=".\Server.h" - > - </File> - </Filter> - <Filter - Name="shared" - > - <File - RelativePath="..\..\src\ByteBuffer.cpp" - > - </File> - <File - RelativePath="..\..\src\ByteBuffer.h" - > - </File> - <File - RelativePath="..\..\src\StringUtils.cpp" - > - </File> - <File - RelativePath="..\..\src\StringUtils.h" - > - </File> - <Filter - Name="OSSupport" - > - <File - RelativePath="..\..\src\OSSupport\CriticalSection.cpp" - > - </File> - <File - RelativePath="..\..\src\OSSupport\CriticalSection.h" - > - </File> - <File - RelativePath="..\..\src\OSSupport\IsThread.cpp" - > - </File> - <File - RelativePath="..\..\src\OSSupport\IsThread.h" - > - </File> - <File - RelativePath="..\..\src\OSSupport\Timer.cpp" - > - </File> - <File - RelativePath="..\..\src\OSSupport\Timer.h" - > - </File> - </Filter> - </Filter> - <File - RelativePath=".\ProtoProxy.txt" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> 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 a017b5a25..0927f2f7b 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -413,15 +413,15 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > <File - RelativePath=".\icon.ico" + RelativePath="..\src\Resources\icon.ico" > </File> <File - RelativePath=".\MCServer.rc" + RelativePath="..\src\Resources\MCServer.rc" > </File> <File - RelativePath=".\resource_MCServer.h" + RelativePath="..\src\Resources\resource_MCServer.h" > </File> <File @@ -443,6 +443,14 @@ > </File> <File + RelativePath="..\src\BiomeDef.cpp" + > + </File> + <File + RelativePath="..\src\BiomeDef.h" + > + </File> + <File RelativePath="..\src\BlockArea.cpp" > </File> @@ -2018,10 +2026,6 @@ > </File> <File - RelativePath="..\src\Bindings\tolua_base.h" - > - </File> - <File RelativePath="..\src\Bindings\WebPlugin.cpp" > </File> diff --git a/VC2008/debug_profile_run.cmd b/VC2008/debug_profile_run.cmd deleted file mode 100644 index a078768d0..000000000 --- a/VC2008/debug_profile_run.cmd +++ /dev/null @@ -1,73 +0,0 @@ -@echo off -:: -:: Profiling using a MSVC standalone profiler -:: -:: See http://www.codeproject.com/Articles/144643/Profiling-of-C-Applications-in-Visual-Studio-for-F for details -:: - - - - -set pt="C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools" -set appdir=..\MCServer -set app=MCServer_dbgprof.exe - -:: outputdir is relative to appdir! -set outputdir=..\Profiling -set outputname=profile.vsp -set output=%outputdir%\%outputname% - - - - - -:: Must cd to MCServer's directory so that it can find settings.ini etc. -cd %appdir% - -::Create the output directory, if it didn't exist -mkdir %outputdir% - - - - - -:: Start the profiler -%pt%\vsperfcmd /start:sample /output:%output% -if errorlevel 1 goto haderror - -:: Launch the application via the profiler -%pt%\vsperfcmd /launch:%app% -if errorlevel 1 goto haderror - -:: Shut down the profiler (this command waits, until the application is terminated) -%pt%\vsperfcmd /shutdown -if errorlevel 1 goto haderror - - - - - -:: cd to outputdir, so that the reports are generated there -cd %outputdir% - -:: generate the report files (.csv) -%pt%\vsperfreport /summary:all %outputname% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols" -if errorlevel 1 goto haderror - - - - - -goto finished - - - - -:haderror -echo An error was encountered -pause - - - - -:finished diff --git a/VC2008/profile_run.cmd b/VC2008/profile_run.cmd deleted file mode 100644 index e8e6eb11b..000000000 --- a/VC2008/profile_run.cmd +++ /dev/null @@ -1,73 +0,0 @@ -@echo off -:: -:: Profiling using a MSVC standalone profiler -:: -:: See http://www.codeproject.com/Articles/144643/Profiling-of-C-Applications-in-Visual-Studio-for-F for details -:: - - - - -set pt="C:\Program Files\Microsoft Visual Studio 9.0\Team Tools\Performance Tools" -set appdir=..\MCServer -set app=MCServer_profiled.exe - -:: outputdir is relative to appdir! -set outputdir=..\Profiling -set outputname=profile.vsp -set output=%outputdir%\%outputname% - - - - - -:: Must cd to MCServer's directory so that it can find settings.ini etc. -cd %appdir% - -::Create the output directory, if it didn't exist -mkdir %outputdir% - - - - - -:: Start the profiler -%pt%\vsperfcmd /start:sample /output:%output% -if errorlevel 1 goto haderror - -:: Launch the application via the profiler -%pt%\vsperfcmd /launch:%app% -if errorlevel 1 goto haderror - -:: Shut down the profiler (this command waits, until the application is terminated) -%pt%\vsperfcmd /shutdown -if errorlevel 1 goto haderror - - - - - -:: cd to outputdir, so that the reports are generated there -cd %outputdir% - -:: generate the report files (.csv) -%pt%\vsperfreport /summary:all %outputname% /symbolpath:"srv*C:\Programovani\Symbols*http://msdl.microsoft.com/download/symbols" -if errorlevel 1 goto haderror - - - - - -goto finished - - - - -:haderror -echo An error was encountered -pause - - - - -:finished diff --git a/VC2013/CryptoPP.vcxproj.filters b/VC2013/CryptoPP.vcxproj.filters index becd042b8..d47a1c34c 100644 --- a/VC2013/CryptoPP.vcxproj.filters +++ b/VC2013/CryptoPP.vcxproj.filters @@ -2,15 +2,15 @@ <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <ItemGroup> <Filter Include="Source Files"> - <UniqueIdentifier>{3c30caed-20a3-4bd8-b12e-fdd1e13455e5}</UniqueIdentifier> + <UniqueIdentifier>{59bfc075-705c-42cd-adf7-40cef1aed8e1}</UniqueIdentifier> <Extensions>.cpp</Extensions> </Filter> <Filter Include="Header Files"> - <UniqueIdentifier>{770573d2-b90d-43f4-ac1c-464ab10c46ec}</UniqueIdentifier> + <UniqueIdentifier>{407d7f02-df9e-485b-a95f-2f1dad08cbed}</UniqueIdentifier> <Extensions>.;.h</Extensions> </Filter> <Filter Include="Miscellaneous"> - <UniqueIdentifier>{1ac058bb-f217-4ac3-a14b-9c6ba021e030}</UniqueIdentifier> + <UniqueIdentifier>{293a01a6-81d1-4272-a7ff-310526bbc77f}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> diff --git a/VC2013/MCServer.rc b/VC2013/MCServer.rc deleted file mode 100644 index e0fbbea5d..000000000 --- a/VC2013/MCServer.rc +++ /dev/null @@ -1,17 +0,0 @@ -// Generated by ResEdit 1.5.11 -// Copyright (C) 2006-2012 -// http://www.resedit.net - -#include <windows.h> -#include <commctrl.h> -#include <richedit.h> -#include "resource_MCServer.h" - - - - -// -// Icon resources -// -LANGUAGE 9, SUBLANG_DEFAULT -IDI_ICON1 ICON "icon.ico" diff --git a/VC2013/MCServer.vcxproj b/VC2013/MCServer.vcxproj index 9daecba07..36c29bf11 100644 --- a/VC2013/MCServer.vcxproj +++ b/VC2013/MCServer.vcxproj @@ -218,14 +218,15 @@ </Link> </ItemDefinitionGroup> <ItemGroup> - <Image Include="icon.ico" /> + <Image Include="..\src\Resources\icon.ico" /> </ItemGroup> <ItemGroup> - <ResourceCompile Include="MCServer.rc" /> + <ResourceCompile Include="..\src\Resources\MCServer.rc" /> </ItemGroup> <ItemGroup> - <ClInclude Include="resource_MCServer.h" /> + <ClInclude Include="..\src\Resources\resource_MCServer.h" /> <ClInclude Include="..\src\Authenticator.h" /> + <ClInclude Include="..\src\BiomeDef.h" /> <ClInclude Include="..\src\BlockArea.h" /> <ClInclude Include="..\src\BlockID.h" /> <ClInclude Include="..\src\BlockTracer.h" /> @@ -372,7 +373,6 @@ <ClInclude Include="..\src\Bindings\Plugin.h" /> <ClInclude Include="..\src\Bindings\PluginLua.h" /> <ClInclude Include="..\src\Bindings\PluginManager.h" /> - <ClInclude Include="..\src\Bindings\tolua_base.h" /> <ClInclude Include="..\src\Bindings\WebPlugin.h" /> <ClInclude Include="..\lib\inifile\iniFile.h" /> <ClInclude Include="..\lib\md5\md5.h" /> @@ -616,6 +616,7 @@ </ItemGroup> <ItemGroup> <ClCompile Include="..\src\Authenticator.cpp" /> + <ClCompile Include="..\src\BiomeDef.cpp" /> <ClCompile Include="..\src\BlockArea.cpp" /> <ClCompile Include="..\src\BlockID.cpp" /> <ClCompile Include="..\src\BoundingBox.cpp" /> diff --git a/VC2013/MCServer.vcxproj.filters b/VC2013/MCServer.vcxproj.filters index 30e90a9b0..176afad2e 100644 --- a/VC2013/MCServer.vcxproj.filters +++ b/VC2013/MCServer.vcxproj.filters @@ -10,73 +10,73 @@ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> </Filter> <Filter Include="Source Files\Mobs"> - <UniqueIdentifier>{813698c3-b2c1-4f3d-a89c-7ac6239fff97}</UniqueIdentifier> + <UniqueIdentifier>{46ffa881-c36b-41b0-85df-90e0f78c6285}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Entities"> - <UniqueIdentifier>{b120a538-d8b9-4576-8675-36cf01fd69fc}</UniqueIdentifier> + <UniqueIdentifier>{5eb3c155-b618-4232-92a5-52b3ae70ec96}</UniqueIdentifier> </Filter> <Filter Include="Source Files\UI"> - <UniqueIdentifier>{85037cf1-81a5-47c7-8c2e-899ea706b8e7}</UniqueIdentifier> + <UniqueIdentifier>{5f745788-b9aa-4dde-9763-cdfaddb3dfdf}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Simulator"> - <UniqueIdentifier>{46c9cb22-7c7f-4589-b9b2-1fc79d2bdbdf}</UniqueIdentifier> + <UniqueIdentifier>{acb44271-df18-41b2-8a50-656a49c39d3c}</UniqueIdentifier> </Filter> <Filter Include="Source Files\OSSupport"> - <UniqueIdentifier>{f12178cb-2ecb-4e48-9a8d-ba3e2e73cfbc}</UniqueIdentifier> + <UniqueIdentifier>{1091cb9f-3d9d-4ed5-9359-fc762be21759}</UniqueIdentifier> </Filter> <Filter Include="Source Files\OSSupport\Android Specific"> - <UniqueIdentifier>{488bc224-735f-405c-83de-870373cb52cb}</UniqueIdentifier> + <UniqueIdentifier>{c40bec86-f173-440a-b07e-bab15c8ce965}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Bindings"> - <UniqueIdentifier>{41c0d7c9-43b5-4d17-b50e-3c8ac3aa2905}</UniqueIdentifier> + <UniqueIdentifier>{4180990c-1257-4d07-9009-08535fedfbf8}</UniqueIdentifier> </Filter> <Filter Include="Source Files\External"> - <UniqueIdentifier>{2c71a15a-8c65-4be7-bdfb-e083f4841c4a}</UniqueIdentifier> + <UniqueIdentifier>{ffc2297f-c790-4190-a56f-ac6a1f97a30c}</UniqueIdentifier> </Filter> <Filter Include="Source Files\WorldStorage"> - <UniqueIdentifier>{2227f719-f0ac-444e-af14-230853017c45}</UniqueIdentifier> + <UniqueIdentifier>{011ff757-845a-4342-862e-44207ec46a94}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Generating"> - <UniqueIdentifier>{eb070b55-ba10-4bce-ba06-5d785a055e54}</UniqueIdentifier> + <UniqueIdentifier>{7f7a0b8c-4ee6-4a3a-92d6-5ba242a565f3}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Blocks"> - <UniqueIdentifier>{779dac55-c718-4fe1-8b67-547d431b9ebc}</UniqueIdentifier> + <UniqueIdentifier>{07157169-9da7-4998-9f00-4580641cf811}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Items"> - <UniqueIdentifier>{89847a5d-608a-4137-a766-1557276b4fcf}</UniqueIdentifier> + <UniqueIdentifier>{5b92b198-0a58-4399-9c8e-662bd5062b6c}</UniqueIdentifier> </Filter> <Filter Include="Source Files\Protocol"> - <UniqueIdentifier>{e159d08d-daec-46de-9b60-9f8e660da91d}</UniqueIdentifier> + <UniqueIdentifier>{16a88457-3862-4ff0-a591-a7160ea956f5}</UniqueIdentifier> </Filter> <Filter Include="Source Files\SQLite"> - <UniqueIdentifier>{0278092b-abe5-4276-81cf-59e4079e5bc7}</UniqueIdentifier> + <UniqueIdentifier>{a3561ecf-a501-4c76-b176-1f214b7a5523}</UniqueIdentifier> </Filter> <Filter Include="Source Files\LuaExpat"> - <UniqueIdentifier>{e4879cf2-e769-4e1d-8905-0f6c40ee5bc1}</UniqueIdentifier> + <UniqueIdentifier>{a35eb320-d10b-4592-92ed-2d2f242dbed7}</UniqueIdentifier> </Filter> <Filter Include="Source Files\BlockEntities"> - <UniqueIdentifier>{d641a9d4-f5dc-4808-bee6-194306505244}</UniqueIdentifier> + <UniqueIdentifier>{1c271d11-30ce-4aef-b8a9-7c8ee560d5d6}</UniqueIdentifier> </Filter> <Filter Include="Source Files\HTTPServer"> - <UniqueIdentifier>{a1e39415-2aca-4779-a558-2567a9de304f}</UniqueIdentifier> + <UniqueIdentifier>{223bdf26-d107-498f-8c42-00c19ef80348}</UniqueIdentifier> </Filter> <Filter Include="Config files"> - <UniqueIdentifier>{eb5f3060-03ed-4548-8bde-340454d3d23a}</UniqueIdentifier> + <UniqueIdentifier>{99140e5f-0287-4601-ad28-bad2533d8876}</UniqueIdentifier> </Filter> <Filter Include="Plugins"> - <UniqueIdentifier>{7c681450-041a-4846-acf6-951c1f4e32a4}</UniqueIdentifier> + <UniqueIdentifier>{beb25b3b-31f3-468e-a721-6d0dc297e4b5}</UniqueIdentifier> </Filter> <Filter Include="Plugins\Core"> - <UniqueIdentifier>{e961964c-9fb7-4513-89fa-05e0b760e0f1}</UniqueIdentifier> + <UniqueIdentifier>{f848f39d-680d-4f9c-8dcb-da9a0bb871f5}</UniqueIdentifier> </Filter> <Filter Include="Plugins\ChatLog"> - <UniqueIdentifier>{70696c83-2307-43c6-8851-81aa3baa8523}</UniqueIdentifier> + <UniqueIdentifier>{7c735e41-f3b2-4500-856b-54845f834eb2}</UniqueIdentifier> </Filter> <Filter Include="Plugins\Debuggers"> - <UniqueIdentifier>{d3b692db-0684-4b89-9d38-2e5af12e9a6e}</UniqueIdentifier> + <UniqueIdentifier>{83d5aac9-2975-4334-9acc-b48e96a16b23}</UniqueIdentifier> </Filter> <Filter Include="Plugins\APIDump"> - <UniqueIdentifier>{6eee304c-f055-4758-a248-a125e1af7e73}</UniqueIdentifier> + <UniqueIdentifier>{e5167107-9cc8-4e03-b519-c3a13b9b7955}</UniqueIdentifier> </Filter> </ItemGroup> <ItemGroup> @@ -96,6 +96,9 @@ <ClInclude Include="..\src\Authenticator.h"> <Filter>Source Files</Filter> </ClInclude> + <ClInclude Include="..\src\BiomeDef.h"> + <Filter>Source Files</Filter> + </ClInclude> <ClInclude Include="..\src\BlockArea.h"> <Filter>Source Files</Filter> </ClInclude> @@ -513,9 +516,6 @@ <ClInclude Include="..\src\Bindings\PluginManager.h"> <Filter>Source Files\Bindings</Filter> </ClInclude> - <ClInclude Include="..\src\Bindings\tolua_base.h"> - <Filter>Source Files\Bindings</Filter> - </ClInclude> <ClInclude Include="..\src\Bindings\WebPlugin.h"> <Filter>Source Files\Bindings</Filter> </ClInclude> @@ -1114,6 +1114,9 @@ <ClCompile Include="..\src\Authenticator.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\src\BiomeDef.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="..\src\BlockArea.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/VC2013/icon.ico b/VC2013/icon.ico Binary files differdeleted file mode 100644 index 4024523a1..000000000 --- a/VC2013/icon.ico +++ /dev/null diff --git a/VC2013/resource_MCServer.h b/VC2013/resource_MCServer.h deleted file mode 100644 index 42f6c4eaf..000000000 --- a/VC2013/resource_MCServer.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef IDC_STATIC -#define IDC_STATIC (-1) -#endif - -#define IDI_ICON1 101 diff --git a/lib/cryptopp/misc.h b/lib/cryptopp/misc.h index 2b326dd60..9149b9ac0 100644 --- a/lib/cryptopp/misc.h +++ b/lib/cryptopp/misc.h @@ -545,7 +545,7 @@ inline void SecureWipeArray(T *buf, size_t n) } // this function uses wcstombs(), which assumes that setlocale() has been called -static std::string StringNarrow(const wchar_t *str, bool throwOnError = true) +inline std::string StringNarrow(const wchar_t *str, bool throwOnError = true) { #ifdef _MSC_VER #pragma warning(push) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index da523e783..afa1c110d 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -137,7 +137,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) { valuename = line.substr(0, pLeft); value = line.substr(pLeft + 1); - SetValue(keyname, valuename, value); + AddValue(keyname, valuename, value); break; } @@ -344,55 +344,79 @@ AString cIniFile::GetValueName(const AString & keyname, const int valueID) const +void cIniFile::AddValue(const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value) +{ + int keyID = FindKey(a_KeyName); + if (keyID == noID) + { + keyID = int(AddKeyName(a_KeyName)); + } + + keys[keyID].names.push_back(a_ValueName); + keys[keyID].values.push_back(a_Value); +} + + + + + +void cIniFile::AddValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value) +{ + AddValue(a_KeyName, a_ValueName, Printf("%d", a_Value)); +} + + + + + +void cIniFile::AddValueF(const AString & a_KeyName, const AString & a_ValueName, const double a_Value) +{ + AddValue(a_KeyName, a_ValueName, Printf("%f", a_Value)); +} + + + + + bool cIniFile::SetValue(const int keyID, const int valueID, const AString & value) { - if ((keyID < (int)keys.size()) && (valueID < (int)keys[keyID].names.size())) + if (((size_t)keyID >= keys.size()) || ((size_t)valueID >= keys[keyID].names.size())) { - keys[keyID].values[valueID] = value; + return false; } - return false; + keys[keyID].values[valueID] = value; + return true; } -bool cIniFile::SetValue(const AString & keyname, const AString & valuename, const AString & value, bool const create) +bool cIniFile::SetValue(const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists) { - int keyID = FindKey(keyname); + int keyID = FindKey(a_KeyName); if (keyID == noID) { - if (create) - { - keyID = int(AddKeyName(keyname)); - } - else + if (!a_CreateIfNotExists) { return false; } + keyID = AddKeyName(a_KeyName); } - int valueID = FindValue(int(keyID), valuename); + int valueID = FindValue(keyID, a_ValueName); if (valueID == noID) { - if (!create) + if (!a_CreateIfNotExists) { return false; } - keys[keyID].names.resize(keys[keyID].names.size() + 1, valuename); - keys[keyID].values.resize(keys[keyID].values.size() + 1, value); + keys[keyID].names.push_back(a_ValueName); + keys[keyID].values.push_back(a_Value); } else { - if (!create) - { - keys[keyID].values[valueID] = value; - } - else - { - keys[keyID].names.resize(keys[keyID].names.size() + 1, valuename); - keys[keyID].values.resize(keys[keyID].values.size() + 1, value); - } + keys[keyID].values[valueID] = a_Value; } return true; @@ -402,37 +426,32 @@ bool cIniFile::SetValue(const AString & keyname, const AString & valuename, cons -bool cIniFile::SetValueI(const AString & keyname, const AString & valuename, const int value, bool const create) +bool cIniFile::SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists) { - AString Data; - Printf(Data, "%d", value); - return SetValue(keyname, valuename, Data, create); + return SetValue(a_KeyName, a_ValueName, Printf("%d", a_Value), a_CreateIfNotExists); } -bool cIniFile::SetValueF(const AString & keyname, const AString & valuename, double const value, bool const create) +bool cIniFile::SetValueF(const AString & a_KeyName, const AString & a_ValueName, double const a_Value, const bool a_CreateIfNotExists) { - AString Data; - Printf(Data, "%f", value); - return SetValue(keyname, valuename, Data, create); + return SetValue(a_KeyName, a_ValueName, Printf("%f", a_Value), a_CreateIfNotExists); } -bool cIniFile::SetValueV(const AString & keyname, const AString & valuename, char * format, ...) +bool cIniFile::SetValueV(const AString & a_KeyName, const AString & a_ValueName, const char * a_Format, ...) { va_list args; - va_start(args, format); - + va_start(args, a_Format); AString Data; - AppendVPrintf(Data, format, args); + AppendVPrintf(Data, a_Format, args); va_end(args); - return SetValue(keyname, valuename, Data); + return SetValue(a_KeyName, a_ValueName, Data); } diff --git a/lib/inifile/iniFile.h b/lib/inifile/iniFile.h index 83d961fc6..40af618dc 100644 --- a/lib/inifile/iniFile.h +++ b/lib/inifile/iniFile.h @@ -35,7 +35,7 @@ class cIniFile { private: - bool m_IsCaseInsensitive; + bool m_IsCaseInsensitive; struct key { @@ -122,22 +122,32 @@ public: return (GetValueSetI(keyname, valuename, defValue ? 1 : 0) != 0); } - // Sets value of [keyname] valuename =. - // Specify the optional paramter as false (0) if you do not want it to create - // the key if it doesn't exist. Returns true if data entered, false otherwise. + // Adds a new value to the specified key. + // If a value of the same name already exists, creates another one (non-standard INI file) + void AddValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value); + void AddValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value); + void AddValueB(const AString & a_KeyName, const AString & a_ValueName, const bool a_Value) + { + return AddValueI(a_KeyName, a_ValueName, a_Value ? 1 : 0); + } + void AddValueF(const AString & a_KeyName, const AString & a_ValueName, const double a_Value); + + // Overwrites the value of [keyname].valuename + // Specify the optional parameter as false (0) if you do not want the value created if it doesn't exist. + // Returns true if value set, false otherwise. // Overloaded to accept string, int, and double. - bool SetValue( const int keyID, const int valueID, const AString & value); - bool SetValue( const AString & keyname, const AString & valuename, const AString & value, const bool create = true); - bool SetValueI( const AString & keyname, const AString & valuename, const int value, const bool create = true); - bool SetValueB( const AString & keyname, const AString & valuename, const bool value, const bool create = true) + bool SetValue (const int keyID, const int valueID, const AString & value); + bool SetValue (const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists = true); + bool SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists = true); + bool SetValueB(const AString & a_KeyName, const AString & a_ValueName, const bool a_Value, const bool a_CreateIfNotExists = true) { - return SetValueI( keyname, valuename, int(value), create); + return SetValueI(a_KeyName, a_ValueName, int(a_Value), a_CreateIfNotExists); } - bool SetValueF( const AString & keyname, const AString & valuename, const double value, const bool create = true); + bool SetValueF(const AString & a_KeyName, const AString & a_ValueName, const double a_Value, const bool a_CreateIfNotExists = true); // tolua_end - bool SetValueV( const AString & keyname, const AString & valuename, char *format, ...); + bool SetValueV( const AString & a_KeyName, const AString & a_ValueName, const char * a_Format, ...); // tolua_begin diff --git a/lib/lua/CMakeLists.txt b/lib/lua/CMakeLists.txt index b4b5b5f1d..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/") @@ -21,10 +21,44 @@ endif() # Lua needs to be linked dynamically on Windows and statically on *nix, so that LuaRocks work if (WIN32) add_library(lua SHARED ${SOURCE}) + set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer) + + # Output the executable into the $/MCServer folder, so that MCServer can find it: + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer) + 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 + RUNTIME_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer + ) + + if (MSVC) + # Remove SCL warnings, we expect this library to have been tested safe + SET_TARGET_PROPERTIES( + 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() +# Tell Lua what dynamic loader to use (for LuaRocks): +if (UNIX) + add_definitions(-DLUA_USE_DLOPEN) +endif() + if (UNIX) target_link_libraries(lua m ${DYNAMIC_LOADER}) endif() + diff --git a/lib/zlib/CMakeLists.txt b/lib/zlib/CMakeLists.txt index fe6dba6ae..b1b74031d 100644 --- a/lib/zlib/CMakeLists.txt +++ b/lib/zlib/CMakeLists.txt @@ -9,3 +9,11 @@ file(GLOB SOURCE ) add_library(zlib ${SOURCE}) + +if (MSVC) + # Remove SCL warnings, we expect this library to have been tested safe + SET_TARGET_PROPERTIES( + zlib PROPERTIES COMPILE_FLAGS "-D_CRT_SECURE_NO_WARNINGS" + ) +endif() + diff --git a/lib/zlib/example.c b/lib/zlib/example.c.txt index f515a4853..f515a4853 100644 --- a/lib/zlib/example.c +++ b/lib/zlib/example.c.txt diff --git a/lib/zlib/minigzip.c b/lib/zlib/minigzip.c.txt index aa7ac7a04..aa7ac7a04 100644 --- a/lib/zlib/minigzip.c +++ b/lib/zlib/minigzip.c.txt diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index e9a5ea0c6..2d0300ebf 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -1,8 +1,6 @@ $#include "../Globals.h" -$#include "tolua_base.h" - // Typedefs from Globals.h, so that we don't have to process that file: typedef long long Int64; typedef int Int32; @@ -14,6 +12,7 @@ typedef unsigned short UInt16; $cfile "../ChunkDef.h" +$cfile "../BiomeDef.h" $cfile "../../lib/inifile/iniFile.h" diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 83351591c..00e62fcf6 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -228,6 +228,9 @@ bool cLuaState::PushFunction(const char * a_FunctionName) return false; } + // Push the error handler for lua_pcall() + lua_pushcfunction(m_LuaState, &ReportFnCallErrors); + lua_getglobal(m_LuaState, a_FunctionName); if (!lua_isfunction(m_LuaState, -1)) { @@ -249,6 +252,9 @@ bool cLuaState::PushFunction(int a_FnRef) ASSERT(IsValid()); ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack + // Push the error handler for lua_pcall() + lua_pushcfunction(m_LuaState, &ReportFnCallErrors); + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // same as lua_getref() if (!lua_isfunction(m_LuaState, -1)) { @@ -264,27 +270,29 @@ bool cLuaState::PushFunction(int a_FnRef) -bool cLuaState::PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName) +bool cLuaState::PushFunction(const cTableRef & a_TableRef) { ASSERT(IsValid()); ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack - - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef); // Get the table ref + + // Push the error handler for lua_pcall() + lua_pushcfunction(m_LuaState, &ReportFnCallErrors); + + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef.GetTableRef()); // Get the table ref if (!lua_istable(m_LuaState, -1)) { // Not a table, bail out lua_pop(m_LuaState, 1); return false; } - lua_getfield(m_LuaState, -1, a_FnName); + lua_getfield(m_LuaState, -1, a_TableRef.GetFnName()); if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1)) { // Not a valid function, bail out lua_pop(m_LuaState, 2); return false; } - lua_remove(m_LuaState, -2); // Remove the table ref from the stack - m_CurrentFunctionName = "<table_callback>"; + Printf(m_CurrentFunctionName, "<table-callback %s>", a_TableRef.GetFnName()); m_NumCurrentFunctionArgs = 0; return true; } @@ -624,18 +632,6 @@ void cLuaState::Push(cTNTEntity * a_TNTEntity) -void cLuaState::Push(cCreeper * a_Creeper) -{ - ASSERT(IsValid()); - - tolua_pushusertype(m_LuaState, a_Creeper, "cCreeper"); - m_NumCurrentFunctionArgs += 1; -} - - - - - void cLuaState::Push(Vector3i * a_Vector) { ASSERT(IsValid()); @@ -732,11 +728,13 @@ void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal) bool cLuaState::CallFunction(int a_NumResults) { ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first - ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1)); + ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1)); // The function to call + ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 2)); // The error handler - int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, 0); - if (ReportErrors(s)) + int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, -m_NumCurrentFunctionArgs - 2); + if (s != 0) { + // The error has already been printed together with the stacktrace LOGWARNING("Error in %s calling function %s()", m_SubsystemName.c_str(), m_CurrentFunctionName.c_str()); m_NumCurrentFunctionArgs = -1; m_CurrentFunctionName.clear(); @@ -964,15 +962,24 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status) void cLuaState::LogStackTrace(void) { + LogStackTrace(m_LuaState); +} + + + + + +void cLuaState::LogStackTrace(lua_State * a_LuaState) +{ LOGWARNING("Stack trace:"); lua_Debug entry; int depth = 0; - while (lua_getstack(m_LuaState, depth, &entry)) + while (lua_getstack(a_LuaState, depth, &entry)) { - int status = lua_getinfo(m_LuaState, "Sln", &entry); + int status = lua_getinfo(a_LuaState, "Sln", &entry); assert(status); - LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?"); + LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "(no name)"); depth++; } LOGWARNING("Stack trace end"); @@ -1005,6 +1012,17 @@ AString cLuaState::GetTypeText(int a_StackPos) +int cLuaState::ReportFnCallErrors(lua_State * a_LuaState) +{ + LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1)); + LogStackTrace(a_LuaState); + return 1; // We left the error message on the stack as the return value +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cLuaState::cRef: diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h index 796559b6f..414e5e4b2 100644 --- a/src/Bindings/LuaState.h +++ b/src/Bindings/LuaState.h @@ -85,6 +85,23 @@ public: } ; + /** Used for calling functions stored in a reference-stored table */ + class cTableRef + { + int m_TableRef; + const char * m_FnName; + public: + cTableRef(int a_TableRef, const char * a_FnName) : + m_TableRef(a_TableRef), + m_FnName(a_FnName) + { + } + + int GetTableRef(void) const { return m_TableRef; } + const char * GetFnName(void) const { return m_FnName; } + } ; + + /// A dummy class that's used only to delimit function args from return values for cLuaState::Call() class cRet { @@ -133,24 +150,6 @@ public: /// Returns true if a_FunctionName is a valid Lua function that can be called bool HasFunction(const char * a_FunctionName); - /** Pushes the function of the specified name onto the stack. - Returns true if successful. Logs a warning on failure (incl. m_SubsystemName) - */ - bool PushFunction(const char * a_FunctionName); - - /** Pushes a function that has been saved into the global registry, identified by a_FnRef. - Returns true if successful. Logs a warning on failure - */ - bool PushFunction(int a_FnRef); - - /** Pushes a function that is stored in a table ref. - Returns true if successful, false on failure. Doesn't log failure. - */ - bool PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName); - - /// Pushes a usertype of the specified class type onto the stack - void PushUserType(void * a_Object, const char * a_Type); - // Push a value onto the stack void Push(const AString & a_String); void Push(const AStringVector & a_Vector); @@ -178,12 +177,11 @@ public: void Push(cWebAdmin * a_WebAdmin); void Push(const HTTPTemplateRequest * a_Request); void Push(cTNTEntity * a_TNTEntity); - void Push(cCreeper * a_Creeper); void Push(Vector3i * a_Vector); void Push(void * a_Ptr); void Push(cHopperEntity * a_Hopper); void Push(cBlockEntity * a_BlockEntity); - + /// Call any 0-param 0-return Lua function in a single line: template <typename FnT> bool Call(FnT a_FnName) @@ -802,25 +800,6 @@ public: } - /// Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, bool & a_ReturnedVal); - - /// Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, AString & a_ReturnedVal); - - /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, int & a_ReturnedVal); - - /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged - void GetReturn(int a_StackPos, double & a_ReturnedVal); - - /** - Calls the function that has been pushed onto the stack by PushFunction(), - with arguments pushed by PushXXX(). - Returns true if successful, logs a warning on failure. - */ - bool CallFunction(int a_NumReturnValues); - /// Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1); @@ -848,6 +827,9 @@ public: /// Logs all items in the current stack trace to the server console void LogStackTrace(void); + /// Logs all items in the current stack trace to the server console + static void LogStackTrace(lua_State * a_LuaState); + /// Returns the type of the item on the specified position in the stack AString GetTypeText(int a_StackPos); @@ -867,6 +849,47 @@ protected: /// Number of arguments currently pushed (for the Push / Call chain) int m_NumCurrentFunctionArgs; + + + /** Pushes the function of the specified name onto the stack. + Returns true if successful. Logs a warning on failure (incl. m_SubsystemName) + */ + bool PushFunction(const char * a_FunctionName); + + /** Pushes a function that has been saved into the global registry, identified by a_FnRef. + Returns true if successful. Logs a warning on failure + */ + bool PushFunction(int a_FnRef); + + /** Pushes a function that is stored in a referenced table by name + Returns true if successful. Logs a warning on failure + */ + bool PushFunction(const cTableRef & a_TableRef); + + /// Pushes a usertype of the specified class type onto the stack + void PushUserType(void * a_Object, const char * a_Type); + + /// Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, bool & a_ReturnedVal); + + /// Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, AString & a_ReturnedVal); + + /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, int & a_ReturnedVal); + + /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged + void GetReturn(int a_StackPos, double & a_ReturnedVal); + + /** + Calls the function that has been pushed onto the stack by PushFunction(), + with arguments pushed by PushXXX(). + Returns true if successful, logs a warning on failure. + */ + bool CallFunction(int a_NumReturnValues); + + /** Used as the error reporting function for function calls */ + static int ReportFnCallErrors(lua_State * a_LuaState); } ; diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 6221727c4..ebee2d697 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -984,6 +984,73 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S) +class cLuaScheduledWorldTask : + public cWorld::cScheduledTask +{ +public: + cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef, int a_Ticks) : + cScheduledTask(a_Ticks), + m_Plugin(a_Plugin), + m_FnRef(a_FnRef) + { + } + +protected: + cPluginLua & m_Plugin; + int m_FnRef; + + // cWorld::cTask overrides: + virtual void Run(cWorld & a_World) override + { + m_Plugin.Call(m_FnRef, &a_World); + } +}; + + + + + +static int tolua_cWorld_ScheduleTask(lua_State * tolua_S) +{ + // Binding for cWorld::ScheduleTask + // Params: function, Ticks + + // Retrieve the cPlugin from the LuaState: + cPluginLua * Plugin = GetLuaPlugin(tolua_S); + if (Plugin == NULL) + { + // An error message has been already printed in GetLuaPlugin() + return 0; + } + + // Retrieve the args: + cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, 0); + if (self == NULL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance"); + } + if (!lua_isfunction(tolua_S, 2)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1"); + } + + // Create a reference to the function: + int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FnRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1"); + } + + int Ticks = (int) tolua_tonumber (tolua_S, 3, 0); + + self->ScheduleTask(new cLuaScheduledWorldTask(*Plugin, FnRef, Ticks)); + return 0; +} + + + + + static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) { cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, 0); @@ -991,7 +1058,6 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) const cPluginManager::PluginMap & AllPlugins = self->GetAllPlugins(); lua_newtable(tolua_S); - int newTable = lua_gettop(tolua_S); int index = 1; cPluginManager::PluginMap::const_iterator iter = AllPlugins.begin(); while (iter != AllPlugins.end()) @@ -1883,7 +1949,6 @@ static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) const cWebPlugin::TabNameList & TabNames = self->GetTabNames(); lua_newtable(tolua_S); - int newTable = lua_gettop(tolua_S); int index = 1; cWebPlugin::TabNameList::const_iterator iter = TabNames.begin(); while(iter != TabNames.end()) @@ -1904,6 +1969,35 @@ static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S) +static int tolua_cClientHandle_SendPluginMessage(lua_State * L) +{ + cLuaState S(L); + if ( + !S.CheckParamUserType(1, "cClientHandle") || + !S.CheckParamString(2, 3) || + !S.CheckParamEnd(4) + ) + { + return 0; + } + cClientHandle * Client = (cClientHandle *)tolua_tousertype(L, 1, NULL); + if (Client == NULL) + { + LOGWARNING("ClientHandle is nil in cClientHandle:SendPluginMessage()"); + S.LogStackTrace(); + return 0; + } + AString Channel, Message; + Channel.assign(lua_tostring(L, 2), lua_strlen(L, 2)); + Message.assign(lua_tostring(L, 3), lua_strlen(L, 3)); + Client->SendPluginMessage(Channel, Message); + return 0; +} + + + + + static int Lua_ItemGrid_GetSlotCoords(lua_State * L) { tolua_Error tolua_err; @@ -1953,118 +2047,72 @@ public: virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnNextBlock"), + a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_EntryFace, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - m_LuaState.Push(a_BlockType); - m_LuaState.Push(a_BlockMeta); - m_LuaState.Push(a_EntryFace); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnNextBlockNoData"), + a_BlockX, a_BlockY, a_BlockZ, a_EntryFace, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - m_LuaState.Push(a_EntryFace); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnOutOfWorld")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnOutOfWorld"), + a_BlockX, a_BlockY, a_BlockZ, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnIntoWorld")) + bool res = false; + if (!m_LuaState.Call( + cLuaState::cTableRef(m_TableRef, "OnIntoWorld"), + a_BlockX, a_BlockY, a_BlockZ, + cLuaState::Return, res + )) { // No such function in the table, skip the callback return false; } - m_LuaState.Push(a_BlockX); - m_LuaState.Push(a_BlockY); - m_LuaState.Push(a_BlockZ); - if (!m_LuaState.CallFunction(1)) - { - return false; - } - bool res = false; - if (lua_isboolean(m_LuaState, -1)) - { - res = (lua_toboolean(m_LuaState, -1) != 0); - } - lua_pop(m_LuaState, 1); return res; } virtual void OnNoMoreHits(void) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoMoreHits")) - { - // No such function in the table, skip the callback - return; - } - m_LuaState.CallFunction(0); + m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoMoreHits")); } virtual void OnNoChunk(void) override { - if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoChunk")) - { - // No such function in the table, skip the callback - return; - } - m_LuaState.CallFunction(0); + m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoChunk")); } protected: @@ -2237,6 +2285,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta); tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines); tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask); + tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask); tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); @@ -2292,6 +2341,7 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_beginmodule(tolua_S, "cClientHandle"); tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); + tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cItemGrid"); diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 209842e55..4c4664815 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -90,6 +90,8 @@ bool cPluginLua::Initialize(void) // Load all files for this plugin, and execute them AStringVector Files = cFile::GetFolderContents(PluginPath.c_str()); + + int numFiles = 0; for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr) { if (itr->rfind(".lua") == AString::npos) @@ -101,9 +103,20 @@ bool cPluginLua::Initialize(void) { Close(); return false; + } + else + { + numFiles++; } } // for itr - Files[] + if (numFiles == 0) + { + LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str()); + Close(); + return false; + } + // Call intialize function bool res = false; if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res)) @@ -423,7 +436,7 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool & { case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; - case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; + case esMonster: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cMonster *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 68e6aea33..24bb914d1 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -169,9 +169,9 @@ void cPluginManager::InsertDefaultPlugins(cIniFile & a_SettingsIni) a_SettingsIni.AddKeyComment("Plugins", " Plugin=HookNotify"); a_SettingsIni.AddKeyComment("Plugins", " Plugin=ChunkWorx"); a_SettingsIni.AddKeyComment("Plugins", " Plugin=APIDump"); - a_SettingsIni.SetValue("Plugins", "Plugin", "Core"); - a_SettingsIni.SetValue("Plugins", "Plugin", "TransAPI"); - a_SettingsIni.SetValue("Plugins", "Plugin", "ChatLog"); + a_SettingsIni.AddValue("Plugins", "Plugin", "Core"); + a_SettingsIni.AddValue("Plugins", "Plugin", "TransAPI"); + a_SettingsIni.AddValue("Plugins", "Plugin", "ChatLog"); } diff --git a/src/Bindings/tolua++.h b/src/Bindings/tolua++.h index 4dfd06318..73e65b746 100644 --- a/src/Bindings/tolua++.h +++ b/src/Bindings/tolua++.h @@ -2,12 +2,18 @@ // tolua++.h // Redirection file, needed because ToLua++ generates the Bindings.cpp file with >> #include "tolua++.h" << +// Only used from Bindings.cpp #include "tolua++/include/tolua++.h" +#ifdef _MSC_VER + // Disable specific warnings for the generated Bindings.cpp file: + #pragma warning(disable: 4800) // 'int' : forcing value to bool 'true' or 'false' (performance warning) +#endif // _MSC_VER + diff --git a/src/Bindings/tolua_base.h b/src/Bindings/tolua_base.h deleted file mode 100644 index 6a76f97b1..000000000 --- a/src/Bindings/tolua_base.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef TOLUA_BASE_H -#define TOLUA_BASE_H - -#pragma warning(disable:4800) // This file is ONLY included by Bindings.cpp and it throws lots of C4800 warnings - -#include "tolua++/include/tolua++.h" - - - - - -class ToluaBase { - - int lua_instance; - -protected: - - lua_State* lua_state; - - void lua_stacktrace(lua_State* L) const - { - lua_Debug entry; - int depth = 0; - - while (lua_getstack(L, depth, &entry)) - { - lua_getinfo(L, "Sln", &entry); - - LOGERROR("%s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?"); - depth++; - } - } - - - bool report_errors(int status) const - { - if ( status!=0 ) - { - const char* s = lua_tostring(lua_state, -1); - LOGERROR("-- %s", s ); - //lua_pop(lua_state, 1); - LOGERROR("Stack:"); - lua_stacktrace( lua_state ); - return true; - } - return false; - } - - bool push_method(const char* name, lua_CFunction f) const { - - if (!lua_state) return false; - - lua_getref(lua_state, lua_instance); - lua_pushstring(lua_state, name); - //LOGINFO("1. push_method() Stack size: %i", lua_gettop( lua_state ) ); - lua_gettable(lua_state, -2); - //LOGINFO("2. push_method() Stack size: %i", lua_gettop( lua_state ) ); - - if (lua_isnil(lua_state, -1)) { - - // pop the table - lua_pop(lua_state, 2); - return false; - - } else { - - if (f) { - if (lua_iscfunction(lua_state, -1)) { - lua_pop(lua_state, 2); - return false; - }; - /* // not for now - lua_pushcfunction(lua_state, f); - if (lua_rawequal(lua_state, -1, -2)) { - - // avoid recursion, pop both functions and the table - lua_pop(lua_state, 3); - return false; - }; - - // pop f - lua_pop(lua_state, 1); - */ - }; - - // swap table with function - lua_insert(lua_state, -2); - }; - - return true; - }; - - void dbcall(lua_State* L, int nargs, int nresults) const { - - // using lua_call for now - int s = lua_pcall(L, nargs, nresults, 0); - report_errors( s ); - }; -public: - - int GetInstance() { return lua_instance; } - lua_State* GetLuaState() { return lua_state; } - - void tolua__set_instance(lua_State* L, lua_Object lo) { - - lua_state = L; - - lua_pushvalue(L, lo); - lua_instance = lua_ref(lua_state, 1); - }; - - ToluaBase() { - - lua_state = NULL; - }; - - ~ToluaBase() { - - if (lua_state) { - - lua_unref(lua_state, lua_instance); - }; - }; -}; - -#endif - - diff --git a/src/Bindings/virtual_method_hooks.lua b/src/Bindings/virtual_method_hooks.lua index 15ff1d7f8..c610d424f 100644 --- a/src/Bindings/virtual_method_hooks.lua +++ b/src/Bindings/virtual_method_hooks.lua @@ -504,3 +504,11 @@ end + +function post_output_hook() + print("Bindings have been generated.") +end + + + + diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp new file mode 100644 index 000000000..89a1cdefb --- /dev/null +++ b/src/BiomeDef.cpp @@ -0,0 +1,131 @@ + +// BiomeDef.cpp + +// Implements biome helper functions + +#include "Globals.h" +#include "BiomeDef.h" + + +EMCSBiome StringToBiome(const AString & a_BiomeString) +{ + // If it is a number, return it: + int res = atoi(a_BiomeString.c_str()); + if ((res != 0) || (a_BiomeString.compare("0") == 0)) + { + // It was a valid number + return (EMCSBiome)res; + } + + // Convert using the built-in map: + static struct { + EMCSBiome m_Biome; + const char * m_String; + } BiomeMap[] = + { + {biOcean, "Ocean"} , + {biPlains, "Plains"}, + {biDesert, "Desert"}, + {biExtremeHills, "ExtremeHills"}, + {biForest, "Forest"}, + {biTaiga, "Taiga"}, + {biSwampland, "Swampland"}, + {biRiver, "River"}, + {biNether, "Hell"}, + {biNether, "Nether"}, + {biEnd, "Sky"}, + {biEnd, "End"}, + {biFrozenOcean, "FrozenOcean"}, + {biFrozenRiver, "FrozenRiver"}, + {biIcePlains, "IcePlains"}, + {biIcePlains, "Tundra"}, + {biIceMountains, "IceMountains"}, + {biMushroomIsland, "MushroomIsland"}, + {biMushroomShore, "MushroomShore"}, + {biBeach, "Beach"}, + {biDesertHills, "DesertHills"}, + {biForestHills, "ForestHills"}, + {biTaigaHills, "TaigaHills"}, + {biExtremeHillsEdge, "ExtremeHillsEdge"}, + {biJungle, "Jungle"}, + {biJungleHills, "JungleHills"}, + + // Release 1.7 biomes: + {biJungleEdge, "JungleEdge"}, + {biDeepOcean, "DeepOcean"}, + {biStoneBeach, "StoneBeach"}, + {biColdBeach, "ColdBeach"}, + {biBirchForest, "BirchForest"}, + {biBirchForestHills, "BirchForestHills"}, + {biRoofedForest, "RoofedForest"}, + {biColdTaiga, "ColdTaiga"}, + {biColdTaigaHills, "ColdTaigaHills"}, + {biMegaTaiga, "MegaTaiga"}, + {biMegaTaigaHills, "MegaTaigaHills"}, + {biExtremeHillsPlus, "ExtremeHillsPlus"}, + {biSavanna, "Savanna"}, + {biSavannaPlateau, "SavannaPlateau"}, + {biMesa, "Mesa"}, + {biMesaPlateauF, "MesaPlateauF"}, + {biMesaPlateau, "MesaPlateau"}, + + // Release 1.7 variants: + {biSunflowerPlains, "SunflowerPlains"}, + {biDesertM, "DesertM"}, + {biExtremeHillsM, "ExtremeHillsM"}, + {biFlowerForest, "FlowerForest"}, + {biTaigaM, "TaigaM"}, + {biSwamplandM, "SwamplandM"}, + {biIcePlainsSpikes, "IcePlainsSpikes"}, + {biJungleM, "JungleM"}, + {biJungleEdgeM, "JungleEdgeM"}, + {biBirchForestM, "BirchForestM"}, + {biBirchForestHillsM, "BirchForestHillsM"}, + {biRoofedForestM, "RoofedForestM"}, + {biColdTaigaM, "ColdTaigaM"}, + {biMegaSpruceTaiga, "MegaSpruceTaiga"}, + {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"}, + {biExtremeHillsPlusM, "ExtremeHillsPlusM"}, + {biSavannaM, "SavannaM"}, + {biSavannaPlateauM, "SavannaPlateauM"}, + {biMesaBryce, "MesaBryce"}, + {biMesaPlateauFM, "MesaPlateauFM"}, + {biMesaPlateauM, "MesaPlateauM"}, + } ; + + for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++) + { + if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0) + { + return BiomeMap[i].m_Biome; + } + } // for i - BiomeMap[] + return (EMCSBiome)-1; +} + + + + + +bool IsBiomeNoDownfall(EMCSBiome a_Biome) +{ + switch (a_Biome) + { + case biDesert: + case biDesertHills: + case biDesertM: + case biSavanna: + case biSavannaM: + case biSavannaPlateau: + case biSavannaPlateauM: + case biNether: + case biEnd: + { + return true; + } + default: + { + return false; + } + } +} diff --git a/src/BiomeDef.h b/src/BiomeDef.h new file mode 100644 index 000000000..df1e387f0 --- /dev/null +++ b/src/BiomeDef.h @@ -0,0 +1,107 @@ + +// BiomeDef.h + +// Defines relevant information and methods related to biomes + + + + + +#pragma once + + + + + +// tolua_begin +/** Biome IDs +The first batch corresponds to the clientside biomes, used by MineCraft. +BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client +*/ +enum EMCSBiome +{ + biOcean = 0, + biPlains = 1, + biDesert = 2, + biExtremeHills = 3, + biForest = 4, + biTaiga = 5, + biSwampland = 6, + biRiver = 7, + biHell = 8, // same as Nether + biNether = 8, + biSky = 9, // same as biEnd + biEnd = 9, + biFrozenOcean = 10, + biFrozenRiver = 11, + biIcePlains = 12, + biTundra = 12, // same as Ice Plains + biIceMountains = 13, + biMushroomIsland = 14, + biMushroomShore = 15, + biBeach = 16, + biDesertHills = 17, + biForestHills = 18, + biTaigaHills = 19, + biExtremeHillsEdge = 20, + biJungle = 21, + biJungleHills = 22, + + // Release 1.7 biomes: + biJungleEdge = 23, + biDeepOcean = 24, + biStoneBeach = 25, + biColdBeach = 26, + biBirchForest = 27, + biBirchForestHills = 28, + biRoofedForest = 29, + biColdTaiga = 30, + biColdTaigaHills = 31, + biMegaTaiga = 32, + biMegaTaigaHills = 33, + biExtremeHillsPlus = 34, + biSavanna = 35, + biSavannaPlateau = 36, + biMesa = 37, + biMesaPlateauF = 38, + biMesaPlateau = 39, + + // Automatically capture the maximum consecutive biome value into biMaxBiome: + biNumBiomes, // True number of biomes, since they are zero-based + biMaxBiome = biNumBiomes - 1, // The maximum biome value + + // Add this number to the biomes to get the variant + biVariant = 128, + + // Release 1.7 biome variants: + biSunflowerPlains = 129, + biDesertM = 130, + biExtremeHillsM = 131, + biFlowerForest = 132, + biTaigaM = 133, + biSwamplandM = 134, + biIcePlainsSpikes = 140, + biJungleM = 149, + biJungleEdgeM = 151, + biBirchForestM = 155, + biBirchForestHillsM = 156, + biRoofedForestM = 157, + biColdTaigaM = 158, + biMegaSpruceTaiga = 160, + biMegaSpruceTaigaHills = 161, + biExtremeHillsPlusM = 162, + biSavannaM = 163, + biSavannaPlateauM = 164, + biMesaBryce = 165, + biMesaPlateauFM = 166, + biMesaPlateauM = 167, +} ; + +/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure. +extern EMCSBiome StringToBiome(const AString & a_BiomeString); + +/// Returns true if the biome has no downfall - deserts and savannas +extern bool IsBiomeNoDownfall(EMCSBiome a_Biome); + + +// tolua_end 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/BlockID.cpp b/src/BlockID.cpp index 05d4c6595..095865d07 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -20,7 +20,7 @@ bool g_BlockPistonBreakable[256]; bool g_BlockIsSnowable[256]; bool g_BlockRequiresSpecialTool[256]; bool g_BlockIsSolid[256]; -bool g_BlockIsTorchPlaceable[256]; +bool g_BlockFullyOccupiesVoxel[256]; @@ -267,106 +267,6 @@ AString ItemToFullString(const cItem & a_Item) -EMCSBiome StringToBiome(const AString & a_BiomeString) -{ - // If it is a number, return it: - int res = atoi(a_BiomeString.c_str()); - if ((res != 0) || (a_BiomeString.compare("0") == 0)) - { - // It was a valid number - return (EMCSBiome)res; - } - - // Convert using the built-in map: - static struct { - EMCSBiome m_Biome; - const char * m_String; - } BiomeMap[] = - { - {biOcean, "Ocean"} , - {biPlains, "Plains"}, - {biDesert, "Desert"}, - {biExtremeHills, "ExtremeHills"}, - {biForest, "Forest"}, - {biTaiga, "Taiga"}, - {biSwampland, "Swampland"}, - {biRiver, "River"}, - {biNether, "Hell"}, - {biNether, "Nether"}, - {biEnd, "Sky"}, - {biEnd, "End"}, - {biFrozenOcean, "FrozenOcean"}, - {biFrozenRiver, "FrozenRiver"}, - {biIcePlains, "IcePlains"}, - {biIcePlains, "Tundra"}, - {biIceMountains, "IceMountains"}, - {biMushroomIsland, "MushroomIsland"}, - {biMushroomShore, "MushroomShore"}, - {biBeach, "Beach"}, - {biDesertHills, "DesertHills"}, - {biForestHills, "ForestHills"}, - {biTaigaHills, "TaigaHills"}, - {biExtremeHillsEdge, "ExtremeHillsEdge"}, - {biJungle, "Jungle"}, - {biJungleHills, "JungleHills"}, - - // Release 1.7 biomes: - {biJungleEdge, "JungleEdge"}, - {biDeepOcean, "DeepOcean"}, - {biStoneBeach, "StoneBeach"}, - {biColdBeach, "ColdBeach"}, - {biBirchForest, "BirchForest"}, - {biBirchForestHills, "BirchForestHills"}, - {biRoofedForest, "RoofedForest"}, - {biColdTaiga, "ColdTaiga"}, - {biColdTaigaHills, "ColdTaigaHills"}, - {biMegaTaiga, "MegaTaiga"}, - {biMegaTaigaHills, "MegaTaigaHills"}, - {biExtremeHillsPlus, "ExtremeHillsPlus"}, - {biSavanna, "Savanna"}, - {biSavannaPlateau, "SavannaPlateau"}, - {biMesa, "Mesa"}, - {biMesaPlateauF, "MesaPlateauF"}, - {biMesaPlateau, "MesaPlateau"}, - - // Release 1.7 variants: - {biSunflowerPlains, "SunflowerPlains"}, - {biDesertM, "DesertM"}, - {biExtremeHillsM, "ExtremeHillsM"}, - {biFlowerForest, "FlowerForest"}, - {biTaigaM, "TaigaM"}, - {biSwamplandM, "SwamplandM"}, - {biIcePlainsSpikes, "IcePlainsSpikes"}, - {biJungleM, "JungleM"}, - {biJungleEdgeM, "JungleEdgeM"}, - {biBirchForestM, "BirchForestM"}, - {biBirchForestHillsM, "BirchForestHillsM"}, - {biRoofedForestM, "RoofedForestM"}, - {biColdTaigaM, "ColdTaigaM"}, - {biMegaSpruceTaiga, "MegaSpruceTaiga"}, - {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"}, - {biExtremeHillsPlusM, "ExtremeHillsPlusM"}, - {biSavannaM, "SavannaM"}, - {biSavannaPlateauM, "SavannaPlateauM"}, - {biMesaBryce, "MesaBryce"}, - {biMesaPlateauFM, "MesaPlateauFM"}, - {biMesaPlateauM, "MesaPlateauM"}, - } ; - - for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++) - { - if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0) - { - return BiomeMap[i].m_Biome; - } - } // for i - BiomeMap[] - return (EMCSBiome)-1; -} - - - - - int StringToMobType(const AString & a_MobString) { static struct { @@ -591,7 +491,7 @@ public: memset(g_BlockTransparent, 0x00, sizeof(g_BlockTransparent)); memset(g_BlockOneHitDig, 0x00, sizeof(g_BlockOneHitDig)); memset(g_BlockPistonBreakable, 0x00, sizeof(g_BlockPistonBreakable)); - memset(g_BlockIsTorchPlaceable, 0x00, sizeof(g_BlockIsTorchPlaceable)); + memset(g_BlockFullyOccupiesVoxel, 0x00, sizeof(g_BlockFullyOccupiesVoxel)); // Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415 for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSnowable); i++) @@ -867,6 +767,7 @@ public: g_BlockIsSolid[E_BLOCK_MELON_STEM] = false; g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false; g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false; + g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false; g_BlockIsSolid[E_BLOCK_RAIL] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false; g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false; @@ -891,67 +792,67 @@ public: g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false; // Torch placeable blocks: - g_BlockIsTorchPlaceable[E_BLOCK_BEDROCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_COAL] = true; - g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_REDSTONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_BOOKCASE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_BRICK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_CLAY] = true; - g_BlockIsTorchPlaceable[E_BLOCK_COAL_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_COBBLESTONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_COMMAND_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_CRAFTING_TABLE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DIAMOND_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DIAMOND_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DIRT] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DISPENSER] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DOUBLE_STONE_SLAB] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DOUBLE_WOODEN_SLAB] = true; - g_BlockIsTorchPlaceable[E_BLOCK_DROPPER] = true; - g_BlockIsTorchPlaceable[E_BLOCK_EMERALD_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_EMERALD_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_END_STONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_FURNACE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_GLOWSTONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_GOLD_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_GOLD_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_GRASS] = true; - g_BlockIsTorchPlaceable[E_BLOCK_GRAVEL] = true; - g_BlockIsTorchPlaceable[E_BLOCK_HARDENED_CLAY] = true; - g_BlockIsTorchPlaceable[E_BLOCK_HAY_BALE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_HUGE_BROWN_MUSHROOM] = true; - g_BlockIsTorchPlaceable[E_BLOCK_HUGE_RED_MUSHROOM] = true; - g_BlockIsTorchPlaceable[E_BLOCK_IRON_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_IRON_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_JACK_O_LANTERN] = true; - g_BlockIsTorchPlaceable[E_BLOCK_JUKEBOX] = true; - g_BlockIsTorchPlaceable[E_BLOCK_LAPIS_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_LAPIS_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_LOG] = true; - g_BlockIsTorchPlaceable[E_BLOCK_MELON] = true; - g_BlockIsTorchPlaceable[E_BLOCK_MOSSY_COBBLESTONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_MYCELIUM] = true; - g_BlockIsTorchPlaceable[E_BLOCK_NETHERRACK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_NETHER_BRICK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_NETHER_QUARTZ_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_NOTE_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_OBSIDIAN] = true; - g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_PLANKS] = true; - g_BlockIsTorchPlaceable[E_BLOCK_PUMPKIN] = true; - g_BlockIsTorchPlaceable[E_BLOCK_QUARTZ_BLOCK] = true; - g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_LAMP_OFF] = true; - g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_LAMP_ON] = true; - g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_ORE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_ORE_GLOWING] = true; - g_BlockIsTorchPlaceable[E_BLOCK_SANDSTONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_SAND] = true; - g_BlockIsTorchPlaceable[E_BLOCK_SILVERFISH_EGG] = true; - g_BlockIsTorchPlaceable[E_BLOCK_SPONGE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_STAINED_CLAY] = true; - g_BlockIsTorchPlaceable[E_BLOCK_WOOL] = true; - g_BlockIsTorchPlaceable[E_BLOCK_STONE] = true; - g_BlockIsTorchPlaceable[E_BLOCK_STONE_BRICKS] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_BEDROCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_COAL] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_REDSTONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_BOOKCASE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_BRICK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_CLAY] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_COAL_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_COBBLESTONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_COMMAND_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_CRAFTING_TABLE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DIRT] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DISPENSER] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_STONE_SLAB] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_WOODEN_SLAB] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_DROPPER] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_END_STONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_FURNACE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_GLOWSTONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_GRASS] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_GRAVEL] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_HARDENED_CLAY] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_HAY_BALE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_BROWN_MUSHROOM] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_RED_MUSHROOM] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_JACK_O_LANTERN] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_JUKEBOX] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_LOG] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_MELON] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_MOSSY_COBBLESTONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_MYCELIUM] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_NETHERRACK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_BRICK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_QUARTZ_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_NOTE_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_OBSIDIAN] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_PACKED_ICE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_PLANKS] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_PUMPKIN] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_QUARTZ_BLOCK] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_OFF] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_ON] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE_GLOWING] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_SANDSTONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_SAND] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_SILVERFISH_EGG] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_SPONGE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_STAINED_CLAY] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_WOOL] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_STONE] = true; + g_BlockFullyOccupiesVoxel[E_BLOCK_STONE_BRICKS] = true; } } BlockPropertiesInitializer; diff --git a/src/BlockID.h b/src/BlockID.h index 288719ccf..b31c589b9 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -876,9 +876,6 @@ extern AString ItemTypeToString(short a_ItemType); /// Translates a full item into a fully-specified string (including meta and count). If the ItemType is not recognized, the ItemType number is output into the string. extern AString ItemToFullString(const cItem & a_Item); -/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure. -extern EMCSBiome StringToBiome(const AString & a_BiomeString); - /// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT) extern int StringToMobType(const AString & a_MobString); @@ -909,7 +906,7 @@ extern bool g_BlockPistonBreakable[256]; extern bool g_BlockIsSnowable[256]; extern bool g_BlockRequiresSpecialTool[256]; extern bool g_BlockIsSolid[256]; -extern bool g_BlockIsTorchPlaceable[256]; +extern bool g_BlockFullyOccupiesVoxel[256]; 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/BlockGlowstone.h b/src/Blocks/BlockGlowstone.h index 5f0d95dee..6c198efc4 100644 --- a/src/Blocks/BlockGlowstone.h +++ b/src/Blocks/BlockGlowstone.h @@ -20,8 +20,8 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Reset meta to 0 - // TODO: More drops? - a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, 1, 0)); + MTRand r1; + a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, (char)(2 + r1.randInt(2)), 0)); } } ; diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index 15fe2071c..5b0c89127 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -20,7 +20,7 @@ public: // Flip the ON bit on/off using the XOR bitwise operation NIBBLETYPE Meta = (a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08); - a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER, Meta); // SetMeta doesn't work for unpowering levers, so setblock a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f); } 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/BlockRedstone.h b/src/Blocks/BlockRedstone.h index 1bd9995f2..5ffb77fb6 100644 --- a/src/Blocks/BlockRedstone.h +++ b/src/Blocks/BlockRedstone.h @@ -20,7 +20,7 @@ public: virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { - return ((a_RelY > 0) && g_BlockIsTorchPlaceable[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]); + return ((a_RelY > 0) && g_BlockFullyOccupiesVoxel[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]); } 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/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index 9e543dfd7..faba9c4f5 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -98,7 +98,7 @@ public: static bool CanBePlacedOn(BLOCKTYPE a_BlockType, char a_BlockFace) { - if ( !g_BlockIsTorchPlaceable[a_BlockType] ) + if ( !g_BlockFullyOccupiesVoxel[a_BlockType] ) { return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle } @@ -127,7 +127,7 @@ public: { return i; } - else if ((g_BlockIsTorchPlaceable[BlockInQuestion]) && (i != BLOCK_FACE_BOTTOM)) + else if ((g_BlockFullyOccupiesVoxel[BlockInQuestion]) && (i != BLOCK_FACE_BOTTOM)) { // Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face return i; @@ -161,7 +161,7 @@ public: // No need to check for upright orientation, it was done when the torch was placed return true; } - else if ( !g_BlockIsTorchPlaceable[BlockInQuestion] ) + else if ( !g_BlockFullyOccupiesVoxel[BlockInQuestion] ) { return false; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 853138769..275099540 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,11 +1,7 @@ -cmake_minimum_required (VERSION 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") @@ -25,12 +21,34 @@ if (NOT MSVC) list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp") + # If building a windows version, but not using MSVC, add the resources directly to the makefile: + if (WIN32) + FILE(GLOB ResourceFiles + "Resources/*.rc" + ) + list(APPEND SOURCE "${ResourceFiles}") + endif() + + else () + # Generate the Bindings if they don't exist: + if (NOT EXISTS "${PROJECT_SOURCE_DIR}/Bindings/Bindings.cpp") + message("Bindings.cpp not found, generating now") + set(tolua_executable ${PROJECT_SOURCE_DIR}/Bindings/tolua++.exe) + execute_process( + COMMAND ${tolua_executable} -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/Bindings + ) + endif() + + # Add all subfolders as solution-folders: + list(APPEND FOLDERS "Resources") function(includefolder PATH) FILE(GLOB FOLDER_FILES "${PATH}/*.cpp" "${PATH}/*.h" + "${PATH}/*.rc" ) source_group("${PATH}" FILES ${FOLDER_FILES}) endfunction(includefolder) @@ -59,25 +77,31 @@ else () SET_SOURCE_FILES_PROPERTIES( "StackWalker.cpp LeakFinder.h" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\"" ) + list(APPEND SOURCE "Resources/MCServer.rc") endif() - set(EXECUTABLE MCServer) add_executable(${EXECUTABLE} ${SOURCE}) -set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer) -if (MSVC) - # MSVC generator adds a "Debug" or "Release" postfixes to the EXECUTABLE_OUTPUT_PATH, we need to cancel them: - SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES PREFIX "../") - SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES IMPORT_PREFIX "../") -endif() +# Output the executable into the $/MCServer folder, so that it has access to external resources: +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer) +SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer + RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer + RUNTIME_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer + RUNTIME_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer +) # Make the debug executable have a "_debug" suffix SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES DEBUG_POSTFIX "_debug") +# Make the profiled executables have a "_profile" postfix +SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES DEBUGPROFILE_POSTFIX "_debug_profile") +SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES RELEASEPROFILE_POSTFIX "_profile") + # Precompiled headers (2nd part) if (MSVC) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index fb26e983d..0735c8144 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -1743,7 +1743,14 @@ bool cChunk::AddClient(cClientHandle* a_Client) for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr ) { - LOGD("cChunk: Entity #%d (%s) at [%i, %i, %i] spawning for player \"%s\"", (*itr)->GetUniqueID(), (*itr)->GetClass(), m_PosX, m_PosY, m_PosZ, a_Client->GetUsername().c_str()); + /* + // DEBUG: + LOGD("cChunk: Entity #%d (%s) at [%i, %i, %i] spawning for player \"%s\"", + (*itr)->GetUniqueID(), (*itr)->GetClass(), + m_PosX, m_PosY, m_PosZ, + a_Client->GetUsername().c_str() + ); + */ (*itr)->SpawnOn(*a_Client); } return true; @@ -1768,7 +1775,13 @@ void cChunk::RemoveClient( cClientHandle* a_Client ) { for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr ) { - LOGD("chunk [%i, %i] destroying entity #%i for player \"%s\"", m_PosX, m_PosZ, (*itr)->GetUniqueID(), a_Client->GetUsername().c_str() ); + /* + // DEBUG: + LOGD("chunk [%i, %i] destroying entity #%i for player \"%s\"", + m_PosX, m_PosZ, + (*itr)->GetUniqueID(), a_Client->GetUsername().c_str() + ); + */ a_Client->SendDestroyEntity(*(*itr)); } } diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 7d727a4d4..d1288994c 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -10,6 +10,7 @@ #pragma once #include "Vector3i.h" +#include "BiomeDef.h" @@ -57,97 +58,6 @@ typedef unsigned char HEIGHTTYPE; - - -// tolua_begin -/** Biome IDs -The first batch corresponds to the clientside biomes, used by MineCraft. -BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client -*/ -enum EMCSBiome -{ - biOcean = 0, - biPlains = 1, - biDesert = 2, - biExtremeHills = 3, - biForest = 4, - biTaiga = 5, - biSwampland = 6, - biRiver = 7, - biHell = 8, // same as Nether - biNether = 8, - biSky = 9, // same as biEnd - biEnd = 9, - biFrozenOcean = 10, - biFrozenRiver = 11, - biIcePlains = 12, - biTundra = 12, // same as Ice Plains - biIceMountains = 13, - biMushroomIsland = 14, - biMushroomShore = 15, - biBeach = 16, - biDesertHills = 17, - biForestHills = 18, - biTaigaHills = 19, - biExtremeHillsEdge = 20, - biJungle = 21, - biJungleHills = 22, - - // Release 1.7 biomes: - biJungleEdge = 23, - biDeepOcean = 24, - biStoneBeach = 25, - biColdBeach = 26, - biBirchForest = 27, - biBirchForestHills = 28, - biRoofedForest = 29, - biColdTaiga = 30, - biColdTaigaHills = 31, - biMegaTaiga = 32, - biMegaTaigaHills = 33, - biExtremeHillsPlus = 34, - biSavanna = 35, - biSavannaPlateau = 36, - biMesa = 37, - biMesaPlateauF = 38, - biMesaPlateau = 39, - - // Automatically capture the maximum consecutive biome value into biMaxBiome: - biNumBiomes, // True number of biomes, since they are zero-based - biMaxBiome = biNumBiomes - 1, // The maximum biome value - - // Add this number to the biomes to get the variant - biVariant = 128, - - // Release 1.7 biome variants: - biSunflowerPlains = 129, - biDesertM = 130, - biExtremeHillsM = 131, - biFlowerForest = 132, - biTaigaM = 133, - biSwamplandM = 134, - biIcePlainsSpikes = 140, - biJungleM = 149, - biJungleEdgeM = 151, - biBirchForestM = 155, - biBirchForestHillsM = 156, - biRoofedForestM = 157, - biColdTaigaM = 158, - biMegaSpruceTaiga = 160, - biMegaSpruceTaigaHills = 161, - biExtremeHillsPlusM = 162, - biSavannaM = 163, - biSavannaPlateauM = 164, - biMesaBryce = 165, - biMesaPlateauFM = 166, - biMesaPlateauM = 167, -} ; - -// tolua_end - - - - /// Constants used throughout the code, useful typedefs and utility functions class cChunkDef { @@ -610,8 +520,10 @@ public: // Illegal in C++03: typedef std::list< cCoordWithData<X> > cCoordWithDataList<X>; typedef cCoordWithData<int> cCoordWithInt; +typedef cCoordWithData<BLOCKTYPE> cCoordWithBlock; typedef std::list<cCoordWithInt> cCoordWithIntList; typedef std::vector<cCoordWithInt> cCoordWithIntVector; +typedef std::vector<cCoordWithBlock> cCoordWithBlockVector; diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 8125acb47..c8513d516 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -629,6 +629,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 +1037,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 +1069,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); } @@ -1978,6 +1989,15 @@ void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player) +void cClientHandle::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + m_Protocol->SendPluginMessage(a_Channel, a_Message); +} + + + + + void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { m_Protocol->SendRemoveEntityEffect(a_Entity, a_EffectID); diff --git a/src/ClientHandle.h b/src/ClientHandle.h index bc17df780..da2704b72 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -120,6 +120,7 @@ public: void SendPlayerMoveLook (void); void SendPlayerPosition (void); void SendPlayerSpawn (const cPlayer & a_Player); + void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID); void SendRespawn (void); void SendExperience (void); @@ -170,7 +171,13 @@ public: void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem); void HandleDisconnect (const AString & a_Reason); void HandleEntityAction (int a_EntityID, char a_ActionID); + + /** Called when the protocol handshake has been received (for protocol versions that support it; + otherwise the first instant when a username is received). + Returns true if the player is to be let in, false if they were disconnected + */ bool HandleHandshake (const AString & a_Username); + void HandleKeepAlive (int a_KeepAliveID); void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status); void HandlePing (void); diff --git a/src/Defines.h b/src/Defines.h index 534802d55..7a86f499e 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -41,8 +41,8 @@ extern bool g_BlockRequiresSpecialTool[256]; /// Is this block solid (player cannot walk through)? extern bool g_BlockIsSolid[256]; -/// Can torches be placed on this block? -extern bool g_BlockIsTorchPlaceable[256]; +/// Does this block fully occupy it's voxel - is it a 'full' block? +extern bool g_BlockFullyOccupiesVoxel[256]; /// Experience Orb setup enum @@ -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, } ; @@ -563,34 +564,6 @@ namespace ItemCategory } } - - - - -/// Returns true if the biome has no downfall - deserts and savannas -inline bool IsBiomeNoDownfall(EMCSBiome a_Biome) -{ - switch (a_Biome) - { - case biDesert: - case biDesertHills: - case biDesertM: - case biSavanna: - case biSavannaM: - case biSavannaPlateau: - case biSavannaPlateauM: - case biNether: - case biEnd: - { - return true; - } - default: - { - return false; - } - } -} - // tolua_end diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 8a74c9da4..565c78dfd 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -75,13 +75,16 @@ cEntity::~cEntity() { ASSERT(!m_World->HasEntity(m_UniqueID)); // Before deleting, the entity needs to have been removed from the world + /* + // DEBUG: LOGD("Deleting entity %d at pos {%.2f, %.2f, %.2f} ~ [%d, %d]; ptr %p", m_UniqueID, m_Pos.x, m_Pos.y, m_Pos.z, (int)(m_Pos.x / cChunkDef::Width), (int)(m_Pos.z / cChunkDef::Width), this ); - + */ + if (m_AttachedTo != NULL) { Detach(); @@ -138,9 +141,13 @@ bool cEntity::Initialize(cWorld * a_World) return false; } + /* + // DEBUG: LOGD("Initializing entity #%d (%s) at {%.02f, %.02f, %.02f}", m_UniqueID, GetClass(), m_Pos.x, m_Pos.y, m_Pos.z ); + */ + m_IsInitialized = true; m_World = a_World; m_World->AddEntity(this); @@ -256,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); } @@ -321,7 +328,10 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = 0; } - AddSpeed(a_TDI.Knockback * 2); + if (IsMob() || IsPlayer()) // Knockback for only players and mobs + { + AddSpeed(a_TDI.Knockback * 2); + } m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT); @@ -614,9 +624,12 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) m_bOnGround = true; + /* + // DEBUG: LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}", m_UniqueID, GetClass(), BlockX, BlockY, BlockZ ); + */ } if (!m_bOnGround) @@ -626,11 +639,6 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) { fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water. } - else if (IsBlockRail(BlockBelow) && IsMinecart()) // Rails aren't solid, except for Minecarts - { - fallspeed = 0; - m_bOnGround = true; - } else if (BlockIn == E_BLOCK_COBWEB) { NextSpeed.y *= 0.05; // Reduce overall falling speed @@ -645,41 +653,18 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } else { - if (IsMinecart()) + // Friction + if (NextSpeed.SqrLength() > 0.0004f) { - if (!IsBlockRail(BlockBelow)) + NextSpeed.x *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.x) < 0.05) { - // Friction if minecart is off track, otherwise, Minecart.cpp handles this - if (NextSpeed.SqrLength() > 0.0004f) - { - NextSpeed.x *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.x) < 0.05) - { - NextSpeed.x = 0; - } - NextSpeed.z *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.z) < 0.05) - { - NextSpeed.z = 0; - } - } + NextSpeed.x = 0; } - } - else - { - // Friction for non-minecarts - if (NextSpeed.SqrLength() > 0.0004f) + NextSpeed.z *= 0.7f / (1 + a_Dt); + if (fabs(NextSpeed.z) < 0.05) { - NextSpeed.x *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.x) < 0.05) - { - NextSpeed.x = 0; - } - NextSpeed.z *= 0.7f / (1 + a_Dt); - if (fabs(NextSpeed.z) < 0.05) - { - NextSpeed.z = 0; - } + NextSpeed.z = 0; } } } @@ -1104,9 +1089,11 @@ void cEntity::AttachTo(cEntity * a_AttachTo) // Already attached to that entity, nothing to do here return; } - - // Detach from any previous entity: - Detach(); + if (m_AttachedTo != NULL) + { + // Detach from any previous entity: + Detach(); + } // Attach to the new entity: m_AttachedTo = a_AttachTo; diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 2ba1b303d..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); @@ -327,7 +325,7 @@ public: void AttachTo(cEntity * a_AttachTo); /// Detaches from the currently attached entity, if any - void Detach(void); + virtual void Detach(void); /// Makes sure head yaw is not over the specified range. void WrapHeadYaw(); diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index f75e23d8b..d0d384481 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -2,6 +2,7 @@ // Minecart.cpp // Implements the cMinecart class representing a minecart in the world +// Handles physics when a minecart is on any type of rail (overrides simulator in Entity.cpp) // Indiana Jones! #include "Globals.h" @@ -10,6 +11,10 @@ #include "../ClientHandle.h" #include "../Chunk.h" #include "Player.h" +#include "../BoundingBox.h" + +#define MAX_SPEED 8 +#define MAX_SPEED_NEGATIVE -MAX_SPEED @@ -18,11 +23,15 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) : super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7), m_Payload(a_Payload), - m_LastDamage(0) + m_LastDamage(0), + m_DetectorRailPosition(0, 0, 0), + m_bIsOnDetectorRail(false) { SetMass(20.f); SetMaxHealth(6); SetHealth(6); + SetWidth(1.2); + SetHeight(0.9); } @@ -45,6 +54,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) } } a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart + a_ClientHandle.SendEntityMetadata(*this); } @@ -53,6 +63,11 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle) void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) { + if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead + { + return; + } + int PosY = (int)floor(GetPosY()); if ((PosY <= 0) || (PosY >= cChunkDef::Height)) { @@ -70,286 +85,513 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) // Inside an unloaded chunk, bail out all processing return; } - BLOCKTYPE BelowType = Chunk->GetBlock(RelPosX, PosY - 1, RelPosZ); - BLOCKTYPE InsideType = Chunk->GetBlock(RelPosX, PosY, RelPosZ); - if (IsBlockRail(BelowType)) + BLOCKTYPE InsideType; + NIBBLETYPE InsideMeta; + Chunk->GetBlockTypeMeta(RelPosX, PosY, RelPosZ, InsideType, InsideMeta); + + if (!IsBlockRail(InsideType)) { - HandleRailPhysics(a_Dt, *Chunk); + Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta); // When an descending minecart hits a flat rail, it goes through the ground; check for this + if (IsBlockRail(InsideType)) AddPosY(1); // Push cart upwards } - else + + if (IsBlockRail(InsideType)) { - if (IsBlockRail(InsideType)) + bool WasDetectorRail = false; + SnapToRail(InsideMeta); + + switch (InsideType) { - SetPosY(PosY + 1); - HandleRailPhysics(a_Dt, *Chunk); + case E_BLOCK_RAIL: HandleRailPhysics(InsideMeta, a_Dt); break; + case E_BLOCK_ACTIVATOR_RAIL: break; + case E_BLOCK_POWERED_RAIL: HandlePoweredRailPhysics(InsideMeta); break; + case E_BLOCK_DETECTOR_RAIL: + { + HandleDetectorRailPhysics(InsideMeta, a_Dt); + WasDetectorRail = true; + break; + } + default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break; } - else + + AddPosition(GetSpeed() * (a_Dt / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp + + if (m_bIsOnDetectorRail && !WasDetectorRail) { - super::HandlePhysics(a_Dt, *Chunk); - BroadcastMovementUpdate(); + m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07); + m_bIsOnDetectorRail = false; } } + else + { + // Not on rail, default physics + SetPosY(floor(GetPosY()) + 0.35); // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail + super::HandlePhysics(a_Dt, *Chunk); + } + + // Broadcast positioning changes to client + BroadcastMovementUpdate(); } -static const double MAX_SPEED = 8; -static const double MAX_SPEED_NEGATIVE = (0 - MAX_SPEED); - -void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk) +void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) { - - super::HandlePhysics(a_Dt, a_Chunk); // Main physics handling - /* NOTE: Please bear in mind that taking away from negatives make them even more negative, adding to negatives make them positive, etc. */ - // Get block meta below the cart - int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; - int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; - NIBBLETYPE BelowMeta = a_Chunk.GetMeta(RelPosX, (int)floor(GetPosY() - 1), RelPosZ); - double SpeedX = GetSpeedX(), SpeedY = GetSpeedY(), SpeedZ = GetSpeedZ(); // Get current speed - - switch (BelowMeta) + switch (a_RailMeta) { case E_META_RAIL_ZM_ZP: // NORTHSOUTH { - SetRotation(270); - SpeedY = 0; // Don't move vertically as on ground - SpeedX = 0; // Correct diagonal movement from curved rails + SetYaw(270); + SetPosY(floor(GetPosY()) + 0.55); + SetSpeedY(0); // Don't move vertically as on ground + SetSpeedX(0); // Correct diagonal movement from curved rails + + if (TestBlockCollision(a_RailMeta)) return; - if (SpeedZ != 0) // Don't do anything if cart is stationary + if (GetSpeedZ() != 0) // Don't do anything if cart is stationary { - if (SpeedZ > 0) + if (GetSpeedZ() > 0) { // Going SOUTH, slow down - SpeedZ = SpeedZ - 0.1; + AddSpeedZ(-0.1); } else { // Going NORTH, slow down - SpeedZ = SpeedZ + 0.1; + AddSpeedZ(0.1); } } break; } - case E_META_RAIL_XM_XP: // EASTWEST { - SetRotation(180); - SpeedY = 0; - SpeedZ = 0; + SetYaw(180); + SetPosY(floor(GetPosY()) + 0.55); + SetSpeedY(0); + SetSpeedZ(0); + + if (TestBlockCollision(a_RailMeta)) return; - if (SpeedX != 0) + if (GetSpeedX() != 0) { - if (SpeedX > 0) + if (GetSpeedX() > 0) { - SpeedX = SpeedX - 0.1; + AddSpeedX(-0.1); } else { - SpeedX = SpeedX + 0.1; + AddSpeedX(0.1); } } break; } - case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH { - SetRotation(270); - SetPosY(floor(GetPosY()) + 0.2); // It seems it doesn't work without levitation :/ - SpeedX = 0; + SetYaw(270); + SetSpeedX(0); - if (SpeedZ >= 0) + if (GetSpeedZ() >= 0) { // SpeedZ POSITIVE, going SOUTH - if (SpeedZ <= MAX_SPEED) // Speed limit + if (GetSpeedZ() <= MAX_SPEED) // Speed limit { - SpeedZ = SpeedZ + 0.5; // Speed up - SpeedY = (0 - SpeedZ); // Downward movement is negative (0 minus positive numbers is negative) - } - else - { - SpeedZ = MAX_SPEED; // Enforce speed limit - SpeedY = (0 - SpeedZ); + AddSpeedZ(0.5); // Speed up + SetSpeedY(-GetSpeedZ()); // Downward movement is negative (0 minus positive numbers is negative) } } else { // SpeedZ NEGATIVE, going NORTH - SpeedZ = SpeedZ + 0.4; // Slow down - SpeedY = (0 - SpeedZ); // Upward movement is positive (0 minus negative number is positive number) + AddSpeedZ(1); // Slow down + SetSpeedY(-GetSpeedZ()); // Upward movement is positive (0 minus negative number is positive number) } break; } - case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH { - SetRotation(270); - SetPosY(floor(GetPosY()) + 0.2); - SpeedX = 0; + SetYaw(270); + SetSpeedX(0); - if (SpeedZ > 0) + if (GetSpeedZ() > 0) { // SpeedZ POSITIVE, going SOUTH - SpeedZ = SpeedZ - 0.4; // Slow down - SpeedY = SpeedZ; // Upward movement positive + AddSpeedZ(-1); // Slow down + SetSpeedY(GetSpeedZ()); // Upward movement positive } else { - if (SpeedZ >= MAX_SPEED_NEGATIVE) // Speed limit + if (GetSpeedZ() >= MAX_SPEED_NEGATIVE) // Speed limit { // SpeedZ NEGATIVE, going NORTH - SpeedZ = SpeedZ - 0.5; // Speed up - SpeedY = SpeedZ; // Downward movement negative - } - else - { - SpeedZ = MAX_SPEED_NEGATIVE; // Enforce speed limit - SpeedY = SpeedZ; + AddSpeedZ(-0.5); // Speed up + SetSpeedY(GetSpeedZ()); // Downward movement negative } } break; } - case E_META_RAIL_ASCEND_XM: // ASCEND EAST { - SetRotation(180); - SetPosY(floor(GetPosY()) + 0.2); - SpeedZ = 0; + SetYaw(180); + SetSpeedZ(0); - if (SpeedX >= 0) + if (GetSpeedX() >= 0) { - if (SpeedX <= MAX_SPEED) - { - SpeedX = SpeedX + 0.5; - SpeedY = (0 - SpeedX); - } - else + if (GetSpeedX() <= MAX_SPEED) { - SpeedX = MAX_SPEED; - SpeedY = (0 - SpeedX); + AddSpeedX(0.5); + SetSpeedY(-GetSpeedX()); } } else { - SpeedX = SpeedX + 0.4; - SpeedY = (0 - SpeedX); + AddSpeedX(1); + SetSpeedY(-GetSpeedX()); } break; } - case E_META_RAIL_ASCEND_XP: // ASCEND WEST { - SetRotation(180); - SetPosY(floor(GetPosY()) + 0.2); - SpeedZ = 0; + SetYaw(180); + SetSpeedZ(0); - if (SpeedX > 0) + if (GetSpeedX() > 0) { - SpeedX = SpeedX - 0.4; - SpeedY = SpeedX; + AddSpeedX(-1); + SetSpeedY(GetSpeedX()); } else { - if (SpeedX >= MAX_SPEED_NEGATIVE) + if (GetSpeedX() >= MAX_SPEED_NEGATIVE) { - SpeedX = SpeedX - 0.5; - SpeedY = SpeedX; - } - else - { - SpeedX = MAX_SPEED_NEGATIVE; - SpeedY = SpeedX; + AddSpeedX(-0.5); + SetSpeedY(GetSpeedX()); } } break; } - case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST { - SetRotation(315); // Set correct rotation server side - SetPosY(floor(GetPosY()) + 0.2); // Levitate dat cart + SetYaw(315); // Set correct rotation server side + SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart + + if (TestBlockCollision(a_RailMeta)) return; - if (SpeedZ > 0) // Cart moving south + if (GetSpeedZ() > 0) // Cart moving south { - SpeedX = (0 - SpeedZ); // Diagonally move southwest (which will make cart hit a southwest rail) + int OldX = (int)floor(GetPosX()); + AddSpeedX(-GetSpeedZ() + 0.5); // See below + AddPosX(-GetSpeedZ() * (a_Dt / 1000)); // Diagonally move southwest (which will make cart hit a southwest rail) + // If we are already at southwest rail, set Z speed to zero as we can be moving so fast, MCS doesn't tick fast enough to active the handle for the rail... + // ...and so we derail unexpectedly. + if (GetPosX() <= OldX - 1) SetSpeedZ(0); } - else if (SpeedX > 0) // Cart moving east + else if (GetSpeedX() > 0) // Cart moving east { - SpeedZ = (0 - SpeedX); // Diagonally move northeast + int OldZ = (int)floor(GetPosZ()); + AddSpeedZ(-GetSpeedX() + 0.5); + AddPosZ(-GetSpeedX() * (a_Dt / 1000)); // Diagonally move northeast + if (GetPosZ() <= OldZ - 1) SetSpeedX(0); } break; } - case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST { - SetRotation(225); - SetPosY(floor(GetPosY()) + 0.2); + SetYaw(225); + SetPosY(floor(GetPosY()) + 0.55); + + if (TestBlockCollision(a_RailMeta)) return; - if (SpeedZ > 0) + if (GetSpeedZ() > 0) { - SpeedX = SpeedZ; + int OldX = (int)floor(GetPosX()); + AddSpeedX(GetSpeedZ() - 0.5); + AddPosX(GetSpeedZ() * (a_Dt / 1000)); + if (GetPosX() >= OldX + 1) SetSpeedZ(0); } - else if (SpeedX < 0) + else if (GetSpeedX() < 0) { - SpeedZ = SpeedX; + int OldZ = (int)floor(GetPosZ()); + AddSpeedZ(GetSpeedX() + 0.5); + AddPosZ(GetSpeedX() * (a_Dt / 1000)); + if (GetPosZ() <= OldZ - 1) SetSpeedX(0); } break; } - case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST { - SetRotation(135); - SetPosY(floor(GetPosY()) + 0.2); + SetYaw(135); + SetPosY(floor(GetPosY()) + 0.55); - if (SpeedZ < 0) + if (TestBlockCollision(a_RailMeta)) return; + + if (GetSpeedZ() < 0) { - SpeedX = SpeedZ; + int OldX = (int)floor(GetPosX()); + AddSpeedX(GetSpeedZ() + 0.5); + AddPosX(GetSpeedZ() * (a_Dt / 1000)); + if (GetPosX() <= OldX - 1) SetSpeedZ(0); } - else if (SpeedX > 0) + else if (GetSpeedX() > 0) { - SpeedZ = SpeedX; + int OldZ = (int)floor(GetPosZ()); + AddSpeedZ(GetSpeedX() - 0.5); + AddPosZ(GetSpeedX() * (a_Dt / 1000)); + if (GetPosZ() >= OldZ + 1) SetSpeedX(0); } break; } - case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST { - SetRotation(45); - SetPosY(floor(GetPosY()) + 0.2); + SetYaw(45); + SetPosY(floor(GetPosY()) + 0.55); + + if (TestBlockCollision(a_RailMeta)) return; - if (SpeedZ < 0) + if (GetSpeedZ() < 0) { - SpeedX = (0 - SpeedZ); + int OldX = (int)floor(GetPosX()); + AddSpeedX(-GetSpeedZ() - 0.5); + AddPosX(-GetSpeedZ() * (a_Dt / 1000)); + if (GetPosX() >= OldX + 1) SetSpeedZ(0); } - else if (SpeedX < 0) + else if (GetSpeedX() < 0) { - SpeedZ = (0 - SpeedX); + int OldZ = (int)floor(GetPosZ()); + AddSpeedZ(-GetSpeedX() - 0.5); + AddPosZ(-GetSpeedX() * (a_Dt / 1000)); + if (GetPosZ() >= OldZ + 1) SetSpeedX(0); } break; } - default: { ASSERT(!"Unhandled rail meta!"); // Dun dun DUN! break; } } +} - // Set speed to speed variables - SetSpeedX(SpeedX); - SetSpeedY(SpeedY); - SetSpeedZ(SpeedZ); - // Broadcast position to client - BroadcastMovementUpdate(); + +void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta) +{ + // Initialise to 'slow down' values + int AccelDecelSpeed = -1; + int AccelDecelNegSpeed = 1; + + if ((a_RailMeta & 0x8) == 0x8) + { + // Rail powered - set variables to 'speed up' values + AccelDecelSpeed = 1; + AccelDecelNegSpeed = -1; + } + + switch (a_RailMeta & 0x07) + { + case E_META_RAIL_ZM_ZP: // NORTHSOUTH + { + SetYaw(270); + SetPosY(floor(GetPosY()) + 0.55); + SetSpeedY(0); + SetSpeedX(0); + + if (TestBlockCollision(a_RailMeta)) return; + + if (GetSpeedZ() != 0) + { + if (GetSpeedZ() > 0) + { + AddSpeedZ(AccelDecelNegSpeed); + } + else + { + AddSpeedZ(AccelDecelSpeed); + } + } + break; + } + case E_META_RAIL_XM_XP: // EASTWEST + { + SetYaw(180); + SetPosY(floor(GetPosY()) + 0.55); + SetSpeedY(0); + SetSpeedZ(0); + + if (TestBlockCollision(a_RailMeta)) return; + + if (GetSpeedX() != 0) + { + if (GetSpeedX() > 0) + { + AddSpeedX(AccelDecelSpeed); + } + else + { + AddSpeedX(AccelDecelNegSpeed); + } + } + break; + } + } +} + + + + + +void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt) +{ + m_bIsOnDetectorRail = true; + m_DetectorRailPosition = Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); + + m_World->SetBlockMeta(m_DetectorRailPosition, a_RailMeta | 0x08); + + HandleRailPhysics(a_RailMeta & 0x07, a_Dt); +} + + + + + +void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta) +{ + switch (a_RailMeta) + { + case E_META_RAIL_ASCEND_XM: + case E_META_RAIL_ASCEND_XP: + case E_META_RAIL_XM_XP: + { + SetSpeedZ(0); + SetPosZ(floor(GetPosZ()) + 0.5); + break; + } + case E_META_RAIL_ASCEND_ZM: + case E_META_RAIL_ASCEND_ZP: + case E_META_RAIL_ZM_ZP: + { + SetSpeedX(0); + SetPosX(floor(GetPosX()) + 0.5); + break; + } + default: break; + } +} + + + + + +bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) +{ + switch (a_RailMeta) + { + case E_META_RAIL_ZM_ZP: + { + if (GetSpeedZ() > 0) + { + BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())); + if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) + { + // We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P + cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1); + cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); + + if (bbBlock.DoesIntersect(bbMinecart)) + { + SetSpeed(0, 0, 0); + SetPosZ(floor(GetPosZ()) + 0.4); + return true; + } + } + } + else + { + BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1); + if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) + { + cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1); + cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight()); + + if (bbBlock.DoesIntersect(bbMinecart)) + { + SetSpeed(0, 0, 0); + SetPosZ(floor(GetPosZ()) + 0.65); + return true; + } + } + } + break; + } + case E_META_RAIL_XM_XP: + { + if (GetSpeedX() > 0) + { + BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); + if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) + { + cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1); + cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); + + if (bbBlock.DoesIntersect(bbMinecart)) + { + SetSpeed(0, 0, 0); + SetPosX(floor(GetPosX()) + 0.4); + return true; + } + } + } + else + { + BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); + if (!IsBlockRail(Block) && g_BlockIsSolid[Block]) + { + cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1); + cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); + + if (bbBlock.DoesIntersect(bbMinecart)) + { + SetSpeed(0, 0, 0); + SetPosX(floor(GetPosX()) + 0.65); + return true; + } + } + } + break; + } + case E_META_RAIL_CURVED_ZM_XM: + case E_META_RAIL_CURVED_ZM_XP: + case E_META_RAIL_CURVED_ZP_XM: + case E_META_RAIL_CURVED_ZP_XP: + { + BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); + BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); + BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); + BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); + if ( + (!IsBlockRail(BlockXM) && g_BlockIsSolid[BlockXM]) || + (!IsBlockRail(BlockXP) && g_BlockIsSolid[BlockXP]) || + (!IsBlockRail(BlockZM) && g_BlockIsSolid[BlockZM]) || + (!IsBlockRail(BlockZP) && g_BlockIsSolid[BlockZP]) + ) + { + SetSpeed(0, 0, 0); + SetPosition((int)floor(GetPosX()) + 0.5, GetPosY(), (int)floor(GetPosZ()) + 0.5); + return true; + } + break; + } + default: break; + } + return false; } @@ -358,6 +600,14 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk) void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) { + if (TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative()) + { + Destroy(); + TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative + super::DoTakeDamage(TDI); + return; // No drops for creative + } + m_LastDamage = TDI.FinalDamage; super::DoTakeDamage(TDI); @@ -365,7 +615,7 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) if (GetHealth() <= 0) { - Destroy(true); + Destroy(); cItems Drops; switch (m_Payload) @@ -410,11 +660,25 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) +void cMinecart::Destroyed() +{ + if (m_bIsOnDetectorRail) + { + m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07); + } +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// 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) { } @@ -422,7 +686,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) { @@ -489,7 +753,8 @@ void cMinecartWithChest::OnRightClicked(cPlayer & a_Player) cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) : super(mpFurnace, a_X, a_Y, a_Z), - m_IsFueled(false) + m_IsFueled(false), + m_FueledTimeLeft(-1) { } @@ -505,8 +770,12 @@ void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player) { a_Player.GetInventory().RemoveOneEquippedItem(); } - + if (!m_IsFueled) // We don't want to change the direction by right clicking it. + { + AddSpeed(a_Player.GetLookVector().x, 0, a_Player.GetLookVector().z); + } m_IsFueled = true; + m_FueledTimeLeft = m_FueledTimeLeft + 600; // The minecart will be active 600 more ticks. m_World->BroadcastEntityMetadata(*this); } } @@ -515,6 +784,32 @@ void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player) +void cMinecartWithFurnace::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + + if (m_IsFueled) + { + m_FueledTimeLeft--; + if (m_FueledTimeLeft < 0) + { + m_IsFueled = false; + m_World->BroadcastEntityMetadata(*this); + return; + } + + if (GetSpeed().Length() > 6) + { + return; + } + AddSpeed(GetSpeed() / 4); + } +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cMinecartWithTNT: diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index b1b48be4e..874d0204e 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -51,17 +51,38 @@ public: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual void Destroyed() override; int LastDamage(void) const { return m_LastDamage; } - void HandleRailPhysics(float a_Dt, cChunk & a_Chunk); ePayload GetPayload(void) const { return m_Payload; } protected: ePayload m_Payload; + int m_LastDamage; + Vector3i m_DetectorRailPosition; + bool m_bIsOnDetectorRail; cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z); - int m_LastDamage; + /** Handles physics on normal rails + For each tick, slow down on flat rails, speed up or slow down on ascending/descending rails (depending on direction), and turn on curved rails + */ + void HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt); + + /** Handles powered rail physics + Each tick, speed up or slow down cart, depending on metadata of rail (powered or not) + */ + void HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta); + + /** Handles detector rail activation + Activates detector rails when a minecart is on them. Calls HandleRailPhysics() for physics simulations + */ + void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt); + + /** Snaps a minecart to a rail's axis, resetting its speed */ + void SnapToRail(NIBBLETYPE a_RailMeta); + /** Tests is a solid block is in front of a cart, and stops the cart (and returns true) if so; returns false if no obstruction*/ + bool TestBlockCollision(NIBBLETYPE a_RailMeta); } ; @@ -69,18 +90,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; } ; @@ -130,10 +157,18 @@ public: // cEntity overrides: virtual void OnRightClicked(cPlayer & a_Player) override; - bool IsFueled (void) const { return m_IsFueled; } + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + + // Set functions. + void SetIsFueled(bool a_IsFueled, int a_FueledTimeLeft = -1) {m_IsFueled = a_IsFueled; m_FueledTimeLeft = a_FueledTimeLeft;} + + // Get functions. + int GetFueledTimeLeft(void) const {return m_FueledTimeLeft; } + bool IsFueled (void) const {return m_IsFueled;} private: + int m_FueledTimeLeft; bool m_IsFueled; } ; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index bc92790aa..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())); @@ -1884,3 +1889,33 @@ void cPlayer::ApplyFoodExhaustionFromMovement() + +void cPlayer::Detach() +{ + super::Detach(); + int PosX = (int)floor(GetPosX()); + int PosY = (int)floor(GetPosY()); + int PosZ = (int)floor(GetPosZ()); + + // Search for a position within an area to teleport player after detachment + // Position must be solid land, and occupied by a nonsolid block + // If nothing found, player remains where they are + for (int x = PosX - 2; x <= (PosX + 2); ++x) + { + for (int y = PosY; y <= (PosY + 3); ++y) + { + for (int z = PosZ - 2; z <= (PosZ + 2); ++z) + { + if (!g_BlockIsSolid[m_World->GetBlock(x, y, z)] && g_BlockIsSolid[m_World->GetBlock(x, y - 1, z)]) + { + TeleportToCoords(x, y, z); + return; + } + } + } + } +} + + + + diff --git a/src/Entities/Player.h b/src/Entities/Player.h index f9ce950ba..bf3ca08e8 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -350,6 +350,8 @@ public: virtual bool IsCrouched (void) const { return m_IsCrouched; } virtual bool IsSprinting(void) const { return m_IsSprinting; } virtual bool IsRclking (void) const { return IsEating(); } + + virtual void Detach(void); protected: typedef std::map< std::string, bool > PermissionMap; 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/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp index 126a896af..baa5b76b8 100644 --- a/src/Generating/ChunkGenerator.cpp +++ b/src/Generating/ChunkGenerator.cpp @@ -2,13 +2,11 @@ #include "Globals.h" #include "ChunkGenerator.h" -#include "../World.h" #include "inifile/iniFile.h" -#include "../Root.h" -#include "../Bindings/PluginManager.h" #include "ChunkDesc.h" #include "ComposableGenerator.h" #include "Noise3DGenerator.h" +#include "../MersenneTwister.h" @@ -29,8 +27,9 @@ const unsigned int QUEUE_SKIP_LIMIT = 500; cChunkGenerator::cChunkGenerator(void) : super("cChunkGenerator"), - m_World(NULL), - m_Generator(NULL) + m_Generator(NULL), + m_PluginInterface(NULL), + m_ChunkSink(NULL) { } @@ -47,10 +46,12 @@ cChunkGenerator::~cChunkGenerator() -bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) +bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile) { + m_PluginInterface = &a_PluginInterface; + m_ChunkSink = &a_ChunkSink; + MTRand rnd; - m_World = a_World; m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt()); AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable"); @@ -73,7 +74,7 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) return false; } - m_Generator->Initialize(a_World, a_IniFile); + m_Generator->Initialize(a_IniFile); return super::Start(); } @@ -237,14 +238,14 @@ void cChunkGenerator::Execute(void) } // Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set - if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) + if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ)) { LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ); // Already generated, ignore request continue; } - if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) + if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ)) { LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ); continue; @@ -253,9 +254,6 @@ void cChunkGenerator::Execute(void) LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - // Save the chunk right after generating, so that we don't have to generate it again on next run - m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ); - NumChunksGenerated++; } // while (!bStop) } @@ -265,27 +263,20 @@ void cChunkGenerator::Execute(void) void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ) { + ASSERT(m_PluginInterface != NULL); + ASSERT(m_ChunkSink != NULL); + cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ); - cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); + m_PluginInterface->CallHookChunkGenerating(ChunkDesc); m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc); - cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc); + m_PluginInterface->CallHookChunkGenerated(ChunkDesc); #ifdef _DEBUG // Verify that the generator has produced valid data: ChunkDesc.VerifyHeightmap(); #endif - cChunkDef::BlockNibbles BlockMetas; - ChunkDesc.CompressBlockMetas(BlockMetas); - - m_World->SetChunkData( - a_ChunkX, a_ChunkZ, - ChunkDesc.GetBlockTypes(), BlockMetas, - NULL, NULL, // We don't have lighting, chunk will be lighted when needed - &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(), - ChunkDesc.GetEntities(), ChunkDesc.GetBlockEntities(), - true - ); + m_ChunkSink->OnChunkGenerated(ChunkDesc); } @@ -304,9 +295,8 @@ cChunkGenerator::cGenerator::cGenerator(cChunkGenerator & a_ChunkGenerator) : -void cChunkGenerator::cGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +void cChunkGenerator::cGenerator::Initialize(cIniFile & a_IniFile) { - m_World = a_World; UNUSED(a_IniFile); } @@ -319,7 +309,7 @@ EMCSBiome cChunkGenerator::cGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ) cChunkDef::BiomeMap Biomes; int Y = 0; int ChunkX, ChunkZ; - cWorld::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, Y, ChunkZ); + cChunkDef::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, ChunkZ); GenerateBiomes(ChunkX, ChunkZ, Biomes); return cChunkDef::GetBiome(Biomes, a_BlockX, a_BlockZ); } diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h index 2d3bb8082..9b2d9eb3c 100644 --- a/src/Generating/ChunkGenerator.h +++ b/src/Generating/ChunkGenerator.h @@ -26,7 +26,6 @@ If the generator queue is overloaded, the generator skips chunks with no clients // fwd: -class cWorld; class cIniFile; class cChunkDesc; @@ -40,7 +39,7 @@ class cChunkGenerator : typedef cIsThread super; public: - /// The interface that a class has to implement to become a generator + /** The interface that a class has to implement to become a generator */ class cGenerator { public: @@ -48,7 +47,7 @@ public: virtual ~cGenerator() {} ; // Force a virtual destructor /// Called to initialize the generator on server startup. - virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile); + virtual void Initialize(cIniFile & a_IniFile); /// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading. virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0; @@ -61,14 +60,59 @@ public: protected: cChunkGenerator & m_ChunkGenerator; - cWorld * m_World; + } ; + + + /** The interface through which the plugins are called for their OnChunkGenerating / OnChunkGenerated hooks. */ + class cPluginInterface + { + public: + // Force a virtual destructor + virtual ~cPluginInterface() {} + + /** Called when the chunk is about to be generated. + The generator may be partly or fully overriden by the implementation + */ + virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) = 0; + + /** Called after the chunk is generated, before it is handed to the chunk sink. + a_ChunkDesc contains the generated chunk data. Implementation may modify this data. + */ + virtual void CallHookChunkGenerated(cChunkDesc & a_ChunkDesc) = 0; + } ; + + + /** The interface through which the generated chunks are handed to the cWorld or whoever created us. */ + class cChunkSink + { + public: + // Force a virtual destructor + virtual ~cChunkSink() {} + + /** Called after the chunk has been generated + The interface may store the chunk, send it over network, whatever. + The chunk is not expected to be modified, but the generator will survive if the implementation + changes the data within. All changes are ignored, though. + */ + virtual void OnChunkGenerated(cChunkDesc & a_ChunkDesc) = 0; + + /** Called just before the chunk generation is started, + to verify that it hasn't been generated in the meantime. + If this callback returns true, the chunk is not generated. + */ + virtual bool IsChunkValid(int a_ChunkX, int a_ChunkZ) = 0; + + /** Called when the generator is overloaded to skip chunks that are no longer needed. + If this callback returns false, the chunk is not generated. + */ + virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) = 0; } ; cChunkGenerator (void); ~cChunkGenerator(); - bool Start(cWorld * a_World, cIniFile & a_IniFile); + bool Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile); void Stop(void); /// Queues the chunk for generation; removes duplicate requests @@ -91,8 +135,6 @@ public: private: - cWorld * m_World; - int m_Seed; cCriticalSection m_CS; @@ -101,6 +143,13 @@ private: cEvent m_evtRemoved; ///< Set when an item is removed from the queue cGenerator * m_Generator; ///< The actual generator engine used to generate chunks + + /** The plugin interface that may modify the generated chunks */ + cPluginInterface * m_PluginInterface; + + /** The destination where the generated chunks are sent */ + cChunkSink * m_ChunkSink; + // cIsThread override: virtual void Execute(void) override; diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 9817b6654..b01f84627 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -28,11 +28,88 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cTerrainCompositionGen: +cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed) +{ + AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); + if (CompoGenName.empty()) + { + LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\"."); + CompoGenName = "Biomal"; + a_IniFile.SetValue("Generator", "CompositionGen", CompoGenName); + } + + cTerrainCompositionGen * res = NULL; + if (NoCaseCompare(CompoGenName, "sameblock") == 0) + { + res = new cCompoGenSameBlock; + } + else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0) + { + res = new cCompoGenDebugBiomes; + } + else if (NoCaseCompare(CompoGenName, "classic") == 0) + { + res = new cCompoGenClassic; + } + else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0) + { + res = new cDistortedHeightmap(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(CompoGenName, "end") == 0) + { + res = new cEndGen(a_Seed); + } + else if (NoCaseCompare(CompoGenName, "nether") == 0) + { + res = new cCompoGenNether(a_Seed); + } + else if (NoCaseCompare(CompoGenName, "Noise3D") == 0) + { + res = new cNoise3DComposable(a_Seed); + } + else if (NoCaseCompare(CompoGenName, "biomal") == 0) + { + res = new cCompoGenBiomal(a_Seed); + + /* + // Performance-testing: + LOGINFO("Measuring performance of cCompoGenBiomal..."); + clock_t BeginTick = clock(); + for (int x = 0; x < 500; x++) + { + cChunkDesc Desc(200 + x * 8, 200 + x * 8); + a_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap()); + a_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap()); + res->ComposeTerrain(Desc); + } + clock_t Duration = clock() - BeginTick; + LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); + //*/ + } + else + { + LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str()); + a_IniFile.DeleteValue("Generator", "CompositionGen"); + a_IniFile.SetValue("Generator", "CompositionGen", "Biomal"); + return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed); + } + ASSERT(res != NULL); + + // Read the settings from the ini file: + res->InitializeCompoGen(a_IniFile); + + return res; +} +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cComposableGenerator: + cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) : super(a_ChunkGenerator), m_BiomeGen(NULL), @@ -80,9 +157,9 @@ cComposableGenerator::~cComposableGenerator() -void cComposableGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +void cComposableGenerator::Initialize(cIniFile & a_IniFile) { - super::Initialize(a_World, a_IniFile); + super::Initialize(a_IniFile); InitBiomeGen(a_IniFile); InitHeightGen(a_IniFile); @@ -173,60 +250,8 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile) void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) { - AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); - if (HeightGenName.empty()) - { - LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\"."); - HeightGenName = "Biomal"; - } - - int Seed = m_ChunkGenerator.GetSeed(); bool CacheOffByDefault = false; - if (NoCaseCompare(HeightGenName, "flat") == 0) - { - m_HeightGen = new cHeiGenFlat; - CacheOffByDefault = true; // We're generating faster than a cache would retrieve data - } - else if (NoCaseCompare(HeightGenName, "classic") == 0) - { - m_HeightGen = new cHeiGenClassic(Seed); - } - else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) - { - m_HeightGen = new cDistortedHeightmap(Seed, *m_BiomeGen); - } - else if (NoCaseCompare(HeightGenName, "End") == 0) - { - m_HeightGen = new cEndGen(Seed); - } - else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) - { - m_HeightGen = new cNoise3DComposable(Seed); - } - else // "biomal" or <not found> - { - if (NoCaseCompare(HeightGenName, "biomal") != 0) - { - LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str()); - } - m_HeightGen = new cHeiGenBiomal(Seed, *m_BiomeGen); - - /* - // Performance-testing: - LOGINFO("Measuring performance of cHeiGenBiomal..."); - clock_t BeginTick = clock(); - for (int x = 0; x < 500; x++) - { - cChunkDef::HeightMap Heights; - m_HeightGen->GenHeightMap(x * 5, x * 5, Heights); - } - clock_t Duration = clock() - BeginTick; - LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); - //*/ - } - - // Read the settings: - m_HeightGen->InitializeHeightGen(a_IniFile); + m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, *m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault); // Add a cache, if requested: int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64); @@ -251,67 +276,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile) void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile) { - int Seed = m_ChunkGenerator.GetSeed(); - AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); - if (CompoGenName.empty()) - { - LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\"."); - CompoGenName = "Biomal"; - } - if (NoCaseCompare(CompoGenName, "sameblock") == 0) - { - m_CompositionGen = new cCompoGenSameBlock; - } - else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0) - { - m_CompositionGen = new cCompoGenDebugBiomes; - } - else if (NoCaseCompare(CompoGenName, "classic") == 0) - { - m_CompositionGen = new cCompoGenClassic; - } - else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0) - { - m_CompositionGen = new cDistortedHeightmap(Seed, *m_BiomeGen); - } - else if (NoCaseCompare(CompoGenName, "end") == 0) - { - m_CompositionGen = new cEndGen(Seed); - } - else if (NoCaseCompare(CompoGenName, "nether") == 0) - { - m_CompositionGen = new cCompoGenNether(Seed); - } - else if (NoCaseCompare(CompoGenName, "Noise3D") == 0) - { - m_CompositionGen = new cNoise3DComposable(m_ChunkGenerator.GetSeed()); - } - else - { - if (NoCaseCompare(CompoGenName, "biomal") != 0) - { - LOGWARN("Unknown CompositionGen \"%s\", using \"biomal\" instead.", CompoGenName.c_str()); - } - m_CompositionGen = new cCompoGenBiomal(Seed); - - /* - // Performance-testing: - LOGINFO("Measuring performance of cCompoGenBiomal..."); - clock_t BeginTick = clock(); - for (int x = 0; x < 500; x++) - { - cChunkDesc Desc(200 + x * 8, 200 + x * 8); - m_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap()); - m_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap()); - m_CompositionGen->ComposeTerrain(Desc); - } - clock_t Duration = clock() - BeginTick; - LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); - //*/ - } - - // Read the settings from the ini file: - m_CompositionGen->InitializeCompoGen(a_IniFile); + m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, *m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed()); int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64); if (CompoGenCacheSize > 1) @@ -402,15 +367,16 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile) void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { int Seed = m_ChunkGenerator.GetSeed(); - AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator"); + eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld")); + 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: if (NoCaseCompare(*itr, "BottomLava") == 0) { - int DefaultBottomLavaLevel = (m_World->GetDimension() == dimNether) ? 30 : 10; + int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10; int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel); m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel)); } @@ -424,7 +390,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "LavaSprings") == 0) { - m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, *m_World)); + m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension)); } else if (NoCaseCompare(*itr, "Lilypads") == 0) { @@ -448,7 +414,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) } else if (NoCaseCompare(*itr, "WaterSprings") == 0) { - m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, *m_World)); + m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension)); } } // for itr - Str[] } diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h index 732f64303..29add0636 100644 --- a/src/Generating/ComposableGenerator.h +++ b/src/Generating/ComposableGenerator.h @@ -50,7 +50,7 @@ public: virtual void InitializeBiomeGen(cIniFile & a_IniFile) {} /// Creates the correct BiomeGen descendant based on the ini file settings and the seed provided. - /// a_CacheOffByDefault gets set to whether the cache should be enabled by default + /// a_CacheOffByDefault gets set to whether the cache should be disabled by default /// Used in BiomeVisualiser, too. /// Implemented in BioGen.cpp! static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault); @@ -77,6 +77,13 @@ public: /// Reads parameters from the ini file, prepares generator for use. virtual void InitializeHeightGen(cIniFile & a_IniFile) {} + + /** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided. + a_BiomeGen is the underlying biome generator, some height generators may depend on it to generate more biomes + a_CacheOffByDefault gets set to whether the cache should be disabled by default + Implemented in HeiGen.cpp! + */ + static cTerrainHeightGen * CreateHeightGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault); } ; @@ -97,6 +104,12 @@ public: /// Reads parameters from the ini file, prepares generator for use. virtual void InitializeCompoGen(cIniFile & a_IniFile) {} + + /** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided. + a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes + a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values + */ + static cTerrainCompositionGen * CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed); } ; @@ -149,7 +162,7 @@ public: cComposableGenerator(cChunkGenerator & a_ChunkGenerator); virtual ~cComposableGenerator(); - virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override; + virtual void Initialize(cIniFile & a_IniFile) override; virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override; diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp index 4ac6ff0f3..02045f76a 100644 --- a/src/Generating/FinishGen.cpp +++ b/src/Generating/FinishGen.cpp @@ -72,7 +72,7 @@ void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc) PosX = (int) floor(16 / Val1); } - // Calculate PosZ + // Calculate PosZ if (Val2 <= 1) { PosZ = (int) floor(Val2 * 16); @@ -640,7 +640,7 @@ void cFinishGenPreSimulator::StationarizeFluid( /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cFinishGenFluidSprings: -cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, const cWorld & a_World) : +cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension) : m_Noise(a_Seed + a_Fluid * 100), // Need to take fluid into account, otherwise water and lava springs generate next to each other m_HeightDistribution(255), m_Fluid(a_Fluid) @@ -649,7 +649,7 @@ cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cI AString SectionName = IsWater ? "WaterSprings" : "LavaSprings"; AString DefaultHeightDistribution; int DefaultChance = 0; - switch (a_World.GetDimension()) + switch (a_Dimension) { case dimNether: { diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h index a444721f8..2e5732929 100644 --- a/src/Generating/FinishGen.h +++ b/src/Generating/FinishGen.h @@ -51,9 +51,9 @@ class cFinishGenNetherClumpFoliage : public cFinishGen { public: - cFinishGenNetherClumpFoliage(int a_Seed) : + cFinishGenNetherClumpFoliage(int a_Seed) : m_Noise(a_Seed), - m_Seed(a_Seed) + m_Seed(a_Seed) { } @@ -187,7 +187,7 @@ class cFinishGenFluidSprings : public cFinishGen { public: - cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, const cWorld & a_World); + cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension); protected: diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp index 2bf641089..10710b4a1 100644 --- a/src/Generating/HeiGen.cpp +++ b/src/Generating/HeiGen.cpp @@ -7,6 +7,9 @@ #include "HeiGen.h" #include "../LinearUpscale.h" #include "inifile/iniFile.h" +#include "DistortedHeightmap.h" +#include "EndGen.h" +#include "Noise3DGenerator.h" @@ -14,6 +17,77 @@ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cTerrainHeightGen: + +cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault) +{ + AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", ""); + if (HeightGenName.empty()) + { + LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\"."); + HeightGenName = "Biomal"; + } + + a_CacheOffByDefault = false; + cTerrainHeightGen * res = NULL; + if (NoCaseCompare(HeightGenName, "flat") == 0) + { + res = new cHeiGenFlat; + a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data + } + else if (NoCaseCompare(HeightGenName, "classic") == 0) + { + res = new cHeiGenClassic(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0) + { + res = new cDistortedHeightmap(a_Seed, a_BiomeGen); + } + else if (NoCaseCompare(HeightGenName, "End") == 0) + { + res = new cEndGen(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "Noise3D") == 0) + { + res = new cNoise3DComposable(a_Seed); + } + else if (NoCaseCompare(HeightGenName, "biomal") == 0) + { + res = new cHeiGenBiomal(a_Seed, a_BiomeGen); + + /* + // Performance-testing: + LOGINFO("Measuring performance of cHeiGenBiomal..."); + clock_t BeginTick = clock(); + for (int x = 0; x < 500; x++) + { + cChunkDef::HeightMap Heights; + res->GenHeightMap(x * 5, x * 5, Heights); + } + clock_t Duration = clock() - BeginTick; + LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC); + //*/ + } + else + { + // No match found, force-set the default and retry + LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str()); + a_IniFile.DeleteValue("Generator", "HeightGen"); + a_IniFile.SetValue("Generator", "HeightGen", "Biomal"); + return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault); + } + + // Read the settings: + res->InitializeHeightGen(a_IniFile); + + return res; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cHeiGenFlat: void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp index 2511bb656..afa40c647 100644 --- a/src/Generating/Noise3DGenerator.cpp +++ b/src/Generating/Noise3DGenerator.cpp @@ -150,10 +150,8 @@ cNoise3DGenerator::~cNoise3DGenerator() -void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile) +void cNoise3DGenerator::Initialize(cIniFile & a_IniFile) { - m_World = a_World; - // Params: m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62); m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0); diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h index 0d211cddc..42f61a854 100644 --- a/src/Generating/Noise3DGenerator.h +++ b/src/Generating/Noise3DGenerator.h @@ -24,7 +24,7 @@ public: cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator); virtual ~cNoise3DGenerator(); - virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override; + virtual void Initialize(cIniFile & a_IniFile) override; virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override; virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override; diff --git a/src/Globals.h b/src/Globals.h index f886ba2d0..d2080b8eb 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -233,6 +233,7 @@ public: // Common headers (part 2, with macros): #include "ChunkDef.h" +#include "BiomeDef.h" #include "BlockID.h" #include "Entities/Effects.h" 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/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h index 38bf00ba6..de90c8075 100644 --- a/src/Items/ItemRedstoneDust.h +++ b/src/Items/ItemRedstoneDust.h @@ -27,7 +27,7 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ) override { - if (!g_BlockIsTorchPlaceable[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) // Some solid blocks, such as cocoa beans, are not suitable for dust + if (!g_BlockFullyOccupiesVoxel[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) // Some solid blocks, such as cocoa beans, are not suitable for dust { return false; } 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/Log.cpp b/src/Log.cpp index a0de4531b..2d6be0f59 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -147,11 +147,11 @@ void cLog::Log(const char * a_Format, va_list argList) -void cLog::Log(const char* a_Format, ...) +void cLog::Log(const char * a_Format, ...) { va_list argList; va_start(argList, a_Format); - Log( a_Format, argList ); + Log(a_Format, argList); va_end(argList); } @@ -159,9 +159,9 @@ void cLog::Log(const char* a_Format, ...) -void cLog::SimpleLog(const char* a_String) +void cLog::SimpleLog(const char * a_String) { - Log("%s", a_String ); + Log("%s", a_String); } @@ -14,11 +14,11 @@ private: public: cLog(const AString & a_FileName); ~cLog(); - void Log(const char* a_Format, va_list argList ); - void Log(const char* a_Format, ...); + void Log(const char * a_Format, va_list argList); + void Log(const char * a_Format, ...); // tolua_begin - void SimpleLog(const char* a_String); - void OpenLog( const char* a_FileName ); + void SimpleLog(const char * a_String); + void OpenLog(const char * a_FileName); void CloseLog(); void ClearLog(); static cLog* GetInstance(); diff --git a/src/MCServer.vcproj.user b/src/MCServer.vcproj.user new file mode 100644 index 000000000..b17909f71 --- /dev/null +++ b/src/MCServer.vcproj.user @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<VisualStudioUserFile + ProjectType="Visual C++" + Version="9,00" + ShowAllFiles="false" + > + <Configurations> + <Configuration + Name="Debug|Win32" + > + <DebugSettings + Command="$(TargetPath)" + WorkingDirectory="..\MCServer" + CommandArguments="" + Attach="false" + DebuggerType="3" + RemoteCommand="" + HttpUrl="" + PDBPath="" + SQLDebugging="" + Environment="" + EnvironmentMerge="true" + DebuggerFlavor="0" + MPIRunCommand="" + MPIRunArguments="" + MPIRunWorkingDirectory="" + ApplicationCommand="" + ApplicationArguments="" + ShimCommand="" + MPIAcceptMode="" + MPIAcceptFilter="" + /> + </Configuration> + <Configuration + Name="DebugProfile|Win32" + > + <DebugSettings + Command="$(TargetPath)" + WorkingDirectory="..\MCServer" + CommandArguments="" + Attach="false" + DebuggerType="3" + RemoteCommand="" + HttpUrl="" + PDBPath="" + SQLDebugging="" + Environment="" + EnvironmentMerge="true" + DebuggerFlavor="0" + MPIRunCommand="" + MPIRunArguments="" + MPIRunWorkingDirectory="" + ApplicationCommand="" + ApplicationArguments="" + ShimCommand="" + MPIAcceptMode="" + MPIAcceptFilter="" + /> + </Configuration> + <Configuration + Name="MinSizeRel|Win32" + > + <DebugSettings + Command="$(TargetPath)" + WorkingDirectory="..\MCServer" + CommandArguments="" + Attach="false" + DebuggerType="3" + RemoteCommand="" + HttpUrl="" + PDBPath="" + SQLDebugging="" + Environment="" + EnvironmentMerge="true" + DebuggerFlavor="0" + MPIRunCommand="" + MPIRunArguments="" + MPIRunWorkingDirectory="" + ApplicationCommand="" + ApplicationArguments="" + ShimCommand="" + MPIAcceptMode="" + MPIAcceptFilter="" + /> + </Configuration> + <Configuration + Name="Release|Win32" + > + <DebugSettings + Command="$(TargetPath)" + WorkingDirectory="..\MCServer" + CommandArguments="" + Attach="false" + DebuggerType="3" + RemoteCommand="" + HttpUrl="" + PDBPath="" + SQLDebugging="" + Environment="" + EnvironmentMerge="true" + DebuggerFlavor="0" + MPIRunCommand="" + MPIRunArguments="" + MPIRunWorkingDirectory="" + ApplicationCommand="" + ApplicationArguments="" + ShimCommand="" + MPIAcceptMode="" + MPIAcceptFilter="" + /> + </Configuration> + <Configuration + Name="ReleaseProfile|Win32" + > + <DebugSettings + Command="$(TargetPath)" + WorkingDirectory="..\MCServer" + CommandArguments="" + Attach="false" + DebuggerType="3" + Remote="1" + RemoteMachine="ASAGA" + RemoteCommand="" + HttpUrl="" + PDBPath="" + SQLDebugging="" + Environment="" + EnvironmentMerge="true" + DebuggerFlavor="0" + MPIRunCommand="" + MPIRunArguments="" + MPIRunWorkingDirectory="" + ApplicationCommand="" + ApplicationArguments="" + ShimCommand="" + MPIAcceptMode="" + MPIAcceptFilter="" + /> + </Configuration> + <Configuration + Name="RelWithDebInfo|Win32" + > + <DebugSettings + Command="$(TargetPath)" + WorkingDirectory="..\MCServer" + CommandArguments="" + Attach="false" + DebuggerType="3" + RemoteCommand="" + HttpUrl="" + PDBPath="" + SQLDebugging="" + Environment="" + EnvironmentMerge="true" + DebuggerFlavor="0" + MPIRunCommand="" + MPIRunArguments="" + MPIRunWorkingDirectory="" + ApplicationCommand="" + ApplicationArguments="" + ShimCommand="" + MPIAcceptMode="" + MPIAcceptFilter="" + /> + </Configuration> + </Configurations> +</VisualStudioUserFile> 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/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp index 55454a4b5..08aec0c65 100644 --- a/src/OSSupport/BlockingTCPLink.cpp +++ b/src/OSSupport/BlockingTCPLink.cpp @@ -7,17 +7,6 @@ -#ifdef _WIN32 - #define MSG_NOSIGNAL (0) -#endif -#ifdef __MACH__ - #define MSG_NOSIGNAL (0) -#endif - - - - - cBlockingTCPLink::cBlockingTCPLink(void) { } diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index f25f800c2..8ea5d8320 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -72,10 +72,6 @@ void cSocket::CloseSocket() #else // _WIN32 - if (shutdown(m_Socket, SHUT_RDWR) != 0)//SD_BOTH); - { - LOGWARN("Error on shutting down socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str()); - } if (close(m_Socket) != 0) { LOGWARN("Error closing socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str()); @@ -368,7 +364,7 @@ int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags int cSocket::Send(const char * a_Buffer, unsigned int a_Length) { - return send(m_Socket, a_Buffer, a_Length, 0); + return send(m_Socket, a_Buffer, a_Length, MSG_NOSIGNAL); } diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h index 81bfd28fc..b86560de8 100644 --- a/src/OSSupport/Socket.h +++ b/src/OSSupport/Socket.h @@ -5,6 +5,18 @@ +// Windows and MacOSX don't have the MSG_NOSIGNAL flag +#if ( \ + defined(_WIN32) || \ + (defined(__APPLE__) && defined(__MACH__)) \ +) + #define MSG_NOSIGNAL (0) +#endif + + + + + class cSocket { public: diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index fdbffb3e9..3293da32c 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -87,6 +87,7 @@ public: virtual void SendPlayerMoveLook (void) = 0; virtual void SendPlayerPosition (void) = 0; virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0; virtual void SendRespawn (void) = 0; virtual void SendExperience (void) = 0; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index e49dd43ff..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(); } @@ -704,6 +704,20 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) +void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_PLUGIN_MESSAGE); + WriteString(a_Channel); + WriteShort((short)a_Message.size()); + SendData(a_Message.data(), a_Message.size()); + Flush(); +} + + + + + void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { cCSLock Lock(m_CSPacket); @@ -850,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) { @@ -883,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/Protocol125.h b/src/Protocol/Protocol125.h index 0b32137d8..d0e5c9428 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -63,6 +63,7 @@ public: virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendRespawn (void) override; virtual void SendExperience (void) override; 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 8ec5dec29..5b3a79555 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -121,7 +121,7 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { - cPacketizer Pkt(*this, 0x24); // Block Break Animation packet + cPacketizer Pkt(*this, 0x25); // Block Break Animation packet Pkt.WriteInt(a_EntityID); Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockY); @@ -216,8 +216,23 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity) void cProtocol172::SendDisconnect(const AString & a_Reason) { - cPacketizer Pkt(*this, 0x40); - Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str())); + switch (m_State) + { + case 2: + { + // During login: + cPacketizer Pkt(*this, 0); + Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str())); + break; + } + case 3: + { + // In-game: + cPacketizer Pkt(*this, 0x40); + Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str())); + break; + } + } } @@ -628,6 +643,18 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) +void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + cPacketizer Pkt(*this, 0x3f); + Pkt.WriteString(a_Channel); + Pkt.WriteShort((short)a_Message.size()); + Pkt.WriteBuf(a_Message.data(), a_Message.size()); +} + + + + + void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { cPacketizer Pkt(*this, 0x1E); @@ -1010,11 +1037,31 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) return; } - HandlePacket(bb, PacketType); + if (!HandlePacket(bb, PacketType)) + { + // Unknown packet, already been reported, but without the length. Log the length here: + LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen); + + #ifdef _DEBUG + // Dump the packet contents into the log: + bb.ResetRead(); + AString Packet; + bb.ReadAll(Packet); + Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection + AString Out; + CreateHexDump(Out, Packet.data(), (int)Packet.size(), 24); + LOGD("Packet contents:\n%s", Out.c_str()); + #endif // _DEBUG + + return; + } 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, 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); } @@ -1024,7 +1071,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) -void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) +bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) { switch (m_State) { @@ -1033,8 +1080,8 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) // Status switch (a_PacketType) { - case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return; - case 0x01: HandlePacketStatusPing (a_ByteBuffer); return; + case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true; + case 0x01: HandlePacketStatusPing (a_ByteBuffer); return true; } break; } @@ -1044,8 +1091,8 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) // Login switch (a_PacketType) { - case 0x00: HandlePacketLoginStart (a_ByteBuffer); return; - case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return; + case 0x00: HandlePacketLoginStart (a_ByteBuffer); return true; + case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true; } break; } @@ -1055,36 +1102,54 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) // Game switch (a_PacketType) { - case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return; - case 0x01: HandlePacketChatMessage (a_ByteBuffer); return; - case 0x02: HandlePacketUseEntity (a_ByteBuffer); return; - case 0x03: HandlePacketPlayer (a_ByteBuffer); return; - case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return; - case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return; - case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return; - case 0x07: HandlePacketBlockDig (a_ByteBuffer); return; - case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return; - case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return; - case 0x0a: HandlePacketAnimation (a_ByteBuffer); return; - case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return; - case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return; - case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return; - case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return; + case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return true; + case 0x01: HandlePacketChatMessage (a_ByteBuffer); return true; + case 0x02: HandlePacketUseEntity (a_ByteBuffer); return true; + case 0x03: HandlePacketPlayer (a_ByteBuffer); return true; + case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return true; + case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return true; + case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return true; + case 0x07: HandlePacketBlockDig (a_ByteBuffer); return true; + case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return true; + case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return true; + case 0x0a: HandlePacketAnimation (a_ByteBuffer); return true; + case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return true; + case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return true; + case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return true; + case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true; case 0x0f: // Confirm transaction - not used in MCS - case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return; - case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return; - case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return; - case 0x14: HandlePacketTabComplete (a_ByteBuffer); return; - case 0x15: HandlePacketClientSettings (a_ByteBuffer); return; - case 0x16: HandlePacketClientStatus (a_ByteBuffer); return; - case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return; + case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; + case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true; + case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true; + case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true; + case 0x15: HandlePacketClientSettings (a_ByteBuffer); return true; + case 0x16: HandlePacketClientStatus (a_ByteBuffer); return true; + case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return true; } 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; } @@ -1144,6 +1209,12 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) // TODO: Protocol encryption should be set up here if not localhost / auth + if (!m_Client->HandleHandshake(Username)) + { + // The client is not welcome here, they have been sent a Kick packet already + return; + } + // Send login success: { cPacketizer Pkt(*this, 0x02); // Login success packet @@ -1614,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 ( @@ -1627,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; + } + } + } } } @@ -1678,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); @@ -1769,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/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 23ff2365d..07dba834b 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -86,6 +86,7 @@ public: virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendRespawn (void) override; virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 @@ -221,8 +222,10 @@ protected: /// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets void AddReceivedData(const char * a_Data, int a_Size); - /// Reads and handles the packet. The packet length and type have already been read. - void HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType); + /** Reads and handles the packet. The packet length and type have already been read. + Returns true if the packet was understood, false if it was an unknown packet + */ + bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType); // Packet handlers while in the Status state (m_State == 1): void HandlePacketStatusPing (cByteBuffer & a_ByteBuffer); diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index e2ea0e6e5..a21f4f042 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -476,6 +476,16 @@ void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player) +void cProtocolRecognizer::SendPluginMessage(const AString & a_Channel, const AString & a_Message) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendPluginMessage(a_Channel, a_Message); +} + + + + + void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { ASSERT(m_Protocol != NULL); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index fbcf59f3b..e94f4cde8 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -98,6 +98,7 @@ public: virtual void SendPlayerMoveLook (void) override; virtual void SendPlayerPosition (void) override; virtual void SendPlayerSpawn (const cPlayer & a_Player) override; + virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override; virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override; virtual void SendRespawn (void) override; virtual void SendExperience (void) override; diff --git a/VC2008/MCServer.rc b/src/Resources/MCServer.rc index e0fbbea5d..e0fbbea5d 100644 --- a/VC2008/MCServer.rc +++ b/src/Resources/MCServer.rc diff --git a/VC2008/icon.ico b/src/Resources/icon.ico Binary files differindex 4024523a1..4024523a1 100644 --- a/VC2008/icon.ico +++ b/src/Resources/icon.ico diff --git a/VC2008/icon_128.png b/src/Resources/icon_128.png Binary files differindex 87d939a04..87d939a04 100644 --- a/VC2008/icon_128.png +++ b/src/Resources/icon_128.png diff --git a/VC2008/icon_256.png b/src/Resources/icon_256.png Binary files differindex 9a77a490f..9a77a490f 100644 --- a/VC2008/icon_256.png +++ b/src/Resources/icon_256.png diff --git a/VC2008/resource_MCServer.h b/src/Resources/resource_MCServer.h index 42f6c4eaf..42f6c4eaf 100644 --- a/VC2008/resource_MCServer.h +++ b/src/Resources/resource_MCServer.h diff --git a/src/Server.h b/src/Server.h index d79417fb0..703a7077e 100644 --- a/src/Server.h +++ b/src/Server.h @@ -107,7 +107,7 @@ public: // tolua_export /// Notifies the server that a player is being destroyed; the server uses this to adjust the number of players void PlayerDestroying(const cPlayer * a_Player); - /* Returns base64 encoded favicon data (obtained from favicon.png) */ + /** Returns base64 encoded favicon data (obtained from favicon.png) */ const AString & GetFaviconData(void) const { return m_FaviconData; } CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; } diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp index f65908729..469680098 100644 --- a/src/Simulator/RedstoneSimulator.cpp +++ b/src/Simulator/RedstoneSimulator.cpp @@ -44,83 +44,46 @@ void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChu int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width; int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width; + + BLOCKTYPE Block; + NIBBLETYPE Meta; + a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); - if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ))) - { - return; - } - - // Check for duplicates: - cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); - for (cRedstoneSimulatorChunkData::const_iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) - { - if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) - { - return; - } - } - - ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ)); -} - - - - - -void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) -{ - cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); - if (ChunkData.empty()) - { - return; - } - - int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; + // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid + // Checking only when a block is changed, as opposed to every tick, also improves performance - // Check to see if PoweredBlocks have invalid items (source is air or unpowered) - for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();) + for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) { - int RelX = itr->a_SourcePos.x - a_ChunkX * cChunkDef::Width; - int RelZ = itr->a_SourcePos.z - a_ChunkZ * cChunkDef::Width; - int DestRelX = itr->a_BlockPos.x - a_ChunkX * cChunkDef::Width; - int DestRelZ = itr->a_BlockPos.z - a_ChunkZ * cChunkDef::Width; - - BLOCKTYPE SourceBlockType; - NIBBLETYPE SourceBlockMeta; - BLOCKTYPE DestBlockType; - if ( - !a_Chunk->UnboundedRelGetBlock(RelX, itr->a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta) || - !a_Chunk->UnboundedRelGetBlockType(DestRelX, itr->a_BlockPos.y, DestRelZ, DestBlockType) - ) + if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - if (SourceBlockType != itr->a_SourceBlock) + if (!IsPotentialSource(Block)) { - LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); - itr = m_PoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + m_PoweredBlocks.erase(itr); + break; } else if ( // Changeable sources - ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || - ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || - ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) || - (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) || - (((SourceBlockType == E_BLOCK_STONE_PRESSURE_PLATE) || (SourceBlockType == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (SourceBlockMeta == 0)) + ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || + ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || + ((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) || + (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || + (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) ) { - LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); - itr = m_PoweredBlocks.erase(itr); + LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + m_PoweredBlocks.erase(itr); + break; } - else if (SourceBlockType == E_BLOCK_DAYLIGHT_SENSOR) + else if (Block == E_BLOCK_DAYLIGHT_SENSOR) { if (!a_Chunk->IsLightValid()) { - m_World.QueueLightChunk(a_ChunkX, a_ChunkZ); - ++itr; - continue; + m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ()); + break; } else { @@ -130,126 +93,125 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness(); { LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level"); - itr = m_PoweredBlocks.erase(itr); - } - else - { - ++itr; - continue; + m_PoweredBlocks.erase(itr); + break; } } } - else if ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (DestBlockType == E_BLOCK_REDSTONE_WIRE)) + } + + for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + { + if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - // It is simply not allowed that a wire powers another wire, presuming that data here is sane and a dest and source are beside each other - LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because its source was also wire"); - itr = m_PoweredBlocks.erase(itr); + if (!IsPotentialSource(Block)) + { + LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + m_LinkedPoweredBlocks.erase(itr); + break; + } + else if ( + // Things that can send power through a block but which depends on meta + ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || + ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || + (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) + ) + { + LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + m_LinkedPoweredBlocks.erase(itr); + break; + } } - else + else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { - ++itr; + if (!IsViableMiddleBlock(Block)) + { + LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + m_LinkedPoweredBlocks.erase(itr); + break; + } } } - // Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed - for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();) + for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr) { - int RelX = itr->a_SourcePos.x - a_ChunkX * cChunkDef::Width; - int RelZ = itr->a_SourcePos.z - a_ChunkZ * cChunkDef::Width; - int MidRelX = itr->a_MiddlePos.x - a_ChunkX * cChunkDef::Width; - int MidRelZ = itr->a_MiddlePos.z - a_ChunkZ * cChunkDef::Width; - - BLOCKTYPE SourceBlockType; - NIBBLETYPE SourceBlockMeta; - BLOCKTYPE MiddleBlockType; - if ( - !a_Chunk->UnboundedRelGetBlock(RelX, itr->a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta) || - !a_Chunk->UnboundedRelGetBlockType(MidRelX, itr->a_MiddlePos.y, MidRelZ, MiddleBlockType) - ) + if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - if (SourceBlockType != itr->a_SourceBlock) - { - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); - itr = m_LinkedPoweredBlocks.erase(itr); - } - else if (MiddleBlockType != itr->a_MiddleBlock) - { - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); - itr = m_LinkedPoweredBlocks.erase(itr); - } - else if ( - // Things that can send power through a block but which depends on meta - ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) || - ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) || - (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) - ) + if (!IsAllowedBlock(Block)) { - LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str()); - itr = m_LinkedPoweredBlocks.erase(itr); - } - else - { - ++itr; + LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + m_SimulatedPlayerToggleableBlocks.erase(itr); + break; } } - for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end();) + for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr) { - int RelX = itr->a_BlockPos.x - a_ChunkX * cChunkDef::Width; - int RelZ = itr->a_BlockPos.z - a_ChunkZ * cChunkDef::Width; - - BLOCKTYPE SourceBlockType; - if (!a_Chunk->UnboundedRelGetBlockType(RelX, itr->a_BlockPos.y, RelZ, SourceBlockType)) + if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - else if (!IsAllowedBlock(SourceBlockType)) + + if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF)) { - LOGD("cRedstoneSimulator: Erased block %s from toggleable simulated list as block is no longer redstone", ItemToFullString(SourceBlockType).c_str()); - itr = m_SimulatedPlayerToggleableBlocks.erase(itr); + m_RepeatersDelayList.erase(itr); + break; } - else + } + + cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); + for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr) + { + if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block { - ++itr; + if (!IsAllowedBlock(Block)) + { + ChunkData.erase(itr); // The new blocktype is not redstone; it must be removed from this list + } + else + { + itr->Data = Block; // Update block information + } + return; } } - for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end();) + if (!IsAllowedBlock(Block)) { - int RelX = itr->a_BlockPos.x - a_ChunkX * cChunkDef::Width; - int RelZ = itr->a_BlockPos.z - a_ChunkZ * cChunkDef::Width; + return; + } - BLOCKTYPE SourceBlockType; - if (!a_Chunk->UnboundedRelGetBlockType(RelX, itr->a_BlockPos.y, RelZ, SourceBlockType)) - { - continue; - } + ChunkData.push_back(cCoordWithBlock(RelX, a_BlockY, RelZ, Block)); +} - if ((SourceBlockType != E_BLOCK_REDSTONE_REPEATER_ON) && (SourceBlockType != E_BLOCK_REDSTONE_REPEATER_OFF)) - { - itr = m_RepeatersDelayList.erase(itr); - continue; - } - ++itr; - } - for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;) + + +void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) +{ + // We still attempt to simulate all blocks in the chunk every tick, because of outside influence that needs to be taken into account + // For example, repeaters need to be ticked, pressure plates checked for entities, daylight sensor checked for light changes, etc. + // The easiest way to make this more efficient is probably just to reduce code within the handlers that put too much strain on server, like getting or setting blocks + // A marking dirty system might be a TODO for later on, perhaps + + cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData(); + if (ChunkData.empty()) { - BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z); - if (!IsAllowedBlock(BlockType)) - { - dataitr = ChunkData.erase(dataitr); - continue; - } + return; + } + + int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; + int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; - // PoweredBlock and LinkedPoweredBlock list was fine, now to the actual handling + for (cRedstoneSimulatorChunkData::const_iterator dataitr = ChunkData.begin(); dataitr != ChunkData.end(); ++dataitr) + { int a_X = BaseX + dataitr->x; int a_Z = BaseZ + dataitr->z; - switch (BlockType) + switch (dataitr->Data) { 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; @@ -262,19 +224,19 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: { - HandleRedstoneTorch(a_X, dataitr->y, a_Z, BlockType); + HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data); break; } case E_BLOCK_STONE_BUTTON: case E_BLOCK_WOODEN_BUTTON: { - HandleRedstoneButton(a_X, dataitr->y, a_Z, BlockType); + HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data); break; } case E_BLOCK_REDSTONE_REPEATER_OFF: case E_BLOCK_REDSTONE_REPEATER_ON: { - HandleRedstoneRepeater(a_X, dataitr->y, a_Z, BlockType); + HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data); break; } case E_BLOCK_PISTON: @@ -286,7 +248,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c case E_BLOCK_REDSTONE_LAMP_OFF: case E_BLOCK_REDSTONE_LAMP_ON: { - HandleRedstoneLamp(a_X, dataitr->y, a_Z, BlockType); + HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data); break; } case E_BLOCK_DISPENSER: @@ -305,18 +267,16 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_POWERED_RAIL: { - HandleRail(a_X, dataitr->y, a_Z, BlockType); + HandleRail(a_X, dataitr->y, a_Z, dataitr->Data); break; } case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE: { - HandlePressurePlate(a_X, dataitr->y, a_Z, BlockType); + HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data); break; } } - - ++dataitr; } } @@ -487,7 +447,7 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl }; // Check to see if directly beside a power source - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ)) { m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power } @@ -545,7 +505,7 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl // transferring power to other wires around. // However, self not directly powered anymore, so source must have been removed, // therefore, self must be set to meta zero - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); + m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock return; // No need to process block power sets because self not powered } else @@ -693,7 +653,7 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int // Apparently, incrementing ticks only works reliably here, and not in SimChunk; // With a world with lots of redstone, the repeaters simply do not delay // I am confounded to say why. Perhaps optimisation failure. - LOGD("Incremented a repeater @ %i %i %i | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); + LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); itr->a_ElapsedTicks++; } } @@ -781,48 +741,20 @@ void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) { - if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) + if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) { - // Block position is located at top half of door - // Is Y - 1 both within world boundaries, a door block, and the bottom half of a door? - // The bottom half stores the open/closed information - if ( - (a_BlockY - 1 >= 0) && - ((m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR) || (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_IRON_DOOR)) && - (m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ & 0x08) == 0) - ) + if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) { - if ((m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ) & 0x04) == 0) // Closed door? - { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open - { - cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); - } - } - else // Opened door - { - if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so - { - cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); - } - } + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); + SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); } } else { - if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x04) == 0) // Closed door? - { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open - { - cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); - } - } - else // Opened door + if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) { - if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so - { - cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); - } + cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ); + SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); } } } @@ -970,6 +902,7 @@ void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_B else { m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); } break; } @@ -1032,6 +965,7 @@ void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_B else { m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); } break; } @@ -1188,6 +1122,33 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block +bool cRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) + { + if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + + if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE) + { + return true; + } + } + + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) + { + if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + + if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE) + { + return true; + } + } + return false; // Source was in front of the piston's front face +} + + + + bool cRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered) { @@ -1333,11 +1294,6 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block // Don't set air, fixes some bugs (wires powering themselves) return; } - if ((Block == E_BLOCK_REDSTONE_WIRE) && (a_SourceBlock == E_BLOCK_REDSTONE_WIRE)) - { - // Wires cannot power themselves normally, instead, the wire handler will manually set meta - return; - } for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list { @@ -1354,7 +1310,6 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block sPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); - RC.a_SourceBlock = a_SourceBlock; m_PoweredBlocks.push_back(RC); } @@ -1379,11 +1334,6 @@ void cRedstoneSimulator::SetBlockLinkedPowered( { return; } - if ((a_SourceBlock == E_BLOCK_REDSTONE_WIRE) && (DestBlock == E_BLOCK_REDSTONE_WIRE)) - { - // Wires cannot power another wire through a block - return; - } for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list { @@ -1402,8 +1352,6 @@ void cRedstoneSimulator::SetBlockLinkedPowered( RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); - RC.a_SourceBlock = a_SourceBlock; - RC.a_MiddleBlock = a_MiddleBlock; m_LinkedPoweredBlocks.push_back(RC); } diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h index 1080c3f81..63a5be3d3 100644 --- a/src/Simulator/RedstoneSimulator.h +++ b/src/Simulator/RedstoneSimulator.h @@ -4,7 +4,7 @@ #include "Simulator.h" /// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used -typedef cCoordWithIntList cRedstoneSimulatorChunkData; +typedef cCoordWithBlockVector cRedstoneSimulatorChunkData; @@ -39,7 +39,6 @@ private: { Vector3i a_BlockPos; // Position of powered block Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos - BLOCKTYPE a_SourceBlock; // The source block type (for pistons pushing away sources and replacing with non source etc.) }; struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) @@ -47,8 +46,6 @@ private: Vector3i a_BlockPos; Vector3i a_MiddlePos; Vector3i a_SourcePos; - BLOCKTYPE a_SourceBlock; - BLOCKTYPE a_MiddleBlock; }; struct sSimulatedPlayerToggleableList @@ -81,102 +78,89 @@ private: // In addition to being non-performant, it would stop the player from actually breaking said device /* ====== SOURCES ====== */ - /// <summary>Handles the redstone torch</summary> + /** Handles the redstone torch */ void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); - /// <summary>Handles the redstone block</summary> + /** Handles the redstone block */ void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles levers</summary> + /** Handles levers */ void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles buttons</summary> + /** Handles buttons */ void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); - /// <summary>Handles daylight sensors</summary> + /** Handles daylight sensors */ void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles pressure plates</summary> + /** Handles pressure plates */ void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); /* ==================== */ /* ====== CARRIERS ====== */ - /// <summary>Handles redstone wire</summary> + /** Handles redstone wire */ void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles repeaters</summary> + /** Handles repeaters */ void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); /* ====================== */ /* ====== DEVICES ====== */ - /// <summary>Handles pistons</summary> + /** Handles pistons */ void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles dispensers and droppers</summary> + /** Handles dispensers and droppers */ void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles TNT (exploding)</summary> + /** Handles TNT (exploding) */ void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles redstone lamps</summary> + /** Handles redstone lamps */ void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); - /// <summary>Handles doords</summary> + /** Handles doords */ void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles activator, detector, and powered rails</summary> + /** Handles activator, detector, and powered rails */ void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); - /// <summary>Handles trapdoors</summary> + /** Handles trapdoors */ void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Handles noteblocks</summary> + /** Handles noteblocks */ void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ); /* ===================== */ /* ====== Helper functions ====== */ - /// <summary>Marks a block as powered</summary> + /** Marks a block as powered */ void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock); - /// <summary>Marks a block as being powered through another block</summary> + /** Marks a block as being powered through another block */ void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock); - /// <summary>Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back</summary> + /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */ void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered); - /// <summary>Marks the second block in a direction as linked powered</summary> + /** Marks the second block in a direction as linked powered */ void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock); - /// <summary>Marks all blocks immediately surrounding a coordinate as powered</summary> + /** Marks all blocks immediately surrounding a coordinate as powered */ void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock); - /// <summary>Queues a repeater to be powered or unpowered</summary> + /** Queues a repeater to be powered or unpowered */ void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn); - /// <summary>Returns if a coordinate is powered or linked powered</summary> + /** Returns if a coordinate is powered or linked powered */ bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); } - /// <summary>Returns if a coordinate is in the directly powered blocks list</summary> + /** Returns if a coordinate is in the directly powered blocks list */ bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Returns if a coordinate is in the indirectly powered blocks list</summary> + /** Returns if a coordinate is in the indirectly powered blocks list */ bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Returns if a coordinate was marked as simulated (for blocks toggleable by players)</summary> + /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered); - /// <summary>Returns if a repeater is powered</summary> + /** Returns if a repeater is powered */ bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); - /// <summary>Returns if a piston is powered</summary> + /** Returns if a piston is powered */ bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + /** Returns if a wire is powered + The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire + */ + bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ); - /// <summary>Returns if lever metadata marks it as emitting power</summary> + + /** Returns if lever metadata marks it as emitting power */ bool IsLeverOn(NIBBLETYPE a_BlockMeta); - /// <summary>Returns if button metadata marks it as emitting power</summary> + /** Returns if button metadata marks it as emitting power */ bool IsButtonOn(NIBBLETYPE a_BlockMeta); /* ============================== */ /* ====== Misc Functions ====== */ - /// <summary>Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation</summary> - inline static bool IsViableMiddleBlock(BLOCKTYPE Block) - { - if (!g_BlockIsSolid[Block]) { return false; } + /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ + inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return g_BlockFullyOccupiesVoxel[Block]; } - switch (Block) - { - // Add SOLID but not viable middle blocks here - case E_BLOCK_PISTON: - case E_BLOCK_PISTON_EXTENSION: - case E_BLOCK_STICKY_PISTON: - case E_BLOCK_REDSTONE_REPEATER_ON: - case E_BLOCK_REDSTONE_REPEATER_OFF: - case E_BLOCK_DAYLIGHT_SENSOR: - { - return false; - } - default: return true; - } - } - - /// <summary>Returns if a block is a mechanism (something that accepts power and does something)</summary> + /** Returns if a block is a mechanism (something that accepts power and does something) */ inline static bool IsMechanism(BLOCKTYPE Block) { switch (Block) @@ -205,16 +189,16 @@ private: } } - /// <summary>Returns if a block has the potential to output power</summary> + /** Returns if a block has the potential to output power */ inline static bool IsPotentialSource(BLOCKTYPE Block) { switch (Block) { + case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DAYLIGHT_SENSOR: case E_BLOCK_WOODEN_BUTTON: case E_BLOCK_STONE_BUTTON: case E_BLOCK_REDSTONE_WIRE: - case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: case E_BLOCK_LEVER: case E_BLOCK_REDSTONE_REPEATER_ON: @@ -227,7 +211,7 @@ private: } } - /// <summary>Returns if a block is any sort of redstone device</summary> + /** Returns if a block is any sort of redstone device */ inline static bool IsRedstone(BLOCKTYPE Block) { switch (Block) @@ -248,6 +232,7 @@ private: case E_BLOCK_LEVER: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_NOTE_BLOCK: + case E_BLOCK_POWERED_RAIL: case E_BLOCK_REDSTONE_LAMP_OFF: case E_BLOCK_REDSTONE_LAMP_ON: case E_BLOCK_REDSTONE_REPEATER_OFF: 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/StringUtils.cpp b/src/StringUtils.cpp index 0b38297ef..0dbd41c12 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -18,27 +18,40 @@ -AString & AppendVPrintf(AString & str, const char *format, va_list args) +AString & AppendVPrintf(AString & str, const char * format, va_list args) { ASSERT(format != NULL); char buffer[2048]; size_t len; + #ifdef va_copy + va_list argsCopy; + va_copy(argsCopy, args); + #else + #define argsCopy args + #endif #ifdef _MSC_VER // MS CRT provides secure printf that doesn't behave like in the C99 standard - if ((len = _vsnprintf_s(buffer, ARRAYCOUNT(buffer), _TRUNCATE, format, args)) != -1) + if ((len = _vsnprintf_s(buffer, ARRAYCOUNT(buffer), _TRUNCATE, format, argsCopy)) != -1) #else // _MSC_VER - if ((len = vsnprintf(buffer, ARRAYCOUNT(buffer), format, args)) < ARRAYCOUNT(buffer)) + if ((len = vsnprintf(buffer, ARRAYCOUNT(buffer), format, argsCopy)) < ARRAYCOUNT(buffer)) #endif // else _MSC_VER { // The result did fit into the static buffer + #ifdef va_copy + va_end(argsCopy); + #endif str.append(buffer, len); return str; } + #ifdef va_copy + va_end(argsCopy); + #endif - // The result did not fit into the static buffer + // The result did not fit into the static buffer, use a dynamic buffer: #ifdef _MSC_VER // for MS CRT, we need to calculate the result length + // MS doesn't have va_copy() and does nod need it at all len = _vscprintf(format, args); if (len == -1) { @@ -47,13 +60,19 @@ AString & AppendVPrintf(AString & str, const char *format, va_list args) #endif // _MSC_VER // Allocate a buffer and printf into it: + #ifdef va_copy + va_copy(argsCopy, args); + #endif std::vector<char> Buffer(len + 1); #ifdef _MSC_VER - vsprintf_s((char *)&(Buffer.front()), Buffer.size(), format, args); + vsprintf_s((char *)&(Buffer.front()), Buffer.size(), format, argsCopy); #else // _MSC_VER - vsnprintf((char *)&(Buffer.front()), Buffer.size(), format, args); + vsnprintf((char *)&(Buffer.front()), Buffer.size(), format, argsCopy); #endif // else _MSC_VER str.append(&(Buffer.front()), Buffer.size() - 1); + #ifdef va_copy + va_end(argsCopy); + #endif return str; } @@ -89,7 +108,7 @@ AString Printf(const char * format, ...) -AString & AppendPrintf(AString &str, const char *format, ...) +AString & AppendPrintf(AString &str, const char * format, ...) { va_list args; va_start(args, format); diff --git a/src/StringUtils.h b/src/StringUtils.h index 2373f3843..dfbfc2a75 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -21,7 +21,7 @@ typedef std::list<AString> AStringList; -/// Add the formated string to the existing data in the string +/** Add the formated string to the existing data in the string */ extern AString & AppendVPrintf(AString & str, const char * format, va_list args); /// Output the formatted text into the string 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 39300d419..3e7c0ef74 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -10,11 +10,13 @@ #include "Root.h" #include "inifile/iniFile.h" #include "ChunkMap.h" +#include "Generating/ChunkDesc.h" #include "OSSupport/Timer.h" // 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" @@ -229,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), @@ -238,6 +241,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_SkyDarkness(0), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) + m_GeneratorCallbacks(*this), m_TickThread(*this) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -509,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); @@ -582,8 +587,8 @@ void cWorld::Start(void) m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1); m_Lighting.Start(this); - m_Storage.Start(this, m_StorageSchema); - m_Generator.Start(this, IniFile); + m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor ); + m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile); m_ChunkSender.Start(this); m_TickThread.Start(); @@ -688,6 +693,7 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec) TickClients(a_Dt); TickQueuedBlocks(); TickQueuedTasks(); + TickScheduledTasks(); GetSimulatorManager()->Simulate(a_Dt); @@ -859,6 +865,31 @@ void cWorld::TickQueuedTasks(void) } // for itr - m_Tasks[] } +void cWorld::TickScheduledTasks() +{ + ScheduledTaskList Tasks; + // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks + { + cCSLock Lock(m_CSScheduledTasks); + ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); + while (itr != m_ScheduledTasks.end() && (*itr)->Ticks > 0) + { + Tasks.push_back(m_ScheduledTasks.front()); + m_ScheduledTasks.pop_front(); + } + for(;itr != m_ScheduledTasks.end(); itr++) + { + (*itr)->Ticks--; + } + } + + // Execute and delete each task: + for (ScheduledTaskList::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr) + { + (*itr)->Run(*this); + delete *itr; + } // for itr - m_Tasks[] +} @@ -1645,6 +1676,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); @@ -2569,6 +2623,19 @@ void cWorld::QueueTask(cTask * a_Task) m_Tasks.push_back(a_Task); } +void cWorld::ScheduleTask(cScheduledTask * a_Task) +{ + cCSLock Lock(m_CSScheduledTasks); + for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++) + { + if((*itr)->Ticks >= a_Task->Ticks) + { + m_ScheduledTasks.insert(itr, a_Task); + return; + } + } + m_ScheduledTasks.push_back(a_Task); +} @@ -2843,3 +2910,77 @@ void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cWorld::cChunkGeneratorCallbacks: + +cWorld::cChunkGeneratorCallbacks::cChunkGeneratorCallbacks(cWorld & a_World) : + m_World(&a_World) +{ +} + + + + + +void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc) +{ + cChunkDef::BlockNibbles BlockMetas; + a_ChunkDesc.CompressBlockMetas(BlockMetas); + + m_World->SetChunkData( + a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), + a_ChunkDesc.GetBlockTypes(), BlockMetas, + NULL, NULL, // We don't have lighting, chunk will be lighted when needed + &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(), + a_ChunkDesc.GetEntities(), a_ChunkDesc.GetBlockEntities(), + true + ); + + // Save the chunk right after generating, so that we don't have to generate it again on next run + m_World->GetStorage().QueueSaveChunk(a_ChunkDesc.GetChunkX(), 0, a_ChunkDesc.GetChunkZ()); +} + + + + + +bool cWorld::cChunkGeneratorCallbacks::IsChunkValid(int a_ChunkX, int a_ChunkZ) +{ + return m_World->IsChunkValid(a_ChunkX, a_ChunkZ); +} + + + + + +bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) +{ + return m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ); +} + + + + + +void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) +{ + cPluginManager::Get()->CallHookChunkGenerating( + m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc + ); +} + + + + + +void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_ChunkDesc) +{ + cPluginManager::Get()->CallHookChunkGenerated( + m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc + ); +} + + + + + diff --git a/src/World.h b/src/World.h index f90ddd90f..ef74a65c7 100644 --- a/src/World.h +++ b/src/World.h @@ -82,7 +82,18 @@ public: virtual void Run(cWorld & a_World) = 0; } ; + /// A common ancestor for all scheduled tasks queued onto the tick thread + class cScheduledTask + { + public: + cScheduledTask(const int a_Ticks) : Ticks(a_Ticks) {}; + virtual ~cScheduledTask() {}; + virtual void Run(cWorld & a_World) = 0; + int Ticks; + }; + typedef std::vector<cTask *> cTasks; + typedef std::list<cScheduledTask *> ScheduledTaskList; class cTaskSaveAllChunks : public cTask @@ -363,6 +374,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); @@ -533,6 +547,9 @@ public: /// Queues a task onto the tick thread. The task object will be deleted once the task is finished void QueueTask(cTask * a_Task); // Exported in ManualBindings.cpp + + // Queues a task onto the tick thread. The task object will be deleted once the task is finished + void ScheduleTask(cScheduledTask * a_Task); /// Returns the number of chunks loaded int GetNumChunks() const; // tolua_export @@ -636,6 +653,27 @@ private: virtual void Execute(void) override; } ; + + /** Implementation of the callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */ + class cChunkGeneratorCallbacks : + public cChunkGenerator::cChunkSink, + public cChunkGenerator::cPluginInterface + { + cWorld * m_World; + + // cChunkSink overrides: + virtual void OnChunkGenerated (cChunkDesc & a_ChunkDesc) override; + virtual bool IsChunkValid (int a_ChunkX, int a_ChunkZ) override; + virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) override; + + // cPluginInterface overrides: + virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) override; + virtual void CallHookChunkGenerated (cChunkDesc & a_ChunkDesc) override; + + public: + cChunkGeneratorCallbacks(cWorld & a_World); + } ; + AString m_WorldName; AString m_IniFileName; @@ -643,6 +681,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; @@ -714,6 +754,9 @@ private: cChunkGenerator m_Generator; + /** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */ + cChunkGeneratorCallbacks m_GeneratorCallbacks; + cChunkSender m_ChunkSender; cLightingThread m_Lighting; cTickThread m_TickThread; @@ -721,9 +764,16 @@ private: /// Guards the m_Tasks cCriticalSection m_CSTasks; + /// Guards the m_ScheduledTasks + cCriticalSection m_CSScheduledTasks; + /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks cTasks m_Tasks; + /// Tasks that have been queued to be executed on the tick thread at some number of ticks in + /// the future; guarded by m_CSScheduledTasks + ScheduledTaskList m_ScheduledTasks; + /// Guards m_Clients cCriticalSection m_CSClients; @@ -751,6 +801,9 @@ private: /// Executes all tasks queued onto the tick thread void TickQueuedTasks(void); + /// Executes all tasks queued onto the tick thread + void TickScheduledTasks(void); + /// Ticks all clients that are in this world void TickClients(float a_Dt); diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index e5043de1f..e1205f2be 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -257,7 +257,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(); } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 8605930b6..16513cd1b 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -58,8 +58,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 +273,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; } @@ -1150,7 +1151,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 +1892,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..e66e63b08 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); 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... |