summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml8
-rw-r--r--CMakeLists.txt11
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--MCServer/.gitignore6
-rw-r--r--MCServer/Plugins/@EnableMobDebug.lua29
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua44
-rw-r--r--MCServer/Plugins/APIDump/Classes/Geometry.lua13
-rw-r--r--MCServer/Plugins/APIDump/main_APIDump.lua91
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua40
-rw-r--r--MCServer/Plugins/InfoReg.lua4
-rw-r--r--MCServer/crafting.txt56
-rw-r--r--SetFlags.cmake13
-rw-r--r--Tools/MCADefrag/Globals.h5
-rw-r--r--Tools/ProtoProxy/Connection.cpp16
-rw-r--r--Tools/ProtoProxy/Connection.h2
-rw-r--r--Tools/ProtoProxy/Globals.h7
-rw-r--r--src/Bindings/AllToLua.pkg11
-rw-r--r--src/Bindings/LuaState.cpp18
-rw-r--r--src/Bindings/LuaState.h12
-rw-r--r--src/Bindings/ManualBindings.cpp11
-rw-r--r--src/Bindings/PluginLua.cpp1
-rw-r--r--src/Bindings/PluginManager.cpp2
-rw-r--r--src/BlockArea.cpp19
-rw-r--r--src/BlockArea.h9
-rw-r--r--src/BlockEntities/DispenserEntity.cpp8
-rw-r--r--src/BlockInfo.cpp1
-rw-r--r--src/Blocks/BlockAnvil.h63
-rw-r--r--src/Blocks/BlockCake.h55
-rw-r--r--src/Blocks/BlockHandler.cpp4
-rw-r--r--src/Blocks/BlockLeaves.h1
-rw-r--r--src/Blocks/BlockMushroom.h1
-rw-r--r--src/Blocks/BlockVine.h2
-rw-r--r--src/Blocks/MetaRotater.h21
-rw-r--r--src/BoundingBox.cpp2
-rw-r--r--src/BoundingBox.h2
-rw-r--r--src/ByteBuffer.cpp32
-rw-r--r--src/ByteBuffer.h2
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/ChunkDef.h39
-rw-r--r--src/ChunkMap.cpp7
-rw-r--r--src/ClientHandle.cpp66
-rw-r--r--src/ClientHandle.h6
-rw-r--r--src/CommandOutput.cpp4
-rw-r--r--src/CommandOutput.h2
-rw-r--r--src/CompositeChat.cpp64
-rw-r--r--src/CraftingRecipes.cpp91
-rw-r--r--src/CraftingRecipes.h3
-rw-r--r--src/Cuboid.cpp54
-rw-r--r--src/Cuboid.h15
-rw-r--r--src/DeadlockDetect.h2
-rw-r--r--src/Defines.h49
-rw-r--r--src/Entities/Entity.cpp2
-rw-r--r--src/Entities/Entity.h4
-rw-r--r--src/Entities/ExpOrb.cpp26
-rw-r--r--src/Entities/ExpOrb.h23
-rw-r--r--src/Entities/Floater.h2
-rw-r--r--src/Entities/HangingEntity.cpp53
-rw-r--r--src/Entities/HangingEntity.h49
-rw-r--r--src/Entities/ItemFrame.cpp39
-rw-r--r--src/Entities/ItemFrame.h22
-rw-r--r--src/Entities/Pickup.cpp2
-rw-r--r--src/Entities/Pickup.h23
-rw-r--r--src/Entities/Player.cpp33
-rw-r--r--src/Entities/Player.h11
-rw-r--r--src/Entities/ProjectileEntity.cpp113
-rw-r--r--src/Entities/ProjectileEntity.h13
-rw-r--r--src/Entities/TNTEntity.cpp33
-rw-r--r--src/Entities/TNTEntity.h23
-rw-r--r--src/FurnaceRecipe.cpp2
-rw-r--r--src/Generating/ChunkGenerator.cpp4
-rw-r--r--src/Generating/ComposableGenerator.cpp5
-rw-r--r--src/Generating/POCPieceGenerator.cpp270
-rw-r--r--src/Generating/POCPieceGenerator.h54
-rw-r--r--src/Generating/PieceGenerator.cpp625
-rw-r--r--src/Generating/PieceGenerator.h247
-rw-r--r--src/Globals.h58
-rw-r--r--src/Item.cpp30
-rw-r--r--src/Item.h16
-rw-r--r--src/Items/ItemCake.h41
-rw-r--r--src/Items/ItemHandler.cpp5
-rw-r--r--src/Items/ItemItemFrame.h6
-rw-r--r--src/Items/ItemLighter.h26
-rw-r--r--src/Items/ItemShears.h5
-rw-r--r--src/Items/ItemThrowable.h6
-rw-r--r--src/LightingThread.cpp6
-rw-r--r--src/LineBlockTracer.cpp2
-rw-r--r--src/Log.cpp2
-rw-r--r--src/Log.h4
-rw-r--r--src/MCLogger.h16
-rw-r--r--src/Map.h2
-rw-r--r--src/Matrix4.h224
-rw-r--r--src/Matrix4f.cpp4
-rw-r--r--src/Matrix4f.h225
-rw-r--r--src/MersenneTwister.h10
-rw-r--r--src/MobSpawner.cpp2
-rw-r--r--src/Mobs/Bat.cpp2
-rw-r--r--src/Mobs/Sheep.cpp26
-rw-r--r--src/Mobs/Squid.cpp2
-rw-r--r--src/Noise.cpp8
-rw-r--r--src/OSSupport/BlockingTCPLink.cpp2
-rw-r--r--src/OSSupport/File.h2
-rw-r--r--src/OSSupport/IsThread.h2
-rw-r--r--src/OSSupport/Socket.cpp3
-rw-r--r--src/OSSupport/SocketThreads.cpp2
-rw-r--r--src/Protocol/Protocol125.cpp13
-rw-r--r--src/Protocol/Protocol125.h1
-rw-r--r--src/Protocol/Protocol132.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp89
-rw-r--r--src/Root.cpp10
-rw-r--r--src/Scoreboard.h2
-rw-r--r--src/Server.cpp4
-rw-r--r--src/Simulator/FireSimulator.cpp26
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp2
-rw-r--r--src/Simulator/Simulator.cpp1
-rw-r--r--src/Simulator/Simulator.h2
-rw-r--r--src/StringUtils.cpp7
-rw-r--r--src/StringUtils.h10
-rw-r--r--src/Tracer.cpp4
-rw-r--r--src/Tracer.h3
-rw-r--r--src/UI/Window.cpp2
-rw-r--r--src/Vector3.h286
-rw-r--r--src/Vector3d.cpp77
-rw-r--r--src/Vector3d.h81
-rw-r--r--src/Vector3f.cpp34
-rw-r--r--src/Vector3f.h47
-rw-r--r--src/Vector3i.cpp16
-rw-r--r--src/Vector3i.h45
-rw-r--r--src/WebAdmin.cpp1
-rw-r--r--src/World.cpp33
-rw-r--r--src/World.h7
-rw-r--r--src/WorldStorage/FastNBT.cpp16
-rw-r--r--src/WorldStorage/FastNBT.h2
-rw-r--r--src/WorldStorage/FireworksSerializer.cpp256
-rw-r--r--src/WorldStorage/FireworksSerializer.h92
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp88
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h8
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp23
-rw-r--r--src/WorldStorage/WSSAnvil.cpp186
-rw-r--r--src/WorldStorage/WSSAnvil.h5
-rw-r--r--src/WorldStorage/WSSCompact.cpp13
-rw-r--r--src/WorldStorage/WSSCompact.h2
142 files changed, 3778 insertions, 1172 deletions
diff --git a/.gitignore b/.gitignore
index c8ad93a80..c544f394d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
build/
+nbproject/
ipch/
Win32/
MCServer/MCServer
diff --git a/.travis.yml b/.travis.yml
index c6537cf47..0ab25ae3b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,7 +3,13 @@ compiler:
- gcc
- clang
# Build MCServer
-script: cmake . -DCMAKE_BUILD_TYPE=RELEASE -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | ./MCServer)
+script: cmake . -DBUILD_TOOLS=1 -DSELF_TEST=1 && make -j 2 && cd MCServer/ && (echo stop | $MCSERVER_PATH)
+
+env:
+ - TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
+ - TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug
+ - TRAVIS_MCSERVER_BUILD_TYPE=RELEASE TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer
+ - TRAVIS_MCSERVER_BUILD_TYPE=DEBUG TRAVIS_MCSERVER_FORCE32=1 MCSERVER_PATH=./MCServer_debug
# Notification Settings
notifications:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 05b6d879b..9a860920c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,6 +3,17 @@ cmake_minimum_required (VERSION 2.6)
# 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)
+# These env variables are used for configuring Travis CI builds.
+# See https://github.com/mc-server/MCServer/pull/767
+if(DEFINED ENV{TRAVIS_MCSERVER_BUILD_TYPE})
+ message("Setting build type to $ENV{TRAVIS_MCSERVER_BUILD_TYPE}")
+ set(CMAKE_BUILD_TYPE $ENV{TRAVIS_MCSERVER_BUILD_TYPE})
+endif()
+
+if(DEFINED ENV{TRAVIS_MCSERVER_FORCE32})
+ set(FORCE32 $ENV{TRAVIS_MCSERVER_FORCE32})
+endif()
+
# This has to be done before any flags have been set up.
if(${BUILD_TOOLS})
add_subdirectory(Tools/MCADefrag/)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7ec7058ae..0c36be8b7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,7 +1,7 @@
Code Stuff
----------
- * We use C++03
+ * We use C++03 with some C++11 extensions (ask if you think that something would be useful)
* Use the provided wrappers for OS stuff:
- Threading is done by inheriting from `cIsThread`, thread synchronization through `cCriticalSection`, `cSemaphore` and `cEvent`, file access and filesystem operations through the `cFile` class, high-precision timers through `cTimer`, high-precision sleep through `cSleep`
* No magic numbers, use named constants:
diff --git a/MCServer/.gitignore b/MCServer/.gitignore
index 0fd04ef59..64f062ef7 100644
--- a/MCServer/.gitignore
+++ b/MCServer/.gitignore
@@ -19,10 +19,8 @@ schematics
*.pdb
memdump*
*.grab
-Galleries.cfg
-Galleries.example.cfg
-Galleries.sqlite
-ProtectionAreas.sqlite
+*.cfg
+*.sqlite
helgrind.log
valgrind.log
motd.txt
diff --git a/MCServer/Plugins/@EnableMobDebug.lua b/MCServer/Plugins/@EnableMobDebug.lua
deleted file mode 100644
index 48d4c36b7..000000000
--- a/MCServer/Plugins/@EnableMobDebug.lua
+++ /dev/null
@@ -1,29 +0,0 @@
-
--- @EnableMobDebug.lua
-
--- Enables the MobDebug debugger, used by ZeroBrane Studio, for a plugin
--- Needs to be named with a @ at the start so that it's loaded as the first file of the plugin
-
---[[
-Usage:
-Copy this file to your plugin's folder when you want to debug that plugin
-You should neither check this file into the plugin's version control system,
-nor distribute it in the final release.
---]]
-
-
-
-
-
--- Try to load the debugger, be silent about failures:
-local IsSuccess, MobDebug = pcall(require, "mobdebug")
-if (IsSuccess) then
- MobDebug.start()
-
- -- The debugger will automatically put a breakpoint on this line, use this opportunity to set more breakpoints in your code
- LOG(cPluginManager:GetCurrentPlugin():GetName() .. ": MobDebug enabled")
-end
-
-
-
-
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 1e572492b..c5599b212 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -114,7 +114,7 @@ g_APIDesc =
GetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ", Return = "NIBBLETYPE", Notes = "Returns the skylight at the specified absolute coords" },
GetBlockType = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE", Notes = "Returns the block type at the specified absolute coords" },
GetBlockTypeMeta = { Params = "BlockX, BlockY, BlockZ", Return = "BLOCKTYPE, NIBBLETYPE", Notes = "Returns the block type and meta at the specified absolute coords" },
- GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the objectis currently holding" },
+ GetDataTypes = { Params = "", Return = "number", Notes = "Returns the mask of datatypes that the object is currently holding" },
GetOrigin = { Params = "", Return = "OriginX, OriginY, OriginZ", Notes = "Returns the origin coords of where the area was read from." },
GetOriginX = { Params = "", Return = "number", Notes = "Returns the origin x-coord" },
GetOriginY = { Params = "", Return = "number", Notes = "Returns the origin y-coord" },
@@ -129,6 +129,7 @@ g_APIDesc =
GetSizeY = { Params = "", Return = "number", Notes = "Returns the size of the held data in the y-axis" },
GetSizeZ = { Params = "", Return = "number", Notes = "Returns the size of the held data in the z-axis" },
GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the area - the total number of blocks stored within." },
+ GetWEOffset = { Params = "", Return = "{{Vector3i}}", Notes = "Returns the WE offset, a data value sometimes stored in the schematic files. MCServer doesn't use this value, but provides access to it using this method. The default is {0, 0, 0}."},
HasBlockLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include blocklight" },
HasBlockMetas = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block metas" },
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
@@ -178,6 +179,11 @@ g_APIDesc =
SetRelBlockSkyLight = { Params = "RelBlockX, RelBlockY, RelBlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified relative coords" },
SetRelBlockType = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType", Return = "", Notes = "Sets the block type at the specified relative coords" },
SetRelBlockTypeMeta = { Params = "RelBlockX, RelBlockY, RelBlockZ, BlockType, BlockMeta", Return = "", Notes = "Sets the block type and meta at the specified relative coords" },
+ SetWEOffset =
+ {
+ { Params = "{{Vector3i|Offset}}", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
+ { Params = "OffsetX, OffsetY, OffsetZ", Return = "", Notes = "Sets the WE offset, a data value sometimes stored in the schematic files. Mostly used for WorldEdit. MCServer doesn't use this value, but provides access to it using this method." },
+ },
Write =
{
{ Params = "World, {{Vector3i|MinPoint}}, DataTypes", Return = "bool", Notes = "Writes the area into World at the specified coords, returns true if successful" },
@@ -417,6 +423,7 @@ g_APIDesc =
SetUseDefaultFinish = { Params = "bool", Return = "", Notes = "Sets the chunk to use default finishers or not" },
SetUseDefaultHeight = { Params = "bool", Return = "", Notes = "Sets the chunk to use default height generator or not" },
SetUseDefaultStructures = { Params = "bool", Return = "", Notes = "Sets the chunk to use default structures or not" },
+ UpdateHeightmap = { Params = "", Return = "", Notes = "Updates the heightmap to match current contents. The plugins should do that if they modify the contents and don't modify the heightmap accordingly; MCServer expects (and checks in Debug mode) that the heightmap matches the contents when the cChunkDesc is returned from a plugin." },
WriteBlockArea = { Params = "{{cBlockArea|BlockArea}}, MinRelX, MinRelY, MinRelZ", Return = "", Notes = "Writes data from the block area into the chunk" },
},
AdditionalInfo =
@@ -466,6 +473,7 @@ end
Functions =
{
+ GetLocale = { Params = "", Return = "Locale", Notes = "Returns the locale string that the client sends as part of the protocol handshake. Can be used to provide localized strings." },
GetPing = { Params = "", Return = "number", Notes = "Returns the ping time, in ms" },
GetPlayer = { Params = "", Return = "{{cPlayer|cPlayer}}", Notes = "Returns the player object connected to this client. Note that this may be nil, for example if the player object is not yet spawned." },
GetUniqueID = { Params = "", Return = "number", Notes = "Returns the UniqueID of the client used to identify the client in the server" },
@@ -474,6 +482,7 @@ end
HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." },
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." },
+ SetLocale = { Params = "Locale", Return = "", Notes = "Sets the locale that MCServer keeps on record. Initially the locale is initialized in protocol handshake, this function allows plugins to override the stored value (but only server-side and only until the user disconnects)." },
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." },
@@ -877,7 +886,6 @@ cFile:Delete("/usr/bin/virus.exe");
SetColor = { Return = "" },
GetColor = { Return = "string" },
AddCommand = { Return = "" },
- HasCommand = { Return = "bool" },
AddPermission = { Return = "" },
InheritFrom = { Return = "" },
},
@@ -1144,7 +1152,6 @@ These ItemGrids are available in the API and can be manipulated by the plugins,
IsEnchantable = { Params = "", Return = "bool", Notes = "Returns true if the item is enchantable" },
IsFullStack = { Params = "", Return = "bool", Notes = "Returns true if the item is stacked up to its maximum stacking" },
IsSameType = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is of the same ItemType as the one stored in the object. This is true even if the two items have different enchantments" },
- IsStackableWith = { Params = "cItem", Return = "bool", Notes = "Returns true if the item in the parameter is stackable with the one stored in the object. Two items with different enchantments cannot be stacked" },
IsBothNameAndLoreEmpty = { Params = "", Return = "bool", Notes = "Returns if both the custom name and lore are not set." },
IsCustomNameEmpty = { Params = "", Return = "bool", Notes = "Returns if the custom name of the cItem is empty." },
IsLoreEmpty = { Params = "", Return = "", Notes = "Returns if the lore of the cItem is empty." },
@@ -1650,7 +1657,6 @@ a_Player:OpenWindow(Window);
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 = "(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." },
CloseWindowIfID = { Params = "WindowID, [CanRefuse]", Return = "", Notes = "Closes the currently open UI window if its ID matches the given ID. If CanRefuse is true (default), the window may refuse the closing." },
DeltaExperience = { Params = "DeltaXP", Return = "", Notes = "Adds or removes XP from the current XP amount. Won't allow XP to go negative. Returns the new experience, -1 on error (XP overflow)." },
@@ -1727,7 +1733,6 @@ a_Player:OpenWindow(Window);
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 = "(STATIC) Returns the total amount of XP needed for the specified XP level. Inverse of CalcLevelFromXp()." },
},
Constants =
@@ -1789,13 +1794,13 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
BindCommand =
{
- { Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
- { Params = "Command, Permission, Callback, HelpString", Return = "", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display." },
+ { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
+ { Params = "Command, Permission, Callback, HelpString", Return = "[bool]", Notes = "Binds an in-game command with the specified callback function, permission and help string. By common convention, providing an empty string for HelpString will hide the command from the /help display. Returns true if successful, logs to console and returns no value on error." },
},
BindConsoleCommand =
{
- { Params = "Command, Callback, HelpString", Return = "", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
- { Params = "Command, Callback, HelpString", Return = "", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command." },
+ { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "(STATIC) Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
+ { Params = "Command, Callback, HelpString", Return = "[bool]", Notes = "Binds a console command with the specified callback function and help string. By common convention, providing an empty string for HelpString will hide the command from the \"help\" console command. Returns true if successful, logs to console and returns no value on error." },
},
CallPlugin = { Params = "PluginName, FunctionName, [FunctionArgs...]", Return = "[FunctionRets]", Notes = "(STATIC) Calls the specified function in the specified plugin, passing all the given arguments to it. If it succeeds, it returns all the values returned by that function. If it fails, returns no value at all. Note that only strings, numbers, bools, nils and classes can be used for parameters and return values; tables and functions cannot be copied across plugins." },
DisablePlugin = { Params = "PluginName", Return = "bool", Notes = "Disables a plugin specified by its name. Returns true if the plugin was disabled, false if it wasn't found or wasn't active." },
@@ -2025,8 +2030,9 @@ end
Desc = "This class manages a TNT entity.",
Functions =
{
- GetCounterTime = { Return = "number", Notes = "Returns the time until the entity explodes." },
- GetMaxFuseTime = { Return = "number", Notes = "Returns how long the fuse was." },
+ Explode = { Return = "", Notes = "Explode the tnt." },
+ GetFuseTicks = { Return = "number", Notes = "Returns the fuse ticks until the tnt will explode." },
+ SetFuseTicks = { Return = "number", Notes = "Set the fuse ticks until the tnt will explode." },
},
Inherits = "cEntity",
},
@@ -2261,7 +2267,7 @@ end
SpawnMob = { Params = "X, Y, Z, {{cMonster|MonsterType}}", Return = "EntityID", Notes = "Spawns the specified type of mob at the specified coords. Returns the EntityID of the creates entity, or -1 on failure. " },
SpawnFallingBlock = { Params = "X, Y, Z, BlockType, BlockMeta", Return = "EntityID", Notes = "Spawns an {{cFallingBlock|Falling Block}} entity at the specified coords with the given block type/meta" },
SpawnExperienceOrb = { Params = "X, Y, Z, Reward", Return = "EntityID", Notes = "Spawns an {{cExpOrb|experience orb}} at the specified coords, with the given reward" },
- SpawnPrimedTNT = { Params = "X, Y, Z, FuseTimeSecs, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse time. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
+ SpawnPrimedTNT = { Params = "X, Y, Z, FuseTicks, InitialVelocityCoeff", Return = "", Notes = "Spawns a {{cTNTEntity|primed TNT entity}} at the specified coords, with the given fuse ticks. The entity gets a random speed multiplied by the InitialVelocityCoeff, 1 being the default value." },
TryGetHeight = { Params = "BlockX, BlockZ", Return = "IsValid, Height", Notes = "Returns true and height of the highest non-air block if the chunk is loaded, or false otherwise." },
UpdateSign = { Params = "X, Y, Z, Line1, Line2, Line3, Line4, [{{cPlayer|Player}}]", Return = "", Notes = "Sets the sign text at the specified coords. The sign-updating hooks are called for the change. The Player parameter is used to indicate the player from whom the change has come, it may be nil. Same as SetSignLiens()" },
UseBlockEntity = { Params = "{{cPlayer|Player}}, BlockX, BlockY, BlockZ", Return = "", Notes = "Makes the specified Player use the block entity at the specified coords (open chest UI, etc.) If the cords are in an unloaded chunk or there's no block entity, ignores the call." },
@@ -2623,7 +2629,8 @@ end
]],
Functions =
{
- AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFace|face}}"},
+ AddFaceDirection = {Params = "BlockX, BlockY, BlockZ, BlockFace, [IsInverse]", Return = "BlockX, BlockY, BlockZ", Notes = "Returns the coords of a block adjacent to the specified block through the specified {{Globals#BlockFaces|face}}"},
+ BlockFaceToString = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "string", Notes = "Returns the string representation of the {{Globals#BlockFaces|eBlockFace}} constant. Uses the axis-direction-based names, such as BLOCK_FACE_XP." },
BlockStringToType = {Params = "BlockTypeString", Return = "BLOCKTYPE", Notes = "Returns the block type parsed from the given string"},
ClickActionToString = {Params = "{{Globals#ClickAction|ClickAction}}", Return = "string", Notes = "Returns a string description of the ClickAction enumerated value"},
DamageTypeToString = {Params = "{{Globals#DamageType|DamageType}}", Return = "string", Notes = "Converts the {{Globals#DamageType|DamageType}} enumerated value to a string representation "},
@@ -2642,9 +2649,12 @@ end
LOGINFO = {Params = "string", Notes = "Logs a text into the server console using 'info' severity (yellow text)"},
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)"},
+ MirrorBlockFaceY = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after mirroring it around the Y axis (or rotating 180 degrees around it)." },
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"},
+ RotateBlockFaceCCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees counter-clockwise." },
+ RotateBlockFaceCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees clockwise." },
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)"},
StringToBiome = {Params = "string", Return = "{{Globals#BiomeTypes|BiomeType}}", Notes = "Converts a string representation to a {{Globals#BiomeTypes|BiomeType}} enumerated value"},
@@ -2691,7 +2701,13 @@ end
Include = "^BLOCK_FACE_.*",
TextBefore = [[
These constants are used to describe individual faces of the block. They are used when the
- client is interacting with a block, or when the {{cLineBlockTracer}} hits a block, etc.
+ client is interacting with a block in the {{OnPlayerBreakingBlock|HOOK_PLAYER_BREAKING_BLOCK}},
+ {{OnPlayerBrokenBlock|HOOK_PLAYER_BROKEN_BLOCK}}, {{OnPlayerLeftClick|HOOK_PLAYER_LEFT_CLICK}},
+ {{OnPlayerPlacedBlock|HOOK_PLAYER_PLACED_BLOCK}}, {{OnPlayerPlacingBlock|HOOK_PLAYER_PLACING_BLOCK}},
+ {{OnPlayerRightClick|HOOK_PLAYER_RIGHT_CLICK}}, {{OnPlayerUsedBlock|HOOK_PLAYER_USED_BLOCK}},
+ {{OnPlayerUsedItem|HOOK_PLAYER_USED_ITEM}}, {{OnPlayerUsingBlock|HOOK_PLAYER_USING_BLOCK}},
+ and {{OnPlayerUsingItem|HOOK_PLAYER_USING_ITEM}} hooks, or when the {{cLineBlockTracer}} hits a
+ block, etc.
]],
},
ClickAction =
diff --git a/MCServer/Plugins/APIDump/Classes/Geometry.lua b/MCServer/Plugins/APIDump/Classes/Geometry.lua
index e83d6e4b1..9887bfb89 100644
--- a/MCServer/Plugins/APIDump/Classes/Geometry.lua
+++ b/MCServer/Plugins/APIDump/Classes/Geometry.lua
@@ -53,7 +53,7 @@ return
{
Desc = [[
cCuboid offers some native support for integral-boundary cuboids. A cuboid internally consists of
- two {{Vector3i}}s. By default the cuboid doesn't make any assumptions about the defining points,
+ two {{Vector3i}}-s. By default the cuboid doesn't make any assumptions about the defining points,
but for most of the operations in the cCuboid class, the p1 member variable is expected to be the
minima and the p2 variable the maxima. The Sort() function guarantees this condition.</p>
<p>
@@ -63,12 +63,17 @@ return
{
constructor =
{
- { Params = "OtheCuboid", Return = "cCuboid", Notes = "Creates a new Cuboid object as a copy of OtherCuboid" },
+ { Params = "", Return = "cCuboid", Notes = "Creates a new Cuboid object with all-zero coords" },
+ { Params = "OtherCuboid", Return = "cCuboid", Notes = "Creates a new Cuboid object as a copy of OtherCuboid" },
{ Params = "{{Vector3i|Point1}}, {{Vector3i|Point2}}", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
{ Params = "X, Y, Z", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified point as both its corners (the cuboid has a size of 1 in each direction)." },
{ Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "cCuboid", Notes = "Creates a new Cuboid object with the specified points as its corners." },
},
- Assign = { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "", Notes = "Assigns all the coords stored in the cuboid. Sort-state is ignored." },
+ Assign =
+ {
+ { Params = "SrcCuboid", Return = "", Notes = "Copies all the coords from the src cuboid to this cuboid. Sort-state is ignored." },
+ { Params = "X1, Y1, Z1, X2, Y2, Z2", Return = "", Notes = "Assigns all the coords to the specified values. Sort-state is ignored." },
+ },
ClampX = { Params = "MinX, MaxX", Return = "", Notes = "Clamps both X coords into the range provided. Sortedness-agnostic." },
ClampY = { Params = "MinY, MaxY", Return = "", Notes = "Clamps both Y coords into the range provided. Sortedness-agnostic." },
ClampZ = { Params = "MinZ, MaxZ", Return = "", Notes = "Clamps both Z coords into the range provided. Sortedness-agnostic." },
@@ -76,6 +81,7 @@ return
DifY = { Params = "", Return = "number", Notes = "Returns the difference between the two Y coords (Y-size minus 1). Assumes sorted." },
DifZ = { Params = "", Return = "number", Notes = "Returns the difference between the two Z coords (Z-size minus 1). Assumes sorted." },
DoesIntersect = { Params = "OtherCuboid", Return = "bool", Notes = "Returns true if this cuboid has at least one voxel in common with OtherCuboid. Note that edges are considered inclusive. Assumes both sorted." },
+ Engulf = { Params = "{{Vector3i|Point}}", Return = "", Notes = "If needed, expands the cuboid to include the specified point. Doesn't shrink. Assumes sorted. " },
Expand = { Params = "SubMinX, AddMaxX, SubMinY, AddMaxY, SubMinZ, AddMaxZ", Return = "", Notes = "Expands the cuboid by the specified amount in each direction. Works on unsorted cuboids as well. NOTE: this function doesn't check for underflows." },
GetVolume = { Params = "", Return = "number", Notes = "Returns the volume of the cuboid, in blocks. Note that the volume considers both coords inclusive. Works on unsorted cuboids, too." },
IsCompletelyInside = { Params = "OuterCuboid", Return = "bool", Notes = "Returns true if this cuboid is completely inside (in all directions) in OuterCuboid. Assumes both sorted." },
@@ -308,6 +314,7 @@ end
},
Equals = { Params = "Vector3i", Return = "bool", Notes = "Returns true if this vector is exactly the same as the specified vector." },
Length = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector." },
+ Move = { Params = "X, Y, Z", Return = "", Notes = "Moves the vector by the specified amount in each axis direction." },
Set = { Params = "x, y, z", Return = "", Notes = "Sets all the coords of the vector at once" },
SqrLength = { Params = "", Return = "number", Notes = "Returns the (euclidean) length of this vector, squared. This operation is slightly less computationally expensive than Length(), while it conserves some properties of Length(), such as comparison." },
},
diff --git a/MCServer/Plugins/APIDump/main_APIDump.lua b/MCServer/Plugins/APIDump/main_APIDump.lua
index bd509dcb6..4ed692b52 100644
--- a/MCServer/Plugins/APIDump/main_APIDump.lua
+++ b/MCServer/Plugins/APIDump/main_APIDump.lua
@@ -9,22 +9,6 @@
-- Global variables:
g_Plugin = nil;
g_PluginFolder = "";
-g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
-g_Stats = -- Statistics about the documentation
-{
- NumTotalClasses = 0,
- NumUndocumentedClasses = 0,
- NumTotalFunctions = 0,
- NumUndocumentedFunctions = 0,
- NumTotalConstants = 0,
- NumUndocumentedConstants = 0,
- NumTotalVariables = 0,
- NumUndocumentedVariables = 0,
- NumTotalHooks = 0,
- NumUndocumentedHooks = 0,
- NumTrackedLinks = 0,
- NumInvalidLinks = 0,
-}
@@ -33,15 +17,35 @@ g_Stats = -- Statistics about the documentation
function Initialize(Plugin)
g_Plugin = Plugin;
-
- Plugin:SetName("APIDump");
- Plugin:SetVersion(1);
+ g_PluginFolder = Plugin:GetLocalFolder();
LOG("Initialising " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
- g_PluginFolder = Plugin:GetLocalFolder();
+ cPluginManager:BindConsoleCommand("api", HandleCmdApi, "Dumps the Lua API docs into the API/ subfolder")
+ g_Plugin:AddWebTab("APIDump", HandleWebAdminDump)
+ -- TODO: Add a WebAdmin tab that has a Dump button
+ return true
+end
+
+
+
+
+
+function HandleCmdApi(a_Split)
+ DumpApi()
+ return true
+end
+
+
+
+
+
+function DumpApi()
+ LOG("Dumping the API...")
-- Load the API descriptions from the Classes and Hooks subfolders:
+ -- This needs to be done each time the command is invoked because the export modifies the tables' contents
+ dofile(g_PluginFolder .. "/APIDesc.lua")
if (g_APIDesc.Classes == nil) then
g_APIDesc.Classes = {};
end
@@ -51,6 +55,24 @@ function Initialize(Plugin)
LoadAPIFiles("/Classes/", g_APIDesc.Classes);
LoadAPIFiles("/Hooks/", g_APIDesc.Hooks);
+ -- Reset the stats:
+ g_TrackedPages = {}; -- List of tracked pages, to be checked later whether they exist. Each item is an array of referring pagenames.
+ g_Stats = -- Statistics about the documentation
+ {
+ NumTotalClasses = 0,
+ NumUndocumentedClasses = 0,
+ NumTotalFunctions = 0,
+ NumUndocumentedFunctions = 0,
+ NumTotalConstants = 0,
+ NumUndocumentedConstants = 0,
+ NumTotalVariables = 0,
+ NumUndocumentedVariables = 0,
+ NumTotalHooks = 0,
+ NumUndocumentedHooks = 0,
+ NumTrackedLinks = 0,
+ NumInvalidLinks = 0,
+ }
+
-- dump all available API functions and objects:
-- DumpAPITxt();
@@ -58,7 +80,6 @@ function Initialize(Plugin)
DumpAPIHtml();
LOG("APIDump finished");
-
return true
end
@@ -67,6 +88,9 @@ end
function LoadAPIFiles(a_Folder, a_DstTable)
+ assert(type(a_Folder) == "string")
+ assert(type(a_DstTable) == "table")
+
local Folder = g_PluginFolder .. a_Folder;
for idx, fnam in ipairs(cFile:GetFolderContents(Folder)) do
local FileName = Folder .. fnam;
@@ -317,6 +341,11 @@ end
function DumpAPIHtml()
LOG("Dumping all available functions and constants to API subfolder...");
+ -- Create the output folder
+ if not(cFile:IsFolder("API")) then
+ cFile:CreateFolder("API");
+ end
+
LOG("Copying static files..");
cFile:CreateFolder("API/Static");
local localFolder = g_Plugin:GetLocalFolder();
@@ -366,11 +395,6 @@ function DumpAPIHtml()
ReadDescriptions(API);
ReadHooks(Hooks);
- -- Create the output folder
- if not(cFile:IsFolder("API")) then
- cFile:CreateFolder("API");
- end
-
-- Create a "class index" file, write each class as a link to that file,
-- then dump class contents into class-specific file
LOG("Writing HTML files...");
@@ -1428,3 +1452,18 @@ end
+
+function HandleWebAdminDump(a_Request)
+ if (a_Request.PostParams["Dump"] ~= nil) then
+ DumpApi()
+ end
+ return
+ [[
+ <p>Pressing the button will generate the API dump on the server. Note that this can take some time.</p>
+ <form method="POST"><input type="submit" name="Dump" value="Dump the API"/></form>
+ ]]
+end
+
+
+
+
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index f99c48242..d2c9a2a49 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -56,7 +56,8 @@ function Initialize(Plugin)
PM:BindCommand("/sched", "debuggers", HandleSched, "- Schedules a simple countdown using cWorld:ScheduleTask()");
PM:BindCommand("/cs", "debuggers", HandleChunkStay, "- Tests the ChunkStay Lua integration for the specified chunk coords");
PM:BindCommand("/compo", "debuggers", HandleCompo, "- Tests the cCompositeChat bindings")
- PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one");
+ PM:BindCommand("/sb", "debuggers", HandleSetBiome, "- Sets the biome around you to the specified one")
+ PM:BindCommand("/wesel", "debuggers", HandleWESel, "- Expands the current WE selection by 1 block in X/Z")
Plugin:AddWebTab("Debuggers", HandleRequest_Debuggers)
Plugin:AddWebTab("StressTest", HandleRequest_StressTest)
@@ -1298,6 +1299,43 @@ end
+function HandleWESel(a_Split, a_Player)
+ -- Check if the selection is a cuboid:
+ local IsCuboid = cPluginManager:CallPlugin("WorldEdit", "IsPlayerSelectionCuboid")
+ if (IsCuboid == nil) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit is not loaded"))
+ return true
+ elseif (IsCuboid == false) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, the selection is not a cuboid"))
+ return true
+ end
+
+ -- Get the selection:
+ local SelCuboid = cCuboid()
+ local IsSuccess = cPluginManager:CallPlugin("WorldEdit", "GetPlayerCuboidSelection", a_Player, SelCuboid)
+ if not(IsSuccess) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit reported failure while getting current selection"))
+ return true
+ end
+
+ -- Adjust the selection:
+ local NumBlocks = tonumber(a_Split[2] or "1") or 1
+ SelCuboid:Expand(NumBlocks, NumBlocks, 0, 0, NumBlocks, NumBlocks)
+
+ -- Set the selection:
+ local IsSuccess = cPluginManager:CallPlugin("WorldEdit", "SetPlayerCuboidSelection", a_Player, SelCuboid)
+ if not(IsSuccess) then
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtFailure):AddTextPart("Cannot adjust selection, WorldEdit reported failure while setting new selection"))
+ return true
+ end
+ a_Player:SendMessage(cCompositeChat():SetMessageType(mtInformation):AddTextPart("Successfully adjusted the selection by " .. NumBlocks .. " block(s)"))
+ return true
+end
+
+
+
+
+
function OnPlayerJoined(a_Player)
-- Test composite chat chaining:
a_Player:SendMessage(cCompositeChat()
diff --git a/MCServer/Plugins/InfoReg.lua b/MCServer/Plugins/InfoReg.lua
index 1cf68dbed..b3717884a 100644
--- a/MCServer/Plugins/InfoReg.lua
+++ b/MCServer/Plugins/InfoReg.lua
@@ -59,13 +59,13 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
return true;
end
- -- Check if the handler is valid:
+ -- If the handler is not valid, check the next sublevel:
if (Subcommand.Handler == nil) then
if (Subcommand.Subcommands == nil) then
LOG("Cannot find handler for command " .. a_CmdString .. " " .. Verb);
return false;
end
- ListSubcommands(a_Player, Subcommand.Subcommands, a_CmdString .. " " .. Verb);
+ MultiCommandHandler(a_Split, a_Player, a_CmdString .. " " .. Verb, Subcommand, a_Level + 1);
return true;
end
diff --git a/MCServer/crafting.txt b/MCServer/crafting.txt
index 92abe24cb..60cda0673 100644
--- a/MCServer/crafting.txt
+++ b/MCServer/crafting.txt
@@ -39,6 +39,7 @@
#
# Need to list each of the four log types, otherwise all logs would get converted into apple planks (^0)
+
ApplePlanks, 4 = AppleLog, *
ConiferPlanks, 4 = ConiferLog, *
BirchPlanks, 4 = BirchLog, *
@@ -434,6 +435,55 @@ GoldNugget, 9 = GoldIngot, *
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
-
-
-
+#******************************************************#
+# Fireworks & Co.
+# (Best not to add non-vanilla items to this as it will cause internal firework data handling code to log warnings)
+
+# Ballistic firework rockets - plain and with firework star, all with 1 - 3 gunpowder
+FireworkRocket = Paper, * | Gunpowder, *
+FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, *
+FireworkRocket = Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
+FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, *
+FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, *
+FireworkRocket = FireworkStar, * | Paper, * | Gunpowder, * | Gunpowder, * | Gunpowder, *
+
+# Radioactive firework stars
+# Plain powder and dye
+FireworkStar = Gunpowder, * | Dye ^-1, *
+
+# Powder and effect, with effect combining
+FireworkStar = Gunpowder, * | Dye ^-1, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Glowdust, * | Diamond, *
+
+# Powder and shape (no shape combining possible)
+FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, *
+
+# Power and shape (no shape combining possible), combined with effect
+FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, *
+
+# Power and shape (no shape combining possible), combined with effect (with effect combining)
+FireworkStar = Gunpowder, * | Dye ^-1, * | Firecharge, * | Glowdust, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Goldnugget, * | Glowdust, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | Feather, * | Glowdust, * | Diamond, *
+FireworkStar = Gunpowder, * | Dye ^-1, * | SkeletonHead ^-1, * | Glowdust, * | Diamond, *
+
+# Star fade colour-change
+FireworkStar = FireworkStar, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
+FireworkStar = FireworkStar, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, * | Dye ^-1, *
diff --git a/SetFlags.cmake b/SetFlags.cmake
index 6a8211fa2..b786da0d0 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -182,14 +182,23 @@ macro(set_exe_flags)
string(REPLACE "-w" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
- add_flags_cxx("-Wall -Wextra")
+ add_flags_cxx("-Wall -Wextra -Wno-unused-parameter -Wno-error=switch")
# we support non-IEEE 754 fpus so can make no guarentees about error
add_flags_cxx("-ffast-math")
- # clang does not provide the __extern_always_inline macro and a part of libm depends on this when using fast-math
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # clang does not provide the __extern_always_inline macro and a part of libm depends on this when using fast-math
add_flags_cxx("-D__extern_always_inline=inline")
+ add_flags_cxx("-Werror -Weverything -Wno-c++98-compat-pedantic -Wno-string-conversion")
+ add_flags_cxx("-Wno-extra-semi -Wno-error=switch-enum -Wno-documentation")
+ add_flags_cxx("-Wno-error=sign-conversion -Wno-error=conversion -Wno-padded")
+ add_flags_cxx("-Wno-error=deprecated -Wno-error=weak-vtables -Wno-error=float-equal")
+ add_flags_cxx("-Wno-error=missing-prototypes -Wno-error=non-virtual-dtor")
+ add_flags_cxx("-Wno-error=covered-switch-default -Wno-error=shadow")
+ add_flags_cxx("-Wno-error=exit-time-destructors -Wno-error=missing-variable-declarations")
+ add_flags_cxx("-Wno-error=global-constructors -Wno-implicit-fallthrough")
+ add_flags_cxx("-Wno-error=unreachable-code")
endif()
endif()
diff --git a/Tools/MCADefrag/Globals.h b/Tools/MCADefrag/Globals.h
index 6f4bbdc76..0f31de7e3 100644
--- a/Tools/MCADefrag/Globals.h
+++ b/Tools/MCADefrag/Globals.h
@@ -37,7 +37,8 @@
// Some portability macros :)
#define stricmp strcasecmp
-
+
+ #define FORMATSTRING(formatIndex,va_argsIndex)
#else
#error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler"
@@ -58,6 +59,8 @@
#define ALIGN_8
#define ALIGN_16
*/
+
+ #define FORMATSTRING(formatIndex,va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
#endif
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp
index 91d2fc42f..46119ff42 100644
--- a/Tools/ProtoProxy/Connection.cpp
+++ b/Tools/ProtoProxy/Connection.cpp
@@ -131,8 +131,6 @@
} \
}
-
-#define MAX_ENC_LEN 1024
@@ -473,14 +471,14 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
-bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, int a_Size, const char * a_Peer)
+bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
{
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
const Byte * Data = (const Byte *)a_Data;
while (a_Size > 0)
{
Byte Buffer[64 KiB];
- int NumBytes = (a_Size > sizeof(Buffer)) ? sizeof(Buffer) : a_Size;
+ size_t NumBytes = (a_Size > sizeof(Buffer)) ? sizeof(Buffer) : a_Size;
a_Encryptor.ProcessData(Buffer, Data, NumBytes);
bool res = SendData(a_Socket, (const char *)Buffer, NumBytes, a_Peer);
if (!res)
@@ -2263,7 +2261,9 @@ bool cConnection::HandleServerSpawnObjectVehicle(void)
HANDLE_SERVER_PACKET_READ(ReadByte, Byte, Yaw);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, DataIndicator);
AString ExtraData;
- short VelocityX, VelocityY, VelocityZ;
+ short VelocityX = 0;
+ short VelocityY = 0;
+ short VelocityZ = 0;
if (DataIndicator != 0)
{
HANDLE_SERVER_PACKET_READ(ReadBEShort, short, SpeedX);
@@ -2697,7 +2697,7 @@ bool cConnection::ParseMetadata(cByteBuffer & a_Buffer, AString & a_Metadata)
a_Metadata.push_back(x);
while (x != 0x7f)
{
- int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
+ // int Index = ((unsigned)((unsigned char)x)) & 0x1f; // Lower 5 bits = index
int Type = ((unsigned)((unsigned char)x)) >> 5; // Upper 3 bits = type
int Length = 0;
switch (Type)
@@ -2772,7 +2772,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
{
int Index = ((unsigned)((unsigned char)a_Metadata[pos])) & 0x1f; // Lower 5 bits = index
int Type = ((unsigned)((unsigned char)a_Metadata[pos])) >> 5; // Upper 3 bits = type
- int Length = 0;
+ // int Length = 0;
switch (Type)
{
case 0:
@@ -2827,7 +2827,7 @@ void cConnection::LogMetadata(const AString & a_Metadata, size_t a_IndentCount)
ASSERT(!"Cannot parse item description from metadata");
return;
}
- int After = bb.GetReadableSpace();
+ // int After = bb.GetReadableSpace();
int BytesConsumed = BytesLeft - bb.GetReadableSpace();
Log("%sslot[%d] = %s (%d bytes)", Indent.c_str(), Index, ItemDesc.c_str(), BytesConsumed);
diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h
index 5e4f8cd7b..70b759d0f 100644
--- a/Tools/ProtoProxy/Connection.h
+++ b/Tools/ProtoProxy/Connection.h
@@ -109,7 +109,7 @@ protected:
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
- bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, int a_Size, const char * a_Peer);
+ bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h
index 547903e7a..0724d3a52 100644
--- a/Tools/ProtoProxy/Globals.h
+++ b/Tools/ProtoProxy/Globals.h
@@ -37,6 +37,8 @@
// Some portability macros :)
#define stricmp strcasecmp
+
+ #define FORMATSTRING(formatIndex,va_argsIndex)
#else
@@ -59,6 +61,9 @@
#define ALIGN_16
*/
+ #define FORMATSTRING(formatIndex,va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
+
+
#endif
@@ -233,4 +238,4 @@ public:
#define LOGERROR printf
#define LOGINFO printf
-#define LOGWARNING printf \ No newline at end of file
+#define LOGWARNING printf
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 2676281f9..1cd7c74f8 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -11,6 +11,7 @@ typedef unsigned int UInt32;
typedef unsigned short UInt16;
+$cfile "../Vector3.h"
$cfile "../ChunkDef.h"
$cfile "../BiomeDef.h"
@@ -62,10 +63,6 @@ $cfile "../BlockEntities/MobHeadEntity.h"
$cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h"
$cfile "../Root.h"
-$cfile "../Vector3f.h"
-$cfile "../Vector3d.h"
-$cfile "../Vector3i.h"
-$cfile "../Matrix4f.h"
$cfile "../Cuboid.h"
$cfile "../BoundingBox.h"
$cfile "../Tracer.h"
@@ -97,4 +94,10 @@ typedef unsigned char Byte;
+// Aliases
+$renaming Vector3<double> @ Vector3d
+$renaming Vector3<float> @ Vector3f
+$renaming Vector3<int> @ Vector3i
+
+
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index aa6ee05b3..f24e15c3b 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -94,12 +94,20 @@ void cLuaState::Create(void)
}
m_LuaState = lua_open();
luaL_openlibs(m_LuaState);
+ m_IsOwned = true;
+}
+
+
+
+
+
+void cLuaState::RegisterAPILibs(void)
+{
tolua_AllToLua_open(m_LuaState);
ManualBindings::Bind(m_LuaState);
DeprecatedBindings::Bind(m_LuaState);
luaopen_lsqlite3(m_LuaState);
luaopen_lxp(m_LuaState);
- m_IsOwned = true;
}
@@ -734,10 +742,6 @@ void cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{
a_Value.assign(data, len);
}
- else
- {
- a_Value.clear();
- }
}
@@ -1281,7 +1285,9 @@ void cLuaState::LogStack(lua_State * a_LuaState, const char * a_Header)
{
UNUSED(a_Header); // The param seems unused when compiling for release, so the compiler warns
- LOGD((a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
+
+ // Format string consisting only of %s is used to appease the compiler
+ LOGD("%s",(a_Header != NULL) ? a_Header : "Lua C API Stack contents:");
for (int i = lua_gettop(a_LuaState); i > 0; i--)
{
AString Value;
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 4a7a6fadb..f5cb8379d 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -29,6 +29,8 @@ extern "C"
#include "lua/src/lauxlib.h"
}
+#include "../Vector3.h"
+
@@ -52,7 +54,6 @@ class cWebAdmin;
struct HTTPTemplateRequest;
class cTNTEntity;
class cCreeper;
-class Vector3i;
class cHopperEntity;
class cBlockEntity;
@@ -139,9 +140,14 @@ public:
/** Allows this object to be used in the same way as a lua_State *, for example in the LuaLib functions */
operator lua_State * (void) { return m_LuaState; }
- /** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor */
+ /** Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor.
+ The regular Lua libs are registered, but the MCS API is not registered (so that Lua can be used as
+ lite-config as well), use RegisterAPILibs() to do that. */
void Create(void);
+ /** Registers all the API libraries that MCS provides into m_LuaState. */
+ void RegisterAPILibs(void);
+
/** Closes the m_LuaState, if not closed already */
void Close(void);
@@ -194,7 +200,7 @@ public:
void Push(const HTTPTemplateRequest * a_Request);
void Push(cTNTEntity * a_TNTEntity);
void Push(Vector3i * a_Vector);
- void Push(void * a_Ptr);
+ NORETURNDEBUG void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity);
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index a5247bbe6..20bbc48f2 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -1497,7 +1497,8 @@ static int tolua_cPluginManager_BindCommand(lua_State * L)
}
Plugin->BindCommand(Command, FnRef);
- return 0;
+ lua_pushboolean(L, true);
+ return 1;
}
@@ -1521,7 +1522,10 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
// Read the arguments to this API call:
tolua_Error tolua_err;
int idx = 1;
- if (tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err))
+ if (
+ tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err) ||
+ tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
+ )
{
idx++;
}
@@ -1561,7 +1565,8 @@ static int tolua_cPluginManager_BindConsoleCommand(lua_State * L)
}
Plugin->BindConsoleCommand(Command, FnRef);
- return 0;
+ lua_pushboolean(L, true);
+ return 1;
}
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 45c8216be..cccbc3c93 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -75,6 +75,7 @@ bool cPluginLua::Initialize(void)
if (!m_LuaState.IsValid())
{
m_LuaState.Create();
+ m_LuaState.RegisterAPILibs();
// Inject the identification global variables into the state:
lua_pushlightuserdata(m_LuaState, this);
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index c7df6357e..b9cf160c4 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -248,7 +248,7 @@ bool cPluginManager::CallHookChat(cPlayer * a_Player, AString & a_Message)
{
AStringVector Split(StringSplit(a_Message, " "));
ASSERT(!Split.empty()); // This should not happen - we know there's at least one char in the message so the split needs to be at least one item long
- a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", Split[0].c_str()));
+ a_Player->SendMessageInfo(Printf("Unknown command: \"%s\"", a_Message.c_str()));
LOGINFO("Player %s issued an unknown command: \"%s\"", a_Player->GetName().c_str(), a_Message.c_str());
return true; // Cancel sending
}
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index d07ef747a..406e18a3b 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -168,6 +168,7 @@ cBlockArea::cBlockArea(void) :
m_SizeX(0),
m_SizeY(0),
m_SizeZ(0),
+ m_WEOffset(0, 0, 0),
m_BlockTypes(NULL),
m_BlockMetas(NULL),
m_BlockLight(NULL),
@@ -254,6 +255,24 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
+void cBlockArea::SetWEOffset(int a_OffsetX, int a_OffsetY, int a_OffsetZ)
+{
+ m_WEOffset.Set(a_OffsetX, a_OffsetY, a_OffsetZ);
+}
+
+
+
+
+
+void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
+{
+ m_WEOffset.Set(a_Offset.x, a_Offset.y, a_Offset.z);
+}
+
+
+
+
+
void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
{
m_OriginX = a_OriginX;
diff --git a/src/BlockArea.h b/src/BlockArea.h
index 0703f195e..e0e8fe972 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -13,13 +13,13 @@
#pragma once
#include "ForEachChunkProvider.h"
+#include "Vector3.h"
// fwd:
class cCuboid;
-class Vector3i;
@@ -209,6 +209,8 @@ public:
void SetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockLight);
void SetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_BlockSkyLight);
void SetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockSkyLight);
+ void SetWEOffset (int a_OffsetX, int a_OffsetY, int a_OffsetZ);
+ void SetWEOffset (const Vector3i & a_Offset);
// Getters:
BLOCKTYPE GetRelBlockType (int a_RelX, int a_RelY, int a_RelZ) const;
@@ -219,6 +221,7 @@ public:
NIBBLETYPE GetBlockLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
NIBBLETYPE GetRelBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ) const;
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ) const;
+ const Vector3i & GetWEOffset (void) const {return m_WEOffset;}
void SetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
@@ -299,6 +302,10 @@ protected:
int m_SizeY;
int m_SizeZ;
+ /** An extra data value sometimes stored in the .schematic file. Used mainly by the WorldEdit plugin.
+ cBlockArea doesn't use this value in any way. */
+ Vector3i m_WEOffset;
+
BLOCKTYPE * m_BlockTypes;
NIBBLETYPE * m_BlockMetas; // Each meta is stored as a separate byte for faster access
NIBBLETYPE * m_BlockLight; // Each light value is stored as a separate byte for faster access
diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp
index 374f3d6e3..e03bf776d 100644
--- a/src/BlockEntities/DispenserEntity.cpp
+++ b/src/BlockEntities/DispenserEntity.cpp
@@ -116,7 +116,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
{
double TNTX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double TNTZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
- m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 4, 0); // 4 seconds fuse, no initial velocity
+ m_World->SpawnPrimedTNT(TNTX, DispY + 0.5, TNTZ, 80, 0); // 80 ticks fuse, no initial velocity
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}
break;
@@ -138,6 +138,12 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
break;
}
+ case E_ITEM_FIRE_CHARGE:
+ {
+ // TODO: Spawn fireball entity
+ break;
+ }
+
default:
{
DropFromSlot(a_Chunk, a_SlotNum);
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index d1ecfdf7e..7d438ba3e 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -93,6 +93,7 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_IRON_BARS ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_IRON_DOOR ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_LEAVES ].m_SpreadLightFalloff = 1;
+ ms_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
ms_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h
new file mode 100644
index 000000000..9f5f84be0
--- /dev/null
+++ b/src/Blocks/BlockAnvil.h
@@ -0,0 +1,63 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+class cBlockAnvilHandler :
+ public cBlockHandler
+{
+public:
+ cBlockAnvilHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2));
+ }
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = m_BlockType;
+
+ int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3;
+ int RawMeta = a_BlockMeta >> 2;
+
+ Direction++;
+ Direction %= 4;
+ switch (Direction)
+ {
+ case 0: a_BlockMeta = 0x2 | RawMeta << 2; break;
+ case 1: a_BlockMeta = 0x3 | RawMeta << 2; break;
+ case 2: a_BlockMeta = 0x0 | RawMeta << 2; break;
+ case 3: a_BlockMeta = 0x1 | RawMeta << 2; break;
+ default:
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ virtual bool IsUseable() override
+ {
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockCake.h b/src/Blocks/BlockCake.h
new file mode 100644
index 000000000..36e133388
--- /dev/null
+++ b/src/Blocks/BlockCake.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockCakeHandler :
+ public cBlockHandler
+{
+public:
+ cBlockCakeHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
+ {
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (!a_Player->Feed(2, 0.1))
+ {
+ return;
+ }
+
+ if (Meta >= 5)
+ {
+ a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
+ }
+ else
+ {
+ a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta + 1);
+ }
+ }
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ // Give nothing
+ }
+
+ virtual bool IsUseable(void) override
+ {
+ return true;
+ }
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.cloth";
+ }
+} ;
+
+
+
+
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index aa97b2ca9..4f74e2f45 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -6,10 +6,12 @@
#include "../Root.h"
#include "../Bindings/PluginManager.h"
#include "../Chunk.h"
+#include "BlockAnvil.h"
#include "BlockBed.h"
#include "BlockBrewingStand.h"
#include "BlockButton.h"
#include "BlockCactus.h"
+#include "BlockCake.h"
#include "BlockCarpet.h"
#include "BlockCauldron.h"
#include "BlockChest.h"
@@ -85,12 +87,14 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
// Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
+ case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType);
case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType);
case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_BROWN_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_CACTUS: return new cBlockCactusHandler (a_BlockType);
+ case E_BLOCK_CAKE: return new cBlockCakeHandler (a_BlockType);
case E_BLOCK_CARROTS: return new cBlockCropsHandler (a_BlockType);
case E_BLOCK_CARPET: return new cBlockCarpetHandler (a_BlockType);
case E_BLOCK_CAULDRON: return new cBlockCauldronHandler (a_BlockType);
diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h
index 7b8f0b378..a6d3373c1 100644
--- a/src/Blocks/BlockLeaves.h
+++ b/src/Blocks/BlockLeaves.h
@@ -16,6 +16,7 @@
{ \
case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \
case E_BLOCK_LOG: return true; \
+ case E_BLOCK_NEW_LOG: return true; \
}
bool HasNearLog(cBlockArea &a_Area, int a_BlockX, int a_BlockY, int a_BlockZ);
diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h
index 623cfda64..c30c1a401 100644
--- a/src/Blocks/BlockMushroom.h
+++ b/src/Blocks/BlockMushroom.h
@@ -39,6 +39,7 @@ public:
case E_BLOCK_CACTUS:
case E_BLOCK_ICE:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
case E_BLOCK_AIR:
{
return false;
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index 708583e70..8041d9359 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -73,7 +73,7 @@ public:
/// Returns true if the specified block type is good for vines to attach to
static bool IsBlockAttachable(BLOCKTYPE a_BlockType)
{
- return (a_BlockType == E_BLOCK_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
+ return (a_BlockType == E_BLOCK_LEAVES) || (a_BlockType == E_BLOCK_NEW_LEAVES) || cBlockInfo::IsSolid(a_BlockType);
}
diff --git a/src/Blocks/MetaRotater.h b/src/Blocks/MetaRotater.h
index d3664b6f1..dde88e6db 100644
--- a/src/Blocks/MetaRotater.h
+++ b/src/Blocks/MetaRotater.h
@@ -4,6 +4,15 @@
#pragma once
+// MSVC generates warnings for the templated AssertIfNotMatched parameter conditions, so disable it:
+#ifdef _MSC_VER
+ #pragma warning(disable: 4127) // Conditional expression is constant
+#endif
+
+
+
+
+
/*
Provides a mixin for rotations and reflections following the standard pattern of apply mask then use case.
@@ -29,6 +38,9 @@ public:
};
+
+
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta)
{
@@ -49,6 +61,8 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
+
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta)
{
@@ -69,6 +83,8 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
+
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta)
{
@@ -85,6 +101,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
+
template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched>
NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta)
{
@@ -97,3 +114,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc
// Not Facing East or West; No change.
return a_Meta;
}
+
+
+
+
diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp
index aab51c539..482f9923f 100644
--- a/src/BoundingBox.cpp
+++ b/src/BoundingBox.cpp
@@ -10,7 +10,7 @@
-#if SELF_TEST
+#ifdef SELF_TEST
/** A simple self-test that is executed on program start, used to verify bbox functionality */
static class SelfTest_BoundingBox
diff --git a/src/BoundingBox.h b/src/BoundingBox.h
index 9ac5f11b8..a7c6c3eea 100644
--- a/src/BoundingBox.h
+++ b/src/BoundingBox.h
@@ -8,7 +8,7 @@
#pragma once
-#include "Vector3d.h"
+#include "Vector3.h"
#include "Defines.h"
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index 96a135562..1893d89a8 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -62,11 +62,11 @@ public:
cByteBuffer buf(50);
buf.Write("\x05\xac\x02\x00", 4);
UInt32 v1;
- assert(buf.ReadVarInt(v1) && (v1 == 5));
+ assert_test(buf.ReadVarInt(v1) && (v1 == 5));
UInt32 v2;
- assert(buf.ReadVarInt(v2) && (v2 == 300));
+ assert_test(buf.ReadVarInt(v2) && (v2 == 300));
UInt32 v3;
- assert(buf.ReadVarInt(v3) && (v3 == 0));
+ assert_test(buf.ReadVarInt(v3) && (v3 == 0));
}
void TestWrite(void)
@@ -77,8 +77,8 @@ public:
buf.WriteVarInt(0);
AString All;
buf.ReadAll(All);
- assert(All.size() == 4);
- assert(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
+ assert_test(All.size() == 4);
+ assert_test(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0);
}
void TestWrap(void)
@@ -87,17 +87,17 @@ public:
for (int i = 0; i < 1000; i++)
{
size_t FreeSpace = buf.GetFreeSpace();
- assert(buf.GetReadableSpace() == 0);
- assert(FreeSpace > 0);
- assert(buf.Write("a", 1));
- assert(buf.CanReadBytes(1));
- assert(buf.GetReadableSpace() == 1);
+ assert_test(buf.GetReadableSpace() == 0);
+ assert_test(FreeSpace > 0);
+ assert_test(buf.Write("a", 1));
+ assert_test(buf.CanReadBytes(1));
+ assert_test(buf.GetReadableSpace() == 1);
unsigned char v = 0;
- assert(buf.ReadByte(v));
- assert(v == 'a');
- assert(buf.GetReadableSpace() == 0);
+ assert_test(buf.ReadByte(v));
+ assert_test(v == 'a');
+ assert_test(buf.GetReadableSpace() == 0);
buf.CommitRead();
- assert(buf.GetFreeSpace() == FreeSpace); // We're back to normal
+ assert_test(buf.GetFreeSpace() == FreeSpace); // We're back to normal
}
}
@@ -459,7 +459,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
}
if (Size > MAX_STRING_SIZE)
{
- LOGWARNING("%s: String too large: %llu (%llu KiB)", __FUNCTION__, Size, Size / 1024);
+ LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
}
return ReadString(a_Value, (int)Size);
}
@@ -767,7 +767,7 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
{
return false;
}
- RawBEToUTF8((short *)(RawData.data()), a_NumChars, a_String);
+ RawBEToUTF8(RawData.data(), a_NumChars, a_String);
return true;
}
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index ed2e10a55..1915467f3 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -43,7 +43,7 @@ public:
size_t GetReadableSpace(void) const;
/// Returns the current data start index. For debugging purposes.
- int GetDataStart(void) const { return m_DataStart; }
+ size_t GetDataStart(void) const { return m_DataStart; }
/// Returns true if the specified amount of bytes are available for reading
bool CanReadBytes(size_t a_Count) const;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5029906aa..0f0db9c80 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,4 +1,3 @@
-
cmake_minimum_required (VERSION 2.8.2)
project (MCServer)
@@ -10,7 +9,6 @@ set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities)
-
if (NOT MSVC)
#Bindings needs to reference other folders so are done here
@@ -59,12 +57,14 @@ if (NOT MSVC)
Entities/Player.h
Entities/ProjectileEntity.h
Entities/TNTEntity.h
+ Entities/ExpOrb.h
+ Entities/HangingEntity.h
+ Entities/ItemFrame.h
Generating/ChunkDesc.h
Group.h
Inventory.h
Item.h
ItemGrid.h
- Matrix4f.h
Mobs/Monster.h
OSSupport/File.h
Root.h
@@ -72,9 +72,7 @@ if (NOT MSVC)
StringUtils.h
Tracer.h
UI/Window.h
- Vector3d.h
- Vector3f.h
- Vector3i.h
+ Vector3.h
WebAdmin.h
World.h
)
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 7be2fa2df..9c7753820 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -9,7 +9,7 @@
#pragma once
-#include "Vector3i.h"
+#include "Vector3.h"
#include "BiomeDef.h"
@@ -62,16 +62,12 @@ typedef unsigned char HEIGHTTYPE;
class cChunkDef
{
public:
- enum
- {
- // Chunk dimensions:
- Width = 16,
- Height = 256,
- NumBlocks = Width * Height * Width,
-
- /// If the data is collected into a single buffer, how large it needs to be:
- BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2), // 2.5 * numblocks
- } ;
+ // Chunk dimensions:
+ static const int Width = 16;
+ static const int Height = 256;
+ static const int NumBlocks = Width * Height * Width;
+ /// If the data is collected into a single buffer, how large it needs to be:
+ static const int BlockDataSize = cChunkDef::NumBlocks * 2 + (cChunkDef::NumBlocks / 2); // 2.5 * numblocks
/// The type used for any heightmap operations and storage; idx = x + Width * z; Height points to the highest non-air block in the column
typedef HEIGHTTYPE HeightMap[Width * Width];
@@ -116,7 +112,7 @@ public:
}
- inline static unsigned int MakeIndex(int x, int y, int z )
+ inline static int MakeIndex(int x, int y, int z )
{
if (
(x < Width) && (x > -1) &&
@@ -132,7 +128,7 @@ public:
}
- inline static unsigned int MakeIndexNoCheck(int x, int y, int z)
+ inline static int MakeIndexNoCheck(int x, int y, int z)
{
#if AXIS_ORDER == AXIS_ORDER_XZY
// For some reason, NOT using the Horner schema is faster. Weird.
@@ -255,7 +251,7 @@ public:
ASSERT(!"cChunkDef::SetNibble(): index out of range!");
return;
}
- a_Buffer[a_BlockIdx / 2] = (
+ a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>(
(a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble
((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set
);
@@ -275,20 +271,20 @@ public:
}
int Index = MakeIndexNoCheck(x, y, z);
- a_Buffer[Index / 2] = (
+ a_Buffer[Index / 2] = static_cast<NIBBLETYPE>(
(a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble
((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set
);
}
- inline static char GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
+ inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
{
return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
}
- inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
+ inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value )
{
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
}
@@ -306,6 +302,9 @@ The virtual methods are called in the same order as they're declared here.
class cChunkDataCallback abstract
{
public:
+
+ virtual ~cChunkDataCallback() {}
+
/** Called before any other callbacks to inform of the current coords
(only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()).
If false is returned, the chunk is skipped.
@@ -432,6 +431,9 @@ Used primarily for entity moving while both chunks are locked.
class cClientDiffCallback
{
public:
+
+ virtual ~cClientDiffCallback() {}
+
/// Called for clients that are in Chunk1 and not in Chunk2,
virtual void Removed(cClientHandle * a_Client) = 0;
@@ -492,6 +494,9 @@ typedef std::vector<cChunkCoords> cChunkCoordsVector;
class cChunkCoordCallback
{
public:
+
+ virtual ~cChunkCoordCallback() {}
+
virtual void Call(int a_ChunkX, int a_ChunkZ) = 0;
} ;
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index 40964c654..62c1ec544 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -1383,6 +1383,13 @@ void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
}
break;
}
+ case E_BLOCK_NEW_LEAVES:
+ {
+ if (itr->BlockType == E_BLOCK_NEW_LOG)
+ {
+ Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
+ }
+ }
}
} // for itr - a_Blocks[]
}
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index b08c029c0..46c10ae82 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -22,9 +22,6 @@
#include "Blocks/BlockSlab.h"
#include "Blocks/ChunkInterface.h"
-#include "Vector3f.h"
-#include "Vector3d.h"
-
#include "Root.h"
#include "Authenticator.h"
@@ -36,22 +33,12 @@
-
-
-#define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
- case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\
- case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; }
-
-
-
-
-
-/** If the number of queued outgoing packets reaches this, the client will be kicked */
-#define MAX_OUTGOING_PACKETS 2000
-
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
#define MAX_EXPLOSIONS_PER_TICK 20
+/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
+#define MAX_BLOCK_CHANGE_INTERACTIONS 20
+
/** How many ticks before the socket is closed after the client is destroyed (#31) */
static const int TICKS_BEFORE_CLOSE = 20;
@@ -700,6 +687,14 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status
);
+ m_NumBlockChangeInteractionsThisTick++;
+
+ if (!CheckBlockInteractionsRate())
+ {
+ Kick("Too many blocks were destroyed per unit time - hacked client?");
+ return;
+ }
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
{
@@ -707,12 +702,6 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
return;
}
-
- if (!CheckBlockInteractionsRate())
- {
- // Too many interactions per second, simply ignore. Probably a hacked client, so don't even send bak the block
- return;
- }
switch (a_Status)
{
@@ -890,7 +879,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
LOGD("Prevented a dig/aim bug in the client (finish {%d, %d, %d} vs start {%d, %d, %d}, HSD: %s)",
a_BlockX, a_BlockY, a_BlockZ,
m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ,
- m_HasStartedDigging
+ (m_HasStartedDigging ? "True" : "False")
);
return;
}
@@ -944,7 +933,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- if (a_BlockFace > -1)
+ if (a_BlockFace != BLOCK_FACE_NONE)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
@@ -955,7 +944,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
if (!CheckBlockInteractionsRate())
{
- LOGD("Too many block interactions, aborting placement");
+ Kick("Too many blocks were placed/interacted with per unit time - hacked client?");
return;
}
@@ -1634,28 +1623,12 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
{
ASSERT(m_Player != NULL);
ASSERT(m_Player->GetWorld() != NULL);
- /*
- // TODO: _X 2012_11_01: This needs a total re-thinking and rewriting
- int LastActionCnt = m_Player->GetLastBlockActionCnt();
- if ((m_Player->GetWorld()->GetTime() - m_Player->GetLastBlockActionTime()) < 0.1)
- {
- // Limit the number of block interactions per tick
- m_Player->SetLastBlockActionTime(); //Player tried to interact with a block. Reset last block interation time.
- m_Player->SetLastBlockActionCnt(LastActionCnt + 1);
- if (m_Player->GetLastBlockActionCnt() > MAXBLOCKCHANGEINTERACTIONS)
- {
- // Kick if more than MAXBLOCKCHANGEINTERACTIONS per tick
- LOGWARN("Player %s tried to interact with a block too quickly! (could indicate bot) Was Kicked.", m_Username.c_str());
- Kick("You're a baaaaaad boy!");
- return false;
- }
- }
- else
+
+ if (m_NumBlockChangeInteractionsThisTick > MAX_BLOCK_CHANGE_INTERACTIONS)
{
- m_Player->SetLastBlockActionCnt(0); // Reset count
- m_Player->SetLastBlockActionTime(); // Player tried to interact with a block. Reset last block interation time.
+ return false;
}
- */
+
return true;
}
@@ -1728,8 +1701,9 @@ void cClientHandle::Tick(float a_Dt)
}
}
- // Reset explosion counter:
+ // Reset explosion & block change counters:
m_NumExplosionsThisTick = 0;
+ m_NumBlockChangeInteractionsThisTick = 0;
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 035fadfe4..8366caa16 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -12,7 +12,7 @@
#define CCLIENTHANDLE_H_INCLUDED
#include "Defines.h"
-#include "Vector3d.h"
+#include "Vector3.h"
#include "OSSupport/SocketThreads.h"
#include "ChunkDef.h"
#include "ByteBuffer.h"
@@ -46,7 +46,6 @@ class cClientHandle : // tolua_export
public cSocketThreads::cCallback
{ // tolua_export
public:
- static const int MAXBLOCKCHANGEINTERACTIONS = 20; // 5 didn't help, 10 still doesn't work in Creative, 20 seems to have done the trick
#if defined(ANDROID_NDK)
static const int DEFAULT_VIEW_DISTANCE = 4; // The default ViewDistance (used when no value is set in Settings.ini)
@@ -321,6 +320,9 @@ private:
/** Number of explosions sent this tick */
int m_NumExplosionsThisTick;
+
+ /** Number of place or break interactions this tick */
+ int m_NumBlockChangeInteractionsThisTick;
static int s_ClientCount;
int m_UniqueID;
diff --git a/src/CommandOutput.cpp b/src/CommandOutput.cpp
index c221682a1..2c116b3d6 100644
--- a/src/CommandOutput.cpp
+++ b/src/CommandOutput.cpp
@@ -51,7 +51,7 @@ void cLogCommandOutputCallback::Finished(void)
{
case '\n':
{
- LOG(m_Buffer.substr(last, i - last).c_str());
+ LOG("%s", m_Buffer.substr(last, i - last).c_str());
last = i + 1;
break;
}
@@ -59,7 +59,7 @@ void cLogCommandOutputCallback::Finished(void)
} // for i - m_Buffer[]
if (last < len)
{
- LOG(m_Buffer.substr(last).c_str());
+ LOG("%s", m_Buffer.substr(last).c_str());
}
// Clear the buffer for the next command output:
diff --git a/src/CommandOutput.h b/src/CommandOutput.h
index 3763d625f..5682b4fd8 100644
--- a/src/CommandOutput.h
+++ b/src/CommandOutput.h
@@ -17,7 +17,7 @@ public:
virtual ~cCommandOutputCallback() {}; // Force a virtual destructor in subclasses
/// Syntax sugar function, calls Out() with Printf()-ed parameters; appends a "\n"
- void Out(const char * a_Fmt, ...);
+ void Out(const char * a_Fmt, ...) FORMATSTRING(2, 3);
/// Called when the command wants to output anything; may be called multiple times
virtual void Out(const AString & a_Text) = 0;
diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp
index 3eec35657..a917ee70f 100644
--- a/src/CompositeChat.cpp
+++ b/src/CompositeChat.cpp
@@ -10,7 +10,7 @@
-#if SELF_TEST
+#ifdef SELF_TEST
/** A simple self-test that verifies that the composite chat parser is working properly. */
class SelfTest_CompositeChat
@@ -32,15 +32,15 @@ public:
cCompositeChat Msg;
Msg.ParseText("Testing @2color codes and http://links parser");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 4);
- assert(Parts[0]->m_PartType == cCompositeChat::ptText);
- assert(Parts[1]->m_PartType == cCompositeChat::ptText);
- assert(Parts[2]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[3]->m_PartType == cCompositeChat::ptText);
- assert(Parts[0]->m_Style == "");
- assert(Parts[1]->m_Style == "@2");
- assert(Parts[2]->m_Style == "@2");
- assert(Parts[3]->m_Style == "@2");
+ assert_test(Parts.size() == 4);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[2]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[3]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[0]->m_Style == "");
+ assert_test(Parts[1]->m_Style == "@2");
+ assert_test(Parts[2]->m_Style == "@2");
+ assert_test(Parts[3]->m_Style == "@2");
}
void TestParser2(void)
@@ -48,15 +48,15 @@ public:
cCompositeChat Msg;
Msg.ParseText("@3Advanced stuff: @5overriding color codes and http://links.with/@4color-in-them handling");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 4);
- assert(Parts[0]->m_PartType == cCompositeChat::ptText);
- assert(Parts[1]->m_PartType == cCompositeChat::ptText);
- assert(Parts[2]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[3]->m_PartType == cCompositeChat::ptText);
- assert(Parts[0]->m_Style == "@3");
- assert(Parts[1]->m_Style == "@5");
- assert(Parts[2]->m_Style == "@5");
- assert(Parts[3]->m_Style == "@5");
+ assert_test(Parts.size() == 4);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[2]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[3]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[0]->m_Style == "@3");
+ assert_test(Parts[1]->m_Style == "@5");
+ assert_test(Parts[2]->m_Style == "@5");
+ assert_test(Parts[3]->m_Style == "@5");
}
void TestParser3(void)
@@ -64,11 +64,11 @@ public:
cCompositeChat Msg;
Msg.ParseText("http://links.starting the text");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 2);
- assert(Parts[0]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[1]->m_PartType == cCompositeChat::ptText);
- assert(Parts[0]->m_Style == "");
- assert(Parts[1]->m_Style == "");
+ assert_test(Parts.size() == 2);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[0]->m_Style == "");
+ assert_test(Parts[1]->m_Style == "");
}
void TestParser4(void)
@@ -76,11 +76,11 @@ public:
cCompositeChat Msg;
Msg.ParseText("links finishing the text: http://some.server");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 2);
- assert(Parts[0]->m_PartType == cCompositeChat::ptText);
- assert(Parts[1]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[0]->m_Style == "");
- assert(Parts[1]->m_Style == "");
+ assert_test(Parts.size() == 2);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptText);
+ assert_test(Parts[1]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[0]->m_Style == "");
+ assert_test(Parts[1]->m_Style == "");
}
void TestParser5(void)
@@ -88,9 +88,9 @@ public:
cCompositeChat Msg;
Msg.ParseText("http://only.links");
const cCompositeChat::cParts & Parts = Msg.GetParts();
- assert(Parts.size() == 1);
- assert(Parts[0]->m_PartType == cCompositeChat::ptUrl);
- assert(Parts[0]->m_Style == "");
+ assert_test(Parts.size() == 1);
+ assert_test(Parts[0]->m_PartType == cCompositeChat::ptUrl);
+ assert_test(Parts[0]->m_Style == "");
}
} gTest;
diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp
index fb1a10cca..30e7a8733 100644
--- a/src/CraftingRecipes.cpp
+++ b/src/CraftingRecipes.cpp
@@ -1,4 +1,4 @@
-
+
// CraftingRecipes.cpp
// Interfaces to the cCraftingRecipes class representing the storage of crafting recipes
@@ -192,7 +192,9 @@ void cCraftingGrid::Dump(void)
{
for (int y = 0; y < m_Height; y++) for (int x = 0; x < m_Width; x++)
{
+ #ifdef _DEBUG
int idx = x + m_Width * y;
+ #endif
LOGD("Slot (%d, %d): Type %d, health %d, count %d",
x, y, m_Items[idx].m_ItemType, m_Items[idx].m_ItemDamage, m_Items[idx].m_ItemCount
);
@@ -338,7 +340,7 @@ void cCraftingRecipes::LoadRecipes(void)
}
AddRecipeLine(LineNum, Recipe);
} // for itr - Split[]
- LOG("Loaded %d crafting recipes", m_Recipes.size());
+ LOG("Loaded " SIZE_T_FMT " crafting recipes", m_Recipes.size());
}
@@ -762,9 +764,94 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti
Recipe->m_Ingredients.push_back(*itrS);
}
Recipe->m_Ingredients.insert(Recipe->m_Ingredients.end(), MatchedSlots.begin(), MatchedSlots.end());
+
+ // We use Recipe instead of a_Recipe because we want the wildcard ingredients' slot numbers as well, which was just added previously
+ HandleFireworks(a_CraftingGrid, Recipe.get(), a_GridStride, a_OffsetX, a_OffsetY);
+
return Recipe.release();
}
+
+void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY)
+{
+ // TODO: add support for more than one dye in the recipe
+ // A manual and temporary solution (listing everything) is in crafting.txt for fade colours, but a programmatic solutions needs to be done for everything else
+
+ if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_ROCKET)
+ {
+ for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
+ {
+ switch (itr->m_Item.m_ItemType)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ // Result was a rocket, found a star - copy star data to rocket data
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
+ break;
+ }
+ case E_ITEM_GUNPOWDER:
+ {
+ // Gunpowder - increase flight time
+ a_Recipe->m_Result.m_FireworkItem.m_FlightTimeInTicks += 20;
+ break;
+ }
+ case E_ITEM_PAPER: break;
+ default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break;
+ }
+ }
+ }
+ else if (a_Recipe->m_Result.m_ItemType == E_ITEM_FIREWORK_STAR)
+ {
+ std::vector<int> DyeColours;
+ bool FoundStar = false;
+
+ for (cRecipeSlots::const_iterator itr = a_Recipe->m_Ingredients.begin(); itr != a_Recipe->m_Ingredients.end(); ++itr)
+ {
+ switch (itr->m_Item.m_ItemType)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ // Result was star, found another star - probably adding fade colours, but copy data over anyhow
+ FoundStar = true;
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ a_Recipe->m_Result.m_FireworkItem.CopyFrom(a_CraftingGrid[GridID].m_FireworkItem);
+ break;
+ }
+ case E_ITEM_DYE:
+ {
+ int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY);
+ DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage));
+ break;
+ }
+ case E_ITEM_GUNPOWDER: break;
+ case E_ITEM_DIAMOND: a_Recipe->m_Result.m_FireworkItem.m_HasTrail = true; break;
+ case E_ITEM_GLOWSTONE_DUST: a_Recipe->m_Result.m_FireworkItem.m_HasFlicker = true; break;
+
+ case E_ITEM_FIRE_CHARGE: a_Recipe->m_Result.m_FireworkItem.m_Type = 1; break;
+ case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break;
+ case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break;
+ case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break;
+ default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins
+ }
+ }
+
+ if (FoundStar && (!DyeColours.empty()))
+ {
+ // Found a star and a dye? Fade colours.
+ a_Recipe->m_Result.m_FireworkItem.m_FadeColours = DyeColours;
+ }
+ else if (!DyeColours.empty())
+ {
+ // Only dye? Normal colours.
+ a_Recipe->m_Result.m_FireworkItem.m_Colours = DyeColours;
+ }
+ }
+}
+
+
+
+
diff --git a/src/CraftingRecipes.h b/src/CraftingRecipes.h
index 9d92cbfab..90e41eddc 100644
--- a/src/CraftingRecipes.h
+++ b/src/CraftingRecipes.h
@@ -165,6 +165,9 @@ protected:
/// Checks if the grid matches the specified recipe, offset by the specified offsets. Returns a matched cRecipe * if so, or NULL if not matching. Caller must delete the return value!
cRecipe * MatchRecipe(const cItem * a_CraftingGrid, int a_GridWidth, int a_GridHeight, int a_GridStride, const cRecipe * a_Recipe, int a_OffsetX, int a_OffsetY);
+
+ /** Searches for anything firework related, and does the data setting if appropriate */
+ void HandleFireworks(const cItem * a_CraftingGrid, cCraftingRecipes::cRecipe * a_Recipe, int a_GridStride, int a_OffsetX, int a_OffsetY);
} ;
diff --git a/src/Cuboid.cpp b/src/Cuboid.cpp
index 782837b23..3e5240248 100644
--- a/src/Cuboid.cpp
+++ b/src/Cuboid.cpp
@@ -38,6 +38,20 @@ void cCuboid::Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2)
+void cCuboid::Assign(const cCuboid & a_SrcCuboid)
+{
+ p1.x = a_SrcCuboid.p1.x;
+ p1.y = a_SrcCuboid.p1.y;
+ p1.z = a_SrcCuboid.p1.z;
+ p2.x = a_SrcCuboid.p2.x;
+ p2.y = a_SrcCuboid.p2.y;
+ p2.z = a_SrcCuboid.p2.z;
+}
+
+
+
+
+
void cCuboid::Sort(void)
{
if (p1.x > p2.x)
@@ -72,6 +86,9 @@ int cCuboid::GetVolume(void) const
bool cCuboid::DoesIntersect(const cCuboid & a_Other) const
{
+ ASSERT(IsSorted());
+ ASSERT(a_Other.IsSorted());
+
// In order for cuboids to intersect, each of their coord intervals need to intersect
return (
DoIntervalsIntersect(p1.x, p2.x, a_Other.p1.x, a_Other.p2.x) &&
@@ -86,6 +103,9 @@ bool cCuboid::DoesIntersect(const cCuboid & a_Other) const
bool cCuboid::IsCompletelyInside(const cCuboid & a_Outer) const
{
+ ASSERT(IsSorted());
+ ASSERT(a_Outer.IsSorted());
+
return (
(p1.x >= a_Outer.p1.x) &&
(p2.x <= a_Outer.p2.x) &&
@@ -197,3 +217,37 @@ bool cCuboid::IsSorted(void) const
+
+void cCuboid::Engulf(const Vector3i & a_Point)
+{
+ if (a_Point.x < p1.x)
+ {
+ p1.x = a_Point.x;
+ }
+ else if (a_Point.x > p2.x)
+ {
+ p2.x = a_Point.x;
+ }
+
+ if (a_Point.y < p1.y)
+ {
+ p1.y = a_Point.y;
+ }
+ else if (a_Point.y > p2.y)
+ {
+ p2.y = a_Point.y;
+ }
+
+ if (a_Point.z < p1.z)
+ {
+ p1.z = a_Point.z;
+ }
+ else if (a_Point.z > p2.z)
+ {
+ p2.z = a_Point.z;
+ }
+}
+
+
+
+
diff --git a/src/Cuboid.h b/src/Cuboid.h
index 51ccf799b..3239c54fc 100644
--- a/src/Cuboid.h
+++ b/src/Cuboid.h
@@ -1,8 +1,7 @@
#pragma once
-#include "Vector3i.h"
-#include "Vector3d.h"
+#include "Vector3.h"
@@ -22,6 +21,7 @@ public:
cCuboid(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2) : p1(a_X1, a_Y1, a_Z1), p2(a_X2, a_Y2, a_Z2) {}
void Assign(int a_X1, int a_Y1, int a_Z1, int a_X2, int a_Y2, int a_Z2);
+ void Assign(const cCuboid & a_SrcCuboid);
void Sort(void);
@@ -34,7 +34,8 @@ public:
Works on unsorted cuboids, too. */
int GetVolume(void) const;
- /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive. */
+ /** Returns true if the cuboids have at least one voxel in common. Both coords are considered inclusive.
+ Assumes both cuboids are sorted. */
bool DoesIntersect(const cCuboid & a_Other) const;
bool IsInside(const Vector3i & v) const
@@ -64,7 +65,8 @@ public:
);
}
- /** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords) */
+ /** Returns true if this cuboid is completely inside the specifie cuboid (in all 6 coords).
+ Assumes both cuboids are sorted. */
bool IsCompletelyInside(const cCuboid & a_Outer) const;
/** Moves the cuboid by the specified offsets in each direction */
@@ -72,7 +74,7 @@ public:
/** Expands the cuboid by the specified amount in each direction.
Works on unsorted cuboids as well.
- Note that this function doesn't check for underflows. */
+ Note that this function doesn't check for underflows when using negative amounts. */
void Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ);
/** Clamps both X coords to the specified range. Works on unsorted cuboids, too. */
@@ -86,6 +88,9 @@ public:
/** Returns true if the coords are properly sorted (lesser in p1, greater in p2) */
bool IsSorted(void) const;
+
+ /** If needed, expands the cuboid so that it contains the specified point. Assumes sorted. Doesn't contract. */
+ void Engulf(const Vector3i & a_Point);
} ;
// tolua_end
diff --git a/src/DeadlockDetect.h b/src/DeadlockDetect.h
index cb2309169..6aa98acbb 100644
--- a/src/DeadlockDetect.h
+++ b/src/DeadlockDetect.h
@@ -60,7 +60,7 @@ protected:
void CheckWorldAge(const AString & a_WorldName, Int64 a_Age);
/// Called when a deadlock is detected. Aborts the server.
- void DeadlockDetected(void);
+ NORETURN void DeadlockDetected(void);
} ;
diff --git a/src/Defines.h b/src/Defines.h
index 6ab2274a4..38411c69d 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -2,6 +2,7 @@
#pragma once
#include "ChatColor.h"
+#include <limits>
@@ -276,6 +277,26 @@ inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace)
+/** Returns the textual representation of the BlockFace constant. */
+inline AString BlockFaceToString(eBlockFace a_BlockFace)
+{
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_XM: return "BLOCK_FACE_XM";
+ case BLOCK_FACE_XP: return "BLOCK_FACE_XP";
+ case BLOCK_FACE_YM: return "BLOCK_FACE_YM";
+ case BLOCK_FACE_YP: return "BLOCK_FACE_YP";
+ case BLOCK_FACE_ZM: return "BLOCK_FACE_ZM";
+ case BLOCK_FACE_ZP: return "BLOCK_FACE_ZP";
+ case BLOCK_FACE_NONE: return "BLOCK_FACE_NONE";
+ }
+ return Printf("Unknown BLOCK_FACE: %d", a_BlockFace);
+}
+
+
+
+
+
inline bool IsValidBlock(int a_BlockType)
{
if (
@@ -469,7 +490,7 @@ inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a
inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch)
{
- if (a_X != 0)
+ if (fabs(a_X) < std::numeric_limits<double>::epsilon())
{
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
}
@@ -509,16 +530,22 @@ enum eMessageType
// http://forum.mc-server.org/showthread.php?tid=1212
// MessageType...
- mtCustom, // Send raw data without any processing
- mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
- mtInformation, // Informational message (i.e. command usage)
- mtSuccess, // Something executed successfully
- mtWarning, // Something concerning (i.e. reload) is about to happen
- mtFatal, // Something catastrophic occured (i.e. plugin crash)
- mtDeath, // Denotes death of player
- mtPrivateMessage, // Player to player messaging identifier
- mtJoin, // A player has joined the server
- mtLeave, // A player has left the server
+ mtCustom, // Send raw data without any processing
+ mtFailure, // Something could not be done (i.e. command not executed due to insufficient privilege)
+ mtInformation, // Informational message (i.e. command usage)
+ mtSuccess, // Something executed successfully
+ mtWarning, // Something concerning (i.e. reload) is about to happen
+ mtFatal, // Something catastrophic occured (i.e. plugin crash)
+ mtDeath, // Denotes death of player
+ mtPrivateMessage, // Player to player messaging identifier
+ mtJoin, // A player has joined the server
+ mtLeave, // A player has left the server
+
+ // Common aliases:
+ mtFail = mtFailure,
+ mtError = mtFailure,
+ mtInfo = mtInformation,
+ mtPM = mtPrivateMessage,
};
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 96e8c15a5..0750ae05e 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -4,7 +4,7 @@
#include "../World.h"
#include "../Server.h"
#include "../Root.h"
-#include "../Matrix4f.h"
+#include "../Matrix4.h"
#include "../ClientHandle.h"
#include "../Chunk.h"
#include "../Simulator/FluidSimulator.h"
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index b3b1cef83..a73565de7 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -2,9 +2,7 @@
#pragma once
#include "../Item.h"
-#include "../Vector3d.h"
-#include "../Vector3f.h"
-#include "../Vector3i.h"
+#include "../Vector3.h"
diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp
index 3398f1c7b..3623c869a 100644
--- a/src/Entities/ExpOrb.cpp
+++ b/src/Entities/ExpOrb.cpp
@@ -5,20 +5,26 @@
#include "../ClientHandle.h"
-cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward) :
- cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Reward(a_Reward)
+cExpOrb::cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward)
+ : cEntity(etExpOrb, a_X, a_Y, a_Z, 0.98, 0.98)
+ , m_Reward(a_Reward)
+ , m_Timer(0.f)
{
+ SetMaxHealth(5);
+ SetHealth(5);
}
-cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) :
- cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Reward(a_Reward)
+cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward)
+ : cEntity(etExpOrb, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98)
+ , m_Reward(a_Reward)
+ , m_Timer(0.f)
{
+ SetMaxHealth(5);
+ SetHealth(5);
}
@@ -52,7 +58,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(m_Reward);
- m_World->BroadcastSoundEffect("random.orb", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_World->BroadcastSoundEffect("random.orb", (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
Destroy();
}
@@ -64,4 +70,10 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
BroadcastMovementUpdate();
}
HandlePhysics(a_Dt, a_Chunk);
+
+ m_Timer += a_Dt;
+ if (m_Timer >= 1000 * 60 * 5) // 5 minutes
+ {
+ Destroy(true);
+ }
}
diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h
index 47d86922c..c1150bd03 100644
--- a/src/Entities/ExpOrb.h
+++ b/src/Entities/ExpOrb.h
@@ -7,14 +7,17 @@
+// tolua_begin
class cExpOrb :
public cEntity
{
typedef cExpOrb super;
public:
+ // tolua_end
+
CLASS_PROTODEF(cExpOrb);
-
+
cExpOrb(double a_X, double a_Y, double a_Z, int a_Reward);
cExpOrb(const Vector3d & a_Pos, int a_Reward);
@@ -22,9 +25,21 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SpawnOn(cClientHandle & a_Client) override;
- // cExpOrb functions
- int GetReward(void) const { return m_Reward; }
+ /** Returns the number of ticks that this entity has existed */
+ int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
+
+ /** Set the number of ticks that this entity has existed */
+ void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
+
+ /** Get the exp amount */
+ int GetReward(void) const { return m_Reward; } // tolua_export
+
+ /** Set the exp amount */
+ void SetReward(int a_Reward) { m_Reward = a_Reward; } // tolua_export
protected:
int m_Reward;
-} ; \ No newline at end of file
+
+ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
+ float m_Timer;
+} ; // tolua_export \ No newline at end of file
diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h
index 865d6dc50..f3b51d77b 100644
--- a/src/Entities/Floater.h
+++ b/src/Entities/Floater.h
@@ -11,7 +11,7 @@
class cFloater :
public cEntity
{
- typedef cFloater super;
+ typedef cEntity super;
public:
//tolua_end
diff --git a/src/Entities/HangingEntity.cpp b/src/Entities/HangingEntity.cpp
new file mode 100644
index 000000000..41ac86268
--- /dev/null
+++ b/src/Entities/HangingEntity.cpp
@@ -0,0 +1,53 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "HangingEntity.h"
+#include "ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cHangingEntity::cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
+ : cEntity(a_EntityType, a_X, a_Y, a_Z, 0.8, 0.8)
+ , m_BlockFace(a_BlockFace)
+{
+ SetMaxHealth(1);
+ SetHealth(1);
+}
+
+
+
+
+
+void cHangingEntity::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ int Dir = 0;
+
+ // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
+ switch (m_BlockFace)
+ {
+ case BLOCK_FACE_ZP: break; // Initialised to zero
+ case BLOCK_FACE_ZM: Dir = 2; break;
+ case BLOCK_FACE_XM: Dir = 1; break;
+ case BLOCK_FACE_XP: Dir = 3; break;
+ default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
+ }
+
+ if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
+ {
+ SetYaw((Dir * 90) - 180);
+ }
+ else
+ {
+ SetYaw(Dir * 90);
+ }
+
+ a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
+ a_ClientHandle.SendEntityMetadata(*this);
+}
+
+
+
+
diff --git a/src/Entities/HangingEntity.h b/src/Entities/HangingEntity.h
new file mode 100644
index 000000000..6498e4b5b
--- /dev/null
+++ b/src/Entities/HangingEntity.h
@@ -0,0 +1,49 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cHangingEntity :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+
+ CLASS_PROTODEF(cHangingEntity);
+
+ cHangingEntity(eEntityType a_EntityType, eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
+
+ /** Returns the orientation from the hanging entity */
+ eBlockFace GetDirection() const { return m_BlockFace; } // tolua_export
+
+ /** Set the orientation from the hanging entity */
+ void SetDirection(eBlockFace a_BlockFace) { m_BlockFace = a_BlockFace; } // tolua_export
+
+ /** Returns the X coord. */
+ int GetTileX() const { return POSX_TOINT; } // tolua_export
+
+ /** Returns the Y coord. */
+ int GetTileY() const { return POSY_TOINT; } // tolua_export
+
+ /** Returns the Z coord. */
+ int GetTileZ() const { return POSZ_TOINT; } // tolua_export
+
+private:
+
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+
+ eBlockFace m_BlockFace;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
index 8cfa5e18d..9dd909880 100644
--- a/src/Entities/ItemFrame.cpp
+++ b/src/Entities/ItemFrame.cpp
@@ -10,43 +10,10 @@
cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
- : cEntity(etItemFrame, a_X, a_Y, a_Z, 0.8, 0.8),
- m_BlockFace(a_BlockFace),
- m_Item(E_BLOCK_AIR),
- m_Rotation(0)
+ : cHangingEntity(etItemFrame, a_BlockFace, a_X, a_Y, a_Z)
+ , m_Item(E_BLOCK_AIR)
+ , m_Rotation(0)
{
- SetMaxHealth(1);
- SetHealth(1);
-}
-
-
-
-
-
-void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle)
-{
- int Dir = 0;
-
- // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
- switch (m_BlockFace)
- {
- case BLOCK_FACE_ZP: break; // Initialised to zero
- case BLOCK_FACE_ZM: Dir = 2; break;
- case BLOCK_FACE_XM: Dir = 1; break;
- case BLOCK_FACE_XP: Dir = 3; break;
- default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
- }
-
- if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
- {
- SetYaw((Dir * 90) - 180);
- }
- else
- {
- SetYaw(Dir * 90);
- }
-
- a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
}
diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h
index 43915e3f9..6577e7d94 100644
--- a/src/Entities/ItemFrame.h
+++ b/src/Entities/ItemFrame.h
@@ -1,7 +1,7 @@
#pragma once
-#include "Entity.h"
+#include "HangingEntity.h"
@@ -9,10 +9,10 @@
// tolua_begin
class cItemFrame :
- public cEntity
+ public cHangingEntity
{
// tolua_end
- typedef cEntity super;
+ typedef cHangingEntity super;
public:
@@ -20,18 +20,24 @@ public:
cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
- const cItem & GetItem(void) { return m_Item; }
- Byte GetRotation(void) const { return m_Rotation; }
+ /** Returns the item in the frame */
+ const cItem & GetItem(void) { return m_Item; } // tolua_export
+
+ /** Set the item in the frame */
+ void SetItem(cItem & a_Item) { m_Item = a_Item; }; // tolua_export
+
+ /** Returns the rotation from the item in the frame */
+ Byte GetRotation(void) const { return m_Rotation; } // tolua_export
+
+ /** Set the rotation from the item in the frame */
+ void SetRotation(Byte a_Rotation) { m_Rotation = a_Rotation; } // tolua_export
private:
- virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
- virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
virtual void KilledBy(cEntity * a_Killer) override;
virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
- eBlockFace m_BlockFace;
cItem m_Item;
Byte m_Rotation;
diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp
index c5503c16a..7fc89b62b 100644
--- a/src/Entities/Pickup.cpp
+++ b/src/Entities/Pickup.cpp
@@ -82,7 +82,7 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_It
void cPickup::SpawnOn(cClientHandle & a_Client)
{
- a_Client.SendPickupSpawn(*this);
+ a_Client.SendPickupSpawn(*this);
}
diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h
index c273567d1..74b917bce 100644
--- a/src/Entities/Pickup.h
+++ b/src/Entities/Pickup.h
@@ -26,31 +26,34 @@ public:
CLASS_PROTODEF(cPickup);
cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f);
-
+
cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; }
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
-
+
bool CollectedBy(cPlayer * a_Dest); // tolua_export
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- /// Returns the number of ticks that this entity has existed
- int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
-
- /// Returns true if the pickup has already been collected
+
+ /** Returns the number of ticks that this entity has existed */
+ int GetAge(void) const { return (int)(m_Timer / 50); } // tolua_export
+
+ /** Set the number of ticks that this entity has existed */
+ void SetAge(int a_Age) { m_Timer = (float)(a_Age * 50); } // tolua_export
+
+ /** Returns true if the pickup has already been collected */
bool IsCollected(void) const { return m_bCollected; } // tolua_export
- /// Returns true if created by player (i.e. vomiting), used for determining picking-up delay time
+ /** Returns true if created by player (i.e. vomiting), used for determining picking-up delay time */
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
-
+
private:
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
Vector3d m_WaterSpeed;
- /// The number of ticks that the entity has existed / timer between collect and destroy; in msec
+ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer;
cItem m_Item;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 42ee14cf3..440d30595 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -10,17 +10,11 @@
#include "../BlockEntities/BlockEntity.h"
#include "../GroupManager.h"
#include "../Group.h"
-#include "../ChatColor.h"
-#include "../Item.h"
-#include "../Tracer.h"
#include "../Root.h"
#include "../OSSupport/Timer.h"
-#include "../MersenneTwister.h"
#include "../Chunk.h"
#include "../Items/ItemHandler.h"
-
-#include "../Vector3d.h"
-#include "../Vector3f.h"
+#include "../Vector3.h"
#include "inifile/iniFile.h"
#include "json/json.h"
@@ -45,10 +39,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_Inventory(*this)
, m_CurrentWindow(NULL)
, m_InventoryWindow(NULL)
- , m_TimeLastPickupCheck(0.f)
, m_Color('-')
- , m_LastBlockActionTime(0)
- , m_LastBlockActionCnt(0)
, m_GameMode(eGameMode_NotSet)
, m_IP("")
, m_ClientHandle(a_Client)
@@ -86,7 +77,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastPlayerListTime = t1.GetNowTime();
m_TimeLastTeleportPacket = 0;
- m_TimeLastPickupCheck = 0;
m_PlayerName = a_PlayerName;
m_bDirtyPosition = true; // So chunks are streamed to player at spawn
@@ -1047,27 +1037,6 @@ void cPlayer::CloseWindowIfID(char a_WindowID, bool a_CanRefuse)
-void cPlayer::SetLastBlockActionTime()
-{
- if (m_World != NULL)
- {
- m_LastBlockActionTime = m_World->GetWorldAge() / 20.0f;
- }
-}
-
-
-
-
-
-void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
-{
- m_LastBlockActionCnt = a_LastBlockActionCnt;
-}
-
-
-
-
-
void cPlayer::SetGameMode(eGameMode a_GameMode)
{
if ((a_GameMode < gmMin) || (a_GameMode >= gmMax))
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 83a553821..c25053c21 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -50,7 +50,7 @@ public:
/// Returns the curently equipped weapon; empty item if none
virtual cItem GetEquippedWeapon(void) const override { return m_Inventory.GetEquippedItem(); }
- /// Returns the currently equipped helmet; empty item if nonte
+ /// Returns the currently equipped helmet; empty item if none
virtual cItem GetEquippedHelmet(void) const override { return m_Inventory.GetEquippedHelmet(); }
/// Returns the currently equipped chestplate; empty item if none
@@ -165,11 +165,6 @@ public:
// tolua_end
void SetIP(const AString & a_IP);
-
- float GetLastBlockActionTime() { return m_LastBlockActionTime; }
- int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
- void SetLastBlockActionCnt( int );
- void SetLastBlockActionTime();
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
void LoginSetGameMode(eGameMode a_GameMode);
@@ -422,12 +417,8 @@ protected:
cWindow * m_CurrentWindow;
cWindow * m_InventoryWindow;
- float m_TimeLastPickupCheck;
-
char m_Color;
- float m_LastBlockActionTime;
- int m_LastBlockActionCnt;
eGameMode m_GameMode;
AString m_IP;
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 03bc0c99d..f4ab825f2 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -214,7 +214,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
-cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
+cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
{
Vector3d Speed;
if (a_Speed != NULL)
@@ -231,8 +231,15 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
case pkGhastFireball: return new cGhastFireballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkFireCharge: return new cFireChargeEntity (a_Creator, a_X, a_Y, a_Z, Speed);
case pkExpBottle: return new cExpBottleEntity (a_Creator, a_X, a_Y, a_Z, Speed);
- case pkFirework: return new cFireworkEntity (a_Creator, a_X, a_Y, a_Z );
- // TODO: the rest
+ case pkFirework:
+ {
+ if (a_Item.m_FireworkItem.m_Colours.empty())
+ {
+ return NULL;
+ }
+
+ return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
+ }
}
LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
@@ -276,6 +283,7 @@ AString cProjectileEntity::GetMCAClassName(void) const
case pkExpBottle: return "ThrownExpBottle";
case pkSplashPotion: return "ThrownPotion";
case pkWitherSkull: return "WitherSkull";
+ case pkFirework: return "Firework";
case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
}
ASSERT(!"Unhandled projectile entity kind!");
@@ -655,8 +663,6 @@ cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, do
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
- // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs
-
Destroy();
}
@@ -664,6 +670,30 @@ void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFac
+void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
+{
+ int TotalDamage = 0;
+ if (a_EntityHit.IsMob())
+ {
+ cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
+ if (MobType == cMonster::mtBlaze)
+ {
+ TotalDamage = 3;
+ }
+ else if (MobType == cMonster::mtEnderDragon)
+ {
+ TotalDamage = 1;
+ }
+ }
+ a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
+
+ Destroy(true);
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cBottleOEnchantingEntity :
@@ -693,8 +723,10 @@ void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFireworkEntity :
-cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z) :
-super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
+super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
+ m_ExplodeTimer(0),
+ m_FireworkItem(a_Item)
{
}
@@ -702,30 +734,20 @@ super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
-void cFireworkEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
+void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
- if ((a_HitFace != BLOCK_FACE_BOTTOM) && (a_HitFace != BLOCK_FACE_NONE))
+ int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
+ int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
+ int PosY = POSY_TOINT;
+
+ if ((PosY < 0) || (PosY >= cChunkDef::Height))
{
- return;
+ goto setspeed;
}
- SetSpeed(0, 0, 0);
- SetPosition(GetPosX(), GetPosY() - 0.5, GetPosZ());
-
- m_IsInGround = true;
-
- BroadcastMovementUpdate();
-}
-
-
-
-
-
-void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
-{
if (m_IsInGround)
{
- if (a_Chunk.GetBlock((int)GetPosX(), (int)GetPosY() + 1, (int)GetPosZ()) == E_BLOCK_AIR)
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
{
m_IsInGround = false;
}
@@ -734,28 +756,35 @@ void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return;
}
}
+ else
+ {
+ if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
+ {
+ OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
+ return;
+ }
+ }
- Vector3d PerTickSpeed = GetSpeed() / 20;
- Vector3d Pos = GetPosition();
+setspeed:
+ AddSpeedY(1);
+ AddPosition(GetSpeed() * (a_Dt / 1000));
+}
- // Trace the tick's worth of movement as a line:
- Vector3d NextPos = Pos + PerTickSpeed;
- cProjectileTracerCallback TracerCallback(this);
- if (!cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
+
+
+
+
+void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{
- // Something has been hit, abort all other processing
- return;
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
+ Destroy();
}
- // The tracer also checks the blocks for slowdown blocks - water and lava - and stores it for later in its SlowdownCoeff
-
- // Update the position:
- SetPosition(NextPos);
- // Add slowdown and gravity effect to the speed:
- Vector3d NewSpeed(GetSpeed());
- NewSpeed.y += 2;
- NewSpeed *= TracerCallback.GetSlowdownCoeff();
- SetSpeed(NewSpeed);
+ m_ExplodeTimer++;
}
diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h
index e80592999..efb7ae783 100644
--- a/src/Entities/ProjectileEntity.h
+++ b/src/Entities/ProjectileEntity.h
@@ -46,7 +46,7 @@ public:
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
- static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
+ static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
@@ -259,6 +259,7 @@ protected:
// cProjectileEntity overrides:
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
+ virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
// tolua_begin
@@ -305,13 +306,19 @@ public:
CLASS_PROTODEF(cFireworkEntity);
- cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z);
+ cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
+ const cItem & GetItem(void) const { return m_FireworkItem; }
protected:
// cProjectileEntity overrides:
- virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ int m_ExplodeTimer;
+ cItem m_FireworkItem;
// tolua_begin
diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp
index 339107b2e..02f31f5bb 100644
--- a/src/Entities/TNTEntity.cpp
+++ b/src/Entities/TNTEntity.cpp
@@ -8,10 +8,9 @@
-cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec) :
+cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks) :
super(etTNT, a_X, a_Y, a_Z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
+ m_FuseTicks(a_FuseTicks)
{
}
@@ -19,10 +18,9 @@ cTNTEntity::cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSe
-cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
+cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) :
super(etTNT, a_Pos.x, a_Pos.y, a_Pos.z, 0.98, 0.98),
- m_Counter(0),
- m_MaxFuseTime(a_FuseTimeInSec)
+ m_FuseTicks(a_FuseTicks)
{
}
@@ -42,18 +40,27 @@ void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
+void cTNTEntity::Explode(void)
+{
+ m_FuseTicks = 0;
+ Destroy(true);
+ LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
+ m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
+}
+
+
+
+
+
void cTNTEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
BroadcastMovementUpdate();
- float delta_time = a_Dt / 1000; // Convert miliseconds to seconds
- m_Counter += delta_time;
- if (m_Counter > m_MaxFuseTime) // Check if we go KABOOOM
+
+ m_FuseTicks -= 1;
+ if (m_FuseTicks <= 0)
{
- Destroy(true);
- LOGD("BOOM at {%f,%f,%f}", GetPosX(), GetPosY(), GetPosZ());
- m_World->DoExplosionAt(4.0, GetPosX() + 0.49, GetPosY() + 0.49, GetPosZ() + 0.49, true, esPrimedTNT, this);
- return;
+ Explode();
}
}
diff --git a/src/Entities/TNTEntity.h b/src/Entities/TNTEntity.h
index d1fcae766..116f5a8cb 100644
--- a/src/Entities/TNTEntity.h
+++ b/src/Entities/TNTEntity.h
@@ -16,19 +16,28 @@ public:
// tolua_end
CLASS_PROTODEF(cTNTEntity);
- cTNTEntity(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec);
- cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
+ cTNTEntity(double a_X, double a_Y, double a_Z, int a_FuseTicks = 80);
+ cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks = 80);
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
-
- double GetCounterTime(void) const { return m_Counter; } // tolua_export
- double GetMaxFuseTime(void) const { return m_MaxFuseTime; } // tolua_export
+
+ // tolua_begin
+
+ /** Explode the tnt */
+ void Explode(void);
+
+ /** Returns the fuse ticks until the tnt will explode */
+ int GetFuseTicks(void) const { return m_FuseTicks; }
+
+ /** Set the fuse ticks until the tnt will explode */
+ void SetFuseTicks(int a_FuseTicks) { m_FuseTicks = a_FuseTicks; }
+
+ // tolua_end
protected:
- double m_Counter; ///< How much time has elapsed since the object was created, in seconds
- double m_MaxFuseTime; ///< How long the fuse is, in seconds
+ int m_FuseTicks; ///< How much ticks is left, while the tnt will explode
}; // tolua_export
diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp
index 2e2276981..1810d7c49 100644
--- a/src/FurnaceRecipe.cpp
+++ b/src/FurnaceRecipe.cpp
@@ -175,7 +175,7 @@ void cFurnaceRecipe::ReloadRecipes(void)
{
LOGERROR("ERROR: FurnaceRecipe, syntax error" );
}
- LOG("Loaded %u furnace recipes and %u fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
+ LOG("Loaded " SIZE_T_FMT " furnace recipes and " SIZE_T_FMT " fuels", m_pState->Recipes.size(), m_pState->Fuel.size());
}
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index ef38f1399..73f0223e8 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -116,7 +116,7 @@ void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_Chunk
// Add to queue, issue a warning if too many:
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
{
- LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size());
+ LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (" SIZE_T_FMT ")", a_ChunkX, a_ChunkZ, m_Queue.size());
}
m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
}
@@ -180,7 +180,7 @@ BLOCKTYPE cChunkGenerator::GetIniBlock(cIniFile & a_IniFile, const AString & a_S
BLOCKTYPE Block = BlockStringToType(BlockType);
if (Block < 0)
{
- LOGWARN("[&s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
+ LOGWARN("[%s].%s Could not parse block value \"%s\". Using default: \"%s\".", a_SectionName.c_str(), a_ValueName.c_str(), BlockType.c_str(),a_Default.c_str());
return BlockStringToType(a_Default);
}
return Block;
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index e96e9a645..6c00b5905 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -22,6 +22,7 @@
#include "EndGen.h"
#include "MineShafts.h"
#include "Noise3DGenerator.h"
+#include "POCPieceGenerator.h"
#include "Ravines.h"
@@ -364,6 +365,10 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
m_FinishGens.push_back(new cStructGenOreNests(Seed));
}
+ else if (NoCaseCompare(*itr, "POCPieces") == 0)
+ {
+ m_FinishGens.push_back(new cPOCPieceGenerator(Seed));
+ }
else if (NoCaseCompare(*itr, "PreSimulator") == 0)
{
m_FinishGens.push_back(new cFinishGenPreSimulator);
diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp
new file mode 100644
index 000000000..9ed4b565e
--- /dev/null
+++ b/src/Generating/POCPieceGenerator.cpp
@@ -0,0 +1,270 @@
+
+// POCPieceGenerator.cpp
+
+// Implements the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
+// The generator generates a maze of rooms at {0, 50, 0}
+
+#include "Globals.h"
+#include "POCPieceGenerator.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+/** POC pieces are simple boxes that have connectors in the middle of their walls.
+Each wall has one connector, there are 3 connector types that get assigned semi-randomly.
+The piece also knows how to imprint itself in a cChunkDesc, each piece has a different color glass
+and each connector is uses a different color wool frame. */
+class cPOCPiece :
+ public cPiece
+{
+public:
+ cPOCPiece(int a_SizeXZ, int a_Height) :
+ m_SizeXZ(a_SizeXZ),
+ m_Height(a_Height)
+ {
+ m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, 0, 0, BLOCK_FACE_ZM));
+ m_Connectors.push_back(cConnector(m_SizeXZ / 2, a_Height / 2, m_SizeXZ - 1, 1, BLOCK_FACE_ZP));
+ m_Connectors.push_back(cConnector(0, a_Height / 2, m_SizeXZ / 2, 2, BLOCK_FACE_XM));
+ m_Connectors.push_back(cConnector(m_SizeXZ - 1, a_Height - 1, m_SizeXZ / 2, m_SizeXZ % 3, BLOCK_FACE_XP));
+ }
+
+
+ /** Imprints the piece in the specified chunk. Assumes they intersect. */
+ void ImprintInChunk(cChunkDesc & a_ChunkDesc, const Vector3i & a_Pos, int a_NumCCWRotations)
+ {
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ Vector3i Min = a_Pos;
+ Min.Move(-BlockX, 0, -BlockZ);
+ Vector3i Max = Min;
+ Max.Move(m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
+ ASSERT(Min.x < cChunkDef::Width);
+ ASSERT(Min.z < cChunkDef::Width);
+ ASSERT(Max.x >= 0);
+ ASSERT(Max.z >= 0);
+ if (Min.x >= 0)
+ {
+ // Draw the XM wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Min.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Min.z >= 0)
+ {
+ // Draw the ZM wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Min.z, Min.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Max.x < cChunkDef::Width)
+ {
+ // Draw the XP wall:
+ a_ChunkDesc.FillRelCuboid(Max.x, Max.x, Min.y, Max.y, Min.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+ if (Max.z < cChunkDef::Width)
+ {
+ // Draw the ZP wall:
+ a_ChunkDesc.FillRelCuboid(Min.x, Max.x, Min.y, Max.y, Max.z, Max.z, E_BLOCK_STAINED_GLASS, m_SizeXZ % 16);
+ }
+
+ // Draw all the connectors:
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ cConnector Conn = cPiece::RotateMoveConnector(*itr, a_NumCCWRotations, a_Pos.x, a_Pos.y, a_Pos.z);
+ Conn.m_Pos.Move(-BlockX, 0, -BlockZ);
+ if (
+ (Conn.m_Pos.x >= 0) && (Conn.m_Pos.x < cChunkDef::Width) &&
+ (Conn.m_Pos.z >= 0) && (Conn.m_Pos.z < cChunkDef::Width)
+ )
+ {
+ a_ChunkDesc.SetBlockTypeMeta(Conn.m_Pos.x, Conn.m_Pos.y, Conn.m_Pos.z, E_BLOCK_WOOL, itr->m_Type % 16);
+ }
+
+ /*
+ // TODO: Frame the connectors
+ switch (itr->m_Direction)
+ {
+ case BLOCK_FACE_XM:
+ case BLOCK_FACE_XP:
+ {
+ // TODO
+ break;
+ }
+
+ case BLOCK_FACE_ZM:
+ case BLOCK_FACE_ZP:
+ {
+ // TODO
+ break;
+ }
+ }
+ */
+ } // for itr - m_Connectors[]
+ }
+
+protected:
+ int m_SizeXZ;
+ int m_Height;
+ cConnectors m_Connectors;
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override
+ {
+ return m_Connectors;
+ }
+
+ virtual Vector3i GetSize(void) const override
+ {
+ return Vector3i(m_SizeXZ, m_Height, m_SizeXZ);
+ }
+
+ virtual cCuboid GetHitBox(void) const override
+ {
+ return cCuboid(0, 0, 0, m_SizeXZ - 1, m_Height - 1, m_SizeXZ - 1);
+ }
+
+ virtual bool CanRotateCCW(int a_NumRotations) const override
+ {
+ return true;
+ }
+};
+
+
+
+
+
+/*
+static void DebugPieces(const cPlacedPieces & a_Pieces)
+{
+ size_t idx = 0;
+ for (cPlacedPieces::const_iterator itr = a_Pieces.begin(), end = a_Pieces.end(); itr != end; ++itr, ++idx)
+ {
+ const cCuboid & HitBox = (*itr)->GetHitBox();
+ printf(" %u: %d rotations, {%d - %d, %d - %d}\n",
+ idx, (*itr)->GetNumCCWRotations(),
+ HitBox.p1.x, HitBox.p2.x, HitBox.p1.z, HitBox.p2.z
+ );
+ } // for itr - a_Pieces[]
+}
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPOCPieceGenerator:
+
+cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) :
+ m_Seed(a_Seed)
+{
+ // Prepare a vector of available pieces:
+ m_AvailPieces.push_back(new cPOCPiece(5, 3));
+ m_AvailPieces.push_back(new cPOCPiece(7, 5));
+ m_AvailPieces.push_back(new cPOCPiece(9, 5));
+ m_AvailPieces.push_back(new cPOCPiece(5, 7));
+
+ // Generate the structure:
+ cBFSPieceGenerator Gen(*this, a_Seed);
+ Gen.PlacePieces(0, 50, 0, 6, m_Pieces);
+
+ // DebugPieces(m_Pieces);
+
+ // Get the smallest cuboid encompassing the entire generated structure:
+ cCuboid Bounds(0, 50, 0, 0, 50, 0);
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ Vector3i MinCoords = (*itr)->GetCoords();
+ Bounds.Engulf(MinCoords);
+ Bounds.Engulf(MinCoords + (*itr)->GetPiece().GetSize());
+ } // for itr - m_Pieces[]
+ m_Bounds = Bounds;
+}
+
+
+
+
+
+cPOCPieceGenerator::~cPOCPieceGenerator()
+{
+ cPieceGenerator::FreePieces(m_Pieces);
+}
+
+
+
+
+
+void cPOCPieceGenerator::GenFinish(cChunkDesc & a_ChunkDesc)
+{
+ int BlockX = a_ChunkDesc.GetChunkX() * cChunkDef::Width;
+ int BlockZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width;
+ if (
+ (BlockX + 16 < m_Bounds.p1.x) || (BlockX > m_Bounds.p2.x) || // X coords out of bounds of the generated structure
+ (BlockZ + 16 < m_Bounds.p1.z) || (BlockZ > m_Bounds.p2.z) // Z coords out of bounds of the generated structure
+ )
+ {
+ return;
+ }
+
+ // Imprint each piece in the chunk:
+ for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ const Vector3i & Pos = (*itr)->GetCoords();
+ Vector3i Size = (*itr)->GetPiece().GetSize();
+ if (((*itr)->GetNumCCWRotations() % 2) == 1)
+ {
+ std::swap(Size.x, Size.z);
+ }
+ if (
+ (Pos.x >= BlockX + 16) || (Pos.x + Size.x - 1 < BlockX) ||
+ (Pos.z >= BlockZ + 16) || (Pos.z + Size.z - 1 < BlockZ)
+ )
+ {
+ // This piece doesn't intersect the chunk
+ continue;
+ }
+
+ ((cPOCPiece &)(*itr)->GetPiece()).ImprintInChunk(a_ChunkDesc, Pos, (*itr)->GetNumCCWRotations());
+ } // for itr - m_Pieces[]
+ a_ChunkDesc.UpdateHeightmap();
+}
+
+
+
+
+
+cPieces cPOCPieceGenerator::GetPiecesWithConnector(int a_ConnectorType)
+{
+ // Each piece has each connector
+ return m_AvailPieces;
+}
+
+
+
+
+
+cPieces cPOCPieceGenerator::GetStartingPieces(void)
+{
+ // Any piece can be a starting piece
+ return m_AvailPieces;
+}
+
+
+
+
+
+void cPOCPieceGenerator::PiecePlaced(const cPiece & a_Piece)
+{
+ UNUSED(a_Piece);
+}
+
+
+
+
+
+void cPOCPieceGenerator::Reset(void)
+{
+ // Nothing needed
+}
+
+
+
+
diff --git a/src/Generating/POCPieceGenerator.h b/src/Generating/POCPieceGenerator.h
new file mode 100644
index 000000000..de3114ce0
--- /dev/null
+++ b/src/Generating/POCPieceGenerator.h
@@ -0,0 +1,54 @@
+
+// POCPieceGenerator.h
+
+// Declares the cPOCPieceGenerator class representing a Proof-Of_Concept structure generator using the cPieceGenerator technique
+// The generator generates a maze of rooms at {0, 100, 0}
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "ComposableGenerator.h"
+
+
+
+
+
+class cPOCPieceGenerator :
+ public cFinishGen,
+ protected cPiecePool
+{
+public:
+ cPOCPieceGenerator(int a_Seed);
+ ~cPOCPieceGenerator();
+
+protected:
+ int m_Seed;
+
+ /** The pieces from which the generated structure is built. */
+ cPieces m_AvailPieces;
+
+ /** The placed pieces of the generated structure. */
+ cPlacedPieces m_Pieces;
+
+ /** Bounds of the complete structure, to save on processing outside chunks. */
+ cCuboid m_Bounds;
+
+
+ // cFinishGen overrides:
+ virtual void GenFinish(cChunkDesc & a_ChunkDesc) override;
+
+ // cPiecePool overrides:
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
+ virtual cPieces GetStartingPieces(void) override;
+ virtual void PiecePlaced(const cPiece & a_Piece) override;
+ virtual void Reset(void) override;
+} ;
+
+
+
+
+
diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp
new file mode 100644
index 000000000..8999a5ff7
--- /dev/null
+++ b/src/Generating/PieceGenerator.cpp
@@ -0,0 +1,625 @@
+
+// PieceGenerator.cpp
+
+// Implements the cBFSPieceGenerator class and cDFSPieceGenerator class
+// representing base classes for generating structures composed of individual "pieces"
+
+#include "Globals.h"
+#include "PieceGenerator.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Self-test:
+
+static class cPieceGeneratorSelfTest :
+ public cPiecePool
+{
+public:
+ cPieceGeneratorSelfTest(void)
+ {
+ // Prepare the internal state:
+ InitializePieces();
+
+ // Generate:
+ cBFSPieceGenerator Gen(*this, 0);
+ cPlacedPieces OutPieces;
+ Gen.PlacePieces(500, 50, 500, 3, OutPieces);
+
+ // Print out the pieces:
+ printf("OutPieces.size() = " SIZE_T_FMT "\n", OutPieces.size());
+ size_t idx = 0;
+ for (cPlacedPieces::const_iterator itr = OutPieces.begin(), end = OutPieces.end(); itr != end; ++itr, ++idx)
+ {
+ const Vector3i & Coords = (*itr)->GetCoords();
+ cCuboid Hitbox = (*itr)->GetHitBox();
+ Hitbox.Sort();
+ printf(SIZE_T_FMT ": {%d, %d, %d}, rot %d, hitbox {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n", idx,
+ Coords.x, Coords.y, Coords.z,
+ (*itr)->GetNumCCWRotations(),
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ } // itr - OutPieces[]
+ printf("Done.\n");
+
+ // Free the placed pieces properly:
+ Gen.FreePieces(OutPieces);
+ }
+
+ ~cPieceGeneratorSelfTest()
+ {
+ // Dealloc all the pieces:
+ for (cPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ }
+ m_Pieces.clear();
+ }
+
+protected:
+ class cTestPiece :
+ public cPiece
+ {
+ int m_Size;
+ public:
+ cTestPiece(int a_Size) :
+ m_Size(a_Size)
+ {
+ }
+
+ virtual cConnectors GetConnectors(void) const override
+ {
+ // Each piece has 4 connectors, one of each type, plus one extra, at the center of its walls:
+ cConnectors res;
+ res.push_back(cConnector(m_Size / 2, 1, 0, 0, BLOCK_FACE_ZM));
+ res.push_back(cConnector(m_Size / 2, 1, m_Size - 1, 1, BLOCK_FACE_ZP));
+ res.push_back(cConnector(0, 1, m_Size / 2, 2, BLOCK_FACE_XM));
+ res.push_back(cConnector(m_Size - 1, 1, m_Size / 2, m_Size % 3, BLOCK_FACE_XP));
+ return res;
+ }
+
+ virtual Vector3i GetSize(void) const override
+ {
+ return Vector3i(m_Size, 5, m_Size);
+ }
+
+ virtual cCuboid GetHitBox(void) const override
+ {
+ return cCuboid(0, 0, 0, m_Size - 1, 4, m_Size - 1);
+ }
+
+ virtual bool CanRotateCCW(int a_NumCCWRotations) const override
+ {
+ return true;
+ }
+ };
+
+ cPieces m_Pieces;
+
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override
+ {
+ // Each piece contains each connector
+ return m_Pieces;
+ }
+
+
+ virtual cPieces GetStartingPieces(void) override
+ {
+ return m_Pieces;
+ }
+
+
+ virtual void PiecePlaced(const cPiece & a_Piece) override
+ {
+ UNUSED(a_Piece);
+ }
+
+
+ virtual void Reset(void) override
+ {
+ }
+
+
+ void InitializePieces(void)
+ {
+ m_Pieces.push_back(new cTestPiece(5));
+ m_Pieces.push_back(new cTestPiece(7));
+ m_Pieces.push_back(new cTestPiece(9));
+ }
+} g_Test;
+
+#endif // SELF_TEST
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPiece:
+
+
+Vector3i cPiece::RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const
+{
+ Vector3i Size = GetSize();
+ switch (a_NumCCWRotations)
+ {
+ case 0:
+ {
+ // No rotation needed
+ return a_Pos;
+ }
+ case 1:
+ {
+ // 1 CCW rotation:
+ return Vector3i(a_Pos.z, a_Pos.y, Size.x - a_Pos.x - 1);
+ }
+ case 2:
+ {
+ // 2 rotations ( = axis flip):
+ return Vector3i(Size.x - a_Pos.x - 1, a_Pos.y, Size.z - a_Pos.z - 1);
+ }
+ case 3:
+ {
+ // 1 CW rotation:
+ return Vector3i(Size.z - a_Pos.z - 1, a_Pos.y, a_Pos.x);
+ }
+ }
+ ASSERT(!"Unhandled rotation");
+ return a_Pos;
+}
+
+
+
+
+
+cPiece::cConnector cPiece::RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
+{
+ cPiece::cConnector res(a_Connector);
+
+ // Rotate the res connector:
+ switch (a_NumCCWRotations)
+ {
+ case 0:
+ {
+ // No rotation needed
+ break;
+ }
+ case 1:
+ {
+ // 1 CCW rotation:
+ res.m_Direction = RotateBlockFaceCCW(res.m_Direction);
+ break;
+ }
+ case 2:
+ {
+ // 2 rotations ( = axis flip):
+ res.m_Direction = MirrorBlockFaceY(res.m_Direction);
+ break;
+ }
+ case 3:
+ {
+ // 1 CW rotation:
+ res.m_Direction = RotateBlockFaceCW(res.m_Direction);
+ break;
+ }
+ }
+ res.m_Pos = RotatePos(a_Connector.m_Pos, a_NumCCWRotations);
+
+ // Move the res connector:
+ res.m_Pos.x += a_MoveX;
+ res.m_Pos.y += a_MoveY;
+ res.m_Pos.z += a_MoveZ;
+
+ return res;
+}
+
+
+
+
+
+cCuboid cPiece::RotateHitBoxToConnector(
+ const cPiece::cConnector & a_MyConnector,
+ const Vector3i & a_ToConnectorPos,
+ int a_NumCCWRotations
+) const
+{
+ ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
+ Vector3i ConnPos = RotatePos(a_MyConnector.m_Pos, a_NumCCWRotations);
+ ConnPos = a_ToConnectorPos - ConnPos;
+ return RotateMoveHitBox(a_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z);
+}
+
+
+
+
+
+cCuboid cPiece::RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const
+{
+ ASSERT(a_NumCCWRotations == (a_NumCCWRotations % 4));
+ cCuboid res = GetHitBox();
+ res.p1 = RotatePos(res.p1, a_NumCCWRotations);
+ res.p2 = RotatePos(res.p2, a_NumCCWRotations);
+ res.p1.Move(a_MoveX, a_MoveY, a_MoveZ);
+ res.p2.Move(a_MoveX, a_MoveY, a_MoveZ);
+ return res;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPiece::cConnector:
+
+cPiece::cConnector::cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction) :
+ m_Pos(a_X, a_Y, a_Z),
+ m_Type(a_Type),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+cPiece::cConnector::cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction) :
+ m_Pos(a_Pos),
+ m_Type(a_Type),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPlacedPiece:
+
+cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations) :
+ m_Parent(a_Parent),
+ m_Piece(&a_Piece),
+ m_Coords(a_Coords),
+ m_NumCCWRotations(a_NumCCWRotations)
+{
+ m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1);
+ m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z);
+ m_HitBox.Sort();
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator:
+
+cPieceGenerator::cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
+ m_PiecePool(a_PiecePool),
+ m_Noise(a_Seed),
+ m_Seed(a_Seed)
+{
+}
+
+
+
+
+
+void cPieceGenerator::FreePieces(cPlacedPieces & a_PlacedPieces)
+{
+ for (cPlacedPieces::iterator itr = a_PlacedPieces.begin(), end = a_PlacedPieces.end(); itr != end; ++itr)
+ {
+ delete *itr;
+ } // for itr - a_PlacedPieces[]
+ a_PlacedPieces.clear();
+}
+
+
+
+
+
+cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors)
+{
+ m_PiecePool.Reset();
+ int rnd = m_Noise.IntNoise3DInt(a_BlockX, a_BlockY, a_BlockZ) / 7;
+
+ // Choose a random one of the starting pieces:
+ cPieces StartingPieces = m_PiecePool.GetStartingPieces();
+ cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()];
+ rnd = rnd >> 16;
+
+ // Choose a random supported rotation:
+ int Rotations[4] = {0};
+ int NumRotations = 1;
+ for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++)
+ {
+ if (StartingPiece->CanRotateCCW(i))
+ {
+ Rotations[NumRotations] = i;
+ NumRotations += 1;
+ }
+ }
+ int Rotation = Rotations[rnd % NumRotations];
+
+ cPlacedPiece * res = new cPlacedPiece(NULL, *StartingPiece, Vector3i(a_BlockX, a_BlockY, a_BlockZ), Rotation);
+
+ // Place the piece's connectors into a_OutConnectors:
+ const cPiece::cConnectors & Conn = StartingPiece->GetConnectors();
+ for (cPiece::cConnectors::const_iterator itr = Conn.begin(), end = Conn.end(); itr != end; ++itr)
+ {
+ a_OutConnectors.push_back(
+ cFreeConnector(res, StartingPiece->RotateMoveConnector(*itr, Rotation, a_BlockX, a_BlockY, a_BlockZ))
+ );
+ }
+
+ return res;
+}
+
+
+
+
+
+bool cPieceGenerator::TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece,
+ const cPiece::cConnector & a_Connector,
+ cPlacedPieces & a_OutPieces,
+ cPieceGenerator::cFreeConnectors & a_OutConnectors
+)
+{
+ // Translation of direction - direction -> number of CCW rotations needed:
+ // You need DirectionRotationTable[rot1][rot2] CCW turns to connect rot1 to rot2 (they are opposite)
+ static const int DirectionRotationTable[6][6] =
+ {
+ /* YM, YP, ZM, ZP, XM, XP */
+ /* YM */ { 0, 0, 0, 0, 0, 0},
+ /* YP */ { 0, 0, 0, 0, 0, 0},
+ /* ZM */ { 0, 0, 2, 0, 1, 3},
+ /* ZP */ { 0, 0, 0, 2, 3, 1},
+ /* XM */ { 0, 0, 3, 1, 2, 0},
+ /* XP */ { 0, 0, 1, 3, 0, 2},
+ };
+
+ // Get a list of available connections:
+ const int * RotTable = DirectionRotationTable[a_Connector.m_Direction];
+ cConnections Connections;
+ cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type);
+ Connections.reserve(AvailablePieces.size());
+ Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
+ AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
+
+ /*
+ // DEBUG:
+ printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
+ //*/
+
+ for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
+ {
+ cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
+ for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
+ {
+ if (itrC->m_Type != a_Connector.m_Type)
+ {
+ continue;
+ }
+ // This is a same-type connector, find out how to rotate to it:
+ int NumCCWRotations = RotTable[itrC->m_Direction];
+ if (!(*itrP)->CanRotateCCW(NumCCWRotations))
+ {
+ // Doesn't support this rotation
+ continue;
+ }
+ if (!CheckConnection(a_Connector, ConnPos, **itrP, *itrC, NumCCWRotations, a_OutPieces))
+ {
+ // Doesn't fit in this rotation
+ continue;
+ }
+ Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
+ } // for itrC - Connectors[]
+ } // for itrP - AvailablePieces[]
+ if (Connections.empty())
+ {
+ // No available connections, bail out
+ return false;
+ }
+
+ // Choose a random connection from the list:
+ int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
+ cConnection & Conn = Connections[rnd % Connections.size()];
+
+ // Place the piece:
+ /*
+ // DEBUG
+ printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
+ Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
+ BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
+ Conn.m_NumCCWRotations
+ );
+ //*/
+
+ Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
+ ConnPos -= NewPos;
+ cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
+ a_OutPieces.push_back(PlacedPiece);
+
+ // Add the new piece's connectors to the list of free connectors:
+ cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
+
+ /*
+ // DEBUG:
+ printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
+ //*/
+
+ for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
+ {
+ // This is the connector through which we have been connected to the parent, don't add
+ continue;
+ }
+ a_OutConnectors.push_back(cFreeConnector(PlacedPiece, Conn.m_Piece->RotateMoveConnector(*itr, Conn.m_NumCCWRotations, ConnPos.x, ConnPos.y, ConnPos.z)));
+ }
+
+ return true;
+}
+
+
+
+
+
+bool cPieceGenerator::CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector,
+ const Vector3i & a_ToPos,
+ const cPiece & a_Piece,
+ const cPiece::cConnector & a_NewConnector,
+ int a_NumCCWRotations,
+ const cPlacedPieces & a_OutPieces
+)
+{
+ // For each placed piece, test the hitbox against the new piece:
+ cCuboid RotatedHitBox = a_Piece.RotateHitBoxToConnector(a_NewConnector, a_ToPos, a_NumCCWRotations);
+ RotatedHitBox.Sort();
+ for (cPlacedPieces::const_iterator itr = a_OutPieces.begin(), end = a_OutPieces.end(); itr != end; ++itr)
+ {
+ if ((*itr)->GetHitBox().DoesIntersect(RotatedHitBox))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+
+//*
+// DEBUG:
+void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed)
+{
+ printf(" Connector pool: " SIZE_T_FMT " items\n", a_ConnectorPool.size() - a_NumProcessed);
+ size_t idx = 0;
+ for (cPieceGenerator::cFreeConnectors::const_iterator itr = a_ConnectorPool.begin() + a_NumProcessed, end = a_ConnectorPool.end(); itr != end; ++itr, ++idx)
+ {
+ printf(" " SIZE_T_FMT ": {%d, %d, %d}, type %d, direction %s, depth %d\n",
+ idx,
+ itr->m_Connector.m_Pos.x, itr->m_Connector.m_Pos.y, itr->m_Connector.m_Pos.z,
+ itr->m_Connector.m_Type,
+ BlockFaceToString(itr->m_Connector.m_Direction).c_str(),
+ itr->m_Piece->GetDepth()
+ );
+ } // for itr - a_ConnectorPool[]
+}
+//*/
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator::cConnection:
+
+cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
+ m_Piece(&a_Piece),
+ m_Connector(a_Connector),
+ m_NumCCWRotations(a_NumCCWRotations)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cPieceGenerator::cFreeConnector:
+
+cPieceGenerator::cFreeConnector::cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector) :
+ m_Piece(a_Piece),
+ m_Connector(a_Connector)
+{
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cBFSPieceGenerator:
+
+cBFSPieceGenerator::cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed) :
+ super(a_PiecePool, a_Seed)
+{
+}
+
+
+
+
+
+void cBFSPieceGenerator::PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces)
+{
+ a_OutPieces.clear();
+ cFreeConnectors ConnectorPool;
+
+ // Place the starting piece:
+ a_OutPieces.push_back(PlaceStartingPiece(a_BlockX, a_BlockY, a_BlockZ, ConnectorPool));
+
+ /*
+ // DEBUG:
+ printf("Placed the starting piece at {%d, %d, %d}\n", a_BlockX, a_BlockY, a_BlockZ);
+ cCuboid Hitbox = a_OutPieces[0]->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, 0);
+ //*/
+
+ // Place pieces at the available connectors:
+ /*
+ Instead of removing them one by one from the pool, we process them sequentially and take note of the last
+ processed one. To save on memory, once the number of processed connectors reaches a big number, a chunk
+ of the connectors is removed.
+ */
+ size_t NumProcessed = 0;
+ while (ConnectorPool.size() > NumProcessed)
+ {
+ cFreeConnector & Conn = ConnectorPool[NumProcessed];
+ if (Conn.m_Piece->GetDepth() < a_MaxDepth)
+ {
+ if (TryPlacePieceAtConnector(*Conn.m_Piece, Conn.m_Connector, a_OutPieces, ConnectorPool))
+ {
+ /*
+ // DEBUG:
+ const cPlacedPiece * NewPiece = a_OutPieces.back();
+ const Vector3i & Coords = NewPiece->GetCoords();
+ printf("Placed a new piece at {%d, %d, %d}, rotation %d\n", Coords.x, Coords.y, Coords.z, NewPiece->GetNumCCWRotations());
+ cCuboid Hitbox = NewPiece->GetHitBox();
+ Hitbox.Sort();
+ printf(" Hitbox: {%d, %d, %d} - {%d, %d, %d} (%d * %d * %d)\n",
+ Hitbox.p1.x, Hitbox.p1.y, Hitbox.p1.z,
+ Hitbox.p2.x, Hitbox.p2.y, Hitbox.p2.z,
+ Hitbox.DifX() + 1, Hitbox.DifY() + 1, Hitbox.DifZ() + 1
+ );
+ DebugConnectorPool(ConnectorPool, NumProcessed + 1);
+ //*/
+ }
+ }
+ NumProcessed++;
+ if (NumProcessed > 1000)
+ {
+ ConnectorPool.erase(ConnectorPool.begin(), ConnectorPool.begin() + NumProcessed);
+ NumProcessed = 0;
+ }
+ }
+}
+
+
+
+
diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h
new file mode 100644
index 000000000..bef9d3463
--- /dev/null
+++ b/src/Generating/PieceGenerator.h
@@ -0,0 +1,247 @@
+
+// PieceGenerator.h
+
+// Declares the cBFSPieceGenerator class and cDFSPieceGenerator class
+// representing base classes for generating structures composed of individual "pieces"
+
+/*
+Each uses a slightly different approach to generating:
+ - DFS extends pieces one by one until it hits the configured depth (or can't connect another piece anymore),
+ then starts looking at adjacent connectors (like depth-first search).
+ - BFS keeps a pool of currently-open connectors, chooses one at random and tries to place a piece on it,
+ thus possibly extending the pool of open connectors (like breadth-first search).
+*/
+
+
+
+
+
+#pragma once
+
+#include "../Defines.h"
+#include "../Cuboid.h"
+#include "../Noise.h"
+
+
+
+
+
+/** Represents a single piece. Can have multiple connectors of different types where other pieces can connect. */
+class cPiece
+{
+public:
+ // Force a virtual destructor in all descendants
+ virtual ~cPiece() {}
+
+ struct cConnector
+ {
+ /** Position relative to the piece */
+ Vector3i m_Pos;
+
+ /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */
+ int m_Type;
+
+ /** Direction in which the connector is facing.
+ Will be matched by the opposite direction for the connecting connector. */
+ eBlockFace m_Direction;
+
+ cConnector(int a_X, int a_Y, int a_Z, int a_Type, eBlockFace a_Direction);
+ cConnector(const Vector3i & a_Pos, int a_Type, eBlockFace a_Direction);
+ };
+
+ typedef std::vector<cConnector> cConnectors;
+
+ /** Returns all of the available connectors that the piece has.
+ Each connector has a (relative) position in the piece, and a type associated with it. */
+ virtual cConnectors GetConnectors(void) const = 0;
+
+ /** Returns the dimensions of this piece.
+ The dimensions cover the entire piece, there is no block that the piece generates outside of this size. */
+ virtual Vector3i GetSize(void) const = 0;
+
+ /** Returns the "hitbox" of this piece.
+ A hitbox is what is compared and must not intersect other pieces' hitboxes when generating. */
+ virtual cCuboid GetHitBox(void) const = 0;
+
+ /** Returns true if the piece can be rotated CCW the specific number of 90-degree turns. */
+ virtual bool CanRotateCCW(int a_NumRotations) const = 0;
+
+ /** Returns a copy of the a_Pos after rotating the piece the specified number of CCW rotations. */
+ Vector3i RotatePos(const Vector3i & a_Pos, int a_NumCCWRotations) const;
+
+ /** Returns a copy of the connector that is rotated and then moved by the specified amounts. */
+ cConnector RotateMoveConnector(const cConnector & a_Connector, int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+
+ /** Returns the hitbox after the specified number of rotations and moved so that a_MyConnector is placed at a_ToConnectorPos. */
+ cCuboid RotateHitBoxToConnector(const cConnector & a_MyConnector, const Vector3i & a_ToConnectorPos, int a_NumCCWRotations) const;
+
+ /** Returns the hitbox after the specified number of CCW rotations and moved by the specified amounts. */
+ cCuboid RotateMoveHitBox(int a_NumCCWRotations, int a_MoveX, int a_MoveY, int a_MoveZ) const;
+};
+
+typedef std::vector<cPiece *> cPieces;
+
+
+
+
+
+/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
+placed and adjust the returned piece vectors. */
+class cPiecePool
+{
+public:
+ // Force a virtual destructor in all descendants:
+ virtual ~cPiecePool() {}
+
+ /** Returns a list of pieces that contain the specified connector type.
+ The cPiece pointers returned are managed by the pool and the caller doesn't free them. */
+ virtual cPieces GetPiecesWithConnector(int a_ConnectorType) = 0;
+
+ /** Returns the pieces that should be used as the starting point.
+ Multiple starting points are supported, one of the returned piece will be chosen. */
+ virtual cPieces GetStartingPieces(void) = 0;
+
+ /** Called after a piece is placed, to notify the pool that it has been used.
+ The pool may adjust the pieces it will return the next time. */
+ virtual void PiecePlaced(const cPiece & a_Piece) = 0;
+
+ /** Called when the pool has finished the current structure and should reset any piece-counters it has
+ for a new structure. */
+ virtual void Reset(void) = 0;
+};
+
+
+
+
+
+/** Represents a single piece that has been placed to specific coords in the world. */
+class cPlacedPiece
+{
+public:
+ cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations);
+
+ const cPiece & GetPiece (void) const { return *m_Piece; }
+ const Vector3i & GetCoords (void) const { return m_Coords; }
+ int GetNumCCWRotations(void) const { return m_NumCCWRotations; }
+ const cCuboid & GetHitBox (void) const { return m_HitBox; }
+ int GetDepth (void) const { return m_Depth; }
+
+protected:
+ const cPlacedPiece * m_Parent;
+ const cPiece * m_Piece;
+ Vector3i m_Coords;
+ int m_NumCCWRotations;
+ cCuboid m_HitBox;
+ int m_Depth;
+};
+
+typedef std::vector<cPlacedPiece *> cPlacedPieces;
+
+
+
+
+
+class cPieceGenerator
+{
+public:
+ cPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Cleans up all the memory used by the placed pieces.
+ Call this utility function instead of freeing the items on your own. */
+ static void FreePieces(cPlacedPieces & a_PlacedPieces);
+
+protected:
+ /** The type used for storing a connection from one piece to another, while building the piece tree. */
+ struct cConnection
+ {
+ cPiece * m_Piece; // The piece being connected
+ cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
+ int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
+
+ cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations);
+ };
+ typedef std::vector<cConnection> cConnections;
+
+ /** The type used for storing a pool of connectors that will be attempted to expand by another piece. */
+ struct cFreeConnector
+ {
+ cPlacedPiece * m_Piece;
+ cPiece::cConnector m_Connector;
+
+ cFreeConnector(cPlacedPiece * a_Piece, const cPiece::cConnector & a_Connector);
+ };
+ typedef std::vector<cFreeConnector> cFreeConnectors;
+
+
+ cPiecePool & m_PiecePool;
+ cNoise m_Noise;
+ int m_Seed;
+
+
+ /** Selects a starting piece and places it, including the rotations.
+ Also puts the piece's connectors in a_OutConnectors. */
+ cPlacedPiece * PlaceStartingPiece(int a_BlockX, int a_BlockY, int a_BlockZ, cFreeConnectors & a_OutConnectors);
+
+ /** Tries to place a new piece at the specified (placed) connector. Returns true if successful. */
+ bool TryPlacePieceAtConnector(
+ const cPlacedPiece & a_ParentPiece, // The existing piece to a new piece should be placed
+ const cPiece::cConnector & a_Connector, // The existing connector (world-coords) to which a new piece should be placed
+ cPlacedPieces & a_OutPieces, // Already placed pieces, to be checked for intersections
+ cFreeConnectors & a_OutConnectors // List of free connectors to which the new connectors will be placed
+ );
+
+ /** Checks if the specified piece would fit with the already-placed pieces, using the specified connector
+ and number of CCW rotations.
+ a_ExistingConnector is in world-coords and is already rotated properly
+ a_ToPos is the world-coords position on which the new connector should be placed (1 block away from a_ExistingConnector, in its Direction)
+ a_NewConnector is in the original (non-rotated) coords.
+ Returns true if the piece fits, false if not. */
+ bool CheckConnection(
+ const cPiece::cConnector & a_ExistingConnector, // The existing connector
+ const Vector3i & a_ToPos, // The position on which the new connector should be placed
+ const cPiece & a_Piece, // The new piece
+ const cPiece::cConnector & a_NewConnector, // The connector of the new piece
+ int a_NumCCWRotations, // Number of rotations for the new piece to align the connector
+ const cPlacedPieces & a_OutPieces // All the already-placed pieces to check
+ );
+
+ /** DEBUG: Outputs all the connectors in the pool into stdout.
+ a_NumProcessed signals the number of connectors from the pool that should be considered processed (not listed). */
+ void DebugConnectorPool(const cPieceGenerator::cFreeConnectors & a_ConnectorPool, size_t a_NumProcessed);
+} ;
+
+
+
+
+
+class cBFSPieceGenerator :
+ public cPieceGenerator
+{
+ typedef cPieceGenerator super;
+
+public:
+ cBFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Generates a placement for pieces at the specified coords.
+ Caller must free each individual cPlacedPiece in a_OutPieces. */
+ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MaxDepth, cPlacedPieces & a_OutPieces);
+};
+
+
+
+
+
+class cDFSPieceGenerator :
+ public cPieceGenerator
+{
+public:
+ cDFSPieceGenerator(cPiecePool & a_PiecePool, int a_Seed);
+
+ /** Generates a placement for pieces at the specified coords.
+ Caller must free each individual cPlacedPiece in a_OutPieces. */
+ void PlacePieces(int a_BlockX, int a_BlockY, int a_BlockZ, cPlacedPieces & a_OutPieces);
+};
+
+
+
+
diff --git a/src/Globals.h b/src/Globals.h
index 28805a83f..3e62832b7 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -38,6 +38,15 @@
// No alignment needed in MSVC
#define ALIGN_8
#define ALIGN_16
+
+ #define FORMATSTRING(formatIndex, va_argsIndex)
+
+ // MSVC has its own custom version of zu format
+ #define SIZE_T_FMT "%Iu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "Iu"
+ #define SIZE_T_FMT_HEX "%Ix"
+
+ #define NORETURN __declspec(noreturn)
#elif defined(__GNUC__)
@@ -56,6 +65,14 @@
// Some portability macros :)
#define stricmp strcasecmp
+
+ #define FORMATSTRING(formatIndex, va_argsIndex) __attribute__((format (printf, formatIndex, va_argsIndex)))
+
+ #define SIZE_T_FMT "%zu"
+ #define SIZE_T_FMT_PRECISION(x) "%" #x "zu"
+ #define SIZE_T_FMT_HEX "%zx"
+
+ #define NORETURN __attribute((__noreturn__))
#else
@@ -81,7 +98,14 @@
#endif
+#ifdef _DEBUG
+ #define NORETURNDEBUG NORETURN
+#else
+ #define NORETURNDEBUG
+#endif
+
+#include <stddef.h>
// Integral types with predefined sizes:
@@ -96,8 +120,23 @@ typedef unsigned short UInt16;
typedef unsigned char Byte;
+// If you get an error about specialization check the size of integral types
+template <typename T, size_t Size, bool x = sizeof(T) == Size>
+class SizeChecker;
+template <typename T, size_t Size>
+class SizeChecker<T, Size, true>
+{
+ T v;
+};
+
+template class SizeChecker<Int64, 8>;
+template class SizeChecker<Int32, 4>;
+template class SizeChecker<Int16, 2>;
+template class SizeChecker<UInt64, 8>;
+template class SizeChecker<UInt32, 4>;
+template class SizeChecker<UInt16, 2>;
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for any class that shouldn't allow copying itself
@@ -179,7 +218,7 @@ typedef unsigned char Byte;
#include <memory>
#include <set>
#include <queue>
-
+#include <limits>
@@ -220,9 +259,10 @@ typedef unsigned char Byte;
// Pretty much the same as ASSERT() but stays in Release builds
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
-
-
-
+// Same as assert but in all Self test builds
+#ifdef SELF_TEST
+#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
+#endif
/// A generic interface used mainly in ForEach() functions
template <typename Type> class cItemCallback
@@ -246,6 +286,14 @@ T Clamp(T a_Value, T a_Min, T a_Max)
+#ifndef TOLUA_TEMPLATE_BIND
+#define TOLUA_TEMPLATE_BIND(x)
+#endif
+
+
+
+
+
// Common headers (part 2, with macros):
#include "ChunkDef.h"
#include "BiomeDef.h"
@@ -254,5 +302,3 @@ T Clamp(T a_Value, T a_Min, T a_Max)
#include "Entities/Effects.h"
-
-
diff --git a/src/Item.cpp b/src/Item.cpp
index 9170006b6..856b68be6 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -1,4 +1,4 @@
-
+
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Item.h"
@@ -139,6 +139,16 @@ void cItem::GetJson(Json::Value & a_OutValue) const
{
a_OutValue["Lore"] = m_Lore;
}
+
+ if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ a_OutValue["Flicker"] = m_FireworkItem.m_HasFlicker;
+ a_OutValue["Trail"] = m_FireworkItem.m_HasTrail;
+ a_OutValue["Type"] = m_FireworkItem.m_Type;
+ a_OutValue["FlightTimeInTicks"] = m_FireworkItem.m_FlightTimeInTicks;
+ a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem);
+ a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem);
+ }
}
}
@@ -157,6 +167,16 @@ void cItem::FromJson(const Json::Value & a_Value)
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
m_CustomName = a_Value.get("Name", "").asString();
m_Lore = a_Value.get("Lore", "").asString();
+
+ if ((m_ItemType == E_ITEM_FIREWORK_ROCKET) || (m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ m_FireworkItem.m_HasFlicker = a_Value.get("Flicker", false).asBool();
+ m_FireworkItem.m_HasTrail = a_Value.get("Trail", false).asBool();
+ m_FireworkItem.m_Type = (NIBBLETYPE)a_Value.get("Type", 0).asInt();
+ m_FireworkItem.m_FlightTimeInTicks = (short)a_Value.get("FlightTimeInTicks", 0).asInt();
+ m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem);
+ m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem);
+ }
}
}
@@ -196,7 +216,7 @@ cItem * cItems::Get(int a_Idx)
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently %d items. Returning a nil.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to get an out-of-bounds item at index %d; there are currently " SIZE_T_FMT " items. Returning a nil.", a_Idx, size());
return NULL;
}
return &at(a_Idx);
@@ -210,7 +230,7 @@ void cItems::Set(int a_Idx, const cItem & a_Item)
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently %d items. Not setting.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Not setting.", a_Idx, size());
return;
}
at(a_Idx) = a_Item;
@@ -224,7 +244,7 @@ void cItems::Delete(int a_Idx)
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to delete an item at an out-of-bounds index %d; there are currently %d items. Ignoring.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to delete an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Ignoring.", a_Idx, size());
return;
}
erase(begin() + a_Idx);
@@ -238,7 +258,7 @@ void cItems::Set(int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDama
{
if ((a_Idx < 0) || (a_Idx >= (int)size()))
{
- LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently %d items. Not setting.", a_Idx, size());
+ LOGWARNING("cItems: Attempt to set an item at an out-of-bounds index %d; there are currently " SIZE_T_FMT " items. Not setting.", a_Idx, size());
return;
}
at(a_Idx) = cItem(a_ItemType, a_ItemCount, a_ItemDamage);
diff --git a/src/Item.h b/src/Item.h
index cc3b3c961..4bdfb12dd 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -11,6 +11,7 @@
#include "Defines.h"
#include "Enchantments.h"
+#include "WorldStorage/FireworksSerializer.h"
@@ -38,7 +39,8 @@ public:
m_ItemCount(0),
m_ItemDamage(0),
m_CustomName(""),
- m_Lore("")
+ m_Lore(""),
+ m_FireworkItem()
{
}
@@ -57,7 +59,8 @@ public:
m_ItemDamage (a_ItemDamage),
m_Enchantments(a_Enchantments),
m_CustomName (a_CustomName),
- m_Lore (a_Lore)
+ m_Lore (a_Lore),
+ m_FireworkItem()
{
if (!IsValidItem(m_ItemType))
{
@@ -77,7 +80,8 @@ public:
m_ItemDamage (a_CopyFrom.m_ItemDamage),
m_Enchantments(a_CopyFrom.m_Enchantments),
m_CustomName (a_CopyFrom.m_CustomName),
- m_Lore (a_CopyFrom.m_Lore)
+ m_Lore (a_CopyFrom.m_Lore),
+ m_FireworkItem(a_CopyFrom.m_FireworkItem)
{
}
@@ -90,6 +94,7 @@ public:
m_Enchantments.Clear();
m_CustomName = "";
m_Lore = "";
+ m_FireworkItem.EmptyData();
}
@@ -115,7 +120,8 @@ public:
(m_ItemDamage == a_Item.m_ItemDamage) &&
(m_Enchantments == a_Item.m_Enchantments) &&
(m_CustomName == a_Item.m_CustomName) &&
- (m_Lore == a_Item.m_Lore)
+ (m_Lore == a_Item.m_Lore) &&
+ m_FireworkItem.IsEqualTo(a_Item.m_FireworkItem)
);
}
@@ -177,6 +183,8 @@ public:
cEnchantments m_Enchantments;
AString m_CustomName;
AString m_Lore;
+
+ cFireworkItem m_FireworkItem;
};
// tolua_end
diff --git a/src/Items/ItemCake.h b/src/Items/ItemCake.h
new file mode 100644
index 000000000..48e23ed59
--- /dev/null
+++ b/src/Items/ItemCake.h
@@ -0,0 +1,41 @@
+
+#pragma once
+
+#include "ItemHandler.h"
+
+
+
+
+
+class cItemCakeHandler :
+ public cItemHandler
+{
+public:
+ cItemCakeHandler(int a_ItemType) :
+ cItemHandler(a_ItemType)
+ {
+ }
+
+
+ virtual bool IsPlaceable(void) override
+ {
+ return true;
+ }
+
+
+ virtual bool GetPlacementBlockTypeMeta(
+ cWorld * a_World, cPlayer * a_Player,
+ int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
+ int a_CursorX, int a_CursorY, int a_CursorZ,
+ BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
+ ) override
+ {
+ a_BlockType = E_BLOCK_CAKE;
+ a_BlockMeta = 0;
+ return true;
+ }
+} ;
+
+
+
+
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 1d357fcf1..454fabdd7 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -13,6 +13,7 @@
#include "ItemBow.h"
#include "ItemBrewingStand.h"
#include "ItemBucket.h"
+#include "ItemCake.h"
#include "ItemCauldron.h"
#include "ItemCloth.h"
#include "ItemComparator.h"
@@ -94,6 +95,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
// Single item per handler, alphabetically sorted:
case E_BLOCK_LEAVES: return new cItemLeavesHandler(a_ItemType);
+ case E_BLOCK_NEW_LEAVES: return new cItemLeavesHandler(a_ItemType);
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
@@ -101,12 +103,14 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler();
case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
+ case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_COMPARATOR: return new cItemComparatorHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
case E_ITEM_EGG: return new cItemEggHandler();
case E_ITEM_EMPTY_MAP: return new cItemEmptyMapHandler();
case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
+ case E_ITEM_FIRE_CHARGE: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FIREWORK_ROCKET: return new cItemFireworkHandler();
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
@@ -337,6 +341,7 @@ char cItemHandler::GetMaxStackSize(void)
case E_ITEM_BREWING_STAND: return 64;
case E_ITEM_BUCKET: return 16;
case E_ITEM_CARROT: return 64;
+ case E_ITEM_CAKE: return 1;
case E_ITEM_CAULDRON: return 64;
case E_ITEM_CLAY: return 64;
case E_ITEM_CLAY_BRICK: return 64;
diff --git a/src/Items/ItemItemFrame.h b/src/Items/ItemItemFrame.h
index 74e987445..27e7dba35 100644
--- a/src/Items/ItemItemFrame.h
+++ b/src/Items/ItemItemFrame.h
@@ -34,7 +34,11 @@ public:
if (Block == E_BLOCK_AIR)
{
cItemFrame * ItemFrame = new cItemFrame(a_Dir, a_BlockX, a_BlockY, a_BlockZ);
- ItemFrame->Initialize(a_World);
+ if (!ItemFrame->Initialize(a_World))
+ {
+ delete ItemFrame;
+ return false;
+ }
if (!a_Player->IsGameModeCreative())
{
diff --git a/src/Items/ItemLighter.h b/src/Items/ItemLighter.h
index cc7daeb08..2db6c829a 100644
--- a/src/Items/ItemLighter.h
+++ b/src/Items/ItemLighter.h
@@ -26,15 +26,34 @@ public:
return false;
}
- a_Player->UseEquippedItem();
+ if (!a_Player->IsGameModeCreative())
+ {
+ switch (m_ItemType)
+ {
+ case E_ITEM_FLINT_AND_STEEL:
+ {
+ a_Player->UseEquippedItem();
+ break;
+ }
+ case E_ITEM_FIRE_CHARGE:
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unknown Lighter Item!");
+ }
+ }
+ }
switch (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ))
{
case E_BLOCK_TNT:
{
// Activate the TNT:
- a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f);
+ a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
break;
}
@@ -49,6 +68,7 @@ public:
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
{
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
+ a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F);
break;
}
}
diff --git a/src/Items/ItemShears.h b/src/Items/ItemShears.h
index b8f75f5ba..39d2776fa 100644
--- a/src/Items/ItemShears.h
+++ b/src/Items/ItemShears.h
@@ -28,10 +28,10 @@ public:
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override
{
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if (Block == E_BLOCK_LEAVES)
+ if ((Block == E_BLOCK_LEAVES) || (Block == E_BLOCK_NEW_LEAVES))
{
cItems Drops;
- Drops.push_back(cItem(E_BLOCK_LEAVES, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
+ Drops.push_back(cItem(Block, 1, a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x03));
a_World->SpawnItemPickups(Drops, a_BlockX, a_BlockY, a_BlockZ);
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
@@ -49,6 +49,7 @@ public:
case E_BLOCK_COBWEB:
case E_BLOCK_VINES:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
return true;
}
diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h
index 46049f961..c6a4e714e 100644
--- a/src/Items/ItemThrowable.h
+++ b/src/Items/ItemThrowable.h
@@ -35,7 +35,7 @@ public:
Vector3d Pos = a_Player->GetThrowStartPos();
Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
- a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
+ a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed);
return true;
}
@@ -127,13 +127,13 @@ public:
return false;
}
+ a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem());
+
if (!a_Player->IsGameModeCreative())
{
a_Player->GetInventory().RemoveOneEquippedItem();
}
- a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, 0);
-
return true;
}
diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp
index 44dadb8a9..302473d71 100644
--- a/src/LightingThread.cpp
+++ b/src/LightingThread.cpp
@@ -13,12 +13,6 @@
-/// If more than this many chunks are in the queue, a warning is printed to the log
-#define WARN_ON_QUEUE_SIZE 800
-
-
-
-
/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]:
class cReader :
diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp
index da1c7f2fd..f4f29e833 100644
--- a/src/LineBlockTracer.cpp
+++ b/src/LineBlockTracer.cpp
@@ -5,7 +5,7 @@
#include "Globals.h"
#include "LineBlockTracer.h"
-#include "Vector3d.h"
+#include "Vector3.h"
#include "World.h"
#include "Chunk.h"
diff --git a/src/Log.cpp b/src/Log.cpp
index 1ea327d5d..a7be04b1a 100644
--- a/src/Log.cpp
+++ b/src/Log.cpp
@@ -118,7 +118,7 @@ void cLog::Log(const char * a_Format, va_list argList)
AString Line;
#ifdef _DEBUG
- Printf(Line, "[%04x|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
+ Printf(Line, "[%04lx|%02d:%02d:%02d] %s", cIsThread::GetCurrentID(), timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
#else
Printf(Line, "[%02d:%02d:%02d] %s", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, Message.c_str());
#endif
diff --git a/src/Log.h b/src/Log.h
index cba248dae..d6a406154 100644
--- a/src/Log.h
+++ b/src/Log.h
@@ -14,8 +14,8 @@ 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) FORMATSTRING(2, 0);
+ void Log(const char * a_Format, ...) FORMATSTRING(2, 3);
// tolua_begin
void SimpleLog(const char * a_String);
void OpenLog(const char * a_FileName);
diff --git a/src/MCLogger.h b/src/MCLogger.h
index c949a4cdf..996e60329 100644
--- a/src/MCLogger.h
+++ b/src/MCLogger.h
@@ -21,10 +21,10 @@ public: // tolua_export
~cMCLogger(); // tolua_export
- void Log(const char* a_Format, va_list a_ArgList);
- void Info(const char* a_Format, va_list a_ArgList);
- void Warn(const char* a_Format, va_list a_ArgList);
- void Error(const char* a_Format, va_list a_ArgList);
+ void Log(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Info(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Warn(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
+ void Error(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0);
void LogSimple(const char* a_Text, int a_LogType = 0 ); // tolua_export
@@ -57,10 +57,10 @@ private:
-extern void LOG(const char* a_Format, ...);
-extern void LOGINFO(const char* a_Format, ...);
-extern void LOGWARN(const char* a_Format, ...);
-extern void LOGERROR(const char* a_Format, ...);
+extern void LOG(const char* a_Format, ...) FORMATSTRING(1, 2);
+extern void LOGINFO(const char* a_Format, ...) FORMATSTRING(1, 2);
+extern void LOGWARN(const char* a_Format, ...) FORMATSTRING(1, 2);
+extern void LOGERROR(const char* a_Format, ...) FORMATSTRING(1, 2);
diff --git a/src/Map.h b/src/Map.h
index a313d5431..ee7c537b1 100644
--- a/src/Map.h
+++ b/src/Map.h
@@ -64,7 +64,7 @@ public:
unsigned int GetPixelX(void) const { return m_PixelX; }
unsigned int GetPixelZ(void) const { return m_PixelZ; }
- int GetRot(void) const { return m_Rot; }
+ unsigned int GetRot(void) const { return m_Rot; }
eType GetType(void) const { return m_Type; }
diff --git a/src/Matrix4.h b/src/Matrix4.h
new file mode 100644
index 000000000..456677f0f
--- /dev/null
+++ b/src/Matrix4.h
@@ -0,0 +1,224 @@
+
+#pragma once
+
+
+
+#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
+#include <math.h>
+
+
+
+
+
+template <typename T>
+// tolua_begin
+class Matrix4
+{
+
+ TOLUA_TEMPLATE_BIND((T, float, double))
+
+ // tolua_end
+
+public:
+
+ T cell[16];
+
+ // tolua_begin
+
+ inline Matrix4(void)
+ {
+ Identity();
+ }
+
+ inline Matrix4(const Matrix4 & a_Rhs)
+ {
+ *this = a_Rhs;
+ }
+
+ inline Matrix4 & operator = (const Matrix4 & a_Rhs)
+ {
+ for (unsigned int i = 0; i < 16; ++i)
+ {
+ cell[i] = a_Rhs.cell[i];
+ }
+ return *this;
+ }
+
+ inline T & operator [] (int a_N)
+ {
+ ASSERT(a_N < 16);
+ return cell[a_N];
+ }
+
+ inline void Identity()
+ {
+ cell[1] = cell[2] = cell[3] = cell[4] = 0;
+ cell[6] = cell[7] = cell[8] = cell[9] = 0;
+ cell[11] = cell[12] = cell[13] = cell[14] = 0;
+
+ cell[0] = cell[5] = cell[10] = cell[15] = 1;
+ }
+
+ inline void Init(const Vector3<T> & a_Pos, T a_RX, T a_RY, T a_RZ)
+ {
+ Matrix4<T> t;
+ t.RotateX(a_RZ);
+ RotateY(a_RY);
+ Concatenate(t);
+ t.RotateZ(a_RX);
+ Concatenate(t);
+ Translate(a_Pos);
+ }
+
+ inline void RotateX(T a_RX)
+ {
+ T sx = (T) sin(a_RX * M_PI / 180);
+ T cx = (T) cos(a_RX * M_PI / 180);
+
+ Identity();
+
+ cell[5] = cx; cell[6] = sx;
+ cell[9] = -sx; cell[10] = cx;
+ }
+
+ inline void RotateY(T a_RY)
+ {
+ T sy = (T) sin(a_RY * M_PI / 180);
+ T cy = (T) cos(a_RY * M_PI / 180);
+
+ Identity();
+
+ cell[0] = cy; cell[2] = -sy;
+ cell[8] = sy; cell[10] = cy;
+ }
+
+ inline void RotateZ(T a_RZ)
+ {
+ T sz = (T) sin(a_RZ * M_PI / 180);
+ T cz = (T) cos(a_RZ * M_PI / 180);
+
+ Identity();
+
+ cell[0] = cz; cell[1] = sz;
+ cell[4] = -sz; cell[5] = cz;
+ }
+
+ inline void Translate(const Vector3<T> & a_Pos)
+ {
+ cell[3] += a_Pos.x;
+ cell[7] += a_Pos.y;
+ cell[11] += a_Pos.z;
+ }
+
+ inline void SetTranslation(const Vector3<T> & a_Pos)
+ {
+ cell[3] = a_Pos.x;
+ cell[7] = a_Pos.y;
+ cell[11] = a_Pos.z;
+ }
+
+ inline void Concatenate(const Matrix4 & m2)
+ {
+ Matrix4 res;
+
+ for (unsigned int c = 0; c < 4; ++c)
+ {
+ for (unsigned int r = 0; r < 4; ++r)
+ {
+ res.cell[r * 4 + c] = (
+ cell[r * 4 + 0] * m2.cell[c + 0] +
+ cell[r * 4 + 1] * m2.cell[c + 4] +
+ cell[r * 4 + 2] * m2.cell[c + 8] +
+ cell[r * 4 + 3] * m2.cell[c + 12]
+ );
+ }
+ }
+
+ *this = res;
+ }
+
+ inline Vector3<T> Transform(const Vector3<T> & v) const
+ {
+ T x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
+ T y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
+ T z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
+
+ return Vector3<T>(x, y, z);
+ }
+
+ inline void Invert(void)
+ {
+ Matrix4 t;
+
+ T tx = -cell[3];
+ T ty = -cell[7];
+ T tz = -cell[11];
+
+ for (unsigned int h = 0; h < 3; ++h)
+ {
+ for (unsigned int v = 0; v < 3; ++v)
+ {
+ t.cell[h + v * 4] = cell[v + h * 4];
+ }
+ }
+
+ for (unsigned int i = 0; i < 11; ++i)
+ {
+ cell[i] = t.cell[i];
+ }
+
+ cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
+ cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
+ cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
+ }
+
+ inline Vector3<T> GetXColumn(void) const
+ {
+ return Vector3<T>(cell[0], cell[1], cell[2]);
+ }
+
+ inline Vector3<T> GetYColumn(void) const
+ {
+ return Vector3<T>(cell[4], cell[5], cell[6]);
+ }
+
+ inline Vector3<T> GetZColumn(void) const
+ {
+ return Vector3<T>(cell[8], cell[9], cell[10]);
+ }
+
+ inline void SetXColumn(const Vector3<T> & a_X)
+ {
+ cell[0] = a_X.x;
+ cell[1] = a_X.y;
+ cell[2] = a_X.z;
+ }
+
+ inline void SetYColumn(const Vector3<T> & a_Y)
+ {
+ cell[4] = a_Y.x;
+ cell[5] = a_Y.y;
+ cell[6] = a_Y.z;
+ }
+
+ inline void SetZColumn(const Vector3<T> & a_Z)
+ {
+ cell[8] = a_Z.x;
+ cell[9] = a_Z.y;
+ cell[10] = a_Z.z;
+ }
+};
+// tolua_end
+
+
+
+
+// tolua_begin
+typedef Matrix4<double> Matrix4d;
+typedef Matrix4<float> Matrix4f;
+// tolua_end
+
+
+
+
+
diff --git a/src/Matrix4f.cpp b/src/Matrix4f.cpp
deleted file mode 100644
index d0a407a99..000000000
--- a/src/Matrix4f.cpp
+++ /dev/null
@@ -1,4 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-// _X: empty file??
diff --git a/src/Matrix4f.h b/src/Matrix4f.h
deleted file mode 100644
index 249c92f5f..000000000
--- a/src/Matrix4f.h
+++ /dev/null
@@ -1,225 +0,0 @@
-#pragma once
-
-#define _USE_MATH_DEFINES
-#include <math.h>
-#include "Vector3f.h"
-
-class Matrix4f
-{
-public:
- enum
- {
- TX=3,
- TY=7,
- TZ=11,
- D0=0, D1=5, D2=10, D3=15,
- SX=D0, SY=D1, SZ=D2,
- W=D3
- };
- Matrix4f() { Identity(); }
- float& operator [] ( int a_N ) { return cell[a_N]; }
- void Identity()
- {
- cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
- cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
- cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
- }
- void Init( Vector3f a_Pos, float a_RX, float a_RY, float a_RZ )
- {
- Matrix4f t;
- t.RotateX( a_RZ );
- RotateY( a_RY );
- Concatenate( t );
- t.RotateZ( a_RX );
- Concatenate( t );
- Translate( a_Pos );
- }
- void RotateX( float a_RX )
- {
- float sx = (float)sin( a_RX * M_PI / 180 );
- float cx = (float)cos( a_RX * M_PI / 180 );
- Identity();
- cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
- }
- void RotateY( float a_RY )
- {
- float sy = (float)sin( a_RY * M_PI / 180 );
- float cy = (float)cos( a_RY * M_PI / 180 );
- Identity ();
- cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
- }
- void RotateZ( float a_RZ )
- {
- float sz = (float)sin( a_RZ * M_PI / 180 );
- float cz = (float)cos( a_RZ * M_PI / 180 );
- Identity ();
- cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
- }
- void Translate( Vector3f a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
- void SetTranslation( Vector3f a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
- void Concatenate( const Matrix4f& m2 )
- {
- Matrix4f res;
- int c;
- for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
- res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
- cell[r * 4 + 1] * m2.cell[c + 4] +
- cell[r * 4 + 2] * m2.cell[c + 8] +
- cell[r * 4 + 3] * m2.cell[c + 12];
- for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
- }
- Vector3f Transform( const Vector3f& v ) const
- {
- float x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
- float y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
- float z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
- return Vector3f( x, y, z );
- }
- void Invert()
- {
- Matrix4f t;
- int h, i;
- float tx = -cell[3], ty = -cell[7], tz = -cell[11];
- for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
- for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
- cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
- cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
- cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
- }
- Vector3f GetXColumn() { return Vector3f( cell[0], cell[1], cell[2] ); }
- Vector3f GetYColumn() { return Vector3f( cell[4], cell[5], cell[6] ); }
- Vector3f GetZColumn() { return Vector3f( cell[8], cell[9], cell[10] ); }
- void SetXColumn( const Vector3f & a_X )
- {
- cell[0] = a_X.x;
- cell[1] = a_X.y;
- cell[2] = a_X.z;
- }
- void SetYColumn( const Vector3f & a_Y )
- {
- cell[4] = a_Y.x;
- cell[5] = a_Y.y;
- cell[6] = a_Y.z;
- }
- void SetZColumn( const Vector3f & a_Z )
- {
- cell[8] = a_Z.x;
- cell[9] = a_Z.y;
- cell[10] = a_Z.z;
- }
- float cell[16];
-};
-
-
-
-
-
-class Matrix4d
-{
-public:
- enum
- {
- TX=3,
- TY=7,
- TZ=11,
- D0=0, D1=5, D2=10, D3=15,
- SX=D0, SY=D1, SZ=D2,
- W=D3
- };
- Matrix4d() { Identity(); }
- double& operator [] ( int a_N ) { return cell[a_N]; }
- void Identity()
- {
- cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
- cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
- cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
- }
- void Init( Vector3f a_Pos, double a_RX, double a_RY, double a_RZ )
- {
- Matrix4d t;
- t.RotateX( a_RZ );
- RotateY( a_RY );
- Concatenate( t );
- t.RotateZ( a_RX );
- Concatenate( t );
- Translate( a_Pos );
- }
- void RotateX( double a_RX )
- {
- double sx = (double)sin( a_RX * M_PI / 180 );
- double cx = (double)cos( a_RX * M_PI / 180 );
- Identity();
- cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
- }
- void RotateY( double a_RY )
- {
- double sy = (double)sin( a_RY * M_PI / 180 );
- double cy = (double)cos( a_RY * M_PI / 180 );
- Identity ();
- cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
- }
- void RotateZ( double a_RZ )
- {
- double sz = (double)sin( a_RZ * M_PI / 180 );
- double cz = (double)cos( a_RZ * M_PI / 180 );
- Identity ();
- cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
- }
- void Translate( Vector3d a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
- void SetTranslation( Vector3d a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
- void Concatenate( const Matrix4d & m2 )
- {
- Matrix4d res;
- int c;
- for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
- res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
- cell[r * 4 + 1] * m2.cell[c + 4] +
- cell[r * 4 + 2] * m2.cell[c + 8] +
- cell[r * 4 + 3] * m2.cell[c + 12];
- for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
- }
- Vector3d Transform( const Vector3d & v ) const
- {
- double x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
- double y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
- double z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
- return Vector3d( x, y, z );
- }
- void Invert()
- {
- Matrix4d t;
- int h, i;
- double tx = -cell[3], ty = -cell[7], tz = -cell[11];
- for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
- for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
- cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
- cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
- cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
- }
- Vector3d GetXColumn() { return Vector3d( cell[0], cell[1], cell[2] ); }
- Vector3d GetYColumn() { return Vector3d( cell[4], cell[5], cell[6] ); }
- Vector3d GetZColumn() { return Vector3d( cell[8], cell[9], cell[10] ); }
- void SetXColumn( const Vector3d & a_X )
- {
- cell[0] = a_X.x;
- cell[1] = a_X.y;
- cell[2] = a_X.z;
- }
- void SetYColumn( const Vector3d & a_Y )
- {
- cell[4] = a_Y.x;
- cell[5] = a_Y.y;
- cell[6] = a_Y.z;
- }
- void SetZColumn( const Vector3d & a_Z )
- {
- cell[8] = a_Z.x;
- cell[9] = a_Z.y;
- cell[10] = a_Z.z;
- }
- double cell[16];
-} ;
-
-
-
-
diff --git a/src/MersenneTwister.h b/src/MersenneTwister.h
index f4c7b0699..759b8a1ae 100644
--- a/src/MersenneTwister.h
+++ b/src/MersenneTwister.h
@@ -62,7 +62,7 @@
class MTRand {
// Data
public:
- typedef long uint32; // unsigned integer type, at least 32 bits
+ typedef UInt32 uint32; // unsigned integer type, at least 32 bits
enum { N = 624 }; // length of state vector
enum { SAVE = N + 1 }; // length of array for save()
@@ -72,7 +72,7 @@ protected:
uint32 state[N]; // internal state
uint32 *pNext; // next value to get from state
- int left; // number of values left before reload needed
+ uint32 left; // number of values left before reload needed
// Methods
public:
@@ -164,7 +164,7 @@ inline void MTRand::initialize( const uint32 seed )
// only MSBs of the state array. Modified 9 Jan 2002 by Makoto Matsumoto.
uint32 *s = state;
uint32 *r = state;
- int i = 1;
+ uint32 i = 1;
*s++ = seed & 0xffffffffUL;
for( ; i < N; ++i )
{
@@ -205,9 +205,9 @@ inline void MTRand::seed( uint32 *const bigSeed, const uint32 seedLength )
// in each element are discarded.
// Just call seed() if you want to get array from /dev/urandom
initialize(19650218UL);
- int i = 1;
+ uint32 i = 1;
uint32 j = 0;
- int k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
+ uint32 k = ( (uint32)N > seedLength ? (uint32)N : seedLength );
for( ; k; --k )
{
state[i] =
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index 7704f6cf3..a0d0f5c54 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -169,7 +169,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R
(TargetBlock == E_BLOCK_AIR) &&
(BlockAbove == E_BLOCK_AIR) &&
(
- (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES)
+ (BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES) || (BlockBelow == E_BLOCK_NEW_LEAVES)
) &&
(a_RelY >= 62) &&
(m_Random.NextInt(3, a_Biome) != 0)
diff --git a/src/Mobs/Bat.cpp b/src/Mobs/Bat.cpp
index b9c82996b..1417ddd9e 100644
--- a/src/Mobs/Bat.cpp
+++ b/src/Mobs/Bat.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Bat.h"
-#include "../Vector3d.h"
+#include "../Vector3.h"
#include "../Chunk.h"
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 4761103e5..c64360153 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -68,17 +68,28 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
{
- // The sheep should not move when he's eating so only handle the physics.
+ super::Tick(a_Dt, a_Chunk);
+ int PosX = POSX_TOINT;
+ int PosY = POSY_TOINT - 1;
+ int PosZ = POSZ_TOINT;
+
+ if ((PosY <= 0) || (PosY > cChunkDef::Height))
+ {
+ return;
+ }
+
if (m_TimeToStopEating > 0)
{
- HandlePhysics(a_Dt, a_Chunk);
+ m_bMovingToDestination = false; // The sheep should not move when he's eating
m_TimeToStopEating--;
+
if (m_TimeToStopEating == 0)
{
- if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
{
- // The sheep ate the grass so we change it to dirt.
- m_World->SetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ(), E_BLOCK_DIRT, 0);
+ // The sheep ate the grass so we change it to dirt
+ m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
+ GetWorld()->BroadcastSoundParticleEffect(2001, PosX, PosY, PosX, E_BLOCK_GRASS);
m_IsSheared = false;
m_World->BroadcastEntityMetadata(*this);
}
@@ -86,12 +97,11 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
}
else
{
- super::Tick(a_Dt, a_Chunk);
if (m_World->GetTickRandomNumber(600) == 1)
{
- if (m_World->GetBlock((int) GetPosX(), (int) GetPosY() - 1, (int) GetPosZ()) == E_BLOCK_GRASS)
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
{
- m_World->BroadcastEntityStatus(*this, 10);
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
m_TimeToStopEating = 40;
}
}
diff --git a/src/Mobs/Squid.cpp b/src/Mobs/Squid.cpp
index ba9171b39..bd0e141a0 100644
--- a/src/Mobs/Squid.cpp
+++ b/src/Mobs/Squid.cpp
@@ -2,7 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Squid.h"
-#include "../Vector3d.h"
+#include "../Vector3.h"
#include "../Chunk.h"
diff --git a/src/Noise.cpp b/src/Noise.cpp
index 5f23a47f9..a97ea70c6 100644
--- a/src/Noise.cpp
+++ b/src/Noise.cpp
@@ -3,14 +3,6 @@
#include "Noise.h"
-
-
-
-
-#if NOISE_USE_SSE
- #include <smmintrin.h> //_mm_mul_epi32
-#endif
-
#define FAST_FLOOR(x) (((x) < 0) ? (((int)x) - 1) : ((int)x))
diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp
index e9c00d6d4..07f48b955 100644
--- a/src/OSSupport/BlockingTCPLink.cpp
+++ b/src/OSSupport/BlockingTCPLink.cpp
@@ -70,7 +70,7 @@ bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
}
}
- server.sin_addr.s_addr = *((unsigned long *)hp->h_addr);
+ memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length);
server.sin_family = AF_INET;
server.sin_port = htons( (unsigned short)iPort);
if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server)))
diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h
index 07fce6661..b394c5cb9 100644
--- a/src/OSSupport/File.h
+++ b/src/OSSupport/File.h
@@ -131,7 +131,7 @@ public:
/** Returns the list of all items in the specified folder (files, folders, nix pipes, whatever's there). */
static AStringVector GetFolderContents(const AString & a_Folder); // Exported in ManualBindings.cpp
- int Printf(const char * a_Fmt, ...);
+ int Printf(const char * a_Fmt, ...) FORMATSTRING(2, 3);
/** Flushes all the bufferef output into the file (only when writing) */
void Flush(void);
diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h
index b8784ea33..42b8bfdda 100644
--- a/src/OSSupport/IsThread.h
+++ b/src/OSSupport/IsThread.h
@@ -34,7 +34,7 @@ protected:
public:
cIsThread(const AString & iThreadName);
- ~cIsThread();
+ virtual ~cIsThread();
/// Starts the thread; returns without waiting for the actual start
bool Start(void);
diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp
index 6afaceedf..c29e495c3 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -307,7 +307,8 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
CloseSocket();
return false;
}
- addr = *((unsigned long*)hp->h_addr);
+ // Should be optimised to a single word copy
+ memcpy(&addr, hp->h_addr, hp->h_length);
}
sockaddr_in server;
diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp
index a02661d2c..0bc1d6b55 100644
--- a/src/OSSupport/SocketThreads.cpp
+++ b/src/OSSupport/SocketThreads.cpp
@@ -54,7 +54,7 @@ bool cSocketThreads::AddClient(const cSocket & a_Socket, cCallback * a_Client)
}
// No thread has free space, create a new one:
- LOGD("Creating a new cSocketThread (currently have %d)", m_Threads.size());
+ LOGD("Creating a new cSocketThread (currently have " SIZE_T_FMT ")", m_Threads.size());
cSocketThread * Thread = new cSocketThread(this);
if (!Thread->Start())
{
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 50ebb6d43..69f4934d8 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -1269,19 +1269,6 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType)
-#define HANDLE_PACKET_PARSE(Packet) \
- { \
- int res = Packet.Parse(m_ReceivedData); \
- if (res < 0) \
- { \
- return res; \
- } \
- }
-
-
-
-
-
int cProtocol125::ParseArmAnim(void)
{
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 66f3227b0..aca24c03a 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -11,6 +11,7 @@
#include "Protocol.h"
#include "../ByteBuffer.h"
+#include "../Entities/Painting.h"
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 8df550c7b..be9c503ed 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -100,7 +100,7 @@ cProtocol132::~cProtocol132()
{
if (!m_DataToSend.empty())
{
- LOGD("There are %d unsent bytes while deleting cProtocol132", m_DataToSend.size());
+ LOGD("There are " SIZE_T_FMT " unsent bytes while deleting cProtocol132", m_DataToSend.size());
}
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index a72da776d..6fc344eaf 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -1251,7 +1251,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
- m_CommLogFile.Printf("Incoming data, %d (0x%x) unparsed bytes already present in buffer:\n%s\n",
+ m_CommLogFile.Printf("Incoming data, " SIZE_T_FMT " (0x" SIZE_T_FMT_HEX ") unparsed bytes already present in buffer:\n%s\n",
AllData.size(), AllData.size(), Hex.c_str()
);
}
@@ -1344,14 +1344,14 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (bb.GetReadableSpace() != 1)
{
// Read more or less than packet length, report as error
- LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
+ LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read " SIZE_T_FMT " bytes, packet contained %u bytes",
PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
);
// Put a message in the comm log:
if (g_ShouldLogCommIn)
{
- m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got %d left) ^^^^^^\n\n\n",
+ m_CommLogFile.Printf("^^^^^^ Wrong number of bytes read for this packet (exp %d left, got " SIZE_T_FMT " left) ^^^^^^\n\n\n",
1, bb.GetReadableSpace()
);
m_CommLogFile.Flush();
@@ -1373,7 +1373,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
ASSERT(m_ReceivedData.GetReadableSpace() == OldReadableSpace);
AString Hex;
CreateHexDump(Hex, AllData.data(), AllData.size(), 16);
- m_CommLogFile.Printf("There are %d (0x%x) bytes of non-parse-able data left in the buffer:\n%s",
+ m_CommLogFile.Printf("There are " SIZE_T_FMT " (0x" SIZE_T_FMT_HEX ") bytes of non-parse-able data left in the buffer:\n%s",
m_ReceivedData.GetReadableSpace(), m_ReceivedData.GetReadableSpace(), Hex.c_str()
);
m_CommLogFile.Flush();
@@ -2062,7 +2062,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
AString HexDump;
CreateHexDump(HexDump, a_Metadata.data(), a_Metadata.size(), 16);
- LOGWARNING("Cannot unGZIP item metadata (%u bytes):\n%s", a_Metadata.size(), HexDump.c_str());
+ LOGWARNING("Cannot unGZIP item metadata (" SIZE_T_FMT " bytes):\n%s", a_Metadata.size(), HexDump.c_str());
return;
}
@@ -2072,43 +2072,54 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
AString HexDump;
CreateHexDump(HexDump, Uncompressed.data(), Uncompressed.size(), 16);
- LOGWARNING("Cannot parse NBT item metadata: (%u bytes)\n%s", Uncompressed.size(), HexDump.c_str());
+ LOGWARNING("Cannot parse NBT item metadata: (" SIZE_T_FMT " bytes)\n%s", Uncompressed.size(), HexDump.c_str());
return;
}
// Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
- if (
- (NBT.GetType(tag) == TAG_List) &&
- (
- (NBT.GetName(tag) == "ench") ||
- (NBT.GetName(tag) == "StoredEnchantments")
- )
- )
+ AString TagName = NBT.GetName(tag);
+ switch (NBT.GetType(tag))
{
- EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, 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))
+ case TAG_List:
{
- if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ if ((TagName == "ench") || (TagName == "StoredEnchantments")) // Enchantments tags
{
- a_Item.m_CustomName = NBT.GetString(displaytag);
+ EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, NBT, tag);
}
- else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ break;
+ }
+ case TAG_Compound:
+ {
+ if (TagName == "display") // Custom name and lore tag
{
- AString Lore;
-
- for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
{
- 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 ;)
+ 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;
+ }
}
-
- a_Item.m_Lore = Lore;
}
+ else if ((TagName == "Fireworks") || (TagName == "Explosion"))
+ {
+ cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, NBT, tag, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
+ break;
}
+ default: LOGD("Unimplemented NBT data when parsing!"); break;
}
}
}
@@ -2272,7 +2283,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
- if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
+ if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty() && (a_Item.m_ItemType != E_ITEM_FIREWORK_ROCKET) && (a_Item.m_ItemType != E_ITEM_FIREWORK_STAR))
{
WriteShort(-1);
return;
@@ -2311,6 +2322,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
}
Writer.EndCompound();
}
+ if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@@ -2487,10 +2502,22 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
}
case cEntity::etProjectile:
{
- if (((cProjectileEntity &)a_Entity).GetProjectileKind() == cProjectileEntity::pkArrow)
+ cProjectileEntity & Projectile = (cProjectileEntity &)a_Entity;
+ switch (Projectile.GetProjectileKind())
{
- WriteByte(0x10);
- WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ case cProjectileEntity::pkArrow:
+ {
+ WriteByte(0x10);
+ WriteByte(((const cArrowEntity &)a_Entity).IsCritical() ? 1 : 0);
+ break;
+ }
+ case cProjectileEntity::pkFirework:
+ {
+ WriteByte(0xA8);
+ WriteItem(((const cFireworkEntity &)a_Entity).GetItem());
+ break;
+ }
+ default: break;
}
break;
}
diff --git a/src/Root.cpp b/src/Root.cpp
index 69f18104e..3555afb45 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -778,11 +778,11 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output)
int Mem = NumValid * sizeof(cChunk);
a_Output.Out(" Memory used by chunks: %d KiB (%d MiB)", (Mem + 1023) / 1024, (Mem + 1024 * 1024 - 1) / (1024 * 1024));
a_Output.Out(" Per-chunk memory size breakdown:");
- a_Output.Out(" block types: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
- a_Output.Out(" block metadata: %6d bytes (%3d KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
- a_Output.Out(" block lighting: %6d bytes (%3d KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
- a_Output.Out(" heightmap: %6d bytes (%3d KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
- a_Output.Out(" biomemap: %6d bytes (%3d KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
+ a_Output.Out(" block types: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BlockTypes), (sizeof(cChunkDef::BlockTypes) + 1023) / 1024);
+ a_Output.Out(" block metadata: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BlockNibbles), (sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
+ a_Output.Out(" block lighting: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024);
+ a_Output.Out(" heightmap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024);
+ a_Output.Out(" biomemap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024);
int Rest = sizeof(cChunk) - sizeof(cChunkDef::BlockTypes) - 3 * sizeof(cChunkDef::BlockNibbles) - sizeof(cChunkDef::HeightMap) - sizeof(cChunkDef::BiomeMap);
a_Output.Out(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024);
SumNumValid += NumValid;
diff --git a/src/Scoreboard.h b/src/Scoreboard.h
index e22ecaeb1..2fae5e499 100644
--- a/src/Scoreboard.h
+++ b/src/Scoreboard.h
@@ -150,6 +150,8 @@ public:
/** Removes all registered players */
void Reset(void);
+ // tolua_begin
+
/** Returns the number of registered players */
unsigned int GetNumPlayers(void) const;
diff --git a/src/Server.cpp b/src/Server.cpp
index fcbcaa919..d1e53bfff 100644
--- a/src/Server.cpp
+++ b/src/Server.cpp
@@ -24,7 +24,7 @@
#include "MersenneTwister.h"
#include "inifile/iniFile.h"
-#include "Vector3f.h"
+#include "Vector3.h"
#include <fstream>
#include <sstream>
@@ -550,7 +550,7 @@ void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback &
for (AStringPairs::const_iterator itr = Callback.m_Commands.begin(), end = Callback.m_Commands.end(); itr != end; ++itr)
{
const AStringPair & cmd = *itr;
- a_Output.Out(Printf("%-*s%s\n", Callback.m_MaxLen, cmd.first.c_str(), cmd.second.c_str()));
+ a_Output.Out(Printf("%-*s%s\n", static_cast<int>(Callback.m_MaxLen), cmd.first.c_str(), cmd.second.c_str()));
} // for itr - Callback.m_Commands[]
a_Output.Finished();
}
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 4967c83f9..26712e6e6 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -334,21 +334,33 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel
for (size_t i = 0; i < ARRAYCOUNT(gNeighborCoords); i++)
{
BLOCKTYPE BlockType;
- NIBBLETYPE BlockMeta;
- if (!a_Chunk->UnboundedRelGetBlock(a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z, BlockType, BlockMeta))
+ int X = a_RelX + gNeighborCoords[i].x;
+ int Z = a_RelZ + gNeighborCoords[i].z;
+
+ cChunkPtr Neighbour = a_Chunk->GetRelNeighborChunkAdjustCoords(X, Z);
+ if (Neighbour == NULL)
{
- // Neighbor not accessible, ignore it
continue;
}
+ BlockType = Neighbour->GetBlock(X, a_RelY + gCrossCoords[i].y, Z);
+
if (!IsFuel(BlockType))
{
continue;
}
+
+ if (BlockType == E_BLOCK_TNT)
+ {
+ int AbsX = X + Neighbour->GetPosX() * cChunkDef::Width;
+ int AbsZ = Z + Neighbour->GetPosZ() * cChunkDef::Width;
+
+ m_World.SpawnPrimedTNT(AbsX, a_RelY + gNeighborCoords[i].y, AbsZ, 0);
+ Neighbour->SetBlock(X, a_RelY + gNeighborCoords[i].y, Z, E_BLOCK_AIR, 0);
+ return;
+ }
+
bool ShouldReplaceFuel = (m_World.GetTickRandomNumber(MAX_CHANCE_REPLACE_FUEL) < m_ReplaceFuelChance);
- a_Chunk->UnboundedRelSetBlock(
- a_RelX + gNeighborCoords[i].x, a_RelY + gNeighborCoords[i].y, a_RelZ + gNeighborCoords[i].z,
- ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0
- );
+ Neighbour->SetBlock(X, a_RelY + gNeighborCoords[i].y, Z, ShouldReplaceFuel ? E_BLOCK_FIRE : E_BLOCK_AIR, 0);
} // for i - Coords[]
}
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index f377b0aa7..ca2ef4b1a 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -838,7 +838,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_
if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
{
m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f);
- m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5, 4); // 4 seconds to boom
+ m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
}
}
diff --git a/src/Simulator/Simulator.cpp b/src/Simulator/Simulator.cpp
index 06fd0f858..0739f0187 100644
--- a/src/Simulator/Simulator.cpp
+++ b/src/Simulator/Simulator.cpp
@@ -3,7 +3,6 @@
#include "Simulator.h"
#include "../World.h"
-#include "../Vector3i.h"
#include "../BlockID.h"
#include "../Defines.h"
#include "../Chunk.h"
diff --git a/src/Simulator/Simulator.h b/src/Simulator/Simulator.h
index a25b7f1b6..a2e2a5742 100644
--- a/src/Simulator/Simulator.h
+++ b/src/Simulator/Simulator.h
@@ -1,7 +1,7 @@
#pragma once
-#include "../Vector3i.h"
+#include "../Vector3.h"
#include "inifile/iniFile.h"
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 3fe75d611..3f9275798 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -288,13 +288,13 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString &
// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
-AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8)
+AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8)
{
a_UTF8.clear();
a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size
for (int i = 0; i < a_NumShorts; i++)
{
- int c = ntohs(*(a_RawData + i));
+ int c = GetBEShort(&a_RawData[i * 2]);
if (c < 0x80)
{
a_UTF8.push_back((char)c);
@@ -364,10 +364,7 @@ Notice from the original file:
#define UNI_MAX_BMP 0x0000FFFF
#define UNI_MAX_UTF16 0x0010FFFF
-#define UNI_MAX_UTF32 0x7FFFFFFF
-#define UNI_MAX_LEGAL_UTF32 0x0010FFFF
#define UNI_SUR_HIGH_START 0xD800
-#define UNI_SUR_HIGH_END 0xDBFF
#define UNI_SUR_LOW_START 0xDC00
#define UNI_SUR_LOW_END 0xDFFF
diff --git a/src/StringUtils.h b/src/StringUtils.h
index dfbfc2a75..4feff7553 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -22,16 +22,16 @@ typedef std::list<AString> AStringList;
/** Add the formated string to the existing data in the string */
-extern AString & AppendVPrintf(AString & str, const char * format, va_list args);
+extern AString & AppendVPrintf(AString & str, const char * format, va_list args) FORMATSTRING(2, 0);
/// Output the formatted text into the string
-extern AString & Printf (AString & str, const char * format, ...);
+extern AString & Printf (AString & str, const char * format, ...) FORMATSTRING(2, 3);
/// Output the formatted text into string, return string by value
-extern AString Printf(const char * format, ...);
+extern AString Printf(const char * format, ...) FORMATSTRING(1, 2);
/// Add the formatted string to the existing data in the string
-extern AString & AppendPrintf (AString & str, const char * format, ...);
+extern AString & AppendPrintf (AString & str, const char * format, ...) FORMATSTRING(2, 3);
/// Split the string at any of the listed delimiters, return as a stringvector
extern AStringVector StringSplit(const AString & str, const AString & delim);
@@ -58,7 +58,7 @@ extern unsigned int RateCompareString(const AString & s1, const AString & s2 );
extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export
/// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8
-extern AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8);
+extern AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8);
/// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16
extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16);
diff --git a/src/Tracer.cpp b/src/Tracer.cpp
index 968a64439..6da6b2ad7 100644
--- a/src/Tracer.cpp
+++ b/src/Tracer.cpp
@@ -4,10 +4,6 @@
#include "Tracer.h"
#include "World.h"
-#include "Vector3f.h"
-#include "Vector3i.h"
-#include "Vector3d.h"
-
#include "Entities/Entity.h"
#ifndef _WIN32
diff --git a/src/Tracer.h b/src/Tracer.h
index 6c2ab6792..bdb080f0d 100644
--- a/src/Tracer.h
+++ b/src/Tracer.h
@@ -1,8 +1,7 @@
#pragma once
-#include "Vector3i.h"
-#include "Vector3f.h"
+#include "Vector3.h"
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index 1a8456f70..aae7b99a3 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -637,7 +637,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int
{
if ((size_t)(a_Item.m_ItemCount) < a_SlotNums.size())
{
- LOGWARNING("%s: Distributing less items (%d) than slots (%u)", __FUNCTION__, (int)a_Item.m_ItemCount, a_SlotNums.size());
+ LOGWARNING("%s: Distributing less items (%d) than slots (" SIZE_T_FMT ")", __FUNCTION__, (int)a_Item.m_ItemCount, a_SlotNums.size());
// This doesn't seem to happen with the 1.5.1 client, so we don't worry about it for now
return 0;
}
diff --git a/src/Vector3.h b/src/Vector3.h
new file mode 100644
index 000000000..ba4abe3eb
--- /dev/null
+++ b/src/Vector3.h
@@ -0,0 +1,286 @@
+
+#pragma once
+
+
+
+#define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC)
+#include <math.h>
+
+
+
+
+
+template <typename T>
+// tolua_begin
+class Vector3
+{
+
+ TOLUA_TEMPLATE_BIND((T, int, float, double))
+
+public:
+
+ T x, y, z;
+
+
+ inline Vector3(void) : x(0), y(0), z(0) {}
+ inline Vector3(T a_x, T a_y, T a_z) : x(a_x), y(a_y), z(a_z) {}
+
+
+ // Hardcoded copy constructors (tolua++ does not support function templates .. yet)
+ Vector3(const Vector3<float> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {}
+ Vector3(const Vector3<double> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {}
+ Vector3(const Vector3<int> & a_Rhs) : x((T) a_Rhs.x), y((T) a_Rhs.y), z((T) a_Rhs.z) {}
+
+
+ // tolua_end
+ template <typename _T>
+ Vector3(const Vector3<_T> & a_Rhs) : x(a_Rhs.x), y(a_Rhs.y), z(a_Rhs.z) {}
+
+ template <typename _T>
+ Vector3(const Vector3<_T> * a_Rhs) : x(a_Rhs->x), y(a_Rhs->y), z(a_Rhs->z) {}
+ // tolua_begin
+
+
+ inline void Set(T a_x, T a_y, T a_z)
+ {
+ x = a_x;
+ y = a_y;
+ z = a_z;
+ }
+
+ inline void Normalize(void)
+ {
+ double Len = 1.0 / Length();
+
+ x = (T)(x * Len);
+ y = (T)(y * Len);
+ z = (T)(z * Len);
+ }
+
+ inline Vector3<T> NormalizeCopy(void) const
+ {
+ double Len = 1.0 / Length();
+
+ return Vector3<T>(
+ (T)(x * Len),
+ (T)(y * Len),
+ (T)(z * Len)
+ );
+ }
+
+ inline void NormalizeCopy(Vector3<T> & a_Rhs) const
+ {
+ double Len = 1.0 / Length();
+
+ a_Rhs.Set(
+ (T)(x * Len),
+ (T)(y * Len),
+ (T)(z * Len)
+ );
+ }
+
+ inline double Length(void) const
+ {
+ return sqrt((double)(x * x + y * y + z * z));
+ }
+
+ inline double SqrLength(void) const
+ {
+ return x * x + y * y + z * z;
+ }
+
+ inline T Dot(const Vector3<T> & a_Rhs) const
+ {
+ return x * a_Rhs.x + y * a_Rhs.y + z * a_Rhs.z;
+ }
+
+ inline Vector3<T> Cross(const Vector3<T> & a_Rhs) const
+ {
+ return Vector3<T>(
+ y * a_Rhs.z - z * a_Rhs.y,
+ z * a_Rhs.x - x * a_Rhs.z,
+ x * a_Rhs.y - y * a_Rhs.x
+ );
+ }
+
+ inline bool Equals(const Vector3<T> & a_Rhs) const
+ {
+ return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z;
+ }
+
+ inline bool operator < (const Vector3<T> & a_Rhs)
+ {
+ // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ?
+ return (x < a_Rhs.x) || (x == a_Rhs.x && y < a_Rhs.y) || (x == a_Rhs.x && y == a_Rhs.y && z < a_Rhs.z);
+ }
+
+ inline void Move(T a_X, T a_Y, T a_Z)
+ {
+ x += a_X;
+ y += a_Y;
+ z += a_Z;
+ }
+
+ // tolua_end
+
+ inline void operator += (const Vector3<T> & a_Rhs)
+ {
+ x += a_Rhs.x;
+ y += a_Rhs.y;
+ z += a_Rhs.z;
+ }
+
+ inline void operator -= (const Vector3<T> & a_Rhs)
+ {
+ x -= a_Rhs.x;
+ y -= a_Rhs.y;
+ z -= a_Rhs.z;
+ }
+
+ inline void operator *= (const Vector3<T> & a_Rhs)
+ {
+ x *= a_Rhs.x;
+ y *= a_Rhs.y;
+ z *= a_Rhs.z;
+ }
+
+ inline void operator *= (T a_v)
+ {
+ x *= a_v;
+ y *= a_v;
+ z *= a_v;
+ }
+
+ // tolua_begin
+
+ inline Vector3<T> operator + (const Vector3<T>& a_Rhs) const
+ {
+ return Vector3<T>(
+ x + a_Rhs.x,
+ y + a_Rhs.y,
+ z + a_Rhs.z
+ );
+ }
+
+ inline Vector3<T> operator - (const Vector3<T>& a_Rhs) const
+ {
+ return Vector3<T>(
+ x - a_Rhs.x,
+ y - a_Rhs.y,
+ z - a_Rhs.z
+ );
+ }
+
+ inline Vector3<T> operator * (const Vector3<T>& a_Rhs) const
+ {
+ return Vector3<T>(
+ x * a_Rhs.x,
+ y * a_Rhs.y,
+ z * a_Rhs.z
+ );
+ }
+
+ inline Vector3<T> operator * (T a_v) const
+ {
+ return Vector3<T>(
+ x * a_v,
+ y * a_v,
+ z * a_v
+ );
+ }
+
+ inline Vector3<T> operator / (T a_v) const
+ {
+ return Vector3<T>(
+ x / a_v,
+ y / a_v,
+ z / a_v
+ );
+ }
+
+ /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Z coord.
+ The result satisfies the following equation:
+ (*this + Result * (a_OtherEnd - *this)).z = a_Z
+ If the line is too close to being parallel, this function returns NO_INTERSECTION
+ */
+ inline double LineCoeffToXYPlane(const Vector3<T> & a_OtherEnd, T a_Z) const
+ {
+ if (abs(z - a_OtherEnd.z) < EPS)
+ {
+ return NO_INTERSECTION;
+ }
+
+ return (a_Z - z) / (a_OtherEnd.z - z);
+ }
+
+ /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Y coord.
+ The result satisfies the following equation:
+ (*this + Result * (a_OtherEnd - *this)).y = a_Y
+ If the line is too close to being parallel, this function returns NO_INTERSECTION
+ */
+ inline double LineCoeffToXZPlane(const Vector3<T> & a_OtherEnd, T a_Y) const
+ {
+ if (abs(y - a_OtherEnd.y) < EPS)
+ {
+ return NO_INTERSECTION;
+ }
+
+ return (a_Y - y) / (a_OtherEnd.y - y);
+ }
+
+ /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified X coord.
+ The result satisfies the following equation:
+ (*this + Result * (a_OtherEnd - *this)).x = a_X
+ If the line is too close to being parallel, this function returns NO_INTERSECTION
+ */
+ inline double LineCoeffToYZPlane(const Vector3<T> & a_OtherEnd, T a_X) const
+ {
+ if (abs(x - a_OtherEnd.x) < EPS)
+ {
+ return NO_INTERSECTION;
+ }
+
+ return (a_X - x) / (a_OtherEnd.x - x);
+ }
+
+ /** The max difference between two coords for which the coords are assumed equal. */
+ static const double EPS;
+
+ /** Return value of LineCoeffToPlane() if the line is parallel to the plane. */
+ static const double NO_INTERSECTION;
+
+};
+// tolua_end
+
+
+
+
+
+template <typename T>
+const double Vector3<T>::EPS = 0.000001;
+
+template <typename T>
+const double Vector3<T>::NO_INTERSECTION = 1e70;
+
+
+
+
+
+// tolua_begin
+typedef Vector3<double> Vector3d;
+typedef Vector3<float> Vector3f;
+typedef Vector3<int> Vector3i;
+// tolua_end
+
+
+
+
+
+typedef std::list<Vector3i> cVector3iList;
+typedef std::vector<Vector3i> cVector3iArray;
+
+
+
+
+
+
diff --git a/src/Vector3d.cpp b/src/Vector3d.cpp
deleted file mode 100644
index 96ebebab5..000000000
--- a/src/Vector3d.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Vector3d.h"
-#include "Vector3f.h"
-
-
-
-
-
-const double Vector3d::EPS = 0.000001; ///< The max difference between two coords for which the coords are assumed equal
-const double Vector3d::NO_INTERSECTION = 1e70; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane
-
-
-
-
-
-Vector3d::Vector3d(const Vector3f & v) :
- x(v.x),
- y(v.y),
- z(v.z)
-{
-}
-
-
-
-
-
-Vector3d::Vector3d(const Vector3f * v) :
- x(v->x),
- y(v->y),
- z(v->z)
-{
-}
-
-
-
-
-
-double Vector3d::LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const
-{
- if (abs(z - a_OtherEnd.z) < EPS)
- {
- return NO_INTERSECTION;
- }
- return (a_Z - z) / (a_OtherEnd.z - z);
-}
-
-
-
-
-
-double Vector3d::LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const
-{
- if (abs(y - a_OtherEnd.y) < EPS)
- {
- return NO_INTERSECTION;
- }
- return (a_Y - y) / (a_OtherEnd.y - y);
-}
-
-
-
-
-
-double Vector3d::LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const
-{
- if (abs(x - a_OtherEnd.x) < EPS)
- {
- return NO_INTERSECTION;
- }
- return (a_X - x) / (a_OtherEnd.x - x);
-}
-
-
-
-
diff --git a/src/Vector3d.h b/src/Vector3d.h
deleted file mode 100644
index a06a17c09..000000000
--- a/src/Vector3d.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-class Vector3f;
-
-
-
-// tolua_begin
-
-class Vector3d
-{
-public:
- // convert from float
- Vector3d(const Vector3f & v);
- Vector3d(const Vector3f * v);
-
- Vector3d() : x(0), y(0), z(0) {}
- Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {}
-
- inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; }
- inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; }
- inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); }
- inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); }
- inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); }
- inline double SqrLength() const { return x * x + y * y + z * z; }
- inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; }
- inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); }
-
- /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Z coord
- The result satisfies the following equation:
- (*this + Result * (a_OtherEnd - *this)).z = a_Z
- If the line is too close to being parallel, this function returns NO_INTERSECTION
- */
- double LineCoeffToXYPlane(const Vector3d & a_OtherEnd, double a_Z) const;
-
- /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified Y coord
- The result satisfies the following equation:
- (*this + Result * (a_OtherEnd - *this)).y = a_Y
- If the line is too close to being parallel, this function returns NO_INTERSECTION
- */
- double LineCoeffToXZPlane(const Vector3d & a_OtherEnd, double a_Y) const;
-
- /** Returns the coefficient for the (a_OtherEnd - this) line to reach the specified X coord
- The result satisfies the following equation:
- (*this + Result * (a_OtherEnd - *this)).x = a_X
- If the line is too close to being parallel, this function returns NO_INTERSECTION
- */
- double LineCoeffToYZPlane(const Vector3d & a_OtherEnd, double a_X) const;
-
- inline bool Equals(const Vector3d & v) const { return ((x == v.x) && (y == v.y) && (z == v.z)); }
-
- // tolua_end
-
- void operator += ( const Vector3d& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
- void operator += ( Vector3d* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
- void operator -= ( const Vector3d& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
- void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
- void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
-
- // tolua_begin
-
- Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); }
- Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); }
- Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); }
- Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); }
- Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); }
- Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); }
- Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); }
-
- double x, y, z;
-
- static const double EPS; ///< The max difference between two coords for which the coords are assumed equal
- static const double NO_INTERSECTION; ///< Return value of LineCoeffToPlane() if the line is parallel to the plane
-} ;
-
-// tolua_end
-
-
-
-
diff --git a/src/Vector3f.cpp b/src/Vector3f.cpp
deleted file mode 100644
index 59d71d371..000000000
--- a/src/Vector3f.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Vector3f.h"
-#include "Vector3d.h"
-#include "Vector3i.h"
-
-Vector3f::Vector3f( const Vector3d & v )
- : x( (float)v.x )
- , y( (float)v.y )
- , z( (float)v.z )
-{
-}
-
-Vector3f::Vector3f( const Vector3d * v )
- : x( (float)v->x )
- , y( (float)v->y )
- , z( (float)v->z )
-{
-}
-
-Vector3f::Vector3f( const Vector3i & v )
- : x( (float)v.x )
- , y( (float)v.y )
- , z( (float)v.z )
-{
-}
-
-Vector3f::Vector3f( const Vector3i * v )
- : x( (float)v->x )
- , y( (float)v->y )
- , z( (float)v->z )
-{
-} \ No newline at end of file
diff --git a/src/Vector3f.h b/src/Vector3f.h
deleted file mode 100644
index adb154ad7..000000000
--- a/src/Vector3f.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-class Vector3i;
-class Vector3d;
-class Vector3f // tolua_export
-{ // tolua_export
-public: // tolua_export
- Vector3f( const Vector3d & v ); // tolua_export
- Vector3f( const Vector3d * v ); // tolua_export
- Vector3f( const Vector3i & v ); // tolua_export
- Vector3f( const Vector3i * v ); // tolua_export
-
-
- Vector3f() : x(0), y(0), z(0) {} // tolua_export
- Vector3f(float a_x, float a_y, float a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export
-
- inline void Set(float a_x, float a_y, float a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export
- inline void Normalize() { float l = 1.0f / Length(); x *= l; y *= l; z *= l; } // tolua_export
- inline Vector3f NormalizeCopy() const { float l = 1.0f / Length(); return Vector3f( x * l, y * l, z * l ); }// tolua_export
- inline void NormalizeCopy(Vector3f & a_V) const { float l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } // tolua_export
- inline float Length() const { return (float)sqrtf( x * x + y * y + z * z ); } // tolua_export
- inline float SqrLength() const { return x * x + y * y + z * z; } // tolua_export
- inline float Dot( const Vector3f & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } // tolua_export
- inline Vector3f Cross( const Vector3f & v ) const { return Vector3f( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } // tolua_export
-
- inline bool Equals( const Vector3f & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export
-
- void operator += ( const Vector3f& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
- void operator += ( Vector3f* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
- void operator -= ( const Vector3f& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
- void operator -= ( Vector3f* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
- void operator *= ( float a_f ) { x *= a_f; y *= a_f; z *= a_f; }
- void operator *= ( Vector3f* a_V ) { x *= a_V->x; y *= a_V->y; z *= a_V->z; }
- void operator *= ( const Vector3f& a_V ) { x *= a_V.x; y *= a_V.y; z *= a_V.z; }
-
- Vector3f operator + ( const Vector3f& v2 ) const { return Vector3f( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
- Vector3f operator + ( const Vector3f* v2 ) const { return Vector3f( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
- Vector3f operator - ( const Vector3f& v2 ) const { return Vector3f( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
- Vector3f operator - ( const Vector3f* v2 ) const { return Vector3f( x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
- Vector3f operator * ( const float f ) const { return Vector3f( x * f, y * f, z * f ); } // tolua_export
- Vector3f operator * ( const Vector3f& v2 ) const { return Vector3f( x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
-
- float x, y, z; // tolua_export
-
-};// tolua_export
diff --git a/src/Vector3i.cpp b/src/Vector3i.cpp
deleted file mode 100644
index 4ce1e2cf3..000000000
--- a/src/Vector3i.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-
-#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
-
-#include "Vector3i.h"
-#include "Vector3d.h"
-
-
-
-
-
-Vector3i::Vector3i( const Vector3d & v )
- : x( (int)v.x )
- , y( (int)v.y )
- , z( (int)v.z )
-{
-} \ No newline at end of file
diff --git a/src/Vector3i.h b/src/Vector3i.h
deleted file mode 100644
index 7d726a7b3..000000000
--- a/src/Vector3i.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#pragma once
-
-#include <math.h>
-
-class Vector3d;
-class Vector3i // tolua_export
-{ // tolua_export
-public: // tolua_export
- Vector3i( const Vector3d & v ); // tolua_export
-
- Vector3i() : x(0), y(0), z(0) {} // tolua_export
- Vector3i(int a_x, int a_y, int a_z) : x(a_x), y(a_y), z(a_z) {} // tolua_export
-
- inline void Set(int a_x, int a_y, int a_z) { x = a_x, y = a_y, z = a_z; } // tolua_export
- inline float Length() const { return sqrtf( (float)( x * x + y * y + z * z) ); } // tolua_export
- inline int SqrLength() const { return x * x + y * y + z * z; } // tolua_export
-
- inline bool Equals( const Vector3i & v ) const { return (x == v.x && y == v.y && z == v.z ); } // tolua_export
- inline bool Equals( const Vector3i * v ) const { return (x == v->x && y == v->y && z == v->z ); } // tolua_export
-
- void operator += ( const Vector3i& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
- void operator += ( Vector3i* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
- void operator -= ( const Vector3i& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
- void operator -= ( Vector3i* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
- void operator *= ( int a_f ) { x *= a_f; y *= a_f; z *= a_f; }
-
- friend Vector3i operator + ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ); }
- friend Vector3i operator + ( const Vector3i& v1, Vector3i* v2 ) { return Vector3i( v1.x + v2->x, v1.y + v2->y, v1.z + v2->z ); }
- friend Vector3i operator - ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ); }
- friend Vector3i operator - ( const Vector3i& v1, Vector3i* v2 ) { return Vector3i( v1.x - v2->x, v1.y - v2->y, v1.z - v2->z ); }
- friend Vector3i operator - ( const Vector3i* v1, Vector3i& v2 ) { return Vector3i( v1->x - v2.x, v1->y - v2.y, v1->z - v2.z ); }
- friend Vector3i operator * ( const Vector3i& v, const int f ) { return Vector3i( v.x * f, v.y * f, v.z * f ); }
- friend Vector3i operator * ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z ); }
- friend Vector3i operator * ( const int f, const Vector3i& v ) { return Vector3i( v.x * f, v.y * f, v.z * f ); }
- friend bool operator < ( const Vector3i& v1, const Vector3i& v2 ) { return (v1.x<v2.x)||(v1.x==v2.x && v1.y<v2.y)||(v1.x==v2.x && v1.y == v2.y && v1.z<v2.z); }
-
- int x, y, z; // tolua_export
-}; // tolua_export
-
-typedef std::list<Vector3i> cVector3iList;
-typedef std::vector<Vector3i> cVector3iArray;
-
-
-
-
diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp
index e88de5947..402cd3035 100644
--- a/src/WebAdmin.cpp
+++ b/src/WebAdmin.cpp
@@ -127,6 +127,7 @@ bool cWebAdmin::Start(void)
// Initialize the WebAdmin template script and load the file
m_TemplateScript.Create();
+ m_TemplateScript.RegisterAPILibs();
if (!m_TemplateScript.LoadFile(FILE_IO_PREFIX "webadmin/template.lua"))
{
LOGWARN("Could not load WebAdmin template \"%s\", using default template.", FILE_IO_PREFIX "webadmin/template.lua");
diff --git a/src/World.cpp b/src/World.cpp
index f6d277663..012ba915b 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -46,7 +46,6 @@
#include "Generating/Trees.h"
#include "Bindings/PluginManager.h"
#include "Blocks/BlockHandler.h"
-#include "Vector3d.h"
#include "Tracer.h"
@@ -103,7 +102,7 @@ protected:
{
for (;;)
{
- LOG("%d chunks to load, %d chunks to generate",
+ LOG("" SIZE_T_FMT " chunks to load, %d chunks to generate",
m_World->GetStorage().GetLoadQueueLength(),
m_World->GetGenerator().GetQueueLength()
);
@@ -155,7 +154,7 @@ protected:
{
for (;;)
{
- LOG("%d chunks remaining to light", m_Lighting->GetQueueLength()
+ LOG("" SIZE_T_FMT " chunks remaining to light", m_Lighting->GetQueueLength()
);
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
@@ -1726,10 +1725,10 @@ int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType
-void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
+void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTicks, double a_InitialVelocityCoeff)
{
UNUSED(a_InitialVelocityCoeff);
- cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTimeInSec);
+ cTNTEntity * TNT = new cTNTEntity(a_X, a_Y, a_Z, a_FuseTicks);
TNT->Initialize(this);
// TODO: Add a bit of speed in horiz and vert axes, based on the a_InitialVelocityCoeff
}
@@ -2454,14 +2453,14 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3d & a_Pos, float a_SightLimit,
{
cTracer LineOfSight(this);
- float ClosestDistance = a_SightLimit;
- cPlayer* ClosestPlayer = NULL;
+ double ClosestDistance = a_SightLimit;
+ cPlayer * ClosestPlayer = NULL;
cCSLock Lock(m_CSPlayers);
for (cPlayerList::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{
Vector3f Pos = (*itr)->GetPosition();
- float Distance = (Pos - a_Pos).Length();
+ double Distance = (Pos - a_Pos).Length();
if (Distance < ClosestDistance)
{
@@ -2980,9 +2979,9 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
-int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed)
+int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed)
{
- cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed);
+ cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
if (Projectile == NULL)
{
return -1;
@@ -3005,18 +3004,18 @@ void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Resul
cCSLock Lock(m_CSPlayers);
for (cPlayerList::iterator itr = m_Players.begin(), end = m_Players.end(); itr != end; ++itr)
{
- size_t LastSpace = a_Text.find_last_of(" "); //Find the position of the last space
+ size_t LastSpace = a_Text.find_last_of(" "); // Find the position of the last space
- std::string LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); //Find the last word
- std::string PlayerName ((*itr)->GetName());
- std::size_t Found = PlayerName.find(LastWord); //Try to find last word in playername
+ AString LastWord = a_Text.substr(LastSpace + 1, a_Text.length()); // Find the last word
+ AString PlayerName ((*itr)->GetName());
+ size_t Found = PlayerName.find(LastWord); // Try to find last word in playername
- if (Found!=0)
+ if (Found == AString::npos)
{
- continue; //No match
+ continue; // No match
}
- a_Results.push_back((*itr)->GetName()); //Match!
+ a_Results.push_back(PlayerName); // Match!
}
}
diff --git a/src/World.h b/src/World.h
index 738697c94..1950104a8 100644
--- a/src/World.h
+++ b/src/World.h
@@ -14,8 +14,7 @@
#include "ChunkMap.h"
#include "WorldStorage/WorldStorage.h"
#include "Generating/ChunkGenerator.h"
-#include "Vector3i.h"
-#include "Vector3f.h"
+#include "Vector3.h"
#include "ChunkSender.h"
#include "Defines.h"
#include "LightingThread.h"
@@ -445,7 +444,7 @@ public:
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
/** Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided */
- void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
+ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, int a_FuseTimeInSec = 80, double a_InitialVelocityCoeff = 1);
// tolua_end
@@ -708,7 +707,7 @@ public:
int SpawnMobFinalize(cMonster* a_Monster);
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */
- int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp
index 8f80c3f75..be25fd1a4 100644
--- a/src/WorldStorage/FastNBT.cpp
+++ b/src/WorldStorage/FastNBT.cpp
@@ -506,22 +506,18 @@ void cFastNBTWriter::AddIntArray(const AString & a_Name, const int * a_Value, si
{
TagCommon(a_Name, TAG_IntArray);
Int32 len = htonl(a_NumElements);
+ size_t cap = m_Result.capacity();
+ size_t size = m_Result.length();
+ if ((cap - size) < (4 + a_NumElements * 4))
+ {
+ m_Result.reserve(size + 4 + (a_NumElements * 4));
+ }
m_Result.append((const char *)&len, 4);
-#if defined(ANDROID_NDK)
- // Android has alignment issues - cannot byteswap (htonl) an int that is not 32-bit-aligned, which happens in the regular version
for (size_t i = 0; i < a_NumElements; i++)
{
int Element = htonl(a_Value[i]);
m_Result.append((const char *)&Element, 4);
}
-#else
- int * Elements = (int *)(m_Result.data() + m_Result.size());
- m_Result.append(a_NumElements * 4, (char)0);
- for (size_t i = 0; i < a_NumElements; i++)
- {
- Elements[i] = htonl(a_Value[i]);
- }
-#endif
}
diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h
index 01a9ad274..1b8b09c21 100644
--- a/src/WorldStorage/FastNBT.h
+++ b/src/WorldStorage/FastNBT.h
@@ -309,7 +309,7 @@ protected:
eTagType m_ItemType; // for TAG_List, the element type
} ;
- static const int MAX_STACK = 50; // Highliy doubtful that an NBT would be constructed this many levels deep
+ static const int MAX_STACK = 50; // Highly doubtful that an NBT would be constructed this many levels deep
// These two fields emulate a stack. A raw array is used due to speed issues - no reallocations are allowed.
sParent m_Stack[MAX_STACK];
diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp
new file mode 100644
index 000000000..3c97ae0a2
--- /dev/null
+++ b/src/WorldStorage/FireworksSerializer.cpp
@@ -0,0 +1,256 @@
+
+#include "Globals.h"
+#include "FireworksSerializer.h"
+#include "WorldStorage/FastNBT.h"
+
+
+
+
+
+void cFireworkItem::WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type)
+{
+ switch (a_Type)
+ {
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ a_Writer.BeginCompound("Fireworks");
+ a_Writer.AddByte("Flight", a_FireworkItem.m_FlightTimeInTicks / 20);
+ a_Writer.BeginList("Explosions", TAG_Compound);
+ a_Writer.BeginCompound("");
+ a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
+ a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
+ a_Writer.AddByte("Type", a_FireworkItem.m_Type);
+ a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ a_Writer.EndCompound();
+ a_Writer.EndList();
+ a_Writer.EndCompound();
+ break;
+ }
+ case E_ITEM_FIREWORK_STAR:
+ {
+ a_Writer.BeginCompound("Explosion");
+ a_Writer.AddByte("Flicker", a_FireworkItem.m_HasFlicker);
+ a_Writer.AddByte("Trail", a_FireworkItem.m_HasTrail);
+ a_Writer.AddByte("Type", a_FireworkItem.m_Type);
+ if (!a_FireworkItem.m_Colours.empty())
+ {
+ a_Writer.AddIntArray("Colors", &(a_FireworkItem.m_Colours[0]), a_FireworkItem.m_Colours.size());
+ }
+ if (!a_FireworkItem.m_FadeColours.empty())
+ {
+ a_Writer.AddIntArray("FadeColors", &(a_FireworkItem.m_FadeColours[0]), a_FireworkItem.m_FadeColours.size());
+ }
+ a_Writer.EndCompound();
+ break;
+ }
+ default: ASSERT(!"Unhandled firework item!"); break;
+ }
+}
+
+
+
+
+
+void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type)
+{
+ if (a_TagIdx < 0)
+ {
+ return;
+ }
+
+ switch (a_Type)
+ {
+ case E_ITEM_FIREWORK_STAR:
+ {
+ for (int explosiontag = a_NBT.GetFirstChild(a_TagIdx); explosiontag >= 0; explosiontag = a_NBT.GetNextSibling(explosiontag))
+ {
+ eTagType TagType = a_NBT.GetType(explosiontag);
+ if (TagType == TAG_Byte) // Custon name tag
+ {
+ AString ExplosionName = a_NBT.GetName(explosiontag);
+
+ if (ExplosionName == "Flicker")
+ {
+ a_FireworkItem.m_HasFlicker = (a_NBT.GetByte(explosiontag) == 1);
+ }
+ else if (ExplosionName == "Trail")
+ {
+ a_FireworkItem.m_HasTrail = (a_NBT.GetByte(explosiontag) == 1);
+ }
+ else if (ExplosionName == "Type")
+ {
+ a_FireworkItem.m_Type = a_NBT.GetByte(explosiontag);
+ }
+ }
+ else if (TagType == TAG_IntArray)
+ {
+ AString ExplosionName = a_NBT.GetName(explosiontag);
+
+ if (ExplosionName == "Colors")
+ {
+ // Divide by four as data length returned in bytes
+ int DataLength = a_NBT.GetDataLength(explosiontag);
+ // round to the next highest multiple of four
+ DataLength -= DataLength % 4;
+ if (DataLength == 0)
+ {
+ continue;
+ }
+
+ const char * ColourData = (a_NBT.GetData(explosiontag));
+ for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ {
+ a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i));
+ }
+ }
+ else if (ExplosionName == "FadeColors")
+ {
+ int DataLength = a_NBT.GetDataLength(explosiontag) / 4;
+ // round to the next highest multiple of four
+ DataLength -= DataLength % 4;
+ if (DataLength == 0)
+ {
+ continue;
+ }
+
+ const char * FadeColourData = (a_NBT.GetData(explosiontag));
+ for (int i = 0; i < DataLength; i += 4 /* Size of network int*/)
+ {
+ a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i));
+ }
+ }
+ }
+ }
+ break;
+ }
+ case E_ITEM_FIREWORK_ROCKET:
+ {
+ for (int fireworkstag = a_NBT.GetFirstChild(a_TagIdx); fireworkstag >= 0; fireworkstag = a_NBT.GetNextSibling(fireworkstag))
+ {
+ eTagType TagType = a_NBT.GetType(fireworkstag);
+ if (TagType == TAG_Byte) // Custon name tag
+ {
+ if (a_NBT.GetName(fireworkstag) == "Flight")
+ {
+ a_FireworkItem.m_FlightTimeInTicks = a_NBT.GetByte(fireworkstag) * 20;
+ }
+ }
+ else if ((TagType == TAG_List) && (a_NBT.GetName(fireworkstag) == "Explosions"))
+ {
+ int ExplosionsChild = a_NBT.GetFirstChild(fireworkstag);
+ if ((a_NBT.GetType(ExplosionsChild) == TAG_Compound) && (a_NBT.GetName(ExplosionsChild).empty()))
+ {
+ ParseFromNBT(a_FireworkItem, a_NBT, ExplosionsChild, E_ITEM_FIREWORK_STAR);
+ }
+ }
+ }
+ break;
+ }
+ default: ASSERT(!"Unhandled firework item!"); break;
+ }
+}
+
+
+
+
+
+AString cFireworkItem::ColoursToString(const cFireworkItem & a_FireworkItem)
+{
+ AString Result;
+
+ for (std::vector<int>::const_iterator itr = a_FireworkItem.m_Colours.begin(); itr != a_FireworkItem.m_Colours.end(); ++itr)
+ {
+ AppendPrintf(Result, "%i;", *itr);
+ }
+
+ return Result;
+}
+
+
+
+
+
+void cFireworkItem::ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
+{
+ AStringVector Split = StringSplit(a_String, ";");
+
+ for (size_t itr = 0; itr < Split.size(); ++itr)
+ {
+ if (Split[itr].empty())
+ {
+ continue;
+ }
+
+ a_FireworkItem.m_Colours.push_back(atoi(Split[itr].c_str()));
+ }
+}
+
+
+
+
+
+AString cFireworkItem::FadeColoursToString(const cFireworkItem & a_FireworkItem)
+{
+ AString Result;
+
+ for (std::vector<int>::const_iterator itr = a_FireworkItem.m_FadeColours.begin(); itr != a_FireworkItem.m_FadeColours.end(); ++itr)
+ {
+ AppendPrintf(Result, "%i;", *itr);
+ }
+
+ return Result;
+}
+
+
+
+
+
+void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem)
+{
+ AStringVector Split = StringSplit(a_String, ";");
+
+ for (size_t itr = 0; itr < Split.size(); ++itr)
+ {
+ if (Split[itr].empty())
+ {
+ continue;
+ }
+
+ a_FireworkItem.m_FadeColours.push_back(atoi(Split[itr].c_str()));
+ }
+}
+
+
+
+
+
+int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
+{
+ /*
+ Colours are supposed to be calculated via: R << 16 + G << 8 + B
+ However, the RGB values fireworks use aren't the same as the ones for dyes (the ones listed in the MC Wiki)
+ Therefore, here is a list of numbers gotten via the Protocol Proxy
+ */
+
+ switch (a_DyeMeta)
+ {
+ case E_META_DYE_BLACK: return 0x1E1B1B;
+ case E_META_DYE_RED: return 0xB3312C;
+ case E_META_DYE_GREEN: return 0x3B511A;
+ case E_META_DYE_BROWN: return 0x51301A;
+ case E_META_DYE_BLUE: return 0x253192;
+ case E_META_DYE_PURPLE: return 0x7B2FBE;
+ case E_META_DYE_CYAN: return 0x287697;
+ case E_META_DYE_LIGHTGRAY: return 0xABABAB;
+ case E_META_DYE_GRAY: return 0x434343;
+ case E_META_DYE_PINK: return 0xD88198;
+ case E_META_DYE_LIGHTGREEN: return 0x41CD34;
+ case E_META_DYE_YELLOW: return 0xDECF2A;
+ case E_META_DYE_LIGHTBLUE: return 0x6689D3;
+ case E_META_DYE_MAGENTA: return 0xC354CD;
+ case E_META_DYE_ORANGE: return 0xEB8844;
+ case E_META_DYE_WHITE: return 0xF0F0F0;
+ default: ASSERT(!"Unhandled dye meta whilst trying to get colour code for fireworks!"); return 0;
+ }
+}
diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h
new file mode 100644
index 000000000..5b87bafdb
--- /dev/null
+++ b/src/WorldStorage/FireworksSerializer.h
@@ -0,0 +1,92 @@
+
+// FireworksSerializer.h
+
+// Declares the cFireworkItem class representing a firework or firework star
+
+
+
+
+
+#pragma once
+
+#include "Defines.h"
+
+class cFastNBTWriter;
+class cParsedNBT;
+
+
+
+
+
+class cFireworkItem
+{
+public:
+ cFireworkItem(void) :
+ m_HasFlicker(false),
+ m_HasTrail(false),
+ m_Type(0),
+ m_FlightTimeInTicks(0)
+ {
+ }
+
+ inline void CopyFrom(const cFireworkItem & a_Item)
+ {
+ m_FlightTimeInTicks = a_Item.m_FlightTimeInTicks;
+ m_HasFlicker = a_Item.m_HasFlicker;
+ m_HasTrail = a_Item.m_HasTrail;
+ m_Type = a_Item.m_Type;
+ m_Colours = a_Item.m_Colours;
+ m_FadeColours = a_Item.m_FadeColours;
+ }
+
+ inline void EmptyData(void)
+ {
+ m_FlightTimeInTicks = 0;
+ m_HasFlicker = false;
+ m_Type = 0;
+ m_HasTrail = false;
+ m_Colours.clear();
+ m_FadeColours.clear();
+ }
+
+ inline bool IsEqualTo(const cFireworkItem & a_Item) const
+ {
+ return
+ (
+ (m_FlightTimeInTicks == a_Item.m_FlightTimeInTicks) &&
+ (m_HasFlicker == a_Item.m_HasFlicker) &&
+ (m_HasTrail == a_Item.m_HasTrail) &&
+ (m_Type == a_Item.m_Type) &&
+ (m_Colours == a_Item.m_Colours) &&
+ (m_FadeColours == a_Item.m_FadeColours)
+ );
+ }
+
+ /** Writes firework NBT data to a Writer object */
+ static void WriteToNBTCompound(const cFireworkItem & a_FireworkItem, cFastNBTWriter & a_Writer, const ENUM_ITEM_ID a_Type);
+
+ /** Reads NBT data from a NBT object and populates a FireworkItem with it */
+ static void ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNBT & a_NBT, int a_TagIdx, const ENUM_ITEM_ID a_Type);
+
+ /** Converts the firework's vector of colours into a string of values separated by a semicolon */
+ static AString ColoursToString(const cFireworkItem & a_FireworkItem);
+
+ /** Parses a string containing encoded firework colours and populates a FireworkItem with it */
+ static void ColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
+
+ /** Converts the firework's vector of fade colours into a string of values separated by a semicolon */
+ static AString FadeColoursToString(const cFireworkItem & a_FireworkItem);
+
+ /** Parses a string containing encoded firework fade colours and populates a FireworkItem with it */
+ static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
+
+ /** Returns a colour code for fireworks used by the network code */
+ static int GetVanillaColourCodeFromDye(short a_DyeMeta);
+
+ bool m_HasFlicker;
+ bool m_HasTrail;
+ NIBBLETYPE m_Type;
+ short m_FlightTimeInTicks;
+ std::vector<int> m_Colours;
+ std::vector<int> m_FadeColours;
+}; \ No newline at end of file
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index 6d0e29958..acca96ba8 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -28,6 +28,10 @@
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/TNTEntity.h"
+#include "../Entities/ExpOrb.h"
+#include "../Entities/HangingEntity.h"
+#include "../Entities/ItemFrame.h"
#include "../Mobs/Monster.h"
#include "../Mobs/Bat.h"
@@ -91,11 +95,19 @@ void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AStrin
}
// Write the enchantments:
- if (!a_Item.m_Enchantments.IsEmpty())
+ if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)))
{
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
m_Writer.BeginCompound("tag");
- EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
+ if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))
+ {
+ cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
+
+ if (!a_Item.m_Enchantments.IsEmpty())
+ {
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ EnchantmentSerializer::WriteToNBTCompound(a_Item.m_Enchantments, m_Writer, TagName);
+ }
m_Writer.EndCompound();
}
@@ -517,8 +529,8 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
m_Writer.BeginCompound("");
AddBasicEntity(a_Pickup, "Item");
AddItem(a_Pickup->GetItem(), -1, "Item");
- m_Writer.AddShort("Health", a_Pickup->GetHealth());
- m_Writer.AddShort("Age", a_Pickup->GetAge());
+ m_Writer.AddShort("Health", (Int16)(unsigned char)a_Pickup->GetHealth());
+ m_Writer.AddShort("Age", (Int16)a_Pickup->GetAge());
m_Writer.EndCompound();
}
@@ -583,6 +595,66 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
+void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
+{
+ m_Writer.AddByte("Direction", (unsigned char)a_Hanging->GetDirection());
+ m_Writer.AddInt("TileX", a_Hanging->GetTileX());
+ m_Writer.AddInt("TileY", a_Hanging->GetTileY());
+ m_Writer.AddInt("TileZ", a_Hanging->GetTileZ());
+ switch (a_Hanging->GetDirection())
+ {
+ case 0: m_Writer.AddByte("Dir", (unsigned char)2); break;
+ case 1: m_Writer.AddByte("Dir", (unsigned char)1); break;
+ case 2: m_Writer.AddByte("Dir", (unsigned char)0); break;
+ case 3: m_Writer.AddByte("Dir", (unsigned char)3); break;
+ }
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddTNTEntity(cTNTEntity * a_TNT)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_TNT, "PrimedTnt");
+ m_Writer.AddByte("Fuse", (unsigned char)a_TNT->GetFuseTicks());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddExpOrbEntity(cExpOrb * a_ExpOrb)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_ExpOrb, "XPOrb");
+ m_Writer.AddShort("Health", (Int16)(unsigned char)a_ExpOrb->GetHealth());
+ m_Writer.AddShort("Age", (Int16)a_ExpOrb->GetAge());
+ m_Writer.AddShort("Value", (Int16)a_ExpOrb->GetReward());
+ m_Writer.EndCompound();
+}
+
+
+
+
+
+void cNBTChunkSerializer::AddItemFrameEntity(cItemFrame * a_ItemFrame)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_ItemFrame, "ItemFrame");
+ AddHangingEntity(a_ItemFrame);
+ AddItem(a_ItemFrame->GetItem(), -1, "Item");
+ m_Writer.AddByte("ItemRotation", (unsigned char)a_ItemFrame->GetRotation());
+ m_Writer.AddFloat("ItemDropChance", 1.0F);
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@@ -662,9 +734,9 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
- case cEntity::etTNT: /* TODO */ break;
- case cEntity::etExpOrb: /* TODO */ break;
- case cEntity::etItemFrame: /* TODO */ break;
+ case cEntity::etTNT: AddTNTEntity ((cTNTEntity *) a_Entity); break;
+ case cEntity::etExpOrb: AddExpOrbEntity ((cExpOrb *) a_Entity); break;
+ case cEntity::etItemFrame: AddItemFrameEntity ((cItemFrame *) a_Entity); break;
case cEntity::etPainting: /* TODO */ break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 8a9e18413..c1134cd00 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -41,6 +41,10 @@ class cMonster;
class cPickup;
class cItemGrid;
class cProjectileEntity;
+class cTNTEntity;
+class cExpOrb;
+class cHangingEntity;
+class cItemFrame;
@@ -107,6 +111,10 @@ protected:
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
void AddProjectileEntity (cProjectileEntity * a_Projectile);
+ void AddHangingEntity (cHangingEntity * a_Hanging);
+ void AddTNTEntity (cTNTEntity * a_TNT);
+ void AddExpOrbEntity (cExpOrb * a_ExpOrb);
+ void AddItemFrameEntity (cItemFrame * a_ItemFrame);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index b021aeb0c..ef67fdb13 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -177,6 +177,25 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
a_BlockArea.Clear();
a_BlockArea.SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (cBlockArea::baTypes | cBlockArea::baMetas) : cBlockArea::baTypes);
+ int TOffsetX = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetX");
+ int TOffsetY = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetY");
+ int TOffsetZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetZ");
+
+ if (
+ (TOffsetX < 0) || (TOffsetY < 0) || (TOffsetZ < 0) ||
+ (a_NBT.GetType(TOffsetX) != TAG_Int) ||
+ (a_NBT.GetType(TOffsetY) != TAG_Int) ||
+ (a_NBT.GetType(TOffsetZ) != TAG_Int)
+ )
+ {
+ // Not every schematic file has an offset, so we shoudn't give a warn message.
+ a_BlockArea.SetWEOffset(0, 0, 0);
+ }
+ else
+ {
+ a_BlockArea.SetWEOffset(a_NBT.GetInt(TOffsetX), a_NBT.GetInt(TOffsetY), a_NBT.GetInt(TOffsetZ));
+ }
+
// Copy the block types and metas:
int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
@@ -234,6 +253,10 @@ AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockA
Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
}
+ Writer.AddInt("WEOffsetX", a_BlockArea.m_WEOffset.x);
+ Writer.AddInt("WEOffsetY", a_BlockArea.m_WEOffset.y);
+ Writer.AddInt("WEOffsetZ", a_BlockArea.m_WEOffset.z);
+
// TODO: Save entities and block entities
Writer.BeginList("Entities", TAG_Compound);
Writer.EndList();
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 680f2458f..7a2366755 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -36,6 +36,10 @@
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
#include "../Entities/ProjectileEntity.h"
+#include "../Entities/TNTEntity.h"
+#include "../Entities/ExpOrb.h"
+#include "../Entities/HangingEntity.h"
+#include "../Entities/ItemFrame.h"
@@ -365,6 +369,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
{
case E_BLOCK_AIR:
case E_BLOCK_LEAVES:
+ case E_BLOCK_NEW_LEAVES:
{
// nothing needed
break;
@@ -506,10 +511,10 @@ cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_Bio
// The biomes stored don't match in size
return NULL;
}
- const int * BiomeData = (const int *)(a_NBT.GetData(a_TagIdx));
+ const char * BiomeData = (a_NBT.GetData(a_TagIdx));
for (size_t i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++)
{
- (*a_BiomeMap)[i] = (EMCSBiome)(ntohl(BiomeData[i]));
+ (*a_BiomeMap)[i] = (EMCSBiome)(GetBEInt(&BiomeData[i * 4]));
if ((*a_BiomeMap)[i] == 0xff)
{
// Unassigned biomes
@@ -663,6 +668,12 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_
{
EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag);
}
+
+ int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion"));
+ if (EnchTag > 0)
+ {
+ cFireworkItem::ParseFromNBT(a_Item.m_FireworkItem, a_NBT, FireworksTag, (ENUM_ITEM_ID)a_Item.m_ItemType);
+ }
return true;
}
@@ -1091,6 +1102,18 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "PrimedTnt", a_IDTagLength) == 0)
+ {
+ LoadTNTFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
+ else if (strncmp(a_IDTag, "XPOrb", a_IDTagLength) == 0)
+ {
+ LoadExpOrbFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
+ else if (strncmp(a_IDTag, "ItemFrame", a_IDTagLength) == 0)
+ {
+ LoadItemFrameFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
{
LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1373,6 +1396,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT
void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
+ // Load item:
int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
{
@@ -1383,11 +1407,27 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
return;
}
+
std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false
if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx))
{
return;
}
+
+ // Load health:
+ int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
+ if (Health > 0)
+ {
+ Pickup->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
+ }
+
+ // Load age:
+ int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
+ if (Age > 0)
+ {
+ Pickup->SetAge(a_NBT.GetShort(Age));
+ }
+
a_Entities.push_back(Pickup.release());
}
@@ -1395,6 +1435,148 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
+void cWSSAnvil::LoadTNTFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cTNTEntity> TNT(new cTNTEntity(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*TNT.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load Fuse Ticks:
+ int FuseTicks = a_NBT.FindChildByName(a_TagIdx, "Fuse");
+ if (FuseTicks > 0)
+ {
+ TNT->SetFuseTicks((int) a_NBT.GetByte(FuseTicks));
+ }
+
+ a_Entities.push_back(TNT.release());
+}
+
+
+
+
+
+void cWSSAnvil::LoadExpOrbFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cExpOrb> ExpOrb(new cExpOrb(0.0, 0.0, 0.0, 0));
+ if (!LoadEntityBaseFromNBT(*ExpOrb.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load Health:
+ int Health = a_NBT.FindChildByName(a_TagIdx, "Health");
+ if (Health > 0)
+ {
+ ExpOrb->SetHealth((int) (a_NBT.GetShort(Health) & 0xFF));
+ }
+
+ // Load Age:
+ int Age = a_NBT.FindChildByName(a_TagIdx, "Age");
+ if (Age > 0)
+ {
+ ExpOrb->SetAge(a_NBT.GetShort(Age));
+ }
+
+ // Load Reward (Value):
+ int Reward = a_NBT.FindChildByName(a_TagIdx, "Value");
+ if (Reward > 0)
+ {
+ ExpOrb->SetReward(a_NBT.GetShort(Reward));
+ }
+
+ a_Entities.push_back(ExpOrb.release());
+}
+
+
+
+
+
+void cWSSAnvil::LoadHangingFromNBT(cHangingEntity & a_Hanging, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ int Direction = a_NBT.FindChildByName(a_TagIdx, "Direction");
+ if (Direction > 0)
+ {
+ Direction = (int)a_NBT.GetByte(Direction);
+ if ((Direction < 0) || (Direction > 5))
+ {
+ a_Hanging.SetDirection(BLOCK_FACE_NORTH);
+ }
+ else
+ {
+ a_Hanging.SetDirection(static_cast<eBlockFace>(Direction));
+ }
+ }
+ else
+ {
+ Direction = a_NBT.FindChildByName(a_TagIdx, "Dir");
+ if (Direction > 0)
+ {
+ switch ((int)a_NBT.GetByte(Direction))
+ {
+ case 0: a_Hanging.SetDirection(BLOCK_FACE_NORTH); break;
+ case 1: a_Hanging.SetDirection(BLOCK_FACE_TOP); break;
+ case 2: a_Hanging.SetDirection(BLOCK_FACE_BOTTOM); break;
+ case 3: a_Hanging.SetDirection(BLOCK_FACE_SOUTH); break;
+ }
+ }
+ }
+
+ int TileX = a_NBT.FindChildByName(a_TagIdx, "TileX");
+ int TileY = a_NBT.FindChildByName(a_TagIdx, "TileY");
+ int TileZ = a_NBT.FindChildByName(a_TagIdx, "TileZ");
+ if ((TileX > 0) && (TileY > 0) && (TileZ > 0))
+ {
+ a_Hanging.SetPosition(
+ (double)a_NBT.GetInt(TileX),
+ (double)a_NBT.GetInt(TileY),
+ (double)a_NBT.GetInt(TileZ)
+ );
+ }
+}
+
+
+
+
+
+void cWSSAnvil::LoadItemFrameFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ // Load item:
+ int ItemTag = a_NBT.FindChildByName(a_TagIdx, "Item");
+ if ((ItemTag < 0) || (a_NBT.GetType(ItemTag) != TAG_Compound))
+ {
+ return;
+ }
+ cItem Item;
+ if (!LoadItemFromNBT(Item, a_NBT, ItemTag))
+ {
+ return;
+ }
+
+ std::auto_ptr<cItemFrame> ItemFrame(new cItemFrame(BLOCK_FACE_NONE, 0.0, 0.0, 0.0));
+ if (!LoadEntityBaseFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+ ItemFrame->SetItem(Item);
+
+ LoadHangingFromNBT(*ItemFrame.get(), a_NBT, a_TagIdx);
+
+ // Load Rotation:
+ int Rotation = a_NBT.FindChildByName(a_TagIdx, "ItemRotation");
+ if (Rotation > 0)
+ {
+ ItemFrame->SetRotation((Byte)a_NBT.GetByte(Rotation));
+ }
+
+ a_Entities.push_back(ItemFrame.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index b26345b13..50d0e555e 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -20,6 +20,7 @@
class cItemGrid;
class cProjectileEntity;
+class cHangingEntity;
@@ -149,6 +150,10 @@ protected:
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadExpOrbFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadHangingFromNBT (cHangingEntity & a_Hanging,const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadItemFrameFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartRFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartCFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index 5e49e4909..bb9d4b9e6 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -39,7 +39,7 @@ struct cWSSCompact::sChunkHeader
/// The maximum number of PAK files that are cached
-const int MAX_PAK_FILES = 16;
+const size_t MAX_PAK_FILES = 16;
/// The maximum number of unsaved chunks before the cPAKFile saves them to disk
const int MAX_DIRTY_CHUNKS = 16;
@@ -569,7 +569,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
if( ChunksConverted % 32 == 0 )
{
- LOGINFO("Updating \"%s\" version 1 to version 2: %d %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
+ LOGINFO("Updating \"%s\" version 1 to version 2: " SIZE_T_FMT " %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
}
ChunksConverted++;
@@ -607,7 +607,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
if (UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
UncompressedSize, UncompressedData.size(),
Header->m_ChunkX, Header->m_ChunkZ
);
@@ -713,7 +713,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
if( ChunksConverted % 32 == 0 )
{
- LOGINFO("Updating \"%s\" version 2 to version 3: %d %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
+ LOGINFO("Updating \"%s\" version 2 to version 3: " SIZE_T_FMT " %%", m_FileName.c_str(), (ChunksConverted * 100) / m_ChunkHeaders.size() );
}
ChunksConverted++;
@@ -751,7 +751,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
if (UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
UncompressedSize, UncompressedData.size(),
Header->m_ChunkX, Header->m_ChunkZ
);
@@ -764,7 +764,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
// Cannot use cChunk::MakeIndex because it might change again?????????
// For compatibility, use what we know is current
- #define MAKE_2_INDEX( x, y, z ) ( y + (z * 256) + (x * 256 * 16) )
#define MAKE_3_INDEX( x, y, z ) ( x + (z * 16) + (y * 16 * 16) )
unsigned int InChunkOffset = 0;
@@ -867,7 +866,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
if (a_UncompressedSize != (int)UncompressedData.size())
{
- LOGWARNING("Uncompressed data size differs (exp %d bytes, got %d) for chunk [%d, %d]",
+ LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]",
a_UncompressedSize, UncompressedData.size(),
a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ
);
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 64b8d7f31..4df146ec3 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -12,7 +12,7 @@
#define WSSCOMPACT_H_INCLUDED
#include "WorldStorage.h"
-#include "../Vector3i.h"
+#include "../Vector3.h"
#include "json/json.h"