summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android/jni/Android.mk24
-rw-r--r--MCServer/.gitignore1
-rw-r--r--MCServer/Plugins/APIDump/APIDesc.lua9
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua40
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua24
-rw-r--r--MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua25
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua4
-rw-r--r--MCServer/Plugins/InfoReg.lua51
-rw-r--r--src/Bindings/LuaState.cpp12
-rw-r--r--src/Bindings/LuaState.h2
-rw-r--r--src/Bindings/Plugin.h3
-rw-r--r--src/Bindings/PluginLua.cpp61
-rw-r--r--src/Bindings/PluginLua.h3
-rw-r--r--src/Bindings/PluginManager.cpp63
-rw-r--r--src/Bindings/PluginManager.h11
-rw-r--r--src/Bindings/lua51.dll (renamed from src/Bindings/lua5.1.dll)bin167424 -> 167424 bytes
-rw-r--r--src/BlockArea.cpp333
-rw-r--r--src/BlockArea.h46
-rw-r--r--src/BlockID.h13
-rw-r--r--src/Blocks/BlockDirt.h5
-rw-r--r--src/Blocks/BlockMobHead.h14
-rw-r--r--src/Blocks/BlockMushroom.h3
-rw-r--r--src/Blocks/BlockMycelium.h2
-rw-r--r--src/Blocks/BlockSideways.h8
-rw-r--r--src/Blocks/BlockVine.h5
-rw-r--r--src/Blocks/BroadcastInterface.h3
-rw-r--r--src/Blocks/WorldInterface.h3
-rw-r--r--src/Chunk.cpp11
-rw-r--r--src/ClientHandle.cpp6
-rw-r--r--src/DeadlockDetect.cpp5
-rw-r--r--src/Entities/EnderCrystal.cpp56
-rw-r--r--src/Entities/EnderCrystal.h33
-rw-r--r--src/Entities/Entity.h24
-rw-r--r--src/Entities/Player.cpp1
-rw-r--r--src/Entities/ProjectileEntity.cpp12
-rw-r--r--src/ForEachChunkProvider.h2
-rw-r--r--src/Generating/ChunkDesc.cpp6
-rw-r--r--src/Generating/Prefab.cpp312
-rw-r--r--src/Generating/Prefab.h105
-rw-r--r--src/Globals.h10
-rw-r--r--src/HTTPServer/HTTPServer.h4
-rw-r--r--src/Inventory.h2
-rw-r--r--src/ItemGrid.h46
-rw-r--r--src/Mobs/Monster.cpp1
-rw-r--r--src/Mobs/Villager.h2
-rw-r--r--src/Mobs/Wither.cpp52
-rw-r--r--src/Mobs/Wither.h13
-rw-r--r--src/OSSupport/ListenThread.h20
-rw-r--r--src/RCONServer.h2
-rw-r--r--src/Root.cpp1
-rw-r--r--src/Simulator/FireSimulator.cpp14
-rw-r--r--src/UI/WindowOwner.h4
-rw-r--r--src/Vector3.h7
-rw-r--r--src/World.cpp3
-rw-r--r--src/World.h20
-rw-r--r--src/WorldStorage/MapSerializer.cpp6
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp21
-rw-r--r--src/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp10
-rw-r--r--src/WorldStorage/WSSAnvil.cpp27
-rw-r--r--src/WorldStorage/WSSAnvil.h1
61 files changed, 1301 insertions, 308 deletions
diff --git a/Android/jni/Android.mk b/Android/jni/Android.mk
index 3542e588b..ce142d446 100644
--- a/Android/jni/Android.mk
+++ b/Android/jni/Android.mk
@@ -5,7 +5,7 @@ LOCAL_MODULE := mcserver
-LOCAL_SRC_FILES := $(shell find ../CryptoPP ../lua ../jsoncpp ../zlib ../src ../tolua++ ../iniFile ../expat ../md5 ../sqlite ../luaexpat '(' -name '*.cpp' -o -name '*.c' ')')
+LOCAL_SRC_FILES := $(shell find ../lib/polarssl ../lib/lua ../lib/jsoncpp ../lib/zlib ../src ../lib/tolua++ ../lib/iniFile ../lib/expat ../lib/md5 ../lib/sqlite ../lib/luaexpat '(' -name '*.cpp' -o -name '*.c' ')')
LOCAL_SRC_FILES := $(filter-out %SquirrelFunctions.cpp %SquirrelBindings.cpp %cPlugin_Squirrel.cpp %cSquirrelCommandBinder.cpp %minigzip.c %lua.c %tolua.c %toluabind.c %LeakFinder.cpp %StackWalker.cpp %example.c,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(patsubst %.cpp,../%.cpp,$(LOCAL_SRC_FILES))
LOCAL_SRC_FILES := $(patsubst %.c,../%.c,$(LOCAL_SRC_FILES))
@@ -24,17 +24,17 @@ LOCAL_C_INCLUDES := ../src \
../src/packets \
../src/items \
../src/blocks \
- ../tolua++/src/lib \
- ../lua/src \
- ../zlib-1.2.7 \
- ../iniFile \
- ../tolua++/include \
- ../jsoncpp/include \
- ../jsoncpp/src/lib_json \
- ../expat/ \
- ../md5/ \
- ../sqlite/ \
- ../luaexpat/ \
+ ../lib/tolua++/src/lib \
+ ../lib/lua/src \
+ ../lib/zlib-1.2.7 \
+ ../lib/iniFile \
+ ../lib/tolua++/include \
+ ../lib/jsoncpp/include \
+ ../lib/jsoncpp/src/lib_json \
+ ../lib/expat/ \
+ ../lib/md5/ \
+ ../lib/sqlite/ \
+ ../lib/luaexpat/ \
.. \
diff --git a/MCServer/.gitignore b/MCServer/.gitignore
index 64f062ef7..69826ef06 100644
--- a/MCServer/.gitignore
+++ b/MCServer/.gitignore
@@ -6,6 +6,7 @@
MCServer
MCServer_debug
CommLogs/
+GalExports/
logs
players
world*
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua
index 74e7bf860..01f000182 100644
--- a/MCServer/Plugins/APIDump/APIDesc.lua
+++ b/MCServer/Plugins/APIDump/APIDesc.lua
@@ -1826,6 +1826,7 @@ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChatMessage);
},
Constants =
{
+ HOOK_BLOCK_SPREAD = { Notes = "Called when a block spreads based on world conditions" },
HOOK_BLOCK_TO_PICKUPS = { Notes = "Called when a block has been dug and is being converted to pickups. The server has provided the default pickups and the plugins may modify them." },
HOOK_CHAT = { Notes = "Called when a client sends a chat message that is not a command. The plugin may modify the chat message" },
HOOK_CHUNK_AVAILABLE = { Notes = "Called when a chunk is loaded or generated and becomes available in the {{cWorld|world}}." },
@@ -2767,6 +2768,14 @@ end
data provided with the explosions, such as the exploding {{cCreeper|creeper}} entity or the
{{Vector3i|coords}} of the exploding bed.
]],
+ },
+ SpreadSource =
+ {
+ Include = "^ss.*",
+ TextBefore = [[
+ These constants are used to differentiate the various sources of spreads, such as grass growing.
+ They are used in the {{OnBlockSpread|HOOK_BLOCK_SPREAD}} hook.
+ ]],
}
},
}, -- Globals
diff --git a/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua b/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua
new file mode 100644
index 000000000..ed0b5f46f
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnBlockSpread.lua
@@ -0,0 +1,40 @@
+return
+{
+ HOOK_BLOCK_SPREAD =
+ {
+ CalledWhen = "Called when a block spreads based on world conditions",
+ DefaultFnName = "OnBlockSpread", -- also used as pagename
+ Desc = [[
+ This hook is called when a block spreads.</p>
+ <p>
+ The spread carries with it the type of its source - whether it's a block spreads.
+ It also carries the identification of the actual source. The exact type of the identification
+ depends on the source kind:
+ <table>
+ <tr><th>Source</th><th>Notes</th></tr>
+ <tr><td>ssFireSpread</td><td>Fire spreading</td></tr>
+ <tr><td>ssGrassSpread</td><td>Grass spreading</td></tr>
+ <tr><td>ssMushroomSpread</td><td>Mushroom spreading</td></tr>
+ <tr><td>ssMycelSpread</td><td>Mycel spreading</td></tr>
+ <tr><td>ssVineSpread</td><td>Vine spreading</td></tr>
+ </table></p>
+ ]],
+ Params =
+ {
+ { Name = "World", Type = "{{cWorld}}", Notes = "The world in which the block resides" },
+ { Name = "BlockX", Type = "number", Notes = "X-coord of the block" },
+ { Name = "BlockY", Type = "number", Notes = "Y-coord of the block" },
+ { Name = "BlockZ", Type = "number", Notes = "Z-coord of the block" },
+ { Name = "Source", Type = "eSpreadSource", Notes = "Source of the spread. See the table above." },
+ },
+ Returns = [[
+ If the function returns false or no value, the next plugin's callback is called, and finally
+ MCServer will process the spread. If the function
+ returns true, no other callback is called for this event and the spread will not occur.
+ ]],
+ }, -- HOOK_BLOCK_SPREAD
+}
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua
new file mode 100644
index 000000000..1588d420c
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitBlock.lua
@@ -0,0 +1,24 @@
+return
+{
+ HOOK_PROJECTILE_HIT_BLOCK =
+ {
+ CalledWhen = "A projectile hits a solid block.",
+ DefaultFnName = "OnProjectileHitBlock", -- also used as pagename
+ Desc = [[
+ This hook is called when a {{cProjectileEntity|projectile}} hits a solid block..
+ ]],
+ Params =
+ {
+ { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
+ },
+ Returns = [[
+ If the function returns false or no value, the next plugin's callback is called. If the function
+ returns true, no other callback is called for this event and the projectile flies through block..
+ ]],
+ }, -- HOOK_PROJECTILE_HIT_BLOCK
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua
new file mode 100644
index 000000000..dd949fb46
--- /dev/null
+++ b/MCServer/Plugins/APIDump/Hooks/OnProjectileHitEntity.lua
@@ -0,0 +1,25 @@
+return
+{
+ HOOK_PROJECTILE_HIT_ENTITY =
+ {
+ CalledWhen = "A projectile hits another entity.",
+ DefaultFnName = "OnProjectileHitEntity", -- also used as pagename
+ Desc = [[
+ This hook is called when a {{cProjectileEntity|projectile}} hits another entity.
+ ]],
+ Params =
+ {
+ { Name = "ProjectileEntity", Type = "{{cProjectileEntity}}", Notes = "The projectile that hit an entity." },
+ { Name = "Entity", Type = "{{cEntity}}", Notes = "The entity wich was hit." },
+ },
+ Returns = [[
+ If the function returns false or no value, the next plugin's callback is called. If the function
+ returns true, no other callback is called for this event and the projectile flies through the entity.
+ ]],
+ }, -- HOOK_PROJECTILE_HIT_ENTITY
+}
+
+
+
+
+
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index fe3efa306..2cb014875 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -27,11 +27,13 @@ function Initialize(Plugin)
PM:AddHook(cPluginManager.HOOK_CHAT, OnChat);
PM:AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
PM:AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
- 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)
+ -- _X: Disabled so that the normal operation doesn't interfere with anything
+ -- PM:AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
+
PM:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PM:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
PM:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool");
diff --git a/MCServer/Plugins/InfoReg.lua b/MCServer/Plugins/InfoReg.lua
index b3717884a..27e63aa5b 100644
--- a/MCServer/Plugins/InfoReg.lua
+++ b/MCServer/Plugins/InfoReg.lua
@@ -9,16 +9,30 @@
--- Lists all the subcommands that the player has permissions for
local function ListSubcommands(a_Player, a_Subcommands, a_CmdString)
- a_Player:SendMessage("The " .. a_CmdString .. " command requires another verb:");
+ if (a_Player == nil) then
+ LOGINFO("The " .. a_CmdString .. " command requires another verb:")
+ else
+ a_Player:SendMessage("The " .. a_CmdString .. " command requires another verb:")
+ end
+
+ -- Enum all the subcommands:
local Verbs = {};
for cmd, info in pairs(a_Subcommands) do
if (a_Player:HasPermission(info.Permission or "")) then
- table.insert(Verbs, a_CmdString .. " " .. cmd);
+ table.insert(Verbs, " " .. a_CmdString .. " " .. cmd);
end
end
table.sort(Verbs);
- for idx, verb in ipairs(Verbs) do
- a_Player:SendMessage(verb);
+
+ -- Send the list:
+ if (a_Player == nil) then
+ for idx, verb in ipairs(Verbs) do
+ LOGINFO(verb);
+ end
+ else
+ for idx, verb in ipairs(Verbs) do
+ a_Player:SendMessage(verb);
+ end
end
end
@@ -28,6 +42,7 @@ end
--- This is a generic command callback used for handling multicommands' parent commands
-- For example, if there are "/gal save" and "/gal load" commands, this callback handles the "/gal" command
+-- It is used for both console and in-game commands; the console version has a_Player set to nil
local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_Level)
local Verb = a_Split[a_Level + 1];
if (Verb == nil) then
@@ -46,7 +61,11 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
if (a_Level > 1) then
-- This is a true subcommand, display the message and make MCS think the command was handled
-- Otherwise we get weird behavior: for "/cmd verb" we get "unknown command /cmd" although "/cmd" is valid
- a_Player:SendMessage("The " .. a_CmdString .. " command doesn't support verb " .. Verb);
+ if (a_Player == nil) then
+ LOGWARNING("The " .. a_CmdString .. " command doesn't support verb " .. Verb)
+ else
+ a_Player:SendMessage("The " .. a_CmdString .. " command doesn't support verb " .. Verb)
+ end
return true;
end
-- This is a top-level command, let MCS handle the unknown message
@@ -54,9 +73,11 @@ local function MultiCommandHandler(a_Split, a_Player, a_CmdString, a_CmdInfo, a_
end
-- Check the permission:
- if not(a_Player:HasPermission(Subcommand.Permission or "")) then
- a_Player:SendMessage("You don't have permission to execute this command");
- return true;
+ if (a_Player ~= nil) then
+ if not(a_Player:HasPermission(Subcommand.Permission or "")) then
+ a_Player:SendMessage("You don't have permission to execute this command");
+ return true;
+ end
end
-- If the handler is not valid, check the next sublevel:
@@ -149,21 +170,27 @@ end
function RegisterPluginInfoConsoleCommands()
-- A sub-function that registers all subcommands of a single command, using the command's Subcommands table
-- The a_Prefix param already contains the space after the previous command
- local function RegisterSubcommands(a_Prefix, a_Subcommands)
+ local function RegisterSubcommands(a_Prefix, a_Subcommands, a_Level)
assert(a_Subcommands ~= nil);
for cmd, info in pairs(a_Subcommands) do
local CmdName = a_Prefix .. cmd;
- cPluginManager.BindConsoleCommand(cmd, info.Handler, info.HelpString or "");
+ local Handler = info.Handler
+ if (Handler == nil) then
+ Handler = function(a_Split)
+ return MultiCommandHandler(a_Split, nil, CmdName, info, a_Level);
+ end
+ end
+ cPluginManager.BindConsoleCommand(CmdName, Handler, info.HelpString or "");
-- Recursively register any subcommands:
if (info.Subcommands ~= nil) then
- RegisterSubcommands(a_Prefix .. cmd .. " ", info.Subcommands);
+ RegisterSubcommands(a_Prefix .. cmd .. " ", info.Subcommands, a_Level + 1);
end
end
end
-- Loop through all commands in the plugin info, register each:
- RegisterSubcommands("", g_PluginInfo.ConsoleCommands);
+ RegisterSubcommands("", g_PluginInfo.ConsoleCommands, 1);
end
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 47380b8a7..13eb17f7d 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -479,6 +479,18 @@ void cLuaState::Push(cEntity * a_Entity)
+void cLuaState::Push(cProjectileEntity * a_ProjectileEntity)
+{
+ ASSERT(IsValid());
+
+ tolua_pushusertype(m_LuaState, a_ProjectileEntity, "cProjectileEntity");
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(cMonster * a_Monster)
{
ASSERT(IsValid());
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index f0047b362..b9ca2f29b 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -38,6 +38,7 @@ extern "C"
class cWorld;
class cPlayer;
class cEntity;
+class cProjectileEntity;
class cMonster;
class cItem;
class cItems;
@@ -183,6 +184,7 @@ public:
void Push(cPlayer * a_Player);
void Push(const cPlayer * a_Player);
void Push(cEntity * a_Entity);
+ void Push(cProjectileEntity * a_ProjectileEntity);
void Push(cMonster * a_Monster);
void Push(cItem * a_Item);
void Push(cItems * a_Items);
diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h
index 949e4693a..df0bd4dcc 100644
--- a/src/Bindings/Plugin.h
+++ b/src/Bindings/Plugin.h
@@ -46,6 +46,7 @@ public:
* On all these functions, return true if you want to override default behavior and not call other plugins on that callback.
* You can also return false, so default behavior is used.
**/
+ virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) = 0;
virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0;
virtual bool OnChat (cPlayer * a_Player, AString & a_Message) = 0;
virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0;
@@ -89,6 +90,8 @@ public:
virtual bool OnPluginsLoaded (void) = 0;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
+ virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) = 0;
+ virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) = 0;
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) = 0;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) = 0;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) = 0;
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index cccbc3c93..7e69e0f4b 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -195,6 +195,26 @@ void cPluginLua::Tick(float a_Dt)
+bool cPluginLua::OnBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
+{
+ cCSLock Lock(m_CriticalSection);
+ bool res = false;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_SPREAD];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups)
{
cCSLock Lock(m_CriticalSection);
@@ -1088,6 +1108,46 @@ bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a
+bool cPluginLua::OnProjectileHitBlock(cProjectileEntity & a_Projectile)
+{
+ cCSLock Lock(m_CriticalSection);
+ bool res = false;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Projectile, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cPluginLua::OnProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
+{
+ cCSLock Lock(m_CriticalSection);
+ bool res = false;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PROJECTILE_HIT_ENTITY];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Projectile, &a_HitEntity, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
@@ -1430,6 +1490,7 @@ const char * cPluginLua::GetHookFnName(int a_HookType)
{
switch (a_HookType)
{
+ case cPluginManager::HOOK_BLOCK_SPREAD: return "OnBlockSpread";
case cPluginManager::HOOK_BLOCK_TO_PICKUPS: return "OnBlockToPickups";
case cPluginManager::HOOK_CHAT: return "OnChat";
case cPluginManager::HOOK_CHUNK_AVAILABLE: return "OnChunkAvailable";
diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h
index a177f5288..59542d23a 100644
--- a/src/Bindings/PluginLua.h
+++ b/src/Bindings/PluginLua.h
@@ -69,6 +69,7 @@ public:
virtual void Tick(float a_Dt) override;
+ virtual bool OnBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source) override;
virtual bool OnBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) override;
virtual bool OnChat (cPlayer * a_Player, AString & a_Message) override;
virtual bool OnChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override;
@@ -112,6 +113,8 @@ public:
virtual bool OnPluginsLoaded (void) override;
virtual bool OnPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
virtual bool OnPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
+ virtual bool OnProjectileHitBlock (cProjectileEntity & a_Projectile) override;
+ virtual bool OnProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity) override;
virtual bool OnSpawnedEntity (cWorld & a_World, cEntity & a_Entity) override;
virtual bool OnSpawnedMonster (cWorld & a_World, cMonster & a_Monster) override;
virtual bool OnSpawningEntity (cWorld & a_World, cEntity & a_Entity) override;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index b9cf160c4..6a5356c0b 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -205,6 +205,27 @@ void cPluginManager::Tick(float a_Dt)
+bool cPluginManager::CallHookBlockSpread(cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source)
+{
+ HookMap::iterator Plugins = m_Hooks.find(HOOK_BLOCK_SPREAD);
+ if (Plugins == m_Hooks.end())
+ {
+ return false;
+ }
+ for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
+ {
+ if ((*itr)->OnBlockSpread(a_World, a_BlockX, a_BlockY, a_BlockZ, a_Source))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginManager::CallHookBlockToPickups(
cWorld * a_World, cEntity * a_Digger,
int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
@@ -1133,6 +1154,48 @@ bool cPluginManager::CallHookPreCrafting(const cPlayer * a_Player, const cCrafti
+bool cPluginManager::CallHookProjectileHitBlock(cProjectileEntity & a_Projectile)
+{
+ HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_BLOCK);
+ if (Plugins == m_Hooks.end())
+ {
+ return false;
+ }
+ for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
+ {
+ if ((*itr)->OnProjectileHitBlock(a_Projectile))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
+bool cPluginManager::CallHookProjectileHitEntity(cProjectileEntity & a_Projectile, cEntity & a_HitEntity)
+{
+ HookMap::iterator Plugins = m_Hooks.find(HOOK_PROJECTILE_HIT_ENTITY);
+ if (Plugins == m_Hooks.end())
+ {
+ return false;
+ }
+ for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
+ {
+ if ((*itr)->OnProjectileHitEntity(a_Projectile, a_HitEntity))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+
+
bool cPluginManager::CallHookSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
HookMap::iterator Plugins = m_Hooks.find(HOOK_SPAWNED_ENTITY);
diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h
index 44bc5a8d7..512bc1351 100644
--- a/src/Bindings/PluginManager.h
+++ b/src/Bindings/PluginManager.h
@@ -18,6 +18,9 @@ class cChunkDesc;
// fwd: Entities/Entity.h
class cEntity;
+// fwd: Entities/ProjectileEntity.h
+class cProjectileEntity;
+
// fwd: Mobs/Monster.h
class cMonster;
@@ -58,6 +61,7 @@ public: // tolua_export
// tolua_begin
enum PluginHook
{
+ HOOK_BLOCK_SPREAD,
HOOK_BLOCK_TO_PICKUPS,
HOOK_CHAT,
HOOK_CHUNK_AVAILABLE,
@@ -101,6 +105,8 @@ public: // tolua_export
HOOK_PLUGINS_LOADED,
HOOK_POST_CRAFTING,
HOOK_PRE_CRAFTING,
+ HOOK_PROJECTILE_HIT_BLOCK,
+ HOOK_PROJECTILE_HIT_ENTITY,
HOOK_SPAWNED_ENTITY,
HOOK_SPAWNED_MONSTER,
HOOK_SPAWNING_ENTITY,
@@ -127,6 +133,8 @@ public: // tolua_export
class cCommandEnumCallback
{
public:
+ virtual ~cCommandEnumCallback() {}
+
/** Called for each command; return true to abort enumeration
For console commands, a_Permission is not used (set to empty string)
*/
@@ -154,6 +162,7 @@ public: // tolua_export
unsigned int GetNumPlugins() const; // tolua_export
// Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort
+ bool CallHookBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source);
bool CallHookBlockToPickups (cWorld * a_World, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups);
bool CallHookChat (cPlayer * a_Player, AString & a_Message);
bool CallHookChunkAvailable (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
@@ -197,6 +206,8 @@ public: // tolua_export
bool CallHookPluginsLoaded (void);
bool CallHookPostCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
bool CallHookPreCrafting (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
+ bool CallHookProjectileHitBlock (cProjectileEntity & a_Projectile);
+ bool CallHookProjectileHitEntity (cProjectileEntity & a_Projectile, cEntity & a_HitEntity);
bool CallHookSpawnedEntity (cWorld & a_World, cEntity & a_Entity);
bool CallHookSpawnedMonster (cWorld & a_World, cMonster & a_Monster);
bool CallHookSpawningEntity (cWorld & a_World, cEntity & a_Entity);
diff --git a/src/Bindings/lua5.1.dll b/src/Bindings/lua51.dll
index 515cf8b30..515cf8b30 100644
--- a/src/Bindings/lua5.1.dll
+++ b/src/Bindings/lua51.dll
Binary files differ
diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp
index 406e18a3b..f6d54e41c 100644
--- a/src/BlockArea.cpp
+++ b/src/BlockArea.cpp
@@ -162,13 +162,6 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB
// cBlockArea:
cBlockArea::cBlockArea(void) :
- m_OriginX(0),
- m_OriginY(0),
- m_OriginZ(0),
- m_SizeX(0),
- m_SizeY(0),
- m_SizeZ(0),
- m_WEOffset(0, 0, 0),
m_BlockTypes(NULL),
m_BlockMetas(NULL),
m_BlockLight(NULL),
@@ -195,12 +188,8 @@ void cBlockArea::Clear(void)
delete[] m_BlockMetas; m_BlockMetas = NULL;
delete[] m_BlockLight; m_BlockLight = NULL;
delete[] m_BlockSkyLight; m_BlockSkyLight = NULL;
- m_OriginX = 0;
- m_OriginY = 0;
- m_OriginZ = 0;
- m_SizeX = 0;
- m_SizeY = 0;
- m_SizeZ = 0;
+ m_Origin.Set(0, 0, 0);
+ m_Size.Set(0, 0, 0);
}
@@ -243,12 +232,17 @@ void cBlockArea::Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
m_BlockSkyLight[i] = 0x0f;
}
}
- m_SizeX = a_SizeX;
- m_SizeY = a_SizeY;
- m_SizeZ = a_SizeZ;
- m_OriginX = 0;
- m_OriginY = 0;
- m_OriginZ = 0;
+ m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
+ m_Origin.Set(0, 0, 0);
+}
+
+
+
+
+
+void cBlockArea::Create(const Vector3i & a_Size, int a_DataTypes)
+{
+ Create(a_Size.x, a_Size.y, a_Size.z, a_DataTypes);
}
@@ -275,9 +269,7 @@ void cBlockArea::SetWEOffset(const Vector3i & a_Offset)
void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
{
- m_OriginX = a_OriginX;
- m_OriginY = a_OriginY;
- m_OriginZ = a_OriginZ;
+ m_Origin.Set(a_OriginX, a_OriginY, a_OriginZ);
}
@@ -286,7 +278,7 @@ void cBlockArea::SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ)
void cBlockArea::SetOrigin(const Vector3i & a_Origin)
{
- SetOrigin(a_Origin.x, a_Origin.y, a_Origin.z);
+ m_Origin.Set(a_Origin.x, a_Origin.y, a_Origin.z);
}
@@ -342,9 +334,7 @@ bool cBlockArea::Read(cForEachChunkProvider * a_ForEachChunkProvider, int a_MinB
{
return false;
}
- m_OriginX = a_MinBlockX;
- m_OriginY = a_MinBlockY;
- m_OriginZ = a_MinBlockZ;
+ m_Origin.Set(a_MinBlockX, a_MinBlockY, a_MinBlockZ);
cChunkReader Reader(*this);
// Convert block coords to chunks coords:
@@ -408,10 +398,10 @@ bool cBlockArea::Write(cForEachChunkProvider * a_ForEachChunkProvider, int a_Min
LOGWARNING("%s: MinBlockY less than zero, adjusting to zero", __FUNCTION__);
a_MinBlockY = 0;
}
- else if (a_MinBlockY > cChunkDef::Height - m_SizeY)
+ else if (a_MinBlockY > cChunkDef::Height - m_Size.y)
{
LOGWARNING("%s: MinBlockY + m_SizeY more than chunk height, adjusting to chunk height", __FUNCTION__);
- a_MinBlockY = cChunkDef::Height - m_SizeY;
+ a_MinBlockY = cChunkDef::Height - m_Size.y;
}
return a_ForEachChunkProvider->WriteBlockArea(*this, a_MinBlockX, a_MinBlockY, a_MinBlockZ, a_DataTypes);
@@ -443,10 +433,8 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
}
a_Into.Clear();
- a_Into.SetSize(m_SizeX, m_SizeY, m_SizeZ, GetDataTypes());
- a_Into.m_OriginX = m_OriginX;
- a_Into.m_OriginY = m_OriginY;
- a_Into.m_OriginZ = m_OriginZ;
+ a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
+ a_Into.m_Origin = m_Origin;
int BlockCount = GetBlockCount();
if (HasBlockTypes())
{
@@ -487,9 +475,9 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
LOGWARNING("cBlockArea: Cannot open file \"%s\" for raw dump", a_FileName.c_str());
return;
}
- UInt32 SizeX = ntohl(m_SizeX);
- UInt32 SizeY = ntohl(m_SizeY);
- UInt32 SizeZ = ntohl(m_SizeZ);
+ UInt32 SizeX = ntohl(m_Size.x);
+ UInt32 SizeY = ntohl(m_Size.y);
+ UInt32 SizeZ = ntohl(m_Size.z);
f.Write(&SizeX, 4);
f.Write(&SizeY, 4);
f.Write(&SizeZ, 4);
@@ -532,13 +520,13 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY, int a_AddMinZ, int a_SubMaxZ)
{
if (
- (a_AddMinX + a_SubMaxX >= m_SizeX) ||
- (a_AddMinY + a_SubMaxY >= m_SizeY) ||
- (a_AddMinZ + a_SubMaxZ >= m_SizeZ)
+ (a_AddMinX + a_SubMaxX >= m_Size.x) ||
+ (a_AddMinY + a_SubMaxY >= m_Size.y) ||
+ (a_AddMinZ + a_SubMaxZ >= m_Size.z)
)
{
LOGWARNING("cBlockArea:Crop called with more croping than the dimensions: %d x %d x %d with cropping %d, %d and %d",
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
a_AddMinX + a_SubMaxX, a_AddMinY + a_SubMaxY, a_AddMinZ + a_SubMaxZ
);
return;
@@ -560,12 +548,10 @@ void cBlockArea::Crop(int a_AddMinX, int a_SubMaxX, int a_AddMinY, int a_SubMaxY
{
CropNibbles(m_BlockSkyLight, a_AddMinX, a_SubMaxX, a_AddMinY, a_SubMaxY, a_AddMinZ, a_SubMaxZ);
}
- m_OriginX += a_AddMinX;
- m_OriginY += a_AddMinY;
- m_OriginZ += a_AddMinZ;
- m_SizeX -= a_AddMinX + a_SubMaxX;
- m_SizeY -= a_AddMinY + a_SubMaxY;
- m_SizeZ -= a_AddMinZ + a_SubMaxZ;
+ m_Origin.Move(a_AddMinX, a_AddMinY, a_AddMinZ);
+ m_Size.x -= a_AddMinX + a_SubMaxX;
+ m_Size.y -= a_AddMinY + a_SubMaxY;
+ m_Size.z -= a_AddMinZ + a_SubMaxZ;
}
@@ -590,12 +576,10 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
{
ExpandNibbles(m_BlockSkyLight, a_SubMinX, a_AddMaxX, a_SubMinY, a_AddMaxY, a_SubMinZ, a_AddMaxZ);
}
- m_OriginX -= a_SubMinX;
- m_OriginY -= a_SubMinY;
- m_OriginZ -= a_SubMinZ;
- m_SizeX += a_SubMinX + a_AddMaxX;
- m_SizeY += a_SubMinY + a_AddMaxY;
- m_SizeZ += a_SubMinZ + a_AddMaxZ;
+ m_Origin.Move(-a_SubMinX, -a_SubMinY, -a_SubMinZ);
+ m_Size.x += a_SubMinX + a_AddMaxX;
+ m_Size.y += a_SubMinY + a_AddMaxY;
+ m_Size.z += a_SubMinZ + a_AddMaxZ;
}
@@ -645,7 +629,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorOverwrite
);
break;
@@ -660,7 +644,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorFillAir
);
break;
@@ -675,7 +659,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorImprint
);
break;
@@ -690,7 +674,7 @@ void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_R
SrcOffX, SrcOffY, SrcOffZ,
DstOffX, DstOffY, DstOffZ,
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
- m_SizeX, m_SizeY, m_SizeZ,
+ m_Size.x, m_Size.y, m_Size.z,
MergeCombinatorLake
);
break;
@@ -982,17 +966,17 @@ void cBlockArea::RotateCCW(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
- int NewZ = m_SizeX - x - 1;
- for (int z = 0; z < m_SizeZ; z++)
+ int NewZ = m_Size.x - x - 1;
+ for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- int NewIdx = NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ;
+ int NewIdx = NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z;
int OldIdx = MakeIndex(x, y, z);
NewTypes[NewIdx] = m_BlockTypes[OldIdx];
NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCCW(m_BlockMetas[OldIdx]);
@@ -1004,7 +988,7 @@ void cBlockArea::RotateCCW(void)
delete[] NewTypes;
delete[] NewMetas;
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1027,17 +1011,17 @@ void cBlockArea::RotateCW(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; rotate both at the same time:
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- int NewX = m_SizeZ - z - 1;
- for (int y = 0; y < m_SizeY; y++)
+ int NewX = m_Size.z - z - 1;
+ for (int y = 0; y < m_Size.y; y++)
{
- int NewIdx = NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ;
+ int NewIdx = NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z;
int OldIdx = MakeIndex(x, y, z);
NewTypes[NewIdx] = m_BlockTypes[OldIdx];
NewMetas[NewIdx] = BlockHandler(m_BlockTypes[OldIdx])->MetaRotateCW(m_BlockMetas[OldIdx]);
@@ -1049,7 +1033,7 @@ void cBlockArea::RotateCW(void)
delete[] NewTypes;
delete[] NewMetas;
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1072,13 +1056,13 @@ void cBlockArea::MirrorXY(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
- int HalfZ = m_SizeZ / 2;
- int MaxZ = m_SizeZ - 1;
- for (int y = 0; y < m_SizeY; y++)
+ int HalfZ = m_Size.z / 2;
+ int MaxZ = m_Size.z - 1;
+ for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
int Idx1 = MakeIndex(x, y, z);
int Idx2 = MakeIndex(x, y, MaxZ - z);
@@ -1112,13 +1096,13 @@ void cBlockArea::MirrorXZ(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
- int HalfY = m_SizeY / 2;
- int MaxY = m_SizeY - 1;
+ int HalfY = m_Size.y / 2;
+ int MaxY = m_Size.y - 1;
for (int y = 0; y < HalfY; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
int Idx1 = MakeIndex(x, y, z);
int Idx2 = MakeIndex(x, MaxY - y, z);
@@ -1152,11 +1136,11 @@ void cBlockArea::MirrorYZ(void)
}
// We are guaranteed that both blocktypes and blockmetas exist; mirror both at the same time:
- int HalfX = m_SizeX / 2;
- int MaxX = m_SizeX - 1;
- for (int y = 0; y < m_SizeY; y++)
+ int HalfX = m_Size.x / 2;
+ int MaxX = m_Size.x - 1;
+ for (int y = 0; y < m_Size.y; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@@ -1180,16 +1164,16 @@ void cBlockArea::RotateCCWNoMeta(void)
{
if (HasBlockTypes())
{
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
- int NewZ = m_SizeX - x - 1;
- for (int z = 0; z < m_SizeZ; z++)
+ int NewZ = m_Size.x - x - 1;
+ for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewTypes[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)];
+ NewTypes[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockTypes[MakeIndex(x, y, z)];
} // for y
} // for z
} // for x
@@ -1198,23 +1182,23 @@ void cBlockArea::RotateCCWNoMeta(void)
}
if (HasBlockMetas())
{
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int x = 0; x < m_SizeX; x++)
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int x = 0; x < m_Size.x; x++)
{
- int NewZ = m_SizeX - x - 1;
- for (int z = 0; z < m_SizeZ; z++)
+ int NewZ = m_Size.x - x - 1;
+ for (int z = 0; z < m_Size.z; z++)
{
int NewX = z;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewMetas[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)];
+ NewMetas[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockMetas[MakeIndex(x, y, z)];
} // for y
} // for z
} // for x
std::swap(m_BlockMetas, NewMetas);
delete[] NewMetas;
}
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1225,16 +1209,16 @@ void cBlockArea::RotateCWNoMeta(void)
{
if (HasBlockTypes())
{
- BLOCKTYPE * NewTypes = new BLOCKTYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int z = 0; z < m_SizeZ; z++)
+ BLOCKTYPE * NewTypes = new BLOCKTYPE[GetBlockCount()];
+ for (int z = 0; z < m_Size.z; z++)
{
- int NewX = m_SizeZ - z - 1;
- for (int x = 0; x < m_SizeX; x++)
+ int NewX = m_Size.z - z - 1;
+ for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewTypes[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockTypes[MakeIndex(x, y, z)];
+ NewTypes[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockTypes[MakeIndex(x, y, z)];
} // for y
} // for x
} // for z
@@ -1243,23 +1227,23 @@ void cBlockArea::RotateCWNoMeta(void)
}
if (HasBlockMetas())
{
- NIBBLETYPE * NewMetas = new NIBBLETYPE[m_SizeX * m_SizeY * m_SizeZ];
- for (int z = 0; z < m_SizeZ; z++)
+ NIBBLETYPE * NewMetas = new NIBBLETYPE[GetBlockCount()];
+ for (int z = 0; z < m_Size.z; z++)
{
- int NewX = m_SizeZ - z - 1;
- for (int x = 0; x < m_SizeX; x++)
+ int NewX = m_Size.z - z - 1;
+ for (int x = 0; x < m_Size.x; x++)
{
int NewZ = x;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- NewMetas[NewX + NewZ * m_SizeZ + y * m_SizeX * m_SizeZ] = m_BlockMetas[MakeIndex(x, y, z)];
+ NewMetas[NewX + NewZ * m_Size.z + y * m_Size.x * m_Size.z] = m_BlockMetas[MakeIndex(x, y, z)];
} // for y
} // for x
} // for z
std::swap(m_BlockMetas, NewMetas);
delete[] NewMetas;
}
- std::swap(m_SizeX, m_SizeZ);
+ std::swap(m_Size.x, m_Size.z);
}
@@ -1268,15 +1252,15 @@ void cBlockArea::RotateCWNoMeta(void)
void cBlockArea::MirrorXYNoMeta(void)
{
- int HalfZ = m_SizeZ / 2;
- int MaxZ = m_SizeZ - 1;
+ int HalfZ = m_Size.z / 2;
+ int MaxZ = m_Size.z - 1;
if (HasBlockTypes())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, y, MaxZ - z)]);
} // for x
@@ -1286,11 +1270,11 @@ void cBlockArea::MirrorXYNoMeta(void)
if (HasBlockMetas())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
for (int z = 0; z < HalfZ; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, y, MaxZ - z)]);
} // for x
@@ -1305,15 +1289,15 @@ void cBlockArea::MirrorXYNoMeta(void)
void cBlockArea::MirrorXZNoMeta(void)
{
- int HalfY = m_SizeY / 2;
- int MaxY = m_SizeY - 1;
+ int HalfY = m_Size.y / 2;
+ int MaxY = m_Size.y - 1;
if (HasBlockTypes())
{
for (int y = 0; y < HalfY; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockTypes[MakeIndex(x, y, z)], m_BlockTypes[MakeIndex(x, MaxY - y, z)]);
} // for x
@@ -1325,9 +1309,9 @@ void cBlockArea::MirrorXZNoMeta(void)
{
for (int y = 0; y < HalfY; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
std::swap(m_BlockMetas[MakeIndex(x, y, z)], m_BlockMetas[MakeIndex(x, MaxY - y, z)]);
} // for x
@@ -1342,13 +1326,13 @@ void cBlockArea::MirrorXZNoMeta(void)
void cBlockArea::MirrorYZNoMeta(void)
{
- int HalfX = m_SizeX / 2;
- int MaxX = m_SizeX - 1;
+ int HalfX = m_Size.x / 2;
+ int MaxX = m_Size.x - 1;
if (HasBlockTypes())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@@ -1360,9 +1344,9 @@ void cBlockArea::MirrorYZNoMeta(void)
if (HasBlockMetas())
{
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- for (int z = 0; z < m_SizeZ; z++)
+ for (int z = 0; z < m_Size.z; z++)
{
for (int x = 0; x < HalfX; x++)
{
@@ -1393,7 +1377,7 @@ void cBlockArea::SetRelBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a
void cBlockArea::SetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType)
{
- SetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType);
+ SetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType);
}
@@ -1470,7 +1454,7 @@ BLOCKTYPE cBlockArea::GetRelBlockType(int a_RelX, int a_RelY, int a_RelZ) const
BLOCKTYPE cBlockArea::GetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ) const
{
- return GetRelBlockType(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ);
+ return GetRelBlockType(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z);
}
@@ -1533,7 +1517,7 @@ NIBBLETYPE cBlockArea::GetBlockSkyLight(int a_BlockX, int a_BlockY, int a_BlockZ
void cBlockArea::SetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
- SetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta);
+ SetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
}
@@ -1567,7 +1551,7 @@ void cBlockArea::SetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, B
void cBlockArea::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const
{
- return GetRelBlockTypeMeta(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_BlockType, a_BlockMeta);
+ return GetRelBlockTypeMeta(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_BlockType, a_BlockMeta);
}
@@ -1670,9 +1654,7 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
return false;
}
}
- m_SizeX = a_SizeX;
- m_SizeY = a_SizeY;
- m_SizeZ = a_SizeZ;
+ m_Size.Set(a_SizeX, a_SizeY, a_SizeZ);
return true;
}
@@ -1683,13 +1665,13 @@ bool cBlockArea::SetSize(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes)
int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const
{
ASSERT(a_RelX >= 0);
- ASSERT(a_RelX < m_SizeX);
+ ASSERT(a_RelX < m_Size.x);
ASSERT(a_RelY >= 0);
- ASSERT(a_RelY < m_SizeY);
+ ASSERT(a_RelY < m_Size.y);
ASSERT(a_RelZ >= 0);
- ASSERT(a_RelZ < m_SizeZ);
+ ASSERT(a_RelZ < m_Size.z);
- return a_RelX + a_RelZ * m_SizeX + a_RelY * m_SizeX * m_SizeZ;
+ return a_RelX + a_RelZ * m_Size.x + a_RelY * m_Size.x * m_Size.z;
}
@@ -1712,7 +1694,7 @@ void cBlockArea::SetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_V
void cBlockArea::SetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Value, NIBBLETYPE * a_Array)
{
- SetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Value, a_Array);
+ SetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Value, a_Array);
}
@@ -1735,7 +1717,7 @@ NIBBLETYPE cBlockArea::GetRelNibble(int a_RelX, int a_RelY, int a_RelZ, NIBBLETY
NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE * a_Array) const
{
- return GetRelNibble(a_BlockX - m_OriginX, a_BlockY - m_OriginY, a_BlockZ - m_OriginZ, a_Array);
+ return GetRelNibble(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Array);
}
@@ -1748,9 +1730,7 @@ NIBBLETYPE cBlockArea::GetNibble(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBL
cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) :
m_Area(a_Area),
- m_OriginX(a_Area.m_OriginX),
- m_OriginY(a_Area.m_OriginY),
- m_OriginZ(a_Area.m_OriginZ)
+ m_Origin(a_Area.m_Origin.x, a_Area.m_Origin.y, a_Area.m_Origin.z)
{
}
@@ -1760,8 +1740,8 @@ cBlockArea::cChunkReader::cChunkReader(cBlockArea & a_Area) :
void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc)
{
- int SizeY = m_Area.m_SizeY;
- int MinY = m_OriginY;
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
// SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
// OffX, OffZ are the offsets of the current chunk data from the area origin
@@ -1770,7 +1750,7 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
int SizeZ = cChunkDef::Width;
int OffX, OffZ;
int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
if (OffX < 0)
{
BaseX = -OffX;
@@ -1781,7 +1761,7 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
{
BaseX = 0;
}
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ;
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
if (OffZ < 0)
{
BaseZ = -OffZ;
@@ -1793,13 +1773,13 @@ void cBlockArea::cChunkReader::CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLET
BaseZ = 0;
}
// If the chunk extends beyond the area in the X or Z axis, cut off the Size:
- if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX)
+ if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
{
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX);
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
}
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ)
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ);
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
}
for (int y = 0; y < SizeY; y++)
@@ -1843,8 +1823,8 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
return;
}
- int SizeY = m_Area.m_SizeY;
- int MinY = m_OriginY;
+ int SizeY = m_Area.m_Size.y;
+ int MinY = m_Origin.y;
// SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union)
// OffX, OffZ are the offsets of the current chunk data from the area origin
@@ -1853,7 +1833,7 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
int SizeZ = cChunkDef::Width;
int OffX, OffZ;
int BaseX, BaseZ;
- OffX = m_CurrentChunkX * cChunkDef::Width - m_OriginX;
+ OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x;
if (OffX < 0)
{
BaseX = -OffX;
@@ -1864,7 +1844,7 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
{
BaseX = 0;
}
- OffZ = m_CurrentChunkZ * cChunkDef::Width - m_OriginZ;
+ OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z;
if (OffZ < 0)
{
BaseZ = -OffZ;
@@ -1876,13 +1856,13 @@ void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes)
BaseZ = 0;
}
// If the chunk extends beyond the area in the X or Z axis, cut off the Size:
- if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_OriginX + m_Area.m_SizeX)
+ if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x)
{
- SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_OriginX + m_Area.m_SizeX);
+ SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x);
}
- if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_OriginZ + m_Area.m_SizeZ)
+ if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z)
{
- SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_OriginZ + m_Area.m_SizeZ);
+ SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z);
}
for (int y = 0; y < SizeY; y++)
@@ -2002,21 +1982,21 @@ void cBlockArea::CropNibbles(NIBBLEARRAY & a_Array, int a_AddMinX, int a_SubMaxX
void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
{
- int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX;
- int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY;
- int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ;
+ int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
+ int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
+ int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
int OldIndex = 0;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ;
- for (int z = 0; z < m_SizeZ; z++)
+ int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
+ for (int z = 0; z < m_Size.z; z++)
{
- int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX;
+ int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
int idx = IndexBaseZ + a_SubMinX;
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
NewBlockTypes[idx++] = m_BlockTypes[OldIndex++];
} // for x
@@ -2032,21 +2012,21 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMaxY, int a_SubMinZ, int a_AddMaxZ)
{
- int NewSizeX = m_SizeX + a_SubMinX + a_AddMaxX;
- int NewSizeY = m_SizeY + a_SubMinY + a_AddMaxY;
- int NewSizeZ = m_SizeZ + a_SubMinZ + a_AddMaxZ;
+ int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
+ int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
+ int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
int OldIndex = 0;
- for (int y = 0; y < m_SizeY; y++)
+ for (int y = 0; y < m_Size.y; y++)
{
- int IndexBaseY = (y + a_SubMinY) * m_SizeX * m_SizeZ;
- for (int z = 0; z < m_SizeZ; z++)
+ int IndexBaseY = (y + a_SubMinY) * m_Size.x * m_Size.z;
+ for (int z = 0; z < m_Size.z; z++)
{
- int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_SizeX;
+ int IndexBaseZ = IndexBaseY + (z + a_SubMinZ) * m_Size.x;
int idx = IndexBaseZ + a_SubMinX;
- for (int x = 0; x < m_SizeX; x++)
+ for (int x = 0; x < m_Size.x; x++)
{
NewNibbles[idx++] = a_Array[OldIndex++];
} // for x
@@ -2057,6 +2037,9 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
}
+
+
+
void cBlockArea::RelSetData(
int a_RelX, int a_RelY, int a_RelZ,
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
diff --git a/src/BlockArea.h b/src/BlockArea.h
index e0e8fe972..d28325d7d 100644
--- a/src/BlockArea.h
+++ b/src/BlockArea.h
@@ -43,6 +43,8 @@ public:
baSkyLight = 8,
} ;
+ /** The per-block strategy to use when merging another block area into this object.
+ See the Merge function for the description of these */
enum eMergeStrategy
{
msOverwrite,
@@ -57,12 +59,18 @@ public:
/** Clears the data stored to reclaim memory */
void Clear(void);
- /** Creates a new area of the specified size and contents.
- Origin is set to all zeroes.
+ /** Creates a new area of the specified size and contents.
+ Origin is set to all zeroes.
BlockTypes are set to air, block metas to zero, blocklights to zero and skylights to full light.
*/
void Create(int a_SizeX, int a_SizeY, int a_SizeZ, int a_DataTypes = baTypes | baMetas);
+ /** Creates a new area of the specified size and contents.
+ Origin is set to all zeroes.
+ BlockTypes are set to air, block metas to zero, blocklights to zero and skylights to full light.
+ */
+ void Create(const Vector3i & a_Size, int a_DataTypes = baTypes | baMetas);
+
/** Resets the origin. No other changes are made, contents are untouched. */
void SetOrigin(int a_OriginX, int a_OriginY, int a_OriginZ);
@@ -232,18 +240,24 @@ public:
void GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
void GetRelBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const;
+ // GetSize() is already exported manually to return 3 numbers, can't auto-export
+ const Vector3i & GetSize(void) const { return m_Size; }
+
+ // GetOrigin() is already exported manually to return 3 numbers, can't auto-export
+ const Vector3i & GetOrigin(void) const { return m_Origin; }
+
// tolua_begin
- int GetSizeX(void) const { return m_SizeX; }
- int GetSizeY(void) const { return m_SizeY; }
- int GetSizeZ(void) const { return m_SizeZ; }
+ int GetSizeX(void) const { return m_Size.x; }
+ int GetSizeY(void) const { return m_Size.y; }
+ int GetSizeZ(void) const { return m_Size.z; }
/** Returns the volume of the area, as number of blocks */
- int GetVolume(void) const { return m_SizeX * m_SizeY * m_SizeZ; }
+ int GetVolume(void) const { return m_Size.x * m_Size.y * m_Size.z; }
- int GetOriginX(void) const { return m_OriginX; }
- int GetOriginY(void) const { return m_OriginY; }
- int GetOriginZ(void) const { return m_OriginZ; }
+ int GetOriginX(void) const { return m_Origin.x; }
+ int GetOriginY(void) const { return m_Origin.y; }
+ int GetOriginZ(void) const { return m_Origin.z; }
/** Returns the datatypes that are stored in the object (bitmask of baXXX values) */
int GetDataTypes(void) const;
@@ -261,7 +275,7 @@ public:
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
- int GetBlockCount(void) const { return m_SizeX * m_SizeY * m_SizeZ; }
+ int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
protected:
@@ -276,9 +290,7 @@ protected:
protected:
cBlockArea & m_Area;
- int m_OriginX;
- int m_OriginY;
- int m_OriginZ;
+ Vector3i m_Origin;
int m_CurrentChunkX;
int m_CurrentChunkZ;
@@ -295,12 +307,8 @@ protected:
typedef NIBBLETYPE * NIBBLEARRAY;
- int m_OriginX;
- int m_OriginY;
- int m_OriginZ;
- int m_SizeX;
- int m_SizeY;
- int m_SizeZ;
+ Vector3i m_Origin;
+ Vector3i m_Size;
/** An extra data value sometimes stored in the .schematic file. Used mainly by the WorldEdit plugin.
cBlockArea doesn't use this value in any way. */
diff --git a/src/BlockID.h b/src/BlockID.h
index 8adefcfba..2fec512e2 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -866,6 +866,19 @@ enum eShrapnelLevel
slAll
} ;
+
+
+
+
+enum eSpreadSource
+{
+ ssFireSpread,
+ ssGrassSpread,
+ ssMushroomSpread,
+ ssMycelSpread,
+ ssVineSpread,
+} ;
+
// tolua_end
diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h
index 544424a04..a1ab74257 100644
--- a/src/Blocks/BlockDirt.h
+++ b/src/Blocks/BlockDirt.h
@@ -79,7 +79,10 @@ public:
Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta);
if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !IsBlockWater(AboveDest))
{
- Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
+ if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread))
+ {
+ Chunk->FastSetBlock(BlockX, BlockY, BlockZ, E_BLOCK_GRASS, 0);
+ }
}
} // for i - repeat twice
}
diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h
index 2b128f13b..6aa01f986 100644
--- a/src/Blocks/BlockMobHead.h
+++ b/src/Blocks/BlockMobHead.h
@@ -21,6 +21,18 @@ public:
{
a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0));
}
+
+ bool TrySpawnWither(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
+ {
+ if (a_BlockY < 2)
+ {
+ return false;
+ }
+
+ // TODO 2014-03-24 xdot
+
+ return false;
+ }
virtual void OnPlacedByPlayer(
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
@@ -62,6 +74,8 @@ public:
cWorld * World = (cWorld *) &a_WorldInterface;
World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta);
+
+ TrySpawnWither(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
}
} ;
diff --git a/src/Blocks/BlockMushroom.h b/src/Blocks/BlockMushroom.h
index c30c1a401..135d418d7 100644
--- a/src/Blocks/BlockMushroom.h
+++ b/src/Blocks/BlockMushroom.h
@@ -17,6 +17,9 @@ public:
}
+ // TODO: Add Mushroom Spread
+
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
diff --git a/src/Blocks/BlockMycelium.h b/src/Blocks/BlockMycelium.h
index 7f897c72a..2a8ef5fca 100644
--- a/src/Blocks/BlockMycelium.h
+++ b/src/Blocks/BlockMycelium.h
@@ -16,6 +16,8 @@ public:
{
}
+ // TODO: Add Mycel Spread
+
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
a_Pickups.push_back(cItem(E_BLOCK_DIRT, 1, 0));
diff --git a/src/Blocks/BlockSideways.h b/src/Blocks/BlockSideways.h
index 69c0a7230..d67c3aa24 100644
--- a/src/Blocks/BlockSideways.h
+++ b/src/Blocks/BlockSideways.h
@@ -29,7 +29,13 @@ public:
return true;
}
-
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3);
+ }
+
+
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_WoodMeta)
{
switch (a_BlockFace)
diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h
index 8041d9359..d096c81a8 100644
--- a/src/Blocks/BlockVine.h
+++ b/src/Blocks/BlockVine.h
@@ -175,7 +175,10 @@ public:
a_Chunk.UnboundedRelGetBlockType(a_RelX, a_RelY - 1, a_RelZ, Block);
if (Block == E_BLOCK_AIR)
{
- a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
+ if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, a_RelX * cChunkDef::Width, a_RelY - 1, a_RelZ * cChunkDef::Width, ssVineSpread))
+ {
+ a_Chunk.UnboundedRelSetBlock(a_RelX, a_RelY - 1, a_RelZ, E_BLOCK_VINES, a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ));
+ }
}
}
diff --git a/src/Blocks/BroadcastInterface.h b/src/Blocks/BroadcastInterface.h
index 01966ffbd..b1b450690 100644
--- a/src/Blocks/BroadcastInterface.h
+++ b/src/Blocks/BroadcastInterface.h
@@ -4,7 +4,8 @@
class cBroadcastInterface
{
public:
-
+ virtual ~cBroadcastInterface() {}
+
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
diff --git a/src/Blocks/WorldInterface.h b/src/Blocks/WorldInterface.h
index 580339d32..bfbb053d9 100644
--- a/src/Blocks/WorldInterface.h
+++ b/src/Blocks/WorldInterface.h
@@ -9,7 +9,8 @@ class cItems;
class cWorldInterface
{
public:
-
+ virtual ~cWorldInterface() {}
+
virtual Int64 GetTimeOfDay(void) const = 0;
virtual Int64 GetWorldAge(void) const = 0;
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index ea961733f..22b33c595 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -2510,6 +2510,17 @@ cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ)
cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
{
+ // If the relative coords are too far away, use the parent's chunk lookup instead:
+ if ((a_RelX < 128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128))
+ {
+ int BlockX = m_PosX * cChunkDef::Width + a_RelX;
+ int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
+ int BlockY, ChunkX, ChunkZ;
+ AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
+ return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
+ }
+
+ // Walk the neighbors:
bool ReturnThis = true;
if (a_RelX < 0)
{
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 37672b7f0..5ed5f1085 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1608,10 +1608,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
} // for itr - Chunks[]
- // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock
- // Instead, the chunks will be streamed when the client is moved to the new world's Tick list,
- // by setting state to csAuthenticated
- m_State = csAuthenticated;
+ // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set
+ // Meanwhile here, we set last streamed values to bogus ones so everything is resent
m_LastStreamedChunkX = 0x7fffffff;
m_LastStreamedChunkZ = 0x7fffffff;
m_HasSentPlayerChunk = false;
diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp
index 4dc7bfde6..322084dc4 100644
--- a/src/DeadlockDetect.cpp
+++ b/src/DeadlockDetect.cpp
@@ -7,7 +7,7 @@
#include "DeadlockDetect.h"
#include "Root.h"
#include "World.h"
-# include <cstdlib>
+#include <cstdlib>
@@ -16,9 +16,6 @@
/// Number of milliseconds per cycle
const int CYCLE_MILLISECONDS = 100;
-/// When the number of cycles for the same world age hits this value, it is considered a deadlock
-const int NUM_CYCLES_LIMIT = 200; // 200 = twenty seconds
-
diff --git a/src/Entities/EnderCrystal.cpp b/src/Entities/EnderCrystal.cpp
new file mode 100644
index 000000000..a640b236c
--- /dev/null
+++ b/src/Entities/EnderCrystal.cpp
@@ -0,0 +1,56 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "EnderCrystal.h"
+#include "ClientHandle.h"
+#include "Player.h"
+#include "../Chunk.h"
+
+
+
+
+
+cEnderCrystal::cEnderCrystal(double a_X, double a_Y, double a_Z)
+ : cEntity(etEnderCrystal, a_X, a_Y, a_Z, 1.0, 1.0)
+{
+ SetMaxHealth(5);
+}
+
+
+
+
+
+void cEnderCrystal::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ a_ClientHandle.SendSpawnObject(*this, 51, 0, (Byte)GetYaw(), (Byte)GetPitch());
+}
+
+
+
+
+
+void cEnderCrystal::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ UNUSED(a_Dt);
+
+ a_Chunk.SetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT, E_BLOCK_FIRE, 0);
+
+ // No further processing (physics e.t.c.) is needed
+}
+
+
+
+
+
+void cEnderCrystal::KilledBy(cEntity * a_Killer)
+{
+ super::KilledBy(a_Killer);
+
+ m_World->DoExplosionAt(6.0, GetPosX(), GetPosY(), GetPosZ(), true, esEnderCrystal, this);
+
+ Destroy();
+}
+
+
+
+
diff --git a/src/Entities/EnderCrystal.h b/src/Entities/EnderCrystal.h
new file mode 100644
index 000000000..5b86df987
--- /dev/null
+++ b/src/Entities/EnderCrystal.h
@@ -0,0 +1,33 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cEnderCrystal :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+ CLASS_PROTODEF(cEnderCrystal);
+
+ cEnderCrystal(double a_X, double a_Y, double a_Z);
+
+private:
+
+ // cEntity overrides:
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void KilledBy(cEntity * a_Killer) override;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index df80093e5..e41f74b09 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -69,6 +69,7 @@ public:
enum eEntityType
{
etEntity, // For all other types
+ etEnderCrystal,
etPlayer,
etPickup,
etMonster,
@@ -130,18 +131,19 @@ public:
eEntityType GetEntityType(void) const { return m_EntityType; }
- bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
- bool IsPickup (void) const { return (m_EntityType == etPickup); }
- bool IsMob (void) const { return (m_EntityType == etMonster); }
+ bool IsEnderCrystal(void) const { return (m_EntityType == etEnderCrystal); }
+ bool IsPlayer (void) const { return (m_EntityType == etPlayer); }
+ bool IsPickup (void) const { return (m_EntityType == etPickup); }
+ bool IsMob (void) const { return (m_EntityType == etMonster); }
bool IsFallingBlock(void) const { return (m_EntityType == etFallingBlock); }
- bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
- bool IsBoat (void) const { return (m_EntityType == etBoat); }
- bool IsTNT (void) const { return (m_EntityType == etTNT); }
- bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
- bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
- bool IsFloater (void) const { return (m_EntityType == etFloater); }
- bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
- bool IsPainting (void) const { return (m_EntityType == etPainting); }
+ bool IsMinecart (void) const { return (m_EntityType == etMinecart); }
+ bool IsBoat (void) const { return (m_EntityType == etBoat); }
+ bool IsTNT (void) const { return (m_EntityType == etTNT); }
+ bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
+ bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
+ bool IsFloater (void) const { return (m_EntityType == etFloater); }
+ bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
+ bool IsPainting (void) const { return (m_EntityType == etPainting); }
/// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true)
virtual bool IsA(const char * a_ClassName) const;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index 863aaa799..646aad50f 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1489,6 +1489,7 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
// Add player to all the necessary parts of the new world
SetWorld(World);
+ m_ClientHandle->StreamChunks();
World->AddEntity(this);
World->AddPlayer(this);
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index f4ab825f2..a9735a53c 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -4,6 +4,7 @@
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
#include "Globals.h"
+#include "../Bindings/PluginManager.h"
#include "ProjectileEntity.h"
#include "../ClientHandle.h"
#include "Player.h"
@@ -66,6 +67,11 @@ protected:
eBlockFace Face;
if (bb.CalcLineIntersection(Line1, Line2, LineCoeff, Face))
{
+ if (cPluginManager::Get()->CallHookProjectileHitBlock(*m_Projectile))
+ {
+ return false;
+ }
+
Vector3d Intersection = Line1 + m_Projectile->GetSpeed() * LineCoeff;
m_Projectile->OnHitSolidBlock(Intersection, Face);
return true;
@@ -147,7 +153,11 @@ public:
}
// TODO: Some entities don't interact with the projectiles (pickups, falling blocks)
- // TODO: Allow plugins to interfere about which entities can be hit
+ if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity))
+ {
+ // A plugin disagreed.
+ return false;
+ }
if (LineCoeff < m_MinCoeff)
{
diff --git a/src/ForEachChunkProvider.h b/src/ForEachChunkProvider.h
index 6017173ee..7a6e8c5c6 100644
--- a/src/ForEachChunkProvider.h
+++ b/src/ForEachChunkProvider.h
@@ -24,6 +24,8 @@ class cBlockArea;
class cForEachChunkProvider
{
public:
+ virtual ~cForEachChunkProvider() {}
+
/** Calls the callback for each chunk in the specified range. */
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) = 0;
diff --git a/src/Generating/ChunkDesc.cpp b/src/Generating/ChunkDesc.cpp
index 308fbe423..7711723fc 100644
--- a/src/Generating/ChunkDesc.cpp
+++ b/src/Generating/ChunkDesc.cpp
@@ -343,9 +343,9 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
int SizeY = a_MaxRelY - a_MinRelY;
int SizeZ = a_MaxRelZ - a_MinRelZ;
a_Dest.Clear();
- a_Dest.m_OriginX = m_ChunkX * cChunkDef::Width + a_MinRelX;
- a_Dest.m_OriginY = a_MinRelY;
- a_Dest.m_OriginZ = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
+ a_Dest.m_Origin.x = m_ChunkX * cChunkDef::Width + a_MinRelX;
+ a_Dest.m_Origin.y = a_MinRelY;
+ a_Dest.m_Origin.z = m_ChunkZ * cChunkDef::Width + a_MinRelZ;
a_Dest.SetSize(SizeX, SizeY, SizeZ, cBlockArea::baTypes | cBlockArea::baMetas);
for (int y = 0; y < SizeY; y++)
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
new file mode 100644
index 000000000..a9e0a839d
--- /dev/null
+++ b/src/Generating/Prefab.cpp
@@ -0,0 +1,312 @@
+
+// Prefab.cpp
+
+/*
+Implements the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+*/
+
+#include "Globals.h"
+#include "Prefab.h"
+#include "../WorldStorage/SchematicFileSerializer.h"
+#include "ChunkDesc.h"
+
+
+
+
+
+#ifdef SELF_TEST
+
+// Create one static prefab to test the parser:
+static const cPrefab::sDef g_TestPrefabDef =
+{
+ // Size:
+ 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7
+
+ // Block definitions:
+ ".: 0: 0\n" /* 0 */
+ "a:112: 0\n" /* netherbrick */
+ "b:113: 0\n" /* netherbrickfence */,
+
+ // Block data:
+ // Level 1
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+ "aaaaaaa"
+
+ // Level 2
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 3
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 4
+ "aa...aa"
+ "a.....a"
+ "......."
+ "......."
+ "......."
+ "a.....a"
+ "aa...aa"
+
+ // Level 5
+ "aabbbaa"
+ "a.....a"
+ "b.....b"
+ "b.....b"
+ "b.....b"
+ "a.....a"
+ "aabbbaa"
+
+ // Level 6
+ "aaaaaaa"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "a.....a"
+ "aaaaaaa",
+
+ // Connections:
+ "0: 0, 3, 2: 4\n"
+ "0: 2, 3, 0: 2\n",
+
+ // AllowedRotations:
+ 7, /* 1, 2, 3 CCW rotations */
+
+ // Merge strategy:
+ cBlockArea::msImprint
+};
+
+static cPrefab g_TestPrefab(g_TestPrefabDef);
+#endif
+
+
+
+
+
+cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
+ m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
+ m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
+ m_AllowedRotations(a_Def.m_AllowedRotations),
+ m_MergeStrategy(a_Def.m_MergeStrategy)
+{
+ m_BlockArea[0].Create(m_Size);
+ CharMap cm;
+ ParseCharMap(cm, a_Def.m_CharMap);
+ ParseBlockImage(cm, a_Def.m_Image);
+ ParseConnectors(a_Def.m_Connectors);
+
+ // 1 CCW rotation:
+ if ((m_AllowedRotations & 0x01) != 0)
+ {
+ m_BlockArea[1].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[1].RotateCCW();
+ }
+
+ // 2 rotations are the same as mirroring twice; mirroring is faster because it has no reallocations
+ if ((m_AllowedRotations & 0x02) != 0)
+ {
+ m_BlockArea[2].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[2].MirrorXY();
+ m_BlockArea[2].MirrorYZ();
+ }
+
+ // 3 CCW rotations = 1 CW rotation:
+ if ((m_AllowedRotations & 0x04) != 0)
+ {
+ m_BlockArea[3].CopyFrom(m_BlockArea[0]);
+ m_BlockArea[3].RotateCW();
+ }
+}
+
+
+
+
+
+void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
+{
+ Vector3i Placement = a_Placement->GetCoords();
+ int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
+ int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
+ Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
+ a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);
+
+}
+
+
+
+
+
+bool cPrefab::HasConnectorType(int a_ConnectorType) const
+{
+ for (cConnectors::const_iterator itr = m_Connectors.begin(), end = m_Connectors.end(); itr != end; ++itr)
+ {
+ if (itr->m_Type == a_ConnectorType)
+ {
+ return true;
+ }
+ } // for itr - m_Connectors[]
+ return false;
+}
+
+
+
+
+
+void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
+{
+ // Initialize the charmap to all-invalid values:
+ for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++)
+ {
+ a_CharMapOut[i].m_BlockType = 0;
+ a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise
+ }
+
+ // Process the lines in the definition:
+ AStringVector Lines = StringSplitAndTrim(a_CharMapDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ AStringVector CharDef = StringSplitAndTrim(*itr, ":");
+ size_t NumElements = CharDef.size();
+ if ((NumElements < 2) || CharDef[0].empty() || CharDef[1].empty())
+ {
+ LOGWARNING("Bad prefab CharMap definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ unsigned char Src = (unsigned char)CharDef[0][0];
+ ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet?
+ a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str());
+ NIBBLETYPE BlockMeta = 0;
+ if ((NumElements >= 3) && !CharDef[2].empty())
+ {
+ BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
+ ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
+ }
+ a_CharMapOut[Src].m_BlockMeta = BlockMeta;
+ } // for itr - Lines[]
+}
+
+
+
+
+
+void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage)
+{
+ // Map each letter in the a_BlockImage (from the in-source definition) to real blocktype / blockmeta:
+ for (int y = 0; y < m_Size.y; y++)
+ {
+ for (int z = 0; z < m_Size.z; z++)
+ {
+ const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x;
+ for (int x = 0; x < m_Size.x; x++)
+ {
+ const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]];
+ ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap?
+ m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta);
+ }
+ }
+ }
+}
+
+
+
+
+
+void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
+{
+ AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n");
+ for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ continue;
+ }
+ // Split into components: "Type: X, Y, Z: Face":
+ AStringVector Defs = StringSplitAndTrim(*itr, ":");
+ if (Defs.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector definition line: \"%s\", skipping.", itr->c_str());
+ continue;
+ }
+ AStringVector Coords = StringSplitAndTrim(Defs[1], ",");
+ if (Coords.size() != 3)
+ {
+ LOGWARNING("Bad prefab Connector coords definition: \"%s\", skipping.", Defs[1].c_str());
+ continue;
+ }
+
+ // Check that the BlockFace is within range:
+ int BlockFace = atoi(Defs[2].c_str());
+ if ((BlockFace < 0) || (BlockFace >= 6))
+ {
+ LOGWARNING("Bad prefab Connector Blockface: \"%s\", skipping.", Defs[2].c_str());
+ continue;
+ }
+
+ // Add the connector:
+ m_Connectors.push_back(cPiece::cConnector(
+ atoi(Coords[0].c_str()), atoi(Coords[1].c_str()), atoi(Coords[2].c_str()), // Connector pos
+ atoi(Defs[0].c_str()), // Connector type
+ (eBlockFace)BlockFace
+ ));
+ } // for itr - Lines[]
+}
+
+
+
+
+
+cPiece::cConnectors cPrefab::GetConnectors(void) const
+{
+ return m_Connectors;
+}
+
+
+
+
+
+Vector3i cPrefab::GetSize(void) const
+{
+ return m_Size;
+}
+
+
+
+
+
+cCuboid cPrefab::GetHitBox(void) const
+{
+ return m_HitBox;
+}
+
+
+
+
+
+bool cPrefab::CanRotateCCW(int a_NumRotations) const
+{
+ // Either zero rotations
+ // Or the proper bit in m_AllowedRotations is set
+ return (a_NumRotations == 0) || ((m_AllowedRotations & (1 << ((a_NumRotations + 3) % 4))) != 0);
+}
+
+
+
+
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
new file mode 100644
index 000000000..04c4f09da
--- /dev/null
+++ b/src/Generating/Prefab.h
@@ -0,0 +1,105 @@
+
+// Prefab.h
+
+/*
+Declares the cPrefab class, representing a cPiece descendant for the cPieceGenerator that
+uses a prefabricate in a cBlockArea for drawing itself.
+The class can be constructed from data that is stored directly in the executable, in a sPrefabDef structure
+declared in this file as well; the Gallery server exports areas in this format.
+*/
+
+
+
+
+
+#pragma once
+
+#include "PieceGenerator.h"
+#include "../BlockArea.h"
+
+
+
+
+
+// fwd:
+class cChunkDesc;
+
+
+
+
+
+class cPrefab :
+ public cPiece
+{
+public:
+ struct sDef
+ {
+ int m_SizeX;
+ int m_SizeY;
+ int m_SizeZ;
+ const char * m_CharMap;
+ const char * m_Image;
+ const char * m_Connectors;
+ int m_AllowedRotations;
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+ };
+
+ cPrefab(const sDef & a_Def);
+
+ /** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */
+ void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const;
+
+ /** Returns true if the prefab has any connector of the specified type. */
+ bool HasConnectorType(int a_ConnectorType) const;
+
+protected:
+ /** Packs complete definition of a single block, for per-letter assignment. */
+ struct sBlockTypeDef
+ {
+ BLOCKTYPE m_BlockType;
+ NIBBLETYPE m_BlockMeta;
+ };
+
+ /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
+ typedef sBlockTypeDef CharMap[256];
+
+
+ /** The cBlockArea that contains the block definitions for the prefab.
+ The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
+ cBlockArea m_BlockArea[4];
+
+ /** The size of the prefab */
+ Vector3i m_Size;
+
+ /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */
+ cCuboid m_HitBox;
+
+ /** The connectors through which the piece connects to other pieces */
+ cConnectors m_Connectors;
+
+ /** Bitmask, bit N set -> N rotations CCW supported */
+ int m_AllowedRotations;
+
+ /** The merge strategy to use when drawing the prefab into a block area */
+ cBlockArea::eMergeStrategy m_MergeStrategy;
+
+
+ // cPiece overrides:
+ virtual cConnectors GetConnectors(void) const override;
+ virtual Vector3i GetSize(void) const override;
+ virtual cCuboid GetHitBox(void) const override;
+ virtual bool CanRotateCCW(int a_NumRotations) const override;
+
+ /** Parses the CharMap in the definition into a CharMap binary data used for translating the definition into BlockArea. */
+ void ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef);
+
+ /** Parses the Image in the definition into m_BlockArea[0]'s block types and metas, using the specified CharMap. */
+ void ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockImage);
+
+ /** Parses the connectors definition text into m_Connectors member. */
+ void ParseConnectors(const char * a_ConnectorsDef);
+};
+
+
+
+
diff --git a/src/Globals.h b/src/Globals.h
index 3e62832b7..a1cee5c2f 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -264,11 +264,17 @@ template class SizeChecker<UInt16, 2>;
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
#endif
-/// A generic interface used mainly in ForEach() functions
+
+
+
+
+/** A generic interface used mainly in ForEach() functions */
template <typename Type> class cItemCallback
{
public:
- /// Called for each item in the internal list; return true to stop the loop, or false to continue enumerating
+ virtual ~cItemCallback() {}
+
+ /** Called for each item in the internal list; return true to stop the loop, or false to continue enumerating */
virtual bool Item(Type * a_Type) = 0;
} ;
diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h
index 24baf8c95..383abb4b6 100644
--- a/src/HTTPServer/HTTPServer.h
+++ b/src/HTTPServer/HTTPServer.h
@@ -37,6 +37,8 @@ public:
class cCallbacks
{
public:
+ virtual ~cCallbacks() {}
+
/** Called when a new request arrives over a connection and its headers have been parsed.
The request body needn't have arrived yet.
*/
@@ -50,7 +52,7 @@ public:
} ;
cHTTPServer(void);
- ~cHTTPServer();
+ virtual ~cHTTPServer();
/// Initializes the server on the specified ports
bool Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6);
diff --git a/src/Inventory.h b/src/Inventory.h
index fd2089a13..1ad7c4776 100644
--- a/src/Inventory.h
+++ b/src/Inventory.h
@@ -52,6 +52,8 @@ public:
cInventory(cPlayer & a_Owner);
+ virtual ~cInventory() {}
+
// tolua_begin
/// Removes all items from the entire inventory
diff --git a/src/ItemGrid.h b/src/ItemGrid.h
index b344e3daf..c34d5e9e2 100644
--- a/src/ItemGrid.h
+++ b/src/ItemGrid.h
@@ -20,11 +20,13 @@ class cItemGrid
public:
// tolua_end
- /// This class is used as a callback for when a slot changes
+ /** This class is used as a callback for when a slot changes */
class cListener
{
public:
- /// Called whenever a slot changes
+ virtual ~cListener() {}
+
+ /** Called whenever a slot changes */
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) = 0;
} ;
typedef std::vector<cListener *> cListeners;
@@ -38,12 +40,12 @@ public:
int GetHeight (void) const { return m_Height; }
int GetNumSlots(void) const { return m_NumSlots; }
- /// Converts XY coords into slot number; returns -1 on invalid coords
+ /** Converts XY coords into slot number; returns -1 on invalid coords */
int GetSlotNum(int a_X, int a_Y) const;
// tolua_end
- /// Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp
+ /** Converts slot number into XY coords; sets coords to -1 on invalid slot number. Exported in ManualBindings.cpp */
void GetSlotCoords(int a_SlotNum, int & a_X, int & a_Y) const;
// tolua_begin
@@ -62,16 +64,16 @@ public:
void EmptySlot(int a_X, int a_Y);
void EmptySlot(int a_SlotNum);
- /// Returns true if the specified slot is empty or the slot doesn't exist
+ /** Returns true if the specified slot is empty or the slot doesn't exist */
bool IsSlotEmpty(int a_SlotNum) const;
- /// Returns true if the specified slot is empty or the slot doesn't exist
+ /** Returns true if the specified slot is empty or the slot doesn't exist */
bool IsSlotEmpty(int a_X, int a_Y) const;
- /// Sets all items as empty
+ /** Sets all items as empty */
void Clear(void);
- /// Returns number of items out of a_ItemStack that can fit in the storage
+ /** Returns number of items out of a_ItemStack that can fit in the storage */
int HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks = true);
/** Adds as many items out of a_ItemStack as can fit.
@@ -117,37 +119,37 @@ public:
*/
cItem RemoveOneItem(int a_X, int a_Y);
- /// Returns the number of items of type a_Item that are stored
+ /** Returns the number of items of type a_Item that are stored */
int HowManyItems(const cItem & a_Item);
- /// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack
+ /** Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack */
bool HasItems(const cItem & a_ItemStack);
- /// Returns the index of the first empty slot; -1 if all full
+ /** Returns the index of the first empty slot; -1 if all full */
int GetFirstEmptySlot(void) const;
- /// Returns the index of the first non-empty slot; -1 if all empty
+ /** Returns the index of the first non-empty slot; -1 if all empty */
int GetFirstUsedSlot(void) const;
- /// Returns the index of the last empty slot; -1 if all full
+ /** Returns the index of the last empty slot; -1 if all full */
int GetLastEmptySlot(void) const;
- /// Returns the index of the last used slot; -1 if all empty
+ /** Returns the index of the last used slot; -1 if all empty */
int GetLastUsedSlot(void) const;
- /// Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked)
+ /** Returns the index of the first empty slot following a_StartFrom (a_StartFrom is not checked) */
int GetNextEmptySlot(int a_StartFrom) const;
- /// Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked)
+ /** Returns the index of the first used slot following a_StartFrom (a_StartFrom is not checked) */
int GetNextUsedSlot(int a_StartFrom) const;
- /// Copies the contents into a cItems object; preserves the original a_Items contents
+ /** Copies the contents into a cItems object; preserves the original a_Items contents */
void CopyToItems(cItems & a_Items) const;
- /// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
+ /** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
bool DamageItem(int a_SlotNum, short a_Amount);
- /// Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact)
+ /** Adds the specified damage to the specified item; returns true if the item broke (but the item is left intact) */
bool DamageItem(int a_X, int a_Y, short a_Amount);
// tolua_end
@@ -159,10 +161,10 @@ public:
*/
void GenerateRandomLootWithBooks(const cLootProbab * a_LootProbabs, size_t a_CountLootProbabs, int a_NumSlots, int a_Seed);
- /// Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback!
+ /** Adds a callback that gets called whenever a slot changes. Must not be called from within the listener callback! */
void AddListener(cListener & a_Listener);
- /// Removes a slot-change-callback. Must not be called from within the listener callback!
+ /** Removes a slot-change-callback. Must not be called from within the listener callback! */
void RemoveListener(cListener & a_Listener);
// tolua_begin
@@ -177,7 +179,7 @@ protected:
cCriticalSection m_CSListeners; ///< CS that guards the m_Listeners against multi-thread access
bool m_IsInTriggerListeners; ///< Set to true while TriggerListeners is running, to detect attempts to manipulate listener list while triggerring
- /// Calls all m_Listeners for the specified slot number
+ /** Calls all m_Listeners for the specified slot number */
void TriggerListeners(int a_SlotNum);
/** Adds up to a_Num items out of a_ItemStack, as many as can fit, in specified slot
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 16d6aed1f..d3e0f1c26 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -758,6 +758,7 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
case mtSquid: return mfWater;
case mtVillager: return mfPassive;
case mtWitch: return mfHostile;
+ case mtWither: return mfHostile;
case mtWolf: return mfHostile;
case mtZombie: return mfHostile;
case mtZombiePigman: return mfHostile;
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index b99ae876f..5bba4d4ba 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -29,7 +29,7 @@ public:
CLASS_PROTODEF(cVillager);
- // Override functions
+ // cEntity overrides
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index c46e0beab..0e42194ac 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -2,14 +2,64 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Wither.h"
+#include "../World.h"
cWither::cWither(void) :
- super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0)
+ super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
+ m_InvulnerableTicks(220)
{
+ SetMaxHealth(300);
+
+ SetHealth(GetMaxHealth() / 3);
+}
+
+
+
+
+
+void cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ if (a_TDI.DamageType == dtDrowning)
+ {
+ return;
+ }
+
+ if (m_InvulnerableTicks > 0)
+ {
+ return;
+ }
+
+ super::DoTakeDamage(a_TDI);
+}
+
+
+
+
+
+void cWither::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_InvulnerableTicks > 0)
+ {
+ unsigned int NewTicks = m_InvulnerableTicks - 1;
+
+ if (NewTicks == 0)
+ {
+ m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
+ }
+
+ m_InvulnerableTicks = NewTicks;
+
+ if ((NewTicks % 10) == 0)
+ {
+ Heal(10);
+ }
+ }
}
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index 56effc6bb..d09e3607a 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -16,8 +16,21 @@ public:
cWither(void);
CLASS_PROTODEF(cWither);
+
+ unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; }
+
+ void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
+ // cEntity overrides
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+private:
+
+ /** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
+ unsigned int m_InvulnerableTicks;
+
} ;
diff --git a/src/OSSupport/ListenThread.h b/src/OSSupport/ListenThread.h
index 4e337d814..b2d806c82 100644
--- a/src/OSSupport/ListenThread.h
+++ b/src/OSSupport/ListenThread.h
@@ -29,43 +29,45 @@ class cListenThread :
typedef cIsThread super;
public:
- /// Used as the callback for connection events
+ /** Used as the callback for connection events */
class cCallback
{
public:
- /// This callback is called whenever a socket connection is accepted
+ virtual ~cCallback() {}
+
+ /** This callback is called whenever a socket connection is accepted */
virtual void OnConnectionAccepted(cSocket & a_Socket) = 0;
} ;
cListenThread(cCallback & a_Callback, cSocket::eFamily a_Family, const AString & a_ServiceName = "");
~cListenThread();
- /// Creates all the sockets, returns trus if successful, false if not.
+ /** Creates all the sockets, returns trus if successful, false if not. */
bool Initialize(const AString & a_PortsString);
bool Start(void);
void Stop(void);
- /// Call before Initialize() to set the "reuse" flag on the sockets
+ /** Call before Initialize() to set the "reuse" flag on the sockets */
void SetReuseAddr(bool a_Reuse = true);
protected:
typedef std::vector<cSocket> cSockets;
- /// The callback which to notify of incoming connections
+ /** The callback which to notify of incoming connections */
cCallback & m_Callback;
- /// Socket address family to use
+ /** Socket address family to use */
cSocket::eFamily m_Family;
- /// Sockets that are being monitored
+ /** Sockets that are being monitored */
cSockets m_Sockets;
- /// If set to true, the SO_REUSEADDR socket option is set to true
+ /** If set to true, the SO_REUSEADDR socket option is set to true */
bool m_ShouldReuseAddr;
- /// Name of the service that's listening on the ports; for logging purposes only
+ /** Name of the service that's listening on the ports; for logging purposes only */
AString m_ServiceName;
diff --git a/src/RCONServer.h b/src/RCONServer.h
index 0e89800a2..88aac4b5f 100644
--- a/src/RCONServer.h
+++ b/src/RCONServer.h
@@ -29,7 +29,7 @@ class cRCONServer :
{
public:
cRCONServer(cServer & a_Server);
- ~cRCONServer();
+ virtual ~cRCONServer();
void Initialize(cIniFile & a_IniFile);
diff --git a/src/Root.cpp b/src/Root.cpp
index 3555afb45..ba4398b35 100644
--- a/src/Root.cpp
+++ b/src/Root.cpp
@@ -304,6 +304,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile)
{
if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld")
{
+ IniFile.DeleteKeyComment("Worlds", 0);
IniFile.AddKeyComment("Worlds", " World=secondworld");
}
}
diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp
index 26712e6e6..470dfc791 100644
--- a/src/Simulator/FireSimulator.cpp
+++ b/src/Simulator/FireSimulator.cpp
@@ -6,6 +6,8 @@
#include "../BlockID.h"
#include "../Defines.h"
#include "../Chunk.h"
+#include "Root.h"
+#include "../Bindings/PluginManager.h"
@@ -315,9 +317,15 @@ void cFireSimulator::TrySpreadFire(cChunk * a_Chunk, int a_RelX, int a_RelY, int
*/
if (CanStartFireInBlock(a_Chunk, x, y, z))
{
- FLOG("FS: Starting new fire at {%d, %d, %d}.",
- x + a_Chunk->GetPosX() * cChunkDef::Width, y, z + a_Chunk->GetPosZ() * cChunkDef::Width
- );
+ int a_PosX = x + a_Chunk->GetPosX() * cChunkDef::Width;
+ int a_PosZ = z + a_Chunk->GetPosZ() * cChunkDef::Width;
+
+ if (cRoot::Get()->GetPluginManager()->CallHookBlockSpread(&m_World, a_PosX, y, a_PosZ, ssFireSpread))
+ {
+ return;
+ }
+
+ FLOG("FS: Starting new fire at {%d, %d, %d}.", a_PosX, y, a_PosZ);
a_Chunk->UnboundedRelSetBlock(x, y, z, E_BLOCK_FIRE, 0);
}
} // for y
diff --git a/src/UI/WindowOwner.h b/src/UI/WindowOwner.h
index d41abf66d..e3c73edc4 100644
--- a/src/UI/WindowOwner.h
+++ b/src/UI/WindowOwner.h
@@ -33,6 +33,10 @@ public:
{
}
+ virtual ~cWindowOwner()
+ {
+ }
+
void CloseWindow(void)
{
m_Window = NULL;
diff --git a/src/Vector3.h b/src/Vector3.h
index ba4abe3eb..a00e14508 100644
--- a/src/Vector3.h
+++ b/src/Vector3.h
@@ -121,6 +121,13 @@ public:
z += a_Z;
}
+ inline void Move(const Vector3<T> & a_Diff)
+ {
+ x += a_Diff.x;
+ y += a_Diff.y;
+ z += a_Diff.z;
+ }
+
// tolua_end
inline void operator += (const Vector3<T> & a_Rhs)
diff --git a/src/World.cpp b/src/World.cpp
index 3f157157a..e39a605bb 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -60,9 +60,6 @@
-/// Up to this many m_SpreadQueue elements are handled each world tick
-const int MAX_LIGHTING_SPREAD_PER_TICK = 10;
-
const int TIME_SUNSET = 12000;
const int TIME_NIGHT_START = 13187;
const int TIME_NIGHT_END = 22812;
diff --git a/src/World.h b/src/World.h
index 46aece18f..bb2eb0b21 100644
--- a/src/World.h
+++ b/src/World.h
@@ -497,16 +497,16 @@ public:
/** Does an explosion with the specified strength at the specified coordinate
a_SourceData exact type depends on the a_Source:
- | esOther | void * |
- | esPrimedTNT | cTNTEntity * |
- | esMonster | cMonster * |
- | esBed | cVector3i * |
- | esEnderCrystal | Vector3i * |
- | esGhastFireball | cGhastFireball * |
- | esWitherSkullBlack | TBD |
- | esWitherSkullBlue | TBD |
- | esWitherBirth | TBD |
- | esPlugin | void * |
+ | esOther | void * |
+ | esPrimedTNT | cTNTEntity * |
+ | esMonster | cMonster * |
+ | esBed | cVector3i * |
+ | esEnderCrystal | Vector3i * |
+ | esGhastFireball | cGhastFireball * |
+ | esWitherSkullBlack | TBD |
+ | esWitherSkullBlue | TBD |
+ | esWitherBirth | cMonster * |
+ | esPlugin | void * |
*/
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export // override, cannot specify due to tolua
diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp
index a4a0aab57..df72d1cc9 100644
--- a/src/WorldStorage/MapSerializer.cpp
+++ b/src/WorldStorage/MapSerializer.cpp
@@ -141,7 +141,11 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT)
{
eDimension Dimension = (eDimension) a_NBT.GetByte(CurrLine);
- ASSERT(Dimension == m_Map->m_World->GetDimension());
+ if (Dimension != m_Map->m_World->GetDimension())
+ {
+ // TODO 2014-03-20 xdot: We should store nether maps in nether worlds, e.t.c.
+ return false;
+ }
}
CurrLine = a_NBT.FindChildByName(Data, "width");
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index acca96ba8..415693ae2 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -23,6 +23,7 @@
#include "../BlockEntities/FlowerPotEntity.h"
#include "../Entities/Entity.h"
+#include "../Entities/EnderCrystal.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Boat.h"
#include "../Entities/Minecart.h"
@@ -43,6 +44,7 @@
#include "../Mobs/Slime.h"
#include "../Mobs/Skeleton.h"
#include "../Mobs/Villager.h"
+#include "../Mobs/Wither.h"
#include "../Mobs/Wolf.h"
#include "../Mobs/Zombie.h"
@@ -335,6 +337,17 @@ void cNBTChunkSerializer::AddBoatEntity(cBoat * a_Boat)
+void cNBTChunkSerializer::AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_EnderCrystal, "EnderCrystal");
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
{
m_Writer.BeginCompound("");
@@ -422,7 +435,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
case cMonster::mtSquid: EntityClass = "Squid"; break;
case cMonster::mtVillager: EntityClass = "Villager"; break;
case cMonster::mtWitch: EntityClass = "Witch"; break;
- case cMonster::mtWither: EntityClass = "Wither"; break;
+ case cMonster::mtWither: EntityClass = "WitherBoss"; break;
case cMonster::mtWolf: EntityClass = "Wolf"; break;
case cMonster::mtZombie: EntityClass = "Zombie"; break;
case cMonster::mtZombiePigman: EntityClass = "PigZombie"; break;
@@ -501,6 +514,11 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster)
m_Writer.AddInt("Profession", ((const cVillager *)a_Monster)->GetVilType());
break;
}
+ case cMonster::mtWither:
+ {
+ m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks());
+ break;
+ }
case cMonster::mtWolf:
{
m_Writer.AddString("Owner", ((const cWolf *)a_Monster)->GetOwner());
@@ -729,6 +747,7 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
switch (a_Entity->GetEntityType())
{
case cEntity::etBoat: AddBoatEntity ((cBoat *) a_Entity); break;
+ case cEntity::etEnderCrystal: AddEnderCrystalEntity((cEnderCrystal *) a_Entity); break;
case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *) a_Entity); break;
case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break;
case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h
index c1134cd00..51d104970 100644
--- a/src/WorldStorage/NBTChunkSerializer.h
+++ b/src/WorldStorage/NBTChunkSerializer.h
@@ -24,6 +24,7 @@ class cChestEntity;
class cCommandBlockEntity;
class cDispenserEntity;
class cDropperEntity;
+class cEnderCrystal;
class cFurnaceEntity;
class cHopperEntity;
class cJukeboxEntity;
@@ -106,6 +107,7 @@ protected:
// Entities:
void AddBasicEntity (cEntity * a_Entity, const AString & a_ClassName);
void AddBoatEntity (cBoat * a_Boat);
+ void AddEnderCrystalEntity(cEnderCrystal * a_EnderCrystal);
void AddFallingBlockEntity(cFallingBlock * a_FallingBlock);
void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster);
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index ef67fdb13..d8531d965 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -197,7 +197,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
// Copy the block types and metas:
- int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
+ int NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
{
LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
@@ -209,7 +209,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
if (AreMetasPresent)
{
- int NumBytes = a_BlockArea.m_SizeX * a_BlockArea.m_SizeY * a_BlockArea.m_SizeZ;
+ int NumBytes = a_BlockArea.GetBlockCount();
if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
{
LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
@@ -230,9 +230,9 @@ 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.AddShort("Width", a_BlockArea.m_Size.x);
+ Writer.AddShort("Height", a_BlockArea.m_Size.y);
+ Writer.AddShort("Length", a_BlockArea.m_Size.z);
Writer.AddString("Materials", "Alpha");
if (a_BlockArea.HasBlockTypes())
{
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 7a2366755..48934d074 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -32,6 +32,7 @@
#include "../Mobs/IncludeAllMonsters.h"
#include "../Entities/Boat.h"
+#include "../Entities/EnderCrystal.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
#include "../Entities/Pickup.h"
@@ -1057,6 +1058,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadBoatFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ else if (strncmp(a_IDTag, "EnderCrystal", a_IDTagLength) == 0)
+ {
+ LoadEnderCrystalFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
else if (strncmp(a_IDTag, "FallingBlock", a_IDTagLength) == 0)
{
LoadFallingBlockFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
@@ -1238,7 +1243,7 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadWitchFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
- else if (strncmp(a_IDTag, "Wither", a_IDTagLength) == 0)
+ else if (strncmp(a_IDTag, "WitherBoss", a_IDTagLength) == 0)
{
LoadWitherFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
@@ -1275,6 +1280,20 @@ void cWSSAnvil::LoadBoatFromNBT(cEntityList & a_Entities, const cParsedNBT & a_N
+void cWSSAnvil::LoadEnderCrystalFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cEnderCrystal> EnderCrystal(new cEnderCrystal(0, 0, 0));
+ if (!LoadEntityBaseFromNBT(*EnderCrystal.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+ a_Entities.push_back(EnderCrystal.release());
+}
+
+
+
+
+
void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
int TypeIdx = a_NBT.FindChildByName(a_TagIdx, "TileID");
@@ -2250,6 +2269,12 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a
return;
}
+ int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul");
+ if (CurrLine > 0)
+ {
+ Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine));
+ }
+
a_Entities.push_back(Monster.release());
}
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 50d0e555e..1773ee882 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -148,6 +148,7 @@ protected:
void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength);
void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFallingBlockFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadTNTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);