summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitignore1
-rw-r--r--MCServer/.gitignore2
-rw-r--r--MCServer/Plugins/ChatLog/plugin.lua3
-rw-r--r--MCServer/Plugins/ChunkWorx/chunkworx_main.lua3
m---------MCServer/Plugins/Core0
-rw-r--r--MCServer/Plugins/Debuggers/Debuggers.lua60
-rw-r--r--MCServer/Plugins/DiamondMover/DiamondMover.lua12
-rw-r--r--MCServer/Plugins/HookNotify/HookNotify.lua82
-rw-r--r--MCServer/Plugins/MagicCarpet/plugin.lua5
m---------MCServer/Plugins/ProtectionAreas0
-rw-r--r--Tools/AnvilStats/.gitignore4
-rw-r--r--Tools/AnvilStats/AnvilStats.cpp3
-rw-r--r--Tools/AnvilStats/AnvilStats.txt1
-rw-r--r--Tools/AnvilStats/AnvilStats.vcproj16
-rw-r--r--Tools/AnvilStats/Callback.h46
-rw-r--r--Tools/AnvilStats/HeightBiomeMap.cpp230
-rw-r--r--Tools/AnvilStats/HeightBiomeMap.h81
-rw-r--r--Tools/AnvilStats/HeightMap.h4
-rw-r--r--Tools/AnvilStats/ImageComposingCallback.cpp219
-rw-r--r--Tools/AnvilStats/ImageComposingCallback.h105
-rw-r--r--Tools/AnvilStats/Processor.cpp8
-rw-r--r--Tools/ProtoProxy/Connection.cpp61
-rw-r--r--Tools/ProtoProxy/Connection.h6
-rw-r--r--Tools/ProtoProxy/Globals.h1
-rw-r--r--Tools/ProtoProxy/ProtoProxy.vcproj8
-rw-r--r--VC2008/MCServer.vcproj20
-rw-r--r--docs/Login sequence.txt26
-rw-r--r--source/AllToLua.pkg3
-rw-r--r--source/Bindings.cpp1373
-rw-r--r--source/Bindings.h16
-rw-r--r--source/BlockID.h4
-rw-r--r--source/BlockTracer.h4
-rw-r--r--source/Blocks/BlockCarpet.h4
-rw-r--r--source/Blocks/BlockDoubleSlab.h43
-rw-r--r--source/Blocks/BlockHandler.cpp1
-rw-r--r--source/Blocks/BlockSlab.h113
-rw-r--r--source/ClientHandle.cpp99
-rw-r--r--source/ClientHandle.h4
-rw-r--r--source/Defines.h10
-rw-r--r--source/Entities/Entity.cpp49
-rw-r--r--source/Entities/Entity.h8
-rw-r--r--source/Entities/FallingBlock.cpp14
-rw-r--r--source/Entities/FallingBlock.h1
-rw-r--r--source/Entities/Minecart.cpp14
-rw-r--r--source/Entities/Minecart.h1
-rw-r--r--source/Entities/Pickup.cpp21
-rw-r--r--source/Entities/Pickup.h2
-rw-r--r--source/Entities/Player.cpp80
-rw-r--r--source/Entities/Player.h21
-rw-r--r--source/Entities/ProjectileEntity.cpp351
-rw-r--r--source/Entities/ProjectileEntity.h238
-rw-r--r--source/Entities/TNTEntity.cpp14
-rw-r--r--source/Entities/TNTEntity.h1
-rw-r--r--source/Items/ItemBow.h80
-rw-r--r--source/Items/ItemHandler.cpp26
-rw-r--r--source/Items/ItemHandler.h9
-rw-r--r--source/Items/ItemThrowable.h90
-rw-r--r--source/LeakFinder.cpp11
-rw-r--r--source/LineBlockTracer.cpp11
-rw-r--r--source/LineBlockTracer.h3
-rw-r--r--source/LuaState.cpp43
-rw-r--r--source/LuaState.h8
-rw-r--r--source/ManualBindings.cpp160
-rw-r--r--source/OSSupport/IsThread.cpp18
-rw-r--r--source/OSSupport/ListenThread.cpp2
-rw-r--r--source/OSSupport/Socket.cpp4
-rw-r--r--source/OSSupport/Timer.cpp45
-rw-r--r--source/OSSupport/Timer.h31
-rw-r--r--source/Plugin.h7
-rw-r--r--source/PluginLua.cpp723
-rw-r--r--source/PluginLua.h32
-rw-r--r--source/PluginManager.cpp17
-rw-r--r--source/PluginManager.h13
-rw-r--r--source/Protocol/Protocol132.cpp3
-rw-r--r--source/StringUtils.cpp43
-rw-r--r--source/Tracer.cpp4
-rw-r--r--source/Vector3d.h13
-rw-r--r--source/World.cpp37
-rw-r--r--source/World.h1444
-rw-r--r--source/WorldStorage/NBTChunkSerializer.cpp67
-rw-r--r--source/WorldStorage/NBTChunkSerializer.h2
-rw-r--r--source/WorldStorage/WSSAnvil.cpp51
-rw-r--r--source/WorldStorage/WSSAnvil.h1
83 files changed, 4922 insertions, 1572 deletions
diff --git a/.gitignore b/.gitignore
index b8a60a580..7706ecc0a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@ cloc.xsl
*.user
*.suo
/EveryNight.cmd
+*.sublime-*
diff --git a/MCServer/.gitignore b/MCServer/.gitignore
index ca10d90e8..ac226a77d 100644
--- a/MCServer/.gitignore
+++ b/MCServer/.gitignore
@@ -10,7 +10,7 @@ schematics
*.schematic
*.ilk
*.pdb
-memdump.xml
+memdump*
*.grab
ProtectionAreas.sqlite
helgrind.log
diff --git a/MCServer/Plugins/ChatLog/plugin.lua b/MCServer/Plugins/ChatLog/plugin.lua
index c2f6fb81a..adbf986e0 100644
--- a/MCServer/Plugins/ChatLog/plugin.lua
+++ b/MCServer/Plugins/ChatLog/plugin.lua
@@ -13,8 +13,7 @@ function Initialize(Plugin)
Plugin:SetName("ChatLog")
Plugin:SetVersion(3)
- PluginManager = cRoot:Get():GetPluginManager()
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHAT)
+ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChat)
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion())
return true
diff --git a/MCServer/Plugins/ChunkWorx/chunkworx_main.lua b/MCServer/Plugins/ChunkWorx/chunkworx_main.lua
index 66cf00b97..ab9962387 100644
--- a/MCServer/Plugins/ChunkWorx/chunkworx_main.lua
+++ b/MCServer/Plugins/ChunkWorx/chunkworx_main.lua
@@ -26,8 +26,7 @@ function Initialize(Plugin)
PLUGIN:SetName("ChunkWorx")
PLUGIN:SetVersion(6)
- PluginManager = cRoot:Get():GetPluginManager()
- PluginManager:AddHook(PLUGIN, cPluginManager.HOOK_TICK)
+ cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick)
Plugin:AddWebTab("(Re)Generation", HandleRequest_Generation)
diff --git a/MCServer/Plugins/Core b/MCServer/Plugins/Core
-Subproject e3a45f34303331be77aceacf2ba53e503ad7284
+Subproject c8ef7e9f8ed2bc1ffdbb3756c2024536bf00469
diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua
index 90a897aa6..be16e3465 100644
--- a/MCServer/Plugins/Debuggers/Debuggers.lua
+++ b/MCServer/Plugins/Debuggers/Debuggers.lua
@@ -16,15 +16,21 @@ function Initialize(Plugin)
Plugin:SetName("Debuggers")
Plugin:SetVersion(1)
- PluginManager = cRoot:Get():GetPluginManager()
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USING_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USING_ITEM);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_TAKE_DAMAGE);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_TICK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHAT);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_WORLD_TICK);
-
+ --[[
+ -- Test multiple hook handlers:
+ cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick1);
+ cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick2);
+ --]]
+
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USING_BLOCK, OnPlayerUsingBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USING_ITEM, OnPlayerUsingItem);
+ cPluginManager.AddHook(cPluginManager.HOOK_TAKE_DAMAGE, OnTakeDamage);
+ cPluginManager.AddHook(cPluginManager.HOOK_TICK, OnTick);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChat);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY, OnPlayerRightClickingEntity);
+ cPluginManager.AddHook(cPluginManager.HOOK_WORLD_TICK, OnWorldTick);
+
+ PluginManager = cRoot:Get():GetPluginManager();
PluginManager:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities");
PluginManager:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities");
PluginManager:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool");
@@ -39,6 +45,7 @@ function Initialize(Plugin)
PluginManager:BindCommand("/spidey", "debuggers", HandleSpideyCmd, "- Shoots a line of web blocks until it hits non-air");
PluginManager:BindCommand("/ench", "debuggers", HandleEnchCmd, "- Provides an instant dummy enchantment window");
PluginManager:BindCommand("/fs", "debuggers", HandleFoodStatsCmd, "- Turns regular foodstats message on or off");
+ PluginManager:BindCommand("/arr", "debuggers", HandleArrowCmd, "- Creates an arrow going away from the player");
-- Enable the following line for BlockArea / Generator interface testing:
-- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
@@ -415,6 +422,24 @@ end
+function OnTick1()
+ -- For testing multiple hook handlers per plugin
+ LOGINFO("Tick1");
+end
+
+
+
+
+
+function OnTick2()
+ -- For testing multiple hook handlers per plugin
+ LOGINFO("Tick2");
+end
+
+
+
+
+
--- When set to a positive number, the following OnTick() will perform GC and decrease until 0 again
GCOnTick = 0;
@@ -770,6 +795,7 @@ function HandleEnchCmd(a_Split, a_Player)
Wnd:SetProperty(0, 10);
Wnd:SetProperty(1, 15);
Wnd:SetProperty(2, 25);
+ return true;
end
@@ -778,6 +804,22 @@ end
function HandleFoodStatsCmd(a_Split, a_Player)
g_ShowFoodStats = not(g_ShowFoodStats);
+ return true;
+end
+
+
+
+
+
+function HandleArrowCmd(a_Split, a_Player)
+ local World = a_Player:GetWorld();
+ local Pos = a_Player:GetEyePosition();
+ local Speed = a_Player:GetLookVector();
+ Speed:Normalize();
+ Pos = Pos + Speed;
+
+ World:CreateProjectile(Pos.x, Pos.y, Pos.z, cProjectileEntity.pkArrow, a_Player, Speed * 10);
+ return true;
end
diff --git a/MCServer/Plugins/DiamondMover/DiamondMover.lua b/MCServer/Plugins/DiamondMover/DiamondMover.lua
index c89a3394f..0fdd32250 100644
--- a/MCServer/Plugins/DiamondMover/DiamondMover.lua
+++ b/MCServer/Plugins/DiamondMover/DiamondMover.lua
@@ -9,7 +9,6 @@
-- Global variables
-PLUGIN = {} -- Reference to own plugin object
MOVER_SIZE_X = 4;
MOVER_SIZE_Y = 4;
MOVER_SIZE_Z = 4;
@@ -19,13 +18,10 @@ MOVER_SIZE_Z = 4;
function Initialize(Plugin)
- PLUGIN = Plugin;
-
Plugin:SetName("DiamondMover");
Plugin:SetVersion(1);
- PluginManager = cRoot:Get():GetPluginManager();
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USED_ITEM);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_ITEM, OnPlayerUsedItem);
return true;
end
@@ -80,4 +76,8 @@ function OnPlayerUsedItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cu
Area:Write(Player:GetWorld(), BlockX - MOVER_SIZE_X, BlockY - MOVER_SIZE_Y, BlockZ - MOVER_SIZE_Z);
return false;
end
-end \ No newline at end of file
+end
+
+
+
+
diff --git a/MCServer/Plugins/HookNotify/HookNotify.lua b/MCServer/Plugins/HookNotify/HookNotify.lua
index 6badc63e7..ed791090e 100644
--- a/MCServer/Plugins/HookNotify/HookNotify.lua
+++ b/MCServer/Plugins/HookNotify/HookNotify.lua
@@ -13,47 +13,47 @@ function Initialize(Plugin)
Plugin:SetVersion(1);
PluginManager = cPluginManager:Get();
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_BLOCK_TO_PICKUPS);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHAT);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_AVAILABLE);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_UNLOADED);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_UNLOADING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_COLLECTING_PICKUP);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CRAFTING_NO_RECIPE);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_DISCONNECT);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_EXECUTE_COMMAND);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_HANDSHAKE);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_KILLING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_LOGIN);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_BREAKING_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_BROKEN_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_EATING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_JOINED);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_LEFT_CLICK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_MOVING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_PLACED_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_PLACING_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_RIGHT_CLICK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_SHOOTING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_SPAWNED);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_TOSSING_ITEM);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USED_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USED_ITEM);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USING_BLOCK);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_USING_ITEM);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_POST_CRAFTING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PRE_CRAFTING);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNED_ENTITY);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNED_MONSTER);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNING_ENTITY);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_SPAWNING_MONSTER);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_TAKE_DAMAGE);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_UPDATED_SIGN);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_UPDATING_SIGN);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_WEATHER_CHANGED);
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_WEATHER_CHANGING);
+ cPluginManager.AddHook(cPluginManager.HOOK_BLOCK_TO_PICKUPS, OnBlockToPickups);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHAT, OnChat);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_AVAILABLE, OnChunkAvailable);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_GENERATED, OnChunkGenerated);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_GENERATING, OnChunkGenerating);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_UNLOADED, OnChunkUnloaded);
+ cPluginManager.AddHook(cPluginManager.HOOK_CHUNK_UNLOADING, OnChunkUnloading);
+ cPluginManager.AddHook(cPluginManager.HOOK_COLLECTING_PICKUP, OnCollectingPickup);
+ cPluginManager.AddHook(cPluginManager.HOOK_CRAFTING_NO_RECIPE, OnCraftingNoRecipe);
+ cPluginManager.AddHook(cPluginManager.HOOK_DISCONNECT, OnDisconnect);
+ cPluginManager.AddHook(cPluginManager.HOOK_EXECUTE_COMMAND, OnExecuteCommand);
+ cPluginManager.AddHook(cPluginManager.HOOK_HANDSHAKE, OnHandshake);
+ cPluginManager.AddHook(cPluginManager.HOOK_KILLING, OnKilling);
+ cPluginManager.AddHook(cPluginManager.HOOK_LOGIN, OnLogin);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_BREAKING_BLOCK, OnPlayerBreakingBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_BROKEN_BLOCK, OnPlayerBrokenBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_EATING, OnPlayerEating);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_JOINED, OnPlayerJoined);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_LEFT_CLICK, OnPlayerLeftClick);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_PLACED_BLOCK, OnPlayerPlacedBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_PLACING_BLOCK, OnPlayerPlacingBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_RIGHT_CLICK, OnPlayerRightClick);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_SHOOTING, OnPlayerShooting);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_SPAWNED, OnPlayerSpawned);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_TOSSING_ITEM, OnPlayerTossingItem);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_BLOCK, OnPlayerUsedBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_ITEM, OnPlayerUsedItem);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USING_BLOCK, OnPlayerUsingBlock);
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USING_ITEM, OnPlayerUsingItem);
+ cPluginManager.AddHook(cPluginManager.HOOK_POST_CRAFTING, OnPostCrafting);
+ cPluginManager.AddHook(cPluginManager.HOOK_PRE_CRAFTING, OnPreCrafting);
+ cPluginManager.AddHook(cPluginManager.HOOK_SPAWNED_ENTITY, OnSpawnedEntity);
+ cPluginManager.AddHook(cPluginManager.HOOK_SPAWNED_MONSTER, OnSpawnedMonster);
+ cPluginManager.AddHook(cPluginManager.HOOK_SPAWNING_ENTITY, OnSpawningEntity);
+ cPluginManager.AddHook(cPluginManager.HOOK_SPAWNING_MONSTER, OnSpawningMonster);
+ cPluginManager.AddHook(cPluginManager.HOOK_TAKE_DAMAGE, OnTakeDamage);
+ cPluginManager.AddHook(cPluginManager.HOOK_UPDATED_SIGN, OnUpdatedSign);
+ cPluginManager.AddHook(cPluginManager.HOOK_UPDATING_SIGN, OnUpdatingSign);
+ cPluginManager.AddHook(cPluginManager.HOOK_WEATHER_CHANGED, OnWeatherChanged);
+ cPluginManager.AddHook(cPluginManager.HOOK_WEATHER_CHANGING, OnWeatherChanging);
LOGINFO("HookNotify plugin is installed, beware, the log output may be quite large!");
LOGINFO("You want this plugin enabled only when developing another plugin, not for regular gameplay.");
diff --git a/MCServer/Plugins/MagicCarpet/plugin.lua b/MCServer/Plugins/MagicCarpet/plugin.lua
index 3101866cd..27dcdf45d 100644
--- a/MCServer/Plugins/MagicCarpet/plugin.lua
+++ b/MCServer/Plugins/MagicCarpet/plugin.lua
@@ -7,9 +7,8 @@ function Initialize( Plugin )
Plugin:SetName( "MagicCarpet" )
Plugin:SetVersion( 1 )
- PluginManager = cRoot:Get():GetPluginManager()
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_MOVING)
- PluginManager:AddHook(Plugin, cPluginManager.HOOK_DISCONNECT)
+ cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_MOVING, OnPlayerMoving)
+ cPluginManager.AddHook(cPluginManager.HOOK_DISCONNECT, OnDisconnect)
PluginManager:BindCommand("/mc", "magiccarpet", HandleCarpetCommand, " - Spawns a magical carpet");
diff --git a/MCServer/Plugins/ProtectionAreas b/MCServer/Plugins/ProtectionAreas
-Subproject 3019c7b396221b987cd3f89d422276f764834ff
+Subproject bef8ff2a883e98db94f842f9db3d256a039b1fc
diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore
index 4ed720fed..5d98f06ec 100644
--- a/Tools/AnvilStats/.gitignore
+++ b/Tools/AnvilStats/.gitignore
@@ -1,5 +1,9 @@
.xls
Statistics.txt
*.bmp
+Debug/
+Release/
Profiling
*.png
+world/
+*.html \ No newline at end of file
diff --git a/Tools/AnvilStats/AnvilStats.cpp b/Tools/AnvilStats/AnvilStats.cpp
index f0b9dd7e6..d98c21985 100644
--- a/Tools/AnvilStats/AnvilStats.cpp
+++ b/Tools/AnvilStats/AnvilStats.cpp
@@ -8,6 +8,7 @@
#include "Statistics.h"
#include "BiomeMap.h"
#include "HeightMap.h"
+#include "HeightBiomeMap.h"
#include "ChunkExtract.h"
#include "SpringStats.h"
@@ -26,6 +27,7 @@ int main(int argc, char * argv[])
LOG(" 2 - height map");
LOG(" 3 - extract chunks");
LOG(" 4 - count lava- and water- springs");
+ LOG(" 5 - biome and height map");
LOG("\nNo method number present, aborting.");
return -1;
}
@@ -48,6 +50,7 @@ int main(int argc, char * argv[])
case 2: Factory = new cHeightMapFactory; break;
case 3: Factory = new cChunkExtractFactory(WorldFolder); break;
case 4: Factory = new cSpringStatsFactory; break;
+ case 5: Factory = new cHeightBiomeMapFactory; break;
default:
{
LOG("Unknown method \"%s\", aborting.", argv[1]);
diff --git a/Tools/AnvilStats/AnvilStats.txt b/Tools/AnvilStats/AnvilStats.txt
index 19aa4f324..1d8130aa2 100644
--- a/Tools/AnvilStats/AnvilStats.txt
+++ b/Tools/AnvilStats/AnvilStats.txt
@@ -15,6 +15,7 @@ Possible usage:
- count the per-chunk density of specific blocks
- count the per-chunk density of dungeons, by measuring the number of zombie/skeleton/regularspider spawners
- count the per-chunk-per-biome density of trees, by measuring the number of dirt-log vertical transitions, correlating to biome data
+ - draw a vertical map of the world based on a specific measured value (biome, elevation, ...)
This project is Windows-only, although it shouldn't be too difficult to make it portable.
diff --git a/Tools/AnvilStats/AnvilStats.vcproj b/Tools/AnvilStats/AnvilStats.vcproj
index ed4ffa9a5..038f32b97 100644
--- a/Tools/AnvilStats/AnvilStats.vcproj
+++ b/Tools/AnvilStats/AnvilStats.vcproj
@@ -314,6 +314,14 @@
>
</File>
<File
+ RelativePath=".\HeightBiomeMap.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\HeightBiomeMap.h"
+ >
+ </File>
+ <File
RelativePath=".\HeightMap.cpp"
>
</File>
@@ -322,6 +330,14 @@
>
</File>
<File
+ RelativePath=".\ImageComposingCallback.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\ImageComposingCallback.h"
+ >
+ </File>
+ <File
RelativePath=".\Processor.cpp"
>
</File>
diff --git a/Tools/AnvilStats/Callback.h b/Tools/AnvilStats/Callback.h
index 83b330651..eda4a8478 100644
--- a/Tools/AnvilStats/Callback.h
+++ b/Tools/AnvilStats/Callback.h
@@ -22,44 +22,53 @@ class cParsedNBT;
/** The base class for all chunk-processor callbacks, declares the interface.
The processor calls each virtual function in the order they are declared here with the specified args.
-If the function returns true, the processor moves on to next chunk and starts calling the callbacks again from start with
-the new chunk data.
+If the function returns true, the processor doesn't process the data item, moves on to the next chunk
+and starts calling the callbacks again from start with the new chunk data.
So if a statistics collector doesn't need data decompression at all, it can stop the processor from doing so early-enough
and still get meaningful data.
-A callback is guaranteed to run in a single thread and always the same thread.
+A callback is guaranteed to run in a single thread and always the same thread for the same chunk.
A callback is guaranteed to run on all chunks in a region and one region is guaranteed to be handled by only callback.
*/
class cCallback abstract
{
public:
+ enum
+ {
+ CALLBACK_CONTINUE = false,
+ CALLBACK_ABORT = true,
+ } ;
+
virtual ~cCallback() {} // Force a virtual destructor in each descendant
+
+ /// Called when a new region file is about to be opened; by default allow the region
+ virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) { return CALLBACK_CONTINUE; }
/// Called to inform the stats module of the chunk coords for newly processing chunk
virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) = 0;
/// Called to inform about the chunk's data offset in the file (chunk mini-header), the number of sectors it uses and the timestamp field value
- virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) { return true; }
+ virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) { return CALLBACK_ABORT; }
/// Called to inform of the compressed chunk data size and position in the file (offset from file start to the actual data)
- virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) { return true; }
+ virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) { return CALLBACK_ABORT; }
/// Just in case you wanted to process the NBT yourself ;)
- virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) { return true; }
+ virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) { return CALLBACK_ABORT; }
/// The chunk's NBT should specify chunk coords, these are sent here:
- virtual bool OnRealCoords(int a_ChunkX, int a_ChunkZ) { return true; }
+ virtual bool OnRealCoords(int a_ChunkX, int a_ChunkZ) { return CALLBACK_ABORT; }
/// The chunk contains a LastUpdate value specifying the last tick in which it was saved.
- virtual bool OnLastUpdate(Int64 a_LastUpdate) { return true; }
+ virtual bool OnLastUpdate(Int64 a_LastUpdate) { return CALLBACK_ABORT; }
- virtual bool OnTerrainPopulated(bool a_Populated) { return true; }
+ virtual bool OnTerrainPopulated(bool a_Populated) { return CALLBACK_ABORT; }
- virtual bool OnBiomes(const unsigned char * a_BiomeData) { return true; }
+ virtual bool OnBiomes(const unsigned char * a_BiomeData) { return CALLBACK_ABORT; }
/** Called when a heightmap for the chunk is read from the file.
Note that the heightmap is given in big-endian ints, so if you want it, you need to ntohl() it first!
*/
- virtual bool OnHeightMap(const int * a_HeightMapBE) { return true; }
+ virtual bool OnHeightMap(const int * a_HeightMapBE) { return CALLBACK_ABORT; }
/** If there is data for the section, this callback is called; otherwise OnEmptySection() is called instead.
All OnSection() callbacks are called first, and only then all the remaining sections are reported in OnEmptySection().
@@ -71,16 +80,16 @@ public:
const NIBBLETYPE * a_BlockMeta,
const NIBBLETYPE * a_BlockLight,
const NIBBLETYPE * a_BlockSkyLight
- ) { return true; }
+ ) { return CALLBACK_ABORT; }
/** If there is no data for a section, this callback is called; otherwise OnSection() is called instead.
OnEmptySection() callbacks are called after all OnSection() callbacks.
*/
- virtual bool OnEmptySection(unsigned char a_Y) { return false; }
+ virtual bool OnEmptySection(unsigned char a_Y) { return CALLBACK_CONTINUE; }
/** Called after all sections have been processed via either OnSection() or OnEmptySection().
*/
- virtual bool OnSectionsFinished(void) { return true; }
+ virtual bool OnSectionsFinished(void) { return CALLBACK_ABORT; }
/** Called for each entity in the chunk.
Common parameters are parsed from the NBT.
@@ -98,7 +107,7 @@ public:
char a_IsOnGround,
cParsedNBT & a_NBT,
int a_NBTTag
- ) { return true; }
+ ) { return CALLBACK_ABORT; }
/** Called for each tile entity in the chunk.
Common parameters are parsed from the NBT.
@@ -110,14 +119,17 @@ public:
int a_PosX, int a_PosY, int a_PosZ,
cParsedNBT & a_NBT,
int a_NBTTag
- ) { return true; }
+ ) { return CALLBACK_ABORT; }
/// Called for each tile tick in the chunk
virtual bool OnTileTick(
int a_BlockType,
int a_TicksLeft,
int a_PosX, int a_PosY, int a_PosZ
- ) { return true; }
+ ) { return CALLBACK_ABORT; }
+
+ /// Called after the entire region file has been processed. No more callbacks for this region will be called. No processing by default
+ virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) {}
} ;
typedef std::vector<cCallback *> cCallbacks;
diff --git a/Tools/AnvilStats/HeightBiomeMap.cpp b/Tools/AnvilStats/HeightBiomeMap.cpp
new file mode 100644
index 000000000..36918f644
--- /dev/null
+++ b/Tools/AnvilStats/HeightBiomeMap.cpp
@@ -0,0 +1,230 @@
+
+// HeightBiomeMap.cpp
+
+// Declares the cHeightBiomeMap class representing a stats module that produces an image of heights and biomes combined
+
+#include "Globals.h"
+#include "HeightBiomeMap.h"
+#include "HeightMap.h"
+
+
+
+
+
+cHeightBiomeMap::cHeightBiomeMap(void) :
+ super("HeBi"),
+ m_MinRegionX(100000),
+ m_MaxRegionX(-100000),
+ m_MinRegionZ(100000),
+ m_MaxRegionZ(-100000)
+{
+}
+
+
+
+
+
+bool cHeightBiomeMap::OnNewRegion(int a_RegionX, int a_RegionZ)
+{
+ if (a_RegionX < m_MinRegionX)
+ {
+ m_MinRegionX = a_RegionX;
+ }
+ if (a_RegionX > m_MaxRegionX)
+ {
+ m_MaxRegionX = a_RegionX;
+ }
+ if (a_RegionZ < m_MinRegionZ)
+ {
+ m_MinRegionZ = a_RegionZ;
+ }
+ if (a_RegionZ > m_MaxRegionZ)
+ {
+ m_MaxRegionZ = a_RegionZ;
+ }
+ return super::OnNewRegion(a_RegionX, a_RegionZ);
+}
+
+
+
+
+
+bool cHeightBiomeMap::OnNewChunk(int a_ChunkX, int a_ChunkZ)
+{
+ m_CurrentChunkX = a_ChunkX;
+ m_CurrentChunkZ = a_ChunkZ;
+ m_CurrentChunkRelX = m_CurrentChunkX - m_CurrentRegionX * 32;
+ m_CurrentChunkRelZ = m_CurrentChunkZ - m_CurrentRegionZ * 32;
+
+ ASSERT((m_CurrentChunkRelX >= 0) && (m_CurrentChunkRelX < 32));
+ ASSERT((m_CurrentChunkRelZ >= 0) && (m_CurrentChunkRelZ < 32));
+
+ memset(m_BlockTypes, 0, sizeof(m_BlockTypes));
+
+ return CALLBACK_CONTINUE;
+}
+
+
+
+
+
+
+bool cHeightBiomeMap::OnBiomes(const unsigned char * a_BiomeData)
+{
+ memcpy(m_ChunkBiomes, a_BiomeData, sizeof(m_ChunkBiomes));
+
+ return CALLBACK_CONTINUE;
+}
+
+
+
+
+
+bool cHeightBiomeMap::OnHeightMap(const int * a_HeightMapBE)
+{
+ for (int i = 0; i < ARRAYCOUNT(m_ChunkHeight); i++)
+ {
+ m_ChunkHeight[i] = ntohl(a_HeightMapBE[i]);
+ } // for i - m_ChunkHeight
+
+ return CALLBACK_CONTINUE;
+}
+
+
+
+
+
+bool cHeightBiomeMap::OnSection(
+ unsigned char a_Y,
+ const BLOCKTYPE * a_BlockTypes,
+ const NIBBLETYPE * a_BlockAdditional,
+ const NIBBLETYPE * a_BlockMeta,
+ const NIBBLETYPE * a_BlockLight,
+ const NIBBLETYPE * a_BlockSkyLight
+)
+{
+ // Copy the section data into the appropriate place in the internal buffer
+ memcpy(m_BlockTypes + a_Y * 16 * 16 * 16, a_BlockTypes, 16 * 16 * 16);
+ return CALLBACK_CONTINUE;
+}
+
+
+
+
+
+bool cHeightBiomeMap::OnSectionsFinished(void)
+{
+ static const int BiomePalette[] =
+ {
+ // ARGB:
+ 0xff0000ff, /* Ocean */
+ 0xff00cf3f, /* Plains */
+ 0xffffff00, /* Desert */
+ 0xff7f7f7f, /* Extreme Hills */
+ 0xff00cf00, /* Forest */
+ 0xff007f3f, /* Taiga */
+ 0xff3f7f00, /* Swampland */
+ 0xff003fff, /* River */
+ 0xff7f0000, /* Hell */
+ 0xff007fff, /* Sky */
+ 0xff3f3fff, /* Frozen Ocean */
+ 0xff3f3fff, /* Frozen River */
+ 0xff7fffcf, /* Ice Plains */
+ 0xff3fcf7f, /* Ice Mountains */
+ 0xffcf00cf, /* Mushroom Island */
+ 0xff7f00ff, /* Mushroom Island Shore */
+ 0xffffff3f, /* Beach */
+ 0xffcfcf00, /* Desert Hills */
+ 0xff00cf3f, /* Forest Hills */
+ 0xff006f1f, /* Taiga Hills */
+ 0xff7f8f7f, /* Extreme Hills Edge */
+ 0xff004f00, /* Jungle */
+ 0xff003f00, /* Jungle Hills */
+ } ;
+
+ // Remove trees and other unwanted stuff from the heightmap:
+ for (int z = 0; z < 16; z++)
+ {
+ int PixelLine[16]; // line of 16 pixels that is used as a buffer for setting the image pixels
+ for (int x = 0; x < 16; x++)
+ {
+ int Height = m_ChunkHeight[16 * z + x];
+ for (int y = Height; y >= 0; y--)
+ {
+ if (cHeightMap::IsGround(m_BlockTypes[256 * y + 16 * z + x]))
+ {
+ Height = y;
+ break; // for y
+ }
+ } // for y
+
+ // Set the color based on the biome and height:
+ char Biome = m_ChunkBiomes[16 * z + x];
+ PixelLine[x] = ShadeColor(BiomePalette[Biome], Height);
+ } // for x
+
+ // Set the pixelline into the image:
+ SetPixelURow(m_CurrentChunkRelX * 16, m_CurrentChunkRelZ * 16 + z, 16, PixelLine);
+ } // for z
+ return CALLBACK_ABORT;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cHeightBiomeMapFactory:
+
+cHeightBiomeMapFactory::~cHeightBiomeMapFactory()
+{
+ // Get the min and max region coords:
+ int MinRegionX = 100000;
+ int MaxRegionX = -100000;
+ int MinRegionZ = 100000;
+ int MaxRegionZ = -100000;
+ for (cCallbacks::iterator itr = m_Callbacks.begin(), end = m_Callbacks.end(); itr != end; ++itr)
+ {
+ cHeightBiomeMap * cb = (cHeightBiomeMap *)(*itr);
+ if (cb->m_MinRegionX < MinRegionX)
+ {
+ MinRegionX = cb->m_MinRegionX;
+ }
+ if (cb->m_MaxRegionX > MaxRegionX)
+ {
+ MaxRegionX = cb->m_MaxRegionX;
+ }
+ if (cb->m_MinRegionZ < MinRegionZ)
+ {
+ MinRegionZ = cb->m_MinRegionZ;
+ }
+ if (cb->m_MaxRegionZ > MaxRegionZ)
+ {
+ MaxRegionZ = cb->m_MaxRegionZ;
+ }
+ }
+
+ // If the size is small enough, write an HTML file referencing all the images in a table:
+ if ((MaxRegionX >= MinRegionX) && (MaxRegionZ >= MinRegionZ) && (MaxRegionX - MinRegionX < 100) && (MaxRegionZ - MinRegionZ < 100))
+ {
+ cFile HTML("HeBi.html", cFile::fmWrite);
+ if (HTML.IsOpen())
+ {
+ HTML.Printf("<html><body><table cellspacing=0 cellpadding=0>\n");
+ for (int z = MinRegionZ; z <= MaxRegionZ; z++)
+ {
+ HTML.Printf("<tr>");
+ for (int x = MinRegionX; x <= MaxRegionX; x++)
+ {
+ HTML.Printf("<td><img src=\"HeBi.%d.%d.bmp\" /></td>", x, z);
+ }
+ HTML.Printf("</tr>\n");
+ }
+ HTML.Printf("</table></body></html>");
+ }
+ }
+}
+
+
+
+
diff --git a/Tools/AnvilStats/HeightBiomeMap.h b/Tools/AnvilStats/HeightBiomeMap.h
new file mode 100644
index 000000000..d38fa4733
--- /dev/null
+++ b/Tools/AnvilStats/HeightBiomeMap.h
@@ -0,0 +1,81 @@
+
+// HeightBiomeMap.h
+
+// Declares the cHeightBiomeMap class representing a stats module that produces an image of heights and biomes combined
+
+
+
+
+
+#pragma once
+
+#include "ImageComposingCallback.h"
+
+
+
+
+
+class cHeightBiomeMap :
+ public cImageComposingCallback
+{
+ typedef cImageComposingCallback super;
+
+public:
+ // Minima and maxima for the regions processed through this callback
+ int m_MinRegionX, m_MaxRegionX;
+ int m_MinRegionZ, m_MaxRegionZ;
+
+ cHeightBiomeMap(void);
+
+protected:
+ int m_CurrentChunkX; // Absolute chunk coords
+ int m_CurrentChunkZ;
+ int m_CurrentChunkRelX; // Chunk offset from the start of the region
+ int m_CurrentChunkRelZ;
+
+ char m_ChunkBiomes[16 * 16]; ///< Biome-map for the current chunk
+ int m_ChunkHeight[16 * 16]; ///< Height-map for the current chunk
+ BLOCKTYPE m_BlockTypes [16 * 16 * 256]; ///< Block data for the current chunk (between OnSection() and OnSectionsFinished() )
+
+ // cCallback overrides:
+ virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) override;
+ virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) override;
+ virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) override { return CALLBACK_CONTINUE; }
+ virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) override { return CALLBACK_CONTINUE; }
+ virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) override { return CALLBACK_CONTINUE; }
+ virtual bool OnRealCoords(int a_ChunkX, int a_ChunkZ) override { return CALLBACK_CONTINUE; }
+ virtual bool OnLastUpdate(Int64 a_LastUpdate) override { return CALLBACK_CONTINUE; }
+ virtual bool OnTerrainPopulated(bool a_Populated) override { return a_Populated ? CALLBACK_CONTINUE : CALLBACK_ABORT; } // If not populated, we don't want it!
+ virtual bool OnBiomes(const unsigned char * a_BiomeData) override;
+ virtual bool OnHeightMap(const int * a_HeightMapBE) override;
+ virtual bool OnSection(
+ unsigned char a_Y,
+ const BLOCKTYPE * a_BlockTypes,
+ const NIBBLETYPE * a_BlockAdditional,
+ const NIBBLETYPE * a_BlockMeta,
+ const NIBBLETYPE * a_BlockLight,
+ const NIBBLETYPE * a_BlockSkyLight
+ ) override;
+ virtual bool OnSectionsFinished(void) override;
+
+} ;
+
+
+
+
+
+class cHeightBiomeMapFactory :
+ public cCallbackFactory
+{
+public:
+ virtual ~cHeightBiomeMapFactory();
+
+ virtual cCallback * CreateNewCallback(void) override
+ {
+ return new cHeightBiomeMap;
+ }
+} ;
+
+
+
+
diff --git a/Tools/AnvilStats/HeightMap.h b/Tools/AnvilStats/HeightMap.h
index c0e71cbc1..e1d73f300 100644
--- a/Tools/AnvilStats/HeightMap.h
+++ b/Tools/AnvilStats/HeightMap.h
@@ -23,6 +23,8 @@ public:
void Finish(void);
+ static bool IsGround(BLOCKTYPE a_BlockType);
+
protected:
int m_CurrentChunkX; // Absolute chunk coords
int m_CurrentChunkZ;
@@ -55,8 +57,6 @@ protected:
virtual bool OnSectionsFinished(void) override;
void StartNewRegion(int a_RegionX, int a_RegionZ);
-
- static bool IsGround(BLOCKTYPE a_BlockType);
} ;
diff --git a/Tools/AnvilStats/ImageComposingCallback.cpp b/Tools/AnvilStats/ImageComposingCallback.cpp
new file mode 100644
index 000000000..eb43ad49f
--- /dev/null
+++ b/Tools/AnvilStats/ImageComposingCallback.cpp
@@ -0,0 +1,219 @@
+
+// ImageComposingCallback.cpp
+
+// Implements the cImageComposingCallback class that implements a subset of cCallback for composing per-region images
+
+#include "Globals.h"
+#include "ImageComposingCallback.h"
+
+
+
+
+
+cImageComposingCallback::cImageComposingCallback(const AString & a_FileNamePrefix) :
+ m_FileNamePrefix(a_FileNamePrefix),
+ m_CurrentRegionX(INVALID_REGION_COORD),
+ m_CurrentRegionZ(INVALID_REGION_COORD),
+ m_ImageData(new int[32 * 16 * 32 * 16])
+{
+}
+
+
+
+
+
+cImageComposingCallback::~cImageComposingCallback()
+{
+ delete[] m_ImageData;
+}
+
+
+
+
+
+bool cImageComposingCallback::OnNewRegion(int a_RegionX, int a_RegionZ)
+{
+ ASSERT(m_CurrentRegionX == INVALID_REGION_COORD);
+ ASSERT(m_CurrentRegionZ == INVALID_REGION_COORD); // Has any previous region been finished properly?
+
+ m_CurrentRegionX = a_RegionX;
+ m_CurrentRegionZ = a_RegionZ;
+ OnEraseImage();
+
+ return CALLBACK_CONTINUE;
+}
+
+
+
+
+
+void cImageComposingCallback::OnRegionFinished(int a_RegionX, int a_RegionZ)
+{
+ ASSERT(m_CurrentRegionX != INVALID_REGION_COORD);
+ ASSERT(m_CurrentRegionZ != INVALID_REGION_COORD); // Has a region been started properly?
+ ASSERT(m_CurrentRegionX == a_RegionX);
+ ASSERT(m_CurrentRegionZ == a_RegionZ); // Is it the same region that has been started?
+
+ AString FileName = GetFileName(a_RegionX, a_RegionZ);
+ if (!FileName.empty())
+ {
+ OnBeforeImageSaved(a_RegionX, a_RegionZ, FileName);
+ SaveImage(FileName);
+ OnAfterImageSaved(a_RegionX, a_RegionZ, FileName);
+ }
+
+ m_CurrentRegionX = INVALID_REGION_COORD;
+ m_CurrentRegionZ = INVALID_REGION_COORD;
+}
+
+
+
+
+
+AString cImageComposingCallback::GetFileName(int a_RegionX, int a_RegionZ)
+{
+ return Printf("%s.%d.%d.bmp", m_FileNamePrefix.c_str(), a_RegionX, a_RegionZ);
+}
+
+
+
+
+
+void cImageComposingCallback::OnEraseImage(void)
+{
+ // By default erase the image to black:
+ EraseImage(0);
+}
+
+
+
+
+
+void cImageComposingCallback::EraseImage(int a_Color)
+{
+ for (int i = 0; i < PIXEL_COUNT; i++)
+ {
+ m_ImageData[i] = a_Color;
+ }
+}
+
+
+
+
+
+void cImageComposingCallback::EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ)
+{
+ int Base = a_RelChunkZ * IMAGE_HEIGHT + a_RelChunkX * 16;
+ for (int v = 0; v < 16; v++)
+ {
+ int BaseV = Base + v * IMAGE_HEIGHT;
+ for (int u = 0; u < 16; u++)
+ {
+ m_ImageData[BaseV + u] = a_Color;
+ }
+ } // for y
+}
+
+
+
+
+
+void cImageComposingCallback::SetPixel(int a_RelU, int a_RelV, int a_Color)
+{
+ ASSERT((a_RelU >= 0) && (a_RelU < IMAGE_WIDTH));
+ ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT));
+
+ m_ImageData[a_RelU + IMAGE_WIDTH * a_RelV] = a_Color;
+}
+
+
+
+
+
+int cImageComposingCallback::GetPixel(int a_RelU, int a_RelV)
+{
+ if ((a_RelU < 0) || (a_RelU >= IMAGE_WIDTH) || (a_RelV < 0) || (a_RelV >= IMAGE_HEIGHT))
+ {
+ // Outside the image data
+ return -1;
+ }
+
+ return m_ImageData[a_RelU + IMAGE_WIDTH * a_RelV];
+}
+
+
+
+
+
+
+void cImageComposingCallback::SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels)
+{
+ ASSERT((a_RelUStart >= 0) && (a_RelUStart + a_CountU <= IMAGE_WIDTH));
+ ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT));
+ ASSERT(a_Pixels != NULL);
+
+ int Base = a_RelUStart + a_RelV * IMAGE_WIDTH;
+ for (int u = 0; u < a_CountU; u++)
+ {
+ m_ImageData[Base + u] = a_Pixels[u];
+ }
+}
+
+
+
+
+
+int cImageComposingCallback::ShadeColor(int a_Color, int a_Shade)
+{
+ if (a_Shade < 64)
+ {
+ return MixColor(0, a_Color, a_Shade * 4);
+ }
+ return MixColor(a_Color, 0xffffff, (a_Shade - 64) * 4);
+}
+
+
+
+
+
+int cImageComposingCallback::MixColor(int a_Src, int a_Dest, int a_Amount)
+{
+ int r = a_Src & 0xff;
+ int g = (a_Src >> 8) & 0xff;
+ int b = (a_Src >> 16) & 0xff;
+ int rd = a_Dest & 0xff;
+ int gd = (a_Dest >> 8) & 0xff;
+ int bd = (a_Dest >> 16) & 0xff;
+ int nr = r + (rd - r) * a_Amount / 256;
+ int ng = g + (gd - g) * a_Amount / 256;
+ int nb = b + (bd - b) * a_Amount / 256;
+ return nr | (ng << 8) | (nb << 16);
+}
+
+
+
+
+void cImageComposingCallback::SaveImage(const AString & a_FileName)
+{
+ cFile f(a_FileName, cFile::fmWrite);
+ if (!f.IsOpen())
+ {
+ return;
+ }
+
+ // Header for BMP files (is the same for the same-size files)
+ static const unsigned char BMPHeader[] =
+ {
+ 0x42, 0x4D, 0x36, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ } ;
+
+ f.Write(BMPHeader, sizeof(BMPHeader));
+ f.Write(m_ImageData, PIXEL_COUNT * 4);
+}
+
+
+
+
diff --git a/Tools/AnvilStats/ImageComposingCallback.h b/Tools/AnvilStats/ImageComposingCallback.h
new file mode 100644
index 000000000..2936361d6
--- /dev/null
+++ b/Tools/AnvilStats/ImageComposingCallback.h
@@ -0,0 +1,105 @@
+
+// ImageComposingCallback
+
+// Declares the cImageComposingCallback class that implements a subset of cCallback for composing per-region images
+
+
+
+
+
+#pragma once
+
+#include "Callback.h"
+
+
+
+
+/** Implements the plumbing for composing per-region images from multiple chunks.
+To use this class, create a descendant that writes the image data using
+SetPixel() or SetPixelURow() functions.
+
+For the purpose of this class the image data is indexed U (horz) * V (vert), to avoid confusion with other coords.
+The image is a 32bpp raw imagedata, written into a BMP file.
+*/
+class cImageComposingCallback :
+ public cCallback
+{
+public:
+ enum
+ {
+ INVALID_REGION_COORD = 99999, ///< Used for un-assigned region coords
+ IMAGE_WIDTH = 32 * 16,
+ IMAGE_HEIGHT = 32 * 16,
+ PIXEL_COUNT = IMAGE_WIDTH * IMAGE_HEIGHT, ///< Total pixel count of the image data
+ } ;
+
+ cImageComposingCallback(const AString & a_FileNamePrefix);
+ virtual ~cImageComposingCallback();
+
+ // cCallback overrides:
+ virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) override;
+ virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) override;
+
+ // New introduced overridable functions:
+
+ /// Called when a file is about to be saved, to generate the filename
+ virtual AString GetFileName(int a_RegionX, int a_RegionZ);
+
+ /// Called before the file is saved
+ virtual void OnBeforeImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {}
+
+ /// Called after the image is saved to a file
+ virtual void OnAfterImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {}
+
+ /// Called when a new region is beginning, to erase the image data
+ virtual void OnEraseImage(void);
+
+ // Functions for manipulating the image:
+
+ /// Erases the entire image with the specified color
+ void EraseImage(int a_Color);
+
+ /// Erases the specified chunk's portion of the image with the specified color. Note that chunk coords are relative to the current region
+ void EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ);
+
+ /// Returns the current region X coord
+ int GetCurrentRegionX(void) const { return m_CurrentRegionX; }
+
+ /// Returns the current region Z coord
+ int GetCurrentRegionZ(void) const { return m_CurrentRegionZ; }
+
+ /// Sets the pixel at the specified UV coords to the specified color
+ void SetPixel(int a_RelU, int a_RelV, int a_Color);
+
+ /// Returns the color of the pixel at the specified UV coords; -1 if outside
+ int GetPixel(int a_RelU, int a_RelV);
+
+ /// Sets a row of pixels. a_Pixels is expected to be a_CountU pixels wide. a_RelUStart + a_CountU is assumed less than image width
+ void SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels);
+
+ /** "Shades" the given color based on the shade amount given
+ Shade amount 0 .. 63 shades the color from black to a_Color.
+ Shade amount 64 .. 127 shades the color from a_Color to white.
+ All other shade amounts have undefined results.
+ */
+ static int ShadeColor(int a_Color, int a_Shade);
+
+ /// Mixes the two colors in the specified ratio; a_Ratio is between 0 and 256, 0 returning a_Src
+ static int MixColor(int a_Src, int a_Dest, int a_Ratio);
+
+protected:
+ /// Prefix for the filenames, when generated by the default GetFileName() function
+ AString m_FileNamePrefix;
+
+ /// Coords of the currently processed region
+ int m_CurrentRegionX, m_CurrentRegionZ;
+
+ /// Raw image data; 1 MiB worth of data, therefore unsuitable for stack allocation. [u + IMAGE_WIDTH * v]
+ int * m_ImageData;
+
+ void SaveImage(const AString & a_FileName);
+} ;
+
+
+
+
diff --git a/Tools/AnvilStats/Processor.cpp b/Tools/AnvilStats/Processor.cpp
index e7f7eb21d..8e1cc4c4b 100644
--- a/Tools/AnvilStats/Processor.cpp
+++ b/Tools/AnvilStats/Processor.cpp
@@ -76,6 +76,12 @@ void cProcessor::cThread::ProcessFile(const AString & a_FileName)
return;
}
+ if (m_Callback.OnNewRegion(RegionX, RegionZ))
+ {
+ // Callback doesn't want the region file processed
+ return;
+ }
+
cFile f;
if (!f.Open(a_FileName, cFile::fmRead))
{
@@ -92,6 +98,8 @@ void cProcessor::cThread::ProcessFile(const AString & a_FileName)
}
ProcessFileData(FileContents.data(), FileContents.size(), RegionX * 32, RegionZ * 32);
+
+ m_Callback.OnRegionFinished(RegionX, RegionZ);
}
diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp
index 4c2b0d4e9..70dd6acd8 100644
--- a/Tools/ProtoProxy/Connection.cpp
+++ b/Tools/ProtoProxy/Connection.cpp
@@ -201,6 +201,9 @@ enum
PACKET_ENCRYPTION_KEY_REQUEST = 0xfd,
PACKET_PING = 0xfe,
PACKET_KICK = 0xff,
+
+ // Synonyms:
+ PACKET_DISCONNECT = PACKET_KICK,
} ;
@@ -238,7 +241,7 @@ cConnection::cConnection(SOCKET a_ClientSocket, cServer & a_Server) :
m_Server(a_Server),
m_ClientSocket(a_ClientSocket),
m_ServerSocket(-1),
- m_BeginTick(clock()),
+ m_BeginTick(m_Timer.GetNowTime()),
m_ClientState(csUnencrypted),
m_ServerState(csUnencrypted),
m_Nonce(0),
@@ -475,8 +478,7 @@ bool cConnection::RelayFromClient(void)
double cConnection::GetRelativeTime(void)
{
- return (double)(clock() - m_BeginTick) / CLOCKS_PER_SEC;
-
+ return (double)(m_Timer.GetNowTime() - m_BeginTick) / 1000;
}
@@ -558,9 +560,9 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
while (m_ClientBuffer.CanReadBytes(1))
{
- Log("Decoding client's packets, there are now %d bytes in the queue", m_ClientBuffer.GetReadableSpace());
unsigned char PacketType;
m_ClientBuffer.ReadByte(PacketType);
+ Log("Decoding client's packets, there are now %d bytes in the queue; next packet is 0x%02x", m_ClientBuffer.GetReadableSpace(), PacketType);
switch (PacketType)
{
case PACKET_BLOCK_DIG: HANDLE_CLIENT_READ(HandleClientBlockDig); break;
@@ -568,6 +570,7 @@ bool cConnection::DecodeClientsPackets(const char * a_Data, int a_Size)
case PACKET_CHAT_MESSAGE: HANDLE_CLIENT_READ(HandleClientChatMessage); break;
case PACKET_CLIENT_STATUSES: HANDLE_CLIENT_READ(HandleClientClientStatuses); break;
case PACKET_CREATIVE_INVENTORY_ACTION: HANDLE_CLIENT_READ(HandleClientCreativeInventoryAction); break;
+ case PACKET_DISCONNECT: HANDLE_CLIENT_READ(HandleClientDisconnect); break;
case PACKET_ENCRYPTION_KEY_RESPONSE: HANDLE_CLIENT_READ(HandleClientEncryptionKeyResponse); break;
case PACKET_ENTITY_ACTION: HANDLE_CLIENT_READ(HandleClientEntityAction); break;
case PACKET_HANDSHAKE: HANDLE_CLIENT_READ(HandleClientHandshake); break;
@@ -644,7 +647,7 @@ bool cConnection::DecodeServersPackets(const char * a_Data, int a_Size)
{
unsigned char PacketType;
m_ServerBuffer.ReadByte(PacketType);
- Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%x", m_ServerBuffer.GetReadableSpace(), PacketType);
+ Log("Decoding server's packets, there are now %d bytes in the queue; next packet is 0x%02x", m_ServerBuffer.GetReadableSpace(), PacketType);
LogFlush();
switch (PacketType)
{
@@ -843,6 +846,19 @@ bool cConnection::HandleClientCreativeInventoryAction(void)
+bool cConnection::HandleClientDisconnect(void)
+{
+ HANDLE_CLIENT_PACKET_READ(ReadBEUTF16String16, AString, Reason);
+ Log("Received a PACKET_DISCONNECT from the client:");
+ Log(" Reason = \"%s\"", Reason.c_str());
+ COPY_TO_SERVER();
+ return true;
+}
+
+
+
+
+
bool cConnection::HandleClientEncryptionKeyResponse(void)
{
HANDLE_CLIENT_PACKET_READ(ReadBEShort, short, EncKeyLength);
@@ -1704,16 +1720,45 @@ bool cConnection::HandleServerMapChunkBulk(void)
{
return false;
}
- AString Meta;
- if (!m_ServerBuffer.ReadString(Meta, ChunkCount * 12))
+
+ // Read individual chunk metas.
+ // Need to read them first and only then start logging (in case we don't have the full packet yet)
+ struct sChunkMeta
{
- return false;
+ int m_ChunkX, m_ChunkZ;
+ short m_PrimaryBitmap;
+ short m_AddBitmap;
+ sChunkMeta(int a_ChunkX, int a_ChunkZ, short a_PrimaryBitmap, short a_AddBitmap) :
+ m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ), m_PrimaryBitmap(a_PrimaryBitmap), m_AddBitmap(a_AddBitmap)
+ {
+ }
+ } ;
+ typedef std::vector<sChunkMeta> sChunkMetas;
+ sChunkMetas ChunkMetas;
+ ChunkMetas.reserve(ChunkCount);
+ for (short i = 0; i < ChunkCount; i++)
+ {
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkX);
+ HANDLE_SERVER_PACKET_READ(ReadBEInt, int, ChunkZ);
+ HANDLE_SERVER_PACKET_READ(ReadBEShort, short, PrimaryBitmap);
+ HANDLE_SERVER_PACKET_READ(ReadBEShort, short, AddBitmap);
+ ChunkMetas.push_back(sChunkMeta(ChunkX, ChunkZ, PrimaryBitmap, AddBitmap));
}
+
Log("Received a PACKET_MAP_CHUNK_BULK from the server:");
Log(" ChunkCount = %d", ChunkCount);
Log(" Compressed size = %d (0x%x)", CompressedSize, CompressedSize);
Log(" IsSkyLightSent = %s", IsSkyLightSent ? "true" : "false");
+ // Log individual chunk coords:
+ int idx = 0;
+ for (sChunkMetas::iterator itr = ChunkMetas.begin(), end = ChunkMetas.end(); itr != end; ++itr, ++idx)
+ {
+ Log(" [%d]: [%d, %d], primary bitmap 0x%02x, add bitmap 0x%02x",
+ idx, itr->m_ChunkX, itr->m_ChunkZ, itr->m_PrimaryBitmap, itr->m_AddBitmap
+ );
+ } // for itr - ChunkMetas[]
+
// TODO: Save the compressed data into a file for later analysis
COPY_TO_CLIENT();
diff --git a/Tools/ProtoProxy/Connection.h b/Tools/ProtoProxy/Connection.h
index 8d466c62d..c30a28727 100644
--- a/Tools/ProtoProxy/Connection.h
+++ b/Tools/ProtoProxy/Connection.h
@@ -9,8 +9,8 @@
#pragma once
-#include <time.h>
#include "ByteBuffer.h"
+#include "../../source/OSSupport/Timer.h"
@@ -35,7 +35,8 @@ class cConnection
SOCKET m_ClientSocket;
SOCKET m_ServerSocket;
- clock_t m_BeginTick; // Tick when the relative time was first retrieved (used for GetRelativeTime())
+ cTimer m_Timer;
+ long long m_BeginTick; // Tick when the relative time was first retrieved (used for GetRelativeTime())
enum eConnectionState
{
@@ -115,6 +116,7 @@ protected:
bool HandleClientChatMessage(void);
bool HandleClientClientStatuses(void);
bool HandleClientCreativeInventoryAction(void);
+ bool HandleClientDisconnect(void);
bool HandleClientEncryptionKeyResponse(void);
bool HandleClientEntityAction(void);
bool HandleClientHandshake(void);
diff --git a/Tools/ProtoProxy/Globals.h b/Tools/ProtoProxy/Globals.h
index f2c47e96f..3b154b866 100644
--- a/Tools/ProtoProxy/Globals.h
+++ b/Tools/ProtoProxy/Globals.h
@@ -143,6 +143,7 @@ typedef short Int16;
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
+#include <time.h>
diff --git a/Tools/ProtoProxy/ProtoProxy.vcproj b/Tools/ProtoProxy/ProtoProxy.vcproj
index 695e01e76..926bbe586 100644
--- a/Tools/ProtoProxy/ProtoProxy.vcproj
+++ b/Tools/ProtoProxy/ProtoProxy.vcproj
@@ -256,6 +256,14 @@
RelativePath="..\..\source\StringUtils.h"
>
</File>
+ <File
+ RelativePath="..\..\source\OSSupport\Timer.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\source\OSSupport\Timer.h"
+ >
+ </File>
</Filter>
<File
RelativePath=".\ProtoProxy.txt"
diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj
index 16737e0ef..7ffa3c887 100644
--- a/VC2008/MCServer.vcproj
+++ b/VC2008/MCServer.vcproj
@@ -1160,6 +1160,14 @@
>
</File>
<File
+ RelativePath="..\source\Entities\ProjectileEntity.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\source\Entities\ProjectileEntity.h"
+ >
+ </File>
+ <File
RelativePath="..\source\Entities\TNTEntity.cpp"
>
</File>
@@ -2016,10 +2024,6 @@
>
</File>
<File
- RelativePath="..\source\Blocks\BlockDoubleSlab.h"
- >
- </File>
- <File
RelativePath="..\source\blocks\BlockDirt.h"
>
</File>
@@ -2236,6 +2240,10 @@
>
</File>
<File
+ RelativePath="..\source\Items\ItemBow.h"
+ >
+ </File>
+ <File
RelativePath="..\source\Items\ItemBrewingStand.h"
>
</File>
@@ -2340,6 +2348,10 @@
>
</File>
<File
+ RelativePath="..\source\Items\ItemThrowable.h"
+ >
+ </File>
+ <File
RelativePath="..\source\items\ItemWood.h"
>
</File>
diff --git a/docs/Login sequence.txt b/docs/Login sequence.txt
new file mode 100644
index 000000000..df9d386c6
--- /dev/null
+++ b/docs/Login sequence.txt
@@ -0,0 +1,26 @@
+
+This is the connection sequence of the 1.6.2 client to a vanilla server, after the encryption has been established:
+
+S->C: 0xfc (encryption key response) empty payload (4 * 0x00)
+C->S: 0xcd (client statuses)
+S->C: 0x01 (login)
+S->C: 0xfa (plugin message) - "MC|Brand": "vanilla"
+S->C: 0x06 (compass)
+S->C: 0xca (player capabilities)
+S->C: 0x10 (slot select)
+S->C: 0x04 (time update)
+S->C: 0xc9 (player list item)
+S->C: 0x0d (player pos + look)
+S->C: 0x04 (time update)
+S->C: 0x68 (window contents)
+S->C: 0x67 (slot contents) - Window -1, slot -1
+S->C: 0x67 (slot contents) - Window 0, slot 9 .. 44, only occupied slots
+S->C: 0x38 (chunk bulk)
+S->C: 0x28 (entity metadata) player metadata
+S->C: 0x2c (entity properties) player properties
+S->C: 0x04 (time update)
+S->C: 0x38 (chunk bulk)
+C->S: 0xcc (client settings / locale and view)
+C->S: 0xfa (plugin message) - "MC|Brand": "vanilla"
+C->S: 0x0d (player pos + look)
+S->C: 0x38 (chunk bulk) \ No newline at end of file
diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg
index 98c58ed0a..8d87be307 100644
--- a/source/AllToLua.pkg
+++ b/source/AllToLua.pkg
@@ -27,6 +27,8 @@ $cfile "ClientHandle.h"
$cfile "Entities/Entity.h"
$cfile "Entities/Pawn.h"
$cfile "Entities/Player.h"
+$cfile "Entities/Pickup.h"
+$cfile "Entities/ProjectileEntity.h"
$cfile "PluginManager.h"
$cfile "Plugin.h"
$cfile "PluginLua.h"
@@ -45,7 +47,6 @@ $cfile "BlockEntities/DropperEntity.h"
$cfile "BlockEntities/FurnaceEntity.h"
$cfile "WebAdmin.h"
$cfile "WebPlugin.h"
-$cfile "Entities/Pickup.h"
$cfile "Root.h"
$cfile "Vector3f.h"
$cfile "Vector3d.h"
diff --git a/source/Bindings.cpp b/source/Bindings.cpp
index effb9c6ed..d89592bcf 100644
--- a/source/Bindings.cpp
+++ b/source/Bindings.cpp
@@ -1,6 +1,6 @@
/*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 08/19/13 11:57:26.
+** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:04.
*/
#ifndef __cplusplus
@@ -27,6 +27,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
#include "Entities/Entity.h"
#include "Entities/Pawn.h"
#include "Entities/Player.h"
+#include "Entities/Pickup.h"
+#include "Entities/ProjectileEntity.h"
#include "PluginManager.h"
#include "Plugin.h"
#include "PluginLua.h"
@@ -45,7 +47,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
#include "BlockEntities/FurnaceEntity.h"
#include "WebAdmin.h"
#include "WebPlugin.h"
-#include "Entities/Pickup.h"
#include "Root.h"
#include "Vector3f.h"
#include "Vector3d.h"
@@ -202,9 +203,14 @@ static int tolua_collect_Vector3d (lua_State* tolua_S)
/* function to register type */
static void tolua_reg_types (lua_State* tolua_S)
{
+ tolua_usertype(tolua_S,"cThrownEnderPearlEntity");
tolua_usertype(tolua_S,"TakeDamageInfo");
+ tolua_usertype(tolua_S,"cPluginManager");
+ tolua_usertype(tolua_S,"cMonster");
+ tolua_usertype(tolua_S,"cCraftingGrid");
tolua_usertype(tolua_S,"cCraftingRecipe");
tolua_usertype(tolua_S,"cPlugin");
+ tolua_usertype(tolua_S,"cWindow");
tolua_usertype(tolua_S,"cStringMap");
tolua_usertype(tolua_S,"cItemGrid");
tolua_usertype(tolua_S,"cBlockArea");
@@ -212,51 +218,51 @@ static void tolua_reg_types (lua_State* tolua_S)
tolua_usertype(tolua_S,"cLuaWindow");
tolua_usertype(tolua_S,"cServer");
tolua_usertype(tolua_S,"cRoot");
- tolua_usertype(tolua_S,"cDropperEntity");
+ tolua_usertype(tolua_S,"cCuboid");
tolua_usertype(tolua_S,"std::vector<cIniFile::key>");
- tolua_usertype(tolua_S,"cMonster");
+ tolua_usertype(tolua_S,"cGroup");
tolua_usertype(tolua_S,"cPickup");
tolua_usertype(tolua_S,"std::vector<std::string>");
- tolua_usertype(tolua_S,"cWindow");
+ tolua_usertype(tolua_S,"cTracer");
tolua_usertype(tolua_S,"cClientHandle");
tolua_usertype(tolua_S,"cChunkDesc");
tolua_usertype(tolua_S,"cFurnaceRecipe");
- tolua_usertype(tolua_S,"cCraftingGrid");
- tolua_usertype(tolua_S,"cChatColor");
- tolua_usertype(tolua_S,"cGroup");
- tolua_usertype(tolua_S,"cTracer");
- tolua_usertype(tolua_S,"cCuboid");
tolua_usertype(tolua_S,"Vector3i");
- tolua_usertype(tolua_S,"cInventory");
+ tolua_usertype(tolua_S,"cChatColor");
+ tolua_usertype(tolua_S,"cThrownSnowballEntity");
+ tolua_usertype(tolua_S,"cWebAdmin");
+ tolua_usertype(tolua_S,"cCraftingRecipes");
+ tolua_usertype(tolua_S,"cItems");
+ tolua_usertype(tolua_S,"cWebPlugin");
tolua_usertype(tolua_S,"cItem");
tolua_usertype(tolua_S,"Vector3f");
- tolua_usertype(tolua_S,"cCraftingRecipes");
+ tolua_usertype(tolua_S,"cArrowEntity");
tolua_usertype(tolua_S,"cDropSpenserEntity");
- tolua_usertype(tolua_S,"cWorld");
- tolua_usertype(tolua_S,"cWebPlugin");
+ tolua_usertype(tolua_S,"sWebAdminPage");
+ tolua_usertype(tolua_S,"HTTPFormData");
tolua_usertype(tolua_S,"cChestEntity");
tolua_usertype(tolua_S,"cDispenserEntity");
- tolua_usertype(tolua_S,"cWebAdmin");
+ tolua_usertype(tolua_S,"HTTPRequest");
tolua_usertype(tolua_S,"cBlockEntity");
- tolua_usertype(tolua_S,"cCriticalSection");
+ tolua_usertype(tolua_S,"cItemGrid::cListener");
tolua_usertype(tolua_S,"HTTPTemplateRequest");
- tolua_usertype(tolua_S,"sWebAdminPage");
- tolua_usertype(tolua_S,"HTTPRequest");
- tolua_usertype(tolua_S,"HTTPFormData");
tolua_usertype(tolua_S,"cFurnaceEntity");
+ tolua_usertype(tolua_S,"cDropperEntity");
+ tolua_usertype(tolua_S,"cPluginLua");
+ tolua_usertype(tolua_S,"cBlockEntityWithItems");
tolua_usertype(tolua_S,"cLineBlockTracer");
- tolua_usertype(tolua_S,"cPluginManager");
+ tolua_usertype(tolua_S,"cCriticalSection");
tolua_usertype(tolua_S,"cIniFile");
- tolua_usertype(tolua_S,"cBlockEntityWithItems");
+ tolua_usertype(tolua_S,"cEntity");
tolua_usertype(tolua_S,"cListeners");
tolua_usertype(tolua_S,"cPawn");
- tolua_usertype(tolua_S,"cPlayer");
+ tolua_usertype(tolua_S,"cThrownEggEntity");
tolua_usertype(tolua_S,"cGroupManager");
tolua_usertype(tolua_S,"cBlockEntityWindowOwner");
- tolua_usertype(tolua_S,"cEntity");
- tolua_usertype(tolua_S,"cItemGrid::cListener");
- tolua_usertype(tolua_S,"cPluginLua");
- tolua_usertype(tolua_S,"cItems");
+ tolua_usertype(tolua_S,"cInventory");
+ tolua_usertype(tolua_S,"cProjectileEntity");
+ tolua_usertype(tolua_S,"cWorld");
+ tolua_usertype(tolua_S,"cPlayer");
tolua_usertype(tolua_S,"Vector3d");
}
@@ -3075,6 +3081,182 @@ static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* get function: g_BlockPistonBreakable */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable
+static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ tolua_pushboolean(tolua_S,(bool)g_BlockPistonBreakable[tolua_index]);
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* set function: g_BlockPistonBreakable */
+#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockPistonBreakable
+static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ g_BlockPistonBreakable[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0));
+ return 0;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* get function: g_BlockIsSnowable */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable
+static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ tolua_pushboolean(tolua_S,(bool)g_BlockIsSnowable[tolua_index]);
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* set function: g_BlockIsSnowable */
+#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSnowable
+static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ g_BlockIsSnowable[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0));
+ return 0;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* get function: g_BlockRequiresSpecialTool */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool
+static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ tolua_pushboolean(tolua_S,(bool)g_BlockRequiresSpecialTool[tolua_index]);
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* set function: g_BlockRequiresSpecialTool */
+#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockRequiresSpecialTool
+static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ g_BlockRequiresSpecialTool[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0));
+ return 0;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* get function: g_BlockIsSolid */
+#ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid
+static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ tolua_pushboolean(tolua_S,(bool)g_BlockIsSolid[tolua_index]);
+ return 1;
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* set function: g_BlockIsSolid */
+#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSolid
+static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S)
+{
+ int tolua_index;
+#ifndef TOLUA_RELEASE
+ {
+ tolua_Error tolua_err;
+ if (!tolua_isnumber(tolua_S,2,0,&tolua_err))
+ tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err);
+ }
+#endif
+ tolua_index = (int)tolua_tonumber(tolua_S,2,0);
+#ifndef TOLUA_RELEASE
+ if (tolua_index<0 || tolua_index>=256)
+ tolua_error(tolua_S,"array indexing out of range.",NULL);
+#endif
+ g_BlockIsSolid[tolua_index] = ((bool) tolua_toboolean(tolua_S,3,0));
+ return 0;
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* function: ClickActionToString */
#ifndef TOLUA_DISABLE_tolua_AllToLua_ClickActionToString00
static int tolua_AllToLua_ClickActionToString00(lua_State* tolua_S)
@@ -7471,6 +7653,92 @@ static int tolua_AllToLua_cPlayer_GetEquippedItem00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: GetThrowStartPos of class cPlayer */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetThrowStartPos00
+static int tolua_AllToLua_cPlayer_GetThrowStartPos00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetThrowStartPos'", NULL);
+#endif
+ {
+ Vector3d tolua_ret = (Vector3d) self->GetThrowStartPos();
+ {
+#ifdef __cplusplus
+ void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret));
+ tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+#else
+ void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d));
+ tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+#endif
+ }
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetThrowStartPos'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetThrowSpeed of class cPlayer */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetThrowSpeed00
+static int tolua_AllToLua_cPlayer_GetThrowSpeed00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0);
+ double a_SpeedCoeff = ((double) tolua_tonumber(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetThrowSpeed'", NULL);
+#endif
+ {
+ Vector3d tolua_ret = (Vector3d) self->GetThrowSpeed(a_SpeedCoeff);
+ {
+#ifdef __cplusplus
+ void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret));
+ tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+#else
+ void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d));
+ tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+#endif
+ }
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetThrowSpeed'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: GetGameMode of class cPlayer */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetGameMode00
static int tolua_AllToLua_cPlayer_GetGameMode00(lua_State* tolua_S)
@@ -8545,12 +8813,12 @@ static int tolua_AllToLua_cPlayer_SetFoodExhaustionLevel00(lua_State* tolua_S)
#endif
{
cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0);
- double a_FoodSaturationLevel = ((double) tolua_tonumber(tolua_S,2,0));
+ double a_FoodExhaustionLevel = ((double) tolua_tonumber(tolua_S,2,0));
#ifndef TOLUA_RELEASE
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetFoodExhaustionLevel'", NULL);
#endif
{
- self->SetFoodExhaustionLevel(a_FoodSaturationLevel);
+ self->SetFoodExhaustionLevel(a_FoodExhaustionLevel);
}
}
return 0;
@@ -9182,6 +9450,513 @@ static int tolua_AllToLua_cPlayer_IsSubmerged00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: new of class cPickup */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00
+static int tolua_AllToLua_cPickup_new00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) ||
+ !tolua_isnumber(tolua_S,6,1,&tolua_err) ||
+ !tolua_isnumber(tolua_S,7,1,&tolua_err) ||
+ !tolua_isnumber(tolua_S,8,1,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,9,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0));
+ int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0));
+ int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0));
+ const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0));
+ float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f));
+ float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f));
+ float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f));
+ {
+ cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ));
+ tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup");
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: new_local of class cPickup */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00_local
+static int tolua_AllToLua_cPickup_new00_local(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) ||
+ !tolua_isnumber(tolua_S,6,1,&tolua_err) ||
+ !tolua_isnumber(tolua_S,7,1,&tolua_err) ||
+ !tolua_isnumber(tolua_S,8,1,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,9,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0));
+ int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0));
+ int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0));
+ const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0));
+ float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f));
+ float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f));
+ float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f));
+ {
+ cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ));
+ tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetItem of class cPickup */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetItem00
+static int tolua_AllToLua_cPickup_GetItem00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetItem'", NULL);
+#endif
+ {
+ cItem& tolua_ret = (cItem&) self->GetItem();
+ tolua_pushusertype(tolua_S,(void*)&tolua_ret,"cItem");
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetItem'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: CollectedBy of class cPickup */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_CollectedBy00
+static int tolua_AllToLua_cPickup_CollectedBy00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) ||
+ !tolua_isusertype(tolua_S,2,"cPlayer",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0);
+ cPlayer* a_Dest = ((cPlayer*) tolua_tousertype(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CollectedBy'", NULL);
+#endif
+ {
+ bool tolua_ret = (bool) self->CollectedBy(a_Dest);
+ tolua_pushboolean(tolua_S,(bool)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'CollectedBy'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetAge of class cPickup */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetAge00
+static int tolua_AllToLua_cPickup_GetAge00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetAge'", NULL);
+#endif
+ {
+ int tolua_ret = (int) self->GetAge();
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetAge'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: IsCollected of class cPickup */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_IsCollected00
+static int tolua_AllToLua_cPickup_IsCollected00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsCollected'", NULL);
+#endif
+ {
+ bool tolua_ret = (bool) self->IsCollected();
+ tolua_pushboolean(tolua_S,(bool)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'IsCollected'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetProjectileKind of class cProjectileEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetProjectileKind00
+static int tolua_AllToLua_cProjectileEntity_GetProjectileKind00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cProjectileEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cProjectileEntity* self = (const cProjectileEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetProjectileKind'", NULL);
+#endif
+ {
+ cProjectileEntity::eKind tolua_ret = (cProjectileEntity::eKind) self->GetProjectileKind();
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetProjectileKind'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetCreator of class cProjectileEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetCreator00
+static int tolua_AllToLua_cProjectileEntity_GetCreator00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cProjectileEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cProjectileEntity* self = (cProjectileEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetCreator'", NULL);
+#endif
+ {
+ cEntity* tolua_ret = (cEntity*) self->GetCreator();
+ tolua_pushusertype(tolua_S,(void*)tolua_ret,"cEntity");
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetCreator'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetMCAClassName of class cProjectileEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetMCAClassName00
+static int tolua_AllToLua_cProjectileEntity_GetMCAClassName00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cProjectileEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cProjectileEntity* self = (const cProjectileEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMCAClassName'", NULL);
+#endif
+ {
+ AString tolua_ret = (AString) self->GetMCAClassName();
+ tolua_pushcppstring(tolua_S,(const char*)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetMCAClassName'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: IsInGround of class cProjectileEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_IsInGround00
+static int tolua_AllToLua_cProjectileEntity_IsInGround00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cProjectileEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cProjectileEntity* self = (const cProjectileEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsInGround'", NULL);
+#endif
+ {
+ bool tolua_ret = (bool) self->IsInGround();
+ tolua_pushboolean(tolua_S,(bool)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'IsInGround'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetPickupState of class cArrowEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_GetPickupState00
+static int tolua_AllToLua_cArrowEntity_GetPickupState00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPickupState'", NULL);
+#endif
+ {
+ cArrowEntity::ePickupState tolua_ret = (cArrowEntity::ePickupState) self->GetPickupState();
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetPickupState'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: SetPickupState of class cArrowEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_SetPickupState00
+static int tolua_AllToLua_cArrowEntity_SetPickupState00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cArrowEntity",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cArrowEntity* self = (cArrowEntity*) tolua_tousertype(tolua_S,1,0);
+ cArrowEntity::ePickupState a_PickupState = ((cArrowEntity::ePickupState) (int) tolua_tonumber(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetPickupState'", NULL);
+#endif
+ {
+ self->SetPickupState(a_PickupState);
+ }
+ }
+ return 0;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'SetPickupState'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: GetDamageCoeff of class cArrowEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_GetDamageCoeff00
+static int tolua_AllToLua_cArrowEntity_GetDamageCoeff00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetDamageCoeff'", NULL);
+#endif
+ {
+ double tolua_ret = (double) self->GetDamageCoeff();
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetDamageCoeff'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: SetDamageCoeff of class cArrowEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_SetDamageCoeff00
+static int tolua_AllToLua_cArrowEntity_SetDamageCoeff00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cArrowEntity",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cArrowEntity* self = (cArrowEntity*) tolua_tousertype(tolua_S,1,0);
+ double a_DamageCoeff = ((double) tolua_tonumber(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetDamageCoeff'", NULL);
+#endif
+ {
+ self->SetDamageCoeff(a_DamageCoeff);
+ }
+ }
+ return 0;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'SetDamageCoeff'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: CanPickup of class cArrowEntity */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_CanPickup00
+static int tolua_AllToLua_cArrowEntity_CanPickup00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cArrowEntity",0,&tolua_err) ||
+ (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cPlayer",0,&tolua_err)) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cArrowEntity* self = (const cArrowEntity*) tolua_tousertype(tolua_S,1,0);
+ const cPlayer* a_Player = ((const cPlayer*) tolua_tousertype(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CanPickup'", NULL);
+#endif
+ {
+ bool tolua_ret = (bool) self->CanPickup(*a_Player);
+ tolua_pushboolean(tolua_S,(bool)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'CanPickup'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: Get of class cPluginManager */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_Get00
static int tolua_AllToLua_cPluginManager_Get00(lua_State* tolua_S)
@@ -9307,41 +10082,6 @@ static int tolua_AllToLua_cPluginManager_ReloadPlugins00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
-/* method: AddHook of class cPluginManager */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_AddHook00
-static int tolua_AllToLua_cPluginManager_AddHook00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) ||
- !tolua_isusertype(tolua_S,2,"cPlugin",0,&tolua_err) ||
- !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,4,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0);
- cPlugin* a_Plugin = ((cPlugin*) tolua_tousertype(tolua_S,2,0));
- cPluginManager::PluginHook a_Hook = ((cPluginManager::PluginHook) (int) tolua_tonumber(tolua_S,3,0));
-#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddHook'", NULL);
-#endif
- {
- self->AddHook(a_Plugin,a_Hook);
- }
- }
- return 0;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'AddHook'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
/* method: GetNumPlugins of class cPluginManager */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cPluginManager_GetNumPlugins00
static int tolua_AllToLua_cPluginManager_GetNumPlugins00(lua_State* tolua_S)
@@ -10543,6 +11283,95 @@ static int tolua_AllToLua_cWorld_BroadcastChat00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: BroadcastSoundEffect of class cWorld */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_BroadcastSoundEffect00
+static int tolua_AllToLua_cWorld_BroadcastSoundEffect00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
+ !tolua_iscppstring(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,5,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,6,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,7,0,&tolua_err) ||
+ !tolua_isusertype(tolua_S,8,"const cClientHandle",1,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,9,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
+ const AString a_SoundName = ((const AString) tolua_tocppstring(tolua_S,2,0));
+ int a_SrcX = ((int) tolua_tonumber(tolua_S,3,0));
+ int a_SrcY = ((int) tolua_tonumber(tolua_S,4,0));
+ int a_SrcZ = ((int) tolua_tonumber(tolua_S,5,0));
+ float a_Volume = ((float) tolua_tonumber(tolua_S,6,0));
+ float a_Pitch = ((float) tolua_tonumber(tolua_S,7,0));
+ const cClientHandle* a_Exclude = ((const cClientHandle*) tolua_tousertype(tolua_S,8,NULL));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'BroadcastSoundEffect'", NULL);
+#endif
+ {
+ self->BroadcastSoundEffect(a_SoundName,a_SrcX,a_SrcY,a_SrcZ,a_Volume,a_Pitch,a_Exclude);
+ tolua_pushcppstring(tolua_S,(const char*)a_SoundName);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'BroadcastSoundEffect'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
+/* method: BroadcastSoundParticleEffect of class cWorld */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00
+static int tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,5,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,6,0,&tolua_err) ||
+ !tolua_isusertype(tolua_S,7,"const cClientHandle",1,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,8,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
+ int a_EffectID = ((int) tolua_tonumber(tolua_S,2,0));
+ int a_SrcX = ((int) tolua_tonumber(tolua_S,3,0));
+ int a_SrcY = ((int) tolua_tonumber(tolua_S,4,0));
+ int a_SrcZ = ((int) tolua_tonumber(tolua_S,5,0));
+ int a_Data = ((int) tolua_tonumber(tolua_S,6,0));
+ const cClientHandle* a_Exclude = ((const cClientHandle*) tolua_tousertype(tolua_S,7,NULL));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'BroadcastSoundParticleEffect'", NULL);
+#endif
+ {
+ self->BroadcastSoundParticleEffect(a_EffectID,a_SrcX,a_SrcY,a_SrcZ,a_Data,a_Exclude);
+ }
+ }
+ return 0;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'BroadcastSoundParticleEffect'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: UnloadUnusedChunks of class cWorld */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_UnloadUnusedChunks00
static int tolua_AllToLua_cWorld_UnloadUnusedChunks00(lua_State* tolua_S)
@@ -11982,6 +12811,38 @@ static int tolua_AllToLua_cWorld_GetName00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: GetIniFileName of class cWorld */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetIniFileName00
+static int tolua_AllToLua_cWorld_GetIniFileName00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,2,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const cWorld* self = (const cWorld*) tolua_tousertype(tolua_S,1,0);
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetIniFileName'", NULL);
+#endif
+ {
+ const AString tolua_ret = (const AString) self->GetIniFileName();
+ tolua_pushcppstring(tolua_S,(const char*)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'GetIniFileName'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: SaveAllChunks of class cWorld */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SaveAllChunks00
static int tolua_AllToLua_cWorld_SaveAllChunks00(lua_State* tolua_S)
@@ -12555,6 +13416,50 @@ static int tolua_AllToLua_cWorld_SpawnMob00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
+/* method: CreateProjectile of class cWorld */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_CreateProjectile00
+static int tolua_AllToLua_cWorld_CreateProjectile00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,5,0,&tolua_err) ||
+ !tolua_isusertype(tolua_S,6,"cEntity",0,&tolua_err) ||
+ !tolua_isusertype(tolua_S,7,"const Vector3d",1,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,8,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
+ double a_PosX = ((double) tolua_tonumber(tolua_S,2,0));
+ double a_PosY = ((double) tolua_tonumber(tolua_S,3,0));
+ double a_PosZ = ((double) tolua_tonumber(tolua_S,4,0));
+ cProjectileEntity::eKind a_Kind = ((cProjectileEntity::eKind) (int) tolua_tonumber(tolua_S,5,0));
+ cEntity* a_Creator = ((cEntity*) tolua_tousertype(tolua_S,6,0));
+ const Vector3d* a_Speed = ((const Vector3d*) tolua_tousertype(tolua_S,7,NULL));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CreateProjectile'", NULL);
+#endif
+ {
+ int tolua_ret = (int) self->CreateProjectile(a_PosX,a_PosY,a_PosZ,a_Kind,a_Creator,a_Speed);
+ tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function 'CreateProjectile'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* method: Clear of class cInventory */
#ifndef TOLUA_DISABLE_tolua_AllToLua_cInventory_Clear00
static int tolua_AllToLua_cInventory_Clear00(lua_State* tolua_S)
@@ -17892,221 +18797,6 @@ static int tolua_AllToLua_cWebPlugin_SafeString00(lua_State* tolua_S)
}
#endif //#ifndef TOLUA_DISABLE
-/* method: new of class cPickup */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00
-static int tolua_AllToLua_cPickup_new00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) ||
- !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
- !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
- !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
- (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) ||
- !tolua_isnumber(tolua_S,6,1,&tolua_err) ||
- !tolua_isnumber(tolua_S,7,1,&tolua_err) ||
- !tolua_isnumber(tolua_S,8,1,&tolua_err) ||
- !tolua_isnoobj(tolua_S,9,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0));
- int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0));
- int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0));
- const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0));
- float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f));
- float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f));
- float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f));
- {
- cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ));
- tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup");
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
-/* method: new_local of class cPickup */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_new00_local
-static int tolua_AllToLua_cPickup_new00_local(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertable(tolua_S,1,"cPickup",0,&tolua_err) ||
- !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
- !tolua_isnumber(tolua_S,3,0,&tolua_err) ||
- !tolua_isnumber(tolua_S,4,0,&tolua_err) ||
- (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) ||
- !tolua_isnumber(tolua_S,6,1,&tolua_err) ||
- !tolua_isnumber(tolua_S,7,1,&tolua_err) ||
- !tolua_isnumber(tolua_S,8,1,&tolua_err) ||
- !tolua_isnoobj(tolua_S,9,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- int a_MicroPosX = ((int) tolua_tonumber(tolua_S,2,0));
- int a_MicroPosY = ((int) tolua_tonumber(tolua_S,3,0));
- int a_MicroPosZ = ((int) tolua_tonumber(tolua_S,4,0));
- const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0));
- float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f));
- float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f));
- float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f));
- {
- cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_MicroPosX,a_MicroPosY,a_MicroPosZ,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ));
- tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup");
- tolua_register_gc(tolua_S,lua_gettop(tolua_S));
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
-/* method: GetItem of class cPickup */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetItem00
-static int tolua_AllToLua_cPickup_GetItem00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,2,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0);
-#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetItem'", NULL);
-#endif
- {
- cItem& tolua_ret = (cItem&) self->GetItem();
- tolua_pushusertype(tolua_S,(void*)&tolua_ret,"cItem");
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'GetItem'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
-/* method: CollectedBy of class cPickup */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_CollectedBy00
-static int tolua_AllToLua_cPickup_CollectedBy00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"cPickup",0,&tolua_err) ||
- !tolua_isusertype(tolua_S,2,"cPlayer",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,3,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- cPickup* self = (cPickup*) tolua_tousertype(tolua_S,1,0);
- cPlayer* a_Dest = ((cPlayer*) tolua_tousertype(tolua_S,2,0));
-#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'CollectedBy'", NULL);
-#endif
- {
- bool tolua_ret = (bool) self->CollectedBy(a_Dest);
- tolua_pushboolean(tolua_S,(bool)tolua_ret);
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'CollectedBy'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
-/* method: GetAge of class cPickup */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_GetAge00
-static int tolua_AllToLua_cPickup_GetAge00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,2,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0);
-#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetAge'", NULL);
-#endif
- {
- int tolua_ret = (int) self->GetAge();
- tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'GetAge'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
-/* method: IsCollected of class cPickup */
-#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_IsCollected00
-static int tolua_AllToLua_cPickup_IsCollected00(lua_State* tolua_S)
-{
-#ifndef TOLUA_RELEASE
- tolua_Error tolua_err;
- if (
- !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) ||
- !tolua_isnoobj(tolua_S,2,&tolua_err)
- )
- goto tolua_lerror;
- else
-#endif
- {
- const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0);
-#ifndef TOLUA_RELEASE
- if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsCollected'", NULL);
-#endif
- {
- bool tolua_ret = (bool) self->IsCollected();
- tolua_pushboolean(tolua_S,(bool)tolua_ret);
- }
- }
- return 1;
-#ifndef TOLUA_RELEASE
- tolua_lerror:
- tolua_error(tolua_S,"#ferror in function 'IsCollected'.",&tolua_err);
- return 0;
-#endif
-}
-#endif //#ifndef TOLUA_DISABLE
-
/* get function: m_PrimaryServerVersion of class cRoot */
#ifndef TOLUA_DISABLE_tolua_get_cRoot_m_PrimaryServerVersion
static int tolua_get_cRoot_m_PrimaryServerVersion(lua_State* tolua_S)
@@ -20404,6 +21094,50 @@ tolua_lerror:
}
#endif //#ifndef TOLUA_DISABLE
+/* method: operator/ of class Vector3d */
+#ifndef TOLUA_DISABLE_tolua_AllToLua_Vector3d__div00
+static int tolua_AllToLua_Vector3d__div00(lua_State* tolua_S)
+{
+#ifndef TOLUA_RELEASE
+ tolua_Error tolua_err;
+ if (
+ !tolua_isusertype(tolua_S,1,"const Vector3d",0,&tolua_err) ||
+ !tolua_isnumber(tolua_S,2,0,&tolua_err) ||
+ !tolua_isnoobj(tolua_S,3,&tolua_err)
+ )
+ goto tolua_lerror;
+ else
+#endif
+ {
+ const Vector3d* self = (const Vector3d*) tolua_tousertype(tolua_S,1,0);
+ const double f = ((const double) tolua_tonumber(tolua_S,2,0));
+#ifndef TOLUA_RELEASE
+ if (!self) tolua_error(tolua_S,"invalid 'self' in function 'operator/'", NULL);
+#endif
+ {
+ Vector3d tolua_ret = (Vector3d) self->operator/(f);
+ {
+#ifdef __cplusplus
+ void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret));
+ tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+#else
+ void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d));
+ tolua_pushusertype(tolua_S,tolua_obj,"Vector3d");
+ tolua_register_gc(tolua_S,lua_gettop(tolua_S));
+#endif
+ }
+ }
+ }
+ return 1;
+#ifndef TOLUA_RELEASE
+ tolua_lerror:
+ tolua_error(tolua_S,"#ferror in function '.div'.",&tolua_err);
+ return 0;
+#endif
+}
+#endif //#ifndef TOLUA_DISABLE
+
/* get function: x of class Vector3d */
#ifndef TOLUA_DISABLE_tolua_get_Vector3d_x
static int tolua_get_Vector3d_x(lua_State* tolua_S)
@@ -27433,6 +28167,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_constant(tolua_S,"E_ITEM_WAIT_DISC",E_ITEM_WAIT_DISC);
tolua_constant(tolua_S,"E_ITEM_LAST_DISC_PLUS_ONE",E_ITEM_LAST_DISC_PLUS_ONE);
tolua_constant(tolua_S,"E_ITEM_LAST_DISC",E_ITEM_LAST_DISC);
+ tolua_constant(tolua_S,"E_ITEM_LAST",E_ITEM_LAST);
tolua_constant(tolua_S,"E_META_CHEST_FACING_ZM",E_META_CHEST_FACING_ZM);
tolua_constant(tolua_S,"E_META_CHEST_FACING_ZP",E_META_CHEST_FACING_ZP);
tolua_constant(tolua_S,"E_META_CHEST_FACING_XM",E_META_CHEST_FACING_XM);
@@ -27691,6 +28426,10 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_array(tolua_S,"g_BlockSpreadLightFalloff",tolua_get_AllToLua_g_BlockSpreadLightFalloff,tolua_set_AllToLua_g_BlockSpreadLightFalloff);
tolua_array(tolua_S,"g_BlockTransparent",tolua_get_AllToLua_g_BlockTransparent,tolua_set_AllToLua_g_BlockTransparent);
tolua_array(tolua_S,"g_BlockOneHitDig",tolua_get_AllToLua_g_BlockOneHitDig,tolua_set_AllToLua_g_BlockOneHitDig);
+ tolua_array(tolua_S,"g_BlockPistonBreakable",tolua_get_AllToLua_g_BlockPistonBreakable,tolua_set_AllToLua_g_BlockPistonBreakable);
+ tolua_array(tolua_S,"g_BlockIsSnowable",tolua_get_AllToLua_g_BlockIsSnowable,tolua_set_AllToLua_g_BlockIsSnowable);
+ tolua_array(tolua_S,"g_BlockRequiresSpecialTool",tolua_get_AllToLua_g_BlockRequiresSpecialTool,tolua_set_AllToLua_g_BlockRequiresSpecialTool);
+ tolua_array(tolua_S,"g_BlockIsSolid",tolua_get_AllToLua_g_BlockIsSolid,tolua_set_AllToLua_g_BlockIsSolid);
tolua_constant(tolua_S,"BLOCK_FACE_NONE",BLOCK_FACE_NONE);
tolua_constant(tolua_S,"BLOCK_FACE_BOTTOM",BLOCK_FACE_BOTTOM);
tolua_constant(tolua_S,"BLOCK_FACE_TOP",BLOCK_FACE_TOP);
@@ -27842,10 +28581,11 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_constant(tolua_S,"etPlayer",cEntity::etPlayer);
tolua_constant(tolua_S,"etPickup",cEntity::etPickup);
tolua_constant(tolua_S,"etMonster",cEntity::etMonster);
- tolua_constant(tolua_S,"etMob",cEntity::etMob);
tolua_constant(tolua_S,"etFallingBlock",cEntity::etFallingBlock);
tolua_constant(tolua_S,"etMinecart",cEntity::etMinecart);
tolua_constant(tolua_S,"etTNT",cEntity::etTNT);
+ tolua_constant(tolua_S,"etProjectile",cEntity::etProjectile);
+ tolua_constant(tolua_S,"etMob",cEntity::etMob);
tolua_constant(tolua_S,"eEntityType_Entity",cEntity::eEntityType_Entity);
tolua_constant(tolua_S,"eEntityType_Player",cEntity::eEntityType_Player);
tolua_constant(tolua_S,"eEntityType_Pickup",cEntity::eEntityType_Pickup);
@@ -27954,6 +28694,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GetStance",tolua_AllToLua_cPlayer_GetStance00);
tolua_function(tolua_S,"GetInventory",tolua_AllToLua_cPlayer_GetInventory00);
tolua_function(tolua_S,"GetEquippedItem",tolua_AllToLua_cPlayer_GetEquippedItem00);
+ tolua_function(tolua_S,"GetThrowStartPos",tolua_AllToLua_cPlayer_GetThrowStartPos00);
+ tolua_function(tolua_S,"GetThrowSpeed",tolua_AllToLua_cPlayer_GetThrowSpeed00);
tolua_function(tolua_S,"GetGameMode",tolua_AllToLua_cPlayer_GetGameMode00);
tolua_function(tolua_S,"SetGameMode",tolua_AllToLua_cPlayer_SetGameMode00);
tolua_function(tolua_S,"IsGameModeCreative",tolua_AllToLua_cPlayer_IsGameModeCreative00);
@@ -28007,6 +28749,57 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"IsSwimming",tolua_AllToLua_cPlayer_IsSwimming00);
tolua_function(tolua_S,"IsSubmerged",tolua_AllToLua_cPlayer_IsSubmerged00);
tolua_endmodule(tolua_S);
+ #ifdef __cplusplus
+ tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",tolua_collect_cPickup);
+ #else
+ tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",NULL);
+ #endif
+ tolua_beginmodule(tolua_S,"cPickup");
+ tolua_function(tolua_S,"new",tolua_AllToLua_cPickup_new00);
+ tolua_function(tolua_S,"new_local",tolua_AllToLua_cPickup_new00_local);
+ tolua_function(tolua_S,".call",tolua_AllToLua_cPickup_new00_local);
+ tolua_function(tolua_S,"GetItem",tolua_AllToLua_cPickup_GetItem00);
+ tolua_function(tolua_S,"CollectedBy",tolua_AllToLua_cPickup_CollectedBy00);
+ tolua_function(tolua_S,"GetAge",tolua_AllToLua_cPickup_GetAge00);
+ tolua_function(tolua_S,"IsCollected",tolua_AllToLua_cPickup_IsCollected00);
+ tolua_endmodule(tolua_S);
+ tolua_cclass(tolua_S,"cProjectileEntity","cProjectileEntity","cEntity",NULL);
+ tolua_beginmodule(tolua_S,"cProjectileEntity");
+ tolua_constant(tolua_S,"pkArrow",cProjectileEntity::pkArrow);
+ tolua_constant(tolua_S,"pkSnowball",cProjectileEntity::pkSnowball);
+ tolua_constant(tolua_S,"pkEgg",cProjectileEntity::pkEgg);
+ tolua_constant(tolua_S,"pkGhastFireball",cProjectileEntity::pkGhastFireball);
+ tolua_constant(tolua_S,"pkFireCharge",cProjectileEntity::pkFireCharge);
+ tolua_constant(tolua_S,"pkEnderPearl",cProjectileEntity::pkEnderPearl);
+ tolua_constant(tolua_S,"pkExpBottle",cProjectileEntity::pkExpBottle);
+ tolua_constant(tolua_S,"pkSplashPotion",cProjectileEntity::pkSplashPotion);
+ tolua_constant(tolua_S,"pkWitherSkull",cProjectileEntity::pkWitherSkull);
+ tolua_constant(tolua_S,"pkFishingFloat",cProjectileEntity::pkFishingFloat);
+ tolua_function(tolua_S,"GetProjectileKind",tolua_AllToLua_cProjectileEntity_GetProjectileKind00);
+ tolua_function(tolua_S,"GetCreator",tolua_AllToLua_cProjectileEntity_GetCreator00);
+ tolua_function(tolua_S,"GetMCAClassName",tolua_AllToLua_cProjectileEntity_GetMCAClassName00);
+ tolua_function(tolua_S,"IsInGround",tolua_AllToLua_cProjectileEntity_IsInGround00);
+ tolua_endmodule(tolua_S);
+ tolua_cclass(tolua_S,"cArrowEntity","cArrowEntity","cProjectileEntity",NULL);
+ tolua_beginmodule(tolua_S,"cArrowEntity");
+ tolua_constant(tolua_S,"psNoPickup",cArrowEntity::psNoPickup);
+ tolua_constant(tolua_S,"psInSurvivalOrCreative",cArrowEntity::psInSurvivalOrCreative);
+ tolua_constant(tolua_S,"psInCreative",cArrowEntity::psInCreative);
+ tolua_function(tolua_S,"GetPickupState",tolua_AllToLua_cArrowEntity_GetPickupState00);
+ tolua_function(tolua_S,"SetPickupState",tolua_AllToLua_cArrowEntity_SetPickupState00);
+ tolua_function(tolua_S,"GetDamageCoeff",tolua_AllToLua_cArrowEntity_GetDamageCoeff00);
+ tolua_function(tolua_S,"SetDamageCoeff",tolua_AllToLua_cArrowEntity_SetDamageCoeff00);
+ tolua_function(tolua_S,"CanPickup",tolua_AllToLua_cArrowEntity_CanPickup00);
+ tolua_endmodule(tolua_S);
+ tolua_cclass(tolua_S,"cThrownEggEntity","cThrownEggEntity","cProjectileEntity",NULL);
+ tolua_beginmodule(tolua_S,"cThrownEggEntity");
+ tolua_endmodule(tolua_S);
+ tolua_cclass(tolua_S,"cThrownEnderPearlEntity","cThrownEnderPearlEntity","cProjectileEntity",NULL);
+ tolua_beginmodule(tolua_S,"cThrownEnderPearlEntity");
+ tolua_endmodule(tolua_S);
+ tolua_cclass(tolua_S,"cThrownSnowballEntity","cThrownSnowballEntity","cProjectileEntity",NULL);
+ tolua_beginmodule(tolua_S,"cThrownSnowballEntity");
+ tolua_endmodule(tolua_S);
tolua_cclass(tolua_S,"cPluginManager","cPluginManager","",NULL);
tolua_beginmodule(tolua_S,"cPluginManager");
tolua_constant(tolua_S,"HOOK_BLOCK_TO_PICKUPS",cPluginManager::HOOK_BLOCK_TO_PICKUPS);
@@ -28058,11 +28851,12 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_constant(tolua_S,"HOOK_WEATHER_CHANGED",cPluginManager::HOOK_WEATHER_CHANGED);
tolua_constant(tolua_S,"HOOK_WEATHER_CHANGING",cPluginManager::HOOK_WEATHER_CHANGING);
tolua_constant(tolua_S,"HOOK_WORLD_TICK",cPluginManager::HOOK_WORLD_TICK);
+ tolua_constant(tolua_S,"HOOK_NUM_HOOKS",cPluginManager::HOOK_NUM_HOOKS);
+ tolua_constant(tolua_S,"HOOK_MAX",cPluginManager::HOOK_MAX);
tolua_function(tolua_S,"Get",tolua_AllToLua_cPluginManager_Get00);
tolua_function(tolua_S,"GetPlugin",tolua_AllToLua_cPluginManager_GetPlugin00);
tolua_function(tolua_S,"FindPlugins",tolua_AllToLua_cPluginManager_FindPlugins00);
tolua_function(tolua_S,"ReloadPlugins",tolua_AllToLua_cPluginManager_ReloadPlugins00);
- tolua_function(tolua_S,"AddHook",tolua_AllToLua_cPluginManager_AddHook00);
tolua_function(tolua_S,"GetNumPlugins",tolua_AllToLua_cPluginManager_GetNumPlugins00);
tolua_function(tolua_S,"DisablePlugin",tolua_AllToLua_cPluginManager_DisablePlugin00);
tolua_function(tolua_S,"LoadPlugin",tolua_AllToLua_cPluginManager_LoadPlugin00);
@@ -28112,6 +28906,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GetDimension",tolua_AllToLua_cWorld_GetDimension00);
tolua_function(tolua_S,"GetHeight",tolua_AllToLua_cWorld_GetHeight00);
tolua_function(tolua_S,"BroadcastChat",tolua_AllToLua_cWorld_BroadcastChat00);
+ tolua_function(tolua_S,"BroadcastSoundEffect",tolua_AllToLua_cWorld_BroadcastSoundEffect00);
+ tolua_function(tolua_S,"BroadcastSoundParticleEffect",tolua_AllToLua_cWorld_BroadcastSoundParticleEffect00);
tolua_function(tolua_S,"UnloadUnusedChunks",tolua_AllToLua_cWorld_UnloadUnusedChunks00);
tolua_function(tolua_S,"RegenerateChunk",tolua_AllToLua_cWorld_RegenerateChunk00);
tolua_function(tolua_S,"GenerateChunk",tolua_AllToLua_cWorld_GenerateChunk00);
@@ -28150,6 +28946,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GrowSugarcane",tolua_AllToLua_cWorld_GrowSugarcane00);
tolua_function(tolua_S,"GetBiomeAt",tolua_AllToLua_cWorld_GetBiomeAt00);
tolua_function(tolua_S,"GetName",tolua_AllToLua_cWorld_GetName00);
+ tolua_function(tolua_S,"GetIniFileName",tolua_AllToLua_cWorld_GetIniFileName00);
tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00);
tolua_function(tolua_S,"QueueSaveAllChunks",tolua_AllToLua_cWorld_QueueSaveAllChunks00);
tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00);
@@ -28167,6 +28964,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"GetMaxCactusHeight",tolua_AllToLua_cWorld_GetMaxCactusHeight00);
tolua_function(tolua_S,"IsBlockDirectlyWatered",tolua_AllToLua_cWorld_IsBlockDirectlyWatered00);
tolua_function(tolua_S,"SpawnMob",tolua_AllToLua_cWorld_SpawnMob00);
+ tolua_function(tolua_S,"CreateProjectile",tolua_AllToLua_cWorld_CreateProjectile00);
tolua_endmodule(tolua_S);
tolua_cclass(tolua_S,"cInventory","cInventory","cItemGrid::cListener",NULL);
tolua_beginmodule(tolua_S,"cInventory");
@@ -28470,20 +29268,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,"HandleWebRequest",tolua_AllToLua_cWebPlugin_HandleWebRequest00);
tolua_function(tolua_S,"SafeString",tolua_AllToLua_cWebPlugin_SafeString00);
tolua_endmodule(tolua_S);
- #ifdef __cplusplus
- tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",tolua_collect_cPickup);
- #else
- tolua_cclass(tolua_S,"cPickup","cPickup","cEntity",NULL);
- #endif
- tolua_beginmodule(tolua_S,"cPickup");
- tolua_function(tolua_S,"new",tolua_AllToLua_cPickup_new00);
- tolua_function(tolua_S,"new_local",tolua_AllToLua_cPickup_new00_local);
- tolua_function(tolua_S,".call",tolua_AllToLua_cPickup_new00_local);
- tolua_function(tolua_S,"GetItem",tolua_AllToLua_cPickup_GetItem00);
- tolua_function(tolua_S,"CollectedBy",tolua_AllToLua_cPickup_CollectedBy00);
- tolua_function(tolua_S,"GetAge",tolua_AllToLua_cPickup_GetAge00);
- tolua_function(tolua_S,"IsCollected",tolua_AllToLua_cPickup_IsCollected00);
- tolua_endmodule(tolua_S);
tolua_cclass(tolua_S,"cRoot","cRoot","",NULL);
tolua_beginmodule(tolua_S,"cRoot");
tolua_variable(tolua_S,"m_PrimaryServerVersion",tolua_get_cRoot_m_PrimaryServerVersion,tolua_set_cRoot_m_PrimaryServerVersion);
@@ -28580,6 +29364,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
tolua_function(tolua_S,".sub",tolua_AllToLua_Vector3d__sub01);
tolua_function(tolua_S,".mul",tolua_AllToLua_Vector3d__mul00);
tolua_function(tolua_S,".mul",tolua_AllToLua_Vector3d__mul01);
+ tolua_function(tolua_S,".div",tolua_AllToLua_Vector3d__div00);
tolua_variable(tolua_S,"x",tolua_get_Vector3d_x,tolua_set_Vector3d_x);
tolua_variable(tolua_S,"y",tolua_get_Vector3d_y,tolua_set_Vector3d_y);
tolua_variable(tolua_S,"z",tolua_get_Vector3d_z,tolua_set_Vector3d_z);
diff --git a/source/Bindings.h b/source/Bindings.h
index 4dee7f815..c706c2281 100644
--- a/source/Bindings.h
+++ b/source/Bindings.h
@@ -1,8 +1,8 @@
-/*
-** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 08/19/13 11:57:27.
-*/
-
-/* Exported function */
-TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
-
+/*
+** Lua binding: AllToLua
+** Generated automatically by tolua++-1.0.92 on 09/01/13 14:42:05.
+*/
+
+/* Exported function */
+TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
+
diff --git a/source/BlockID.h b/source/BlockID.h
index b08795fdd..02d2c7193 100644
--- a/source/BlockID.h
+++ b/source/BlockID.h
@@ -367,7 +367,9 @@ enum ENUM_ITEM_ID
// Keep these two as the last values of the disc list, without a number - they will get their correct number assigned automagically by C++
// IsValidItem() depends on this!
E_ITEM_LAST_DISC_PLUS_ONE, ///< Useless, really, but needs to be present for the following value
- E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1 ///< Maximum disc itemtype number used
+ E_ITEM_LAST_DISC = E_ITEM_LAST_DISC_PLUS_ONE - 1, ///< Maximum disc itemtype number used
+
+ E_ITEM_LAST = E_ITEM_LAST_DISC, ///< Maximum valid ItemType
};
diff --git a/source/BlockTracer.h b/source/BlockTracer.h
index 6d67f1052..d0a34811d 100644
--- a/source/BlockTracer.h
+++ b/source/BlockTracer.h
@@ -31,12 +31,12 @@ public:
/** Called on each block encountered along the path, including the first block (path start)
When this callback returns true, the tracing is aborted.
*/
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0;
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) = 0;
/** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded
When this callback returns true, the tracing is aborted.
*/
- virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) { return false; }
+ virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) { return false; }
/** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height)
The coords specify the exact point at which the path exited the world.
diff --git a/source/Blocks/BlockCarpet.h b/source/Blocks/BlockCarpet.h
index 9ac998131..5eafd8c21 100644
--- a/source/Blocks/BlockCarpet.h
+++ b/source/Blocks/BlockCarpet.h
@@ -18,8 +18,8 @@ class cBlockCarpetHandler :
public cBlockHandler
{
public:
- cBlockCarpetHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
+ cBlockCarpetHandler(BLOCKTYPE a_BlockType) :
+ cBlockHandler(a_BlockType)
{
}
diff --git a/source/Blocks/BlockDoubleSlab.h b/source/Blocks/BlockDoubleSlab.h
deleted file mode 100644
index ed6ae9a70..000000000
--- a/source/Blocks/BlockDoubleSlab.h
+++ /dev/null
@@ -1,43 +0,0 @@
-
-#pragma once
-
-#include "BlockHandler.h"
-#include "../Items/ItemHandler.h"
-
-
-
-
-
-class cBlockDoubleSlabHandler :
- public cBlockHandler
-{
-public:
- cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType)
- : cBlockHandler(a_BlockType)
- {
- }
-
-
- virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
- {
- if (m_BlockType == E_BLOCK_DOUBLE_STONE_SLAB)
- {
- m_BlockType = E_BLOCK_STONE_SLAB;
- }
- else
- {
- m_BlockType = E_BLOCK_WOODEN_SLAB;
- }
- a_Pickups.push_back(cItem(m_BlockType, 2, a_BlockMeta));
- }
-
-
- virtual const char * GetStepSound(void) override
- {
- return ((m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB) || (m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB)) ? "step.wood" : "step.stone";
- }
-} ;
-
-
-
-
diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp
index 22efa25f5..5134c1103 100644
--- a/source/Blocks/BlockHandler.cpp
+++ b/source/Blocks/BlockHandler.cpp
@@ -17,7 +17,6 @@
#include "BlockDeadBush.h"
#include "BlockDirt.h"
#include "BlockDoor.h"
-#include "BlockDoubleSlab.h"
#include "BlockDropSpenser.h"
#include "BlockEnderchest.h"
#include "BlockEntity.h"
diff --git a/source/Blocks/BlockSlab.h b/source/Blocks/BlockSlab.h
index 6caa3a27a..7c1251b28 100644
--- a/source/Blocks/BlockSlab.h
+++ b/source/Blocks/BlockSlab.h
@@ -1,7 +1,17 @@
+// BlockSlab.h
+
+// Declares cBlockSlabHandler and cBlockDoubleSlabHandler classes
+
+
+
+
+
#pragma once
#include "BlockHandler.h"
+#include "../Items/ItemHandler.h"
+
@@ -30,36 +40,26 @@ public:
) override
{
a_BlockType = m_BlockType;
- BLOCKTYPE Type = (BLOCKTYPE)(a_Player->GetEquippedItem().m_ItemType);
+ BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE Meta = (NIBBLETYPE)(a_Player->GetEquippedItem().m_ItemDamage & 0x07);
- int DoubleType;
- if (Type == E_BLOCK_STONE_SLAB)
- {
- DoubleType = 43; // Make it a double slab (with old type wood)
- }
- else
- {
- DoubleType = 125; // Make it a wooden double slab (new type)
- }
// HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one
- cItemHandler * ItemHandler = cItemHandler::GetItemHandler(DoubleType);
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type));
- // Check if the block at the coordinates is a slab. Eligibility for combining etc. were processed in ClientHandle
- BLOCKTYPE IsSlab;
- IsSlab = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
- if ((IsSlab == E_BLOCK_STONE_SLAB) || (IsSlab == E_BLOCK_WOODEN_SLAB))
+ // Check if the block at the coordinates is a slab. Eligibility for combining has already been processed in ClientHandle
+ if (IsAnySlabType(a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ)))
{
- // Special handling for non top/bottom clicks
+ // Call the function in ClientHandle that places a block when the client sends the packet,
+ // so that plugins may interfere with the placement.
+
if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM))
{
- // As with previous, call the function in ClientHandle that places a block when the client sends the packet
- // This effectively simulates a client placing a double slab, so it goes through plugins etc. so the slabbing can be cancelled
+ // Top and bottom faces need no parameter modification
a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
}
else
{
- // If player cursor is at top half of block
+ // The other faces need to distinguish between top and bottom cursor positions
if (a_CursorY > 7)
{
// Edit the call to use BLOCK_FACE_BOTTOM, otherwise it places incorrectly
@@ -71,19 +71,23 @@ public:
a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_BOTTOM, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler);
}
}
- return false; // Cancel the event because dblslabs were already placed, nothing else needed
+ return false; // Cancel the event, because dblslabs were already placed, nothing else needed
}
+ // Place the single-slab with correct metas:
switch (a_BlockFace)
{
- // Previous IF condition didn't cancel the event (not a slab at coords), so place slab with correct metas
case BLOCK_FACE_TOP:
{
- a_BlockMeta = Meta & 0x7; break; // Bottom half slab block
+ // Bottom half slab block
+ a_BlockMeta = Meta & 0x7;
+ break;
}
case BLOCK_FACE_BOTTOM:
{
- a_BlockMeta = Meta | 0x8; break; // Top half slab block
+ // Top half slab block
+ a_BlockMeta = Meta | 0x8;
+ break;
}
case BLOCK_FACE_EAST:
case BLOCK_FACE_NORTH:
@@ -107,8 +111,69 @@ public:
virtual const char * GetStepSound(void) override
+ {
+ switch (m_BlockType)
+ {
+ case E_BLOCK_WOODEN_SLAB: return "step.wood";
+ case E_BLOCK_STONE_SLAB: return "step.stone";
+ }
+ ASSERT(!"Unhandled slab type!");
+ return "";
+ }
+
+
+ /// Returns true if the specified blocktype is one of the slabs handled by this handler
+ static bool IsAnySlabType(BLOCKTYPE a_BlockType)
+ {
+ return ((a_BlockType == E_BLOCK_WOODEN_SLAB) || (a_BlockType == E_BLOCK_STONE_SLAB));
+ }
+
+
+ /// Converts the single-slab blocktype to its equivalent double-slab blocktype
+ static BLOCKTYPE GetDoubleSlabType(BLOCKTYPE a_SingleSlabBlockType)
+ {
+ switch (a_SingleSlabBlockType)
+ {
+ case E_BLOCK_STONE_SLAB: return E_BLOCK_DOUBLE_STONE_SLAB;
+ case E_BLOCK_WOODEN_SLAB: return E_BLOCK_DOUBLE_WOODEN_SLAB;
+ }
+ ASSERT(!"Unhandled slab type!");
+ return E_BLOCK_AIR;
+ }
+
+} ;
+
+
+
+
+
+class cBlockDoubleSlabHandler :
+ public cBlockHandler
+{
+public:
+ cBlockDoubleSlabHandler(BLOCKTYPE a_BlockType)
+ : cBlockHandler(a_BlockType)
+ {
+ }
+
+
+ virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
+ {
+ if (m_BlockType == E_BLOCK_DOUBLE_STONE_SLAB)
+ {
+ m_BlockType = E_BLOCK_STONE_SLAB;
+ }
+ else
+ {
+ m_BlockType = E_BLOCK_WOODEN_SLAB;
+ }
+ a_Pickups.push_back(cItem(m_BlockType, 2, a_BlockMeta));
+ }
+
+
+ virtual const char * GetStepSound(void) override
{
- return ((m_BlockType == E_BLOCK_WOODEN_SLAB) || (m_BlockType == E_BLOCK_STONE_SLAB)) ? "step.wood" : "step.stone";
+ return ((m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB) || (m_BlockType == E_BLOCK_DOUBLE_WOODEN_SLAB)) ? "step.wood" : "step.stone";
}
} ;
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index 53aae4dc4..357c07105 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -19,6 +19,7 @@
#include "OSSupport/Timer.h"
#include "Items/ItemHandler.h"
#include "Blocks/BlockHandler.h"
+#include "Blocks/BlockSlab.h"
#include "Vector3f.h"
#include "Vector3d.h"
@@ -51,6 +52,9 @@ static const int MAX_EXPLOSIONS_PER_TICK = 100;
/// How many explosions in the recent history are allowed
static const int MAX_RUNNING_SUM_EXPLOSIONS = cClientHandle::NUM_CHECK_EXPLOSIONS_TICKS * MAX_EXPLOSIONS_PER_TICK / 8;
+/// How many ticks before the socket is closed after the client is destroyed (#31)
+static const int TICKS_BEFORE_CLOSE = 20;
+
@@ -84,6 +88,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance)
, m_bKeepThreadGoing(true)
, m_Ping(1000)
, m_PingID(1)
+ , m_TicksSinceDestruction(0)
, m_State(csConnected)
, m_LastStreamedChunkX(0x7fffffff) // bogus chunk coords to force streaming upon login
, m_LastStreamedChunkZ(0x7fffffff)
@@ -111,7 +116,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance)
cClientHandle::~cClientHandle()
{
- ASSERT(m_State == csDestroyed); // Has Destroy() been called?
+ ASSERT(m_State >= csDestroyedWaiting); // Has Destroy() been called?
LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this);
@@ -189,7 +194,7 @@ void cClientHandle::Destroy(void)
RemoveFromAllChunks();
m_Player->GetWorld()->RemoveClientFromChunkSender(this);
}
- m_State = csDestroyed;
+ m_State = csDestroyedWaiting;
}
@@ -571,8 +576,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
// A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
return;
}
+ ItemHandler->OnItemShoot(m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
}
- LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
return;
}
@@ -785,16 +790,16 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta);
- cBlockHandler * Handler = cBlockHandler::GetBlockHandler(BlockType);
+ cBlockHandler * BlockHandler = cBlockHandler::GetBlockHandler(BlockType);
- if (Handler->IsUseable() && !m_Player->IsCrouched())
+ if (BlockHandler->IsUseable() && !m_Player->IsCrouched())
{
if (PlgMgr->CallHookPlayerUsingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta))
{
// A plugin doesn't agree with using the block, abort
return;
}
- Handler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
+ BlockHandler->OnUse(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ);
PlgMgr->CallHookPlayerUsedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
return;
}
@@ -852,25 +857,24 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType);
NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage);
+ if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ {
+ // The block is being placed outside the world, ignore this packet altogether (#128)
+ return;
+ }
+
World->GetBlockTypeMeta(a_BlockX, a_BlockY, a_BlockZ, ClickedBlock, ClickedBlockMeta);
- // Special slab handler coding
+ // Special slab handling - placing a slab onto another slab produces a dblslab instead:
if (
- // If clicked face top: is slab there in the "bottom" position?
- // If clicked face bottom: is the slab there in the "top" position?
- // This prevents a dblslab forming below if you click the top face of a "top" slab.
- (((a_BlockFace == BLOCK_FACE_TOP) && (ClickedBlockMeta == (EquippedBlockDamage & 0x07))) || ((a_BlockFace == BLOCK_FACE_BOTTOM) && (ClickedBlockMeta == (EquippedBlockDamage | 0x08)))) &&
-
- // Is clicked a slab? This is a SLAB handler, not stone or something!
- ((ClickedBlock == E_BLOCK_STONE_SLAB) || (ClickedBlock == E_BLOCK_WOODEN_SLAB)) &&
-
- // Is equipped a some type of slab?
- // This prevents a bug where, well, you get a dblslab by placing TNT or something not a slab.
- ((EquippedBlock == E_BLOCK_STONE_SLAB) || (EquippedBlock == E_BLOCK_WOODEN_SLAB)) &&
-
- // Is equipped slab type same as the slab in the world? After all, we can't combine different slabs!
- ((ClickedBlockMeta & 0x07) == (EquippedBlockDamage & 0x07))
+ cBlockSlabHandler::IsAnySlabType(ClickedBlock) && // Is there a slab already?
+ cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab?
+ ((ClickedBlockMeta & 0x07) == (EquippedBlockDamage & 0x07)) && // Is it the same slab type?
+ (
+ (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab
+ (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab
)
+ )
{
// Coordinates at CLICKED block, don't move them anywhere
}
@@ -881,17 +885,26 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
if (Handler->DoesIgnoreBuildCollision())
{
Handler->OnDestroyedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ);
- //World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
}
- else
+
+ BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+ if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision())
{
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
+ if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height))
+ {
+ // The block is being placed outside the world, ignore this packet altogether (#128)
+ return;
+ }
+
+ BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+
// Clicked on side of block, make sure that placement won't be cancelled if there is a slab able to be double slabbed.
// No need to do combinability (dblslab) checks, client will do that here.
- if ((World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_STONE_SLAB) || (World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_SLAB))
+ if (cBlockSlabHandler::IsAnySlabType(PlaceBlock))
{
- //Is a slab, don't do checks and proceed to double-slabbing
+ // It's a slab, don't do checks and proceed to double-slabbing
}
else
{
@@ -899,13 +912,11 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
if ((a_BlockFace == BLOCK_FACE_TOP) && !Handler->DoesAllowBlockOnTop())
{
// Resend the old block
- // Some times the client still places the block O.o
+ // Sometimes the client still places the block O.o
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
return;
}
-
-
- BLOCKTYPE PlaceBlock = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
+
if (!BlockHandler(PlaceBlock)->DoesIgnoreBuildCollision())
{
// Tried to place a block *into* another?
@@ -915,7 +926,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
}
}
}
- // Special slab handler coding end
BLOCKTYPE BlockType;
NIBBLETYPE BlockMeta;
@@ -951,7 +961,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
NewBlock->OnPlacedByPlayer(World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
// Step sound with 0.8f pitch is used as block placement sound
- World->BroadcastSoundEffect(NewBlock->GetStepSound(),a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f);
+ World->BroadcastSoundEffect(NewBlock->GetStepSound(), a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f);
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
}
@@ -1324,6 +1334,12 @@ void cClientHandle::HandleTabCompletion(const AString & a_Text)
void cClientHandle::SendData(const char * a_Data, int a_Size)
{
+ if (m_HasSentDC)
+ {
+ // This could crash the client, because they've already unloaded the world etc., and suddenly a wild packet appears (#31)
+ return;
+ }
+
{
cCSLock Lock(m_CSOutgoingData);
@@ -1438,6 +1454,17 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
void cClientHandle::Tick(float a_Dt)
{
+ // Handle clients that are waiting for final close while destroyed:
+ if (m_State == csDestroyedWaiting)
+ {
+ m_TicksSinceDestruction += 1; // This field is misused for the timeout counting
+ if (m_TicksSinceDestruction > TICKS_BEFORE_CLOSE)
+ {
+ m_State = csDestroyed;
+ }
+ return;
+ }
+
// Process received network data:
AString IncomingData;
{
@@ -1563,6 +1590,16 @@ void cClientHandle::SendChat(const AString & a_Message)
void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{
+ ASSERT(m_Player != NULL);
+
+ if ((m_State == csAuthenticated) || (m_State == csDownloadingWorld))
+ {
+ if ((a_ChunkX == m_Player->GetChunkX()) && (a_ChunkZ == m_Player->GetChunkZ()))
+ {
+ m_Protocol->SendPlayerMoveLook();
+ }
+ }
+
// Check chunks being sent, erase them from m_ChunksToSend:
bool Found = false;
{
diff --git a/source/ClientHandle.h b/source/ClientHandle.h
index 65ad35165..761cf25fe 100644
--- a/source/ClientHandle.h
+++ b/source/ClientHandle.h
@@ -257,6 +257,9 @@ private:
int m_LastDigBlockX;
int m_LastDigBlockY;
int m_LastDigBlockZ;
+
+ /// Used while csDestroyedWaiting for counting the ticks until the connection is closed
+ int m_TicksSinceDestruction;
enum eState
{
@@ -267,6 +270,7 @@ private:
csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back
csPlaying, ///< Normal gameplay
csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks
+ csDestroyedWaiting, ///< The client has been destroyed, but is still kept so that the Kick packet is delivered (#31)
csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread
// TODO: Add Kicking here as well
diff --git a/source/Defines.h b/source/Defines.h
index 48a7cfb1e..6bc1a18f6 100644
--- a/source/Defines.h
+++ b/source/Defines.h
@@ -29,6 +29,16 @@ extern bool g_BlockTransparent[];
/// Is a block destroyed after a single hit?
extern bool g_BlockOneHitDig[];
+/// Can a piston break this block?
+extern bool g_BlockPistonBreakable[256];
+
+/// Can this block hold snow atop?
+extern bool g_BlockIsSnowable[256];
+
+extern bool g_BlockRequiresSpecialTool[256];
+
+extern bool g_BlockIsSolid[256];
+
diff --git a/source/Entities/Entity.cpp b/source/Entities/Entity.cpp
index b9810aabb..56fd36a05 100644
--- a/source/Entities/Entity.cpp
+++ b/source/Entities/Entity.cpp
@@ -144,6 +144,10 @@ bool cEntity::Initialize(cWorld * a_World)
m_World->AddEntity(this);
cPluginManager::Get()->CallHookSpawnedEntity(*a_World, *this);
+
+ // Spawn the entity on the clients:
+ a_World->BroadcastSpawnEntity(*this);
+
return true;
}
@@ -477,7 +481,7 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
// TODO Add collision detection with entities.
- a_Dt /= 1000;
+ a_Dt /= 1000; // Convert from msec to sec
Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ());
int BlockX = (int) floor(NextPos.x);
@@ -493,7 +497,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
// Make sure we got the correct chunk and a valid one. No one ever knows...
- cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX,BlockZ);
+ cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
if (NextChunk != NULL)
{
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
@@ -513,11 +517,12 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
else
{
- //Push out entity.
+ // Push out entity.
m_bOnGround = true;
NextPos.y += 0.2;
- LOGD("Entity #%d (%s) is inside a block at {%d,%d,%d}",
- m_UniqueID, GetClass(), BlockX, BlockY, BlockZ);
+ LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
+ m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
+ );
}
if (!m_bOnGround)
@@ -525,16 +530,16 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
float fallspeed;
if (IsBlockWater(BlockIn))
{
- fallspeed = -3.0f * a_Dt; //Fall slower in water.
+ fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
}
else if (BlockIn == E_BLOCK_COBWEB)
{
- NextSpeed.y *= 0.05; //Reduce overall falling speed
- fallspeed = 0; //No falling.
+ NextSpeed.y *= 0.05; // Reduce overall falling speed
+ fallspeed = 0; // No falling.
}
else
{
- //Normal gravity
+ // Normal gravity
fallspeed = m_Gravity * a_Dt;
}
NextSpeed.y += fallspeed;
@@ -548,19 +553,25 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
(BlockBelow != E_BLOCK_ACTIVATOR_RAIL)
)
{
- //Friction
+ // Friction
if (NextSpeed.SqrLength() > 0.0004f)
{
- NextSpeed.x *= 0.7f/(1+a_Dt);
- if ( fabs(NextSpeed.x) < 0.05 ) NextSpeed.x = 0;
- NextSpeed.z *= 0.7f/(1+a_Dt);
- if ( fabs(NextSpeed.z) < 0.05 ) NextSpeed.z = 0;
+ NextSpeed.x *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.x) < 0.05)
+ {
+ NextSpeed.x = 0;
+ }
+ NextSpeed.z *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.z) < 0.05)
+ {
+ NextSpeed.z = 0;
+ }
}
}
}
- //Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
- //might have different speed modifiers according to terrain.
+ // Adjust X and Z speed for COBWEB temporary. This speed modification should be handled inside block handlers since we
+ // might have different speed modifiers according to terrain.
if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.x *= 0.25;
@@ -1037,9 +1048,9 @@ void cEntity::SetMass(double a_Mass)
}
else
{
- //Make sure that mass is not zero. 1g is the default because we
- //have to choose a number. It's perfectly legal to have a mass
- //less than 1g as long as is NOT equal or less than zero.
+ // Make sure that mass is not zero. 1g is the default because we
+ // have to choose a number. It's perfectly legal to have a mass
+ // less than 1g as long as is NOT equal or less than zero.
m_Mass = 0.001;
}
}
diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h
index 119cb2fe5..2d058abae 100644
--- a/source/Entities/Entity.h
+++ b/source/Entities/Entity.h
@@ -90,12 +90,13 @@ public:
etPlayer,
etPickup,
etMonster,
- etMob = etMonster, // DEPRECATED, use etMonster instead!
etFallingBlock,
etMinecart,
etTNT,
+ etProjectile,
// DEPRECATED older constants, left over for compatibility reasons (plugins)
+ etMob = etMonster, // DEPRECATED, use etMonster instead!
eEntityType_Entity = etEntity,
eEntityType_Player = etPlayer,
eEntityType_Pickup = etPickup,
@@ -162,7 +163,7 @@ public:
void SetPosY (double a_PosY);
void SetPosZ (double a_PosZ);
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
- void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x,a_Pos.y,a_Pos.z);}
+ void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
void SetRot (const Vector3f & a_Rot);
void SetRotation(double a_Rotation);
void SetPitch (double a_Pitch);
@@ -276,9 +277,8 @@ public:
/** Descendants override this function to send a command to the specified client to spawn the entity on the client.
To spawn on all eligible clients, use cChunkMap::BroadcastSpawnEntity()
- Needs to have a default implementation due to Lua bindings.
*/
- virtual void SpawnOn(cClientHandle & a_Client) {ASSERT(!"SpawnOn() unimplemented!"); }
+ virtual void SpawnOn(cClientHandle & a_Client) = 0;
// tolua_begin
diff --git a/source/Entities/FallingBlock.cpp b/source/Entities/FallingBlock.cpp
index 237327975..9fcd9ac80 100644
--- a/source/Entities/FallingBlock.cpp
+++ b/source/Entities/FallingBlock.cpp
@@ -22,20 +22,6 @@ cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_Block
-bool cFallingBlock::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
{
a_ClientHandle.SendSpawnFallingBlock(*this);
diff --git a/source/Entities/FallingBlock.h b/source/Entities/FallingBlock.h
index 13931f061..5ba9909bb 100644
--- a/source/Entities/FallingBlock.h
+++ b/source/Entities/FallingBlock.h
@@ -29,7 +29,6 @@ public:
NIBBLETYPE GetBlockMeta(void) const { return m_BlockMeta; }
// cEntity overrides:
- virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/source/Entities/Minecart.cpp b/source/Entities/Minecart.cpp
index 9a92df38e..685067e79 100644
--- a/source/Entities/Minecart.cpp
+++ b/source/Entities/Minecart.cpp
@@ -26,20 +26,6 @@ cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
-bool cMinecart::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
{
char SubType = 0;
diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h
index b3386fbc9..f98b02bb5 100644
--- a/source/Entities/Minecart.h
+++ b/source/Entities/Minecart.h
@@ -35,7 +35,6 @@ public:
} ;
// cEntity overrides:
- virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp
index 0417b861d..9b388366a 100644
--- a/source/Entities/Pickup.cpp
+++ b/source/Entities/Pickup.cpp
@@ -40,20 +40,6 @@ cPickup::cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem
-bool cPickup::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cPickup::SpawnOn(cClientHandle & a_Client)
{
a_Client.SendPickupSpawn(*this);
@@ -73,18 +59,19 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
if (!m_bCollected)
{
int BlockY = (int) floor(GetPosY());
- if (BlockY < cChunkDef::Height) // Don't do anything except for falling when above the world
+ if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world
{
int BlockX = (int) floor(GetPosX());
int BlockZ = (int) floor(GetPosZ());
- //Position might have changed due to physics. So we have to make sure we have the correct chunk.
+ // Position might have changed due to physics. So we have to make sure we have the correct chunk.
cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
if (CurrentChunk != NULL) // Make sure the chunk is loaded
{
int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
- BLOCKTYPE BlockBelow = CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ);
+ // If the pickup is on the bottommost block position, make it think the void is made of air: (#131)
+ BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
if (
diff --git a/source/Entities/Pickup.h b/source/Entities/Pickup.h
index b0323dd92..af6eaf3bb 100644
--- a/source/Entities/Pickup.h
+++ b/source/Entities/Pickup.h
@@ -26,8 +26,6 @@ public:
cPickup(int a_MicroPosX, int a_MicroPosY, int a_MicroPosZ, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export
- virtual bool Initialize(cWorld * a_World) override;
-
cItem & GetItem(void) {return m_Item; } // tolua_export
const cItem & GetItem(void) const {return m_Item; }
diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp
index 3ccb4ca1d..0943f61ff 100644
--- a/source/Entities/Player.cpp
+++ b/source/Entities/Player.cpp
@@ -64,6 +64,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_IsSwimming(false)
, m_IsSubmerged(false)
, m_EatingFinishTick(-1)
+ , m_IsChargingBow(false)
+ , m_BowCharge(0)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@@ -200,6 +202,12 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
}
}
+ if (!a_Chunk.IsValid())
+ {
+ // This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
+ return;
+ }
+
super::Tick(a_Dt, a_Chunk);
// Set player swimming state
@@ -207,6 +215,13 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
// Handle air drowning stuff
HandleAir();
+
+ // Handle charging the bow:
+ if (m_IsChargingBow)
+ {
+ m_BowCharge += 1;
+ LOGD("Player \"%s\" charging bow: %d", m_PlayerName.c_str(), m_BowCharge);
+ }
if (m_bDirtyPosition)
{
@@ -247,6 +262,41 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
+void cPlayer::StartChargingBow(void)
+{
+ LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str());
+ m_IsChargingBow = true;
+ m_BowCharge = 0;
+}
+
+
+
+
+
+int cPlayer::FinishChargingBow(void)
+{
+ LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
+ int res = m_BowCharge;
+ m_IsChargingBow = false;
+ m_BowCharge = 0;
+ return res;
+}
+
+
+
+
+
+void cPlayer::CancelChargingBow(void)
+{
+ LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge);
+ m_IsChargingBow = false;
+ m_BowCharge = 0;
+}
+
+
+
+
+
void cPlayer::SetTouchGround(bool a_bTouchGround)
{
// If just
@@ -807,6 +857,36 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
+Vector3d cPlayer::GetThrowStartPos(void) const
+{
+ Vector3d res = GetEyePosition();
+
+ // Adjust the position to be just outside the player's bounding box:
+ res.x += 0.16 * cos(GetPitch());
+ res.y += -0.1;
+ res.z += 0.16 * sin(GetPitch());
+
+ return res;
+}
+
+
+
+
+
+Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const
+{
+ Vector3d res = GetLookVector();
+ res.Normalize();
+
+ // TODO: Add a slight random change (+-0.0075 in each direction)
+
+ return res * a_SpeedCoeff;
+}
+
+
+
+
+
void cPlayer::MoveTo( const Vector3d & a_NewPos )
{
if ((a_NewPos.y < -990) && (GetPosY() > -100))
diff --git a/source/Entities/Player.h b/source/Entities/Player.h
index 5dcce8421..82ff48954 100644
--- a/source/Entities/Player.h
+++ b/source/Entities/Player.h
@@ -62,6 +62,18 @@ public:
/// Returns the currently equipped boots; empty item if none
virtual cItem GetEquippedBoots(void) const override { return m_Inventory.GetEquippedBoots(); }
+
+ /// Starts charging the equipped bow
+ void StartChargingBow(void);
+
+ /// Finishes charging the current bow. Returns the number of ticks for which the bow has been charged
+ int FinishChargingBow(void);
+
+ /// Cancels the current bow charging
+ void CancelChargingBow(void);
+
+ /// Returns true if the player is currently charging the bow
+ bool IsChargingBow(void) const { return m_IsChargingBow; }
void SetTouchGround( bool a_bTouchGround );
inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; }
@@ -78,6 +90,12 @@ public:
// tolua_begin
+ /// Returns the position where projectiles thrown by this player should start, player eye position + adjustment
+ Vector3d GetThrowStartPos(void) const;
+
+ /// Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff.
+ Vector3d GetThrowSpeed(double a_SpeedCoeff) const;
+
/// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
eGameMode GetGameMode(void) const { return m_GameMode; }
@@ -351,6 +369,9 @@ protected:
/// The world tick in which eating will be finished. -1 if not eating
Int64 m_EatingFinishTick;
+
+ bool m_IsChargingBow;
+ int m_BowCharge;
virtual void Destroyed(void);
diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp
new file mode 100644
index 000000000..91b2c97a8
--- /dev/null
+++ b/source/Entities/ProjectileEntity.cpp
@@ -0,0 +1,351 @@
+
+// ProjectileEntity.cpp
+
+// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
+
+#include "Globals.h"
+#include "ProjectileEntity.h"
+#include "../ClientHandle.h"
+#include "Player.h"
+#include "../LineBlockTracer.h"
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cProjectileTracerCallback:
+
+class cProjectileTracerCallback :
+ public cBlockTracer::cCallbacks
+{
+public:
+ cProjectileTracerCallback(cProjectileEntity * a_Projectile) :
+ m_Projectile(a_Projectile)
+ {
+ }
+
+protected:
+ cProjectileEntity * m_Projectile;
+
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
+ {
+ if (g_BlockIsSolid[a_BlockType])
+ {
+ // The projectile hit a solid block
+ m_Projectile->OnHitSolidBlock(a_BlockX, a_BlockY, a_BlockZ, a_EntryFace);
+ return true;
+ }
+
+ // Convey some special effects from special blocks:
+ switch (a_BlockType)
+ {
+ case E_BLOCK_LAVA:
+ case E_BLOCK_STATIONARY_LAVA:
+ {
+ m_Projectile->StartBurning(30);
+ break;
+ }
+ case E_BLOCK_WATER:
+ case E_BLOCK_STATIONARY_WATER:
+ {
+ m_Projectile->StopBurning();
+ break;
+ }
+ } // switch (a_BlockType)
+
+ // Continue tracing
+ return false;
+ }
+} ;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cProjectileEntity:
+
+cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height) :
+ super(etProjectile, a_X, a_Y, a_Z, a_Width, a_Height),
+ m_ProjectileKind(a_Kind),
+ m_Creator(a_Creator),
+ m_IsInGround(false)
+{
+}
+
+
+
+
+
+cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) :
+ super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
+ m_ProjectileKind(a_Kind),
+ m_Creator(a_Creator),
+ m_IsInGround(false)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed)
+{
+ Vector3d Speed;
+ if (a_Speed != NULL)
+ {
+ Speed = *a_Speed;
+ }
+
+ switch (a_Kind)
+ {
+ case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed);
+ case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed);
+ case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed);
+ case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed);
+ // TODO: the rest
+ }
+
+ LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind);
+ return NULL;
+}
+
+
+
+
+
+void cProjectileEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
+{
+ // TODO: Set proper position based on what face was hit
+ switch (a_BlockFace)
+ {
+ case BLOCK_FACE_TOP: SetPosition(0.5 + a_BlockX, 1.0 + a_BlockY, 0.5 + a_BlockZ); break;
+ case BLOCK_FACE_BOTTOM: SetPosition(0.5 + a_BlockX, a_BlockY, 0.5 + a_BlockZ); break;
+ case BLOCK_FACE_EAST: SetPosition( a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
+ case BLOCK_FACE_WEST: SetPosition(1.0 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
+ case BLOCK_FACE_NORTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 1.0 + a_BlockZ); break;
+ case BLOCK_FACE_SOUTH: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, a_BlockZ); break;
+ case BLOCK_FACE_NONE: SetPosition(0.5 + a_BlockX, 0.5 + a_BlockY, 0.5 + a_BlockZ); break;
+ }
+ SetSpeed(0, 0, 0);
+
+ // DEBUG:
+ LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, hit solid block at face %d",
+ m_UniqueID,
+ GetPosX(), GetPosY(), GetPosZ(),
+ a_BlockFace
+ );
+
+ m_IsInGround = true;
+}
+
+
+
+
+
+AString cProjectileEntity::GetMCAClassName(void) const
+{
+ switch (m_ProjectileKind)
+ {
+ case pkArrow: return "Arrow";
+ case pkSnowball: return "Snowball";
+ case pkEgg: return "Egg";
+ case pkGhastFireball: return "Fireball";
+ case pkFireCharge: return "SmallFireball";
+ case pkEnderPearl: return "ThrownEnderPearl";
+ case pkExpBottle: return "ThrownExpBottle";
+ case pkSplashPotion: return "ThrownPotion";
+ case pkWitherSkull: return "WitherSkull";
+ case pkFishingFloat: return ""; // Unknown, perhaps MC doesn't save this?
+ }
+ ASSERT(!"Unhandled projectile entity kind!");
+ return "";
+}
+
+
+
+
+
+void cProjectileEntity::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ BroadcastMovementUpdate();
+}
+
+
+
+
+
+void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
+{
+ if (m_IsInGround)
+ {
+ // Already-grounded projectiles don't move at all
+ return;
+ }
+
+ Vector3d PerTickSpeed = GetSpeed() / 20;
+ Vector3d Pos = GetPosition();
+
+ // Trace the tick's worth of movement as a line:
+ Vector3d NextPos = Pos + PerTickSpeed;
+ cProjectileTracerCallback TracerCallback(this);
+ if (cLineBlockTracer::Trace(*m_World, TracerCallback, Pos, NextPos))
+ {
+ // Nothing in the way, update the position
+ SetPosition(NextPos);
+ }
+
+ // Add gravity effect to the vertical speed component:
+ SetSpeedY(GetSpeedY() + m_Gravity / 20);
+
+ // DEBUG:
+ LOGD("Arrow %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}",
+ m_UniqueID,
+ GetPosX(), GetPosY(), GetPosZ(),
+ GetSpeedX(), GetSpeedY(), GetSpeedZ()
+ );
+}
+
+
+
+
+
+void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
+{
+ // Default spawning - use the projectile kind to spawn an object:
+ a_Client.SendSpawnObject(*this, m_ProjectileKind, 0, 0, 0);
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cArrowEntity:
+
+cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
+ m_PickupState(psNoPickup),
+ m_DamageCoeff(2)
+{
+ SetSpeed(a_Speed);
+ SetMass(0.1);
+ LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f}",
+ m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ()
+ );
+}
+
+
+
+
+
+cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
+ super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
+ m_PickupState(psInSurvivalOrCreative),
+ m_DamageCoeff(2)
+{
+}
+
+
+
+
+
+bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
+{
+ switch (m_PickupState)
+ {
+ case psNoPickup: return false;
+ case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
+ case psInCreative: return a_Player.IsGameModeCreative();
+ }
+ ASSERT(!"Unhandled pickup state");
+ return false;
+}
+
+
+
+
+
+void cArrowEntity::SpawnOn(cClientHandle & a_Client)
+{
+ a_Client.SendSpawnObject(*this, pkArrow, 0, 0, 0);
+}
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cThrownEggEntity:
+
+cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cThrownEggEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
+{
+ // TODO: Random-spawn a chicken or four
+
+ Destroy();
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cThrownEnderPearlEntity :
+
+cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
+{
+ // TODO: Teleport the creator here, make them take 5 damage
+
+ Destroy();
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cThrownSnowballEntity :
+
+cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
+ super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
+{
+ SetSpeed(a_Speed);
+}
+
+
+
+
+
+void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
+{
+ // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs
+
+ Destroy();
+}
+
+
+
+
+
diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h
new file mode 100644
index 000000000..95dc00abc
--- /dev/null
+++ b/source/Entities/ProjectileEntity.h
@@ -0,0 +1,238 @@
+
+// ProjectileEntity.h
+
+// Declares the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
+
+
+
+
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+
+class cProjectileEntity :
+ public cEntity
+{
+ typedef cEntity super;
+
+public:
+ /// The kind of the projectile. The numbers correspond to the network type ID used for spawning via the 0x17 packet.
+ enum eKind
+ {
+ pkArrow = 60,
+ pkSnowball = 61,
+ pkEgg = 62,
+ pkGhastFireball = 63,
+ pkFireCharge = 64,
+ pkEnderPearl = 65,
+ pkExpBottle = 75,
+ pkSplashPotion = 73,
+ pkWitherSkull = 66,
+ pkFishingFloat = 90,
+ } ;
+
+ // tolua_end
+
+ CLASS_PROTODEF(cProjectileEntity);
+
+ cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
+ cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
+
+ static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d * a_Speed = NULL);
+
+ /// Called by the physics blocktracer when the entity hits a solid block, the block's coords and the face hit is given
+ virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
+
+ // tolua_begin
+
+ /// Returns the kind of the projectile (fast class identification)
+ eKind GetProjectileKind(void) const { return m_ProjectileKind; }
+
+ /// Returns the entity who created this projectile; may be NULL
+ cEntity * GetCreator(void) { return m_Creator; }
+
+ /// Returns the string that is used as the entity type (class name) in MCA files
+ AString GetMCAClassName(void) const;
+
+ /// Returns true if the projectile has hit the ground and is stuck there
+ bool IsInGround(void) const { return m_IsInGround; }
+
+protected:
+ eKind m_ProjectileKind;
+
+ /// The entity who has created this projectile; may be NULL (e. g. for dispensers)
+ cEntity * m_Creator;
+
+ /// True if the projectile has hit the ground and is stuck there
+ bool m_IsInGround;
+
+ // tolua_end
+
+ // cEntity overrides:
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
+ virtual void SpawnOn(cClientHandle & a_Client) override;
+
+ // tolua_begin
+} ;
+
+
+
+
+
+class cArrowEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+ /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
+ enum ePickupState
+ {
+ psNoPickup = 0,
+ psInSurvivalOrCreative = 1,
+ psInCreative = 2,
+ } ;
+
+ // tolua_end
+
+ CLASS_PROTODEF(cArrowEntity);
+
+ /// Creates a new arrow with psNoPickup state and default damage modifier coeff
+ cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+ /// Creates a new arrow as shot by a player, initializes it from the player object
+ cArrowEntity(cPlayer & a_Player, double a_Force);
+
+ // tolua_begin
+
+ /// Returns whether the arrow can be picked up by players
+ ePickupState GetPickupState(void) const { return m_PickupState; }
+
+ /// Sets a new pickup state
+ void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
+
+ /// Returns the damage modifier coeff.
+ double GetDamageCoeff(void) const { return m_DamageCoeff; }
+
+ /// Sets the damage modifier coeff
+ void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
+
+ /// Returns true if the specified player can pick the arrow up
+ bool CanPickup(const cPlayer & a_Player) const;
+
+ // tolua_end
+
+protected:
+
+ /// Determines when the arrow can be picked up by players
+ ePickupState m_PickupState;
+
+ /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
+ double m_DamageCoeff;
+
+ // cProjectileEntity overrides:
+ virtual void SpawnOn(cClientHandle & a_Client) override;
+
+ // tolua_begin
+} ;
+
+
+
+
+
+class cThrownEggEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cThrownEggEntity);
+
+ cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // tolua_end
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override;
+
+ // tolua_begin
+
+} ;
+
+
+
+
+
+class cThrownEnderPearlEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cThrownEnderPearlEntity);
+
+ cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // tolua_end
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override;
+
+ // tolua_begin
+
+} ;
+
+
+
+
+
+class cThrownSnowballEntity :
+ public cProjectileEntity
+{
+ typedef cProjectileEntity super;
+
+public:
+
+ // tolua_end
+
+ CLASS_PROTODEF(cThrownSnowballEntity);
+
+ cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
+
+protected:
+
+ // tolua_end
+
+ // cProjectileEntity overrides:
+ virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override;
+
+ // tolua_begin
+
+} ;
+
+
+
+
+
+// tolua_end
+
+
+
diff --git a/source/Entities/TNTEntity.cpp b/source/Entities/TNTEntity.cpp
index 43a0dea09..ad3d9ae0c 100644
--- a/source/Entities/TNTEntity.cpp
+++ b/source/Entities/TNTEntity.cpp
@@ -29,20 +29,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec) :
-bool cTNTEntity::Initialize(cWorld * a_World)
-{
- if (super::Initialize(a_World))
- {
- a_World->BroadcastSpawnEntity(*this);
- return true;
- }
- return false;
-}
-
-
-
-
-
void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle)
{
a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT
diff --git a/source/Entities/TNTEntity.h b/source/Entities/TNTEntity.h
index ae6fc75e2..eb5040e8a 100644
--- a/source/Entities/TNTEntity.h
+++ b/source/Entities/TNTEntity.h
@@ -19,7 +19,6 @@ public:
cTNTEntity(const Vector3d & a_Pos, double a_FuseTimeInSec);
// cEntity overrides:
- virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/source/Items/ItemBow.h b/source/Items/ItemBow.h
new file mode 100644
index 000000000..845192ef7
--- /dev/null
+++ b/source/Items/ItemBow.h
@@ -0,0 +1,80 @@
+
+// ItemBow.h
+
+// Declares the cItemBowHandler class representing the itemhandler for bows
+
+
+
+
+
+#pragma once
+
+#include "../Entities/ProjectileEntity.h"
+
+
+
+
+
+class cItemBowHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+
+public:
+ cItemBowHandler(void) :
+ super(E_ITEM_BOW)
+ {
+ }
+
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ ASSERT(a_Player != NULL);
+
+ // Check if the player has an arrow in the inventory, or is in Creative:
+ if (!(a_Player->IsGameModeCreative() || a_Player->GetInventory().HasItems(cItem(E_ITEM_ARROW))))
+ {
+ return false;
+ }
+ a_Player->StartChargingBow();
+ return true;
+ }
+
+
+ virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override
+ {
+ // Actual shot - produce the arrow with speed based on the ticks that the bow was charged
+ ASSERT(a_Player != NULL);
+
+ int BowCharge = a_Player->FinishChargingBow();
+ double Force = (double)BowCharge / 20;
+ Force = (Force * Force + 2 * Force) / 3; // This formula is used by the 1.6.2 client
+ if (Force < 0.1)
+ {
+ // Too little force, ignore the shot
+ return;
+ }
+ if (Force > 1)
+ {
+ Force = 1;
+ }
+
+ // Create the arrow entity:
+ cArrowEntity * Arrow = new cArrowEntity(*a_Player, Force * 2);
+ if (Arrow == NULL)
+ {
+ return;
+ }
+ if (!Arrow->Initialize(a_Player->GetWorld()))
+ {
+ delete Arrow;
+ return;
+ }
+ a_Player->GetWorld()->BroadcastSpawnEntity(*Arrow);
+ }
+} ;
+
+
+
+
+
diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp
index 66d36e1a6..2ae193d52 100644
--- a/source/Items/ItemHandler.cpp
+++ b/source/Items/ItemHandler.cpp
@@ -8,6 +8,7 @@
// Handlers:
#include "ItemBed.h"
+#include "ItemBow.h"
#include "ItemBrewingStand.h"
#include "ItemBucket.h"
#include "ItemCauldron.h"
@@ -21,6 +22,7 @@
#include "ItemLighter.h"
#include "ItemMinecart.h"
#include "ItemPickaxe.h"
+#include "ItemThrowable.h"
#include "ItemRedstoneDust.h"
#include "ItemRedstoneRepeater.h"
#include "ItemSapling.h"
@@ -47,18 +49,24 @@ cItemHandler * cItemHandler::m_ItemHandler[2268];
-cItemHandler *cItemHandler::GetItemHandler(int a_ItemType)
+cItemHandler * cItemHandler::GetItemHandler(int a_ItemType)
{
- if(a_ItemType < 0) a_ItemType = 0;
+ if (a_ItemType < 0)
+ {
+ ASSERT(!"Bad item type");
+ a_ItemType = 0;
+ }
- if(!m_HandlerInitialized)
- { //We have to initialize
+ if (!m_HandlerInitialized)
+ {
+ // We need to initialize
memset(m_ItemHandler, 0, sizeof(m_ItemHandler));
m_HandlerInitialized = true;
}
- if(m_ItemHandler[a_ItemType])
- return m_ItemHandler[a_ItemType];
- m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
+ if (m_ItemHandler[a_ItemType] == NULL)
+ {
+ m_ItemHandler[a_ItemType] = CreateItemHandler(a_ItemType);
+ }
return m_ItemHandler[a_ItemType];
}
@@ -77,15 +85,19 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_BLOCK_SAPLING: return new cItemSaplingHandler(a_ItemType);
case E_BLOCK_WOOL: return new cItemClothHandler(a_ItemType);
case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
+ case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType);
+ case E_ITEM_EGG: return new cItemEggHandler();
+ case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler();
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType);
case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType);
case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType);
case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType);
+ case E_ITEM_SNOWBALL: return new cItemSnowballHandler();
case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType);
case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType);
diff --git a/source/Items/ItemHandler.h b/source/Items/ItemHandler.h
index 44d43e8f7..e39bb054b 100644
--- a/source/Items/ItemHandler.h
+++ b/source/Items/ItemHandler.h
@@ -21,8 +21,11 @@ class cItemHandler
public:
cItemHandler(int a_ItemType);
- /// Called when the player tries to use the item. Return false to make the item unusable. DEFAULT: False
- virtual bool OnItemUse(cWorld *a_World, cPlayer *a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir); //eg for fishing or hoes
+ /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir);
+
+ /// Called when the client sends the SHOOT status in the lclk packet
+ virtual void OnItemShoot(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) {}
/// Called while the player diggs a block using this item
virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace);
@@ -88,7 +91,7 @@ protected:
int m_ItemType;
static cItemHandler *CreateItemHandler(int m_ItemType);
- static cItemHandler *m_ItemHandler[2268];
+ static cItemHandler * m_ItemHandler[E_ITEM_LAST + 1];
static bool m_HandlerInitialized; //used to detect if the itemhandlers are initialized
};
diff --git a/source/Items/ItemThrowable.h b/source/Items/ItemThrowable.h
new file mode 100644
index 000000000..dacdb6157
--- /dev/null
+++ b/source/Items/ItemThrowable.h
@@ -0,0 +1,90 @@
+
+// ItemThrowable.h
+
+// Declares the itemhandlers for throwable items: eggs, snowballs and ender pearls
+
+
+
+
+
+#pragma once
+
+
+
+
+
+class cItemThrowableHandler :
+ public cItemHandler
+{
+ typedef cItemHandler super;
+public:
+ cItemThrowableHandler(int a_ItemType, cProjectileEntity::eKind a_ProjectileKind, double a_SpeedCoeff) :
+ super(a_ItemType),
+ m_ProjectileKind(a_ProjectileKind),
+ m_SpeedCoeff(a_SpeedCoeff)
+ {
+ }
+
+
+ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override
+ {
+ Vector3d Pos = a_Player->GetThrowStartPos();
+ Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff;
+ a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed);
+ return true;
+ }
+
+protected:
+ cProjectileEntity::eKind m_ProjectileKind;
+ double m_SpeedCoeff;
+} ;
+
+
+
+
+
+class cItemEggHandler :
+ public cItemThrowableHandler
+{
+ typedef cItemThrowableHandler super;
+public:
+ cItemEggHandler(void) :
+ super(E_ITEM_EGG, cProjectileEntity::pkEgg, 30)
+ {
+ }
+} ;
+
+
+
+
+class cItemSnowballHandler :
+ public cItemThrowableHandler
+{
+ typedef cItemThrowableHandler super;
+
+public:
+ cItemSnowballHandler(void) :
+ super(E_ITEM_SNOWBALL, cProjectileEntity::pkSnowball, 30)
+ {
+ }
+} ;
+
+
+
+
+
+class cItemEnderPearlHandler :
+ public cItemThrowableHandler
+{
+ typedef cItemThrowableHandler super;
+
+public:
+ cItemEnderPearlHandler(void) :
+ super(E_ITEM_ENDER_PEARL, cProjectileEntity::pkEnderPearl, 30)
+ {
+ }
+} ;
+
+
+
+
diff --git a/source/LeakFinder.cpp b/source/LeakFinder.cpp
index 3242bba04..272e313a0 100644
--- a/source/LeakFinder.cpp
+++ b/source/LeakFinder.cpp
@@ -116,12 +116,15 @@
/* _X: MSVC 2012 (MSC 1700) seems to use a different allocation scheme for STL containers,
* allocating lots of small objects and running out of memory very soon
* Thus for MSVC 2012 we cut the callstack buffer length in half
+*
+* _X 2013_08_25: The callstack tracking gets worse even for MSVC 2008, a single lua_state eats 50 MiB of RAM
+* Therefore I decided to further reduce the buffers from 0x2000 to 0x1000
*/
// Controlling the callstack depth
#if (_MSC_VER < 1700)
- #define MAX_CALLSTACK_LEN_BUF 0x2000
-#else
#define MAX_CALLSTACK_LEN_BUF 0x1000
+#else
+ #define MAX_CALLSTACK_LEN_BUF 0x0800
#endif
@@ -942,10 +945,10 @@ static int MyAllocHook(int nAllocType, void *pvData,
g_CurrentMemUsage += nSize ;
g_pCRTTable->Insert(lRequest, c, nSize);
- if (g_CurrentMemUsage > 1073741824) //This is 1 gb = 1024 * 1024* 1024.
+ if (g_CurrentMemUsage > 1536 * 1024* 1024)
{
printf("******************************************\n");
- printf("** Server reached 1 GiB memory usage, **\n");
+ printf("** Server reached 1.5 GiB memory usage, **\n");
printf("** something is probably wrong. **\n");
printf("** Writing memory dump into memdump.xml **\n");
printf("******************************************\n");
diff --git a/source/LineBlockTracer.cpp b/source/LineBlockTracer.cpp
index 03464314a..7cc14089d 100644
--- a/source/LineBlockTracer.cpp
+++ b/source/LineBlockTracer.cpp
@@ -55,6 +55,7 @@ bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ,
m_DirX = (m_StartX < m_EndX) ? 1 : -1;
m_DirY = (m_StartY < m_EndY) ? 1 : -1;
m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1;
+ m_CurrentFace = BLOCK_FACE_NONE;
// Check the start coords, adjust into the world:
if (m_StartY < 0)
@@ -178,9 +179,9 @@ bool cLineBlockTracer::MoveToNextBlock(void)
// Based on the wall hit, adjust the current coords
switch (Direction)
{
- case dirX: m_CurrentX += m_DirX; break;
- case dirY: m_CurrentY += m_DirY; break;
- case dirZ: m_CurrentZ += m_DirZ; break;
+ case dirX: m_CurrentX += m_DirX; m_CurrentFace = (m_DirX > 0) ? BLOCK_FACE_EAST : BLOCK_FACE_WEST; break;
+ case dirY: m_CurrentY += m_DirY; m_CurrentFace = (m_DirY > 0) ? BLOCK_FACE_BOTTOM : BLOCK_FACE_TOP; break;
+ case dirZ: m_CurrentZ += m_DirZ; m_CurrentFace = (m_DirZ > 0) ? BLOCK_FACE_SOUTH : BLOCK_FACE_NORTH; break;
case dirNONE: return false;
}
return true;
@@ -211,7 +212,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width;
a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta);
- if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta))
+ if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta, m_CurrentFace))
{
// The callback terminated the trace
return false;
@@ -219,7 +220,7 @@ bool cLineBlockTracer::Item(cChunk * a_Chunk)
}
else
{
- if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ))
+ if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ, m_CurrentFace))
{
// The callback terminated the trace
return false;
diff --git a/source/LineBlockTracer.h b/source/LineBlockTracer.h
index 4616cb191..ccbb70ea6 100644
--- a/source/LineBlockTracer.h
+++ b/source/LineBlockTracer.h
@@ -60,6 +60,9 @@ protected:
// The current block
int m_CurrentX, m_CurrentY, m_CurrentZ;
+
+ // The face through which the current block has been entered
+ char m_CurrentFace;
/// Adjusts the start point above the world to just at the world's top
diff --git a/source/LuaState.cpp b/source/LuaState.cpp
index bbf47fb27..8d2fa8eca 100644
--- a/source/LuaState.cpp
+++ b/source/LuaState.cpp
@@ -884,6 +884,49 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status)
+void cLuaState::LogStackTrace(void)
+{
+ LOGWARNING("Stack trace:");
+ lua_Debug entry;
+ int depth = 0;
+ while (lua_getstack(m_LuaState, depth, &entry))
+ {
+ int status = lua_getinfo(m_LuaState, "Sln", &entry);
+ assert(status);
+
+ LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?");
+ depth++;
+ }
+ LOGWARNING("Stack trace end");
+}
+
+
+
+
+
+AString cLuaState::GetTypeText(int a_StackPos)
+{
+ int Type = lua_type(m_LuaState, a_StackPos);
+ switch (Type)
+ {
+ case LUA_TNONE: return "TNONE";
+ case LUA_TNIL: return "TNIL";
+ case LUA_TBOOLEAN: return "TBOOLEAN";
+ case LUA_TLIGHTUSERDATA: return "TLIGHTUSERDATA";
+ case LUA_TNUMBER: return "TNUMBER";
+ case LUA_TSTRING: return "TSTRING";
+ case LUA_TTABLE: return "TTABLE";
+ case LUA_TFUNCTION: return "TFUNCTION";
+ case LUA_TUSERDATA: return "TUSERDATA";
+ case LUA_TTHREAD: return "TTHREAD";
+ }
+ return Printf("Unknown (%d)", Type);
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cLuaState::cRef:
diff --git a/source/LuaState.h b/source/LuaState.h
index 0eae8206d..caba2484d 100644
--- a/source/LuaState.h
+++ b/source/LuaState.h
@@ -77,7 +77,7 @@ public:
bool IsValid(void) const {return (m_Ref != LUA_REFNIL); }
/// Allows to use this class wherever an int (i. e. ref) is to be used
- operator int(void) { return m_Ref; }
+ operator int(void) const { return m_Ref; }
protected:
cLuaState & m_LuaState;
@@ -782,6 +782,12 @@ public:
/// If the status is nonzero, prints the text on the top of Lua stack and returns true
static bool ReportErrors(lua_State * a_LuaState, int status);
+ /// Logs all items in the current stack trace to the server console
+ void LogStackTrace(void);
+
+ /// Returns the type of the item on the specified position in the stack
+ AString GetTypeText(int a_StackPos);
+
protected:
lua_State * m_LuaState;
diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp
index c975997a5..87efecd35 100644
--- a/source/ManualBindings.cpp
+++ b/source/ManualBindings.cpp
@@ -755,6 +755,159 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S)
+static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx)
+{
+ // Helper function for cPluginmanager:AddHook() binding
+ // Takes care of the new case (#121): args are HOOK_TYPE and CallbackFunction
+ // The arg types have already been checked
+
+ // Retrieve the cPlugin from the LuaState:
+ cPluginLua * Plugin = GetLuaPlugin(S);
+ if (Plugin == NULL)
+ {
+ // An error message has been already printed in GetLuaPlugin()
+ return 0;
+ }
+
+ // Retrieve and check the hook type
+ int HookType = (int)tolua_tonumber(S, a_ParamIdx, -1);
+ if (!a_PluginManager->IsValidHookType(HookType))
+ {
+ LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType);
+ S.LogStackTrace();
+ return 0;
+ }
+
+ // Add the hook to the plugin
+ if (!Plugin->AddHookRef(HookType, a_ParamIdx + 1))
+ {
+ LOGWARNING("cPluginManager.AddHook(): Cannot add hook %d, unknown error.", HookType);
+ S.LogStackTrace();
+ return 0;
+ }
+ a_PluginManager->AddHook(Plugin, HookType);
+
+ // Success
+ return 0;
+}
+
+
+
+
+
+static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx)
+{
+ // Helper function for cPluginmanager:AddHook() binding
+ // Takes care of the old case (#121): args are cPluginLua and HOOK_TYPE
+ // The arg types have already been checked
+
+ // Retrieve and check the cPlugin parameter
+ cPluginLua * Plugin = (cPluginLua *)tolua_tousertype(S, a_ParamIdx, NULL);
+ if (Plugin == NULL)
+ {
+ LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, expected a valid cPlugin object. Hook not added");
+ S.LogStackTrace();
+ return 0;
+ }
+ if (Plugin != GetLuaPlugin(S))
+ {
+ // The plugin parameter passed to us is not our stored plugin. Disallow this!
+ LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, cannot add hook to foreign plugins. Hook not added.");
+ S.LogStackTrace();
+ return 0;
+ }
+
+ // Retrieve and check the hook type
+ int HookType = (int)tolua_tonumber(S, a_ParamIdx + 1, -1);
+ if (!a_PluginManager->IsValidHookType(HookType))
+ {
+ LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType);
+ S.LogStackTrace();
+ return 0;
+ }
+
+ // Get the standard name for the callback function:
+ const char * FnName = cPluginLua::GetHookFnName(HookType);
+ if (FnName == NULL)
+ {
+ LOGWARNING("cPluginManager.AddHook(): Unknown hook type (%d). Hook not added.", HookType);
+ S.LogStackTrace();
+ return 0;
+ }
+
+ // Retrieve the function to call and add it to the plugin:
+ lua_pushstring(S, FnName);
+ bool res = Plugin->AddHookRef(HookType, 1);
+ lua_pop(S, 1); // Pop the function off the stack
+ if (!res)
+ {
+ LOGWARNING("cPluginManager.AddHook(): Function %s not found. Hook not added.", FnName);
+ S.LogStackTrace();
+ return 0;
+ }
+ a_PluginManager->AddHook(Plugin, HookType);
+
+ // Success
+ return 0;
+}
+
+
+
+
+
+static int tolua_cPluginManager_AddHook(lua_State * tolua_S)
+{
+ /*
+ Function signatures:
+ cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) -- (1) recommended
+ cPluginManager:Get():AddHook(HOOK_TYPE, CallbackFunction) -- (2) accepted silently
+ cPluginManager:Get():AddHook(Plugin, HOOK_TYPE) -- (3) old style (#121), accepted but complained about
+ cPluginManager.AddHook(Plugin, HOOK_TYPE) -- (4) old style (#121) mangled, accepted but complained about
+ */
+
+ cLuaState S(tolua_S);
+ cPluginManager * PlgMgr = cPluginManager::Get();
+
+ // If the first param is a cPluginManager, use it instead of the global one:
+ int ParamIdx = 1;
+ tolua_Error err;
+ if (tolua_isusertype(S, 1, "cPluginManager", 0, &err))
+ {
+ // Style 2 or 3, retrieve the PlgMgr instance
+ PlgMgr = (cPluginManager *)tolua_tousertype(S, 1, NULL);
+ if (PlgMgr == NULL)
+ {
+ LOGWARNING("Malformed plugin, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction). Fixing the call for you.");
+ S.LogStackTrace();
+ PlgMgr = cPluginManager::Get();
+ }
+ ParamIdx += 1;
+ }
+
+ if (lua_isnumber(S, ParamIdx) && lua_isfunction(S, ParamIdx + 1))
+ {
+ // The next params are a number and a function, assume style 1 or 2
+ return tolua_cPluginManager_AddHook_FnRef(PlgMgr, S, ParamIdx);
+ }
+ else if (tolua_isusertype(S, ParamIdx, "cPlugin", 0, &err) && lua_isnumber(S, ParamIdx + 1))
+ {
+ // The next params are a cPlugin and a number, assume style 3 or 4
+ LOGINFO("cPluginManager.AddHook(): Deprecated format used, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) instead. Fixing the call for you.");
+ S.LogStackTrace();
+ return tolua_cPluginManager_AddHook_DefFn(PlgMgr, S, ParamIdx);
+ }
+
+ AString ParamDesc;
+ Printf(ParamDesc, "%s, %s, %s", S.GetTypeText(1).c_str(), S.GetTypeText(2).c_str(), S.GetTypeText(3).c_str());
+ LOGWARNING("cPluginManager.AddHook(): bad parameters. Expected HOOK_TYPE and CallbackFunction, got %s. Hook not added.", ParamDesc.c_str());
+ S.LogStackTrace();
+ return 0;
+}
+
+
+
+
+
static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
{
int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */
@@ -1496,7 +1649,7 @@ public:
{
}
- virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override
+ virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock"))
{
@@ -1508,6 +1661,7 @@ public:
m_LuaState.Push(a_BlockZ);
m_LuaState.Push(a_BlockType);
m_LuaState.Push(a_BlockMeta);
+ m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1))
{
return false;
@@ -1521,7 +1675,7 @@ public:
return res;
}
- virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override
+ virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override
{
if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData"))
{
@@ -1531,6 +1685,7 @@ public:
m_LuaState.Push(a_BlockX);
m_LuaState.Push(a_BlockY);
m_LuaState.Push(a_BlockZ);
+ m_LuaState.Push(a_EntryFace);
if (!m_LuaState.CallFunction(1))
{
return false;
@@ -1699,6 +1854,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "ForEachCommand", tolua_cPluginManager_ForEachCommand);
tolua_function(tolua_S, "ForEachConsoleCommand", tolua_cPluginManager_ForEachConsoleCommand);
tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins);
+ tolua_function(tolua_S, "AddHook", tolua_cPluginManager_AddHook);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cPlayer");
diff --git a/source/OSSupport/IsThread.cpp b/source/OSSupport/IsThread.cpp
index 45e329a68..d5fbfcf19 100644
--- a/source/OSSupport/IsThread.cpp
+++ b/source/OSSupport/IsThread.cpp
@@ -136,17 +136,29 @@ bool cIsThread::Wait(void)
{
return true;
}
- LOGD("Waiting for thread %s to finish", m_ThreadName.c_str());
+
+ #ifdef LOGD // ProtoProxy doesn't have LOGD
+ LOGD("Waiting for thread %s to finish", m_ThreadName.c_str());
+ #endif // LOGD
#ifdef _WIN32
int res = WaitForSingleObject(m_Handle, INFINITE);
m_Handle = NULL;
- LOGD("Thread %s finished", m_ThreadName.c_str());
+
+ #ifdef LOGD // ProtoProxy doesn't have LOGD
+ LOGD("Thread %s finished", m_ThreadName.c_str());
+ #endif // LOGD
+
return (res == WAIT_OBJECT_0);
#else // _WIN32
int res = pthread_join(m_Handle, NULL);
m_Handle = NULL;
- LOGD("Thread %s finished", m_ThreadName.c_str());
+
+ #ifdef LOGD // ProtoProxy doesn't have LOGD
+ LOGD("Thread %s finished", m_ThreadName.c_str());
+ #endif // LOGD
+
+ m_HasStarted = false;
return (res == 0);
#endif // else _WIN32
}
diff --git a/source/OSSupport/ListenThread.cpp b/source/OSSupport/ListenThread.cpp
index c586227df..0890aabc8 100644
--- a/source/OSSupport/ListenThread.cpp
+++ b/source/OSSupport/ListenThread.cpp
@@ -80,7 +80,7 @@ void cListenThread::Stop(void)
super::Wait();
// Close all the listening sockets:
- for (cSockets::iterator itr = m_Sockets.begin(), end = m_Sockets.end(); itr != end; ++itr)
+ for (cSockets::iterator itr = m_Sockets.begin() + 1, end = m_Sockets.end(); itr != end; ++itr)
{
itr->CloseSocket();
} // for itr - m_Sockets[]
diff --git a/source/OSSupport/Socket.cpp b/source/OSSupport/Socket.cpp
index f79bdbf47..48b5d704d 100644
--- a/source/OSSupport/Socket.cpp
+++ b/source/OSSupport/Socket.cpp
@@ -74,11 +74,11 @@ void cSocket::CloseSocket()
if (shutdown(m_Socket, SHUT_RDWR) != 0)//SD_BOTH);
{
- LOGWARN("Error on shutting down socket (%s): %s", m_IPString.c_str(), GetLastErrorString().c_str());
+ LOGWARN("Error on shutting down socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str());
}
if (close(m_Socket) != 0)
{
- LOGWARN("Error closing socket (%s): %s", m_IPString.c_str(), GetLastErrorString().c_str());
+ LOGWARN("Error closing socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str());
}
#endif // else _WIN32
diff --git a/source/OSSupport/Timer.cpp b/source/OSSupport/Timer.cpp
index ab7325b5e..ed16f9e3a 100644
--- a/source/OSSupport/Timer.cpp
+++ b/source/OSSupport/Timer.cpp
@@ -8,33 +8,30 @@
-cTimer::cTimer()
-#ifdef _WIN32
- : m_TicksPerSecond( new LARGE_INTEGER )
-#endif
+cTimer::cTimer(void)
{
-#ifdef _WIN32
- QueryPerformanceFrequency( (LARGE_INTEGER*)m_TicksPerSecond );
-#endif
+ #ifdef _WIN32
+ QueryPerformanceFrequency(&m_TicksPerSecond);
+ #endif
}
-cTimer::~cTimer()
+
+
+
+
+long long cTimer::GetNowTime(void)
{
-#ifdef _WIN32
- delete (LARGE_INTEGER*)m_TicksPerSecond;
-#endif
+ #ifdef _WIN32
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ return ((now.QuadPart * 1000) / m_TicksPerSecond.QuadPart);
+ #else
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return (long long)(now.tv_sec * 1000 + now.tv_usec / 1000);
+ #endif
}
-long long cTimer::GetNowTime()
-{
-#ifdef _WIN32
- LARGE_INTEGER now;
- QueryPerformanceCounter( &now );
- LARGE_INTEGER & tps = *((LARGE_INTEGER*)m_TicksPerSecond);
- return ((now.QuadPart*1000) / tps.QuadPart );
-#else
- struct timeval now;
- gettimeofday(&now, NULL);
- return (long long)(now.tv_sec*1000 + now.tv_usec/1000);
-#endif
-} \ No newline at end of file
+
+
+
diff --git a/source/OSSupport/Timer.h b/source/OSSupport/Timer.h
index 5969d0fc9..a059daa41 100644
--- a/source/OSSupport/Timer.h
+++ b/source/OSSupport/Timer.h
@@ -1,15 +1,32 @@
+
+// Timer.h
+
+// Declares the cTimer class representing an OS-independent of retrieving current time with msec accuracy
+
+
+
+
+
#pragma once
+
+
+
+
class cTimer
{
public:
- cTimer();
- ~cTimer();
+ cTimer(void);
- long long GetNowTime();
+ // Returns the current time expressed in milliseconds
+ long long GetNowTime(void);
private:
-#ifdef _WIN32
- void* m_TicksPerSecond; // LARGE_INTEGER*
-#endif
-}; \ No newline at end of file
+ #ifdef _WIN32
+ LARGE_INTEGER m_TicksPerSecond;
+ #endif
+} ;
+
+
+
+
diff --git a/source/Plugin.h b/source/Plugin.h
index 2595b9470..be803bab2 100644
--- a/source/Plugin.h
+++ b/source/Plugin.h
@@ -113,13 +113,6 @@ public:
/// All bound console commands are to be removed, do any language-dependent cleanup here
virtual void ClearConsoleCommands(void) {} ;
- /** Called from cPluginManager::AddHook() to check if the hook can be added.
- Plugin API providers may check if the plugin is written correctly (has the hook handler function)
- Returns true if the hook can be added (handler exists)
- Descendants should also log the specific error message as a warning if they return false.
- */
- virtual bool CanAddHook(cPluginManager::PluginHook a_Hook) = 0;
-
// tolua_begin
const AString & GetName(void) const { return m_Name; }
void SetName(const AString & a_Name) { m_Name = a_Name; }
diff --git a/source/PluginLua.cpp b/source/PluginLua.cpp
index 5128ef0b0..81a536838 100644
--- a/source/PluginLua.cpp
+++ b/source/PluginLua.cpp
@@ -36,7 +36,33 @@ cPluginLua::cPluginLua(const AString & a_PluginDirectory) :
cPluginLua::~cPluginLua()
{
cCSLock Lock(m_CriticalSection);
- m_LuaState.Close();
+ Close();
+}
+
+
+
+
+
+void cPluginLua::Close(void)
+{
+ if (m_LuaState.IsValid())
+ {
+ // Release all the references in the hook map:
+ for (cHookMap::iterator itrH = m_HookMap.begin(), endH = m_HookMap.end(); itrH != endH; ++itrH)
+ {
+ for (cLuaRefs::iterator itrR = itrH->second.begin(), endR = itrH->second.end(); itrR != endR; ++itrR)
+ {
+ delete *itrR;
+ } // for itrR - itrH->second[]
+ } // for itrH - m_HookMap[]
+ m_HookMap.clear();
+
+ m_LuaState.Close();
+ }
+ else
+ {
+ ASSERT(m_HookMap.empty());
+ }
}
@@ -70,7 +96,7 @@ bool cPluginLua::Initialize(void)
AString Path = PluginPath + *itr;
if (!m_LuaState.LoadFile(Path))
{
- m_LuaState.Close();
+ Close();
return false;
}
} // for itr - Files[]
@@ -80,14 +106,14 @@ bool cPluginLua::Initialize(void)
if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res))
{
LOGWARNING("Error in plugin %s: Cannot call the Initialize() function. Plugin is temporarily disabled.", GetName().c_str());
- m_LuaState.Close();
+ Close();
return false;
}
if (!res)
{
LOGINFO("Plugin %s: Initialize() call failed, plugin is temporarily disabled.", GetName().c_str());
- m_LuaState.Close();
+ Close();
return false;
}
@@ -115,7 +141,11 @@ void cPluginLua::OnDisable(void)
void cPluginLua::Tick(float a_Dt)
{
cCSLock Lock(m_CriticalSection);
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_TICK), a_Dt);
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TICK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Dt);
+ }
}
@@ -126,8 +156,16 @@ bool cPluginLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int a_Bl
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_BLOCK_TO_PICKUPS), a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_BLOCK_TO_PICKUPS];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_Digger, a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, &a_Pickups, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -138,8 +176,16 @@ bool cPluginLua::OnChat(cPlayer * a_Player, AString & a_Message)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHAT), a_Player, a_Message, cLuaState::Return, res, a_Message);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHAT];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Player, a_Message, cLuaState::Return, res, a_Message);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -150,8 +196,16 @@ bool cPluginLua::OnChunkAvailable(cWorld * a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_AVAILABLE), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_AVAILABLE];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -162,8 +216,16 @@ bool cPluginLua::OnChunkGenerated(cWorld * a_World, int a_ChunkX, int a_ChunkZ,
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_GENERATED), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -174,8 +236,16 @@ bool cPluginLua::OnChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ,
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_GENERATING), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_GENERATING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, a_ChunkDesc, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -186,8 +256,16 @@ bool cPluginLua::OnChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_UNLOADED), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -198,8 +276,16 @@ bool cPluginLua::OnChunkUnloading(cWorld * a_World, int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CHUNK_UNLOADING), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CHUNK_UNLOADING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_World, a_ChunkX, a_ChunkZ, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -210,8 +296,16 @@ bool cPluginLua::OnCollectingPickup(cPlayer * a_Player, cPickup * a_Pickup)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_COLLECTING_PICKUP), a_Player, a_Pickup, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_COLLECTING_PICKUP];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Player, a_Pickup, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -222,8 +316,16 @@ bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGri
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_CRAFTING_NO_RECIPE), (cPlayer *)a_Player, a_Grid, a_Recipe, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_CRAFTING_NO_RECIPE];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), (cPlayer *)a_Player, a_Grid, a_Recipe, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -234,8 +336,16 @@ bool cPluginLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_DISCONNECT), a_Player, a_Reason, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Player, a_Reason, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -246,8 +356,16 @@ bool cPluginLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & a_Sp
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_EXECUTE_COMMAND), a_Player, a_Split, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXECUTE_COMMAND];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Player, a_Split, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -258,26 +376,33 @@ bool cPluginLua::OnExploded(cWorld & a_World, double a_ExplosionSize, bool a_Can
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- const char * FnName = GetHookFnName(cPluginManager::HOOK_EXPLODED);
- switch (a_Source)
- {
- case esOther: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
- case esPrimedTNT: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break;
- case esCreeper: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res); break;
- case esBed: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
- case esEnderCrystal: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
- case esGhastFireball: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
- case esWitherSkullBlack:
- case esWitherSkullBlue: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
- case esWitherBirth: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
- case esPlugin: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
- default:
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ switch (a_Source)
{
- ASSERT(!"Unhandled ExplosionSource");
- return false;
+ case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
+ case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res); break;
+ case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res); break;
+ case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
+ case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res); break;
+ case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
+ case esWitherSkullBlack:
+ case esWitherSkullBlue: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
+ case esWitherBirth: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
+ case esPlugin: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res); break;
+ default:
+ {
+ ASSERT(!"Unhandled ExplosionSource");
+ return false;
+ }
+ }
+ if (res)
+ {
+ return true;
}
}
- return res;
+ return false;
}
@@ -288,26 +413,33 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- const char * FnName = GetHookFnName(cPluginManager::HOOK_EXPLODING);
- switch (a_Source)
- {
- case esOther: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esPrimedTNT: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esCreeper: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esBed: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esEnderCrystal: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esGhastFireball: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esWitherSkullBlack:
- case esWitherSkullBlue: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esWitherBirth: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esPlugin: m_LuaState.Call(FnName, &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- default:
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_EXPLODING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ switch (a_Source)
{
- ASSERT(!"Unhandled ExplosionSource");
- return false;
+ case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esWitherSkullBlack:
+ case esWitherSkullBlue: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esWitherBirth: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esPlugin: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ default:
+ {
+ ASSERT(!"Unhandled ExplosionSource");
+ return false;
+ }
+ }
+ if (res)
+ {
+ return true;
}
}
- return res;
+ return false;
}
@@ -318,8 +450,16 @@ bool cPluginLua::OnHandshake(cClientHandle * a_Client, const AString & a_Usernam
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_HANDSHAKE), a_Client, a_Username, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HANDSHAKE];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Client, a_Username, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -330,8 +470,17 @@ bool cPluginLua::OnHopperPullingItem(cWorld & a_World, cHopperEntity & a_Hopper,
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_HOPPER_PULLING_ITEM), &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, a_SrcSlotNum, cLuaState::Return, res);
- return res;
+
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PULLING_ITEM];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, &a_Hopper, a_DstSlotNum, &a_SrcEntity, a_SrcSlotNum, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -342,8 +491,16 @@ bool cPluginLua::OnHopperPushingItem(cWorld & a_World, cHopperEntity & a_Hopper,
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_HOPPER_PUSHING_ITEM), &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, a_DstSlotNum, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_HOPPER_PUSHING_ITEM];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, &a_Hopper, a_SrcSlotNum, &a_DstEntity, a_DstSlotNum, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -354,8 +511,16 @@ bool cPluginLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_KILLING), &a_Victim, a_Killer, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_KILLING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Victim, a_Killer, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -366,8 +531,16 @@ bool cPluginLua::OnLogin(cClientHandle * a_Client, int a_ProtocolVersion, const
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_LOGIN), a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_LOGIN];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Client, a_ProtocolVersion, a_Username, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -378,8 +551,16 @@ bool cPluginLua::OnPlayerAnimation(cPlayer & a_Player, int a_Animation)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_ANIMATION), &a_Player, a_Animation, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_ANIMATION];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_Animation, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -390,8 +571,16 @@ bool cPluginLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int a_B
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_BREAKING_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BREAKING_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -402,8 +591,16 @@ bool cPluginLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_BROKEN_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_BROKEN_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_BlockType, a_BlockMeta, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -414,8 +611,16 @@ bool cPluginLua::OnPlayerEating(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_EATING), &a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_EATING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -426,8 +631,16 @@ bool cPluginLua::OnPlayerJoined(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_JOINED), &a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_JOINED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -438,8 +651,16 @@ bool cPluginLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_Block
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_LEFT_CLICK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_LEFT_CLICK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -450,8 +671,16 @@ bool cPluginLua::OnPlayerMoved(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_MOVING), &a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_MOVING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -462,8 +691,16 @@ bool cPluginLua::OnPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a_Blo
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_PLACED_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACED_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -474,8 +711,16 @@ bool cPluginLua::OnPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX, int a_Bl
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_PLACING_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_PLACING_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -486,8 +731,16 @@ bool cPluginLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_Bloc
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_RIGHT_CLICK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -498,8 +751,16 @@ bool cPluginLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a_Ent
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY), &a_Player, &a_Entity, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, &a_Entity, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -510,8 +771,16 @@ bool cPluginLua::OnPlayerShooting(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_SHOOTING), &a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SHOOTING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -522,8 +791,16 @@ bool cPluginLua::OnPlayerSpawned(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_SPAWNED), &a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_SPAWNED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -534,8 +811,16 @@ bool cPluginLua::OnPlayerTossingItem(cPlayer & a_Player)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_TOSSING_ITEM), &a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_TOSSING_ITEM];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -546,8 +831,16 @@ bool cPluginLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_Block
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USED_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -558,8 +851,16 @@ bool cPluginLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_BlockY
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USED_ITEM), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USED_ITEM];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -570,8 +871,16 @@ bool cPluginLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_Bloc
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USING_BLOCK), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_BLOCK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_BlockType, a_BlockMeta, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -582,8 +891,16 @@ bool cPluginLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_Block
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PLAYER_USING_ITEM), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLAYER_USING_ITEM];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -594,8 +911,16 @@ bool cPluginLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGrid *
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_POST_CRAFTING), a_Player, a_Grid, a_Recipe, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_POST_CRAFTING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Player, a_Grid, a_Recipe, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -606,8 +931,16 @@ bool cPluginLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid * a
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_PRE_CRAFTING), a_Player, a_Grid, a_Recipe, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PRE_CRAFTING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), a_Player, a_Grid, a_Recipe, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -618,8 +951,16 @@ bool cPluginLua::OnSpawnedEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNED_ENTITY), &a_World, &a_Entity, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_ENTITY];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, &a_Entity, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -630,8 +971,16 @@ bool cPluginLua::OnSpawnedMonster(cWorld & a_World, cMonster & a_Monster)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNED_MONSTER), &a_World, &a_Monster, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNED_MONSTER];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, &a_Monster, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -642,8 +991,16 @@ bool cPluginLua::OnSpawningEntity(cWorld & a_World, cEntity & a_Entity)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNING_ENTITY), &a_World, &a_Entity, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_ENTITY];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, &a_Entity, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -654,8 +1011,16 @@ bool cPluginLua::OnSpawningMonster(cWorld & a_World, cMonster & a_Monster)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_SPAWNING_MONSTER), &a_World, &a_Monster, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_SPAWNING_MONSTER];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, &a_Monster, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -666,8 +1031,16 @@ bool cPluginLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_TAKE_DAMAGE), &a_Receiver, &a_TDI, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_TAKE_DAMAGE];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_Receiver, &a_TDI, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -683,8 +1056,16 @@ bool cPluginLua::OnUpdatedSign(
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_UPDATED_SIGN), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATED_SIGN];
+ 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_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -700,8 +1081,16 @@ bool cPluginLua::OnUpdatingSign(
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_UPDATING_SIGN), a_World, a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_UPDATING_SIGN];
+ 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_Line1, a_Line2, a_Line3, a_Line4, a_Player, cLuaState::Return, res, a_Line1, a_Line2, a_Line3, a_Line4);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -712,8 +1101,16 @@ bool cPluginLua::OnWeatherChanged(cWorld & a_World)
{
cCSLock Lock(m_CriticalSection);
bool res = false;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_WEATHER_CHANGED), &a_World, cLuaState::Return, res);
- return res;
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGED];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, cLuaState::Return, res);
+ if (res)
+ {
+ return true;
+ }
+ }
+ return false;
}
@@ -725,9 +1122,18 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
cCSLock Lock(m_CriticalSection);
bool res = false;
int NewWeather = a_NewWeather;
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_WEATHER_CHANGING), &a_World, a_NewWeather, cLuaState::Return, res, NewWeather);
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WEATHER_CHANGING];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, NewWeather, cLuaState::Return, res, NewWeather);
+ if (res)
+ {
+ a_NewWeather = (eWeather)NewWeather;
+ return true;
+ }
+ }
a_NewWeather = (eWeather)NewWeather;
- return res;
+ return false;
}
@@ -737,7 +1143,11 @@ bool cPluginLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather)
bool cPluginLua::OnWorldTick(cWorld & a_World, float a_Dt)
{
cCSLock Lock(m_CriticalSection);
- m_LuaState.Call(GetHookFnName(cPluginManager::HOOK_WORLD_TICK), &a_World, a_Dt);
+ cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_WORLD_TICK];
+ for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
+ {
+ m_LuaState.Call((int)(**itr), &a_World, a_Dt);
+ }
return false;
}
@@ -830,13 +1240,16 @@ void cPluginLua::ClearConsoleCommands(void)
-bool cPluginLua::CanAddHook(cPluginManager::PluginHook a_Hook)
+bool cPluginLua::CanAddOldStyleHook(int a_HookType)
{
- const char * FnName = GetHookFnName(a_Hook);
+ const char * FnName = GetHookFnName(a_HookType);
if (FnName == NULL)
{
// Unknown hook ID
- LOGWARNING("Plugin %s wants to add an unknown hook ID (%d). The plugin need not work properly.", GetName().c_str(), a_Hook);
+ LOGWARNING("Plugin %s wants to add an unknown hook ID (%d). The plugin need not work properly.",
+ GetName().c_str(), a_HookType
+ );
+ m_LuaState.LogStackTrace();
return false;
}
@@ -847,23 +1260,9 @@ bool cPluginLua::CanAddHook(cPluginManager::PluginHook a_Hook)
}
LOGWARNING("Plugin %s wants to add a hook (%d), but it doesn't provide the callback function \"%s\" for it. The plugin need not work properly.",
- GetName().c_str(), a_Hook, FnName
+ GetName().c_str(), a_HookType, FnName
);
-
- // Lua stacktrace:
- LOGWARNING("Stack trace:");
- lua_Debug entry;
- int depth = 0;
- while (lua_getstack(m_LuaState, depth, &entry))
- {
- int status = lua_getinfo(m_LuaState, "Sln", &entry);
- assert(status);
-
- LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?");
- depth++;
- }
- LOGWARNING("Stack trace end");
-
+ m_LuaState.LogStackTrace();
return false;
}
@@ -871,9 +1270,9 @@ bool cPluginLua::CanAddHook(cPluginManager::PluginHook a_Hook)
-const char * cPluginLua::GetHookFnName(cPluginManager::PluginHook a_Hook)
+const char * cPluginLua::GetHookFnName(int a_HookType)
{
- switch (a_Hook)
+ switch (a_HookType)
{
case cPluginManager::HOOK_BLOCK_TO_PICKUPS: return "OnBlockToPickups";
case cPluginManager::HOOK_CHAT: return "OnChat";
@@ -928,6 +1327,28 @@ const char * cPluginLua::GetHookFnName(cPluginManager::PluginHook a_Hook)
+bool cPluginLua::AddHookRef(int a_HookType, int a_FnRefIdx)
+{
+ ASSERT(m_CriticalSection.IsLockedByCurrentThread()); // It probably has to be, how else would we have a LuaState?
+
+ // Check if the function reference is valid:
+ cLuaState::cRef * Ref = new cLuaState::cRef(m_LuaState, a_FnRefIdx);
+ if ((Ref == NULL) || !Ref->IsValid())
+ {
+ LOGWARNING("Plugin %s tried to add a hook %d with bad handler function.", GetName().c_str(), a_HookType);
+ m_LuaState.LogStackTrace();
+ delete Ref;
+ return false;
+ }
+
+ m_HookMap[a_HookType].push_back(Ref);
+ return true;
+}
+
+
+
+
+
AString cPluginLua::HandleWebRequest(const HTTPRequest * a_Request )
{
cCSLock Lock(m_CriticalSection);
diff --git a/source/PluginLua.h b/source/PluginLua.h
index 300fadc8b..fee9c4986 100644
--- a/source/PluginLua.h
+++ b/source/PluginLua.h
@@ -100,7 +100,8 @@ public:
virtual void ClearConsoleCommands(void) override;
- virtual bool CanAddHook(cPluginManager::PluginHook a_Hook) override;
+ /// Returns true if the plugin contains the function for the specified hook type, using the old-style registration (#121)
+ bool CanAddOldStyleHook(int a_HookType);
// cWebPlugin override
virtual const AString GetWebTitle(void) const {return GetName(); }
@@ -128,18 +129,35 @@ public:
/// Calls the plugin-specified "cLuaWindow slot changed" callback.
void CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, int a_SlotNum);
-protected:
- cCriticalSection m_CriticalSection;
- cLuaState m_LuaState;
+ /// Returns the name of Lua function that should handle the specified hook type in the older (#121) API
+ static const char * GetHookFnName(int a_HookType);
+ /** Adds a Lua function to be called for the specified hook.
+ The function has to be on the Lua stack at the specified index a_FnRefIdx
+ Returns true if the hook was added successfully.
+ */
+ bool AddHookRef(int a_HookType, int a_FnRefIdx);
+
+protected:
/// Maps command name into Lua function reference
typedef std::map<AString, int> CommandMap;
+ /// Provides an array of Lua function references
+ typedef std::vector<cLuaState::cRef *> cLuaRefs;
+
+ /// Maps hook types into arrays of Lua function references to call for each hook type
+ typedef std::map<int, cLuaRefs> cHookMap;
+
+ cCriticalSection m_CriticalSection;
+ cLuaState m_LuaState;
+
CommandMap m_Commands;
CommandMap m_ConsoleCommands;
-
- /// Returns the name of Lua function that should handle the specified hook
- const char * GetHookFnName(cPluginManager::PluginHook a_Hook);
+
+ cHookMap m_HookMap;
+
+ /// Releases all Lua references and closes the LuaState
+ void Close(void);
} ; // tolua_export
diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp
index e6ff3e6e2..93ee71926 100644
--- a/source/PluginManager.cpp
+++ b/source/PluginManager.cpp
@@ -61,7 +61,7 @@ void cPluginManager::FindPlugins(void)
// First get a clean list of only the currently running plugins, we don't want to mess those up
for (PluginMap::iterator itr = m_Plugins.begin(); itr != m_Plugins.end();)
{
- if( itr->second == NULL )
+ if (itr->second == NULL)
{
PluginMap::iterator thiz = itr;
++thiz;
@@ -1585,6 +1585,15 @@ void cPluginManager::TabCompleteCommand(const AString & a_Text, AStringVector &
+bool cPluginManager::IsValidHookType(int a_HookType)
+{
+ return ((a_HookType >= 0) && (a_HookType <= HOOK_MAX));
+}
+
+
+
+
+
bool cPluginManager::AddPlugin(cPlugin * a_Plugin)
{
m_Plugins[a_Plugin->GetDirectory()] = a_Plugin;
@@ -1603,17 +1612,13 @@ bool cPluginManager::AddPlugin(cPlugin * a_Plugin)
-void cPluginManager::AddHook(cPlugin * a_Plugin, PluginHook a_Hook)
+void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook)
{
if (!a_Plugin)
{
LOGWARN("Called cPluginManager::AddHook() with a_Plugin == NULL");
return;
}
- if (!a_Plugin->CanAddHook(a_Hook))
- {
- return;
- }
PluginList & Plugins = m_Hooks[a_Hook];
Plugins.remove(a_Plugin);
Plugins.push_back(a_Plugin);
diff --git a/source/PluginManager.h b/source/PluginManager.h
index 0933d389f..816e4a40c 100644
--- a/source/PluginManager.h
+++ b/source/PluginManager.h
@@ -110,6 +110,10 @@ public: // tolua_export
// Note that if a hook type is added, it may need processing in cPlugin::CanAddHook() descendants,
// and it definitely needs adding in cPluginLua::GetHookFnName() !
+
+ // Keep these two as the last items, they are used for validity checking and get their values automagically
+ HOOK_NUM_HOOKS,
+ HOOK_MAX = HOOK_NUM_HOOKS - 1,
} ;
// tolua_end
@@ -133,7 +137,9 @@ public: // tolua_export
void FindPlugins(); // tolua_export
void ReloadPlugins(); // tolua_export
- void AddHook( cPlugin* a_Plugin, PluginHook a_Hook ); // tolua_export
+
+ /// Adds the plugin to the list of plugins called for the specified hook type. Handles multiple adds as a single add
+ void AddHook(cPlugin * a_Plugin, int a_HookType);
unsigned int GetNumPlugins() const; // tolua_export
@@ -237,6 +243,9 @@ public: // tolua_export
*/
void TabCompleteCommand(const AString & a_Text, AStringVector & a_Results, cPlayer * a_Player);
+ /// Returns true if the specified hook type is within the allowed range
+ static bool IsValidHookType(int a_HookType);
+
private:
friend class cRoot;
@@ -248,7 +257,7 @@ private:
AString m_HelpString;
} ;
- typedef std::map< cPluginManager::PluginHook, cPluginManager::PluginList > HookMap;
+ typedef std::map<int, cPluginManager::PluginList> HookMap;
typedef std::map<AString, cCommandReg> CommandMap;
PluginList m_DisablePluginList;
diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp
index 2e5c305cc..26a1a9fad 100644
--- a/source/Protocol/Protocol132.cpp
+++ b/source/Protocol/Protocol132.cpp
@@ -340,9 +340,6 @@ void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
Flush();
SendCompass(a_World);
-
- // Send the initial position (so that confirmation works, FS #245):
- SendPlayerMoveLook();
}
diff --git a/source/StringUtils.cpp b/source/StringUtils.cpp
index 403b10a7c..cb91a4da7 100644
--- a/source/StringUtils.cpp
+++ b/source/StringUtils.cpp
@@ -350,6 +350,33 @@ AString & RawBEToUTF8(short * a_RawData, int a_NumShorts, AString & a_UTF8)
// UTF-8 conversion code adapted from:
// http://stackoverflow.com/questions/2867123/convert-utf-16-to-utf-8-under-windows-and-linux-in-c
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Begin of Unicode, Inc.'s code / information
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+Notice from the original file:
+* Copyright 2001-2004 Unicode, Inc.
+*
+* Disclaimer
+*
+* This source code is provided as is by Unicode, Inc. No claims are
+* made as to fitness for any particular purpose. No warranties of any
+* kind are expressed or implied. The recipient agrees to determine
+* applicability of information provided. If this file has been
+* purchased on magnetic or optical media from Unicode, Inc., the
+* sole remedy for any claim will be exchange of defective media
+* within 90 days of receipt.
+*
+* Limitations on Rights to Redistribute This Code
+*
+* Unicode, Inc. hereby grants the right to freely use the information
+* supplied in this file in the creation of products supporting the
+* Unicode Standard, and to make copies of this file in any form
+* for internal or external distribution as long as this notice
+* remains attached.
+*/
+
#define UNI_MAX_BMP 0x0000FFFF
#define UNI_MAX_UTF16 0x0010FFFF
#define UNI_MAX_UTF32 0x7FFFFFFF
@@ -505,18 +532,24 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a
} while (tmpBytesToRead > 0);
}
- --------------------------------------------------------------------- */
-
+ ---------------------------------------------------------------------
+*/
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// End of Unicode, Inc.'s code / information
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-/*
+
+
+
+#define HEX(x) ((x) > 9 ? (x) + 'A' - 10 : (x) + '0')
+
+/**
format binary data this way:
00001234: 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 1234567890abcdef
*/
-#define HEX(x) ((x) > 9 ? (x) + 'A' - 10 : (x) + '0')
-
AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_LineLength)
{
ASSERT(a_LineLength <= 120); // Due to using a fixed size line buffer; increase line[]'s size to lift this max
diff --git a/source/Tracer.cpp b/source/Tracer.cpp
index 6d37f2ed8..42f1ae5dd 100644
--- a/source/Tracer.cpp
+++ b/source/Tracer.cpp
@@ -133,9 +133,9 @@ void cTracer::SetValues(const Vector3f & a_Start, const Vector3f & a_Direction)
int cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int a_Distance)
{
- if (a_Start.y < 0)
+ if ((a_Start.y < 0) || (a_Start.y >= cChunkDef::Height))
{
- LOGD("%s: Start is below the world", __FUNCTION__);
+ LOGD("%s: Start Y is outside the world (%.2f), not tracing.", __FUNCTION__, a_Start.y);
return 0;
}
diff --git a/source/Vector3d.h b/source/Vector3d.h
index 6f28a857b..ecc72e421 100644
--- a/source/Vector3d.h
+++ b/source/Vector3d.h
@@ -30,12 +30,13 @@ public: // tolua_export
void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
- Vector3d operator + ( const Vector3d& v2 ) const { return Vector3d( x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
- Vector3d operator + ( const Vector3d* v2 ) const { return Vector3d( x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
- Vector3d operator - ( const Vector3d& v2 ) const { return Vector3d( x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
- Vector3d operator - ( const Vector3d* v2 ) const { return Vector3d( x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
- Vector3d operator * ( const double f ) const { return Vector3d( x * f, y * f, z * f ); } // tolua_export
- Vector3d operator * ( const Vector3d& v2 ) const { return Vector3d( x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
+ Vector3d operator + (const Vector3d & v2) const { return Vector3d(x + v2.x, y + v2.y, z + v2.z ); } // tolua_export
+ Vector3d operator + (const Vector3d * v2) const { return Vector3d(x + v2->x, y + v2->y, z + v2->z ); } // tolua_export
+ Vector3d operator - (const Vector3d & v2) const { return Vector3d(x - v2.x, y - v2.y, z - v2.z ); } // tolua_export
+ Vector3d operator - (const Vector3d * v2) const { return Vector3d(x - v2->x, y - v2->y, z - v2->z ); } // tolua_export
+ Vector3d operator * (const double f) const { return Vector3d(x * f, y * f, z * f ); } // tolua_export
+ Vector3d operator * (const Vector3d & v2) const { return Vector3d(x * v2.x, y * v2.y, z * v2.z ); } // tolua_export
+ Vector3d operator / (const double f) const { return Vector3d(x / f, y / f, z / f ); } // tolua_export
double x, y, z; // tolua_export
diff --git a/source/World.cpp b/source/World.cpp
index 053eaedc7..ab783d7a7 100644
--- a/source/World.cpp
+++ b/source/World.cpp
@@ -5,8 +5,6 @@
#include "World.h"
#include "ChunkDef.h"
#include "ClientHandle.h"
-#include "Entities/Pickup.h"
-#include "Entities/Player.h"
#include "Server.h"
#include "Item.h"
#include "Root.h"
@@ -14,6 +12,11 @@
#include "ChunkMap.h"
#include "OSSupport/Timer.h"
+// Entities (except mobs):
+#include "Entities/Pickup.h"
+#include "Entities/Player.h"
+#include "Entities/TNTEntity.h"
+
// Simulators:
#include "Simulator/SimulatorManager.h"
#include "Simulator/FloodyFluidSimulator.h"
@@ -55,7 +58,6 @@
#include "PluginManager.h"
#include "Blocks/BlockHandler.h"
#include "Vector3d.h"
-#include "Entities/TNTEntity.h"
#include "Tracer.h"
#include "tolua++.h"
@@ -2202,15 +2204,12 @@ cPlayer * cWorld::FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit)
Vector3f Pos = (*itr)->GetPosition();
float Distance = (Pos - a_Pos).Length();
- if (Distance <= a_SightLimit)
+ if (Distance < ClosestDistance)
{
if (!LineOfSight.Trace(a_Pos,(Pos - a_Pos),(int)(Pos - a_Pos).Length()))
{
- if (Distance < ClosestDistance)
- {
- ClosestDistance = Distance;
- ClosestPlayer = *itr;
- }
+ ClosestDistance = Distance;
+ ClosestPlayer = *itr;
}
}
}
@@ -2650,6 +2649,26 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp
+int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed)
+{
+ cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Speed);
+ if (Projectile == NULL)
+ {
+ return -1;
+ }
+ if (!Projectile->Initialize(this))
+ {
+ delete Projectile;
+ return -1;
+ }
+ BroadcastSpawnEntity(*Projectile);
+ return Projectile->GetUniqueID();
+}
+
+
+
+
+
void cWorld::TabCompleteUserName(const AString & a_Text, AStringVector & a_Results)
{
cCSLock Lock(m_CSPlayers);
diff --git a/source/World.h b/source/World.h
index 8c90b08c4..1f82f4efc 100644
--- a/source/World.h
+++ b/source/World.h
@@ -1,716 +1,728 @@
-
-#pragma once
-
-#ifndef _WIN32
- #include "BlockID.h"
-#else
- enum ENUM_ITEM_ID;
-#endif
-
-#define MAX_PLAYERS 65535
-
-#include "Simulator/SimulatorManager.h"
-#include "MersenneTwister.h"
-#include "ChunkMap.h"
-#include "WorldStorage/WorldStorage.h"
-#include "Generating/ChunkGenerator.h"
-#include "Vector3i.h"
-#include "Vector3f.h"
-#include "ChunkSender.h"
-#include "Defines.h"
-#include "LightingThread.h"
-#include "Item.h"
-#include "Mobs/Monster.h"
-
-
-
-
-
-class cRedstone;
-class cFireSimulator;
-class cFluidSimulator;
-class cSandSimulator;
-class cRedstoneSimulator;
-class cItem;
-class cPlayer;
-class cClientHandle;
-class cEntity;
-class cBlockEntity;
-class cWorldGenerator; // The generator that actually generates the chunks for a single world
-class cChunkGenerator; // The thread responsible for generating chunks
-class cChestEntity;
-class cDispenserEntity;
-class cFurnaceEntity;
-
-typedef std::list< cPlayer * > cPlayerList;
-
-typedef cItemCallback<cPlayer> cPlayerListCallback;
-typedef cItemCallback<cEntity> cEntityCallback;
-typedef cItemCallback<cChestEntity> cChestCallback;
-typedef cItemCallback<cDispenserEntity> cDispenserCallback;
-typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
-
-
-
-
-
-
-// tolua_begin
-class cWorld
-{
-public:
-
- // tolua_end
-
- /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor
- class cLock :
- public cCSLock
- {
- typedef cCSLock super;
- public:
- cLock(cWorld & a_World);
- } ;
-
- /// A common ancestor for all tasks queued onto the tick thread
- class cTask
- {
- public:
- virtual void Run(cWorld & a_World) = 0;
- } ;
-
- typedef std::vector<cTask *> cTasks;
-
- class cTaskSaveAllChunks :
- public cTask
- {
- protected:
- // cTask overrides:
- virtual void Run(cWorld & a_World) override;
- } ;
-
-
- // tolua_begin
-
- static const char * GetClassStatic(void)
- {
- return "cWorld";
- }
-
- /// Return time in seconds
- inline static float GetTime(void)
- {
- LOGWARNING("cWorld:GetTime() is obsolete, use GetWorldAge() or GetTimeOfDay() for a specific world instead.");
- return 0;
- }
-
- int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
- Int64 GetWorldAge(void) const { return m_WorldAge; }
- Int64 GetTimeOfDay(void) const { return m_TimeOfDay; }
-
- void SetTicksUntilWeatherChange(int a_WeatherInterval)
- {
- m_WeatherInterval = a_WeatherInterval;
- }
-
- void SetTimeOfDay(Int64 a_TimeOfDay)
- {
- m_TimeOfDay = a_TimeOfDay;
- m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
- BroadcastTimeUpdate();
- }
-
- void SetWorldTime(Int64 a_TimeOfDay)
- {
- LOGWARNING("cWorld:SetWorldTime() is obsolete, use SetTimeOfDay() instead");
- SetTimeOfDay(a_TimeOfDay);
- }
-
- /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
- eGameMode GetGameMode(void) const { return m_GameMode; }
-
- /// Returns true if the world is in Creative mode
- bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); }
-
- /// Returns true if the world is in Survival mode
- bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); }
-
- /// Returns true if the world is in Adventure mode
- bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
-
- bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
- bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
-
- eDimension GetDimension(void) const { return m_Dimension; }
-
- /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated
- int GetHeight(int a_BlockX, int a_BlockZ);
-
- // tolua_end
-
- /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated
- bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp
-
- // Broadcast respective packets to all clients of the chunk where the event is taking place
- // (Please keep these alpha-sorted)
- void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
- void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
- void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL);
- void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
- void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export
- void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
- void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
- void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
- void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL);
- void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
- 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); // a_Src coords are Block * 8
- void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
- void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
- void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
- void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
- void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
- void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
-
- /// If there is a block entity at the specified coords, sends it to the client specified
- void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
-
- void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
- void MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
- void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
-
- /** Sets the chunk data as either loaded from the storage or generated.
- a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted.
- a_BiomeMap is optional, if not present, biomes will be calculated by the generator
- a_HeightMap is optional, if not present, will be calculated.
- If a_MarkDirty is set, the chunk is set as dirty (used after generating)
- */
- void SetChunkData(
- int a_ChunkX, int a_ChunkZ,
- const BLOCKTYPE * a_BlockTypes,
- const NIBBLETYPE * a_BlockMeta,
- const NIBBLETYPE * a_BlockLight,
- const NIBBLETYPE * a_BlockSkyLight,
- const cChunkDef::HeightMap * a_HeightMap,
- const cChunkDef::BiomeMap * a_BiomeMap,
- cEntityList & a_Entities,
- cBlockEntityList & a_BlockEntities,
- bool a_MarkDirty
- );
-
- void ChunkLighted(
- int a_ChunkX, int a_ChunkZ,
- const cChunkDef::BlockNibbles & a_BlockLight,
- const cChunkDef::BlockNibbles & a_SkyLight
- );
-
- bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback);
-
- /// Gets the chunk's blocks, only the block types
- bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes);
-
- bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const;
- bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const;
-
- void UnloadUnusedChunks(void); // tolua_export
-
- void CollectPickupsByPlayer(cPlayer * a_Player);
-
- void AddPlayer( cPlayer* a_Player );
- void RemovePlayer( cPlayer* a_Player );
-
- /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true
- bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
-
- /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored
- bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
-
- /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
- bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
-
- // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action)
- cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit);
-
- void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
-
- /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr
- void AddEntity(cEntity * a_Entity);
-
- bool HasEntity(int a_UniqueID);
-
- /// Removes the entity, the entity ptr ownership is assumed taken by the caller
- void RemoveEntity(cEntity * a_Entity);
-
- /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true
- bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true
- bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false.
- bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Compares clients of two chunks, calls the callback accordingly
- void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
-
- /// Adds client to a chunk, if not already present; returns true if added, false if present
- bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
-
- /// Removes client from the chunk specified
- void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
-
- /// Removes the client from all chunks it is present in
- void RemoveClientFromChunks(cClientHandle * a_Client);
-
- /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted)
- void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
-
- /// Removes client from ChunkSender's queue of chunks to be sent
- void RemoveClientFromChunkSender(cClientHandle * a_Client);
-
- /// Touches the chunk, causing it to be loaded or generated
- void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
-
- /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
- bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
-
- /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
- void LoadChunks(const cChunkCoordsList & a_Chunks);
-
- /// Marks the chunk as failed-to-load:
- void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
-
- /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign()
- bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
-
- /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines()
- bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
-
- /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay!
- void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
-
- /// Regenerate the given chunk:
- void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
-
- /// Generates the given chunk, if not already generated
- void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
-
- /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted
- void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL);
-
- bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
-
- /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully
- bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
-
- // tolua_begin
-
- /** Sets the block at the specified coords to the specified value.
- Full processing, incl. updating neighbors, is performed.
- */
- void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
-
- /** Sets the block at the specified coords to the specified value.
- The replacement doesn't trigger block updates.
- The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block)
- */
- void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
-
- /** Queues a SetBlock() with the specified parameters after the specified number of ticks.
- Calls SetBlock(), so performs full processing of the replaced block.
- */
- void QueueSetBlock(int a_BlockX, int a_BLockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay);
-
- BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ);
- NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
- void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
- NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
- NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
- bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
- bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
- // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- // Vector3i variants:
- void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
- BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); }
- NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos ) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); }
- void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); }
- // tolua_end
-
- /** Writes the block area into the specified coords.
- Returns true if all chunks have been processed.
- Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
- a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
- */
- bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
-
- // tolua_begin
-
- /// Spawns item pickups for each item in the list. May compress pickups if too many entities:
- void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0);
-
- /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified:
- void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ);
-
- /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided
- void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
-
- // tolua_end
-
- /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType
- void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
-
- /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read.
- bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
-
- // tolua_begin
- bool DigBlock (int a_X, int a_Y, int a_Z);
- void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
-
- double GetSpawnX(void) const { return m_SpawnX; }
- double GetSpawnY(void) const { return m_SpawnY; }
- double GetSpawnZ(void) const { return m_SpawnZ; }
-
- /// Wakes up the simulators for the specified block
- void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- /// Wakes up the simulators for the specified area of blocks
- void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
-
- // tolua_end
-
- inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; }
-
- inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; }
- inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; }
-
- /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
- bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
- bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
-
- /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true
- bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
-
- /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true
- bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
-
- /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
- bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /** Does an explosion with the specified strength at the specified coordinate
- a_SourceData exact type depends on the a_Source:
- | esOther | void * |
- | esPrimedTNT | cTNTEntity * |
- | esCreeper | cCreeper * |
- | esBed | cVector3i * |
- | esEnderCrystal | Vector3i * |
- | esGhastFireball | TBD |
- | esWitherSkullBlack | TBD |
- | esWitherSkullBlue | TBD |
- | esWitherBirth | TBD |
- | esPlugin | void * |
- */
- void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
-
- /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
- bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found
- bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found
- bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found
- bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found
- bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
-
- /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
- bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // tolua_export
-
- /// a_Player is using block entity at [x, y, z], handle that:
- void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); }
-
- /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback
- bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
-
- void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
- void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export
- void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
-
- void GrowTreeImage(const sSetBlockVector & a_Blocks);
-
- /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini
- bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false); // tolua_export
-
- /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config
- void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); // tolua_export
-
- /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem)
- void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockType); // tolua_export
-
- /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config
- void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); // tolua_export
-
- int GetBiomeAt (int a_BlockX, int a_BlockZ); // tolua_export
-
- const AString & GetName(void) const { return m_WorldName; } // tolua_export
- const AString & GetIniFileName(void) const {return m_IniFileName; }
-
- inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
- {
- // TODO: Use floor() instead of weird if statements
- // Also fix Y
- a_ChunkX = a_X/cChunkDef::Width;
- if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
- a_ChunkY = 0;
- a_ChunkZ = a_Z/cChunkDef::Width;
- if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
-
- a_X = a_X - a_ChunkX*cChunkDef::Width;
- a_Y = a_Y - a_ChunkY*cChunkDef::Height;
- a_Z = a_Z - a_ChunkZ*cChunkDef::Width;
- }
-
- inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
- {
- // TODO: Use floor() instead of weird if statements
- // Also fix Y
- (void)a_Y; // not unused anymore
- a_ChunkX = a_X/cChunkDef::Width;
- if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
- a_ChunkY = 0;
- a_ChunkZ = a_Z/cChunkDef::Width;
- if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
- }
-
- /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead
- void SaveAllChunks(void); // tolua_export
-
- /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources
- void QueueSaveAllChunks(void); // tolua_export
-
- /// Queues a task onto the tick thread. The task object will be deleted once the task is finished
- void QueueTask(cTask * a_Task);
-
- /// Returns the number of chunks loaded
- int GetNumChunks() const; // tolua_export
-
- /// Returns the number of chunks loaded and dirty, and in the lighting queue
- void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue);
-
- // Various queues length queries (cannot be const, they lock their CS):
- inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export
- inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
- inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
- inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
-
- void InitializeSpawn(void);
-
- /// Starts threads that belong to this world
- void Start(void);
-
- /// Stops threads that belong to this world (part of deinit)
- void Stop(void);
-
- void TickQueuedBlocks(float a_Dt);
-
- struct BlockTickQueueItem
- {
- int X;
- int Y;
- int Z;
- float ToWait;
- };
-
- void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, float a_TimeToWait); // tolua_export
-
- // tolua_begin
- /// Casts a thunderbolt at the specified coords
- void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ);
-
- /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change
- void SetWeather (eWeather a_NewWeather);
-
- /// Forces a weather change in the next game tick
- void ChangeWeather (void);
-
- /// Returns the current weather
- eWeather GetWeather (void) const { return m_Weather; };
- // tolua_end
-
- cChunkGenerator & GetGenerator(void) { return m_Generator; }
- cWorldStorage & GetStorage (void) { return m_Storage; }
- cChunkMap * GetChunkMap (void) { return m_ChunkMap; }
-
- /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
- void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
-
- int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export
- int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export
-
- bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
-
- /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
- int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
-
- /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread!
- int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
-
- /// Appends all usernames starting with a_Text (case-insensitive) into Results
- void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
-
-private:
-
- friend class cRoot;
-
- class cTickThread :
- public cIsThread
- {
- typedef cIsThread super;
- public:
- cTickThread(cWorld & a_World);
-
- protected:
- cWorld & m_World;
-
- // cIsThread overrides:
- virtual void Execute(void) override;
- } ;
-
-
- AString m_WorldName;
- AString m_IniFileName;
-
- /// Name of the storage schema used to load and save chunks
- AString m_StorageSchema;
-
- /// The dimension of the world, used by the client to provide correct lighting scheme
- eDimension m_Dimension;
-
- /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
- MTRand m_TickRand;
-
- double m_SpawnX;
- double m_SpawnY;
- double m_SpawnZ;
-
- double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins.
- double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day.
- Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs
- Int64 m_TimeOfDay; // Time in ticks, calculated off of m_TimeOfDaySecs
- Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent.
- Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred
- Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
- Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned
-
- eGameMode m_GameMode;
- bool m_bEnabledPVP;
- bool m_IsDeepSnowEnabled;
-
- // The cRedstone class simulates redstone and needs access to m_RSList
- // friend class cRedstone;
- std::vector<int> m_RSList;
-
- std::vector<BlockTickQueueItem *> m_BlockTickQueue;
- std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue
-
- cSimulatorManager * m_SimulatorManager;
- cSandSimulator * m_SandSimulator;
- cFluidSimulator * m_WaterSimulator;
- cFluidSimulator * m_LavaSimulator;
- cFireSimulator * m_FireSimulator;
- cRedstoneSimulator * m_RedstoneSimulator;
-
- cCriticalSection m_CSPlayers;
- cPlayerList m_Players;
-
- cWorldStorage m_Storage;
-
- unsigned int m_MaxPlayers;
-
- cChunkMap * m_ChunkMap;
-
- bool m_bAnimals;
- Int64 m_SpawnMonsterRate;
-
- eWeather m_Weather;
- int m_WeatherInterval;
-
- int m_MaxCactusHeight;
- int m_MaxSugarcaneHeight;
- bool m_IsCactusBonemealable;
- bool m_IsCarrotsBonemealable;
- bool m_IsCropsBonemealable;
- bool m_IsGrassBonemealable;
- bool m_IsMelonStemBonemealable;
- bool m_IsMelonBonemealable;
- bool m_IsPotatoesBonemealable;
- bool m_IsPumpkinStemBonemealable;
- bool m_IsPumpkinBonemealable;
- bool m_IsSaplingBonemealable;
- bool m_IsSugarcaneBonemealable;
-
- cCriticalSection m_CSFastSetBlock;
- sSetBlockList m_FastSetBlockQueue;
-
- cChunkGenerator m_Generator;
-
- cChunkSender m_ChunkSender;
- cLightingThread m_Lighting;
- cTickThread m_TickThread;
-
- /// Guards the m_Tasks
- cCriticalSection m_CSTasks;
-
- /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
- cTasks m_Tasks;
-
- /// Guards m_Clients
- cCriticalSection m_CSClients;
-
- /// List of clients in this world, these will be ticked by this world
- cClientHandleList m_Clients;
-
- /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them
- cClientHandleList m_ClientsToRemove;
-
- /// Clients that are scheduled for adding, waiting for TickClients to add them
- cClientHandleList m_ClientsToAdd;
-
-
- cWorld(const AString & a_WorldName);
- ~cWorld();
-
- void Tick(float a_Dt);
-
- /// Handles the weather in each tick
- void TickWeather(float a_Dt);
-
- /// Handles the mob spawning each tick
- void TickSpawnMobs(float a_Dt);
-
- /// Executes all tasks queued onto the tick thread
- void TickQueuedTasks(void);
-
- /// Ticks all clients that are in this world
- void TickClients(float a_Dt);
-
- /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
- cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
-}; // tolua_export
-
-
-
-
+
+#pragma once
+
+#ifndef _WIN32
+ #include "BlockID.h"
+#else
+ enum ENUM_ITEM_ID;
+#endif
+
+#define MAX_PLAYERS 65535
+
+#include "Simulator/SimulatorManager.h"
+#include "MersenneTwister.h"
+#include "ChunkMap.h"
+#include "WorldStorage/WorldStorage.h"
+#include "Generating/ChunkGenerator.h"
+#include "Vector3i.h"
+#include "Vector3f.h"
+#include "ChunkSender.h"
+#include "Defines.h"
+#include "LightingThread.h"
+#include "Item.h"
+#include "Mobs/Monster.h"
+#include "Entities/ProjectileEntity.h"
+
+
+
+
+
+class cRedstone;
+class cFireSimulator;
+class cFluidSimulator;
+class cSandSimulator;
+class cRedstoneSimulator;
+class cItem;
+class cPlayer;
+class cClientHandle;
+class cEntity;
+class cBlockEntity;
+class cWorldGenerator; // The generator that actually generates the chunks for a single world
+class cChunkGenerator; // The thread responsible for generating chunks
+class cChestEntity;
+class cDispenserEntity;
+class cFurnaceEntity;
+
+typedef std::list< cPlayer * > cPlayerList;
+
+typedef cItemCallback<cPlayer> cPlayerListCallback;
+typedef cItemCallback<cEntity> cEntityCallback;
+typedef cItemCallback<cChestEntity> cChestCallback;
+typedef cItemCallback<cDispenserEntity> cDispenserCallback;
+typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
+
+
+
+
+
+
+// tolua_begin
+class cWorld
+{
+public:
+
+ // tolua_end
+
+ /// A simple RAII locker for the chunkmap - locks the chunkmap in its constructor, unlocks it in the destructor
+ class cLock :
+ public cCSLock
+ {
+ typedef cCSLock super;
+ public:
+ cLock(cWorld & a_World);
+ } ;
+
+ /// A common ancestor for all tasks queued onto the tick thread
+ class cTask
+ {
+ public:
+ virtual void Run(cWorld & a_World) = 0;
+ } ;
+
+ typedef std::vector<cTask *> cTasks;
+
+ class cTaskSaveAllChunks :
+ public cTask
+ {
+ protected:
+ // cTask overrides:
+ virtual void Run(cWorld & a_World) override;
+ } ;
+
+
+ // tolua_begin
+
+ static const char * GetClassStatic(void)
+ {
+ return "cWorld";
+ }
+
+ /// Return time in seconds
+ inline static float GetTime(void)
+ {
+ LOGWARNING("cWorld:GetTime() is obsolete, use GetWorldAge() or GetTimeOfDay() for a specific world instead.");
+ return 0;
+ }
+
+ int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; }
+ Int64 GetWorldAge(void) const { return m_WorldAge; }
+ Int64 GetTimeOfDay(void) const { return m_TimeOfDay; }
+
+ void SetTicksUntilWeatherChange(int a_WeatherInterval)
+ {
+ m_WeatherInterval = a_WeatherInterval;
+ }
+
+ void SetTimeOfDay(Int64 a_TimeOfDay)
+ {
+ m_TimeOfDay = a_TimeOfDay;
+ m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0;
+ BroadcastTimeUpdate();
+ }
+
+ void SetWorldTime(Int64 a_TimeOfDay)
+ {
+ LOGWARNING("cWorld:SetWorldTime() is obsolete, use SetTimeOfDay() instead");
+ SetTimeOfDay(a_TimeOfDay);
+ }
+
+ /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
+ eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /// Returns true if the world is in Creative mode
+ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); }
+
+ /// Returns true if the world is in Survival mode
+ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); }
+
+ /// Returns true if the world is in Adventure mode
+ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
+
+ bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
+ bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }
+
+ eDimension GetDimension(void) const { return m_Dimension; }
+
+ /// Returns the world height at the specified coords; waits for the chunk to get loaded / generated
+ int GetHeight(int a_BlockX, int a_BlockZ);
+
+ // tolua_end
+
+ /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated
+ bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp
+
+ // Broadcast respective packets to all clients of the chunk where the event is taking place
+ // (Please keep these alpha-sorted)
+ void BroadcastAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle);
+ void BroadcastBlockAction (int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockBreakAnimation(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage, const cClientHandle * a_Exclude = NULL);
+ void BroadcastBlockEntity (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL); ///< If there is a block entity at the specified coods, sends it to all clients except a_Exclude
+ void BroadcastChat (const AString & a_Message, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer, const cClientHandle * a_Exclude = NULL);
+ void BroadcastCollectPickup (const cPickup & a_Pickup, const cPlayer & a_Player, const cClientHandle * a_Exclude = NULL);
+ void BroadcastDestroyEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityHeadLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityLook (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityMetadata (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMove (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityRelMoveLook (const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityStatus (const cEntity & a_Entity, char a_Status, const cClientHandle * a_Exclude = NULL);
+ void BroadcastEntityVelocity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastPlayerAnimation (const cPlayer & a_Player, char a_Animation, const cClientHandle * a_Exclude = NULL);
+ void BroadcastPlayerListItem (const cPlayer & a_Player, bool a_IsOnline, const cClientHandle * a_Exclude = NULL);
+ 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); // tolua_export a_Src coords are Block * 8
+ void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
+ void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
+ void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
+ void BroadcastTimeUpdate (const cClientHandle * a_Exclude = NULL);
+ void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
+ void BroadcastWeather (eWeather a_Weather, const cClientHandle * a_Exclude = NULL);
+
+ /// If there is a block entity at the specified coords, sends it to the client specified
+ void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
+
+ void MarkChunkDirty (int a_ChunkX, int a_ChunkZ);
+ void MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
+ void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
+
+ /** Sets the chunk data as either loaded from the storage or generated.
+ a_BlockLight and a_BlockSkyLight are optional, if not present, chunk will be marked as unlighted.
+ a_BiomeMap is optional, if not present, biomes will be calculated by the generator
+ a_HeightMap is optional, if not present, will be calculated.
+ If a_MarkDirty is set, the chunk is set as dirty (used after generating)
+ */
+ void SetChunkData(
+ int a_ChunkX, int a_ChunkZ,
+ const BLOCKTYPE * a_BlockTypes,
+ const NIBBLETYPE * a_BlockMeta,
+ const NIBBLETYPE * a_BlockLight,
+ const NIBBLETYPE * a_BlockSkyLight,
+ const cChunkDef::HeightMap * a_HeightMap,
+ const cChunkDef::BiomeMap * a_BiomeMap,
+ cEntityList & a_Entities,
+ cBlockEntityList & a_BlockEntities,
+ bool a_MarkDirty
+ );
+
+ void ChunkLighted(
+ int a_ChunkX, int a_ChunkZ,
+ const cChunkDef::BlockNibbles & a_BlockLight,
+ const cChunkDef::BlockNibbles & a_SkyLight
+ );
+
+ bool GetChunkData (int a_ChunkX, int a_ChunkZ, cChunkDataCallback & a_Callback);
+
+ /// Gets the chunk's blocks, only the block types
+ bool GetChunkBlockTypes(int a_ChunkX, int a_ChunkZ, BLOCKTYPE * a_BlockTypes);
+
+ bool IsChunkValid (int a_ChunkX, int a_ChunkZ) const;
+ bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) const;
+
+ void UnloadUnusedChunks(void); // tolua_export
+
+ void CollectPickupsByPlayer(cPlayer * a_Player);
+
+ void AddPlayer( cPlayer* a_Player );
+ void RemovePlayer( cPlayer* a_Player );
+
+ /// Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true
+ bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. Callback return ignored
+ bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ /// Finds a player from a partial or complete player name and calls the callback - case-insensitive
+ bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
+
+ // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action)
+ cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit);
+
+ void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
+
+ /// Adds the entity into its appropriate chunk; takes ownership of the entity ptr
+ void AddEntity(cEntity * a_Entity);
+
+ bool HasEntity(int a_UniqueID);
+
+ /// Removes the entity, the entity ptr ownership is assumed taken by the caller
+ void RemoveEntity(cEntity * a_Entity);
+
+ /// Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true
+ bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true
+ bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false.
+ bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Compares clients of two chunks, calls the callback accordingly
+ void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
+
+ /// Adds client to a chunk, if not already present; returns true if added, false if present
+ bool AddChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from the chunk specified
+ void RemoveChunkClient(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes the client from all chunks it is present in
+ void RemoveClientFromChunks(cClientHandle * a_Client);
+
+ /// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is postponed (ChunkSender will send that chunk when it becomes valid+lighted)
+ void SendChunkTo(int a_ChunkX, int a_ChunkZ, cClientHandle * a_Client);
+
+ /// Removes client from ChunkSender's queue of chunks to be sent
+ void RemoveClientFromChunkSender(cClientHandle * a_Client);
+
+ /// Touches the chunk, causing it to be loaded or generated
+ void TouchChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Loads the chunk, if not already loaded. Doesn't generate. Returns true if chunk valid (even if already loaded before)
+ bool LoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Loads the chunks specified. Doesn't report failure, other than chunks being !IsValid()
+ void LoadChunks(const cChunkCoordsList & a_Chunks);
+
+ /// Marks the chunk as failed-to-load:
+ void ChunkLoadFailed(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
+
+ /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as UpdateSign()
+ bool SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
+
+ /// Sets the sign text, asking plugins for permission first. a_Player is the player who this change belongs to, may be NULL. Returns true if sign text changed. Same as SetSignLines()
+ bool UpdateSign(int a_X, int a_Y, int a_Z, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4, cPlayer * a_Player = NULL); // Exported in ManualBindings.cpp
+
+ /// Marks (a_Stay == true) or unmarks (a_Stay == false) chunks as non-unloadable. To be used only by cChunkStay!
+ void ChunksStay(const cChunkCoordsList & a_Chunks, bool a_Stay = true);
+
+ /// Regenerate the given chunk:
+ void RegenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
+
+ /// Generates the given chunk, if not already generated
+ void GenerateChunk(int a_ChunkX, int a_ChunkZ); // tolua_export
+
+ /// Queues a chunk for lighting; a_Callback is called after the chunk is lighted
+ void QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback = NULL);
+
+ bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
+
+ /// Calls the callback for each chunk in the coords specified (all cords are inclusive). Returns true if all chunks have been processed successfully
+ bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
+
+ // tolua_begin
+
+ /** Sets the block at the specified coords to the specified value.
+ Full processing, incl. updating neighbors, is performed.
+ */
+ void SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ /** Sets the block at the specified coords to the specified value.
+ The replacement doesn't trigger block updates.
+ The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block)
+ */
+ void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
+
+ /** Queues a SetBlock() with the specified parameters after the specified number of ticks.
+ Calls SetBlock(), so performs full processing of the replaced block.
+ */
+ void QueueSetBlock(int a_BlockX, int a_BLockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay);
+
+ BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ);
+ NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
+ void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
+ NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
+ NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+ bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
+ bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
+ // TODO: NIBBLETYPE GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ // Vector3i variants:
+ void FastSetBlock(const Vector3i & a_Pos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { FastSetBlock( a_Pos.x, a_Pos.y, a_Pos.z, a_BlockType, a_BlockMeta ); }
+ BLOCKTYPE GetBlock (const Vector3i & a_Pos ) { return GetBlock( a_Pos.x, a_Pos.y, a_Pos.z ); }
+ NIBBLETYPE GetBlockMeta(const Vector3i & a_Pos ) { return GetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z ); }
+ void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); }
+ // tolua_end
+
+ /** Writes the block area into the specified coords.
+ Returns true if all chunks have been processed.
+ Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too.
+ a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together.
+ */
+ bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);
+
+ // tolua_begin
+
+ /// Spawns item pickups for each item in the list. May compress pickups if too many entities:
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0);
+
+ /// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified:
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ);
+
+ /// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided
+ void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
+
+ // tolua_end
+
+ /// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType
+ void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
+
+ /// Retrieves block types of the specified blocks. If a chunk is not loaded, doesn't modify the block. Returns true if all blocks were read.
+ bool GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure);
+
+ // tolua_begin
+ bool DigBlock (int a_X, int a_Y, int a_Z);
+ void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
+
+ double GetSpawnX(void) const { return m_SpawnX; }
+ double GetSpawnY(void) const { return m_SpawnY; }
+ double GetSpawnZ(void) const { return m_SpawnZ; }
+
+ /// Wakes up the simulators for the specified block
+ void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /// Wakes up the simulators for the specified area of blocks
+ void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
+
+ // tolua_end
+
+ inline cSimulatorManager * GetSimulatorManager(void) { return m_SimulatorManager; }
+
+ inline cFluidSimulator * GetWaterSimulator(void) { return m_WaterSimulator; }
+ inline cFluidSimulator * GetLavaSimulator (void) { return m_LavaSimulator; }
+
+ /// Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true
+ bool ForEachChestInChunk (int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true
+ bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
+
+ /// Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true
+ bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
+
+ /// Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true
+ bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
+
+ /// Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true
+ bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /** Does an explosion with the specified strength at the specified coordinate
+ a_SourceData exact type depends on the a_Source:
+ | esOther | void * |
+ | esPrimedTNT | cTNTEntity * |
+ | esCreeper | cCreeper * |
+ | esBed | cVector3i * |
+ | esEnderCrystal | Vector3i * |
+ | esGhastFireball | TBD |
+ | esWitherSkullBlack | TBD |
+ | esWitherSkullBlue | TBD |
+ | esWitherBirth | TBD |
+ | esPlugin | void * |
+ */
+ void DoExplosiontAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export
+
+ /// Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found
+ bool DoWithChestAt (int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found
+ bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found
+ bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found
+ bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found
+ bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
+
+ /// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
+ bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // tolua_export
+
+ /// a_Player is using block entity at [x, y, z], handle that:
+ void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); }
+
+ /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback
+ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
+
+ void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+ void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export
+ void GrowTreeByBiome (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ void GrowTreeImage(const sSetBlockVector & a_Blocks);
+
+ // tolua_begin
+
+ /// Grows the plant at the specified block to its ripe stage (bonemeal used); returns false if the block is not growable. If a_IsBonemeal is true, block is not grown if not allowed in world.ini
+ bool GrowRipePlant(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_IsByBonemeal = false);
+
+ /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config
+ void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+
+ /// Grows a melon or a pumpkin next to the block specified (assumed to be the stem)
+ void GrowMelonPumpkin(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockType);
+
+ /// Grows a sugarcane present at the block specified by the amount of blocks specified, up to the max height specified in the config
+ void GrowSugarcane(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow);
+
+ /// Returns the biome at the specified coords. Reads the biome from the chunk, if loaded, otherwise uses the world generator to provide the biome value
+ int GetBiomeAt(int a_BlockX, int a_BlockZ);
+
+ /// Returns the name of the world
+ const AString & GetName(void) const { return m_WorldName; }
+
+ /// Returns the name of the world.ini file used by this world
+ const AString & GetIniFileName(void) const {return m_IniFileName; }
+
+ // tolua_end
+
+ inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
+ {
+ // TODO: Use floor() instead of weird if statements
+ // Also fix Y
+ a_ChunkX = a_X/cChunkDef::Width;
+ if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
+ a_ChunkY = 0;
+ a_ChunkZ = a_Z/cChunkDef::Width;
+ if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
+
+ a_X = a_X - a_ChunkX*cChunkDef::Width;
+ a_Y = a_Y - a_ChunkY*cChunkDef::Height;
+ a_Z = a_Z - a_ChunkZ*cChunkDef::Width;
+ }
+
+ inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
+ {
+ // TODO: Use floor() instead of weird if statements
+ // Also fix Y
+ (void)a_Y; // not unused anymore
+ a_ChunkX = a_X/cChunkDef::Width;
+ if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
+ a_ChunkY = 0;
+ a_ChunkZ = a_Z/cChunkDef::Width;
+ if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
+ }
+
+ /// Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead
+ void SaveAllChunks(void); // tolua_export
+
+ /// Queues a task to save all chunks onto the tick thread. The prefferred way of saving chunks from external sources
+ void QueueSaveAllChunks(void); // tolua_export
+
+ /// Queues a task onto the tick thread. The task object will be deleted once the task is finished
+ void QueueTask(cTask * a_Task);
+
+ /// Returns the number of chunks loaded
+ int GetNumChunks() const; // tolua_export
+
+ /// Returns the number of chunks loaded and dirty, and in the lighting queue
+ void GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue);
+
+ // Various queues length queries (cannot be const, they lock their CS):
+ inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export
+ inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export
+ inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export
+ inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export
+
+ void InitializeSpawn(void);
+
+ /// Starts threads that belong to this world
+ void Start(void);
+
+ /// Stops threads that belong to this world (part of deinit)
+ void Stop(void);
+
+ void TickQueuedBlocks(float a_Dt);
+
+ struct BlockTickQueueItem
+ {
+ int X;
+ int Y;
+ int Z;
+ float ToWait;
+ };
+
+ void QueueBlockForTick(int a_BlockX, int a_BlockY, int a_BlockZ, float a_TimeToWait); // tolua_export
+
+ // tolua_begin
+ /// Casts a thunderbolt at the specified coords
+ void CastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ);
+
+ /// Sets the specified weather; resets weather interval; asks and notifies plugins of the change
+ void SetWeather (eWeather a_NewWeather);
+
+ /// Forces a weather change in the next game tick
+ void ChangeWeather (void);
+
+ /// Returns the current weather
+ eWeather GetWeather (void) const { return m_Weather; };
+ // tolua_end
+
+ cChunkGenerator & GetGenerator(void) { return m_Generator; }
+ cWorldStorage & GetStorage (void) { return m_Storage; }
+ cChunkMap * GetChunkMap (void) { return m_ChunkMap; }
+
+ /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call
+ void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ int GetMaxSugarcaneHeight(void) const { return m_MaxSugarcaneHeight; } // tolua_export
+ int GetMaxCactusHeight (void) const { return m_MaxCactusHeight; } // tolua_export
+
+ bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
+
+ /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
+ int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
+
+ /// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
+ int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
+
+ /// Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread!
+ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
+
+ /// Appends all usernames starting with a_Text (case-insensitive) into Results
+ void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
+
+private:
+
+ friend class cRoot;
+
+ class cTickThread :
+ public cIsThread
+ {
+ typedef cIsThread super;
+ public:
+ cTickThread(cWorld & a_World);
+
+ protected:
+ cWorld & m_World;
+
+ // cIsThread overrides:
+ virtual void Execute(void) override;
+ } ;
+
+
+ AString m_WorldName;
+ AString m_IniFileName;
+
+ /// Name of the storage schema used to load and save chunks
+ AString m_StorageSchema;
+
+ /// The dimension of the world, used by the client to provide correct lighting scheme
+ eDimension m_Dimension;
+
+ /// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
+ MTRand m_TickRand;
+
+ double m_SpawnX;
+ double m_SpawnY;
+ double m_SpawnZ;
+
+ double m_WorldAgeSecs; // World age, in seconds. Is only incremented, cannot be set by plugins.
+ double m_TimeOfDaySecs; // Time of day in seconds. Can be adjusted. Is wrapped to zero each day.
+ Int64 m_WorldAge; // World age in ticks, calculated off of m_WorldAgeSecs
+ Int64 m_TimeOfDay; // Time in ticks, calculated off of m_TimeOfDaySecs
+ Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent.
+ Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred
+ Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
+ Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned
+
+ eGameMode m_GameMode;
+ bool m_bEnabledPVP;
+ bool m_IsDeepSnowEnabled;
+
+ // The cRedstone class simulates redstone and needs access to m_RSList
+ // friend class cRedstone;
+ std::vector<int> m_RSList;
+
+ std::vector<BlockTickQueueItem *> m_BlockTickQueue;
+ std::vector<BlockTickQueueItem *> m_BlockTickQueueCopy; //Second is for safely removing the objects from the queue
+
+ cSimulatorManager * m_SimulatorManager;
+ cSandSimulator * m_SandSimulator;
+ cFluidSimulator * m_WaterSimulator;
+ cFluidSimulator * m_LavaSimulator;
+ cFireSimulator * m_FireSimulator;
+ cRedstoneSimulator * m_RedstoneSimulator;
+
+ cCriticalSection m_CSPlayers;
+ cPlayerList m_Players;
+
+ cWorldStorage m_Storage;
+
+ unsigned int m_MaxPlayers;
+
+ cChunkMap * m_ChunkMap;
+
+ bool m_bAnimals;
+ Int64 m_SpawnMonsterRate;
+
+ eWeather m_Weather;
+ int m_WeatherInterval;
+
+ int m_MaxCactusHeight;
+ int m_MaxSugarcaneHeight;
+ bool m_IsCactusBonemealable;
+ bool m_IsCarrotsBonemealable;
+ bool m_IsCropsBonemealable;
+ bool m_IsGrassBonemealable;
+ bool m_IsMelonStemBonemealable;
+ bool m_IsMelonBonemealable;
+ bool m_IsPotatoesBonemealable;
+ bool m_IsPumpkinStemBonemealable;
+ bool m_IsPumpkinBonemealable;
+ bool m_IsSaplingBonemealable;
+ bool m_IsSugarcaneBonemealable;
+
+ cCriticalSection m_CSFastSetBlock;
+ sSetBlockList m_FastSetBlockQueue;
+
+ cChunkGenerator m_Generator;
+
+ cChunkSender m_ChunkSender;
+ cLightingThread m_Lighting;
+ cTickThread m_TickThread;
+
+ /// Guards the m_Tasks
+ cCriticalSection m_CSTasks;
+
+ /// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
+ cTasks m_Tasks;
+
+ /// Guards m_Clients
+ cCriticalSection m_CSClients;
+
+ /// List of clients in this world, these will be ticked by this world
+ cClientHandleList m_Clients;
+
+ /// Clients that are scheduled for removal (ticked in another world), waiting for TickClients() to remove them
+ cClientHandleList m_ClientsToRemove;
+
+ /// Clients that are scheduled for adding, waiting for TickClients to add them
+ cClientHandleList m_ClientsToAdd;
+
+
+ cWorld(const AString & a_WorldName);
+ ~cWorld();
+
+ void Tick(float a_Dt);
+
+ /// Handles the weather in each tick
+ void TickWeather(float a_Dt);
+
+ /// Handles the mob spawning each tick
+ void TickSpawnMobs(float a_Dt);
+
+ /// Executes all tasks queued onto the tick thread
+ void TickQueuedTasks(void);
+
+ /// Ticks all clients that are in this world
+ void TickClients(float a_Dt);
+
+ /// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
+ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
+}; // tolua_export
+
+
+
+
diff --git a/source/WorldStorage/NBTChunkSerializer.cpp b/source/WorldStorage/NBTChunkSerializer.cpp
index 706e913ef..baae0dc01 100644
--- a/source/WorldStorage/NBTChunkSerializer.cpp
+++ b/source/WorldStorage/NBTChunkSerializer.cpp
@@ -22,6 +22,8 @@
#include "../Entities/Minecart.h"
#include "../Mobs/Monster.h"
#include "../Entities/Pickup.h"
+#include "../Entities/ProjectileEntity.h"
+
@@ -330,6 +332,62 @@ void cNBTChunkSerializer::AddPickupEntity(cPickup * a_Pickup)
+void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
+{
+ m_Writer.BeginCompound("");
+ AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
+ Vector3d Pos = a_Projectile->GetPosition();
+ m_Writer.AddShort("xTile", (Int16)floor(Pos.x));
+ m_Writer.AddShort("yTile", (Int16)floor(Pos.y));
+ m_Writer.AddShort("zTile", (Int16)floor(Pos.z));
+ m_Writer.AddShort("inTile", 0); // TODO: Query the block type (is it needed?)
+ m_Writer.AddShort("shake", 0); // TODO: Any shake?
+ m_Writer.AddByte ("inGround", a_Projectile->IsInGround() ? 1 : 0);
+
+ switch (a_Projectile->GetProjectileKind())
+ {
+ case cProjectileEntity::pkArrow:
+ {
+ m_Writer.AddByte("inData", 0); // TODO: Query the block meta (is it needed?)
+ m_Writer.AddByte("pickup", ((cArrowEntity *)a_Projectile)->GetPickupState());
+ m_Writer.AddDouble("damage", ((cArrowEntity *)a_Projectile)->GetDamageCoeff());
+ break;
+ }
+ case cProjectileEntity::pkGhastFireball:
+ {
+ m_Writer.AddInt("ExplosionPower", 1);
+ // fall-through:
+ }
+ case cProjectileEntity::pkFireCharge:
+ case cProjectileEntity::pkWitherSkull:
+ {
+ m_Writer.BeginList("Motion", TAG_Double);
+ m_Writer.AddDouble("", a_Projectile->GetSpeedX());
+ m_Writer.AddDouble("", a_Projectile->GetSpeedY());
+ m_Writer.AddDouble("", a_Projectile->GetSpeedZ());
+ m_Writer.EndList();
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unsaved projectile entity!");
+ }
+ } // switch (ProjectileKind)
+ cEntity * Creator = a_Projectile->GetCreator();
+ if (Creator != NULL)
+ {
+ if (Creator->GetEntityType() == cEntity::etPlayer)
+ {
+ m_Writer.AddString("ownerName", ((cPlayer *)Creator)->GetName());
+ }
+ }
+ m_Writer.EndCompound();
+}
+
+
+
+
+
void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Minecart)
{
m_Writer.BeginList("Items", TAG_Compound);
@@ -403,10 +461,11 @@ void cNBTChunkSerializer::Entity(cEntity * a_Entity)
switch (a_Entity->GetEntityType())
{
- case cEntity::etFallingBlock: AddFallingBlockEntity((cFallingBlock *)a_Entity); break;
- case cEntity::etMinecart: AddMinecartEntity ((cMinecart *) a_Entity); break;
- case cEntity::etMonster: AddMonsterEntity ((cMonster *) a_Entity); break;
- case cEntity::etPickup: AddPickupEntity ((cPickup *) 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;
+ case cEntity::etPickup: AddPickupEntity ((cPickup *) a_Entity); break;
+ case cEntity::etProjectile: AddProjectileEntity ((cProjectileEntity *)a_Entity); break;
case cEntity::etPlayer: return; // Players aren't saved into the world
default:
{
diff --git a/source/WorldStorage/NBTChunkSerializer.h b/source/WorldStorage/NBTChunkSerializer.h
index cd1388f89..481c578f3 100644
--- a/source/WorldStorage/NBTChunkSerializer.h
+++ b/source/WorldStorage/NBTChunkSerializer.h
@@ -36,6 +36,7 @@ class cMinecartWithHopper;
class cMonster;
class cPickup;
class cItemGrid;
+class cProjectileEntity;
@@ -97,6 +98,7 @@ protected:
void AddMinecartEntity (cMinecart * a_Minecart);
void AddMonsterEntity (cMonster * a_Monster);
void AddPickupEntity (cPickup * a_Pickup);
+ void AddProjectileEntity (cProjectileEntity * a_Projectile);
void AddMinecartChestContents(cMinecartWithChest * a_Minecart);
diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp
index 72d583e2b..3ab64148e 100644
--- a/source/WorldStorage/WSSAnvil.cpp
+++ b/source/WorldStorage/WSSAnvil.cpp
@@ -20,13 +20,13 @@
#include "../Item.h"
#include "../ItemGrid.h"
#include "../StringCompression.h"
-#include "../Entities/Entity.h"
#include "../OSSupport/MakeDir.h"
#include "FastNBT.h"
+#include "../Mobs/Monster.h"
#include "../Entities/FallingBlock.h"
#include "../Entities/Minecart.h"
-#include "../Mobs/Monster.h"
#include "../Entities/Pickup.h"
+#include "../Entities/ProjectileEntity.h"
@@ -956,6 +956,10 @@ void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a
{
LoadPickupFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
}
+ if (strncmp(a_IDTag, "Arrow", a_IDTagLength) == 0)
+ {
+ LoadArrowFromNBT(a_Entities, a_NBT, a_EntityTagIdx);
+ }
// TODO: other entities
}
@@ -1043,7 +1047,7 @@ void cWSSAnvil::LoadMinecartTFromNBT(cEntityList & a_Entities, const cParsedNBT
return;
}
- //TODO: Everything to do with TNT carts
+ // TODO: Everything to do with TNT carts
a_Entities.push_back(Minecart.release());
}
@@ -1060,7 +1064,7 @@ void cWSSAnvil::LoadMinecartHFromNBT(cEntityList & a_Entities, const cParsedNBT
return;
}
- //TODO: Everything to do with hopper carts
+ // TODO: Everything to do with hopper carts
a_Entities.push_back(Minecart.release());
}
@@ -1093,6 +1097,45 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a
+void cWSSAnvil::LoadArrowFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
+{
+ std::auto_ptr<cArrowEntity> Arrow(new cArrowEntity(NULL, 0, 0, 0, Vector3d(0, 0, 0)));
+ if (!LoadEntityBaseFromNBT(*Arrow.get(), a_NBT, a_TagIdx))
+ {
+ return;
+ }
+
+ // Load pickup state:
+ int PickupIdx = a_NBT.FindChildByName(a_TagIdx, "pickup");
+ if (PickupIdx > 0)
+ {
+ Arrow->SetPickupState((cArrowEntity::ePickupState)a_NBT.GetByte(PickupIdx));
+ }
+ else
+ {
+ // Try the older "player" tag:
+ int PlayerIdx = a_NBT.FindChildByName(a_TagIdx, "player");
+ if (PlayerIdx > 0)
+ {
+ Arrow->SetPickupState((a_NBT.GetByte(PlayerIdx) == 0) ? cArrowEntity::psNoPickup : cArrowEntity::psInSurvivalOrCreative);
+ }
+ }
+
+ // Load damage:
+ int DamageIdx = a_NBT.FindChildByName(a_TagIdx, "damage");
+ if (DamageIdx > 0)
+ {
+ Arrow->SetDamageCoeff(a_NBT.GetDouble(DamageIdx));
+ }
+
+ // Store the new arrow in the entities list:
+ a_Entities.push_back(Arrow.release());
+}
+
+
+
+
+
bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx)
{
double Pos[3];
diff --git a/source/WorldStorage/WSSAnvil.h b/source/WorldStorage/WSSAnvil.h
index 47fda3f7b..b2556ab50 100644
--- a/source/WorldStorage/WSSAnvil.h
+++ b/source/WorldStorage/WSSAnvil.h
@@ -145,6 +145,7 @@ protected:
void LoadMinecartTFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadMinecartHFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadPickupFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
+ void LoadArrowFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx);
/// Loads entity common data from the NBT compound; returns true if successful
bool LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_NBT, int a_TagIdx);