summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua76
-rw-r--r--MCServer/Plugins/APIDump/Classes/BlockEntities.lua14
m---------MCServer/Plugins/Core0
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua53
-rw-r--r--MCServer/Plugins/InfoDump.lua31
-rw-r--r--SetFlags.cmake11
m---------lib/polarssl0
-rw-r--r--src/Bindings/AllToLua.pkg2
-rw-r--r--src/Bindings/LuaState.cpp19
-rw-r--r--src/Bindings/LuaState.h97
-rw-r--r--src/Bindings/ManualBindings.cpp343
-rw-r--r--src/BlockEntities/BlockEntity.cpp2
-rw-r--r--src/BlockEntities/FlowerPotEntity.cpp134
-rw-r--r--src/BlockEntities/FlowerPotEntity.h74
-rw-r--r--src/BlockInfo.cpp30
-rw-r--r--src/BlockInfo.h27
-rw-r--r--src/Blocks/BlockBed.h5
-rw-r--r--src/Blocks/BlockButton.h5
-rw-r--r--src/Blocks/BlockChest.h5
-rw-r--r--src/Blocks/BlockComparator.h12
-rw-r--r--src/Blocks/BlockDoor.cpp25
-rw-r--r--src/Blocks/BlockDoor.h59
-rw-r--r--src/Blocks/BlockDropSpenser.h19
-rw-r--r--src/Blocks/BlockEnderchest.h6
-rw-r--r--src/Blocks/BlockFenceGate.h12
-rw-r--r--src/Blocks/BlockFlowerPot.h83
-rw-r--r--src/Blocks/BlockHandler.cpp56
-rw-r--r--src/Blocks/BlockHandler.h27
-rw-r--r--src/Blocks/BlockMobHead.h5
-rw-r--r--src/Blocks/BlockRedstoneRepeater.h9
-rw-r--r--src/Blocks/BlockStairs.h76
-rw-r--r--src/Blocks/BlockTNT.h32
-rw-r--r--src/Blocks/BlockTorch.h67
-rw-r--r--src/Blocks/BlockTrapdoor.h10
-rw-r--r--src/Blocks/BlockVine.h24
-rw-r--r--src/Blocks/ChunkInterface.cpp2
-rw-r--r--src/Blocks/MetaRotater.h120
-rw-r--r--src/Blocks/WorldInterface.h3
-rw-r--r--src/ByteBuffer.cpp66
-rw-r--r--src/ByteBuffer.h30
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/Chunk.cpp37
-rw-r--r--src/Chunk.h11
-rw-r--r--src/ChunkMap.cpp22
-rw-r--r--src/ChunkMap.h9
-rw-r--r--src/ClientHandle.cpp95
-rw-r--r--src/ClientHandle.h4
-rw-r--r--src/CompositeChat.h17
-rw-r--r--src/Defines.h6
-rw-r--r--src/Entities/Floater.h2
-rw-r--r--src/Entities/Minecart.cpp4
-rw-r--r--src/Entities/Minecart.h4
-rw-r--r--src/Generating/MineShafts.cpp2
-rw-r--r--src/Generating/Trees.cpp2
-rw-r--r--src/Inventory.cpp6
-rw-r--r--src/Items/ItemHandler.cpp2
-rw-r--r--src/Items/ItemHandler.h3
-rw-r--r--src/Items/ItemPickaxe.h22
-rw-r--r--src/Mobs/Villager.cpp2
-rw-r--r--src/OSSupport/SocketThreads.h2
-rw-r--r--src/Protocol/Protocol.h2
-rw-r--r--src/Protocol/Protocol125.cpp13
-rw-r--r--src/Protocol/Protocol125.h22
-rw-r--r--src/Protocol/Protocol132.cpp2
-rw-r--r--src/Protocol/Protocol132.h2
-rw-r--r--src/Protocol/Protocol16x.cpp11
-rw-r--r--src/Protocol/Protocol17x.cpp32
-rw-r--r--src/Protocol/Protocol17x.h2
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp2
-rw-r--r--src/Protocol/ProtocolRecognizer.h2
-rw-r--r--src/Root.cpp7
-rw-r--r--src/Scoreboard.cpp14
-rw-r--r--src/Simulator/DelayedFluidSimulator.cpp2
-rw-r--r--src/Simulator/FloodyFluidSimulator.cpp91
-rw-r--r--src/Simulator/FloodyFluidSimulator.h18
-rw-r--r--src/Simulator/IncrementalRedstoneSimulator.cpp8
-rw-r--r--src/Simulator/VanillaFluidSimulator.cpp150
-rw-r--r--src/Simulator/VanillaFluidSimulator.h42
-rw-r--r--src/World.cpp139
-rw-r--r--src/World.h25
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp15
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp133
-rw-r--r--src/WorldStorage/SchematicFileSerializer.h33
-rw-r--r--src/WorldStorage/WSSAnvil.cpp36
-rw-r--r--src/WorldStorage/WSSAnvil.h1
-rw-r--r--src/WorldStorage/WSSCompact.cpp40
88 files changed, 2146 insertions, 626 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a0a332f30..7ec7058ae 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,8 +22,10 @@ Code Stuff
- This helps prevent mistakes such as `if (a & 1 == 0)`
* White space is free, so use it freely
- "freely" as in "plentifully", not "arbitrarily"
+ * All `case` statements inside a `switch` need an extra indent.
* Each and every control statement deserves its braces. This helps maintainability later on when the file is edited, lines added or removed - the control logic doesn't break so easily.
- The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form.
+ - These two rules really mean that indent is governed by braces
* Add an empty last line in all source files (GCC and GIT can complain otherwise)
* Use doxy-comments for functions in the header file, format as `/** Description */`
* Use spaces after the comment markers: `// Comment` instead of `//Comment`
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 0b6f33b37..1e572492b 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -134,6 +134,7 @@ g_APIDesc =
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
HasBlockTypes = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block types" },
LoadFromSchematicFile = { Params = "FileName", Return = "", Notes = "Clears current content and loads new content from the specified schematic file. Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
+ LoadFromSchematicString = { Params = "SchematicData", Return = "", Notes = "Clears current content and loads new content from the specified string (assumed to contain .schematic data). Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
Merge =
{
{ Params = "BlockAreaSrc, {{Vector3i|RelMinCoords}}, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
@@ -161,6 +162,7 @@ g_APIDesc =
RotateCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Modifies blocks' metas (if present) to match." },
RotateCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Doesn't modify blocks' metas." },
SaveToSchematicFile = { Params = "FileName", Return = "", Notes = "Saves the current contents to a schematic file. Returns true if successful." },
+ SaveToSchematicString = { Params = "", Return = "string", Notes = "Saves the current contents to a string (in a .schematic file format). Returns the data if successful, nil if failed." },
SetBlockLight = { Params = "BlockX, BlockY, BlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified absolute coords" },
SetBlockMeta = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified absolute coords" },
SetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified absolute coords" },
@@ -483,6 +485,58 @@ end
},
}, -- cClientHandle
+ cCompositeChat =
+ {
+ Desc = [[
+ Encapsulates a chat message that can contain various formatting, URLs, commands executed on click
+ and commands suggested on click. The chat message can be sent by the regular chat-sending functions,
+ {{cPlayer}}:SendMessage(), {{cWorld}}:BroadcastChat() and {{cRoot}}:BroadcastChat().</p>
+ <p>
+ Note that most of the functions in this class are so-called modifiers - they modify the object and
+ then return the object itself, so that they can be chained one after another.
+ ]],
+ Functions =
+ {
+ constructor =
+ {
+ { Params = "", Return = "", Notes = "Creates an empty chat message" },
+ { Params = "Text", Return = "", Notes = "Creates a chat message containing the specified text, parsed by the ParseText() function. This allows easy migration from old chat messages." },
+ },
+ AddRunCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, runs the specified command. Chaining." },
+ AddSuggestCommandPart = { Params = "Text, Command, [Style]", Return = "self", Notes = "Adds a text which, when clicked, puts the specified command into the player's chat input area. Chaining." },
+ AddTextPart = { Params = "Text, [Style]", Return = "self", Notes = "Adds a regular text. Chaining." },
+ AddUrlPart = { Params = "Text, Url, [Style]", Return = "self", Notes = "Adds a text which, when clicked, opens up a browser at the specified URL. Chaining." },
+ Clear = { Params = "", Return = "", Notes = "Removes all parts from this object" },
+ GetMessageType = { Params = "", Return = "MessageType", Notes = "Returns the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.)" },
+ ParseText = { Params = "Text", Return = "self", Notes = "Adds text, while recognizing http and https URLs and old-style formatting codes (\"@2\"). Chaining." },
+ SetMessageType = { Params = "MessageType", Return = "self", Notes = "Sets the MessageType (mtXXX constant) that is associated with this message. When sent to a player, the message will be formatted according to this message type and the player's settings (adding \"[INFO]\" prefix etc.) Chaining." },
+ UnderlineUrls = { Params = "", Return = "self", Notes = "Makes all URL parts contained in the message underlined. Doesn't affect parts added in the future. Chaining." },
+ },
+
+ AdditionalInfo =
+ {
+ {
+ Header = "Chaining example",
+ Contents = [[
+ Sending a chat message that is composed of multiple different parts has been made easy thanks to
+ chaining. Consider the following example that shows how a message containing all kinds of parts
+ is sent (adapted from the Debuggers plugin):
+<pre class="prettyprint lang-lua">
+function OnPlayerJoined(a_Player)
+ -- Send an example composite chat message to the player:
+ a_Player:SendMessage(cCompositeChat()
+ :AddTextPart("Hello, ")
+ :AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2") -- Colored underlined link
+ :AddSuggestCommandPart(", and welcome.", "/help", "u") -- Underlined suggest-command
+ :AddRunCommandPart(" SetDay", "/time set 0") -- Regular text that will execute command when clicked
+ :SetMessageType(mtJoin) -- It is a join-message
+ )
+end</pre>
+ ]],
+ },
+ }, -- AdditionalInfo
+ }, -- cCompositeChat
+
cCraftingGrid =
{
Desc = [[
@@ -2098,7 +2152,9 @@ end
DoWithDropSpenserAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper or a dispenser at the specified coords, calls the CallbackFunction with the {{cDropSpenserEntity}} parameter representing the dropper or dispenser. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropSpenserEntity|DropSpenserEntity}}, [CallbackData])</pre> Note that this can be used to access both dispensers and droppers in a similar way. The function returns false if there is neither dispenser nor dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithDropperAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a dropper at the specified coords, calls the CallbackFunction with the {{cDropperEntity}} parameter representing the dropper. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cDropperEntity|DropperEntity}}, [CallbackData])</pre> The function returns false if there is no dropper, or if there is, it returns the bool value that the callback has returned." },
DoWithEntityByID = { Params = "EntityID, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If an entity with the specified ID exists, calls the callback with the {{cEntity}} parameter representing the entity. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cEntity|Entity}}, [CallbackData])</pre> The function returns false if the entity was not found, and it returns the same bool value that the callback has returned if the entity was found." },
+ DoWithFlowerPotAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a flower pot at the specified coords, calls the CallbackFunction with the {{cFlowerPotEntity}} parameter representing the flower pot. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFlowerPotEntity|FlowerPotEntity}}, [CallbackData])</pre> The function returns false if there is no flower pot, or if there is, it returns the bool value that the callback has returned." },
DoWithFurnaceAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a furnace at the specified coords, calls the CallbackFunction with the {{cFurnaceEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cFurnaceEntity|FurnaceEntity}}, [CallbackData])</pre> The function returns false if there is no furnace, or if there is, it returns the bool value that the callback has returned." },
+ DoWithMobHeadAt = { Params = "X, Y, Z, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a mob head at the specified coords, calls the CallbackFunction with the {{cMobHeadEntity}} parameter representing the furnace. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cMobHeadEntity|MobHeadEntity}}, [CallbackData])</pre> The function returns false if there is no mob head, or if there is, it returns the bool value that the callback has returned." },
DoWithNoteBlockAt = { Params = "BlockX, BlockY, BlockZ, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a note block at the specified coords, calls the CallbackFunction with the {{cNoteEntity}} parameter representing the note block. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cNoteEntity|NoteEntity}}, [CallbackData])</pre> The function returns false if there is no note block, or if there is, it returns the bool value that the callback has returned." },
DoWithPlayer = { Params = "PlayerName, CallbackFunction, [CallbackData]", Return = "bool", Notes = "If there is a player of the specified name (exact match), calls the CallbackFunction with the {{cPlayer}} parameter representing the player. The CallbackFunction has the following signature: <pre class=\"prettyprint lang-lua\">function Callback({{cPlayer|Player}}, [CallbackData])</pre> The function returns false if the player was not found, or whatever bool value the callback returned if the player was found." },
FastSetBlock =
@@ -2701,16 +2757,16 @@ end
IgnoreClasses =
{
- "coroutine",
- "debug",
- "io",
- "math",
- "package",
- "os",
- "string",
- "table",
- "g_Stats",
- "g_TrackedPages",
+ "^coroutine$",
+ "^debug$",
+ "^io$",
+ "^math$",
+ "^package$",
+ "^os$",
+ "^string$",
+ "^table$",
+ "^g_Stats$",
+ "^g_TrackedPages$",
},
IgnoreFunctions =
diff --git a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
index 61a8e8d22..de42f66df 100644
--- a/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
+++ b/MCServer/Plugins/APIDump/Classes/BlockEntities.lua
@@ -238,6 +238,20 @@ World:ForEachChestInChunk(Player:GetChunkX(), Player:GetChunkZ(),
},
Inherits = "cBlockEntity";
}, -- cSignEntity
+
+ cFlowerPotEntity =
+ {
+ Desc = [[
+ This class represents a flower pot entity in the world.
+ ]],
+ Functions =
+ {
+ IsItemInPot = { Params = "", Return = "bool", Notes = "Is a flower in the pot?" },
+ GetItem = { Params = "", Return = "{{cItem|Item}}", Notes = "Returns the item in the flower pot." },
+ SetItem = { Params = "{{cItem|Item}}", Return = "", Notes = "Set the item in the flower pot" },
+ },
+ Inherits = "cBlockEntity";
+ }, -- cFlowerPotEntity
}
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core
-Subproject 3b416b07a339b3abcbc127070d56eea05b05373
+Subproject 013a32a7fb3c8a6cfe0aef892d4c7394d4e1be5
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index 66894d835..f99c48242 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -30,6 +30,7 @@ function Initialize(Plugin)
PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
PM:AddHook(cPluginManager.HOOK_PLUGINS_LOADED, OnPluginsLoaded);
PM:AddHook(cPluginManager.HOOK_PLUGIN_MESSAGE, OnPluginMessage);
+ PM:AddHook(cPluginManager.HOOK_PLAYER_JOINED, OnPlayerJoined)
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
@@ -70,6 +71,8 @@ function Initialize(Plugin)
-- TestExpatBindings();
-- TestPluginCalls();
+ TestBlockAreasString()
+
return true
end;
@@ -201,6 +204,42 @@ end
+function TestBlockAreasString()
+ -- Write one area to string, then to file:
+ local BA1 = cBlockArea()
+ BA1:Create(5, 5, 5, cBlockArea.baTypes + cBlockArea.baMetas)
+ BA1:Fill(cBlockArea.baTypes, E_BLOCK_DIAMOND_BLOCK)
+ BA1:FillRelCuboid(1, 3, 1, 3, 1, 3, cBlockArea.baTypes, E_BLOCK_GOLD_BLOCK)
+ local Data = BA1:SaveToSchematicString()
+ if ((type(Data) ~= "string") or (Data == "")) then
+ LOG("Cannot save schematic to string")
+ return
+ end
+ cFile:CreateFolder("schematics")
+ local f = io.open("schematics/StringTest.schematic", "w")
+ f:write(Data)
+ f:close()
+
+ -- Load a second area from that file:
+ local BA2 = cBlockArea()
+ if not(BA2:LoadFromSchematicFile("schematics/StringTest.schematic")) then
+ LOG("Cannot read schematic from string test file")
+ return
+ end
+ BA2:Clear()
+
+ -- Load another area from a string in that file:
+ f = io.open("schematics/StringTest.schematic", "r")
+ Data = f:read("*all")
+ if not(BA2:LoadFromSchematicString(Data)) then
+ LOG("Cannot load schematic from string")
+ end
+end
+
+
+
+
+
function TestSQLiteBindings()
LOG("Testing SQLite bindings...");
@@ -1258,3 +1297,17 @@ end
+
+function OnPlayerJoined(a_Player)
+ -- Test composite chat chaining:
+ a_Player:SendMessage(cCompositeChat()
+ :AddTextPart("Hello, ")
+ :AddUrlPart(a_Player:GetName(), "www.mc-server.org", "u@2")
+ :AddSuggestCommandPart(", and welcome.", "/help", "u")
+ :AddRunCommandPart(" SetDay", "/time set 0")
+ )
+end
+
+
+
+
diff --git a/MCServer/Plugins/InfoDump.lua b/MCServer/Plugins/InfoDump.lua
index e7ed157e3..c61f9c9e6 100644
--- a/MCServer/Plugins/InfoDump.lua
+++ b/MCServer/Plugins/InfoDump.lua
@@ -317,26 +317,19 @@ local function WriteCommandsCategoryGithub(a_Category, f)
if (CategoryName == "") then
CategoryName = "General";
end
- f:write("\n## ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
+ f:write("\n### ", GithubizeString(a_Category.DisplayName or CategoryName), "\n");
-- Write description:
if (a_Category.Description ~= "") then
- f:write(GithubizeString(a_Category.Description), "\n");
+ f:write(GithubizeString(a_Category.Description), "\n\n");
end
+ f:write("| Command | Permission | Description | \n")
+ f:write("| ------- | ---------- | ----------- | \n")
+
-- Write commands:
- f:write("\n");
for idx2, cmd in ipairs(a_Category.Commands) do
- f:write("\n### ", cmd.CommandString, "\n", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "\n\n");
- if (cmd.Info.Permission ~= nil) then
- f:write("Permission required: **", cmd.Info.Permission, "**\n\n");
- end
- if (cmd.Info.DetailedDescription ~= nil) then
- f:write(GithubizeString(cmd.Info.DetailedDescription));
- end
- if (cmd.Info.ParameterCombinations ~= nil) then
- WriteCommandParameterCombinationsGithub(cmd.CommandString, cmd.Info.ParameterCombinations, f);
- end
+ f:write("|", cmd.CommandString, " | ", cmd.Info.Permission or "", " | ", GithubizeString(cmd.Info.HelpString or "UNDOCUMENTED"), "| \n")
end
f:write("\n\n")
end
@@ -537,12 +530,13 @@ local function DumpPermissionsGithub(a_PluginInfo, f)
-- Dump the permissions:
f:write("\n# Permissions\n");
+ f:write("| Permissions | Description | Commands | Recommended groups |\n")
+ f:write("| ----------- | ----------- | -------- | ------------------ |\n")
for idx, perm in ipairs(Permissions) do
- f:write("### ", perm.Name, "\n");
- f:write(GithubizeString(perm.Info.Description or ""));
+ f:write(perm.Name, " | ");
+ f:write(GithubizeString(perm.Info.Description or ""), " | ");
local CommandsAffected = perm.Info.CommandsAffected or {};
if (#CommandsAffected > 0) then
- f:write("\n\nCommands affected:\n - ");
local Affects = {};
for idx2, cmd in ipairs(CommandsAffected) do
if (type(cmd) == "string") then
@@ -551,11 +545,10 @@ local function DumpPermissionsGithub(a_PluginInfo, f)
table.insert(Affects, GetCommandRefGithub(cmd.Name, cmd));
end
end
- f:write(table.concat(Affects, "\n - "));
- f:write("\n");
+ f:write(table.concat(Affects, ", "), " | ");
end
if (perm.Info.RecommendedGroups ~= nil) then
- f:write("\n\nRecommended groups: ", perm.Info.RecommendedGroups, "\n");
+ f:write(perm.Info.RecommendedGroups, " |");
end
f:write("\n");
end
diff --git a/SetFlags.cmake b/SetFlags.cmake
index ded57e6d7..6a8211fa2 100644
--- a/SetFlags.cmake
+++ b/SetFlags.cmake
@@ -1,5 +1,3 @@
-
-
macro (add_flags_lnk FLAGS)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
@@ -62,6 +60,7 @@ macro(set_flags)
# We use a signed char (fixes #640 on RasPi)
add_flags_cxx("-fsigned-char")
+
endif()
@@ -184,6 +183,14 @@ macro(set_exe_flags)
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")
+
+ # 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")
+ add_flags_cxx("-D__extern_always_inline=inline")
+ endif()
endif()
endmacro()
diff --git a/lib/polarssl b/lib/polarssl
-Subproject 2ceda579893ceb23c5eb0d56df47dc235644e0f
+Subproject 2cb1a0c4009ecf368ecc74eb428394e10f9e6d0
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index 6b067b1e5..2676281f9 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -58,6 +58,8 @@ $cfile "../BlockEntities/HopperEntity.h"
$cfile "../BlockEntities/JukeboxEntity.h"
$cfile "../BlockEntities/NoteEntity.h"
$cfile "../BlockEntities/SignEntity.h"
+$cfile "../BlockEntities/MobHeadEntity.h"
+$cfile "../BlockEntities/FlowerPotEntity.h"
$cfile "../WebAdmin.h"
$cfile "../Root.h"
$cfile "../Vector3f.h"
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index a5540df17..aa6ee05b3 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -677,6 +677,7 @@ void cLuaState::Push(Vector3i * a_Vector)
void cLuaState::Push(void * a_Ptr)
{
+ UNUSED(a_Ptr);
ASSERT(IsValid());
// Investigate the cause of this - what is the callstack?
@@ -716,7 +717,7 @@ void cLuaState::Push(cBlockEntity * a_BlockEntity)
-void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, bool & a_ReturnedVal)
{
a_ReturnedVal = (tolua_toboolean(m_LuaState, a_StackPos, a_ReturnedVal ? 1 : 0) > 0);
}
@@ -725,11 +726,17 @@ void cLuaState::GetReturn(int a_StackPos, bool & a_ReturnedVal)
-void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, AString & a_Value)
{
- if (lua_isstring(m_LuaState, a_StackPos))
+ size_t len = 0;
+ const char * data = lua_tolstring(m_LuaState, a_StackPos, &len);
+ if (data != NULL)
+ {
+ a_Value.assign(data, len);
+ }
+ else
{
- a_ReturnedVal = tolua_tocppstring(m_LuaState, a_StackPos, a_ReturnedVal.c_str());
+ a_Value.clear();
}
}
@@ -737,7 +744,7 @@ void cLuaState::GetReturn(int a_StackPos, AString & a_ReturnedVal)
-void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, int & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
{
@@ -749,7 +756,7 @@ void cLuaState::GetReturn(int a_StackPos, int & a_ReturnedVal)
-void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal)
+void cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
{
if (lua_isnumber(m_LuaState, a_StackPos))
{
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index dcb660c3f..4a7a6fadb 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -197,6 +197,19 @@ public:
void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity);
+
+ /** Retrieve value at a_StackPos, if it is a valid bool. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, bool & a_Value);
+
+ /** Retrieve value at a_StackPos, if it is a valid string. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, AString & a_Value);
+
+ /** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, int & a_Value);
+
+ /** Retrieve value at a_StackPos, if it is a valid number. If not, a_Value is unchanged */
+ void GetStackValue(int a_StackPos, double & a_Value);
+
/** Call any 0-param 0-return Lua function in a single line: */
template <typename FnT>
@@ -270,7 +283,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -292,7 +305,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
ASSERT(InitialTop == lua_gettop(m_LuaState));
return true;
@@ -315,7 +328,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -338,7 +351,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -362,7 +375,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -387,7 +400,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -414,7 +427,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -442,7 +455,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -471,7 +484,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -501,7 +514,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -532,7 +545,7 @@ public:
{
return false;
}
- GetReturn(-1, a_Ret1);
+ GetStackValue(-1, a_Ret1);
lua_pop(m_LuaState, 1);
return true;
}
@@ -553,8 +566,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -576,8 +589,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -601,8 +614,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -627,8 +640,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -654,8 +667,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -683,8 +696,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -713,8 +726,8 @@ public:
{
return false;
}
- GetReturn(-2, a_Ret1);
- GetReturn(-1, a_Ret2);
+ GetStackValue(-2, a_Ret1);
+ GetStackValue(-1, a_Ret2);
lua_pop(m_LuaState, 2);
return true;
}
@@ -743,9 +756,9 @@ public:
{
return false;
}
- GetReturn(-3, a_Ret1);
- GetReturn(-2, a_Ret2);
- GetReturn(-1, a_Ret3);
+ GetStackValue(-3, a_Ret1);
+ GetStackValue(-2, a_Ret2);
+ GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3);
return true;
}
@@ -775,9 +788,9 @@ public:
{
return false;
}
- GetReturn(-3, a_Ret1);
- GetReturn(-2, a_Ret2);
- GetReturn(-1, a_Ret3);
+ GetStackValue(-3, a_Ret1);
+ GetStackValue(-2, a_Ret2);
+ GetStackValue(-1, a_Ret3);
lua_pop(m_LuaState, 3);
return true;
}
@@ -808,11 +821,11 @@ public:
{
return false;
}
- GetReturn(-5, a_Ret1);
- GetReturn(-4, a_Ret2);
- GetReturn(-3, a_Ret3);
- GetReturn(-2, a_Ret4);
- GetReturn(-1, a_Ret5);
+ GetStackValue(-5, a_Ret1);
+ GetStackValue(-4, a_Ret2);
+ GetStackValue(-3, a_Ret3);
+ GetStackValue(-2, a_Ret4);
+ GetStackValue(-1, a_Ret5);
lua_pop(m_LuaState, 5);
return true;
}
@@ -918,18 +931,6 @@ protected:
/** Pushes a usertype of the specified class type onto the stack */
void PushUserType(void * a_Object, const char * a_Type);
- /** Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, bool & a_ReturnedVal);
-
- /** Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, AString & a_ReturnedVal);
-
- /** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, int & a_ReturnedVal);
-
- /** Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged */
- void GetReturn(int a_StackPos, double & a_ReturnedVal);
-
/**
Calls the function that has been pushed onto the stack by PushFunction(),
with arguments pushed by PushXXX().
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index fcdd728be..a5247bbe6 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -23,9 +23,11 @@
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "md5/md5.h"
#include "../LineBlockTracer.h"
#include "../WorldStorage/SchematicFileSerializer.h"
+#include "../CompositeChat.h"
@@ -2455,7 +2457,7 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S)
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::LoadFromSchematicFile
- // Exported manually because function has been moved to SchematicFileSerilizer.cpp
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
@@ -2482,10 +2484,41 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
+static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S)
+{
+ // function cBlockArea::LoadFromSchematicString
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cBlockArea") ||
+ !L.CheckParamString (2) ||
+ !L.CheckParamEnd (3)
+ )
+ {
+ return 0;
+ }
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
+ return 0;
+ }
+
+ AString Data;
+ L.GetStackValue(2, Data);
+ bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data);
+ tolua_pushboolean(tolua_S, res);
+ return 1;
+}
+
+
+
+
+
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{
// function cBlockArea::SaveToSchematicFile
- // Exported manually because function has been moved to SchematicFileSerilizer.cpp
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
cLuaState L(tolua_S);
if (
!L.CheckParamUserType(1, "cBlockArea") ||
@@ -2511,6 +2544,285 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
+static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S)
+{
+ // function cBlockArea::SaveToSchematicString
+ // Exported manually because function has been moved to SchematicFileSerializer.cpp
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cBlockArea") ||
+ !L.CheckParamEnd (2)
+ )
+ {
+ return 0;
+ }
+ cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
+ return 0;
+ }
+
+ AString Data;
+ if (cSchematicFileSerializer::SaveToSchematicString(*self, Data))
+ {
+ L.Push(Data);
+ return 1;
+ }
+ return 0;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddRunCommandPart(Message, Command, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2, 3)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Command, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Command);
+ L.GetStackValue(4, Style);
+ self->AddRunCommandPart(Text, Command, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddSuggestCommandPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddSuggestCommandPart(Message, Command, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2, 3)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Command, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Command);
+ L.GetStackValue(4, Style);
+ self->AddSuggestCommandPart(Text, Command, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddTextPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddTextPart(Message, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Style);
+ self->AddTextPart(Text, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_AddUrlPart(lua_State * tolua_S)
+{
+ // function cCompositeChat:AddTextPart(Message, Url, [Style])
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2, 3)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", NULL);
+ return 0;
+ }
+
+ // Add the part:
+ AString Text, Url, Style;
+ L.GetStackValue(2, Text);
+ L.GetStackValue(3, Url);
+ L.GetStackValue(4, Style);
+ self->AddUrlPart(Text, Url, Style);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_ParseText(lua_State * tolua_S)
+{
+ // function cCompositeChat:ParseText(TextMessage)
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamString(2)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", NULL);
+ return 0;
+ }
+
+ // Parse the text:
+ AString Text;
+ L.GetStackValue(2, Text);
+ self->ParseText(Text);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
+{
+ // function cCompositeChat:SetMessageType(MessageType)
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (
+ !L.CheckParamUserType(1, "cCompositeChat") ||
+ !L.CheckParamNumber(2)
+ )
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", NULL);
+ return 0;
+ }
+
+ // Set the type:
+ int MessageType;
+ L.GetStackValue(1, MessageType);
+ self->SetMessageType((eMessageType)MessageType);
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
+static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S)
+{
+ // function cCompositeChat:UnderlineUrls()
+ // Exported manually to support call-chaining (return *this)
+
+ // Check params:
+ cLuaState L(tolua_S);
+ if (!L.CheckParamUserType(1, "cCompositeChat"))
+ {
+ return 0;
+ }
+ cCompositeChat * self = (cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL);
+ if (self == NULL)
+ {
+ tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", NULL);
+ return 0;
+ }
+
+ // Call the processing
+ self->UnderlineUrls();
+
+ // Cut away everything from the stack except for the cCompositeChat instance; return that:
+ lua_settop(L, 1);
+ return 1;
+}
+
+
+
+
+
void ManualBindings::Bind(lua_State * tolua_S)
{
tolua_beginmodule(tolua_S, NULL);
@@ -2527,12 +2839,24 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cBlockArea");
- tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
- tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
- tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
- tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
- tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
- tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
+ tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
+ tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
+ tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
+ tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
+ tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
+ tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString);
+ tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
+ tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString);
+ tolua_endmodule(tolua_S);
+
+ tolua_beginmodule(tolua_S, "cCompositeChat");
+ tolua_function(tolua_S, "AddRunCommandPart", tolua_cCompositeChat_AddRunCommandPart);
+ tolua_function(tolua_S, "AddSuggestCommandPart", tolua_cCompositeChat_AddSuggestCommandPart);
+ tolua_function(tolua_S, "AddTextPart", tolua_cCompositeChat_AddTextPart);
+ tolua_function(tolua_S, "AddUrlPart", tolua_cCompositeChat_AddUrlPart);
+ tolua_function(tolua_S, "ParseText", tolua_cCompositeChat_ParseText);
+ tolua_function(tolua_S, "SetMessageType", tolua_cCompositeChat_SetMessageType);
+ tolua_function(tolua_S, "UnderlineUrls", tolua_cCompositeChat_UnderlineUrls);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cHopperEntity");
@@ -2561,7 +2885,8 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>);
tolua_function(tolua_S, "DoWithNoteBlockAt", tolua_DoWithXYZ<cWorld, cNoteEntity, &cWorld::DoWithNoteBlockAt>);
tolua_function(tolua_S, "DoWithCommandBlockAt", tolua_DoWithXYZ<cWorld, cCommandBlockEntity, &cWorld::DoWithCommandBlockAt>);
- tolua_function(tolua_S, "DoWithMobHeadBlockAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadBlockAt>);
+ tolua_function(tolua_S, "DoWithMobHeadAt", tolua_DoWithXYZ<cWorld, cMobHeadEntity, &cWorld::DoWithMobHeadAt>);
+ tolua_function(tolua_S, "DoWithFlowerPotAt", tolua_DoWithXYZ<cWorld, cFlowerPotEntity, &cWorld::DoWithFlowerPotAt>);
tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>);
tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>);
tolua_function(tolua_S, "ForEachBlockEntityInChunk", tolua_ForEachInChunk<cWorld, cBlockEntity, &cWorld::ForEachBlockEntityInChunk>);
diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp
index 57ad83de9..b42318c2f 100644
--- a/src/BlockEntities/BlockEntity.cpp
+++ b/src/BlockEntities/BlockEntity.cpp
@@ -10,6 +10,7 @@
#include "DispenserEntity.h"
#include "DropperEntity.h"
#include "EnderChestEntity.h"
+#include "FlowerPotEntity.h"
#include "FurnaceEntity.h"
#include "HopperEntity.h"
#include "JukeboxEntity.h"
@@ -30,6 +31,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
+ case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
diff --git a/src/BlockEntities/FlowerPotEntity.cpp b/src/BlockEntities/FlowerPotEntity.cpp
new file mode 100644
index 000000000..87bf8b921
--- /dev/null
+++ b/src/BlockEntities/FlowerPotEntity.cpp
@@ -0,0 +1,134 @@
+
+// FlowerPotEntity.cpp
+
+// Implements the cFlowerPotEntity class representing a single sign in the world
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+#include "json/json.h"
+#include "FlowerPotEntity.h"
+#include "../Entities/Player.h"
+#include "../Item.h"
+
+
+
+
+
+cFlowerPotEntity::cFlowerPotEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
+ super(E_BLOCK_FLOWER_POT, a_BlockX, a_BlockY, a_BlockZ, a_World)
+{
+}
+
+
+
+
+
+// It don't do anything when 'used'
+void cFlowerPotEntity::UsedBy(cPlayer * a_Player)
+{
+ if (IsItemInPot())
+ {
+ return;
+ }
+
+ cItem SelectedItem = a_Player->GetInventory().GetEquippedItem();
+ if (IsFlower(SelectedItem.m_ItemType, SelectedItem.m_ItemDamage))
+ {
+ m_Item = SelectedItem.CopyOne();
+ if (!a_Player->IsGameModeCreative())
+ {
+ a_Player->GetInventory().RemoveOneEquippedItem();
+ }
+ m_World->BroadcastBlockEntity(m_PosX, m_PosY, m_PosZ, a_Player->GetClientHandle());
+ }
+}
+
+
+
+
+
+void cFlowerPotEntity::SendTo(cClientHandle & a_Client)
+{
+ a_Client.SendUpdateBlockEntity(*this);
+}
+
+
+
+
+
+void cFlowerPotEntity::Destroy(void)
+{
+ // Drop the contents as pickups:
+ if (!m_Item.IsEmpty())
+ {
+ ASSERT(m_World != NULL);
+ cItems Pickups;
+ Pickups.Add(m_Item);
+ m_World->SpawnItemPickups(Pickups, m_PosX + 0.5, m_PosY + 0.5, m_PosZ + 0.5);
+
+ m_Item.Empty();
+ }
+}
+
+
+
+
+
+bool cFlowerPotEntity::LoadFromJson(const Json::Value & a_Value)
+{
+ m_PosX = a_Value.get("x", 0).asInt();
+ m_PosY = a_Value.get("y", 0).asInt();
+ m_PosZ = a_Value.get("z", 0).asInt();
+
+ m_Item = cItem();
+ m_Item.FromJson(a_Value.get("Item", 0));
+
+ return true;
+}
+
+
+
+
+
+void cFlowerPotEntity::SaveToJson(Json::Value & a_Value)
+{
+ a_Value["x"] = m_PosX;
+ a_Value["y"] = m_PosY;
+ a_Value["z"] = m_PosZ;
+
+ Json::Value Item;
+ m_Item.GetJson(Item);
+ a_Value["Item"] = Item;
+}
+
+
+
+
+
+bool cFlowerPotEntity::IsFlower(short m_ItemType, short m_ItemData)
+{
+ switch (m_ItemType)
+ {
+ case E_BLOCK_DANDELION:
+ case E_BLOCK_FLOWER:
+ case E_BLOCK_CACTUS:
+ case E_BLOCK_BROWN_MUSHROOM:
+ case E_BLOCK_RED_MUSHROOM:
+ case E_BLOCK_SAPLING:
+ case E_BLOCK_DEAD_BUSH:
+ {
+ return true;
+ }
+ case E_BLOCK_TALL_GRASS:
+ {
+ return (m_ItemData == (short) 2);
+ }
+ default:
+ {
+ return false;
+ }
+ }
+}
+
+
+
+
diff --git a/src/BlockEntities/FlowerPotEntity.h b/src/BlockEntities/FlowerPotEntity.h
new file mode 100644
index 000000000..da3fe9b7e
--- /dev/null
+++ b/src/BlockEntities/FlowerPotEntity.h
@@ -0,0 +1,74 @@
+// FlowerPotEntity.h
+
+// Declares the cFlowerPotEntity class representing a single sign in the world
+
+
+
+
+
+#pragma once
+
+#include "BlockEntity.h"
+
+class cItem;
+
+
+
+
+
+namespace Json
+{
+ class Value;
+}
+
+
+
+
+
+// tolua_begin
+
+class cFlowerPotEntity :
+ public cBlockEntity
+{
+ typedef cBlockEntity super;
+
+public:
+
+ // tolua_end
+
+ /** Creates a new flowerpot entity at the specified block coords. a_World may be NULL */
+ cFlowerPotEntity(int a_BlocX, int a_BlockY, int a_BlockZ, cWorld * a_World);
+
+ bool LoadFromJson( const Json::Value& a_Value );
+ virtual void SaveToJson(Json::Value& a_Value ) override;
+
+ virtual void Destroy(void) override;
+
+ // tolua_begin
+
+ /** Is a flower in the pot? */
+ bool IsItemInPot(void) { return !m_Item.IsEmpty(); }
+
+ /** Get the item in the flower pot */
+ cItem GetItem(void) const { return m_Item; }
+
+ /** Set the item in the flower pot */
+ void SetItem(const cItem a_Item) { m_Item = a_Item; }
+
+ // tolua_end
+
+ virtual void UsedBy(cPlayer * a_Player) override;
+ virtual void SendTo(cClientHandle & a_Client) override;
+
+ static bool IsFlower(short m_ItemType, short m_ItemData);
+
+ static const char * GetClassStatic(void) { return "cFlowerPotEntity"; }
+
+private:
+
+ cItem m_Item;
+} ; // tolua_export
+
+
+
+
diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp
index c73ae18b6..d1ecfdf7e 100644
--- a/src/BlockInfo.cpp
+++ b/src/BlockInfo.cpp
@@ -2,6 +2,7 @@
#include "Globals.h"
#include "BlockInfo.h"
+#include "Blocks/BlockHandler.h"
@@ -23,16 +24,24 @@ cBlockInfo::cBlockInfo()
, m_RequiresSpecialTool(false)
, m_IsSolid(true)
, m_FullyOccupiesVoxel(false)
+ , m_Handler(NULL)
{}
-cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
+cBlockInfo::~cBlockInfo()
{
- ASSERT(a_Type < 256);
+ delete m_Handler;
+}
+
+
+
+
+cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
+{
return ms_Info[a_Type];
}
@@ -42,6 +51,14 @@ cBlockInfo & cBlockInfo::Get(BLOCKTYPE a_Type)
void cBlockInfo::Initialize(void)
{
+ for (unsigned int i = 0; i < 256; ++i)
+ {
+ if (ms_Info[i].m_Handler == NULL)
+ {
+ ms_Info[i].m_Handler = cBlockHandler::CreateBlockHandler((BLOCKTYPE) i);
+ }
+ }
+
// Emissive blocks
ms_Info[E_BLOCK_FIRE ].m_LightValue = 15;
ms_Info[E_BLOCK_GLOWSTONE ].m_LightValue = 15;
@@ -252,6 +269,11 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_VINES ].m_IsSnowable = false;
ms_Info[E_BLOCK_WALLSIGN ].m_IsSnowable = false;
ms_Info[E_BLOCK_WATER ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false;
+ ms_Info[E_BLOCK_COBWEB ].m_IsSnowable = false;
// Blocks that don't drop without a special tool:
@@ -290,6 +312,10 @@ void cBlockInfo::Initialize(void)
ms_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_STONE_SLAB ].m_RequiresSpecialTool = true;
ms_Info[E_BLOCK_VINES ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_FURNACE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_LIT_FURNACE ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_ANVIL ].m_RequiresSpecialTool = true;
+ ms_Info[E_BLOCK_ENCHANTMENT_TABLE ].m_RequiresSpecialTool = true;
// Nonsolid blocks:
diff --git a/src/BlockInfo.h b/src/BlockInfo.h
index 34a845b20..40c1db867 100644
--- a/src/BlockInfo.h
+++ b/src/BlockInfo.h
@@ -5,6 +5,13 @@
+// fwd:
+class cBlockHandler;
+
+
+
+
+
// tolua_begin
class cBlockInfo
{
@@ -13,6 +20,8 @@ public:
cBlockInfo();
+ ~cBlockInfo();
+
/** (Re-)Initializes the internal BlockInfo structures. */
static void Initialize(void);
@@ -49,6 +58,12 @@ public:
/** Does this block fully occupy its voxel - is it a 'full' block? */
bool m_FullyOccupiesVoxel;
+ // tolua_end
+
+ /** Associated block handler. */
+ cBlockHandler * m_Handler;
+
+ // tolua_begin
inline static NIBBLETYPE GetLightValue (BLOCKTYPE a_Type) { return Get(a_Type).m_LightValue; }
inline static NIBBLETYPE GetSpreadLightFalloff(BLOCKTYPE a_Type) { return Get(a_Type).m_SpreadLightFalloff; }
@@ -62,6 +77,8 @@ public:
// tolua_end
+ inline static cBlockHandler * GetHandler (BLOCKTYPE a_Type) { return Get(a_Type).m_Handler; }
+
protected:
@@ -74,3 +91,13 @@ protected:
+
+// Shortcut to get the blockhandler for a specific block
+inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
+{
+ return cBlockInfo::Get(a_BlockType).m_Handler;
+}
+
+
+
+
diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h
index caec2b56f..6daa94730 100644
--- a/src/Blocks/BlockBed.h
+++ b/src/Blocks/BlockBed.h
@@ -4,6 +4,7 @@
#include "BlockHandler.h"
#include "ChunkInterface.h"
#include "WorldInterface.h"
+#include "MetaRotater.h"
#include "../Entities/Player.h"
@@ -11,11 +12,11 @@
class cBlockBedHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockBedHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h
index 2db9b7ec7..740cbe3c4 100644
--- a/src/Blocks/BlockButton.h
+++ b/src/Blocks/BlockButton.h
@@ -2,16 +2,17 @@
#include "BlockHandler.h"
#include "Chunk.h"
+#include "MetaRotater.h"
class cBlockButtonHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{
public:
cBlockButtonHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h
index 02ecc4346..30588d8fc 100644
--- a/src/Blocks/BlockChest.h
+++ b/src/Blocks/BlockChest.h
@@ -4,17 +4,18 @@
#include "BlockEntity.h"
#include "../BlockArea.h"
#include "../Entities/Player.h"
+#include "MetaRotater.h"
class cBlockChestHandler :
- public cBlockEntityHandler
+ public cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>
{
public:
cBlockChestHandler(BLOCKTYPE a_BlockType)
- : cBlockEntityHandler(a_BlockType)
+ : cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h
index aba390d9d..e570ff302 100644
--- a/src/Blocks/BlockComparator.h
+++ b/src/Blocks/BlockComparator.h
@@ -3,17 +3,18 @@
#include "BlockHandler.h"
#include "BlockRedstoneRepeater.h"
+#include "MetaRotater.h"
class cBlockComparatorHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>
{
public:
cBlockComparatorHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType)
{
}
@@ -26,6 +27,13 @@ public:
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ UNUSED(a_ChunkInterface);
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp
index 2ff5c1c37..4e38ef334 100644
--- a/src/Blocks/BlockDoor.cpp
+++ b/src/Blocks/BlockDoor.cpp
@@ -9,7 +9,7 @@
cBlockDoorHandler::cBlockDoorHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : super(a_BlockType)
{
}
@@ -55,6 +55,29 @@ void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
+void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
+{
+ UNUSED(a_ChunkInterface);
+
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
+
+ if (Meta & 8)
+ {
+ // Current block is top of the door
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
+ }
+ else
+ {
+ // Current block is bottom of the door
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
+ }
+}
+
+
+
+
+
void cBlockDoorHandler::OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index ef0dbb787..981774c17 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -4,18 +4,21 @@
#include "BlockHandler.h"
#include "../Entities/Player.h"
#include "Chunk.h"
+#include "MetaRotater.h"
class cBlockDoorHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true>
{
+ typedef cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super;
public:
cBlockDoorHandler(BLOCKTYPE a_BlockType);
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
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;
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
virtual const char * GetStepSound(void) override;
@@ -167,6 +170,60 @@ public:
}
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
+ {
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
+ else
+ {
+ return super::MetaRotateCCW(a_Meta);
+ }
+ }
+
+
+
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
+ {
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
+ else
+ {
+ return super::MetaRotateCW(a_Meta);
+ }
+ }
+
+
+
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
+ {
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
+ else
+ {
+ return super::MetaMirrorXY(a_Meta);
+ }
+ }
+
+
+
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
+ {
+ if (a_Meta & 0x08)
+ {
+ return a_Meta;
+ }
+ else
+ {
+ return super::MetaMirrorYZ(a_Meta);
+ }
+ }
+
} ;
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index 30d347ec9..7e0ad0e55 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -6,17 +6,18 @@
#pragma once
#include "../Piston.h"
+#include "MetaRotater.h"
class cBlockDropSpenserHandler :
- public cBlockEntityHandler
+ public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) :
- cBlockEntityHandler(a_BlockType)
+ cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
@@ -34,6 +35,20 @@ public:
a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
+
+ virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
+ {
+ // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000
+ NIBBLETYPE OtherMeta = a_Meta & 0x08;
+ // Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111
+ switch (a_Meta & 0x07)
+ {
+ case 0x00: return 0x01 + OtherMeta; // Down -> Up
+ case 0x01: return 0x00 + OtherMeta; // Up -> Down
+ }
+ // Not Facing Up or Down; No change.
+ return a_Meta;
+ }
} ;
diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h
index b4b0b995d..97cf484fb 100644
--- a/src/Blocks/BlockEnderchest.h
+++ b/src/Blocks/BlockEnderchest.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockEntity.h"
-
+#include "MetaRotater.h"
class cBlockEnderchestHandler :
- public cBlockEntityHandler
+ public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>
{
public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
- : cBlockEntityHandler(a_BlockType)
+ : cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType)
{
}
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index fb984f345..e3162bbd6 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotater.h"
class cBlockFenceGateHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>
{
public:
cBlockFenceGateHandler(BLOCKTYPE a_BlockType) :
- cBlockHandler(a_BlockType)
+ cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType)
{
}
@@ -48,6 +48,12 @@ public:
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
+
virtual bool IsUseable(void) override
{
return true;
diff --git a/src/Blocks/BlockFlowerPot.h b/src/Blocks/BlockFlowerPot.h
index 4de85f629..fc75ef638 100644
--- a/src/Blocks/BlockFlowerPot.h
+++ b/src/Blocks/BlockFlowerPot.h
@@ -2,101 +2,24 @@
#pragma once
#include "BlockHandler.h"
+#include "BlockEntity.h"
class cBlockFlowerPotHandler :
- public cBlockHandler
+ public cBlockEntityHandler
{
public:
cBlockFlowerPotHandler(BLOCKTYPE a_BlockType) :
- cBlockHandler(a_BlockType)
+ cBlockEntityHandler(a_BlockType)
{
}
-
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_ITEM_FLOWER_POT, 1, 0));
- if (a_BlockMeta == 0)
- {
- return;
- }
- cItem Plant;
- switch (a_BlockMeta)
- {
- case 1: Plant = cItem(E_BLOCK_RED_ROSE, 1, 0); break;
- case 2: Plant = cItem(E_BLOCK_YELLOW_FLOWER, 1, 0); break;
- case 3: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_APPLE); break;
- case 4: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_CONIFER); break;
- case 5: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_BIRCH); break;
- case 6: Plant = cItem(E_BLOCK_SAPLING, 1, E_META_SAPLING_JUNGLE); break;
- case 7: Plant = cItem(E_BLOCK_RED_MUSHROOM, 1, 0); break;
- case 8: Plant = cItem(E_BLOCK_BROWN_MUSHROOM, 1, 0); break;
- case 9: Plant = cItem(E_BLOCK_CACTUS, 1, 0); break;
- case 10: Plant = cItem(E_BLOCK_DEAD_BUSH, 1, 0); break;
- case 11: Plant = cItem(E_BLOCK_TALL_GRASS, 1, E_META_TALL_GRASS_FERN); break;
- default: return;
- }
- a_Pickups.push_back(Plant);
- }
-
-
- void OnUse(cWorld * a_World, cWorldInterface * a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ)
- {
- NIBBLETYPE Meta = a_World->GetBlockMeta( a_BlockX, a_BlockY, a_BlockZ );
- if (Meta != 0)
- {
- // Already filled
- return;
- }
-
- switch (a_Player->GetEquippedItem().m_ItemType)
- {
- case E_BLOCK_RED_ROSE: Meta = 1; break;
- case E_BLOCK_YELLOW_FLOWER: Meta = 2; break;
- case E_BLOCK_SAPLING:
- {
- switch (a_Player->GetEquippedItem().m_ItemDamage)
- {
- case E_META_SAPLING_APPLE: Meta = 3; break;
- case E_META_SAPLING_CONIFER: Meta = 4; break;
- case E_META_SAPLING_BIRCH: Meta = 5; break;
- case E_META_SAPLING_JUNGLE: Meta = 6; break;
- }
- break;
- }
- case E_BLOCK_RED_MUSHROOM: Meta = 7; break;
- case E_BLOCK_BROWN_MUSHROOM: Meta = 8; break;
- case E_BLOCK_CACTUS: Meta = 9; break;
- case E_BLOCK_DEAD_BUSH: Meta = 10; break;
- case E_BLOCK_TALL_GRASS:
- {
- if (a_Player->GetEquippedItem().m_ItemDamage == E_META_TALL_GRASS_FERN)
- {
- Meta = 11;
- }
- else
- {
- return;
- }
- break;
- }
- }
-
- if (a_Player->GetGameMode() != gmCreative)
- {
- a_Player->GetInventory().RemoveOneEquippedItem();
- }
- a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
- }
-
-
- virtual bool IsUseable(void) override
- {
- return true;
}
} ;
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 834727c9a..aa97b2ca9 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -57,6 +57,7 @@
#include "BlockRedstoneLamp.h"
#include "BlockRedstoneRepeater.h"
#include "BlockRedstoneTorch.h"
+#include "BlockTNT.h"
#include "BlockSand.h"
#include "BlockSapling.h"
#include "BlockSideways.h"
@@ -77,33 +78,6 @@
-bool cBlockHandler::m_HandlerInitialized = false;
-cBlockHandler * cBlockHandler::m_BlockHandler[256];
-
-
-
-
-
-cBlockHandler * cBlockHandler::GetBlockHandler(BLOCKTYPE a_BlockType)
-{
- if (!m_HandlerInitialized)
- {
- // We have to initialize
- memset(m_BlockHandler, 0, sizeof(m_BlockHandler));
- m_HandlerInitialized = true;
- }
- if (m_BlockHandler[a_BlockType] != NULL)
- {
- return m_BlockHandler[a_BlockType];
- }
-
- return m_BlockHandler[a_BlockType] = CreateBlockHandler(a_BlockType);
-}
-
-
-
-
-
cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{
switch(a_BlockType)
@@ -172,6 +146,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_NETHER_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_NETHER_PORTAL: return new cBlockPortalHandler (a_BlockType);
case E_BLOCK_NETHER_WART: return new cBlockNetherWartHandler (a_BlockType);
+ case E_BLOCK_NETHER_QUARTZ_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_NEW_LEAVES: return new cBlockNewLeavesHandler (a_BlockType);
case E_BLOCK_NEW_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_NOTE_BLOCK: return new cBlockNoteHandler (a_BlockType);
@@ -192,7 +167,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_REDSTONE_REPEATER_ON: return new cBlockRedstoneRepeaterHandler(a_BlockType);
case E_BLOCK_REDSTONE_TORCH_OFF: return new cBlockRedstoneTorchHandler (a_BlockType);
case E_BLOCK_REDSTONE_TORCH_ON: return new cBlockRedstoneTorchHandler (a_BlockType);
- case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
+ case E_BLOCK_REDSTONE_WIRE: return new cBlockRedstoneHandler (a_BlockType);
case E_BLOCK_RED_MUSHROOM: return new cBlockMushroomHandler (a_BlockType);
case E_BLOCK_RED_ROSE: return new cBlockFlowerHandler (a_BlockType);
case E_BLOCK_SAND: return new cBlockSandHandler (a_BlockType);
@@ -212,6 +187,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType);
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
+ case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
@@ -231,20 +207,6 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
-void cBlockHandler::Deinit()
-{
- for (int i = 0; i < 256; i++)
- {
- delete m_BlockHandler[i];
- }
- memset(m_BlockHandler, 0, sizeof(m_BlockHandler)); // Don't leave any dangling pointers around, just in case
- m_HandlerInitialized = false;
-}
-
-
-
-
-
cBlockHandler::cBlockHandler(BLOCKTYPE a_BlockType)
{
m_BlockType = a_BlockType;
@@ -329,7 +291,7 @@ void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_Bl
{
if ((a_BlockY >= 0) && (a_BlockY < cChunkDef::Height))
{
- GetBlockHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
+ cBlockInfo::GetHandler(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))->OnNeighborChanged(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
}
}
@@ -361,6 +323,14 @@ void cBlockHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface &
+void cBlockHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
+{
+}
+
+
+
+
+
void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
// Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this.
diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h
index a2913d7f8..3a3efb3cc 100644
--- a/src/Blocks/BlockHandler.h
+++ b/src/Blocks/BlockHandler.h
@@ -23,6 +23,8 @@ class cBlockHandler
{
public:
cBlockHandler(BLOCKTYPE a_BlockType);
+
+ virtual ~cBlockHandler() {}
/// Called when the block gets ticked either by a random tick or by a queued tick.
/// Note that the coords are chunk-relative!
@@ -69,6 +71,9 @@ public:
/// Called if the user right clicks the block and the block is useable
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);
+ /** Called when a Right Click to this Block is cancelled */
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
+
/// <summary>Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents</summary>
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
@@ -136,30 +141,14 @@ public:
/// <returns>Block meta following mirroring</returns>
virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) { return a_Meta; }
- /// <summary>Get the blockhandler for a specific block id</summary>
- static cBlockHandler * GetBlockHandler(BLOCKTYPE a_BlockType);
-
- /// <summary>Deletes all initialised block handlers</summary>
- static void Deinit();
-
protected:
BLOCKTYPE m_BlockType;
// Creates a new blockhandler for the given block type. For internal use only, use ::GetBlockHandler() instead.
- static cBlockHandler *CreateBlockHandler(BLOCKTYPE a_BlockType);
- static cBlockHandler *m_BlockHandler[256];
- static bool m_HandlerInitialized; //used to detect if the blockhandlers are initialized
-};
-
+ static cBlockHandler * CreateBlockHandler(BLOCKTYPE a_BlockType);
-
-
-
-// Shortcut to get the blockhandler for a specific block
-inline cBlockHandler * BlockHandler(BLOCKTYPE a_BlockType)
-{
- return cBlockHandler::GetBlockHandler(a_BlockType);
-}
+ friend class cBlockInfo;
+};
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index 6a00c3acd..2b128f13b 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -29,7 +29,7 @@ public:
BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta
) override
{
- class cCallback : public cMobHeadBlockCallback
+ class cCallback : public cMobHeadCallback
{
cPlayer * m_Player;
NIBBLETYPE m_OldBlockMeta;
@@ -45,6 +45,7 @@ public:
a_MobHeadEntity->SetType(static_cast<eMobHeadType>(m_OldBlockMeta));
a_MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
+ a_MobHeadEntity->GetWorld()->BroadcastBlockEntity(a_MobHeadEntity->GetPosX(), a_MobHeadEntity->GetPosY(), a_MobHeadEntity->GetPosZ(), m_Player->GetClientHandle());
return false;
}
@@ -59,7 +60,7 @@ public:
a_BlockMeta = a_BlockFace;
cWorld * World = (cWorld *) &a_WorldInterface;
- World->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
+ World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
}
} ;
diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h
index eb0918acf..1e2a86949 100644
--- a/src/Blocks/BlockRedstoneRepeater.h
+++ b/src/Blocks/BlockRedstoneRepeater.h
@@ -29,7 +29,7 @@ public:
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
-
+
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
{
@@ -37,6 +37,13 @@ public:
}
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ UNUSED(a_ChunkInterface);
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index c1887bc46..ea8405597 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -2,17 +2,17 @@
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotater.h"
class cBlockStairsHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>
{
public:
cBlockStairsHandler(BLOCKTYPE a_BlockType) :
- cBlockHandler(a_BlockType)
+ cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType)
{
}
@@ -25,6 +25,14 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
+ UNUSED(a_ChunkInterface);
+ UNUSED(a_BlockX);
+ UNUSED(a_BlockY);
+ UNUSED(a_BlockZ);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorY);
+ UNUSED(a_CursorZ);
+ UNUSED(a_BlockMeta);
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
@@ -96,54 +104,6 @@ public:
}
- virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x03; // East -> North
- case 0x01: return TopBits | 0x02; // West -> South
- case 0x02: return TopBits | 0x00; // South -> East
- case 0x03: return TopBits | 0x01; // North -> West
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
-
-
- virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x02; // East -> South
- case 0x01: return TopBits | 0x03; // West -> North
- case 0x02: return TopBits | 0x01; // South -> West
- case 0x03: return TopBits | 0x00; // North -> East
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
-
-
- virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x00; // East -> East
- case 0x01: return TopBits | 0x01; // West -> West
- case 0x02: return TopBits | 0x03; // South -> North
- case 0x03: return TopBits | 0x02; // North -> South
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
-
-
virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override
{
// Toggle bit 3:
@@ -151,20 +111,6 @@ public:
}
- virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
- {
- // Bits 3 and 4 stay, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x0c);
- switch (a_Meta & 0x03)
- {
- case 0x00: return TopBits | 0x01; // East -> West
- case 0x01: return TopBits | 0x00; // West -> East
- case 0x02: return TopBits | 0x02; // South -> South
- case 0x03: return TopBits | 0x03; // North -> North
- }
- // Not reachable, but to avoid a compiler warning:
- return 0;
- }
} ;
diff --git a/src/Blocks/BlockTNT.h b/src/Blocks/BlockTNT.h
new file mode 100644
index 000000000..283a03730
--- /dev/null
+++ b/src/Blocks/BlockTNT.h
@@ -0,0 +1,32 @@
+
+#pragma once
+
+#include "BlockHandler.h"
+
+
+
+
+
+class cBlockTNTHandler :
+ public cBlockHandler
+{
+public:
+ cBlockTNTHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+ virtual const char * GetStepSound(void) override
+ {
+ return "step.grass";
+ }
+
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
+ }
+};
+
+
+
+
diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h
index 84bbb37ec..d32c77629 100644
--- a/src/Blocks/BlockTorch.h
+++ b/src/Blocks/BlockTorch.h
@@ -2,17 +2,17 @@
#include "BlockHandler.h"
#include "../Chunk.h"
-
+#include "MetaRotater.h"
class cBlockTorchHandler :
- public cBlockHandler
+ public cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>
{
public:
cBlockTorchHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ : cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType)
{
}
@@ -185,67 +185,6 @@ public:
{
return "step.wood";
}
-
-
- virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x01: return TopBits | 0x04; // East -> North
- case 0x02: return TopBits | 0x03; // West -> South
- case 0x03: return TopBits | 0x01; // South -> East
- case 0x04: return TopBits | 0x02; // North -> West
- default: return a_Meta; // Floor -> Floor
- }
- }
-
-
- virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x01: return TopBits | 0x03; // East -> South
- case 0x02: return TopBits | 0x04; // West -> North
- case 0x03: return TopBits | 0x02; // South -> West
- case 0x04: return TopBits | 0x01; // North -> East
- default: return a_Meta; // Floor -> Floor
- }
- }
-
-
- virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x03: return TopBits | 0x04; // South -> North
- case 0x04: return TopBits | 0x03; // North -> South
- default: return a_Meta; // Keep the rest
- }
- }
-
-
- // Mirroring around the XZ plane doesn't make sense for floor torches,
- // the others stay the same, so let's keep all the metas the same.
- // The base class does tht for us, no need to override MetaMirrorXZ()
-
-
- virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override
- {
- // Bit 4 stays, the rest is swapped around according to a table:
- NIBBLETYPE TopBits = (a_Meta & 0x08);
- switch (a_Meta & 0x07)
- {
- case 0x01: return TopBits | 0x02; // East -> West
- case 0x02: return TopBits | 0x01; // West -> East
- default: return a_Meta; // Keep the rest
- }
- }
} ;
diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h
index 70a369e69..9bae92c4d 100644
--- a/src/Blocks/BlockTrapdoor.h
+++ b/src/Blocks/BlockTrapdoor.h
@@ -36,8 +36,16 @@ public:
{
// Flip the ON bit on/off using the XOR bitwise operation
NIBBLETYPE Meta = (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x04);
-
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
+
+ cWorld * World = (cWorld *) &a_WorldInterface;
+ World->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
+ }
+
+ virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
+ {
+ UNUSED(a_ChunkInterface);
+ a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
}
virtual bool GetPlacementBlockTypeMeta(
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index d8c114284..708583e70 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -1,8 +1,7 @@
-
#pragma once
#include "BlockHandler.h"
-
+#include "MetaRotater.h"
@@ -24,6 +23,10 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
+ UNUSED(a_Player);
+ UNUSED(a_CursorX);
+ UNUSED(a_CursorY);
+ UNUSED(a_CursorZ);
// TODO: Disallow placement where the vine doesn't attach to something properly
BLOCKTYPE BlockType = 0;
NIBBLETYPE BlockMeta;
@@ -162,11 +165,17 @@ public:
return false;
}
- virtual void OnUpdate(cWorld * a_World, int X, int Y, int Z)
+ virtual void OnUpdate(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ)
{
- if (a_World->GetBlock(X, Y - 1, Z) == E_BLOCK_AIR)
+ UNUSED(a_ChunkInterface);
+ UNUSED(a_WorldInterface);
+ UNUSED(a_BlockPluginInterface);
+
+ BLOCKTYPE Block;
+ a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
+ if (Block == E_BLOCK_AIR)
{
- a_World->SetBlock(X, Y - 1, Z, E_BLOCK_VINES, a_World->GetBlockMeta(X, Y, Z));
+ a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
}
}
@@ -180,8 +189,8 @@ public:
{
return ((a_Meta << 1) | (a_Meta >> 3)) & 0x0f; // Rotate bits to the left
}
-
-
+
+
virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override
{
// Bits 2 and 4 stay, bits 1 and 3 swap
@@ -194,6 +203,7 @@ public:
// Bits 1 and 3 stay, bits 2 and 4 swap
return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2));
}
+
} ;
diff --git a/src/Blocks/ChunkInterface.cpp b/src/Blocks/ChunkInterface.cpp
index b2dda19f4..540581ae7 100644
--- a/src/Blocks/ChunkInterface.cpp
+++ b/src/Blocks/ChunkInterface.cpp
@@ -6,7 +6,7 @@
bool cChunkInterface::DigBlock(cWorldInterface & a_WorldInterface, int a_X, int a_Y, int a_Z)
{
- cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z));
+ cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock(a_X, a_Y, a_Z));
Handler->OnDestroyed(*this, a_WorldInterface, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
}
diff --git a/src/Blocks/MetaRotater.h b/src/Blocks/MetaRotater.h
new file mode 100644
index 000000000..dde88e6db
--- /dev/null
+++ b/src/Blocks/MetaRotater.h
@@ -0,0 +1,120 @@
+// MetaRotater.h
+
+// Provides a mixin for rotations and reflections
+
+#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.
+
+Usage:
+Inherit from this class providing your base class as Base, the BitMask for the direction bits in bitmask and the masked value for the directions in North, East, South, West. There is also an aptional parameter AssertIfNotMatched. Set this if it is invalid for a block to exist in any other state.
+*/
+
+template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false>
+class cMetaRotater : public Base
+{
+public:
+
+ cMetaRotater(BLOCKTYPE a_BlockType) :
+ Base(a_BlockType)
+ {}
+
+ virtual ~cMetaRotater() {}
+
+ virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override;
+ virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override;
+};
+
+
+
+
+
+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)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case South: return West | OtherMeta;
+ case West: return North | OtherMeta;
+ case North: return East | OtherMeta;
+ case East: return South | OtherMeta;
+ }
+ if (AssertIfNotMatched)
+ {
+ ASSERT(!"Invalid Meta value");
+ }
+ return a_Meta;
+}
+
+
+
+
+
+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)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case South: return East | OtherMeta;
+ case East: return North | OtherMeta;
+ case North: return West | OtherMeta;
+ case West: return South | OtherMeta;
+ }
+ if (AssertIfNotMatched)
+ {
+ ASSERT(!"Invalid Meta value");
+ }
+ return a_Meta;
+}
+
+
+
+
+
+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)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case South: return North | OtherMeta;
+ case North: return South | OtherMeta;
+ }
+ // Not Facing North or South; No change.
+ return a_Meta;
+}
+
+
+
+
+
+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)
+{
+ NIBBLETYPE OtherMeta = a_Meta & (~BitMask);
+ switch (a_Meta & BitMask)
+ {
+ case West: return East | OtherMeta;
+ case East: return West | OtherMeta;
+ }
+ // Not Facing East or West; No change.
+ return a_Meta;
+}
+
+
+
+
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index b6f2f55a7..e59b00eff 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -27,4 +27,7 @@ public:
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0;
+
+ /** Sends the block on those coords to the player */
+ virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0;
};
diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp
index d2d3beb97..96a135562 100644
--- a/src/ByteBuffer.cpp
+++ b/src/ByteBuffer.cpp
@@ -44,10 +44,10 @@
-#if 0
+#ifdef SELF_TEST
/// Self-test of the VarInt-reading and writing code
-class cByteBufferSelfTest
+static class cByteBufferSelfTest
{
public:
cByteBufferSelfTest(void)
@@ -86,7 +86,7 @@ public:
cByteBuffer buf(3);
for (int i = 0; i < 1000; i++)
{
- int FreeSpace = buf.GetFreeSpace();
+ size_t FreeSpace = buf.GetFreeSpace();
assert(buf.GetReadableSpace() == 0);
assert(FreeSpace > 0);
assert(buf.Write("a", 1));
@@ -171,21 +171,22 @@ cByteBuffer::~cByteBuffer()
-bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
+bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
// Store the current free space for a check after writing:
- int CurFreeSpace = GetFreeSpace();
- int CurReadableSpace = GetReadableSpace();
- int WrittenBytes = 0;
+ size_t CurFreeSpace = GetFreeSpace();
+ size_t CurReadableSpace = GetReadableSpace();
+ size_t WrittenBytes = 0;
if (CurFreeSpace < a_Count)
{
return false;
}
- int TillEnd = m_BufferSize - m_WritePos;
+ ASSERT(m_BufferSize >= m_WritePos);
+ size_t TillEnd = m_BufferSize - m_WritePos;
if (TillEnd <= a_Count)
{
// Need to wrap around the ringbuffer end
@@ -216,16 +217,20 @@ bool cByteBuffer::Write(const char * a_Bytes, int a_Count)
-int cByteBuffer::GetFreeSpace(void) const
+size_t cByteBuffer::GetFreeSpace(void) const
{
CHECK_THREAD;
CheckValid();
if (m_WritePos >= m_DataStart)
{
// Wrap around the buffer end:
+ ASSERT(m_BufferSize >= m_WritePos);
+ ASSERT((m_BufferSize - m_WritePos + m_DataStart) >= 1);
return m_BufferSize - m_WritePos + m_DataStart - 1;
}
// Single free space partition:
+ ASSERT(m_BufferSize >= m_WritePos);
+ ASSERT(m_BufferSize - m_WritePos >= 1);
return m_DataStart - m_WritePos - 1;
}
@@ -234,10 +239,12 @@ int cByteBuffer::GetFreeSpace(void) const
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
-int cByteBuffer::GetUsedSpace(void) const
+size_t cByteBuffer::GetUsedSpace(void) const
{
CHECK_THREAD;
CheckValid();
+ ASSERT(m_BufferSize >= GetFreeSpace());
+ ASSERT((m_BufferSize - GetFreeSpace()) >= 1);
return m_BufferSize - GetFreeSpace() - 1;
}
@@ -246,16 +253,18 @@ int cByteBuffer::GetUsedSpace(void) const
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
-int cByteBuffer::GetReadableSpace(void) const
+size_t cByteBuffer::GetReadableSpace(void) const
{
CHECK_THREAD;
CheckValid();
if (m_ReadPos > m_WritePos)
{
// Wrap around the buffer end:
+ ASSERT(m_BufferSize >= m_ReadPos);
return m_BufferSize - m_ReadPos + m_WritePos;
}
// Single readable space partition:
+ ASSERT(m_WritePos >= m_ReadPos);
return m_WritePos - m_ReadPos ;
}
@@ -263,7 +272,7 @@ int cByteBuffer::GetReadableSpace(void) const
-bool cByteBuffer::CanReadBytes(int a_Count) const
+bool cByteBuffer::CanReadBytes(size_t a_Count) const
{
CHECK_THREAD;
CheckValid();
@@ -274,7 +283,7 @@ bool cByteBuffer::CanReadBytes(int a_Count) const
-bool cByteBuffer::CanWriteBytes(int a_Count) const
+bool cByteBuffer::CanWriteBytes(size_t a_Count) const
{
CHECK_THREAD;
CheckValid();
@@ -650,15 +659,14 @@ bool cByteBuffer::WriteLEInt(int a_Value)
-bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
+bool cByteBuffer::ReadBuf(void * a_Buffer, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
NEEDBYTES(a_Count);
char * Dst = (char *)a_Buffer; // So that we can do byte math
- int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
- ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
@@ -684,14 +692,14 @@ bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count)
-bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
+bool cByteBuffer::WriteBuf(const void * a_Buffer, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
PUTBYTES(a_Count);
char * Src = (char *)a_Buffer; // So that we can do byte math
- int BytesToEndOfBuffer = m_BufferSize - m_WritePos;
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_WritePos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
@@ -714,22 +722,22 @@ bool cByteBuffer::WriteBuf(const void * a_Buffer, int a_Count)
-bool cByteBuffer::ReadString(AString & a_String, int a_Count)
+bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
NEEDBYTES(a_Count);
a_String.clear();
a_String.reserve(a_Count);
- int BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
- ASSERT(BytesToEndOfBuffer >= 0); // Sanity check
+ ASSERT(m_BufferSize >= m_ReadPos);
+ size_t BytesToEndOfBuffer = m_BufferSize - m_ReadPos;
if (BytesToEndOfBuffer <= a_Count)
{
// Reading across the ringbuffer end, read the first part and adjust parameters:
if (BytesToEndOfBuffer > 0)
{
a_String.assign(m_Buffer + m_ReadPos, BytesToEndOfBuffer);
+ ASSERT(a_Count >= BytesToEndOfBuffer);
a_Count -= BytesToEndOfBuffer;
}
m_ReadPos = 0;
@@ -767,11 +775,10 @@ bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
-bool cByteBuffer::SkipRead(int a_Count)
+bool cByteBuffer::SkipRead(size_t a_Count)
{
CHECK_THREAD;
CheckValid();
- ASSERT(a_Count >= 0);
if (!CanReadBytes(a_Count))
{
return false;
@@ -809,6 +816,7 @@ bool cByteBuffer::ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes)
size_t num = (a_NumBytes > sizeof(buf)) ? sizeof(buf) : a_NumBytes;
VERIFY(ReadBuf(buf, num));
VERIFY(a_Dst.Write(buf, num));
+ ASSERT(a_NumBytes >= num);
a_NumBytes -= num;
}
return true;
@@ -846,13 +854,15 @@ void cByteBuffer::ReadAgain(AString & a_Out)
// Used by ProtoProxy to repeat communication twice, once for parsing and the other time for the remote party
CHECK_THREAD;
CheckValid();
- int DataStart = m_DataStart;
+ size_t DataStart = m_DataStart;
if (m_ReadPos < m_DataStart)
{
// Across the ringbuffer end, read the first part and adjust next part's start:
+ ASSERT(m_BufferSize >= m_DataStart);
a_Out.append(m_Buffer + m_DataStart, m_BufferSize - m_DataStart);
DataStart = 0;
}
+ ASSERT(m_ReadPos >= DataStart);
a_Out.append(m_Buffer + DataStart, m_ReadPos - DataStart);
}
@@ -860,7 +870,7 @@ void cByteBuffer::ReadAgain(AString & a_Out)
-void cByteBuffer::AdvanceReadPos(int a_Count)
+void cByteBuffer::AdvanceReadPos(size_t a_Count)
{
CHECK_THREAD;
CheckValid();
diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h
index cbce119b1..ed2e10a55 100644
--- a/src/ByteBuffer.h
+++ b/src/ByteBuffer.h
@@ -31,25 +31,25 @@ public:
~cByteBuffer();
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
- bool Write(const char * a_Bytes, int a_Count);
+ bool Write(const char * a_Bytes, size_t a_Count);
/// Returns the number of bytes that can be successfully written to the ringbuffer
- int GetFreeSpace(void) const;
+ size_t GetFreeSpace(void) const;
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
- int GetUsedSpace(void) const;
+ size_t GetUsedSpace(void) const;
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
- int GetReadableSpace(void) const;
+ size_t GetReadableSpace(void) const;
/// Returns the current data start index. For debugging purposes.
int GetDataStart(void) const { return m_DataStart; }
/// Returns true if the specified amount of bytes are available for reading
- bool CanReadBytes(int a_Count) const;
+ bool CanReadBytes(size_t a_Count) const;
/// Returns true if the specified amount of bytes are available for writing
- bool CanWriteBytes(int a_Count) const;
+ bool CanWriteBytes(size_t a_Count) const;
// Read the specified datatype and advance the read pointer; return true if successfully read:
bool ReadChar (char & a_Value);
@@ -92,19 +92,19 @@ public:
bool WriteLEInt (int a_Value);
/// Reads a_Count bytes into a_Buffer; returns true if successful
- bool ReadBuf(void * a_Buffer, int a_Count);
+ bool ReadBuf(void * a_Buffer, size_t a_Count);
/// Writes a_Count bytes into a_Buffer; returns true if successful
- bool WriteBuf(const void * a_Buffer, int a_Count);
+ bool WriteBuf(const void * a_Buffer, size_t a_Count);
/// Reads a_Count bytes into a_String; returns true if successful
- bool ReadString(AString & a_String, int a_Count);
+ bool ReadString(AString & a_String, size_t a_Count);
/// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
bool ReadUTF16String(AString & a_String, int a_NumChars);
/// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
- bool SkipRead(int a_Count);
+ bool SkipRead(size_t a_Count);
/// Reads all available data into a_Data
void ReadAll(AString & a_Data);
@@ -126,18 +126,18 @@ public:
protected:
char * m_Buffer;
- int m_BufferSize; // Total size of the ringbuffer
+ size_t m_BufferSize; // Total size of the ringbuffer
#ifdef _DEBUG
volatile unsigned long m_ThreadID; // Thread that is currently accessing the object, checked via cSingleThreadAccessChecker
#endif // _DEBUG
- int m_DataStart; // Where the data starts in the ringbuffer
- int m_WritePos; // Where the data ends in the ringbuffer
- int m_ReadPos; // Where the next read will start in the ringbuffer
+ size_t m_DataStart; // Where the data starts in the ringbuffer
+ size_t m_WritePos; // Where the data ends in the ringbuffer
+ size_t m_ReadPos; // Where the next read will start in the ringbuffer
/// Advances the m_ReadPos by a_Count bytes
- void AdvanceReadPos(int a_Count);
+ void AdvanceReadPos(size_t a_Count);
} ;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5e0731264..5029906aa 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -40,6 +40,7 @@ if (NOT MSVC)
BlockEntities/NoteEntity.h
BlockEntities/SignEntity.h
BlockEntities/MobHeadEntity.h
+ BlockEntities/FlowerPotEntity.h
BlockID.h
BoundingBox.h
ChatColor.h
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index a75828461..957d7d575 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -20,6 +20,7 @@
#include "BlockEntities/NoteEntity.h"
#include "BlockEntities/SignEntity.h"
#include "BlockEntities/MobHeadEntity.h"
+#include "BlockEntities/FlowerPotEntity.h"
#include "Entities/Pickup.h"
#include "Item.h"
#include "Noise.h"
@@ -1311,6 +1312,7 @@ void cChunk::CreateBlockEntities(void)
case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX:
+ case E_BLOCK_FLOWER_POT:
{
if (!HasBlockEntityAt(x + m_PosX * Width, y + m_PosY * Height, z + m_PosZ * Width))
{
@@ -1440,6 +1442,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
case E_BLOCK_HEAD:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_JUKEBOX:
+ case E_BLOCK_FLOWER_POT:
{
AddBlockEntity(cBlockEntity::CreateByBlockType(a_BlockType, a_BlockMeta, WorldPos.x, WorldPos.y, WorldPos.z, m_World));
break;
@@ -2337,7 +2340,7 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
-bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
@@ -2369,6 +2372,38 @@ bool cChunk::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMob
+bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
+{
+ // The blockentity list is locked by the parent chunkmap's CS
+ for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
+ {
+ ++itr2;
+ if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ))
+ {
+ continue;
+ }
+ if ((*itr)->GetBlockType() != E_BLOCK_FLOWER_POT)
+ {
+ // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
+ return false;
+ }
+
+ // The correct block entity is here,
+ if (a_Callback.Item((cFlowerPotEntity *)*itr))
+ {
+ return false;
+ }
+ return true;
+ } // for itr - m_BlockEntitites[]
+
+ // Not found:
+ return false;
+}
+
+
+
+
+
bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
// The blockentity list is locked by the parent chunkmap's CS
diff --git a/src/Chunk.h b/src/Chunk.h
index c9e9697ca..b3fa563cc 100644
--- a/src/Chunk.h
+++ b/src/Chunk.h
@@ -32,6 +32,7 @@ class cDispenserEntity;
class cFurnaceEntity;
class cNoteEntity;
class cMobHeadEntity;
+class cFlowerPotEntity;
class cBlockArea;
class cPawn;
class cPickup;
@@ -48,7 +49,8 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
-typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
+typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
@@ -253,8 +255,11 @@ public:
/** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
- /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob header block at those coords or callback returns true, returns true if found */
- bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback);
+ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
+ bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback);
+
+ /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
+ bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback);
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp
index e750ad731..ab4e01334 100644
--- a/src/ChunkMap.cpp
+++ b/src/ChunkMap.cpp
@@ -2191,7 +2191,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
-bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{
int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@@ -2202,7 +2202,25 @@ bool cChunkMap::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
{
return false;
}
- return Chunk->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+ return Chunk->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
+
+
+bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
+{
+ int ChunkX, ChunkZ;
+ int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
+ cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ cCSLock Lock(m_CSLayers);
+ cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ if ((Chunk == NULL) && !Chunk->IsValid())
+ {
+ return false;
+ }
+ return Chunk->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
diff --git a/src/ChunkMap.h b/src/ChunkMap.h
index 9df68c403..9d973f2a9 100644
--- a/src/ChunkMap.h
+++ b/src/ChunkMap.h
@@ -26,6 +26,7 @@ class cFurnaceEntity;
class cNoteEntity;
class cCommandBlockEntity;
class cMobHeadEntity;
+class cFlowerPotEntity;
class cPawn;
class cPickup;
class cChunkDataSerializer;
@@ -41,10 +42,11 @@ typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
+typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
-typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cChunk> cChunkCallback;
@@ -257,7 +259,10 @@ public:
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
- bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback); // Lua-accessible
+ bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Lua-accessible
+
+ /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
+ bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Lua-accessible
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 07a8984c5..b08c029c0 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -96,8 +96,8 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
m_ShouldCheckDownloaded(false),
m_NumExplosionsThisTick(0),
m_UniqueID(0),
- m_Locale("en_GB"),
- m_HasSentPlayerChunk(false)
+ m_HasSentPlayerChunk(false),
+ m_Locale("en_GB")
{
m_Protocol = new cProtocolRecognizer(this);
@@ -555,12 +555,25 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString
}
else if (a_Channel == "REGISTER")
{
+ if (HasPluginChannel(a_Channel))
+ {
+ SendPluginMessage("UNREGISTER", a_Channel);
+ return; // Can't register again if already taken - kinda defeats the point of plugin messaging!
+ }
+
RegisterPluginChannels(BreakApartPluginChannels(a_Message));
}
else if (a_Channel == "UNREGISTER")
{
UnregisterPluginChannels(BreakApartPluginChannels(a_Message));
}
+ else if (!HasPluginChannel(a_Channel))
+ {
+ // Ignore if client sent something but didn't register the channel first
+ LOGD("Player %s sent a plugin message on channel \"%s\", but didn't REGISTER it first", GetUsername().c_str(), a_Channel.c_str());
+ SendPluginMessage("UNREGISTER", a_Channel);
+ return;
+ }
cPluginManager::Get()->CallHookPluginMessage(*this, a_Channel, a_Message);
}
@@ -838,7 +851,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
cWorld * World = m_Player->GetWorld();
cChunkInterface ChunkInterface(World->GetChunkMap());
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(a_OldBlock);
+ cBlockHandler * Handler = cBlockInfo::GetHandler(a_OldBlock);
Handler->OnDigging(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
@@ -852,7 +865,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
int pZ = a_BlockZ;
AddFaceDirection(pX, pY, pZ, a_BlockFace); // Get the block in front of the clicked coordinates (m_bInverse defaulted to false)
- Handler = cBlockHandler::GetBlockHandler(World->GetBlock(pX, pY, pZ));
+ Handler = cBlockInfo::GetHandler(World->GetBlock(pX, pY, pZ));
if (Handler->IsClickedThrough())
{
@@ -920,14 +933,22 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
);
+ cWorld * World = m_Player->GetWorld();
+
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
{
// A plugin doesn't agree with the action, replace the block on the client and quit:
+ cChunkInterface ChunkInterface(World->GetChunkMap());
+ BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
+ BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+
if (a_BlockFace > -1)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things
}
return;
}
@@ -953,17 +974,15 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
if (a_BlockFace > -1)
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
- m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
+ World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
}
return;
}
-
- cWorld * World = m_Player->GetWorld();
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType);
+ cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{
@@ -1447,7 +1466,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
-void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
+void cClientHandle::HandleEntityCrouch(int a_EntityID, bool a_IsCrouching)
{
if (a_EntityID != m_Player->GetUniqueID())
{
@@ -1455,35 +1474,37 @@ void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
return;
}
- switch (a_ActionID)
+ m_Player->SetCrouch(a_IsCrouching);
+}
+
+
+
+
+
+void cClientHandle::HandleEntityLeaveBed(int a_EntityID)
+{
+ if (a_EntityID != m_Player->GetUniqueID())
{
- case 1: // Crouch
- {
- m_Player->SetCrouch(true);
- break;
- }
- case 2: // Uncrouch
- {
- m_Player->SetCrouch(false);
- break;
- }
- case 3: // Leave bed
- {
- m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
- break;
- }
- case 4: // Start sprinting
- {
- m_Player->SetSprint(true);
- break;
- }
- case 5: // Stop sprinting
- {
- m_Player->SetSprint(false);
- SendPlayerMaxSpeed();
- break;
- }
+ // We should only receive entity actions from the entity that is performing the action
+ return;
}
+
+ m_Player->GetWorld()->BroadcastEntityAnimation(*m_Player, 2);
+}
+
+
+
+
+
+void cClientHandle::HandleEntitySprinting(int a_EntityID, bool a_IsSprinting)
+{
+ if (a_EntityID != m_Player->GetUniqueID())
+ {
+ // We should only receive entity actions from the entity that is performing the action
+ return;
+ }
+
+ m_Player->SetSprint(a_IsSprinting);
}
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index 194533402..035fadfe4 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -188,7 +188,9 @@ public:
void HandleChat (const AString & a_Message);
void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
void HandleDisconnect (const AString & a_Reason);
- void HandleEntityAction (int a_EntityID, char a_ActionID);
+ void HandleEntityCrouch (int a_EntityID, bool a_IsCrouching);
+ void HandleEntityLeaveBed (int a_EntityID);
+ void HandleEntitySprinting (int a_EntityID, bool a_IsSprinting);
/** Called when the protocol handshake has been received (for protocol versions that support it;
otherwise the first instant when a username is received).
diff --git a/src/CompositeChat.h b/src/CompositeChat.h
index 51600da4f..27319490d 100644
--- a/src/CompositeChat.h
+++ b/src/CompositeChat.h
@@ -124,14 +124,15 @@ public:
/** Removes all parts from the object. */
void Clear(void);
+ // tolua_end
+
+ // The following are exported in ManualBindings in order to support chaining - they return *this in Lua (#755)
+
/** Adds a plain text part, with optional style.
The default style is plain white text. */
void AddTextPart(const AString & a_Message, const AString & a_Style = "");
- // tolua_end
-
- /** Adds a part that is translated client-side, with the formatting parameters and optional style.
- Exported in ManualBindings due to AStringVector usage - Lua uses an array-table of strings. */
+ /** Adds a part that is translated client-side, with the formatting parameters and optional style. */
void AddClientTranslatedPart(const AString & a_TranslationID, const AStringVector & a_Parameters, const AString & a_Style = "");
// tolua_begin
@@ -155,12 +156,14 @@ public:
/** Sets the message type, which is indicated by prefixes added to the message when serializing. */
void SetMessageType(eMessageType a_MessageType);
- /** Returns the message type set previously by SetMessageType(). */
- eMessageType GetMessageType(void) const { return m_MessageType; }
-
/** Adds the "underline" style to each part that is an URL. */
void UnderlineUrls(void);
+ // tolua_begin
+
+ /** Returns the message type set previously by SetMessageType(). */
+ eMessageType GetMessageType(void) const { return m_MessageType; }
+
// tolua_end
const cParts & GetParts(void) const { return m_Parts; }
diff --git a/src/Defines.h b/src/Defines.h
index 018ecb1d3..6ab2274a4 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -235,8 +235,8 @@ inline eBlockFace MirrorBlockFaceY(eBlockFace a_BlockFace)
case BLOCK_FACE_XP: return BLOCK_FACE_XM;
case BLOCK_FACE_ZM: return BLOCK_FACE_ZP;
case BLOCK_FACE_ZP: return BLOCK_FACE_ZM;
+ default: return a_BlockFace;
}
- return a_BlockFace;
}
@@ -252,8 +252,8 @@ inline eBlockFace RotateBlockFaceCCW(eBlockFace a_BlockFace)
case BLOCK_FACE_XP: return BLOCK_FACE_ZM;
case BLOCK_FACE_ZM: return BLOCK_FACE_XM;
case BLOCK_FACE_ZP: return BLOCK_FACE_XP;
+ default: return a_BlockFace;
}
- return a_BlockFace;
}
@@ -268,8 +268,8 @@ inline eBlockFace RotateBlockFaceCW(eBlockFace a_BlockFace)
case BLOCK_FACE_XP: return BLOCK_FACE_ZP;
case BLOCK_FACE_ZM: return BLOCK_FACE_XP;
case BLOCK_FACE_ZP: return BLOCK_FACE_XM;
+ default: return a_BlockFace;
}
- return a_BlockFace;
}
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/Minecart.cpp b/src/Entities/Minecart.cpp
index f52a7b6d9..7f38aa35a 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -1031,9 +1031,9 @@ cMinecartWithChest::cMinecartWithChest(double a_X, double a_Y, double a_Z) :
-void cMinecartWithChest::SetSlot(int a_Idx, const cItem & a_Item)
+void cMinecartWithChest::SetSlot(size_t a_Idx, const cItem & a_Item)
{
- ASSERT((a_Idx >= 0) && (a_Idx < ARRAYCOUNT(m_Items)));
+ ASSERT(a_Idx < ARRAYCOUNT(m_Items));
m_Items[a_Idx] = a_Item;
}
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index 073e78953..ebdb576e0 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -122,7 +122,7 @@ public:
const cItem & GetSlot(int a_Idx) const { return m_Items[a_Idx]; }
cItem & GetSlot(int a_Idx) { return m_Items[a_Idx]; }
- void SetSlot(int a_Idx, const cItem & a_Item);
+ void SetSlot(size_t a_Idx, const cItem & a_Item);
protected:
@@ -193,4 +193,4 @@ public:
CLASS_PROTODEF(cMinecartWithHopper);
cMinecartWithHopper(double a_X, double a_Y, double a_Z);
-} ; \ No newline at end of file
+} ;
diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp
index d9acc57bb..28dc37567 100644
--- a/src/Generating/MineShafts.cpp
+++ b/src/Generating/MineShafts.cpp
@@ -69,6 +69,8 @@ public:
m_BoundingBox(a_BoundingBox)
{
}
+
+ virtual ~cMineShaft() {}
/// Returns true if this mineshaft intersects the specified cuboid
bool DoesIntersect(const cCuboid & a_Other)
diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp
index a660285d1..4909587b1 100644
--- a/src/Generating/Trees.cpp
+++ b/src/Generating/Trees.cpp
@@ -595,7 +595,7 @@ void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise
{
break;
}
- ASSERT(LayerSize < ARRAYCOUNT(BigOs));
+ ASSERT((size_t)LayerSize < ARRAYCOUNT(BigOs));
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_OtherBlocks, BigOs[LayerSize].Coords, BigOs[LayerSize].Count, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
h--;
}
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index 7f434adfd..c7c089d5f 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -204,6 +204,12 @@ void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item)
return;
}
Grid->SetSlot(GridSlotNum, a_Item);
+
+ // Broadcast the Equipped Item, if the Slot is changed.
+ if ((Grid == &m_HotbarSlots) && (m_EquippedSlotNum == (a_SlotNum - invHotbarOffset)))
+ {
+ m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, 0, a_Item, m_Owner.GetClientHandle());
+ }
}
diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp
index 507f7fa86..1d357fcf1 100644
--- a/src/Items/ItemHandler.cpp
+++ b/src/Items/ItemHandler.cpp
@@ -285,7 +285,7 @@ void cItemHandler::OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const
UNUSED(a_Item);
BLOCKTYPE Block = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(Block);
+ cBlockHandler * Handler = cBlockInfo::GetHandler(Block);
if (a_Player->IsGameModeSurvival())
{
diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h
index ef3f37a7a..5b6c239cc 100644
--- a/src/Items/ItemHandler.h
+++ b/src/Items/ItemHandler.h
@@ -21,6 +21,9 @@ class cItemHandler
public:
cItemHandler(int a_ItemType);
+ // Force virtual destructor
+ virtual ~cItemHandler() {}
+
/// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir);
diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h
index bde7f0905..2a8e40daa 100644
--- a/src/Items/ItemPickaxe.h
+++ b/src/Items/ItemPickaxe.h
@@ -19,17 +19,13 @@ public:
{
switch(m_ItemType)
{
- case E_ITEM_WOODEN_PICKAXE:
- case E_ITEM_GOLD_PICKAXE:
- return 1;
- case E_ITEM_STONE_PICKAXE:
- return 2;
- case E_ITEM_IRON_PICKAXE:
- return 3;
- case E_ITEM_DIAMOND_PICKAXE:
- return 4;
- default:
- return 0;
+ case E_ITEM_WOODEN_PICKAXE: return 1;
+ case E_ITEM_GOLD_PICKAXE: return 1;
+ case E_ITEM_STONE_PICKAXE: return 2;
+ case E_ITEM_IRON_PICKAXE: return 3;
+ case E_ITEM_DIAMOND_PICKAXE: return 4;
+
+ default: return 0;
}
}
@@ -61,6 +57,10 @@ public:
return PickaxeLevel() >= 2;
}
+ case E_BLOCK_ANVIL:
+ case E_BLOCK_ENCHANTMENT_TABLE:
+ case E_BLOCK_FURNACE:
+ case E_BLOCK_LIT_FURNACE:
case E_BLOCK_COAL_ORE:
case E_BLOCK_STONE:
case E_BLOCK_COBBLESTONE:
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 09a6e2d09..bbd8d6aaa 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -150,7 +150,7 @@ void cVillager::HandleFarmerTryHarvestCrops()
BLOCKTYPE CropBlock = m_World->GetBlock(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
if (IsBlockFarmable(CropBlock) && m_World->GetBlockMeta(m_CropsPos.x, m_CropsPos.y, m_CropsPos.z) == 0x7)
{
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(CropBlock);
+ cBlockHandler * Handler = cBlockInfo::GetHandler(CropBlock);
cChunkInterface ChunkInterface(m_World->GetChunkMap());
cBlockInServerPluginInterface PluginInterface(*m_World);
Handler->DropBlock(ChunkInterface, *m_World, PluginInterface, this, m_CropsPos.x, m_CropsPos.y, m_CropsPos.z);
diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h
index fcd2ce11f..b2eb5950f 100644
--- a/src/OSSupport/SocketThreads.h
+++ b/src/OSSupport/SocketThreads.h
@@ -103,7 +103,7 @@ private:
public:
cSocketThread(cSocketThreads * a_Parent);
- ~cSocketThread();
+ virtual ~cSocketThread();
// All these methods assume parent's m_CS is locked
bool HasEmptySlot(void) const {return m_NumSlots < MAX_SLOTS; }
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index b5560f7c1..d3383bf0d 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -52,7 +52,7 @@ public:
virtual ~cProtocol() {}
/// Called when client sends some data
- virtual void DataReceived(const char * a_Data, int a_Size) = 0;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) = 0;
// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index 3980350f5..50ebb6d43 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -1186,7 +1186,7 @@ void cProtocol125::SendData(const char * a_Data, int a_Size)
-void cProtocol125::DataReceived(const char * a_Data, int a_Size)
+void cProtocol125::DataReceived(const char * a_Data, size_t a_Size)
{
if (!m_ReceivedData.Write(a_Data, a_Size))
{
@@ -1375,7 +1375,16 @@ int cProtocol125::ParseEntityAction(void)
{
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_PACKET_READ(ReadChar, char, ActionID);
- m_Client->HandleEntityAction(EntityID, ActionID);
+
+ switch (ActionID)
+ {
+ case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
+ }
+
return PARSE_OK;
}
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 1d1484a60..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"
@@ -24,7 +25,7 @@ public:
cProtocol125(cClientHandle * a_Client);
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
@@ -57,9 +58,17 @@ public:
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
- virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override {} // This protocol doesn't support such message
+ virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override
+ {
+ // This protocol doesn't support such message
+ UNUSED(a_ID);
+ UNUSED(a_Scale);
+ }
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
- virtual void SendPaintingSpawn (const cPainting & a_Painting) override {};
+ virtual void SendPaintingSpawn (const cPainting & a_Painting) override
+ {
+ UNUSED(a_Painting);
+ };
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
@@ -73,7 +82,12 @@ public:
virtual void SendRespawn (void) override;
virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
- virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override {} // This protocol doesn't support such message
+ virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override
+ {
+ UNUSED(a_Name);
+ UNUSED(a_DisplayName);
+ UNUSED(a_Mode);
+ } // This protocol doesn't support such message
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 1f9222a69..8df550c7b 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -108,7 +108,7 @@ cProtocol132::~cProtocol132()
-void cProtocol132::DataReceived(const char * a_Data, int a_Size)
+void cProtocol132::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h
index 89f4636f5..0702fbf5a 100644
--- a/src/Protocol/Protocol132.h
+++ b/src/Protocol/Protocol132.h
@@ -40,7 +40,7 @@ public:
virtual ~cProtocol132();
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
// Sending commands (alphabetically sorted):
virtual void SendBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) override;
diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp
index cfa27b3c4..f6ec0a199 100644
--- a/src/Protocol/Protocol16x.cpp
+++ b/src/Protocol/Protocol16x.cpp
@@ -184,7 +184,16 @@ int cProtocol161::ParseEntityAction(void)
HANDLE_PACKET_READ(ReadBEInt, int, EntityID);
HANDLE_PACKET_READ(ReadChar, char, ActionID);
HANDLE_PACKET_READ(ReadBEInt, int, UnknownHorseVal);
- m_Client->HandleEntityAction(EntityID, ActionID);
+
+ switch (ActionID)
+ {
+ case 1: m_Client->HandleEntityCrouch(EntityID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(EntityID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(EntityID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(EntityID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(EntityID, false); break; // Stop sprinting
+ }
+
return PARSE_OK;
}
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 992023464..a72da776d 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -29,6 +29,7 @@ Implements the 1.7.x protocol classes:
#include "../UI/Window.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../CompositeChat.h"
@@ -97,7 +98,7 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
-void cProtocol172::DataReceived(const char * a_Data, int a_Size)
+void cProtocol172::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_IsEncrypted)
{
@@ -1115,6 +1116,7 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
case E_BLOCK_MOB_SPAWNER: Action = 1; break; // Update mob spawner spinny mob thing
case E_BLOCK_COMMAND_BLOCK: Action = 2; break; // Update command block text
case E_BLOCK_HEAD: Action = 4; break; // Update Mobhead entity
+ case E_BLOCK_FLOWER_POT: Action = 5; break; // Update flower pot
default: ASSERT(!"Unhandled or unimplemented BlockEntity update request!"); break;
}
Pkt.WriteByte(Action);
@@ -1242,7 +1244,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (m_ReceivedData.GetReadableSpace() > 0)
{
AString AllData;
- int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
@@ -1364,7 +1366,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
if (g_ShouldLogCommIn && (m_ReceivedData.GetReadableSpace() > 0))
{
AString AllData;
- int OldReadableSpace = m_ReceivedData.GetReadableSpace();
+ size_t OldReadableSpace = m_ReceivedData.GetReadableSpace();
m_ReceivedData.ReadAll(AllData);
m_ReceivedData.ResetRead();
m_ReceivedData.SkipRead(m_ReceivedData.GetReadableSpace() - OldReadableSpace);
@@ -1730,7 +1732,15 @@ void cProtocol172::HandlePacketEntityAction(cByteBuffer & a_ByteBuffer)
HANDLE_READ(a_ByteBuffer, ReadBEInt, int, PlayerID);
HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Action);
HANDLE_READ(a_ByteBuffer, ReadBEInt, int, JumpBoost);
- m_Client->HandleEntityAction(PlayerID, Action);
+
+ switch (Action)
+ {
+ case 1: m_Client->HandleEntityCrouch(PlayerID, true); break; // Crouch
+ case 2: m_Client->HandleEntityCrouch(PlayerID, false); break; // Uncrouch
+ case 3: m_Client->HandleEntityLeaveBed(PlayerID); break; // Leave Bed
+ case 4: m_Client->HandleEntitySprinting(PlayerID, true); break; // Start sprinting
+ case 5: m_Client->HandleEntitySprinting(PlayerID, false); break; // Stop sprinting
+ }
}
@@ -2345,7 +2355,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
case E_BLOCK_HEAD:
{
cMobHeadEntity & MobHeadEntity = (cMobHeadEntity &)a_BlockEntity;
-
+
Writer.AddInt("x", MobHeadEntity.GetPosX());
Writer.AddInt("y", MobHeadEntity.GetPosY());
Writer.AddInt("z", MobHeadEntity.GetPosZ());
@@ -2355,6 +2365,18 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt
Writer.AddString("id", "Skull"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
break;
}
+ case E_BLOCK_FLOWER_POT:
+ {
+ cFlowerPotEntity & FlowerPotEntity = (cFlowerPotEntity &)a_BlockEntity;
+
+ Writer.AddInt("x", FlowerPotEntity.GetPosX());
+ Writer.AddInt("y", FlowerPotEntity.GetPosY());
+ Writer.AddInt("z", FlowerPotEntity.GetPosZ());
+ Writer.AddInt("Item", (Int32) FlowerPotEntity.GetItem().m_ItemType);
+ Writer.AddInt("Data", (Int32) FlowerPotEntity.GetItem().m_ItemDamage);
+ Writer.AddString("id", "FlowerPot"); // "Tile Entity ID" - MC wiki; vanilla server always seems to send this though
+ break;
+ }
default: break;
}
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 113501568..41163009e 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -56,7 +56,7 @@ public:
cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
/** Called when client sends some data: */
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/** Sending stuff to clients (alphabetically sorted): */
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index 84b052146..3b9003e60 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -68,7 +68,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
-void cProtocolRecognizer::DataReceived(const char * a_Data, int a_Size)
+void cProtocolRecognizer::DataReceived(const char * a_Data, size_t a_Size)
{
if (m_Protocol == NULL)
{
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index 6aaafedeb..d7fb8fad2 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -59,7 +59,7 @@ public:
static AString GetVersionTextFromInt(int a_ProtocolVersion);
/// Called when client sends some data:
- virtual void DataReceived(const char * a_Data, int a_Size) override;
+ virtual void DataReceived(const char * a_Data, size_t a_Size) override;
/// Sending stuff to clients (alphabetically sorted):
virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override;
diff --git a/src/Root.cpp b/src/Root.cpp
index af2cb9e4b..69f18104e 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -245,7 +245,6 @@ void cRoot::Start(void)
delete m_PluginManager; m_PluginManager = NULL;
cItemHandler::Deinit();
- cBlockHandler::Deinit();
LOG("Cleaning up...");
delete m_Server; m_Server = NULL;
@@ -594,7 +593,6 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
unsigned m_NameLength;
const AString m_PlayerName;
- cPlayerListCallback & m_Callback;
virtual bool Item (cPlayer * a_pPlayer)
{
unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
@@ -616,18 +614,17 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac
}
public:
- cCallback (const AString & a_PlayerName, cPlayerListCallback & a_Callback) :
+ cCallback (const AString & a_PlayerName) :
m_BestRating(0),
m_NameLength(a_PlayerName.length()),
m_PlayerName(a_PlayerName),
- m_Callback(a_Callback),
m_BestMatch(NULL),
m_NumMatches(0)
{}
cPlayer * m_BestMatch;
unsigned m_NumMatches;
- } Callback (a_PlayerName, a_Callback);
+ } Callback (a_PlayerName);
ForEachPlayer( Callback );
if (Callback.m_NumMatches == 1)
diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp
index 05fd0314d..8088e624b 100644
--- a/src/Scoreboard.cpp
+++ b/src/Scoreboard.cpp
@@ -312,12 +312,18 @@ bool cScoreboard::RemoveObjective(const AString & a_Name)
return false;
}
- m_Objectives.erase(it);
-
ASSERT(m_World != NULL);
m_World->BroadcastScoreboardObjective(it->second.GetName(), it->second.GetDisplayName(), 1);
- // TODO 2014-03-01 xdot: Remove objective from display slot
+ for (unsigned int i = 0; i < (unsigned int) dsCount; ++i)
+ {
+ if (m_Display[i] == &it->second)
+ {
+ SetDisplay(NULL, (eDisplaySlot) i);
+ }
+ }
+
+ m_Objectives.erase(it);
return true;
}
@@ -500,7 +506,7 @@ bool cScoreboard::ForEachObjective(cObjectiveCallback& a_Callback)
bool cScoreboard::ForEachTeam(cTeamCallback& a_Callback)
{
- cCSLock Lock(m_CSObjectives);
+ cCSLock Lock(m_CSTeams);
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
{
diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp
index 3d2170e44..bc5158d95 100644
--- a/src/Simulator/DelayedFluidSimulator.cpp
+++ b/src/Simulator/DelayedFluidSimulator.cpp
@@ -20,7 +20,7 @@
bool cDelayedFluidSimulatorChunkData::cSlot::Add(int a_RelX, int a_RelY, int a_RelZ)
{
ASSERT(a_RelZ >= 0);
- ASSERT(a_RelZ < ARRAYCOUNT(m_Blocks));
+ ASSERT(a_RelZ < static_cast<int>(ARRAYCOUNT(m_Blocks)));
cCoordWithIntVector & Blocks = m_Blocks[a_RelZ];
int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ);
diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp
index 95182345c..03e94e791 100644
--- a/src/Simulator/FloodyFluidSimulator.cpp
+++ b/src/Simulator/FloodyFluidSimulator.cpp
@@ -54,14 +54,23 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ)
);
- NIBBLETYPE MyMeta = a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ);
- if (!IsAnyFluidBlock(a_Chunk->GetBlock(a_RelX, a_RelY, a_RelZ)))
+ BLOCKTYPE MyBlock; NIBBLETYPE MyMeta;
+ a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta);
+
+ if (!IsAnyFluidBlock(MyBlock))
{
// Can happen - if a block is scheduled for simulating and gets replaced in the meantime.
FLOG(" BadBlockType exit");
return;
}
+ // When in contact with water, lava should harden
+ if (HardenBlock(a_Chunk, a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta))
+ {
+ // Block was changed, bail out
+ return;
+ }
+
if (MyMeta != 0)
{
// Source blocks aren't checked for tributaries, others are.
@@ -86,7 +95,12 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
{
// Spread only down, possibly washing away what's there or turning lava to stone / cobble / obsidian:
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY - 1, a_RelZ, 8);
- SpreadFurther = false;
+
+ // Source blocks spread both downwards and sideways
+ if (MyMeta != 0)
+ {
+ SpreadFurther = false;
+ }
}
// If source creation is on, check for it here:
else if (
@@ -105,10 +119,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
if (SpreadFurther && (NewMeta < 8))
{
// Spread to the neighbors:
- SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, NewMeta);
- SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, NewMeta);
- SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, NewMeta);
- SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, NewMeta);
+ Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
}
// Mark as processed:
@@ -119,6 +130,17 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
+void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
+{
+ SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
+ SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
+}
+
+
+
+
bool cFloodyFluidSimulator::CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta)
{
// If we have a section above, check if there's fluid above this block that would feed it:
@@ -296,6 +318,8 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
a_NewMeta
);
a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
+
+ HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
}
@@ -348,3 +372,56 @@ bool cFloodyFluidSimulator::CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX
+
+bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
+{
+ // Only lava blocks can harden
+ if (!IsBlockLava(a_BlockType))
+ {
+ return false;
+ }
+
+ bool ShouldHarden = false;
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ static const Vector3i Coords[] =
+ {
+ Vector3i( 1, 0, 0),
+ Vector3i(-1, 0, 0),
+ Vector3i( 0, 0, 1),
+ Vector3i( 0, 0, -1),
+ };
+ for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
+ {
+ if (!a_Chunk->UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta))
+ {
+ continue;
+ }
+ if (IsBlockWater(BlockType))
+ {
+ ShouldHarden = true;
+ }
+ } // for i - Coords[]
+
+ if (ShouldHarden)
+ {
+ if (a_Meta == 0)
+ {
+ // Source lava block
+ a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0);
+ return true;
+ }
+ // Ignore last lava level
+ else if (a_Meta <= 4)
+ {
+ a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+
diff --git a/src/Simulator/FloodyFluidSimulator.h b/src/Simulator/FloodyFluidSimulator.h
index c4af2e246..632de3bb2 100644
--- a/src/Simulator/FloodyFluidSimulator.h
+++ b/src/Simulator/FloodyFluidSimulator.h
@@ -38,14 +38,26 @@ protected:
// cDelayedFluidSimulator overrides:
virtual void SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override;
- /// Checks tributaries, if not fed, decreases the block's level and returns true
+ /** Checks tributaries, if not fed, decreases the block's level and returns true. */
bool CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta);
- /// Spreads into the specified block, if the blocktype there allows. a_Area is for checking.
+ /** Spreads into the specified block, if the blocktype there allows. a_Area is for checking. */
void SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
- /// Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so
+ /** Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so. */
bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
+
+ /** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block.
+ *
+ * Returns whether the block was changed or not.
+ */
+ bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta);
+
+ /** Spread water to neighbors.
+ *
+ * May be overridden to provide more sophisticated algorithms.
+ */
+ virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
} ;
diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp
index c9305b8ff..c2b0dac0a 100644
--- a/src/Simulator/IncrementalRedstoneSimulator.cpp
+++ b/src/Simulator/IncrementalRedstoneSimulator.cpp
@@ -937,17 +937,15 @@ void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, i
{
if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x4);
- m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
+ m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, true);
SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
- }
+ }
}
else
{
if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
{
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0xB); // Take into account that the fourth bit is needed for trapdoors too
- m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
+ m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, false);
SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
}
}
diff --git a/src/Simulator/VanillaFluidSimulator.cpp b/src/Simulator/VanillaFluidSimulator.cpp
new file mode 100644
index 000000000..78aff9d68
--- /dev/null
+++ b/src/Simulator/VanillaFluidSimulator.cpp
@@ -0,0 +1,150 @@
+
+// VanillaFluidSimulator.cpp
+
+#include "Globals.h"
+
+#include "VanillaFluidSimulator.h"
+#include "../World.h"
+#include "../Chunk.h"
+#include "../BlockArea.h"
+#include "../Blocks/BlockHandler.h"
+#include "../BlockInServerPluginInterface.h"
+
+
+
+
+
+static const int InfiniteCost = 100;
+
+
+
+
+
+cVanillaFluidSimulator::cVanillaFluidSimulator(
+ cWorld & a_World,
+ BLOCKTYPE a_Fluid,
+ BLOCKTYPE a_StationaryFluid,
+ NIBBLETYPE a_Falloff,
+ int a_TickDelay,
+ int a_NumNeighborsForSource
+) : super(a_World, a_Fluid, a_StationaryFluid, a_Falloff, a_TickDelay, a_NumNeighborsForSource)
+{
+}
+
+
+
+
+
+void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
+{
+ int Cost[4];
+ Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS);
+ Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS);
+ Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS);
+ Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS);
+
+ int MinCost = InfiniteCost;
+ for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
+ {
+ if (Cost[i] < MinCost)
+ {
+ MinCost = Cost[i];
+ }
+ }
+
+ if (Cost[0] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
+ }
+ if (Cost[1] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
+ }
+ if (Cost[2] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
+ }
+ if (Cost[3] == MinCost)
+ {
+ SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
+ }
+}
+
+
+
+
+
+int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration)
+{
+ int Cost = InfiniteCost;
+
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+
+ // Check if block is passable
+ if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta))
+ {
+ return Cost;
+ }
+ if (!IsPassableForFluid(BlockType) && !IsBlockLiquid(BlockType))
+ {
+ return Cost;
+ }
+
+ // Check if block below is passable
+ if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta))
+ {
+ return Cost;
+ }
+ if (IsPassableForFluid(BlockType) || IsBlockLiquid(BlockType))
+ {
+ // Path found, exit
+ return a_Iteration;
+ }
+
+ // 5 blocks away, bail out
+ if (a_Iteration > 3)
+ {
+ return Cost;
+ }
+
+ // Recurse
+ if (a_Dir != X_MINUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+ if (a_Dir != X_PLUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+ if (a_Dir != Z_MINUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+ if (a_Dir != Z_PLUS)
+ {
+ int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS, a_Iteration + 1);
+ if (NextCost < Cost)
+ {
+ Cost = NextCost;
+ }
+ }
+
+ return Cost;
+}
+
+
+
+
diff --git a/src/Simulator/VanillaFluidSimulator.h b/src/Simulator/VanillaFluidSimulator.h
new file mode 100644
index 000000000..a9ea98b5a
--- /dev/null
+++ b/src/Simulator/VanillaFluidSimulator.h
@@ -0,0 +1,42 @@
+
+// VanillaFluidSimulator.h
+
+
+
+
+
+#pragma once
+
+#include "FloodyFluidSimulator.h"
+
+
+
+
+
+// fwd:
+class cBlockArea;
+
+
+
+
+
+class cVanillaFluidSimulator :
+ public cFloodyFluidSimulator
+{
+ typedef cFloodyFluidSimulator super;
+
+public:
+ cVanillaFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay, int a_NumNeighborsForSource);
+
+protected:
+ // cFloodyFluidSimulator overrides:
+ virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override;
+
+ /** Recursively calculates the minimum number of blocks needed to descend a level. */
+ int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0);
+
+} ;
+
+
+
+
diff --git a/src/World.cpp b/src/World.cpp
index 89d0cf454..50908ec16 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -34,6 +34,7 @@
#include "Simulator/NoopRedstoneSimulator.h"
#include "Simulator/SandSimulator.h"
#include "Simulator/IncrementalRedstoneSimulator.h"
+#include "Simulator/VanillaFluidSimulator.h"
#include "Simulator/VaporizeFluidSimulator.h"
// Mobs:
@@ -262,8 +263,6 @@ cWorld::cWorld(const AString & a_WorldName) :
// Load the scoreboard
cScoreboardSerializer Serializer(m_WorldName, &m_Scoreboard);
Serializer.Load();
-
- m_MapManager.LoadMapData();
}
@@ -305,25 +304,52 @@ void cWorld::CastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ)
+int cWorld::GetDefaultWeatherInterval(eWeather a_Weather)
+{
+ switch (a_Weather)
+ {
+ case eWeather_Sunny:
+ {
+ return 14400 + (m_TickRand.randInt() % 4800); // 12 - 16 minutes
+ }
+ case eWeather_Rain:
+ {
+ return 9600 + (m_TickRand.randInt() % 7200); // 8 - 14 minutes
+ }
+ case eWeather_ThunderStorm:
+ {
+ return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes
+ }
+ default:
+ {
+ LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather);
+ return -1;
+ }
+ } // switch (Weather)
+}
+
+
+
+
+
void cWorld::SetWeather(eWeather a_NewWeather)
{
// Do the plugins agree? Do they want a different weather?
- cRoot::Get()->GetPluginManager()->CallHookWeatherChanging(*this, a_NewWeather);
+ if (cRoot::Get()->GetPluginManager()->CallHookWeatherChanging(*this, a_NewWeather))
+ {
+ m_WeatherInterval = GetDefaultWeatherInterval(m_Weather);
+ return;
+ }
// Set new period for the selected weather:
- switch (a_NewWeather)
+ m_WeatherInterval = GetDefaultWeatherInterval(a_NewWeather);
+
+ // The weather can't be found:
+ if (m_WeatherInterval < 0)
{
- case eWeather_Sunny: m_WeatherInterval = 14400 + (m_TickRand.randInt() % 4800); break; // 12 - 16 minutes
- case eWeather_Rain: m_WeatherInterval = 9600 + (m_TickRand.randInt() % 7200); break; // 8 - 14 minutes
- case eWeather_ThunderStorm: m_WeatherInterval = 2400 + (m_TickRand.randInt() % 4800); break; // 2 - 6 minutes
- default:
- {
- LOGWARNING("Requested unknown weather %d, setting sunny for a minute instead.", a_NewWeather);
- a_NewWeather = eWeather_Sunny;
- m_WeatherInterval = 1200;
- break;
- }
- } // switch (NewWeather)
+ return;
+ }
+
m_Weather = a_NewWeather;
BroadcastWeather(m_Weather);
@@ -624,13 +650,13 @@ void cWorld::Start(void)
m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfAmbient, 0));
m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfWater, 0));
+ m_MapManager.LoadMapData();
// Save any changes that the defaults may have done to the ini file:
if (!IniFile.WriteFile(m_IniFileName))
{
LOGWARNING("Could not write world config to %s", m_IniFileName.c_str());
}
-
}
@@ -1171,9 +1197,18 @@ bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCom
-bool cWorld::DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback)
+bool cWorld::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
+{
+ return m_ChunkMap->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+}
+
+
+
+
+
+bool cWorld::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{
- return m_ChunkMap->DoWithMobHeadBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
+ return m_ChunkMap->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
@@ -1726,7 +1761,7 @@ bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
bool cWorld::DigBlock(int a_X, int a_Y, int a_Z)
{
- cBlockHandler *Handler = cBlockHandler::GetBlockHandler(GetBlock(a_X, a_Y, a_Z));
+ cBlockHandler * Handler = cBlockInfo::GetHandler(GetBlock(a_X, a_Y, a_Z));
cChunkInterface ChunkInterface(GetChunkMap());
Handler->OnDestroyed(ChunkInterface, *this, a_X, a_Y, a_Z);
return m_ChunkMap->DigBlock(a_X, a_Y, a_Z);
@@ -2650,6 +2685,47 @@ bool cWorld::SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, co
+bool cWorld::IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta);
+ if (Block != E_BLOCK_TRAPDOOR)
+ {
+ return false;
+ }
+
+ return (Meta & 0x4) > 0;
+}
+
+
+
+
+
+bool cWorld::SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open)
+{
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, Block, Meta);
+ if (Block != E_BLOCK_TRAPDOOR)
+ {
+ return false;
+ }
+
+ bool IsOpen = (Meta & 0x4) > 0;
+ if (a_Open != IsOpen)
+ {
+ SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta ^ 0x4);
+ BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
{
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
@@ -2990,8 +3066,8 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "");
if (SimulatorName.empty())
{
- LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Floody\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
- SimulatorName = "Floody";
+ LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Vanilla\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
+ SimulatorName = "Vanilla";
}
cFluidSimulator * res = NULL;
@@ -3015,15 +3091,24 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
}
else
{
- if (NoCaseCompare(SimulatorName, "floody") != 0)
- {
- // The simulator name doesn't match anything we have, issue a warning:
- LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Floody\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
- }
int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", IsWater ? 1 : 2);
int TickDelay = a_IniFile.GetValueSetI(SimulatorSectionName, "TickDelay", IsWater ? 5 : 30);
int NumNeighborsForSource = a_IniFile.GetValueSetI(SimulatorSectionName, "NumNeighborsForSource", IsWater ? 2 : -1);
- res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+
+ if (NoCaseCompare(SimulatorName, "floody") == 0)
+ {
+ res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+ }
+ else if (NoCaseCompare(SimulatorName, "vanilla") == 0)
+ {
+ res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+ }
+ else
+ {
+ // The simulator name doesn't match anything we have, issue a warning:
+ LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Vanilla\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
+ res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
+ }
}
m_SimulatorManager->RegisterSimulator(res, Rate);
diff --git a/src/World.h b/src/World.h
index d7d5b5059..7c89bd292 100644
--- a/src/World.h
+++ b/src/World.h
@@ -44,6 +44,7 @@ class cWorldGenerator; // The generator that actually generates the chunks for
class cChunkGenerator; // The thread responsible for generating chunks
class cChestEntity;
class cDispenserEntity;
+class cFlowerPotEntity;
class cFurnaceEntity;
class cNoteEntity;
class cMobHeadEntity;
@@ -60,7 +61,8 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
-typedef cItemCallback<cMobHeadEntity> cMobHeadBlockCallback;
+typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
+typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
@@ -139,6 +141,10 @@ public:
BroadcastTimeUpdate();
}
+ /** Returns the default weather interval for the specific weather type.
+ Returns -1 for any unknown weather. */
+ int GetDefaultWeatherInterval(eWeather a_Weather);
+
/** Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable */
eGameMode GetGameMode(void) const { return m_GameMode; }
@@ -342,6 +348,12 @@ public:
/** Sets the command block command. Returns true if command changed. */
bool SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command); // tolua_export
+ /** Is the trapdoor open? Returns false if there is no trapdoor at the specified coords. */
+ bool IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ /** Set the state of a trapdoor. Returns true if the trapdoor was update, false if there was no trapdoor at those coords. */
+ bool SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open); // tolua_export
+
/** Regenerate the given chunk: */
void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
@@ -445,7 +457,7 @@ public:
// tolua_begin
bool DigBlock (int a_X, int a_Y, int a_Z);
- void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
+ virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player);
double GetSpawnX(void) const { return m_SpawnX; }
double GetSpawnY(void) const { return m_SpawnY; }
@@ -521,10 +533,13 @@ public:
/** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp
-
+
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
- bool DoWithMobHeadBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadBlockCallback & a_Callback); // Exported in ManualBindings.cpp
-
+ bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
+ bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Exported in ManualBindings.cpp
+
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index c1c659b36..6d0e29958 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -20,6 +20,7 @@
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../Entities/Entity.h"
#include "../Entities/FallingBlock.h"
@@ -275,6 +276,19 @@ void cNBTChunkSerializer::AddMobHeadEntity(cMobHeadEntity * a_MobHead)
+void cNBTChunkSerializer::AddFlowerPotEntity(cFlowerPotEntity * a_FlowerPot)
+{
+ m_Writer.BeginCompound("");
+ AddBasicTileEntity(a_FlowerPot, "FlowerPot");
+ m_Writer.AddInt ("Item", (Int32) a_FlowerPot->GetItem().m_ItemType);
+ m_Writer.AddInt ("Data", (Int32) a_FlowerPot->GetItem().m_ItemDamage);
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_ClassName)
{
m_Writer.AddString("id", a_ClassName);
@@ -687,6 +701,7 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
+ case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST:
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index 5f9e16ed1..8a9e18413 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -30,6 +30,7 @@ class cJukeboxEntity;
class cNoteEntity;
class cSignEntity;
class cMobHeadEntity;
+class cFlowerPotEntity;
class cFallingBlock;
class cMinecart;
class cMinecartWithChest;
@@ -96,6 +97,7 @@ protected:
void AddSignEntity (cSignEntity * a_Sign);
void AddMobHeadEntity (cMobHeadEntity * a_MobHead);
void AddCommandBlockEntity(cCommandBlockEntity * a_CmdBlock);
+ void AddFlowerPotEntity(cFlowerPotEntity * a_FlowerPot);
// Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index 45fd967bd..b021aeb0c 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -1,10 +1,18 @@
+// SchematicFileSerializer.cpp
+
+// Implements the cSchematicFileSerializer class representing the interface to load and save cBlockArea to a .schematic file
+
#include "Globals.h"
#include "OSSupport/GZipFile.h"
#include "FastNBT.h"
-
#include "SchematicFileSerializer.h"
+#include "../StringCompression.h"
+
+
+
+
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
{
@@ -40,48 +48,51 @@ bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, c
-bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
+bool cSchematicFileSerializer::LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData)
{
- cFastNBTWriter Writer("Schematic");
- Writer.AddShort("Width", a_BlockArea.m_SizeX);
- Writer.AddShort("Height", a_BlockArea.m_SizeY);
- Writer.AddShort("Length", a_BlockArea.m_SizeZ);
- Writer.AddString("Materials", "Alpha");
- if (a_BlockArea.HasBlockTypes())
+ // Uncompress the data:
+ AString UngzippedData;
+ if (UncompressStringGZIP(a_SchematicData.data(), a_SchematicData.size(), UngzippedData) != Z_OK)
{
- Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
- }
- else
- {
- AString Dummy(a_BlockArea.GetBlockCount(), 0);
- Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
+ LOG("%s: Cannot unGZip the schematic data.", __FUNCTION__);
+ return false;
}
- if (a_BlockArea.HasBlockMetas())
+
+ // Parse the NBT:
+ cParsedNBT NBT(UngzippedData.data(), UngzippedData.size());
+ if (!NBT.IsValid())
{
- Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
+ LOG("%s: Cannot parse the NBT in the schematic data.", __FUNCTION__);
+ return false;
}
- else
+
+ return LoadFromSchematicNBT(a_BlockArea, NBT);
+}
+
+
+
+
+
+bool cSchematicFileSerializer::SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName)
+{
+ // Serialize into NBT data:
+ AString NBT = SaveToSchematicNBT(a_BlockArea);
+ if (NBT.empty())
{
- AString Dummy(a_BlockArea.GetBlockCount(), 0);
- Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
+ LOG("%s: Cannot serialize the area into an NBT representation for file \"%s\".", __FUNCTION__, a_FileName.c_str());
+ return false;
}
- // TODO: Save entities and block entities
- Writer.BeginList("Entities", TAG_Compound);
- Writer.EndList();
- Writer.BeginList("TileEntities", TAG_Compound);
- Writer.EndList();
- Writer.Finish();
// Save to file
cGZipFile File;
if (!File.Open(a_FileName, cGZipFile::fmWrite))
{
- LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str());
+ LOG("%s: Cannot open file \"%s\" for writing.", __FUNCTION__, a_FileName.c_str());
return false;
}
- if (!File.Write(Writer.GetResult()))
+ if (!File.Write(NBT))
{
- LOG("Cannot write data to file \"%s\".", a_FileName.c_str());
+ LOG("%s: Cannot write data to file \"%s\".", __FUNCTION__, a_FileName.c_str());
return false;
}
return true;
@@ -92,6 +103,30 @@ bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, con
+bool cSchematicFileSerializer::SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out)
+{
+ // Serialize into NBT data:
+ AString NBT = SaveToSchematicNBT(a_BlockArea);
+ if (NBT.empty())
+ {
+ LOG("%s: Cannot serialize the area into an NBT representation.", __FUNCTION__);
+ return false;
+ }
+
+ // Gzip the data:
+ int res = CompressStringGZIP(NBT.data(), NBT.size(), a_Out);
+ if (res != Z_OK)
+ {
+ LOG("%s: Cannot Gzip the area data NBT representation: %d", __FUNCTION__, res);
+ return false;
+ }
+ return true;
+}
+
+
+
+
+
bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT)
{
int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials");
@@ -170,3 +205,45 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
+
+
+
+AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea)
+{
+ cFastNBTWriter Writer("Schematic");
+ Writer.AddShort("Width", a_BlockArea.m_SizeX);
+ Writer.AddShort("Height", a_BlockArea.m_SizeY);
+ Writer.AddShort("Length", a_BlockArea.m_SizeZ);
+ Writer.AddString("Materials", "Alpha");
+ if (a_BlockArea.HasBlockTypes())
+ {
+ Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
+ }
+ else
+ {
+ AString Dummy(a_BlockArea.GetBlockCount(), 0);
+ Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
+ }
+ if (a_BlockArea.HasBlockMetas())
+ {
+ Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
+ }
+ else
+ {
+ AString Dummy(a_BlockArea.GetBlockCount(), 0);
+ Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
+ }
+
+ // TODO: Save entities and block entities
+ Writer.BeginList("Entities", TAG_Compound);
+ Writer.EndList();
+ Writer.BeginList("TileEntities", TAG_Compound);
+ Writer.EndList();
+ Writer.Finish();
+
+ return Writer.GetResult();
+}
+
+
+
+
diff --git a/src/WorldStorage/SchematicFileSerializer.h b/src/WorldStorage/SchematicFileSerializer.h
index 9be2e5b57..05b6c74f4 100644
--- a/src/WorldStorage/SchematicFileSerializer.h
+++ b/src/WorldStorage/SchematicFileSerializer.h
@@ -1,4 +1,12 @@
+// SchematicFileSerializer.h
+
+// Declares the cSchematicFileSerializer class representing the interface to load and save cBlockArea to a .schematic file
+
+
+
+
+
#pragma once
#include "../BlockArea.h"
@@ -13,17 +21,34 @@ class cParsedNBT;
+
class cSchematicFileSerializer
{
public:
- /// Loads an area from a .schematic file. Returns true if successful
+ /** Loads an area from a .schematic file. Returns true if successful. */
static bool LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
- /// Saves the area into a .schematic file. Returns true if successful
- static bool SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
+ /** Loads an area from a string containing the .schematic file data. Returns true if successful. */
+ static bool LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData);
+
+ /** Saves the area into a .schematic file. Returns true if successful. */
+ static bool SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName);
+
+ /** Saves the area into a string containing the .schematic file data.
+ Returns true if successful, false on failure. The data is stored into a_Out. */
+ static bool SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out);
private:
- /// Loads the area from a schematic file uncompressed and parsed into a NBT tree. Returns true if successful.
+ /** Loads the area from a schematic file uncompressed and parsed into a NBT tree.
+ Returns true if successful. */
static bool LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT);
+
+ /** Saves the area into a NBT representation and returns the NBT data as a string.
+ Returns an empty string if failed. */
+ static AString SaveToSchematicNBT(const cBlockArea & a_BlockArea);
};
+
+
+
+
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 05332d23d..680f2458f 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -25,6 +25,7 @@
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../Mobs/Monster.h"
@@ -578,6 +579,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{
LoadDropperFromNBT(a_BlockEntities, a_NBT, Child);
}
+ else if (strncmp(a_NBT.GetData(sID), "FlowerPot", a_NBT.GetDataLength(sID)) == 0)
+ {
+ LoadFlowerPotFromNBT(a_BlockEntities, a_NBT, Child);
+ }
else if (strncmp(a_NBT.GetData(sID), "Furnace", a_NBT.GetDataLength(sID)) == 0)
{
LoadFurnaceFromNBT(a_BlockEntities, a_NBT, Child, a_BlockTypes, a_BlockMetas);
@@ -760,6 +765,37 @@ void cWSSAnvil::LoadDropperFromNBT(cBlockEntityList & a_BlockEntities, const cPa
+void cWSSAnvil::LoadFlowerPotFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
+ int x, y, z;
+ if (!GetBlockEntityNBTPos(a_NBT, a_TagIdx, x, y, z))
+ {
+ return;
+ }
+ std::auto_ptr<cFlowerPotEntity> FlowerPot(new cFlowerPotEntity(x, y, z, m_World));
+ short ItemType = 0, ItemData = 0;
+
+ int currentLine = a_NBT.FindChildByName(a_TagIdx, "Item");
+ if (currentLine >= 0)
+ {
+ ItemType = (short) a_NBT.GetInt(currentLine);
+ }
+
+ currentLine = a_NBT.FindChildByName(a_TagIdx, "Data");
+ if (currentLine >= 0)
+ {
+ ItemData = (short) a_NBT.GetInt(currentLine);
+ }
+
+ FlowerPot->SetItem(cItem(ItemType, 1, ItemData));
+ a_BlockEntities.push_back(FlowerPot.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadFurnaceFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas)
{
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 4acf3f2a1..b26345b13 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -135,6 +135,7 @@ protected:
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFurnaceFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE * a_BlockTypes, NIBBLETYPE * a_BlockMetas);
void LoadHopperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadJukeboxFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index 4c0684dd8..5e49e4909 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -12,8 +12,10 @@
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
+#include "../BlockEntities/FlowerPotEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/JukeboxEntity.h"
+#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/SignEntity.h"
@@ -75,12 +77,14 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
case E_BLOCK_CHEST: SaveInto = "Chests"; break;
case E_BLOCK_DISPENSER: SaveInto = "Dispensers"; break;
case E_BLOCK_DROPPER: SaveInto = "Droppers"; break;
+ case E_BLOCK_FLOWER_POT: SaveInto = "FlowerPots"; break;
case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break;
case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break;
case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break;
case E_BLOCK_NOTE_BLOCK: SaveInto = "Notes"; break;
case E_BLOCK_JUKEBOX: SaveInto = "Jukeboxes"; break;
case E_BLOCK_COMMAND_BLOCK: SaveInto = "CommandBlocks"; break;
+ case E_BLOCK_HEAD: SaveInto = "MobHeads"; break;
default:
{
@@ -298,6 +302,21 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
}
} // for itr - AllDispensers[]
+ // Load Flowerpots:
+ Json::Value AllFlowerPots = a_Value.get("FlowerPots", Json::nullValue);
+ for (Json::Value::iterator itr = AllFlowerPots.begin(); itr != AllFlowerPots.end(); ++itr)
+ {
+ std::auto_ptr<cFlowerPotEntity> FlowerPotEntity(new cFlowerPotEntity(0, 0, 0, a_World));
+ if (!FlowerPotEntity->LoadFromJson(*itr))
+ {
+ LOGWARNING("ERROR READING FLOWERPOT FROM JSON!" );
+ }
+ else
+ {
+ a_BlockEntities.push_back(FlowerPotEntity.release());
+ }
+ } // for itr - AllFlowerPots[]
+
// Load furnaces:
Json::Value AllFurnaces = a_Value.get("Furnaces", Json::nullValue);
for (Json::Value::iterator itr = AllFurnaces.begin(); itr != AllFurnaces.end(); ++itr)
@@ -331,7 +350,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
// Load note blocks:
Json::Value AllNotes = a_Value.get("Notes", Json::nullValue);
- for( Json::Value::iterator itr = AllNotes.begin(); itr != AllNotes.end(); ++itr )
+ for (Json::Value::iterator itr = AllNotes.begin(); itr != AllNotes.end(); ++itr)
{
std::auto_ptr<cNoteEntity> NoteEntity(new cNoteEntity(0, 0, 0, a_World));
if (!NoteEntity->LoadFromJson(*itr))
@@ -346,7 +365,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
// Load jukeboxes:
Json::Value AllJukeboxes = a_Value.get("Jukeboxes", Json::nullValue);
- for( Json::Value::iterator itr = AllJukeboxes.begin(); itr != AllJukeboxes.end(); ++itr )
+ for (Json::Value::iterator itr = AllJukeboxes.begin(); itr != AllJukeboxes.end(); ++itr)
{
std::auto_ptr<cJukeboxEntity> JukeboxEntity(new cJukeboxEntity(0, 0, 0, a_World));
if (!JukeboxEntity->LoadFromJson(*itr))
@@ -361,7 +380,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
// Load command blocks:
Json::Value AllCommandBlocks = a_Value.get("CommandBlocks", Json::nullValue);
- for( Json::Value::iterator itr = AllCommandBlocks.begin(); itr != AllCommandBlocks.end(); ++itr )
+ for (Json::Value::iterator itr = AllCommandBlocks.begin(); itr != AllCommandBlocks.end(); ++itr)
{
std::auto_ptr<cCommandBlockEntity> CommandBlockEntity(new cCommandBlockEntity(0, 0, 0, a_World));
if (!CommandBlockEntity->LoadFromJson(*itr))
@@ -373,6 +392,21 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
a_BlockEntities.push_back(CommandBlockEntity.release());
}
} // for itr - AllCommandBlocks[]
+
+ // Load mob heads:
+ Json::Value AllMobHeads = a_Value.get("MobHeads", Json::nullValue);
+ for (Json::Value::iterator itr = AllMobHeads.begin(); itr != AllMobHeads.end(); ++itr)
+ {
+ std::auto_ptr<cMobHeadEntity> MobHeadEntity(new cMobHeadEntity(0, 0, 0, a_World));
+ if (!MobHeadEntity->LoadFromJson(*itr))
+ {
+ LOGWARNING("ERROR READING MOB HEAD FROM JSON!" );
+ }
+ else
+ {
+ a_BlockEntities.push_back(MobHeadEntity.release());
+ }
+ } // for itr - AllMobHeads[]
}