Merged the composable_generator branch into the trunk
git-svn-id: http://mc-server.googlecode.com/svn/trunk@504 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
5f29a3e134
commit
a4a418a679
|
@ -264,6 +264,10 @@
|
||||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\BlockID.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\BlockID.h"
|
RelativePath="..\source\BlockID.h"
|
||||||
>
|
>
|
||||||
|
@ -336,14 +340,6 @@
|
||||||
RelativePath="..\source\cFurnaceRecipe.h"
|
RelativePath="..\source\cFurnaceRecipe.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\source\cGenSettings.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\source\cGenSettings.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cGroup.cpp"
|
RelativePath="..\source\cGroup.cpp"
|
||||||
>
|
>
|
||||||
|
@ -462,22 +458,6 @@
|
||||||
RelativePath="..\source\cPiston.h"
|
RelativePath="..\source\cPiston.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\source\cPlugin.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\source\cPlugin.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\source\cPluginManager.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\source\cPluginManager.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cRecipeChecker.cpp"
|
RelativePath="..\source\cRecipeChecker.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1659,6 +1639,14 @@
|
||||||
RelativePath="..\source\cLuaCommandBinder.h"
|
RelativePath="..\source\cLuaCommandBinder.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\cPlugin.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\cPlugin.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cPlugin_Lua.cpp"
|
RelativePath="..\source\cPlugin_Lua.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1675,6 +1663,14 @@
|
||||||
RelativePath="..\source\cPlugin_NewLua.h"
|
RelativePath="..\source\cPlugin_NewLua.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\cPluginManager.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\cPluginManager.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cStringMap.cpp"
|
RelativePath="..\source\cStringMap.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1747,14 +1743,6 @@
|
||||||
RelativePath="..\source\FastNBT.h"
|
RelativePath="..\source\FastNBT.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\source\NBT.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\source\NBT.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\WorldStorage.cpp"
|
RelativePath="..\source\WorldStorage.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1783,6 +1771,14 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="Generating"
|
Name="Generating"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\BioGen.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\BioGen.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cChunkGenerator.cpp"
|
RelativePath="..\source\cChunkGenerator.cpp"
|
||||||
>
|
>
|
||||||
|
@ -1792,31 +1788,87 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cWorldGenerator.cpp"
|
RelativePath="..\source\CompoGen.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cWorldGenerator.h"
|
RelativePath="..\source\CompoGen.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cWorldGenerator_Test.cpp"
|
RelativePath="..\source\FinishGen.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\cWorldGenerator_Test.h"
|
RelativePath="..\source\FinishGen.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\WGFlat.cpp"
|
RelativePath="..\source\HeiGen.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\source\WGFlat.h"
|
RelativePath="..\source\HeiGen.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\StructGen.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\StructGen.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Trees.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\source\Trees.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Config files"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\banned.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\furnace.txt"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\groups.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\items.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\monsters.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\settings.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\users.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\webadmin.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\world\world.ini"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
</Filter>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\makefile"
|
RelativePath="..\makefile"
|
||||||
>
|
>
|
||||||
|
|
|
@ -302,6 +302,8 @@
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\source\BioGen.cpp" />
|
||||||
|
<ClCompile Include="..\source\BlockID.cpp" />
|
||||||
<ClCompile Include="..\source\cAggressiveMonster.cpp" />
|
<ClCompile Include="..\source\cAggressiveMonster.cpp" />
|
||||||
<ClCompile Include="..\Source\cAuthenticator.cpp" />
|
<ClCompile Include="..\Source\cAuthenticator.cpp" />
|
||||||
<ClCompile Include="..\source\cBlockingTCPLink.cpp" />
|
<ClCompile Include="..\source\cBlockingTCPLink.cpp" />
|
||||||
|
@ -324,7 +326,6 @@
|
||||||
<ClCompile Include="..\source\cFurnaceEntity.cpp" />
|
<ClCompile Include="..\source\cFurnaceEntity.cpp" />
|
||||||
<ClCompile Include="..\Source\cFurnaceRecipe.cpp" />
|
<ClCompile Include="..\Source\cFurnaceRecipe.cpp" />
|
||||||
<ClCompile Include="..\source\cFurnaceWindow.cpp" />
|
<ClCompile Include="..\source\cFurnaceWindow.cpp" />
|
||||||
<ClCompile Include="..\source\cGenSettings.cpp" />
|
|
||||||
<ClCompile Include="..\source\cGhast.cpp" />
|
<ClCompile Include="..\source\cGhast.cpp" />
|
||||||
<ClCompile Include="..\Source\cGroup.cpp" />
|
<ClCompile Include="..\Source\cGroup.cpp" />
|
||||||
<ClCompile Include="..\Source\cGroupManager.cpp" />
|
<ClCompile Include="..\Source\cGroupManager.cpp" />
|
||||||
|
@ -347,6 +348,7 @@
|
||||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">Default</BasicRuntimeChecks>
|
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">Default</BasicRuntimeChecks>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\CompoGen.cpp" />
|
||||||
<ClCompile Include="..\source\cPassiveAggressiveMonster.cpp" />
|
<ClCompile Include="..\source\cPassiveAggressiveMonster.cpp" />
|
||||||
<ClCompile Include="..\source\cPassiveMonster.cpp" />
|
<ClCompile Include="..\source\cPassiveMonster.cpp" />
|
||||||
<ClCompile Include="..\Source\cPawn.cpp" />
|
<ClCompile Include="..\Source\cPawn.cpp" />
|
||||||
|
@ -386,16 +388,16 @@
|
||||||
<ClCompile Include="..\source\cWebPlugin_Lua.cpp" />
|
<ClCompile Include="..\source\cWebPlugin_Lua.cpp" />
|
||||||
<ClCompile Include="..\source\cWindow.cpp" />
|
<ClCompile Include="..\source\cWindow.cpp" />
|
||||||
<ClCompile Include="..\source\cWolf.cpp" />
|
<ClCompile Include="..\source\cWolf.cpp" />
|
||||||
<ClCompile Include="..\source\cWorldGenerator.cpp" />
|
|
||||||
<ClCompile Include="..\source\cWorldGenerator_Test.cpp" />
|
|
||||||
<ClCompile Include="..\source\cZombie.cpp" />
|
<ClCompile Include="..\source\cZombie.cpp" />
|
||||||
<ClCompile Include="..\source\cZombiepigman.cpp" />
|
<ClCompile Include="..\source\cZombiepigman.cpp" />
|
||||||
|
<ClCompile Include="..\source\FinishGen.cpp" />
|
||||||
<ClCompile Include="..\source\FastNBT.cpp" />
|
<ClCompile Include="..\source\FastNBT.cpp" />
|
||||||
<ClCompile Include="..\source\Globals.cpp">
|
<ClCompile Include="..\source\Globals.cpp">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\HeiGen.cpp" />
|
||||||
<ClCompile Include="..\source\LeakFinder.cpp">
|
<ClCompile Include="..\source\LeakFinder.cpp">
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
||||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||||
|
@ -422,7 +424,6 @@
|
||||||
<ClCompile Include="..\source\cLog.cpp" />
|
<ClCompile Include="..\source\cLog.cpp" />
|
||||||
<ClCompile Include="..\source\Bindings.cpp" />
|
<ClCompile Include="..\source\Bindings.cpp" />
|
||||||
<ClCompile Include="..\source\main.cpp" />
|
<ClCompile Include="..\source\main.cpp" />
|
||||||
<ClCompile Include="..\source\NBT.cpp" />
|
|
||||||
<ClCompile Include="..\source\packets\cPacket.cpp" />
|
<ClCompile Include="..\source\packets\cPacket.cpp" />
|
||||||
<ClCompile Include="..\source\packets\cPacket_13.cpp" />
|
<ClCompile Include="..\source\packets\cPacket_13.cpp" />
|
||||||
<ClCompile Include="..\source\packets\cPacket_AddToInventory.cpp" />
|
<ClCompile Include="..\source\packets\cPacket_AddToInventory.cpp" />
|
||||||
|
@ -480,15 +481,17 @@
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\StringCompression.cpp" />
|
<ClCompile Include="..\source\StringCompression.cpp" />
|
||||||
<ClCompile Include="..\source\StringUtils.cpp" />
|
<ClCompile Include="..\source\StringUtils.cpp" />
|
||||||
|
<ClCompile Include="..\source\StructGen.cpp" />
|
||||||
|
<ClCompile Include="..\source\Trees.cpp" />
|
||||||
<ClCompile Include="..\source\Vector3d.cpp" />
|
<ClCompile Include="..\source\Vector3d.cpp" />
|
||||||
<ClCompile Include="..\source\Vector3f.cpp" />
|
<ClCompile Include="..\source\Vector3f.cpp" />
|
||||||
<ClCompile Include="..\source\Vector3i.cpp" />
|
<ClCompile Include="..\source\Vector3i.cpp" />
|
||||||
<ClCompile Include="..\source\WGFlat.cpp" />
|
|
||||||
<ClCompile Include="..\source\WorldStorage.cpp" />
|
<ClCompile Include="..\source\WorldStorage.cpp" />
|
||||||
<ClCompile Include="..\source\WSSAnvil.cpp" />
|
<ClCompile Include="..\source\WSSAnvil.cpp" />
|
||||||
<ClCompile Include="..\source\WSSCompact.cpp" />
|
<ClCompile Include="..\source\WSSCompact.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\source\BioGen.h" />
|
||||||
<ClInclude Include="..\Source\BlockID.h" />
|
<ClInclude Include="..\Source\BlockID.h" />
|
||||||
<ClInclude Include="..\source\cAggressiveMonster.h" />
|
<ClInclude Include="..\source\cAggressiveMonster.h" />
|
||||||
<ClInclude Include="..\Source\cAuthenticator.h" />
|
<ClInclude Include="..\Source\cAuthenticator.h" />
|
||||||
|
@ -526,6 +529,7 @@
|
||||||
<ClInclude Include="..\Source\cMonster.h" />
|
<ClInclude Include="..\Source\cMonster.h" />
|
||||||
<ClInclude Include="..\source\cMonsterConfig.h" />
|
<ClInclude Include="..\source\cMonsterConfig.h" />
|
||||||
<ClInclude Include="..\source\cNoise.h" />
|
<ClInclude Include="..\source\cNoise.h" />
|
||||||
|
<ClInclude Include="..\source\CompoGen.h" />
|
||||||
<ClInclude Include="..\source\cPassiveAggressiveMonster.h" />
|
<ClInclude Include="..\source\cPassiveAggressiveMonster.h" />
|
||||||
<ClInclude Include="..\source\cPassiveMonster.h" />
|
<ClInclude Include="..\source\cPassiveMonster.h" />
|
||||||
<ClInclude Include="..\Source\cPawn.h" />
|
<ClInclude Include="..\Source\cPawn.h" />
|
||||||
|
@ -558,7 +562,6 @@
|
||||||
<ClInclude Include="..\source\cStringMap.h" />
|
<ClInclude Include="..\source\cStringMap.h" />
|
||||||
<ClInclude Include="..\source\cSurvivalInventory.h" />
|
<ClInclude Include="..\source\cSurvivalInventory.h" />
|
||||||
<ClInclude Include="..\Source\cTCPLink.h" />
|
<ClInclude Include="..\Source\cTCPLink.h" />
|
||||||
<ClInclude Include="..\source\cGenSettings.h" />
|
|
||||||
<ClInclude Include="..\source\cThread.h" />
|
<ClInclude Include="..\source\cThread.h" />
|
||||||
<ClInclude Include="..\source\cTimer.h" />
|
<ClInclude Include="..\source\cTimer.h" />
|
||||||
<ClInclude Include="..\source\cTorch.h" />
|
<ClInclude Include="..\source\cTorch.h" />
|
||||||
|
@ -571,14 +574,14 @@
|
||||||
<ClInclude Include="..\source\cWindow.h" />
|
<ClInclude Include="..\source\cWindow.h" />
|
||||||
<ClInclude Include="..\source\cWindowOwner.h" />
|
<ClInclude Include="..\source\cWindowOwner.h" />
|
||||||
<ClInclude Include="..\source\cWolf.h" />
|
<ClInclude Include="..\source\cWolf.h" />
|
||||||
<ClInclude Include="..\source\cWorldGenerator.h" />
|
|
||||||
<ClInclude Include="..\source\cWorldGenerator_Test.h" />
|
|
||||||
<ClInclude Include="..\source\cZombie.h" />
|
<ClInclude Include="..\source\cZombie.h" />
|
||||||
<ClInclude Include="..\source\cZombiepigman.h" />
|
<ClInclude Include="..\source\cZombiepigman.h" />
|
||||||
<ClInclude Include="..\source\Endianness.h" />
|
<ClInclude Include="..\source\Endianness.h" />
|
||||||
<ClInclude Include="..\source\FastNBT.h" />
|
<ClInclude Include="..\source\FastNBT.h" />
|
||||||
<ClInclude Include="..\Source\FileDefine.h" />
|
<ClInclude Include="..\Source\FileDefine.h" />
|
||||||
|
<ClInclude Include="..\source\FinishGen.h" />
|
||||||
<ClInclude Include="..\source\Globals.h" />
|
<ClInclude Include="..\source\Globals.h" />
|
||||||
|
<ClInclude Include="..\source\HeiGen.h" />
|
||||||
<ClInclude Include="..\source\LeakFinder.h" />
|
<ClInclude Include="..\source\LeakFinder.h" />
|
||||||
<ClInclude Include="..\source\LightingThread.h" />
|
<ClInclude Include="..\source\LightingThread.h" />
|
||||||
<ClInclude Include="..\Source\LuaFunctions.h" />
|
<ClInclude Include="..\Source\LuaFunctions.h" />
|
||||||
|
@ -605,7 +608,6 @@
|
||||||
<ClInclude Include="..\source\Bindings.h" />
|
<ClInclude Include="..\source\Bindings.h" />
|
||||||
<ClInclude Include="..\source\Defines.h" />
|
<ClInclude Include="..\source\Defines.h" />
|
||||||
<ClInclude Include="..\source\MCSocket.h" />
|
<ClInclude Include="..\source\MCSocket.h" />
|
||||||
<ClInclude Include="..\source\NBT.h" />
|
|
||||||
<ClInclude Include="..\Source\PacketID.h" />
|
<ClInclude Include="..\Source\PacketID.h" />
|
||||||
<ClInclude Include="..\source\packets\cPacket.h" />
|
<ClInclude Include="..\source\packets\cPacket.h" />
|
||||||
<ClInclude Include="..\source\packets\cPacket_13.h" />
|
<ClInclude Include="..\source\packets\cPacket_13.h" />
|
||||||
|
@ -656,15 +658,15 @@
|
||||||
<ClInclude Include="..\source\packets\cPacket_WindowClick.h" />
|
<ClInclude Include="..\source\packets\cPacket_WindowClick.h" />
|
||||||
<ClInclude Include="..\source\packets\cPacket_WindowClose.h" />
|
<ClInclude Include="..\source\packets\cPacket_WindowClose.h" />
|
||||||
<ClInclude Include="..\source\packets\cPacket_WindowOpen.h" />
|
<ClInclude Include="..\source\packets\cPacket_WindowOpen.h" />
|
||||||
<ClInclude Include="..\source\ptr_cChunk.h" />
|
|
||||||
<ClInclude Include="..\source\SquirrelBindings.h" />
|
<ClInclude Include="..\source\SquirrelBindings.h" />
|
||||||
<ClInclude Include="..\source\StackWalker.h" />
|
<ClInclude Include="..\source\StackWalker.h" />
|
||||||
<ClInclude Include="..\source\StringCompression.h" />
|
<ClInclude Include="..\source\StringCompression.h" />
|
||||||
<ClInclude Include="..\source\StringUtils.h" />
|
<ClInclude Include="..\source\StringUtils.h" />
|
||||||
|
<ClInclude Include="..\source\StructGen.h" />
|
||||||
|
<ClInclude Include="..\source\Trees.h" />
|
||||||
<ClInclude Include="..\source\Vector3d.h" />
|
<ClInclude Include="..\source\Vector3d.h" />
|
||||||
<ClInclude Include="..\source\Vector3f.h" />
|
<ClInclude Include="..\source\Vector3f.h" />
|
||||||
<ClInclude Include="..\source\Vector3i.h" />
|
<ClInclude Include="..\source\Vector3i.h" />
|
||||||
<ClInclude Include="..\source\WGFlat.h" />
|
|
||||||
<ClInclude Include="..\source\WorldStorage.h" />
|
<ClInclude Include="..\source\WorldStorage.h" />
|
||||||
<ClInclude Include="..\source\WSSAnvil.h" />
|
<ClInclude Include="..\source\WSSAnvil.h" />
|
||||||
<ClInclude Include="..\source\WSSCompact.h" />
|
<ClInclude Include="..\source\WSSCompact.h" />
|
||||||
|
|
|
@ -217,9 +217,6 @@
|
||||||
<Filter Include="cNoise">
|
<Filter Include="cNoise">
|
||||||
<UniqueIdentifier>{58d6aa00-beab-4654-bbbd-c3b0397a9549}</UniqueIdentifier>
|
<UniqueIdentifier>{58d6aa00-beab-4654-bbbd-c3b0397a9549}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="cGenSettings">
|
|
||||||
<UniqueIdentifier>{731dfafd-78a6-47d4-8494-a8e024f24c07}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="cMakeDir">
|
<Filter Include="cMakeDir">
|
||||||
<UniqueIdentifier>{102fff22-0eb3-4977-9de3-307534954fbc}</UniqueIdentifier>
|
<UniqueIdentifier>{102fff22-0eb3-4977-9de3-307534954fbc}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -379,9 +376,6 @@
|
||||||
<Filter Include="Packets\cPacket_ItemData">
|
<Filter Include="Packets\cPacket_ItemData">
|
||||||
<UniqueIdentifier>{fcc08e08-8dba-47b4-89b0-5dc255bb9b8a}</UniqueIdentifier>
|
<UniqueIdentifier>{fcc08e08-8dba-47b4-89b0-5dc255bb9b8a}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="cChunkGenerator">
|
|
||||||
<UniqueIdentifier>{0d6f822b-71eb-406f-b17a-d188c4924283}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="cEntity\cPawn\cMonster\Personalities">
|
<Filter Include="cEntity\cPawn\cMonster\Personalities">
|
||||||
<UniqueIdentifier>{b0f7c883-e2ca-4bba-89e3-c36656c3de39}</UniqueIdentifier>
|
<UniqueIdentifier>{b0f7c883-e2ca-4bba-89e3-c36656c3de39}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -394,15 +388,9 @@
|
||||||
<Filter Include="cEntity\cPawn\cMonster\Personalities\PassiveAggressive">
|
<Filter Include="cEntity\cPawn\cMonster\Personalities\PassiveAggressive">
|
||||||
<UniqueIdentifier>{71574b1c-a518-4a17-92c1-e3ea340f73bc}</UniqueIdentifier>
|
<UniqueIdentifier>{71574b1c-a518-4a17-92c1-e3ea340f73bc}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="cWorldGenerator">
|
|
||||||
<UniqueIdentifier>{72727ea7-779f-439e-8f30-53bd6985c9e7}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="!LuaPlugins">
|
<Filter Include="!LuaPlugins">
|
||||||
<UniqueIdentifier>{4b86e1cf-ea3c-40b6-82b2-82fa9e6eb35e}</UniqueIdentifier>
|
<UniqueIdentifier>{4b86e1cf-ea3c-40b6-82b2-82fa9e6eb35e}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="cWorldGenerator\cWorldGenerator_Test">
|
|
||||||
<UniqueIdentifier>{c86f4c53-af06-4b42-97dd-ffb7035041ce}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="Simulator">
|
<Filter Include="Simulator">
|
||||||
<UniqueIdentifier>{ad41fc50-2d3d-4f6f-addd-a8bcb15b8518}</UniqueIdentifier>
|
<UniqueIdentifier>{ad41fc50-2d3d-4f6f-addd-a8bcb15b8518}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -433,9 +421,6 @@
|
||||||
<Filter Include="cInventory\cCreativeInventory">
|
<Filter Include="cInventory\cCreativeInventory">
|
||||||
<UniqueIdentifier>{69e6a927-8e49-4d39-af88-f587d17bb8a3}</UniqueIdentifier>
|
<UniqueIdentifier>{69e6a927-8e49-4d39-af88-f587d17bb8a3}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter Include="!Smart_Pointers">
|
|
||||||
<UniqueIdentifier>{9bd7a65c-b60f-4905-ae2b-7c3c7586eaef}</UniqueIdentifier>
|
|
||||||
</Filter>
|
|
||||||
<Filter Include="cPlugin\cPlugin_NewLua">
|
<Filter Include="cPlugin\cPlugin_NewLua">
|
||||||
<UniqueIdentifier>{fb282bd3-cf18-44b3-8ccc-9a5a89701a6d}</UniqueIdentifier>
|
<UniqueIdentifier>{fb282bd3-cf18-44b3-8ccc-9a5a89701a6d}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -445,6 +430,9 @@
|
||||||
<Filter Include="Simulator\cSimulator\cRedstoneSimulator">
|
<Filter Include="Simulator\cSimulator\cRedstoneSimulator">
|
||||||
<UniqueIdentifier>{4b3b7b43-8e8b-4823-b112-2259fdfff7d3}</UniqueIdentifier>
|
<UniqueIdentifier>{4b3b7b43-8e8b-4823-b112-2259fdfff7d3}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Generating">
|
||||||
|
<UniqueIdentifier>{833e49bd-848d-42de-ac60-6cd7656474e3}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
<Filter Include="Storage">
|
<Filter Include="Storage">
|
||||||
<UniqueIdentifier>{038cf4bd-108e-44e2-bdcb-9d48fb26676e}</UniqueIdentifier>
|
<UniqueIdentifier>{038cf4bd-108e-44e2-bdcb-9d48fb26676e}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
@ -664,9 +652,6 @@
|
||||||
<ClCompile Include="..\source\cNoise.cpp">
|
<ClCompile Include="..\source\cNoise.cpp">
|
||||||
<Filter>cNoise</Filter>
|
<Filter>cNoise</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\cGenSettings.cpp">
|
|
||||||
<Filter>cGenSettings</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\source\cMakeDir.cpp">
|
<ClCompile Include="..\source\cMakeDir.cpp">
|
||||||
<Filter>cMakeDir</Filter>
|
<Filter>cMakeDir</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -835,9 +820,6 @@
|
||||||
<ClCompile Include="..\source\packets\cPacket_ItemData.cpp">
|
<ClCompile Include="..\source\packets\cPacket_ItemData.cpp">
|
||||||
<Filter>Packets\cPacket_ItemData</Filter>
|
<Filter>Packets\cPacket_ItemData</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\cChunkGenerator.cpp">
|
|
||||||
<Filter>cChunkGenerator</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\source\cFluidSimulator.cpp">
|
<ClCompile Include="..\source\cFluidSimulator.cpp">
|
||||||
<Filter>Simulator\cSimulator\cFluidSimulator</Filter>
|
<Filter>Simulator\cSimulator\cFluidSimulator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -850,12 +832,6 @@
|
||||||
<ClCompile Include="..\source\cPassiveMonster.cpp">
|
<ClCompile Include="..\source\cPassiveMonster.cpp">
|
||||||
<Filter>cEntity\cPawn\cMonster\Personalities\Passive</Filter>
|
<Filter>cEntity\cPawn\cMonster\Personalities\Passive</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\cWorldGenerator.cpp">
|
|
||||||
<Filter>cWorldGenerator</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\source\cWorldGenerator_Test.cpp">
|
|
||||||
<Filter>cWorldGenerator\cWorldGenerator_Test</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\source\cSimulatorManager.cpp">
|
<ClCompile Include="..\source\cSimulatorManager.cpp">
|
||||||
<Filter>Simulator</Filter>
|
<Filter>Simulator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -896,12 +872,30 @@
|
||||||
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
|
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\ChunkSender.cpp" />
|
<ClCompile Include="..\source\ChunkSender.cpp" />
|
||||||
<ClCompile Include="..\source\WGFlat.cpp" />
|
|
||||||
<ClCompile Include="..\source\packets\cPacket_Player.cpp">
|
<ClCompile Include="..\source\packets\cPacket_Player.cpp">
|
||||||
<Filter>Packets</Filter>
|
<Filter>Packets</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\NBT.cpp">
|
<ClCompile Include="..\source\cChunkGenerator.cpp">
|
||||||
<Filter>Storage</Filter>
|
<Filter>Generating</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\Trees.cpp">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\CompoGen.cpp">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\HeiGen.cpp">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\StructGen.cpp">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\BioGen.cpp">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\BlockID.cpp" />
|
||||||
|
<ClCompile Include="..\source\FinishGen.cpp">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\WorldStorage.cpp">
|
<ClCompile Include="..\source\WorldStorage.cpp">
|
||||||
<Filter>Storage</Filter>
|
<Filter>Storage</Filter>
|
||||||
|
@ -1163,9 +1157,6 @@
|
||||||
<ClInclude Include="..\source\cNoise.h">
|
<ClInclude Include="..\source\cNoise.h">
|
||||||
<Filter>cNoise</Filter>
|
<Filter>cNoise</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\cGenSettings.h">
|
|
||||||
<Filter>cGenSettings</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\source\cMakeDir.h">
|
<ClInclude Include="..\source\cMakeDir.h">
|
||||||
<Filter>cMakeDir</Filter>
|
<Filter>cMakeDir</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1337,9 +1328,6 @@
|
||||||
<ClInclude Include="..\source\packets\cPacket_ItemData.h">
|
<ClInclude Include="..\source\packets\cPacket_ItemData.h">
|
||||||
<Filter>Packets\cPacket_ItemData</Filter>
|
<Filter>Packets\cPacket_ItemData</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\cChunkGenerator.h">
|
|
||||||
<Filter>cChunkGenerator</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\source\cFluidSimulator.h">
|
<ClInclude Include="..\source\cFluidSimulator.h">
|
||||||
<Filter>Simulator\cSimulator\cFluidSimulator</Filter>
|
<Filter>Simulator\cSimulator\cFluidSimulator</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1352,12 +1340,6 @@
|
||||||
<ClInclude Include="..\source\cPassiveMonster.h">
|
<ClInclude Include="..\source\cPassiveMonster.h">
|
||||||
<Filter>cEntity\cPawn\cMonster\Personalities\Passive</Filter>
|
<Filter>cEntity\cPawn\cMonster\Personalities\Passive</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\cWorldGenerator.h">
|
|
||||||
<Filter>cWorldGenerator</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\source\cWorldGenerator_Test.h">
|
|
||||||
<Filter>cWorldGenerator\cWorldGenerator_Test</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\source\cSimulatorManager.h">
|
<ClInclude Include="..\source\cSimulatorManager.h">
|
||||||
<Filter>Simulator</Filter>
|
<Filter>Simulator</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1379,9 +1361,6 @@
|
||||||
<ClInclude Include="..\source\cSurvivalInventory.h">
|
<ClInclude Include="..\source\cSurvivalInventory.h">
|
||||||
<Filter>cInventory\cSurvivalInventory</Filter>
|
<Filter>cInventory\cSurvivalInventory</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\ptr_cChunk.h">
|
|
||||||
<Filter>!Smart_Pointers</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\source\cPlugin_NewLua.h">
|
<ClInclude Include="..\source\cPlugin_NewLua.h">
|
||||||
<Filter>cPlugin\cPlugin_NewLua</Filter>
|
<Filter>cPlugin\cPlugin_NewLua</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@ -1401,13 +1380,30 @@
|
||||||
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
|
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\ChunkSender.h" />
|
<ClInclude Include="..\source\ChunkSender.h" />
|
||||||
<ClInclude Include="..\source\WGFlat.h" />
|
|
||||||
<ClInclude Include="..\source\ChunkDef.h" />
|
<ClInclude Include="..\source\ChunkDef.h" />
|
||||||
<ClInclude Include="..\source\packets\cPacket_Player.h">
|
<ClInclude Include="..\source\packets\cPacket_Player.h">
|
||||||
<Filter>Packets</Filter>
|
<Filter>Packets</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\NBT.h">
|
<ClInclude Include="..\source\cChunkGenerator.h">
|
||||||
<Filter>Storage</Filter>
|
<Filter>Generating</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\StructGen.h">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\Trees.h">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\CompoGen.h">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\HeiGen.h">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\BioGen.h">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\source\FinishGen.h">
|
||||||
|
<Filter>Generating</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\source\WorldStorage.h">
|
<ClInclude Include="..\source\WorldStorage.h">
|
||||||
<Filter>Storage</Filter>
|
<Filter>Storage</Filter>
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
#define SD_SEND 0x01
|
#define SD_SEND 0x01
|
||||||
#else
|
#else
|
||||||
#define MSG_NOSIGNAL (0)
|
#define MSG_NOSIGNAL (0)
|
||||||
|
|
|
@ -47,7 +47,15 @@
|
||||||
#include "UrlHelper.h"
|
#include "UrlHelper.h"
|
||||||
#include "base64.h"
|
#include "base64.h"
|
||||||
|
|
||||||
webserver::request_func webserver::request_func_=0;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
webserver::request_func webserver::request_func_ = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static std::string EatLine( std::string& a_String )
|
static std::string EatLine( std::string& a_String )
|
||||||
{
|
{
|
||||||
|
@ -76,6 +84,10 @@ static std::string EatLine( std::string& a_String )
|
||||||
return RetVal;
|
return RetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Turns
|
// Turns
|
||||||
// "blabla my string with \"quotes\"!"
|
// "blabla my string with \"quotes\"!"
|
||||||
// into
|
// into
|
||||||
|
@ -116,6 +128,10 @@ static std::string GetQuotedString( const std::string& a_String )
|
||||||
return RetVal;
|
return RetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ParseMultipartFormData( webserver::http_request& req, Socket* s)
|
void ParseMultipartFormData( webserver::http_request& req, Socket* s)
|
||||||
{
|
{
|
||||||
static const std::string multipart_form_data = "multipart/form-data";
|
static const std::string multipart_form_data = "multipart/form-data";
|
||||||
|
@ -229,6 +245,10 @@ void ParseMultipartFormData( webserver::http_request& req, Socket* s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
unsigned webserver::Request(void* ptr_s)
|
unsigned webserver::Request(void* ptr_s)
|
||||||
#else
|
#else
|
||||||
|
@ -395,6 +415,10 @@ void* webserver::Request(void* ptr_s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void webserver::Stop()
|
void webserver::Stop()
|
||||||
{
|
{
|
||||||
m_bStop = true;
|
m_bStop = true;
|
||||||
|
@ -402,46 +426,72 @@ void webserver::Stop()
|
||||||
m_Events->Wait();
|
m_Events->Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
void webserver::Begin()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool webserver::Begin()
|
||||||
{
|
{
|
||||||
|
if (!m_Socket->IsValid())
|
||||||
|
{
|
||||||
|
LOGINFO("WebAdmin: The server socket is invalid. Terminating WebAdmin.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
m_bStop = false;
|
m_bStop = false;
|
||||||
while ( !m_bStop )
|
while ( !m_bStop )
|
||||||
{
|
{
|
||||||
Socket* ptr_s=m_Socket->Accept();
|
Socket * ptr_s = m_Socket->Accept();
|
||||||
if( m_bStop )
|
if (m_bStop)
|
||||||
{
|
{
|
||||||
if( ptr_s != 0 )
|
if (ptr_s != 0)
|
||||||
{
|
{
|
||||||
ptr_s->Close();
|
ptr_s->Close();
|
||||||
delete ptr_s;
|
delete ptr_s;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (ptr_s == NULL)
|
||||||
|
{
|
||||||
|
LOGINFO("WebAdmin: Accepted socket is NULL. Terminating WebAdmin to avoid busywait.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// unused variable 'ret'
|
|
||||||
//_beginthreadex(0,0,Request,(void*) ptr_s,0,&ret);
|
|
||||||
// Thanks to Frank M. Hoffmann for fixing a HANDLE leak
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
unsigned ret;
|
unsigned ret;
|
||||||
HANDLE hHandle = reinterpret_cast<HANDLE>(_beginthreadex(0,0,Request,(void*) ptr_s,0,&ret));
|
HANDLE hHandle = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0, Request, (void *)ptr_s, 0, &ret));
|
||||||
CloseHandle(hHandle);
|
CloseHandle(hHandle);
|
||||||
#else
|
#else
|
||||||
pthread_t* hHandle = new pthread_t;
|
// Mattes: TODO: this handle probably leaks!
|
||||||
|
pthread_t * hHandle = new pthread_t;
|
||||||
pthread_create( hHandle, NULL, Request, ptr_s);
|
pthread_create( hHandle, NULL, Request, ptr_s);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
m_Events->Set();
|
m_Events->Set();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
webserver::webserver(unsigned int port_to_listen, request_func r) {
|
|
||||||
m_Socket = new SocketServer(port_to_listen,1);
|
|
||||||
|
|
||||||
|
|
||||||
|
webserver::webserver(unsigned int port_to_listen, request_func r)
|
||||||
|
{
|
||||||
|
m_Socket = new SocketServer(port_to_listen, 1);
|
||||||
|
|
||||||
request_func_ = r;
|
request_func_ = r;
|
||||||
m_Events = new cEvents();
|
m_Events = new cEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
webserver::~webserver()
|
webserver::~webserver()
|
||||||
{
|
{
|
||||||
delete m_Socket;
|
delete m_Socket;
|
||||||
delete m_Events;
|
delete m_Events;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -89,16 +89,18 @@ public:
|
||||||
webserver(unsigned int port_to_listen, request_func);
|
webserver(unsigned int port_to_listen, request_func);
|
||||||
~webserver();
|
~webserver();
|
||||||
|
|
||||||
void Begin();
|
bool Begin();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_bStop;
|
bool m_bStop;
|
||||||
#ifdef _WIN32
|
|
||||||
|
#ifdef _WIN32
|
||||||
static unsigned __stdcall Request(void*);
|
static unsigned __stdcall Request(void*);
|
||||||
#else
|
#else
|
||||||
static void* Request(void*);
|
static void* Request(void*);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static request_func request_func_;
|
static request_func request_func_;
|
||||||
|
|
||||||
cEvents * m_Events;
|
cEvents * m_Events;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on 03/25/12 16:23:48.
|
** Generated automatically by tolua++-1.0.92 on 05/24/12 19:47:53.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
|
@ -2344,7 +2344,7 @@ static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S)
|
||||||
if (tolua_index<0)
|
if (tolua_index<0)
|
||||||
tolua_error(tolua_S,"array indexing out of range.",NULL);
|
tolua_error(tolua_S,"array indexing out of range.",NULL);
|
||||||
#endif
|
#endif
|
||||||
g_BlockLightValue[tolua_index] = ((char) tolua_tonumber(tolua_S,3,0));
|
g_BlockLightValue[tolua_index] = ((unsigned char) tolua_tonumber(tolua_S,3,0));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
@ -2388,7 +2388,7 @@ static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
|
||||||
if (tolua_index<0)
|
if (tolua_index<0)
|
||||||
tolua_error(tolua_S,"array indexing out of range.",NULL);
|
tolua_error(tolua_S,"array indexing out of range.",NULL);
|
||||||
#endif
|
#endif
|
||||||
g_BlockSpreadLightFalloff[tolua_index] = ((char) tolua_tonumber(tolua_S,3,0));
|
g_BlockSpreadLightFalloff[tolua_index] = ((unsigned char) tolua_tonumber(tolua_S,3,0));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
@ -2897,6 +2897,15 @@ static int tolua_get_cChatColor_White(lua_State* tolua_S)
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* get function: Funky of class cChatColor */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_get_cChatColor_Funky
|
||||||
|
static int tolua_get_cChatColor_Funky(lua_State* tolua_S)
|
||||||
|
{
|
||||||
|
tolua_pushcppstring(tolua_S,(const char*)cChatColor::Funky);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: MakeColor of class cChatColor */
|
/* method: MakeColor of class cChatColor */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cChatColor_MakeColor00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cChatColor_MakeColor00
|
||||||
static int tolua_AllToLua_cChatColor_MakeColor00(lua_State* tolua_S)
|
static int tolua_AllToLua_cChatColor_MakeColor00(lua_State* tolua_S)
|
||||||
|
@ -3090,6 +3099,38 @@ static int tolua_AllToLua_cClientHandle_SetViewDistance00(lua_State* tolua_S)
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GetViewDistance of class cClientHandle */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cClientHandle_GetViewDistance00
|
||||||
|
static int tolua_AllToLua_cClientHandle_GetViewDistance00(lua_State* tolua_S)
|
||||||
|
{
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_Error tolua_err;
|
||||||
|
if (
|
||||||
|
!tolua_isusertype(tolua_S,1,"cClientHandle",0,&tolua_err) ||
|
||||||
|
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cClientHandle* self = (cClientHandle*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetViewDistance'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int tolua_ret = (int) self->GetViewDistance();
|
||||||
|
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GetViewDistance'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: GetUniqueID of class cClientHandle */
|
/* method: GetUniqueID of class cClientHandle */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cClientHandle_GetUniqueID00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cClientHandle_GetUniqueID00
|
||||||
static int tolua_AllToLua_cClientHandle_GetUniqueID00(lua_State* tolua_S)
|
static int tolua_AllToLua_cClientHandle_GetUniqueID00(lua_State* tolua_S)
|
||||||
|
@ -3612,6 +3653,102 @@ static int tolua_AllToLua_cEntity_GetLookVector00(lua_State* tolua_S)
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GetChunkX of class cEntity */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetChunkX00
|
||||||
|
static int tolua_AllToLua_cEntity_GetChunkX00(lua_State* tolua_S)
|
||||||
|
{
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_Error tolua_err;
|
||||||
|
if (
|
||||||
|
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||||
|
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetChunkX'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int tolua_ret = (int) self->GetChunkX();
|
||||||
|
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GetChunkX'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GetChunkY of class cEntity */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetChunkY00
|
||||||
|
static int tolua_AllToLua_cEntity_GetChunkY00(lua_State* tolua_S)
|
||||||
|
{
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_Error tolua_err;
|
||||||
|
if (
|
||||||
|
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||||
|
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetChunkY'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int tolua_ret = (int) self->GetChunkY();
|
||||||
|
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GetChunkY'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GetChunkZ of class cEntity */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_GetChunkZ00
|
||||||
|
static int tolua_AllToLua_cEntity_GetChunkZ00(lua_State* tolua_S)
|
||||||
|
{
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_Error tolua_err;
|
||||||
|
if (
|
||||||
|
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||||
|
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetChunkZ'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int tolua_ret = (int) self->GetChunkZ();
|
||||||
|
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GetChunkZ'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: SetPosX of class cEntity */
|
/* method: SetPosX of class cEntity */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetPosX00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetPosX00
|
||||||
static int tolua_AllToLua_cEntity_SetPosX00(lua_State* tolua_S)
|
static int tolua_AllToLua_cEntity_SetPosX00(lua_State* tolua_S)
|
||||||
|
@ -6381,7 +6518,7 @@ static int tolua_AllToLua_cPluginManager_GetPlugin00(lua_State* tolua_S)
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
tolua_Error tolua_err;
|
tolua_Error tolua_err;
|
||||||
if (
|
if (
|
||||||
!tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) ||
|
!tolua_isusertype(tolua_S,1,"const cPluginManager",0,&tolua_err) ||
|
||||||
!tolua_isstring(tolua_S,2,0,&tolua_err) ||
|
!tolua_isstring(tolua_S,2,0,&tolua_err) ||
|
||||||
!tolua_isnoobj(tolua_S,3,&tolua_err)
|
!tolua_isnoobj(tolua_S,3,&tolua_err)
|
||||||
)
|
)
|
||||||
|
@ -6389,7 +6526,7 @@ static int tolua_AllToLua_cPluginManager_GetPlugin00(lua_State* tolua_S)
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
const cPluginManager* self = (const cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
||||||
const char* a_Plugin = ((const char*) tolua_tostring(tolua_S,2,0));
|
const char* a_Plugin = ((const char*) tolua_tostring(tolua_S,2,0));
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPlugin'", NULL);
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPlugin'", NULL);
|
||||||
|
@ -6516,14 +6653,14 @@ static int tolua_AllToLua_cPluginManager_GetNumPlugins00(lua_State* tolua_S)
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
tolua_Error tolua_err;
|
tolua_Error tolua_err;
|
||||||
if (
|
if (
|
||||||
!tolua_isusertype(tolua_S,1,"cPluginManager",0,&tolua_err) ||
|
!tolua_isusertype(tolua_S,1,"const cPluginManager",0,&tolua_err) ||
|
||||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||||
)
|
)
|
||||||
goto tolua_lerror;
|
goto tolua_lerror;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
const cPluginManager* self = (const cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumPlugins'", NULL);
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumPlugins'", NULL);
|
||||||
#endif
|
#endif
|
||||||
|
@ -9855,6 +9992,76 @@ static int tolua_AllToLua_cWorld_UpdateSign00(lua_State* tolua_S)
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: RegenerateChunk of class cWorld */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_RegenerateChunk00
|
||||||
|
static int tolua_AllToLua_cWorld_RegenerateChunk00(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_isnoobj(tolua_S,4,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
int a_ChunkX = ((int) tolua_tonumber(tolua_S,2,0));
|
||||||
|
int a_ChunkZ = ((int) tolua_tonumber(tolua_S,3,0));
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'RegenerateChunk'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
self->RegenerateChunk(a_ChunkX,a_ChunkZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'RegenerateChunk'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GenerateChunk of class cWorld */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GenerateChunk00
|
||||||
|
static int tolua_AllToLua_cWorld_GenerateChunk00(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_isnoobj(tolua_S,4,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
int a_ChunkX = ((int) tolua_tonumber(tolua_S,2,0));
|
||||||
|
int a_ChunkZ = ((int) tolua_tonumber(tolua_S,3,0));
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GenerateChunk'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
self->GenerateChunk(a_ChunkX,a_ChunkZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GenerateChunk'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: SetBlock of class cWorld */
|
/* method: SetBlock of class cWorld */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SetBlock00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SetBlock00
|
||||||
static int tolua_AllToLua_cWorld_SetBlock00(lua_State* tolua_S)
|
static int tolua_AllToLua_cWorld_SetBlock00(lua_State* tolua_S)
|
||||||
|
@ -10409,14 +10616,14 @@ static int tolua_AllToLua_cWorld_GrowTree00(lua_State* tolua_S)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||||
int a_X = ((int) tolua_tonumber(tolua_S,2,0));
|
int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0));
|
||||||
int a_Y = ((int) tolua_tonumber(tolua_S,3,0));
|
int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0));
|
||||||
int a_Z = ((int) tolua_tonumber(tolua_S,4,0));
|
int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0));
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GrowTree'", NULL);
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GrowTree'", NULL);
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
self->GrowTree(a_X,a_Y,a_Z);
|
self->GrowTree(a_BlockX,a_BlockY,a_BlockZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -10428,33 +10635,113 @@ static int tolua_AllToLua_cWorld_GrowTree00(lua_State* tolua_S)
|
||||||
}
|
}
|
||||||
#endif //#ifndef TOLUA_DISABLE
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
/* method: GetWorldSeed of class cWorld */
|
/* method: GrowTreeFromSapling of class cWorld */
|
||||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetWorldSeed00
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GrowTreeFromSapling00
|
||||||
static int tolua_AllToLua_cWorld_GetWorldSeed00(lua_State* tolua_S)
|
static int tolua_AllToLua_cWorld_GrowTreeFromSapling00(lua_State* tolua_S)
|
||||||
{
|
{
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
tolua_Error tolua_err;
|
tolua_Error tolua_err;
|
||||||
if (
|
if (
|
||||||
!tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) ||
|
!tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
|
||||||
!tolua_isnoobj(tolua_S,2,&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_isnoobj(tolua_S,6,&tolua_err)
|
||||||
)
|
)
|
||||||
goto tolua_lerror;
|
goto tolua_lerror;
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
const cWorld* self = (const cWorld*) tolua_tousertype(tolua_S,1,0);
|
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0));
|
||||||
|
int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0));
|
||||||
|
int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0));
|
||||||
|
char a_SaplingMeta = ((char) tolua_tonumber(tolua_S,5,0));
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetWorldSeed'", NULL);
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GrowTreeFromSapling'", NULL);
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
unsigned int tolua_ret = (unsigned int) self->GetWorldSeed();
|
self->GrowTreeFromSapling(a_BlockX,a_BlockY,a_BlockZ,a_SaplingMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GrowTreeFromSapling'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GrowTreeByBiome of class cWorld */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GrowTreeByBiome00
|
||||||
|
static int tolua_AllToLua_cWorld_GrowTreeByBiome00(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_isnoobj(tolua_S,5,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0));
|
||||||
|
int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0));
|
||||||
|
int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0));
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GrowTreeByBiome'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
self->GrowTreeByBiome(a_BlockX,a_BlockY,a_BlockZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
tolua_lerror:
|
||||||
|
tolua_error(tolua_S,"#ferror in function 'GrowTreeByBiome'.",&tolua_err);
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif //#ifndef TOLUA_DISABLE
|
||||||
|
|
||||||
|
/* method: GetBiomeAt of class cWorld */
|
||||||
|
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetBiomeAt00
|
||||||
|
static int tolua_AllToLua_cWorld_GetBiomeAt00(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_isnoobj(tolua_S,4,&tolua_err)
|
||||||
|
)
|
||||||
|
goto tolua_lerror;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||||
|
int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0));
|
||||||
|
int a_BlockZ = ((int) tolua_tonumber(tolua_S,3,0));
|
||||||
|
#ifndef TOLUA_RELEASE
|
||||||
|
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetBiomeAt'", NULL);
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int tolua_ret = (int) self->GetBiomeAt(a_BlockX,a_BlockZ);
|
||||||
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
#ifndef TOLUA_RELEASE
|
#ifndef TOLUA_RELEASE
|
||||||
tolua_lerror:
|
tolua_lerror:
|
||||||
tolua_error(tolua_S,"#ferror in function 'GetWorldSeed'.",&tolua_err);
|
tolua_error(tolua_S,"#ferror in function 'GetBiomeAt'.",&tolua_err);
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -17174,6 +17461,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_constant(tolua_S,"E_BLOCK_GRASS",E_BLOCK_GRASS);
|
tolua_constant(tolua_S,"E_BLOCK_GRASS",E_BLOCK_GRASS);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_DIRT",E_BLOCK_DIRT);
|
tolua_constant(tolua_S,"E_BLOCK_DIRT",E_BLOCK_DIRT);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_COBBLESTONE",E_BLOCK_COBBLESTONE);
|
tolua_constant(tolua_S,"E_BLOCK_COBBLESTONE",E_BLOCK_COBBLESTONE);
|
||||||
|
tolua_constant(tolua_S,"E_BLOCK_PLANKS",E_BLOCK_PLANKS);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_WOOD",E_BLOCK_WOOD);
|
tolua_constant(tolua_S,"E_BLOCK_WOOD",E_BLOCK_WOOD);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_SAPLING",E_BLOCK_SAPLING);
|
tolua_constant(tolua_S,"E_BLOCK_SAPLING",E_BLOCK_SAPLING);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_BEDROCK",E_BLOCK_BEDROCK);
|
tolua_constant(tolua_S,"E_BLOCK_BEDROCK",E_BLOCK_BEDROCK);
|
||||||
|
@ -17260,6 +17548,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_constant(tolua_S,"E_BLOCK_SOULSAND",E_BLOCK_SOULSAND);
|
tolua_constant(tolua_S,"E_BLOCK_SOULSAND",E_BLOCK_SOULSAND);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_GLOWSTONE",E_BLOCK_GLOWSTONE);
|
tolua_constant(tolua_S,"E_BLOCK_GLOWSTONE",E_BLOCK_GLOWSTONE);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_PORT",E_BLOCK_PORT);
|
tolua_constant(tolua_S,"E_BLOCK_PORT",E_BLOCK_PORT);
|
||||||
|
tolua_constant(tolua_S,"E_BLOCK_NETHER_PORTAL",E_BLOCK_NETHER_PORTAL);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_JACK_O_LANTERN",E_BLOCK_JACK_O_LANTERN);
|
tolua_constant(tolua_S,"E_BLOCK_JACK_O_LANTERN",E_BLOCK_JACK_O_LANTERN);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_CAKE",E_BLOCK_CAKE);
|
tolua_constant(tolua_S,"E_BLOCK_CAKE",E_BLOCK_CAKE);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_REDSTONE_REPEATER_OFF",E_BLOCK_REDSTONE_REPEATER_OFF);
|
tolua_constant(tolua_S,"E_BLOCK_REDSTONE_REPEATER_OFF",E_BLOCK_REDSTONE_REPEATER_OFF);
|
||||||
|
@ -17291,6 +17580,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_constant(tolua_S,"E_BLOCK_END_PORTAL",E_BLOCK_END_PORTAL);
|
tolua_constant(tolua_S,"E_BLOCK_END_PORTAL",E_BLOCK_END_PORTAL);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_END_PORTAL_FRAME",E_BLOCK_END_PORTAL_FRAME);
|
tolua_constant(tolua_S,"E_BLOCK_END_PORTAL_FRAME",E_BLOCK_END_PORTAL_FRAME);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_END_STONE",E_BLOCK_END_STONE);
|
tolua_constant(tolua_S,"E_BLOCK_END_STONE",E_BLOCK_END_STONE);
|
||||||
|
tolua_constant(tolua_S,"E_BLOCK_DRAGON_EGG",E_BLOCK_DRAGON_EGG);
|
||||||
|
tolua_constant(tolua_S,"E_BLOCK_REDSTONE_LAMP_OFF",E_BLOCK_REDSTONE_LAMP_OFF);
|
||||||
|
tolua_constant(tolua_S,"E_BLOCK_REDSTONE_LAMP_ON",E_BLOCK_REDSTONE_LAMP_ON);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_",E_BLOCK_);
|
tolua_constant(tolua_S,"E_BLOCK_",E_BLOCK_);
|
||||||
tolua_constant(tolua_S,"E_ITEM_EMPTY",E_ITEM_EMPTY);
|
tolua_constant(tolua_S,"E_ITEM_EMPTY",E_ITEM_EMPTY);
|
||||||
tolua_constant(tolua_S,"E_ITEM_STONE",E_ITEM_STONE);
|
tolua_constant(tolua_S,"E_ITEM_STONE",E_ITEM_STONE);
|
||||||
|
@ -17544,6 +17836,25 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_constant(tolua_S,"E_ITEM_STRAD_DISC",E_ITEM_STRAD_DISC);
|
tolua_constant(tolua_S,"E_ITEM_STRAD_DISC",E_ITEM_STRAD_DISC);
|
||||||
tolua_constant(tolua_S,"E_ITEM_WARD_DISC",E_ITEM_WARD_DISC);
|
tolua_constant(tolua_S,"E_ITEM_WARD_DISC",E_ITEM_WARD_DISC);
|
||||||
tolua_constant(tolua_S,"E_ITEM_11_DISC",E_ITEM_11_DISC);
|
tolua_constant(tolua_S,"E_ITEM_11_DISC",E_ITEM_11_DISC);
|
||||||
|
tolua_constant(tolua_S,"E_META_PLANKS_APPLE",E_META_PLANKS_APPLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_PLANKS_CONIFER",E_META_PLANKS_CONIFER);
|
||||||
|
tolua_constant(tolua_S,"E_META_PLANKS_BIRCH",E_META_PLANKS_BIRCH);
|
||||||
|
tolua_constant(tolua_S,"E_META_PLANKS_JUNGLE",E_META_PLANKS_JUNGLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_LOG_APPLE",E_META_LOG_APPLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_LOG_CONIFER",E_META_LOG_CONIFER);
|
||||||
|
tolua_constant(tolua_S,"E_META_LOG_BIRCH",E_META_LOG_BIRCH);
|
||||||
|
tolua_constant(tolua_S,"E_META_LOG_JUNGLE",E_META_LOG_JUNGLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_LEAVES_APPLE",E_META_LEAVES_APPLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_LEAVES_CONIFER",E_META_LEAVES_CONIFER);
|
||||||
|
tolua_constant(tolua_S,"E_META_LEAVES_BIRCH",E_META_LEAVES_BIRCH);
|
||||||
|
tolua_constant(tolua_S,"E_META_LEAVES_JUNGLE",E_META_LEAVES_JUNGLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_SAPLING_APPLE",E_META_SAPLING_APPLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_SAPLING_CONIFER",E_META_SAPLING_CONIFER);
|
||||||
|
tolua_constant(tolua_S,"E_META_SAPLING_BIRCH",E_META_SAPLING_BIRCH);
|
||||||
|
tolua_constant(tolua_S,"E_META_SAPLING_JUNGLE",E_META_SAPLING_JUNGLE);
|
||||||
|
tolua_constant(tolua_S,"E_META_TALL_GRASS_DEAD_SHRUB",E_META_TALL_GRASS_DEAD_SHRUB);
|
||||||
|
tolua_constant(tolua_S,"E_META_TALL_GRASS_GRASS",E_META_TALL_GRASS_GRASS);
|
||||||
|
tolua_constant(tolua_S,"E_META_TALL_GRASS_FERN",E_META_TALL_GRASS_FERN);
|
||||||
tolua_constant(tolua_S,"E_KEEP_ALIVE",E_KEEP_ALIVE);
|
tolua_constant(tolua_S,"E_KEEP_ALIVE",E_KEEP_ALIVE);
|
||||||
tolua_constant(tolua_S,"E_LOGIN",E_LOGIN);
|
tolua_constant(tolua_S,"E_LOGIN",E_LOGIN);
|
||||||
tolua_constant(tolua_S,"E_HANDSHAKE",E_HANDSHAKE);
|
tolua_constant(tolua_S,"E_HANDSHAKE",E_HANDSHAKE);
|
||||||
|
@ -17638,6 +17949,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_variable(tolua_S,"LightPurple",tolua_get_cChatColor_LightPurple,NULL);
|
tolua_variable(tolua_S,"LightPurple",tolua_get_cChatColor_LightPurple,NULL);
|
||||||
tolua_variable(tolua_S,"Yellow",tolua_get_cChatColor_Yellow,NULL);
|
tolua_variable(tolua_S,"Yellow",tolua_get_cChatColor_Yellow,NULL);
|
||||||
tolua_variable(tolua_S,"White",tolua_get_cChatColor_White,NULL);
|
tolua_variable(tolua_S,"White",tolua_get_cChatColor_White,NULL);
|
||||||
|
tolua_variable(tolua_S,"Funky",tolua_get_cChatColor_Funky,NULL);
|
||||||
tolua_function(tolua_S,"MakeColor",tolua_AllToLua_cChatColor_MakeColor00);
|
tolua_function(tolua_S,"MakeColor",tolua_AllToLua_cChatColor_MakeColor00);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
tolua_cclass(tolua_S,"cClientHandle","cClientHandle","",NULL);
|
tolua_cclass(tolua_S,"cClientHandle","cClientHandle","",NULL);
|
||||||
|
@ -17647,6 +17959,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_function(tolua_S,"GetUsername",tolua_AllToLua_cClientHandle_GetUsername00);
|
tolua_function(tolua_S,"GetUsername",tolua_AllToLua_cClientHandle_GetUsername00);
|
||||||
tolua_function(tolua_S,"GetPing",tolua_AllToLua_cClientHandle_GetPing00);
|
tolua_function(tolua_S,"GetPing",tolua_AllToLua_cClientHandle_GetPing00);
|
||||||
tolua_function(tolua_S,"SetViewDistance",tolua_AllToLua_cClientHandle_SetViewDistance00);
|
tolua_function(tolua_S,"SetViewDistance",tolua_AllToLua_cClientHandle_SetViewDistance00);
|
||||||
|
tolua_function(tolua_S,"GetViewDistance",tolua_AllToLua_cClientHandle_GetViewDistance00);
|
||||||
tolua_function(tolua_S,"GetUniqueID",tolua_AllToLua_cClientHandle_GetUniqueID00);
|
tolua_function(tolua_S,"GetUniqueID",tolua_AllToLua_cClientHandle_GetUniqueID00);
|
||||||
tolua_endmodule(tolua_S);
|
tolua_endmodule(tolua_S);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -17673,6 +17986,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_function(tolua_S,"GetPitch",tolua_AllToLua_cEntity_GetPitch00);
|
tolua_function(tolua_S,"GetPitch",tolua_AllToLua_cEntity_GetPitch00);
|
||||||
tolua_function(tolua_S,"GetRoll",tolua_AllToLua_cEntity_GetRoll00);
|
tolua_function(tolua_S,"GetRoll",tolua_AllToLua_cEntity_GetRoll00);
|
||||||
tolua_function(tolua_S,"GetLookVector",tolua_AllToLua_cEntity_GetLookVector00);
|
tolua_function(tolua_S,"GetLookVector",tolua_AllToLua_cEntity_GetLookVector00);
|
||||||
|
tolua_function(tolua_S,"GetChunkX",tolua_AllToLua_cEntity_GetChunkX00);
|
||||||
|
tolua_function(tolua_S,"GetChunkY",tolua_AllToLua_cEntity_GetChunkY00);
|
||||||
|
tolua_function(tolua_S,"GetChunkZ",tolua_AllToLua_cEntity_GetChunkZ00);
|
||||||
tolua_function(tolua_S,"SetPosX",tolua_AllToLua_cEntity_SetPosX00);
|
tolua_function(tolua_S,"SetPosX",tolua_AllToLua_cEntity_SetPosX00);
|
||||||
tolua_function(tolua_S,"SetPosY",tolua_AllToLua_cEntity_SetPosY00);
|
tolua_function(tolua_S,"SetPosY",tolua_AllToLua_cEntity_SetPosY00);
|
||||||
tolua_function(tolua_S,"SetPosZ",tolua_AllToLua_cEntity_SetPosZ00);
|
tolua_function(tolua_S,"SetPosZ",tolua_AllToLua_cEntity_SetPosZ00);
|
||||||
|
@ -17909,6 +18225,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_function(tolua_S,"GetNumPlayers",tolua_AllToLua_cWorld_GetNumPlayers00);
|
tolua_function(tolua_S,"GetNumPlayers",tolua_AllToLua_cWorld_GetNumPlayers00);
|
||||||
tolua_function(tolua_S,"GetPlayer",tolua_AllToLua_cWorld_GetPlayer00);
|
tolua_function(tolua_S,"GetPlayer",tolua_AllToLua_cWorld_GetPlayer00);
|
||||||
tolua_function(tolua_S,"UpdateSign",tolua_AllToLua_cWorld_UpdateSign00);
|
tolua_function(tolua_S,"UpdateSign",tolua_AllToLua_cWorld_UpdateSign00);
|
||||||
|
tolua_function(tolua_S,"RegenerateChunk",tolua_AllToLua_cWorld_RegenerateChunk00);
|
||||||
|
tolua_function(tolua_S,"GenerateChunk",tolua_AllToLua_cWorld_GenerateChunk00);
|
||||||
tolua_function(tolua_S,"SetBlock",tolua_AllToLua_cWorld_SetBlock00);
|
tolua_function(tolua_S,"SetBlock",tolua_AllToLua_cWorld_SetBlock00);
|
||||||
tolua_function(tolua_S,"FastSetBlock",tolua_AllToLua_cWorld_FastSetBlock00);
|
tolua_function(tolua_S,"FastSetBlock",tolua_AllToLua_cWorld_FastSetBlock00);
|
||||||
tolua_function(tolua_S,"GetBlock",tolua_AllToLua_cWorld_GetBlock00);
|
tolua_function(tolua_S,"GetBlock",tolua_AllToLua_cWorld_GetBlock00);
|
||||||
|
@ -17925,7 +18243,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||||
tolua_function(tolua_S,"GetSpawnZ",tolua_AllToLua_cWorld_GetSpawnZ00);
|
tolua_function(tolua_S,"GetSpawnZ",tolua_AllToLua_cWorld_GetSpawnZ00);
|
||||||
tolua_function(tolua_S,"GetBlockEntity",tolua_AllToLua_cWorld_GetBlockEntity00);
|
tolua_function(tolua_S,"GetBlockEntity",tolua_AllToLua_cWorld_GetBlockEntity00);
|
||||||
tolua_function(tolua_S,"GrowTree",tolua_AllToLua_cWorld_GrowTree00);
|
tolua_function(tolua_S,"GrowTree",tolua_AllToLua_cWorld_GrowTree00);
|
||||||
tolua_function(tolua_S,"GetWorldSeed",tolua_AllToLua_cWorld_GetWorldSeed00);
|
tolua_function(tolua_S,"GrowTreeFromSapling",tolua_AllToLua_cWorld_GrowTreeFromSapling00);
|
||||||
|
tolua_function(tolua_S,"GrowTreeByBiome",tolua_AllToLua_cWorld_GrowTreeByBiome00);
|
||||||
|
tolua_function(tolua_S,"GetBiomeAt",tolua_AllToLua_cWorld_GetBiomeAt00);
|
||||||
tolua_function(tolua_S,"GetName",tolua_AllToLua_cWorld_GetName00);
|
tolua_function(tolua_S,"GetName",tolua_AllToLua_cWorld_GetName00);
|
||||||
tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00);
|
tolua_function(tolua_S,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00);
|
||||||
tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00);
|
tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on 03/25/12 16:23:48.
|
** Generated automatically by tolua++-1.0.92 on 05/24/12 19:47:53.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported function */
|
/* Exported function */
|
||||||
|
|
89
source/BioGen.cpp
Normal file
89
source/BioGen.cpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
|
||||||
|
// BioGen.cpp
|
||||||
|
|
||||||
|
// Implements the various biome generators
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "BioGen.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cBioGenConstant:
|
||||||
|
|
||||||
|
void cBioGenConstant::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(a_BiomeMap); i++)
|
||||||
|
{
|
||||||
|
a_BiomeMap[i] = m_Biome;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cBioGenDistortedVoronoi:
|
||||||
|
|
||||||
|
void cBioGenDistortedVoronoi::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
|
||||||
|
{
|
||||||
|
// TODO: Replace this placeholder
|
||||||
|
ASSERT(!"Not implemented yet");
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(a_BiomeMap); i++)
|
||||||
|
{
|
||||||
|
a_BiomeMap[i] = (EMCSBiome)(a_ChunkX + a_ChunkZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cBioGenCheckerboard:
|
||||||
|
|
||||||
|
void cBioGenCheckerboard::GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
|
||||||
|
{
|
||||||
|
// The list of biomes we will generate in the checkerboard:
|
||||||
|
static EMCSBiome Biomes[] =
|
||||||
|
{
|
||||||
|
biOcean,
|
||||||
|
biPlains,
|
||||||
|
biDesert,
|
||||||
|
biExtremeHills,
|
||||||
|
biForest,
|
||||||
|
biTaiga,
|
||||||
|
biSwampland,
|
||||||
|
biRiver,
|
||||||
|
biFrozenOcean,
|
||||||
|
biFrozenRiver,
|
||||||
|
biIcePlains,
|
||||||
|
biIceMountains,
|
||||||
|
biMushroomIsland,
|
||||||
|
biMushroomShore,
|
||||||
|
biBeach,
|
||||||
|
biDesertHills,
|
||||||
|
biForestHills,
|
||||||
|
biTaigaHills,
|
||||||
|
biExtremeHillsEdge,
|
||||||
|
biJungle,
|
||||||
|
biJungleHills,
|
||||||
|
} ;
|
||||||
|
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
int Base = cChunkDef::Width * a_ChunkZ + z;
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
int Add = cChunkDef::Width * a_ChunkX + x;
|
||||||
|
a_BiomeMap[x + cChunkDef::Width * z] = Biomes[(Base / m_BiomeSize + Add / m_BiomeSize) % ARRAYCOUNT(Biomes)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
75
source/BioGen.h
Normal file
75
source/BioGen.h
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
|
||||||
|
// BioGen.h
|
||||||
|
|
||||||
|
/*
|
||||||
|
Interfaces to the various biome generators:
|
||||||
|
- cBioGenConstant
|
||||||
|
- cBioGenCheckerboard
|
||||||
|
- cBioGenDistortedVoronoi
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cChunkGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cBioGenConstant :
|
||||||
|
public cBiomeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cBioGenConstant(EMCSBiome a_Biome) : m_Biome(a_Biome) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
EMCSBiome m_Biome;
|
||||||
|
|
||||||
|
// cBiomeGen override:
|
||||||
|
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cBioGenDistortedVoronoi :
|
||||||
|
public cBiomeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cBioGenDistortedVoronoi(int a_Seed) : m_Seed(a_Seed) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_Seed;
|
||||||
|
|
||||||
|
// cBiomeGen override:
|
||||||
|
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cBioGenCheckerboard :
|
||||||
|
public cBiomeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cBioGenCheckerboard(int a_BiomeSize) : m_BiomeSize((a_BiomeSize < 8) ? 8 : a_BiomeSize) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_BiomeSize;
|
||||||
|
|
||||||
|
// cBiomeGen override:
|
||||||
|
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
186
source/BlockID.cpp
Normal file
186
source/BlockID.cpp
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
|
||||||
|
// BlockID.cpp
|
||||||
|
|
||||||
|
// Implements the helper functions for converting Block ID string to int etc.
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
#include "../iniFile/iniFile.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NIBBLETYPE g_BlockLightValue[256];
|
||||||
|
NIBBLETYPE g_BlockSpreadLightFalloff[256];
|
||||||
|
bool g_BlockTransparent[256];
|
||||||
|
bool g_BlockOneHitDig[256];
|
||||||
|
bool g_BlockPistonBreakable[256];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cBlockIDMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cBlockIDMap(void) : m_Ini("items.ini")
|
||||||
|
{
|
||||||
|
m_Ini.ReadFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Resolve(const AString & a_ItemName)
|
||||||
|
{
|
||||||
|
return m_Ini.GetValueI("Items", a_ItemName, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cIniFile m_Ini;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static cBlockIDMap gsBlockIDMap;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int BlockStringToType(const AString & a_BlockTypeString)
|
||||||
|
{
|
||||||
|
int res = atoi(a_BlockTypeString.c_str());
|
||||||
|
if ((res != 0) || (a_BlockTypeString.compare("0") == 0))
|
||||||
|
{
|
||||||
|
// It was a valid number, return that
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gsBlockIDMap.Resolve(a_BlockTypeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// This is actually just some code that needs to run at program startup, so it is wrapped into a global var's constructor:
|
||||||
|
class cBlockPropertiesInitializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cBlockPropertiesInitializer(void)
|
||||||
|
{
|
||||||
|
memset( g_BlockLightValue, 0x00, sizeof( g_BlockLightValue ) );
|
||||||
|
memset( g_BlockSpreadLightFalloff, 0x0f, sizeof( g_BlockSpreadLightFalloff ) ); // 0x0f means total falloff
|
||||||
|
memset( g_BlockTransparent, 0x00, sizeof( g_BlockTransparent ) );
|
||||||
|
memset( g_BlockOneHitDig, 0x00, sizeof( g_BlockOneHitDig ) );
|
||||||
|
memset( g_BlockPistonBreakable, 0x00, sizeof( g_BlockPistonBreakable ) );
|
||||||
|
|
||||||
|
// Emissive blocks
|
||||||
|
g_BlockLightValue[E_BLOCK_FIRE] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_GLOWSTONE] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_JACK_O_LANTERN] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_LAVA] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_STATIONARY_LAVA] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_END_PORTAL] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_REDSTONE_LAMP_ON] = 15;
|
||||||
|
g_BlockLightValue[E_BLOCK_TORCH] = 14;
|
||||||
|
g_BlockLightValue[E_BLOCK_BURNING_FURNACE] = 13;
|
||||||
|
g_BlockLightValue[E_BLOCK_NETHER_PORTAL] = 11;
|
||||||
|
g_BlockLightValue[E_BLOCK_REDSTONE_ORE_GLOWING] = 9;
|
||||||
|
g_BlockLightValue[E_BLOCK_REDSTONE_REPEATER_ON] = 9;
|
||||||
|
g_BlockLightValue[E_BLOCK_REDSTONE_TORCH_ON] = 7;
|
||||||
|
g_BlockLightValue[E_BLOCK_BREWING_STAND] = 1;
|
||||||
|
g_BlockLightValue[E_BLOCK_BROWN_MUSHROOM] = 1;
|
||||||
|
g_BlockLightValue[E_BLOCK_DRAGON_EGG] = 1;
|
||||||
|
|
||||||
|
// Spread blocks
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_AIR] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_TORCH] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_FIRE] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_LAVA] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_LAVA] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_WATER] = 4; // Light in water dissapears faster
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_STATIONARY_WATER] = 4;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_LEAVES] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_GLASS] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_GLOWSTONE] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_SIGN_POST] = 1;
|
||||||
|
g_BlockSpreadLightFalloff[E_BLOCK_WALLSIGN] = 1;
|
||||||
|
|
||||||
|
// Transparent blocks
|
||||||
|
g_BlockTransparent[E_BLOCK_AIR] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_GLASS] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_FIRE] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_ICE] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_TORCH] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_SIGN_POST] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_WALLSIGN] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_TALL_GRASS] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_YELLOW_FLOWER] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_RED_ROSE] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_BROWN_MUSHROOM] = true;
|
||||||
|
g_BlockTransparent[E_BLOCK_SNOW] = true;
|
||||||
|
|
||||||
|
// TODO: Any other transparent blocks?
|
||||||
|
|
||||||
|
// One hit break blocks
|
||||||
|
g_BlockOneHitDig[E_BLOCK_SAPLING] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_YELLOW_FLOWER] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_RED_ROSE] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_BROWN_MUSHROOM] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_RED_MUSHROOM] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_TNT] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_TORCH] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REDSTONE_WIRE] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_CROPS] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_OFF] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REDSTONE_TORCH_ON] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REEDS] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REDSTONE_WIRE] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_OFF] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_REDSTONE_REPEATER_ON] = true;
|
||||||
|
g_BlockOneHitDig[E_BLOCK_LOCKED_CHEST] = true;
|
||||||
|
g_BlockOneHitDig [E_BLOCK_FIRE] = true;
|
||||||
|
|
||||||
|
// Blocks that breaks when pushed by piston
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_AIR] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_STATIONARY_WATER] = false; //This gave pistons the ability to drop water :D
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_WATER] = false;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_STATIONARY_LAVA] = false;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_LAVA] = false;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_BED] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_COBWEB] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_TALL_GRASS] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_YELLOW_FLOWER] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_BROWN_MUSHROOM] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_RED_ROSE] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_RED_MUSHROOM] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_DEAD_BUSH] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_TORCH] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_FIRE] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_REDSTONE_WIRE] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_CROPS] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_LADDER] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_WOODEN_DOOR] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_IRON_DOOR] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_LEVER] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_STONE_BUTTON] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_ON] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_REDSTONE_TORCH_OFF] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_SNOW] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_REEDS] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_PUMPKIN_STEM] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_MELON_STEM] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_MELON] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_PUMPKIN] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_JACK_O_LANTERN] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_VINES] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_STONE_PRESSURE_PLATE] = true;
|
||||||
|
g_BlockPistonBreakable[E_BLOCK_WOODEN_PRESSURE_PLATE] = true;
|
||||||
|
}
|
||||||
|
} BlockPropertiesInitializer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ enum ENUM_BLOCK_ID
|
||||||
E_BLOCK_GRASS = 2,
|
E_BLOCK_GRASS = 2,
|
||||||
E_BLOCK_DIRT = 3,
|
E_BLOCK_DIRT = 3,
|
||||||
E_BLOCK_COBBLESTONE = 4,
|
E_BLOCK_COBBLESTONE = 4,
|
||||||
E_BLOCK_WOOD = 5,
|
E_BLOCK_PLANKS = 5,
|
||||||
|
E_BLOCK_WOOD = E_BLOCK_PLANKS,
|
||||||
E_BLOCK_SAPLING = 6,
|
E_BLOCK_SAPLING = 6,
|
||||||
E_BLOCK_BEDROCK = 7,
|
E_BLOCK_BEDROCK = 7,
|
||||||
E_BLOCK_WATER = 8,
|
E_BLOCK_WATER = 8,
|
||||||
|
@ -93,7 +94,8 @@ enum ENUM_BLOCK_ID
|
||||||
E_BLOCK_BLOODSTONE = 87,
|
E_BLOCK_BLOODSTONE = 87,
|
||||||
E_BLOCK_SOULSAND = 88,
|
E_BLOCK_SOULSAND = 88,
|
||||||
E_BLOCK_GLOWSTONE = 89,
|
E_BLOCK_GLOWSTONE = 89,
|
||||||
E_BLOCK_PORT = 90,
|
E_BLOCK_PORT = 90, // Deprecated, use E_BLOCK_NETHER_PORTAL instead
|
||||||
|
E_BLOCK_NETHER_PORTAL = 90,
|
||||||
E_BLOCK_JACK_O_LANTERN = 91,
|
E_BLOCK_JACK_O_LANTERN = 91,
|
||||||
E_BLOCK_CAKE = 92,
|
E_BLOCK_CAKE = 92,
|
||||||
E_BLOCK_REDSTONE_REPEATER_OFF = 93,
|
E_BLOCK_REDSTONE_REPEATER_OFF = 93,
|
||||||
|
@ -125,6 +127,9 @@ enum ENUM_BLOCK_ID
|
||||||
E_BLOCK_END_PORTAL = 119,
|
E_BLOCK_END_PORTAL = 119,
|
||||||
E_BLOCK_END_PORTAL_FRAME = 120,
|
E_BLOCK_END_PORTAL_FRAME = 120,
|
||||||
E_BLOCK_END_STONE = 121,
|
E_BLOCK_END_STONE = 121,
|
||||||
|
E_BLOCK_DRAGON_EGG = 122,
|
||||||
|
E_BLOCK_REDSTONE_LAMP_OFF = 123,
|
||||||
|
E_BLOCK_REDSTONE_LAMP_ON = 124,
|
||||||
E_BLOCK_ = 121,
|
E_BLOCK_ = 121,
|
||||||
};
|
};
|
||||||
//tolua_end
|
//tolua_end
|
||||||
|
@ -394,38 +399,60 @@ enum ENUM_ITEM_ID
|
||||||
E_ITEM_WARD_DISC = 2265,
|
E_ITEM_WARD_DISC = 2265,
|
||||||
E_ITEM_11_DISC = 2266,
|
E_ITEM_11_DISC = 2266,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// E_BLOCK_PLANKS metas:
|
||||||
|
E_META_PLANKS_APPLE = 0,
|
||||||
|
E_META_PLANKS_CONIFER = 1,
|
||||||
|
E_META_PLANKS_BIRCH = 2,
|
||||||
|
E_META_PLANKS_JUNGLE = 3,
|
||||||
|
|
||||||
|
// E_BLOCK_LOG metas:
|
||||||
|
E_META_LOG_APPLE = 0,
|
||||||
|
E_META_LOG_CONIFER = 1,
|
||||||
|
E_META_LOG_BIRCH = 2,
|
||||||
|
E_META_LOG_JUNGLE = 3,
|
||||||
|
|
||||||
|
// E_BLOCK_LEAVES metas:
|
||||||
|
E_META_LEAVES_APPLE = 0,
|
||||||
|
E_META_LEAVES_CONIFER = 1,
|
||||||
|
E_META_LEAVES_BIRCH = 2,
|
||||||
|
E_META_LEAVES_JUNGLE = 3,
|
||||||
|
|
||||||
|
// E_BLOCK_SAPLING metas (lowest 3 bits):
|
||||||
|
E_META_SAPLING_APPLE = 0,
|
||||||
|
E_META_SAPLING_CONIFER = 1,
|
||||||
|
E_META_SAPLING_BIRCH = 2,
|
||||||
|
E_META_SAPLING_JUNGLE = 3,
|
||||||
|
|
||||||
|
// E_BLOCK_TALL_GRASS metas:
|
||||||
|
E_META_TALL_GRASS_DEAD_SHRUB = 0,
|
||||||
|
E_META_TALL_GRASS_GRASS = 1,
|
||||||
|
E_META_TALL_GRASS_FERN = 2,
|
||||||
|
} ;
|
||||||
//tolua_end
|
//tolua_end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Biome IDs, as stored in the Anvil format and sent in the MapChunk packet
|
// Translates a blocktype string into blocktype. Takes either a number or an items.ini alias as input. Returns -1 on failure.
|
||||||
enum eBiomeID
|
extern int BlockStringToType(const AString & a_BlockTypeString);
|
||||||
{
|
|
||||||
biOcean = 0,
|
|
||||||
biPlains = 1,
|
|
||||||
biDesert = 2,
|
|
||||||
biExtremeHills = 3,
|
|
||||||
biForest = 4,
|
// Block properties:
|
||||||
biTaiga = 5,
|
extern NIBBLETYPE g_BlockLightValue[256];
|
||||||
biSwampland = 6,
|
extern NIBBLETYPE g_BlockSpreadLightFalloff[256];
|
||||||
biRiver = 7,
|
extern bool g_BlockTransparent[256];
|
||||||
biHell = 8, // Nether?
|
extern bool g_BlockOneHitDig[256];
|
||||||
biSky = 9,
|
extern bool g_BlockPistonBreakable[256];
|
||||||
biFrozenOcean = 10,
|
|
||||||
biFrozenRiver = 11,
|
|
||||||
biIcePlains = 12,
|
|
||||||
biIceMountains = 13,
|
|
||||||
biMushroomIsland = 14,
|
|
||||||
biMushroomShore = 15,
|
|
||||||
biBeach = 16,
|
|
||||||
biDesertHills = 17,
|
|
||||||
biForestHills = 18,
|
|
||||||
biTaigaHills = 19,
|
|
||||||
biExtremeHillsEdge = 20,
|
|
||||||
biJungle = 21,
|
|
||||||
biJungleHills = 22,
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,51 @@ typedef std::list<cBlockEntity *> cBlockEntityList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// The datatype used by blockdata, metadata, blocklight and skylight
|
/// The datatype used by blockdata
|
||||||
typedef char BLOCKTYPE;
|
typedef char BLOCKTYPE;
|
||||||
typedef char BIOMETYPE;
|
|
||||||
|
/// The datatype used by nibbledata (meta, light, skylight)
|
||||||
|
typedef unsigned char NIBBLETYPE;
|
||||||
|
|
||||||
|
/// The type used by the heightmap
|
||||||
|
typedef unsigned char HEIGHTTYPE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Biome IDs
|
||||||
|
The first batch corresponds to the clientside biomes, used by MineCraft.
|
||||||
|
BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client
|
||||||
|
When adding or deleting, you might want to edit the cBioGenCheckerBoard in BioGen.cpp to
|
||||||
|
include / exclude that biome in that generator.
|
||||||
|
*/
|
||||||
|
enum EMCSBiome
|
||||||
|
{
|
||||||
|
biOcean = 0,
|
||||||
|
biPlains = 1,
|
||||||
|
biDesert = 2,
|
||||||
|
biExtremeHills = 3,
|
||||||
|
biForest = 4,
|
||||||
|
biTaiga = 5,
|
||||||
|
biSwampland = 6,
|
||||||
|
biRiver = 7,
|
||||||
|
biHell = 8, // Nether?
|
||||||
|
biSky = 9,
|
||||||
|
biFrozenOcean = 10,
|
||||||
|
biFrozenRiver = 11,
|
||||||
|
biIcePlains = 12,
|
||||||
|
biIceMountains = 13,
|
||||||
|
biMushroomIsland = 14,
|
||||||
|
biMushroomShore = 15,
|
||||||
|
biBeach = 16,
|
||||||
|
biDesertHills = 17,
|
||||||
|
biForestHills = 18,
|
||||||
|
biTaigaHills = 19,
|
||||||
|
biExtremeHillsEdge = 20,
|
||||||
|
biJungle = 21,
|
||||||
|
biJungleHills = 22,
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +107,20 @@ public:
|
||||||
|
|
||||||
static const unsigned int INDEX_OUT_OF_RANGE = 0xffffffff;
|
static const unsigned int INDEX_OUT_OF_RANGE = 0xffffffff;
|
||||||
|
|
||||||
typedef unsigned char HeightMap[Width * Width];
|
/// The type used for any heightmap operations and storage; idx = x + Width * z
|
||||||
|
typedef HEIGHTTYPE HeightMap[Width * Width];
|
||||||
|
|
||||||
|
/** The type used for any biomemap operations and storage inside MCServer,
|
||||||
|
using MCServer biomes (need not correspond to client representation!)
|
||||||
|
idx = x + Width * z // Need to verify this with the protocol spec, currently unknown!
|
||||||
|
*/
|
||||||
|
typedef EMCSBiome BiomeMap[Width * Width];
|
||||||
|
|
||||||
|
/// The type used for block type operations and storage, AXIS_ORDER ordering
|
||||||
|
typedef BLOCKTYPE BlockTypes[NumBlocks];
|
||||||
|
|
||||||
|
/// The type used for block data in nibble format, AXIS_ORDER ordering
|
||||||
|
typedef NIBBLETYPE BlockNibbles[NumBlocks / 2];
|
||||||
|
|
||||||
|
|
||||||
/// Converts absolute block coords into relative (chunk + block) coords:
|
/// Converts absolute block coords into relative (chunk + block) coords:
|
||||||
|
@ -134,7 +189,49 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static BLOCKTYPE GetNibble(BLOCKTYPE * a_Buffer, int a_BlockIdx)
|
inline static void SetBlock(BLOCKTYPE * a_BlockTypes, int a_X, int a_Y, int a_Z, BLOCKTYPE a_Type)
|
||||||
|
{
|
||||||
|
ASSERT((a_X >= 0) && (a_X < Width));
|
||||||
|
ASSERT((a_Y >= 0) && (a_Y < Height));
|
||||||
|
ASSERT((a_Z >= 0) && (a_Z < Width));
|
||||||
|
a_BlockTypes[MakeIndexNoCheck(a_X, a_Y, a_Z)] = a_Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline static BLOCKTYPE GetBlock(BLOCKTYPE * a_BlockTypes, int a_X, int a_Y, int a_Z)
|
||||||
|
{
|
||||||
|
ASSERT((a_X >= 0) && (a_X < Width));
|
||||||
|
ASSERT((a_Y >= 0) && (a_Y < Height));
|
||||||
|
ASSERT((a_Z >= 0) && (a_Z < Width));
|
||||||
|
return a_BlockTypes[MakeIndexNoCheck(a_X, a_Y, a_Z)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline static int GetHeight(const HeightMap & a_HeightMap, int a_X, int a_Z)
|
||||||
|
{
|
||||||
|
return a_HeightMap[a_X + Width * a_Z];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline static void SetHeight(HeightMap & a_HeightMap, int a_X, int a_Z, unsigned char a_Height)
|
||||||
|
{
|
||||||
|
a_HeightMap[a_X + Width * a_Z] = a_Height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline static EMCSBiome GetBiome(const BiomeMap & a_BiomeMap, int a_X, int a_Z)
|
||||||
|
{
|
||||||
|
return a_BiomeMap[a_X + Width * a_Z];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline static void SetBiome(BiomeMap & a_BiomeMap, int a_X, int a_Z, EMCSBiome a_Biome)
|
||||||
|
{
|
||||||
|
a_BiomeMap[a_X + Width * a_Z] = a_Biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static NIBBLETYPE GetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx)
|
||||||
{
|
{
|
||||||
if ((a_BlockIdx > -1) && (a_BlockIdx < cChunkDef::NumBlocks))
|
if ((a_BlockIdx > -1) && (a_BlockIdx < cChunkDef::NumBlocks))
|
||||||
{
|
{
|
||||||
|
@ -144,7 +241,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static BLOCKTYPE GetNibble(BLOCKTYPE * a_Buffer, int x, int y, int z)
|
static NIBBLETYPE GetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z)
|
||||||
{
|
{
|
||||||
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
||||||
{
|
{
|
||||||
|
@ -155,7 +252,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void SetNibble(BLOCKTYPE * a_Buffer, int a_BlockIdx, BLOCKTYPE a_Nibble)
|
static void SetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble)
|
||||||
{
|
{
|
||||||
if ((a_BlockIdx > -1) && (a_BlockIdx < cChunkDef::NumBlocks))
|
if ((a_BlockIdx > -1) && (a_BlockIdx < cChunkDef::NumBlocks))
|
||||||
{
|
{
|
||||||
|
@ -167,7 +264,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void SetNibble(BLOCKTYPE * a_Buffer, int x, int y, int z, BLOCKTYPE a_Nibble)
|
static void SetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble)
|
||||||
{
|
{
|
||||||
if ((x < cChunkDef::Width) && (x > -1) && (y < cChunkDef::Height) && (y > -1) && (z < cChunkDef::Width) && (z > -1))
|
if ((x < cChunkDef::Width) && (x > -1) && (y < cChunkDef::Height) && (y > -1) && (z < cChunkDef::Width) && (z > -1))
|
||||||
{
|
{
|
||||||
|
@ -180,13 +277,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline static BLOCKTYPE GetNibble(BLOCKTYPE * a_Buffer, const Vector3i & a_BlockPos )
|
inline static char GetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos )
|
||||||
{
|
{
|
||||||
return GetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
|
return GetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline static void SetNibble(BLOCKTYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
|
inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, char a_Value )
|
||||||
{
|
{
|
||||||
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
|
SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value );
|
||||||
}
|
}
|
||||||
|
@ -207,17 +304,23 @@ public:
|
||||||
/// Called once to provide heightmap data
|
/// Called once to provide heightmap data
|
||||||
virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {};
|
virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {};
|
||||||
|
|
||||||
|
/// Called once to provide biome data
|
||||||
|
virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {};
|
||||||
|
|
||||||
/// Called once to export block types
|
/// Called once to export block types
|
||||||
virtual void BlockTypes (const BLOCKTYPE * a_Type) {};
|
virtual void BlockTypes (const BLOCKTYPE * a_Type) {};
|
||||||
|
|
||||||
/// Called once to export block meta
|
/// Called once to export block meta
|
||||||
virtual void BlockMeta (const BLOCKTYPE * a_Meta) {};
|
virtual void BlockMeta (const NIBBLETYPE * a_Meta) {};
|
||||||
|
|
||||||
|
/// Called once to let know if the chunk lighting is valid. Return value is used to control if BlockLight() and BlockSkyLight() are called next
|
||||||
|
virtual bool LightIsValid(bool a_IsLightValid) {return true; };
|
||||||
|
|
||||||
/// Called once to export block light
|
/// Called once to export block light
|
||||||
virtual void BlockLight (const BLOCKTYPE * a_Meta) {};
|
virtual void BlockLight (const NIBBLETYPE * a_Meta) {};
|
||||||
|
|
||||||
/// Called once to export sky light
|
/// Called once to export sky light
|
||||||
virtual void BlockSkyLight(const BLOCKTYPE * a_Meta) {};
|
virtual void BlockSkyLight(const NIBBLETYPE * a_Meta) {};
|
||||||
|
|
||||||
/// Called for each entity in the chunk
|
/// Called for each entity in the chunk
|
||||||
virtual void Entity(cEntity * a_Entity) {};
|
virtual void Entity(cEntity * a_Entity) {};
|
||||||
|
@ -237,29 +340,30 @@ class cChunkDataCollector :
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BLOCKTYPE m_BlockData[cChunkDef::BlockDataSize];
|
// Must be char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
|
||||||
|
char m_BlockData[cChunkDef::BlockDataSize];
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
|
virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockData, a_BlockTypes, cChunkDef::NumBlocks);
|
memcpy(m_BlockData, a_BlockTypes, sizeof(cChunkDef::BlockTypes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void BlockMeta(const BLOCKTYPE * a_BlockMeta) override
|
virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockData + cChunkDef::NumBlocks, a_BlockMeta, cChunkDef::NumBlocks / 2);
|
memcpy(m_BlockData + cChunkDef::NumBlocks, a_BlockMeta, cChunkDef::NumBlocks / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void BlockLight(const BLOCKTYPE * a_BlockLight) override
|
virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockData + 3 * cChunkDef::NumBlocks / 2, a_BlockLight, cChunkDef::NumBlocks / 2);
|
memcpy(m_BlockData + 3 * cChunkDef::NumBlocks / 2, a_BlockLight, cChunkDef::NumBlocks / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void BlockSkyLight(const BLOCKTYPE * a_BlockSkyLight) override
|
virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockData + 2 * cChunkDef::NumBlocks, a_BlockSkyLight, cChunkDef::NumBlocks / 2);
|
memcpy(m_BlockData + 2 * cChunkDef::NumBlocks, a_BlockSkyLight, cChunkDef::NumBlocks / 2);
|
||||||
}
|
}
|
||||||
|
@ -276,12 +380,10 @@ class cChunkDataSeparateCollector :
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
BLOCKTYPE m_BlockTypes[cChunkDef::NumBlocks];
|
cChunkDef::BlockTypes m_BlockTypes;
|
||||||
|
cChunkDef::BlockNibbles m_BlockMetas;
|
||||||
// TODO: These should be NIBBLETYPE:
|
cChunkDef::BlockNibbles m_BlockLight;
|
||||||
BLOCKTYPE m_BlockMetas[cChunkDef::NumBlocks / 2];
|
cChunkDef::BlockNibbles m_BlockSkyLight;
|
||||||
BLOCKTYPE m_BlockLight[cChunkDef::NumBlocks / 2];
|
|
||||||
BLOCKTYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2];
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -291,19 +393,19 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void BlockMeta(const BLOCKTYPE * a_BlockMeta) override
|
virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockMetas, a_BlockMeta, sizeof(m_BlockMetas));
|
memcpy(m_BlockMetas, a_BlockMeta, sizeof(m_BlockMetas));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void BlockLight(const BLOCKTYPE * a_BlockLight) override
|
virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void BlockSkyLight(const BLOCKTYPE * a_BlockSkyLight) override
|
virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override
|
||||||
{
|
{
|
||||||
memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
|
memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
|
||||||
}
|
}
|
||||||
|
@ -334,12 +436,20 @@ struct sSetBlock
|
||||||
{
|
{
|
||||||
int x, y, z;
|
int x, y, z;
|
||||||
int ChunkX, ChunkZ;
|
int ChunkX, ChunkZ;
|
||||||
char BlockType, BlockMeta;
|
BLOCKTYPE BlockType;
|
||||||
|
NIBBLETYPE BlockMeta;
|
||||||
|
|
||||||
sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); // absolute block position
|
sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ); // absolute block position
|
||||||
|
sSetBlock(int a_ChunkX, int a_ChunkZ, int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) :
|
||||||
|
ChunkX(a_ChunkX), ChunkZ(a_ChunkZ),
|
||||||
|
x(a_X), y(a_Y), z(a_Z),
|
||||||
|
BlockType(a_BlockType),
|
||||||
|
BlockMeta(a_BlockMeta)
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::list< sSetBlock > sSetBlockList;
|
typedef std::list<sSetBlock> sSetBlockList;
|
||||||
|
typedef std::vector<sSetBlock> sSetBlockVector;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -366,3 +476,13 @@ typedef std::list<cChunkCoords> cChunkCoordsList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Interface class used as a callback for operations that involve chunk coords
|
||||||
|
class cChunkCoordCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void Call(int a_ChunkX, int a_ChunkZ) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,27 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cNotifyChunkSender:
|
||||||
|
|
||||||
|
void cNotifyChunkSender::Call(int a_ChunkX, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
m_ChunkSender->ChunkReady(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cChunkSender:
|
||||||
|
|
||||||
cChunkSender::cChunkSender(void) :
|
cChunkSender::cChunkSender(void) :
|
||||||
super("ChunkSender"),
|
super("ChunkSender"),
|
||||||
m_World(NULL)
|
m_World(NULL),
|
||||||
|
m_Notify(NULL)
|
||||||
{
|
{
|
||||||
memset(m_BiomeData, biPlains, sizeof(m_BiomeData));
|
m_Notify.SetChunkSender(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,18 +198,32 @@ void cChunkSender::SendChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the chunk has no clients, no need to packetize it:
|
||||||
if (!m_World->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ))
|
if (!m_World->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the chunk is not valid, do nothing - whoever needs it has queued it for loading / generating
|
||||||
|
if (!m_World->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the chunk is not lighted, queue it for relighting and get notified when it's ready:
|
||||||
|
if (!m_World->IsChunkLighted(a_ChunkX, a_ChunkZ))
|
||||||
|
{
|
||||||
|
m_World->QueueLightChunk(a_ChunkX, a_ChunkZ, &m_Notify);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Prepare MapChunk packets:
|
// Prepare MapChunk packets:
|
||||||
if( !m_World->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, *this) )
|
if( !m_World->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, *this) )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cPacket_PreChunk PreChunk(a_ChunkX, a_ChunkZ, true);
|
cPacket_PreChunk PreChunk(a_ChunkX, a_ChunkZ, true);
|
||||||
cPacket_MapChunk MapChunk(a_ChunkX, a_ChunkY, a_ChunkZ, m_BlockData, m_BiomeData);
|
cPacket_MapChunk MapChunk(a_ChunkX, a_ChunkY, a_ChunkZ, m_BlockData, m_BiomeMap);
|
||||||
|
|
||||||
// Send:
|
// Send:
|
||||||
if (a_Client == NULL)
|
if (a_Client == NULL)
|
||||||
|
@ -247,3 +277,24 @@ void cChunkSender::Entity(cEntity * a_Entity)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkSender::BiomeData(const cChunkDef::BiomeMap * a_BiomeMap)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(m_BiomeMap); i++)
|
||||||
|
{
|
||||||
|
if ((*a_BiomeMap)[i] < 255)
|
||||||
|
{
|
||||||
|
// Normal MC biome, copy as-is:
|
||||||
|
m_BiomeMap[i] = (unsigned char)((*a_BiomeMap)[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: MCS-specific biome, need to map to some basic MC biome:
|
||||||
|
ASSERT(!"Unimplemented MCS-specific biome");
|
||||||
|
}
|
||||||
|
} // for i - m_BiomeMap[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,33 @@ class cClientHandle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd:
|
||||||
|
class cChunkSender;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Callback that can be used to notify chunk sender upon another chunkcoord notification
|
||||||
|
class cNotifyChunkSender :
|
||||||
|
public cChunkCoordCallback
|
||||||
|
{
|
||||||
|
virtual void Call(int a_ChunkX, int a_ChunkZ) override;
|
||||||
|
|
||||||
|
cChunkSender * m_ChunkSender;
|
||||||
|
public:
|
||||||
|
cNotifyChunkSender(cChunkSender * a_ChunkSender) : m_ChunkSender(a_ChunkSender) {}
|
||||||
|
|
||||||
|
void SetChunkSender(cChunkSender * a_ChunkSender)
|
||||||
|
{
|
||||||
|
m_ChunkSender = a_ChunkSender;
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cChunkSender:
|
class cChunkSender:
|
||||||
public cIsThread,
|
public cIsThread,
|
||||||
public cChunkDataCollector
|
public cChunkDataCollector
|
||||||
|
@ -101,9 +128,11 @@ protected:
|
||||||
cEvent m_evtRemoved; // Set when removed clients are safe to be deleted
|
cEvent m_evtRemoved; // Set when removed clients are safe to be deleted
|
||||||
int m_RemoveCount; // Number of threads waiting for a client removal (m_evtRemoved needs to be set this many times)
|
int m_RemoveCount; // Number of threads waiting for a client removal (m_evtRemoved needs to be set this many times)
|
||||||
|
|
||||||
|
cNotifyChunkSender m_Notify; // Used for chunks that don't have a valid lighting - they will be re-queued after lightcalc
|
||||||
|
|
||||||
// Data about the chunk that is being sent:
|
// Data about the chunk that is being sent:
|
||||||
// NOTE that m_BlockData[] is inherited from the cChunkDataCollector
|
// NOTE that m_BlockData[] is inherited from the cChunkDataCollector
|
||||||
BIOMETYPE m_BiomeData[cChunkDef::Width * cChunkDef::Width];
|
unsigned char m_BiomeMap[cChunkDef::Width * cChunkDef::Width];
|
||||||
PacketList m_Packets; // Accumulator for the entity-packets to send
|
PacketList m_Packets; // Accumulator for the entity-packets to send
|
||||||
|
|
||||||
// cIsThread override:
|
// cIsThread override:
|
||||||
|
@ -111,6 +140,7 @@ protected:
|
||||||
|
|
||||||
// cChunkDataCollector overrides:
|
// cChunkDataCollector overrides:
|
||||||
// (Note that they are called while the ChunkMap's CS is locked - don't do heavy calculations here!)
|
// (Note that they are called while the ChunkMap's CS is locked - don't do heavy calculations here!)
|
||||||
|
virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) override;
|
||||||
virtual void Entity (cEntity * a_Entity) override;
|
virtual void Entity (cEntity * a_Entity) override;
|
||||||
virtual void BlockEntity (cBlockEntity * a_Entity) override;
|
virtual void BlockEntity (cBlockEntity * a_Entity) override;
|
||||||
|
|
||||||
|
|
174
source/CompoGen.cpp
Normal file
174
source/CompoGen.cpp
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
|
||||||
|
// CompoGen.cpp
|
||||||
|
|
||||||
|
/* Implements the various terrain composition generators:
|
||||||
|
- cCompoGenSameBlock
|
||||||
|
- cCompoGenDebugBiomes
|
||||||
|
- cCompoGenClassic
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CompoGen.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cCompoGenSameBlock:
|
||||||
|
|
||||||
|
void cCompoGenSameBlock::ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
memset(a_BlockTypes, E_BLOCK_AIR, sizeof(a_BlockTypes));
|
||||||
|
memset(a_BlockMeta, 0, sizeof(a_BlockMeta));
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
int Start;
|
||||||
|
if (m_IsBedrocked)
|
||||||
|
{
|
||||||
|
a_BlockTypes[cChunkDef::MakeIndex(x, 0, z)] = E_BLOCK_BEDROCK;
|
||||||
|
Start = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Start = 0;
|
||||||
|
}
|
||||||
|
for (int y = a_HeightMap[x + cChunkDef::Width * z]; y >= Start; y--)
|
||||||
|
{
|
||||||
|
a_BlockTypes[cChunkDef::MakeIndex(x, y, z)] = m_BlockType;
|
||||||
|
} // for y
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cCompoGenDebugBiomes:
|
||||||
|
|
||||||
|
void cCompoGenDebugBiomes::ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
memset(a_BlockTypes, E_BLOCK_AIR, sizeof(a_BlockTypes));
|
||||||
|
memset(a_BlockMeta, 0, sizeof(a_BlockMeta));
|
||||||
|
|
||||||
|
cChunkDef::BiomeMap BiomeMap;
|
||||||
|
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
|
||||||
|
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
BLOCKTYPE BlockType = (BLOCKTYPE)cChunkDef::GetBiome(BiomeMap, x, z);
|
||||||
|
for (int y = a_HeightMap[x + cChunkDef::Width * z]; y >= 0; y--)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, BlockType);
|
||||||
|
} // for y
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cCompoGenClassic:
|
||||||
|
|
||||||
|
cCompoGenClassic::cCompoGenClassic(int a_SeaLevel, int a_BeachHeight, int a_BeachDepth) :
|
||||||
|
m_SeaLevel(a_SeaLevel),
|
||||||
|
m_BeachHeight(a_BeachHeight),
|
||||||
|
m_BeachDepth(a_BeachDepth)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cCompoGenClassic::ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* The classic composition means:
|
||||||
|
- 1 layer of grass, 3 of dirt and the rest stone, if the height > sealevel + beachheight
|
||||||
|
- 3 sand and a 1 sandstone, rest stone if between sealevel and sealevel + beachheight
|
||||||
|
- water from waterlevel to height, then 3 sand, 1 sandstone, the rest stone, if water depth < beachdepth
|
||||||
|
- water from waterlevel, then 3 dirt, the rest stone otherwise
|
||||||
|
- bedrock at the bottom
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(a_BlockTypes, E_BLOCK_AIR, sizeof(a_BlockTypes));
|
||||||
|
memset(a_BlockMeta, 0, sizeof(a_BlockMeta));
|
||||||
|
|
||||||
|
// The patterns to use for different situations, must be same length!
|
||||||
|
static const BLOCKTYPE PatternGround[] = {E_BLOCK_GRASS, E_BLOCK_DIRT, E_BLOCK_DIRT, E_BLOCK_DIRT} ;
|
||||||
|
static const BLOCKTYPE PatternBeach[] = {E_BLOCK_SAND, E_BLOCK_SAND, E_BLOCK_SAND, E_BLOCK_SANDSTONE} ;
|
||||||
|
static const BLOCKTYPE PatternOcean[] = {E_BLOCK_DIRT, E_BLOCK_DIRT, E_BLOCK_DIRT, E_BLOCK_STONE} ;
|
||||||
|
static int PatternLength = ARRAYCOUNT(PatternGround);
|
||||||
|
ASSERT(ARRAYCOUNT(PatternGround) == ARRAYCOUNT(PatternBeach));
|
||||||
|
ASSERT(ARRAYCOUNT(PatternGround) == ARRAYCOUNT(PatternOcean));
|
||||||
|
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
int Height = a_HeightMap[x + cChunkDef::Width * z];
|
||||||
|
const BLOCKTYPE * Pattern;
|
||||||
|
if (Height > m_SeaLevel + m_BeachHeight)
|
||||||
|
{
|
||||||
|
Pattern = PatternGround;
|
||||||
|
}
|
||||||
|
else if (Height > m_SeaLevel - m_BeachDepth)
|
||||||
|
{
|
||||||
|
Pattern = PatternBeach;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Pattern = PatternOcean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill water from sealevel down to height (if any):
|
||||||
|
for (int y = m_SeaLevel; y >= Height; --y)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_STATIONARY_WATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill from height till the bottom:
|
||||||
|
for (int y = Height; y >= 1; y--)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, (Height - y < PatternLength) ? Pattern[Height - y] : E_BLOCK_STONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The last layer is always bedrock:
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, 0, z, E_BLOCK_BEDROCK);
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
101
source/CompoGen.h
Normal file
101
source/CompoGen.h
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
|
||||||
|
// CompoGen.h
|
||||||
|
|
||||||
|
/* Interfaces to the various terrain composition generators:
|
||||||
|
- cCompoGenSameBlock
|
||||||
|
- cCompoGenDebugBiomes
|
||||||
|
- cCompoGenClassic
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cChunkGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCompoGenSameBlock :
|
||||||
|
public cTerrainCompositionGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cCompoGenSameBlock(BLOCKTYPE a_BlockType, bool a_IsBedrocked) :
|
||||||
|
m_BlockType(a_BlockType),
|
||||||
|
m_IsBedrocked(a_IsBedrocked)
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
BLOCKTYPE m_BlockType;
|
||||||
|
bool m_IsBedrocked;
|
||||||
|
|
||||||
|
// cTerrainCompositionGen overrides:
|
||||||
|
virtual void ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCompoGenDebugBiomes :
|
||||||
|
public cTerrainCompositionGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cCompoGenDebugBiomes(cBiomeGen * a_BiomeGen) : m_BiomeGen(a_BiomeGen) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
cBiomeGen * m_BiomeGen;
|
||||||
|
|
||||||
|
// cTerrainCompositionGen overrides:
|
||||||
|
virtual void ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCompoGenClassic :
|
||||||
|
public cTerrainCompositionGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cCompoGenClassic(int a_SeaLevel, int a_BeachHeight, int a_BeachDepth);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_SeaLevel;
|
||||||
|
int m_BeachHeight;
|
||||||
|
int m_BeachDepth;
|
||||||
|
|
||||||
|
// cTerrainCompositionGen overrides:
|
||||||
|
virtual void ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
//tolua_begin
|
//tolua_begin
|
||||||
// emissive blocks
|
// emissive blocks
|
||||||
extern char g_BlockLightValue[];
|
extern unsigned char g_BlockLightValue[];
|
||||||
// whether blocks allow spreading
|
// whether blocks allow spreading
|
||||||
extern char g_BlockSpreadLightFalloff[];
|
extern unsigned char g_BlockSpreadLightFalloff[];
|
||||||
// whether blocks are transparent (light can shine though)
|
// whether blocks are transparent (light can shine though)
|
||||||
extern bool g_BlockTransparent[];
|
extern bool g_BlockTransparent[];
|
||||||
// one hit break blocks
|
// one hit break blocks
|
||||||
|
|
|
@ -259,7 +259,7 @@ protected:
|
||||||
{
|
{
|
||||||
// Compound: add the type and name:
|
// Compound: add the type and name:
|
||||||
m_Result.push_back((char)a_Type);
|
m_Result.push_back((char)a_Type);
|
||||||
WriteString(a_Name.c_str(), a_Name.length());
|
WriteString(a_Name.c_str(), (short)a_Name.length());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
154
source/FinishGen.cpp
Normal file
154
source/FinishGen.cpp
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
|
||||||
|
// FinishGen.cpp
|
||||||
|
|
||||||
|
/* Implements the various finishing generators:
|
||||||
|
- cFinishGenSnow
|
||||||
|
- cFinishGenIce
|
||||||
|
- cFinishGenSprinkleFoliage
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
|
||||||
|
#include "FinishGen.h"
|
||||||
|
#include "cNoise.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFinishGenSprinkleFoliage:
|
||||||
|
|
||||||
|
void cFinishGenSprinkleFoliage::GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Generate small foliage (1-block):
|
||||||
|
|
||||||
|
// TODO: Update heightmap with 1-block-tall foliage
|
||||||
|
cNoise Noise(m_Seed);
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
int BlockZ = a_ChunkZ * cChunkDef::Width + z;
|
||||||
|
const float zz = (float)BlockZ;
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
int BlockX = a_ChunkX * cChunkDef::Width + x;
|
||||||
|
if (((Noise.IntNoise2DInt(BlockX, BlockZ) / 8) % 128) < 124)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int Top = cChunkDef::GetHeight(a_HeightMap, x, z);
|
||||||
|
if (Top > 250)
|
||||||
|
{
|
||||||
|
// Nothing grows above Y=250
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (cChunkDef::GetBlock(a_BlockTypes, x, Top + 1, z) != E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
// Space already taken by something else, don't grow here
|
||||||
|
// WEIRD, since we're using heightmap, so there should NOT be anything above it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float xx = (float)BlockX;
|
||||||
|
float val1 = Noise.CubicNoise2D(xx * 0.1f, zz * 0.1f );
|
||||||
|
float val2 = Noise.CubicNoise2D(xx * 0.01f, zz * 0.01f );
|
||||||
|
switch (cChunkDef::GetBlock(a_BlockTypes, x, Top, z))
|
||||||
|
{
|
||||||
|
case E_BLOCK_GRASS:
|
||||||
|
{
|
||||||
|
float val3 = Noise.CubicNoise2D(xx * 0.01f + 10, zz * 0.01f + 10 );
|
||||||
|
float val4 = Noise.CubicNoise2D(xx * 0.05f + 20, zz * 0.05f + 20 );
|
||||||
|
if (val1 + val2 > 0.2f)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, ++Top, z, E_BLOCK_YELLOW_FLOWER);
|
||||||
|
}
|
||||||
|
else if (val2 + val3 > 0.2f)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, ++Top, z, E_BLOCK_RED_ROSE);
|
||||||
|
}
|
||||||
|
else if (val3 + val4 > 0.2f)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, ++Top, z, E_BLOCK_RED_MUSHROOM);
|
||||||
|
}
|
||||||
|
else if (val1 + val4 > 0.2f)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, ++Top, z, E_BLOCK_BROWN_MUSHROOM);
|
||||||
|
}
|
||||||
|
else if (val1 + val2 + val3 + val4 < -0.1)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock (a_BlockTypes, x, ++Top, z, E_BLOCK_TALL_GRASS);
|
||||||
|
cChunkDef::SetNibble(a_BlockMeta, x, Top, z, E_META_TALL_GRASS_GRASS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} // case E_BLOCK_GRASS
|
||||||
|
|
||||||
|
case E_BLOCK_SAND:
|
||||||
|
{
|
||||||
|
if (val1 + val2 > 0.f)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, ++Top, z, E_BLOCK_CACTUS);
|
||||||
|
if (val1 > val2)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, ++Top, z, E_BLOCK_CACTUS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (TopBlock)
|
||||||
|
cChunkDef::SetHeight(a_HeightMap, x, z, Top);
|
||||||
|
} // for y
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFinishGenSnow:
|
||||||
|
|
||||||
|
void cFinishGenSnow::GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// TODO: Add snow block in snowy biomes onto blocks that can be snowed over
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cFinishGenIce:
|
||||||
|
|
||||||
|
void cFinishGenIce::GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// TODO: Turn surface water into ice in icy biomes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
82
source/FinishGen.h
Normal file
82
source/FinishGen.h
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
|
||||||
|
// FinishGen.h
|
||||||
|
|
||||||
|
/* Interfaces to the various finishing generators:
|
||||||
|
- cFinishGenSnow
|
||||||
|
- cFinishGenIce
|
||||||
|
- cFinishGenSprinkleFoliage
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#include "cChunkGenerator.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cFinishGenSnow :
|
||||||
|
public cFinishGen
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// cFinishGen override:
|
||||||
|
virtual void GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cFinishGenIce :
|
||||||
|
public cFinishGen
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// cFinishGen override:
|
||||||
|
virtual void GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cFinishGenSprinkleFoliage :
|
||||||
|
public cFinishGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cFinishGenSprinkleFoliage(int a_Seed) : m_Seed(a_Seed) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int m_Seed;
|
||||||
|
|
||||||
|
// cFinishGen override:
|
||||||
|
virtual void GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ typedef short Int16;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Common headers:
|
// Common headers (part 1, without macros):
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
#include "cSleep.h"
|
#include "cSleep.h"
|
||||||
#include "cCriticalSection.h"
|
#include "cCriticalSection.h"
|
||||||
|
@ -187,3 +187,11 @@ public:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Common headers (part 2, with macros):
|
||||||
|
#include "ChunkDef.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
91
source/HeiGen.cpp
Normal file
91
source/HeiGen.cpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
|
||||||
|
// HeiGen.cpp
|
||||||
|
|
||||||
|
// Implements the various terrain height generators
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "HeiGen.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cHeiGenFlat:
|
||||||
|
|
||||||
|
void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(a_HeightMap); i++)
|
||||||
|
{
|
||||||
|
a_HeightMap[i] = m_Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cHeiGenClassic:
|
||||||
|
|
||||||
|
cHeiGenClassic::cHeiGenClassic(int a_Seed, float a_HeightFreq1, float a_HeightAmp1, float a_HeightFreq2, float a_HeightAmp2, float a_HeightFreq3, float a_HeightAmp3) :
|
||||||
|
m_Seed(a_Seed),
|
||||||
|
m_Noise(a_Seed),
|
||||||
|
m_HeightFreq1(a_HeightFreq1),
|
||||||
|
m_HeightAmp1 (a_HeightAmp1),
|
||||||
|
m_HeightFreq2(a_HeightFreq2),
|
||||||
|
m_HeightAmp2 (a_HeightAmp2),
|
||||||
|
m_HeightFreq3(a_HeightFreq3),
|
||||||
|
m_HeightAmp3 (a_HeightAmp3)
|
||||||
|
{
|
||||||
|
// Nothing needed yet
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
float cHeiGenClassic::GetNoise(float x, float y)
|
||||||
|
{
|
||||||
|
float oct1 = m_Noise.CubicNoise2D(x * m_HeightFreq1, y * m_HeightFreq1) * m_HeightAmp1;
|
||||||
|
float oct2 = m_Noise.CubicNoise2D(x * m_HeightFreq2, y * m_HeightFreq2) * m_HeightAmp2;
|
||||||
|
float oct3 = m_Noise.CubicNoise2D(x * m_HeightFreq3, y * m_HeightFreq3) * m_HeightAmp3;
|
||||||
|
|
||||||
|
float height = m_Noise.CubicNoise2D(x * 0.1f, y * 0.1f ) * 2;
|
||||||
|
|
||||||
|
float flatness = ((m_Noise.CubicNoise2D(x * 0.5f, y * 0.5f) + 1.f) * 0.5f) * 1.1f; // 0 ... 1.5
|
||||||
|
flatness *= flatness * flatness;
|
||||||
|
|
||||||
|
return (oct1 + oct2 + oct3) * flatness + height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cHeiGenClassic::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
const float zz = (float)(a_ChunkZ * cChunkDef::Width + z);
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
const float xx = (float)(a_ChunkX * cChunkDef::Width + x);
|
||||||
|
|
||||||
|
int hei = 64 + (int)(GetNoise(xx * 0.05f, zz * 0.05f) * 16);
|
||||||
|
if (hei < 10)
|
||||||
|
{
|
||||||
|
hei = 10;
|
||||||
|
}
|
||||||
|
if (hei > 250)
|
||||||
|
{
|
||||||
|
hei = 250;
|
||||||
|
}
|
||||||
|
cChunkDef::SetHeight(a_HeightMap, x , z, hei);
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
64
source/HeiGen.h
Normal file
64
source/HeiGen.h
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
|
||||||
|
// HeiGen.h
|
||||||
|
|
||||||
|
/*
|
||||||
|
Interfaces to the various height generators:
|
||||||
|
- cHeiGenFlat
|
||||||
|
- cHeiGenClassic
|
||||||
|
- cHeiGenBiomal
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cChunkGenerator.h"
|
||||||
|
#include "cNoise.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cHeiGenFlat :
|
||||||
|
public cTerrainHeightGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cHeiGenFlat(int a_Height) : m_Height(a_Height) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_Height;
|
||||||
|
|
||||||
|
// cTerrainHeightGen override:
|
||||||
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cHeiGenClassic :
|
||||||
|
public cTerrainHeightGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cHeiGenClassic(int a_Seed, float a_HeightFreq1, float a_HeightAmp1, float a_HeightFreq2, float a_HeightAmp2, float a_HeightFreq3, float a_HeightAmp3);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_Seed;
|
||||||
|
cNoise m_Noise;
|
||||||
|
float m_HeightFreq1, m_HeightAmp1;
|
||||||
|
float m_HeightFreq2, m_HeightAmp2;
|
||||||
|
float m_HeightFreq3, m_HeightAmp3;
|
||||||
|
|
||||||
|
float GetNoise(float x, float y);
|
||||||
|
|
||||||
|
// cTerrainHeightGen override:
|
||||||
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,67 @@
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "LightingThread.h"
|
#include "LightingThread.h"
|
||||||
|
#include "cChunkMap.h"
|
||||||
|
#include "cWorld.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// If more than this many chunks are in the queue, a warning is printed to the log
|
||||||
|
#define WARN_ON_QUEUE_SIZE 800
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Chunk data callback that takes the chunk data and puts them into cLightingThread's m_BlockTypes[] / m_HeightMap[]:
|
||||||
|
class cReader :
|
||||||
|
public cChunkDataCallback
|
||||||
|
{
|
||||||
|
virtual void BlockTypes(const BLOCKTYPE * a_Type) override
|
||||||
|
{
|
||||||
|
// ROW is a block of 16 Blocks, one whole row is copied at a time (hopefully the compiler will optimize that)
|
||||||
|
// C++ doesn't permit copying arrays, but arrays as a part of a struct is ok :)
|
||||||
|
typedef struct {BLOCKTYPE m_Row[16]; } ROW;
|
||||||
|
ROW * InputRows = (ROW *)a_Type;
|
||||||
|
ROW * OutputRows = (ROW *)m_BlockTypes;
|
||||||
|
int InputIdx = 0;
|
||||||
|
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
|
||||||
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
OutputRows[OutputIdx] = InputRows[InputIdx++];
|
||||||
|
OutputIdx += 3;
|
||||||
|
} // for z
|
||||||
|
// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
|
||||||
|
// We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip
|
||||||
|
OutputIdx += cChunkDef::Width * 6;
|
||||||
|
} // for y
|
||||||
|
} // BlockTypes()
|
||||||
|
|
||||||
|
|
||||||
|
virtual void HeightMap(const cChunkDef::HeightMap * a_Heightmap) override
|
||||||
|
{
|
||||||
|
typedef struct {HEIGHTTYPE m_Row[16]; } ROW;
|
||||||
|
ROW * InputRows = (ROW *)a_Heightmap;
|
||||||
|
ROW * OutputRows = (ROW *)m_HeightMap;
|
||||||
|
int InputIdx = 0;
|
||||||
|
int OutputIdx = m_ReadingChunkX + m_ReadingChunkZ * cChunkDef::Width * 3;
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
OutputRows[OutputIdx] = InputRows[InputIdx++];
|
||||||
|
OutputIdx += 3;
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int m_ReadingChunkX; // 0, 1 or 2; x-offset of the chunk we're reading from the BlockTypes start
|
||||||
|
int m_ReadingChunkZ; // 0, 1 or 2; z-offset of the chunk we're reading from the BlockTypes start
|
||||||
|
BLOCKTYPE * m_BlockTypes; // 3x3 chunks of block types, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
|
||||||
|
HEIGHTTYPE * m_HeightMap; // 3x3 chunks of height map, organized as a single XZY blob of data (instead of 3x3 XZY blobs)
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,7 +75,8 @@
|
||||||
// cLightingThread:
|
// cLightingThread:
|
||||||
|
|
||||||
cLightingThread::cLightingThread(void) :
|
cLightingThread::cLightingThread(void) :
|
||||||
super("cLightingThread")
|
super("cLightingThread"),
|
||||||
|
m_World(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,17 +93,26 @@ cLightingThread::~cLightingThread()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cLightingThread::Start(cWorld * a_World)
|
||||||
|
{
|
||||||
|
ASSERT(m_World == NULL); // Not started yet
|
||||||
|
m_World = a_World;
|
||||||
|
|
||||||
|
return super::Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cLightingThread::Stop(void)
|
void cLightingThread::Stop(void)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
for (cLightingBufferQueue::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
m_Queue.clear();
|
||||||
{
|
|
||||||
delete *itr;
|
|
||||||
} // for itr - m_Queue[]
|
|
||||||
}
|
}
|
||||||
m_ShouldTerminate = true;
|
m_ShouldTerminate = true;
|
||||||
m_Event.Set();
|
m_evtItemAdded.Set();
|
||||||
|
|
||||||
Wait();
|
Wait();
|
||||||
}
|
}
|
||||||
|
@ -50,9 +121,89 @@ void cLightingThread::Stop(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cLightingThread::QueueLighting(cWorld * a_World, int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ)
|
void cLightingThread::QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter)
|
||||||
{
|
{
|
||||||
// TODO
|
ASSERT(m_World != NULL); // Did you call Start() properly?
|
||||||
|
|
||||||
|
cChunkStay * ChunkStay = new cChunkStay(m_World);
|
||||||
|
ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
|
||||||
|
ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
|
ChunkStay->Add(a_ChunkX + 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
|
||||||
|
ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ + 1);
|
||||||
|
ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
|
ChunkStay->Add(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ - 1);
|
||||||
|
ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ + 1);
|
||||||
|
ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
|
ChunkStay->Add(a_ChunkX - 1, ZERO_CHUNK_Y, a_ChunkZ - 1);
|
||||||
|
ChunkStay->Enable();
|
||||||
|
ChunkStay->Load();
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
m_Queue.push_back(sItem(a_ChunkX, a_ChunkZ, ChunkStay, a_CallbackAfter));
|
||||||
|
if (m_Queue.size() > WARN_ON_QUEUE_SIZE)
|
||||||
|
{
|
||||||
|
LOGINFO("Lighting thread overloaded, %d items in queue", m_Queue.size());
|
||||||
|
}
|
||||||
|
m_evtItemAdded.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLightingThread::WaitForQueueEmpty(void)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
while (!m_ShouldTerminate && (!m_Queue.empty() || !m_PostponedQueue.empty()))
|
||||||
|
{
|
||||||
|
cCSUnlock Unlock(Lock);
|
||||||
|
m_evtQueueEmpty.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t cLightingThread::GetQueueLength(void)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
return m_Queue.size() + m_PostponedQueue.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLightingThread::ChunkReady(int a_ChunkX, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
// Check all the items in the m_PostponedQueue, if the chunk is their neighbor, move the item to m_Queue
|
||||||
|
|
||||||
|
bool NewlyAdded = false;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
for (sItems::iterator itr = m_PostponedQueue.begin(); itr != m_PostponedQueue.end(); )
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
(itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1) &&
|
||||||
|
(itr->x - a_ChunkX >= -1) && (itr->x - a_ChunkX <= 1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// It is a neighbor
|
||||||
|
m_Queue.push_back(*itr);
|
||||||
|
itr = m_PostponedQueue.erase(itr);
|
||||||
|
NewlyAdded = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++itr;
|
||||||
|
}
|
||||||
|
} // for itr - m_PostponedQueue[]
|
||||||
|
} // Lock(m_CS)
|
||||||
|
|
||||||
|
if (NewlyAdded)
|
||||||
|
{
|
||||||
|
m_evtItemAdded.Set(); // Notify the thread it has some work to do
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,52 +212,318 @@ void cLightingThread::QueueLighting(cWorld * a_World, int a_MinX, int a_MaxX, in
|
||||||
|
|
||||||
void cLightingThread::Execute(void)
|
void cLightingThread::Execute(void)
|
||||||
{
|
{
|
||||||
// TODO
|
while (true)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
if (m_Queue.size() == 0)
|
||||||
|
{
|
||||||
|
cCSUnlock Unlock(Lock);
|
||||||
|
m_evtItemAdded.Wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ShouldTerminate)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process one items from the queue:
|
||||||
|
sItem Item;
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
if (m_Queue.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Item = m_Queue.front();
|
||||||
|
m_Queue.pop_front();
|
||||||
|
if (m_Queue.empty())
|
||||||
|
{
|
||||||
|
m_evtQueueEmpty.Set();
|
||||||
|
}
|
||||||
|
} // CSLock(m_CS)
|
||||||
|
|
||||||
|
LightChunk(Item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cLightingThread::cLightingBuffer:
|
|
||||||
|
|
||||||
cLightingThread::cLightingBuffer::cLightingBuffer(int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ) :
|
void cLightingThread::LightChunk(cLightingThread::sItem & a_Item)
|
||||||
m_MinX(a_MinX),
|
|
||||||
m_MaxX(a_MaxX),
|
|
||||||
m_MinY(a_MinY),
|
|
||||||
m_MaxY(a_MaxY),
|
|
||||||
m_MinZ(a_MinZ),
|
|
||||||
m_MaxZ(a_MaxZ)
|
|
||||||
{
|
{
|
||||||
// TODO: initialize strides
|
cChunkDef::BlockNibbles BlockLight, SkyLight;
|
||||||
|
|
||||||
|
if (!ReadChunks(a_Item.x, a_Item.z))
|
||||||
|
{
|
||||||
|
// Neighbors not available. Re-queue in the postponed queue
|
||||||
|
cCSLock Lock(m_CS);
|
||||||
|
m_PostponedQueue.push_back(a_Item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// DEBUG: torch somewhere:
|
||||||
|
m_BlockTypes[19 + 24 * cChunkDef::Width * 3 + (m_HeightMap[24 + 24 * cChunkDef::Width * 3] / 2) * BlocksPerYLayer] = E_BLOCK_TORCH;
|
||||||
|
// m_HeightMap[24 + 24 * cChunkDef::Width * 3]++;
|
||||||
|
*/
|
||||||
|
|
||||||
|
PrepareBlockLight();
|
||||||
|
CalcLight(m_BlockLight);
|
||||||
|
|
||||||
|
PrepareSkyLight();
|
||||||
|
CalcLight(m_SkyLight);
|
||||||
|
|
||||||
|
CompressLight(m_BlockLight, BlockLight);
|
||||||
|
CompressLight(m_SkyLight, SkyLight);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// DEBUG:
|
||||||
|
{
|
||||||
|
cFile f("chunk_BlockTypes.dat", cFile::fmWrite);
|
||||||
|
if (f.IsOpen())
|
||||||
|
{
|
||||||
|
f.Write(m_BlockTypes, sizeof(m_BlockTypes));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG:
|
||||||
|
{
|
||||||
|
cFile f("Chunk_SkyLight.dat", cFile::fmWrite);
|
||||||
|
if (f.IsOpen())
|
||||||
|
{
|
||||||
|
f.Write(m_SkyLight, sizeof(m_SkyLight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG:
|
||||||
|
{
|
||||||
|
cFile f("Chunk_BlockLight.dat", cFile::fmWrite);
|
||||||
|
if (f.IsOpen())
|
||||||
|
{
|
||||||
|
f.Write(m_BlockLight, sizeof(m_BlockLight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
m_World->ChunkLighted(a_Item.x, a_Item.z, BlockLight, SkyLight);
|
||||||
|
|
||||||
|
if (a_Item.m_Callback != NULL)
|
||||||
|
{
|
||||||
|
a_Item.m_Callback->Call(a_Item.x, a_Item.z);
|
||||||
|
}
|
||||||
|
delete a_Item.m_ChunkStay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cLightingThread::cLightingBuffer::GetFromWorld(cWorld * a_World)
|
bool cLightingThread::ReadChunks(int a_ChunkX, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
// TODO: Set m_BlockData, m_SkyLight and m_BlockLight from the world's chunks
|
cReader Reader;
|
||||||
|
Reader.m_BlockTypes = m_BlockTypes;
|
||||||
|
Reader.m_HeightMap = m_HeightMap;
|
||||||
|
|
||||||
|
for (int z = 0; z < 3; z++)
|
||||||
|
{
|
||||||
|
Reader.m_ReadingChunkZ = z;
|
||||||
|
for (int x = 0; x < 3; x++)
|
||||||
|
{
|
||||||
|
Reader.m_ReadingChunkX = x;
|
||||||
|
if (!m_World->GetChunkData(a_ChunkX + x - 1, ZERO_CHUNK_Y, a_ChunkZ + z - 1, Reader))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
|
||||||
|
memset(m_BlockLight, 0, sizeof(m_BlockLight));
|
||||||
|
memset(m_SkyLight, 0, sizeof(m_SkyLight));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cLightingThread::cLightingBuffer::SetToWorld (cWorld * a_World)
|
void cLightingThread::PrepareSkyLight(void)
|
||||||
{
|
{
|
||||||
// TODO: Set world's chunks from m_BlockData, m_SkyLight and m_BlockLight
|
// Clear seeds:
|
||||||
|
memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
|
||||||
|
m_NumSeeds = 0;
|
||||||
|
|
||||||
|
// Walk every column that has all XZ neighbors
|
||||||
|
for (int z = 1; z < cChunkDef::Width * 3 - 1; z++)
|
||||||
|
{
|
||||||
|
int BaseZ = z * cChunkDef::Width * 3;
|
||||||
|
for (int x = 1; x < cChunkDef::Width * 3 - 1; x++)
|
||||||
|
{
|
||||||
|
int idx = BaseZ + x;
|
||||||
|
int Current = m_HeightMap[idx] + 1;
|
||||||
|
int Neighbor1 = m_HeightMap[idx + 1] + 1; // X + 1
|
||||||
|
int Neighbor2 = m_HeightMap[idx - 1] + 1; // X - 1
|
||||||
|
int Neighbor3 = m_HeightMap[idx + cChunkDef::Width * 3] + 1; // Z + 1
|
||||||
|
int Neighbor4 = m_HeightMap[idx - cChunkDef::Width * 3] + 1; // Z - 1
|
||||||
|
int MaxNeighbor = MAX(MAX(Neighbor1, Neighbor2), MAX(Neighbor3, Neighbor4)); // Maximum of the four neighbors
|
||||||
|
|
||||||
|
// TODO: The following cycle can be transofrmed into two separate cycles with no condition inside them, one lighting and the other seeding
|
||||||
|
for (int y = Current, Index = idx + y * BlocksPerYLayer; y < cChunkDef::Height; y++, Index += BlocksPerYLayer)
|
||||||
|
{
|
||||||
|
// If all the XZ neighbors are lower than y, abort for the current column (but light up the rest of it):
|
||||||
|
if (y >= MaxNeighbor)
|
||||||
|
{
|
||||||
|
for (int y2 = y; y2 < cChunkDef::Height; y2++, Index += BlocksPerYLayer)
|
||||||
|
{
|
||||||
|
m_SkyLight[Index] = 15;
|
||||||
|
} // for y2
|
||||||
|
break; // for y
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add current block as a seed:
|
||||||
|
m_IsSeed1[Index] = true;
|
||||||
|
m_SeedIdx1[m_NumSeeds++] = Index;
|
||||||
|
|
||||||
|
// Light it up to full skylight:
|
||||||
|
m_SkyLight[Index] = 15;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cLightingThread::cLightingBuffer::Process(void)
|
void cLightingThread::PrepareBlockLight(void)
|
||||||
{
|
{
|
||||||
// TODO: Does the actual lighting on this buffer
|
// Clear seeds:
|
||||||
|
memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
|
||||||
|
m_NumSeeds = 0;
|
||||||
|
|
||||||
|
// Walk every column that has all XZ neighbors, make a seed for each light-emitting block:
|
||||||
|
for (int z = 1; z < cChunkDef::Width * 3 - 1; z++)
|
||||||
|
{
|
||||||
|
int BaseZ = z * cChunkDef::Width * 3;
|
||||||
|
for (int x = 1; x < cChunkDef::Width * 3 - 1; x++)
|
||||||
|
{
|
||||||
|
int idx = BaseZ + x;
|
||||||
|
for (int y = m_HeightMap[idx], Index = idx + y * BlocksPerYLayer; y >= 0; y--, Index -= BlocksPerYLayer)
|
||||||
|
{
|
||||||
|
if (g_BlockLightValue[m_BlockTypes[Index]] == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add current block as a seed:
|
||||||
|
m_IsSeed1[Index] = true;
|
||||||
|
m_SeedIdx1[m_NumSeeds++] = Index;
|
||||||
|
|
||||||
|
// Light it up:
|
||||||
|
m_BlockLight[Index] = g_BlockLightValue[m_BlockTypes[Index]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLightingThread::CalcLight(NIBBLETYPE * a_Light)
|
||||||
|
{
|
||||||
|
int NumSeeds2 = 0;
|
||||||
|
while (m_NumSeeds > 0)
|
||||||
|
{
|
||||||
|
// Buffer 1 -> buffer 2
|
||||||
|
memset(m_IsSeed2, 0, sizeof(m_IsSeed2));
|
||||||
|
NumSeeds2 = 0;
|
||||||
|
CalcLightStep(a_Light, m_NumSeeds, m_IsSeed1, m_SeedIdx1, NumSeeds2, m_IsSeed2, m_SeedIdx2);
|
||||||
|
if (NumSeeds2 == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer 2 -> buffer 1
|
||||||
|
memset(m_IsSeed1, 0, sizeof(m_IsSeed1));
|
||||||
|
m_NumSeeds = 0;
|
||||||
|
CalcLightStep(a_Light, NumSeeds2, m_IsSeed2, m_SeedIdx2, m_NumSeeds, m_IsSeed1, m_SeedIdx1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLightingThread::CalcLightStep(
|
||||||
|
NIBBLETYPE * a_Light,
|
||||||
|
int a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn,
|
||||||
|
int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int NumSeedsOut = 0;
|
||||||
|
for (int i = 0; i < a_NumSeedsIn; i++)
|
||||||
|
{
|
||||||
|
int SeedIdx = a_SeedIdxIn[i];
|
||||||
|
int SeedX = SeedIdx % (cChunkDef::Width * 3);
|
||||||
|
int SeedZ = (SeedIdx / (cChunkDef::Width * 3)) % (cChunkDef::Width * 3);
|
||||||
|
int SeedY = SeedIdx / BlocksPerYLayer;
|
||||||
|
|
||||||
|
// Propagate seed:
|
||||||
|
if (SeedX < cChunkDef::Width * 3)
|
||||||
|
{
|
||||||
|
PropagateLight(a_Light, SeedIdx, SeedIdx + 1, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
|
||||||
|
}
|
||||||
|
if (SeedX > 0)
|
||||||
|
{
|
||||||
|
PropagateLight(a_Light, SeedIdx, SeedIdx - 1, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
|
||||||
|
}
|
||||||
|
if (SeedZ < cChunkDef::Width * 3)
|
||||||
|
{
|
||||||
|
PropagateLight(a_Light, SeedIdx, SeedIdx + cChunkDef::Width * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
|
||||||
|
}
|
||||||
|
if (SeedZ > 0)
|
||||||
|
{
|
||||||
|
PropagateLight(a_Light, SeedIdx, SeedIdx - cChunkDef::Width * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
|
||||||
|
}
|
||||||
|
if (SeedY < cChunkDef::Height)
|
||||||
|
{
|
||||||
|
PropagateLight(a_Light, SeedIdx, SeedIdx + cChunkDef::Width * cChunkDef::Width * 3 * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
|
||||||
|
}
|
||||||
|
if (SeedY > 0)
|
||||||
|
{
|
||||||
|
PropagateLight(a_Light, SeedIdx, SeedIdx - cChunkDef::Width * cChunkDef::Width * 3 * 3, NumSeedsOut, a_IsSeedOut, a_SeedIdxOut);
|
||||||
|
}
|
||||||
|
} // for i - a_SeedIdxIn[]
|
||||||
|
a_NumSeedsOut = NumSeedsOut;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cLightingThread::CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight)
|
||||||
|
{
|
||||||
|
int InIdx = cChunkDef::Width * 49; // Index to the first nibble of the middle chunk in the a_LightArray
|
||||||
|
int OutIdx = 0;
|
||||||
|
for (int y = 0; y < cChunkDef::Height; y++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x += 2)
|
||||||
|
{
|
||||||
|
a_ChunkLight[OutIdx++] = (a_LightArray[InIdx + 1] << 4) | a_LightArray[InIdx];
|
||||||
|
InIdx += 2;
|
||||||
|
}
|
||||||
|
InIdx += cChunkDef::Width * 2;
|
||||||
|
}
|
||||||
|
// Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows
|
||||||
|
// We've already walked cChunkDef::Width * 3 in the "for z" cycle, that makes cChunkDef::Width * 6 rows left to skip
|
||||||
|
InIdx += cChunkDef::Width * cChunkDef::Width * 6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,22 +2,48 @@
|
||||||
// LightingThread.h
|
// LightingThread.h
|
||||||
|
|
||||||
// Interfaces to the cLightingThread class representing the thread that processes requests for lighting
|
// Interfaces to the cLightingThread class representing the thread that processes requests for lighting
|
||||||
// Note that the world generators need direct access to the lighting methods so that they can light the generated chunk
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lighting is done on whole chunks. For each chunk to be lighted, the whole 3x3 chunk area around it is read,
|
||||||
|
then it is processed, so that the middle chunk area has valid lighting, and the lighting is copied into the ChunkMap.
|
||||||
|
Lighting is calculated in full char arrays instead of nibbles, so that accessing the arrays is fast.
|
||||||
|
Lighting is calculated in a flood-fill fashion:
|
||||||
|
1. Generate seeds from where the light spreads (full skylight / light-emitting blocks)
|
||||||
|
2. For each seed:
|
||||||
|
- Spread the light 1 block in each of the 6 cardinal directions, if the blocktype allows
|
||||||
|
- If the recipient block has had lower lighting value than that being spread, make it a new seed
|
||||||
|
3. Repeat step 2, until there are no more seeds
|
||||||
|
The seeds need two fast operations:
|
||||||
|
- Check if a block at [x, y, z] is already a seed
|
||||||
|
- Get the next seed in the row
|
||||||
|
For that reason it is stored in two arrays, one stores a bool saying a seed is in that position,
|
||||||
|
the other is an array of seed coords, encoded as a single int.
|
||||||
|
Step 2 needs two separate storages for old seeds and new seeds, so there are two actual storages for that purpose,
|
||||||
|
their content is swapped after each full step-2-cycle.
|
||||||
|
|
||||||
|
The thread has two queues of chunks that are to be lighted.
|
||||||
|
The first queue, m_Queue, is the only one that is publicly visible, chunks get queued there by external requests.
|
||||||
|
The second one, m_PostponedQueue, is for chunks that have been taken out of m_Queue and didn't have neighbors ready.
|
||||||
|
Chunks from m_PostponedQueue are moved back into m_Queue when their neighbors get valid, using the ChunkReady callback.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cIsThread.h"
|
#include "cIsThread.h"
|
||||||
|
#include "ChunkDef.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fwd:
|
// fwd: "cWorld.h"
|
||||||
class cWorld;
|
class cWorld;
|
||||||
|
|
||||||
|
// fwd: "cChunkMap.h"
|
||||||
|
class cChunkStay;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,53 +54,121 @@ class cLightingThread :
|
||||||
typedef cIsThread super;
|
typedef cIsThread super;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
class cLightingBuffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cLightingBuffer(int m_MinX, int m_MaxX, int m_MinY, int m_MaxY, int m_MinZ, int m_MaxZ);
|
|
||||||
|
|
||||||
/// Copies the world's existing chunks into m_BlockData, m_Skylight and m_BlockLight
|
|
||||||
void GetFromWorld(cWorld * a_World);
|
|
||||||
void SetToWorld (cWorld * a_World);
|
|
||||||
|
|
||||||
void Process(void); // Does the actual lighting on this buffer
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// Block coords:
|
|
||||||
int m_MinX, m_MaxX;
|
|
||||||
int m_MinY, m_MaxY;
|
|
||||||
int m_MinZ, m_MaxZ;
|
|
||||||
|
|
||||||
int m_StrideX; // = OffsetOfBlock(x, y, z) - OffsetOfBlock(x + 1, y, z)
|
|
||||||
int m_StrideZ; // = OffsetOfBlock(x, y, z) - OffsetOfBlock(x, y, z + 1)
|
|
||||||
|
|
||||||
// These buffers actually store 1 block in each direction more than is specified in the coords
|
|
||||||
// This way we can throw out a lot of conditions inside the processing cycles
|
|
||||||
// And it allows us to light a chunk with regard to its surrounding chunks without much work
|
|
||||||
// (So if m_MinX is 16 and m_MaxX is 32, the buffers actually contain data for X in range from 15 to 33 (18 items)
|
|
||||||
char * m_BlockData;
|
|
||||||
char * m_SkyLight;
|
|
||||||
char * m_BlockLight;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
cLightingThread(void);
|
cLightingThread(void);
|
||||||
~cLightingThread();
|
~cLightingThread();
|
||||||
|
|
||||||
|
bool Start(cWorld * a_World);
|
||||||
|
|
||||||
void Stop(void);
|
void Stop(void);
|
||||||
|
|
||||||
void QueueLighting(cWorld * a_World, int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ); // queues the request
|
/// Queues the entire chunk for lighting
|
||||||
|
void QueueChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_CallbackAfter = NULL);
|
||||||
|
|
||||||
|
/// Blocks until the queue is empty or the thread is terminated
|
||||||
|
void WaitForQueueEmpty(void);
|
||||||
|
|
||||||
|
size_t GetQueueLength(void);
|
||||||
|
|
||||||
|
/// Called from cWorld when a chunk gets valid. Chunks in m_PostponedQueue may need moving into m_Queue
|
||||||
|
void ChunkReady(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef std::list<cLightingBuffer *> cLightingBufferQueue;
|
struct sItem
|
||||||
|
{
|
||||||
|
int x, z;
|
||||||
|
cChunkStay * m_ChunkStay;
|
||||||
|
cChunkCoordCallback * m_Callback;
|
||||||
|
|
||||||
|
sItem(void) {} // empty default constructor needed
|
||||||
|
sItem(int a_X, int a_Z, cChunkStay * a_ChunkStay, cChunkCoordCallback * a_Callback) :
|
||||||
|
x(a_X),
|
||||||
|
z(a_Z),
|
||||||
|
m_ChunkStay(a_ChunkStay),
|
||||||
|
m_Callback(a_Callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
} ;
|
||||||
|
|
||||||
cCriticalSection m_CS;
|
typedef std::list<sItem> sItems;
|
||||||
cLightingBufferQueue m_Queue;
|
|
||||||
cEvent m_Event; // Set when queue is appended or to stop the thread
|
|
||||||
|
|
||||||
|
cWorld * m_World;
|
||||||
|
cCriticalSection m_CS;
|
||||||
|
sItems m_Queue;
|
||||||
|
sItems m_PostponedQueue; // Chunks that have been postponed due to missing neighbors
|
||||||
|
cEvent m_evtItemAdded; // Set when queue is appended, or to stop the thread
|
||||||
|
cEvent m_evtQueueEmpty; // Set when the queue gets empty
|
||||||
|
|
||||||
|
// Buffers for the 3x3 chunk data
|
||||||
|
// These buffers alone are 1.7 MiB in size, therefore they cannot be located on the stack safely - some architectures may have only 1 MiB for stack, or even less
|
||||||
|
// Placing the buffers into the object means that this object can light chunks only in one thread!
|
||||||
|
// The blobs are XZY organized as a whole, instead of 3x3 XZY-organized subarrays ->
|
||||||
|
// -> This means data has to be scatterred when reading and gathered when writing!
|
||||||
|
static const int BlocksPerYLayer = cChunkDef::Width * cChunkDef::Width * 3 * 3;
|
||||||
|
BLOCKTYPE m_BlockTypes[BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
NIBBLETYPE m_BlockLight[BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
NIBBLETYPE m_SkyLight [BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
HEIGHTTYPE m_HeightMap [BlocksPerYLayer];
|
||||||
|
|
||||||
|
// Seed management (5.7 MiB)
|
||||||
|
// Two buffers, in each calc step one is set as input and the other as output, then in the next step they're swapped
|
||||||
|
// Each seed is represented twice in this structure - both as a "list" and as a "position".
|
||||||
|
// "list" allows fast traversal from seed to seed
|
||||||
|
// "position" allows fast checking if a coord is already a seed
|
||||||
|
unsigned char m_IsSeed1 [BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
unsigned int m_SeedIdx1[BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
unsigned char m_IsSeed2 [BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
unsigned int m_SeedIdx2[BlocksPerYLayer * cChunkDef::Height];
|
||||||
|
int m_NumSeeds;
|
||||||
|
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
|
|
||||||
|
/// Lights the entire chunk. If neighbor chunks don't exist, touches them and re-queues the chunk
|
||||||
|
void LightChunk(sItem & a_Item);
|
||||||
|
|
||||||
|
/// Prepares m_BlockTypes and m_HeightMap data; returns false if any of the chunks fail. Zeroes out the light arrays
|
||||||
|
bool ReadChunks(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
|
/// Uses m_HeightMap to initialize the m_SkyLight[] data; fills in seeds for the skylight
|
||||||
|
void PrepareSkyLight(void);
|
||||||
|
|
||||||
|
/// Uses m_BlockTypes to initialize the m_BlockLight[] data; fills in seeds for the blocklight
|
||||||
|
void PrepareBlockLight(void);
|
||||||
|
|
||||||
|
/// Calculates light in the light array specified, using stored seeds
|
||||||
|
void CalcLight(NIBBLETYPE * a_Light);
|
||||||
|
|
||||||
|
/// Does one step in the light calculation - one seed propagation and seed recalculation
|
||||||
|
void CalcLightStep(
|
||||||
|
NIBBLETYPE * a_Light,
|
||||||
|
int a_NumSeedsIn, unsigned char * a_IsSeedIn, unsigned int * a_SeedIdxIn,
|
||||||
|
int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Compresses from 1-byte-per-block into 2-bytes-per-block:
|
||||||
|
void CompressLight(NIBBLETYPE * a_LightArray, NIBBLETYPE * a_ChunkLight);
|
||||||
|
|
||||||
|
inline void PropagateLight(
|
||||||
|
NIBBLETYPE * a_Light,
|
||||||
|
int a_SrcIdx, int a_DstIdx,
|
||||||
|
int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]])
|
||||||
|
{
|
||||||
|
// The dest block already has enough light than we're offerring
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_Light[a_DstIdx] = a_Light[a_SrcIdx] - g_BlockSpreadLightFalloff[m_BlockTypes[a_DstIdx]];
|
||||||
|
if (!a_IsSeedOut[a_DstIdx])
|
||||||
|
{
|
||||||
|
a_IsSeedOut[a_DstIdx] = true;
|
||||||
|
a_SeedIdxOut[a_NumSeedsOut++] = a_DstIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
899
source/NBT.cpp
899
source/NBT.cpp
|
@ -1,899 +0,0 @@
|
||||||
|
|
||||||
// NBT.cpp
|
|
||||||
|
|
||||||
// Implements the classes used for NBT representation, parsing and serializing
|
|
||||||
|
|
||||||
/*
|
|
||||||
This file has been retrofitted from a different project of mine (_Xoft(o)) and melded here, so it is not strictyl MCS-styled
|
|
||||||
Also the project used error codes, which MCS doesn't need, so they were declared locally only.
|
|
||||||
The code is not strictly safe, it could leak pointers when exceptions are thrown. It could use a RAII redesign.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Globals.h"
|
|
||||||
#include "NBT.h"
|
|
||||||
#include "Endianness.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Error codes
|
|
||||||
// Unused by MCS
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
ERROR_PRIVATE_BASE = 0x00040000,
|
|
||||||
|
|
||||||
ERROR_PRIVATE_NBTPARSER_BADTYPE, // The parsed type is not recognized
|
|
||||||
ERROR_PRIVATE_NBTPARSER_INVALIDLENGTH, // The parsed name has an invalid length (negative-length string etc.)
|
|
||||||
ERROR_PRIVATE_NBTPARSER_UNEXPECTEDTAG, // The parser has encountered a tag that should not be at such a point
|
|
||||||
ERROR_PRIVATE_NBTPARSER_TOOSHORT, // The parser was invoked on data that is too short
|
|
||||||
|
|
||||||
ERROR_PRIVATE_NBT_UNINITIALIZEDLIST, // NBTList needs its ChildType set before adding items to it
|
|
||||||
ERROR_PRIVATE_NBT_TYPEMISMATCH, // NBTList must have all of its children of the same type
|
|
||||||
ERROR_PRIVATE_NBT_UNEXPECTEDTAG, // NBTList and NBTCompound cannot contain a TAG_End
|
|
||||||
ERROR_PRIVATE_NBT_BADTYPE, // NBTList's children type cannot be set to such a value
|
|
||||||
ERROR_PRIVATE_NBT_LISTNOTEMPTY, // NBTList must be empty to allow setting children type
|
|
||||||
ERROR_PRIVATE_NBT_INDEXOUTOFRANGE, // Requesting an item with invalid index from a list or a compound
|
|
||||||
|
|
||||||
ERROR_PRIVATE_UNKNOWN, // Unknown error
|
|
||||||
} ;
|
|
||||||
|
|
||||||
#ifndef ERROR_SUCCESS
|
|
||||||
// This constant is actually #defined in the WinAPI; it cannot be put into the above enum, but needs to be #defined (for *nix)
|
|
||||||
#define ERROR_SUCCESS 0
|
|
||||||
#endif // ERROR_SUCCCESS
|
|
||||||
|
|
||||||
#ifndef ERROR_NOT_ENOUGH_MEMORY
|
|
||||||
// This constant is actually #defined in the WinAPI; it cannot be put into the above enum, but needs to be #defined (for *nix)
|
|
||||||
#define ERROR_NOT_ENOUGH_MEMORY 8
|
|
||||||
#endif // ERROR_NOT_ENOUGH_MEMORY
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define RETURN_INT_IF_FAILED(X) {int r = X; if (r != ERROR_SUCCESS) return r; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cNBTTag:
|
|
||||||
|
|
||||||
cNBTTag * cNBTTag::CreateTag(cNBTTag * a_Parent, eTagType a_Type, const AString & a_Name)
|
|
||||||
{
|
|
||||||
// Creates a new instance of a tag specified by a_Type, uses the correct class
|
|
||||||
switch (a_Type)
|
|
||||||
{
|
|
||||||
case TAG_Byte: return new cNBTByte (a_Parent, a_Name);
|
|
||||||
case TAG_Short: return new cNBTShort (a_Parent, a_Name);
|
|
||||||
case TAG_Int: return new cNBTInt (a_Parent, a_Name);
|
|
||||||
case TAG_Long: return new cNBTLong (a_Parent, a_Name);
|
|
||||||
case TAG_Float: return new cNBTFloat (a_Parent, a_Name);
|
|
||||||
case TAG_Double: return new cNBTDouble (a_Parent, a_Name);
|
|
||||||
case TAG_ByteArray: return new cNBTByteArray(a_Parent, a_Name);
|
|
||||||
case TAG_String: return new cNBTString (a_Parent, a_Name);
|
|
||||||
case TAG_List: return new cNBTList (a_Parent, a_Name, TAG_End);
|
|
||||||
case TAG_Compound: return new cNBTCompound (a_Parent, a_Name);
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
ASSERT(!"Unknown TAG type requested");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const cNBTTag * cNBTTag::FindChildByPath(const AString & iPath) const
|
|
||||||
{
|
|
||||||
size_t PrevIdx = 0;
|
|
||||||
size_t idx = iPath.find('\\');
|
|
||||||
const cNBTTag * res = this;
|
|
||||||
while ((res != NULL) && (idx != AString::npos))
|
|
||||||
{
|
|
||||||
res = res->FindChildByName(AString(iPath, PrevIdx, idx - PrevIdx));
|
|
||||||
PrevIdx = idx + 1;
|
|
||||||
idx = iPath.find('\\', PrevIdx);
|
|
||||||
}
|
|
||||||
if (res != NULL)
|
|
||||||
{
|
|
||||||
res = res->FindChildByName(AString(iPath, PrevIdx));
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cNBTList:
|
|
||||||
|
|
||||||
void cNBTList::Clear(void)
|
|
||||||
{
|
|
||||||
for (cNBTTags::iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
delete *itr;
|
|
||||||
}
|
|
||||||
m_Children.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTList::Add(cNBTTag * iTag)
|
|
||||||
{
|
|
||||||
// Catch usage errors while debugging:
|
|
||||||
ASSERT(m_ChildrenType != TAG_End); // Didn't call SetChildrenType()
|
|
||||||
ASSERT(iTag->GetType() == m_ChildrenType); // Child of different type
|
|
||||||
|
|
||||||
// Catch errors while running:
|
|
||||||
if (m_ChildrenType == TAG_End)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBT_UNINITIALIZEDLIST;
|
|
||||||
}
|
|
||||||
if (iTag->GetType() != m_ChildrenType)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBT_TYPEMISMATCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Children.push_back(iTag);
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTList::SetChildrenType(cNBTTag::eTagType a_Type)
|
|
||||||
{
|
|
||||||
// Catch usage errors while debugging:
|
|
||||||
ASSERT(a_Type != TAG_End); // Invalid, though not specifically in the NBT spec
|
|
||||||
ASSERT(m_Children.size() == 0); // Can change only when empty
|
|
||||||
|
|
||||||
// Catch runtime errors:
|
|
||||||
if (a_Type == TAG_End)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBT_BADTYPE;
|
|
||||||
}
|
|
||||||
if (m_Children.size() != 0)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBT_LISTNOTEMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ChildrenType = a_Type;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cNBTTag * cNBTList::GetChildByIdx(size_t iIndex)
|
|
||||||
{
|
|
||||||
// Catch usage errors while debugging:
|
|
||||||
ASSERT((iIndex >= 0) && (iIndex < m_Children.size()));
|
|
||||||
|
|
||||||
// Catch runtime errors:
|
|
||||||
if ((iIndex < 0) || (iIndex >= m_Children.size()))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Children[iIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cNBTTag * cNBTList::FindChildByName(const AString & a_Name) const
|
|
||||||
{
|
|
||||||
for (cNBTTags::const_iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
if ((*itr)->GetName() == a_Name)
|
|
||||||
{
|
|
||||||
return *itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cNBTCompound:
|
|
||||||
|
|
||||||
void cNBTCompound::Clear(void)
|
|
||||||
{
|
|
||||||
for (cNBTTags::iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
delete *itr;
|
|
||||||
}
|
|
||||||
m_Children.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTCompound::Add(cNBTTag * iTag)
|
|
||||||
{
|
|
||||||
// Catch usage errors while debugging:
|
|
||||||
ASSERT(iTag->GetType() != TAG_End);
|
|
||||||
|
|
||||||
// Catch runtime errors:
|
|
||||||
if (iTag->GetType() == TAG_End)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBT_UNEXPECTEDTAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Children.push_back(iTag);
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cNBTTag * cNBTCompound::GetChildByIdx(size_t iIndex)
|
|
||||||
{
|
|
||||||
// Catch usage errors while debugging:
|
|
||||||
ASSERT((iIndex >= 0) && (iIndex < m_Children.size()));
|
|
||||||
|
|
||||||
// Catch runtime errors:
|
|
||||||
if ((iIndex < 0) || (iIndex >= m_Children.size()))
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_Children[iIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cNBTTag * cNBTCompound::FindChildByName(const AString & a_Name) const
|
|
||||||
{
|
|
||||||
for (cNBTTags::const_iterator itr = m_Children.begin(); itr != m_Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
if ((*itr)->GetName() == a_Name)
|
|
||||||
{
|
|
||||||
return *itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cNBTParser:
|
|
||||||
|
|
||||||
int cNBTParser::ReadByte(const char ** a_Data, int * a_Length, char & a_Value)
|
|
||||||
{
|
|
||||||
if (*a_Length < 1)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_Value = **a_Data;
|
|
||||||
*a_Data += 1;
|
|
||||||
*a_Length -= 1;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadInt16(const char ** a_Data, int * a_Length, Int16 & a_Value)
|
|
||||||
{
|
|
||||||
if (*a_Length < 2)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_Value = ntohs(*((Int16 *)*a_Data));
|
|
||||||
*a_Data += 2;
|
|
||||||
*a_Length -= 2;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadInt32(const char ** a_Data, int * a_Length, Int32 & a_Value)
|
|
||||||
{
|
|
||||||
if (*a_Length < 4)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_Value = ntohl(*((Int32 *)*a_Data));
|
|
||||||
*a_Data += 4;
|
|
||||||
*a_Length -= 4;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadInt64(const char ** a_Data, int * a_Length, Int64 & a_Value)
|
|
||||||
{
|
|
||||||
if (*a_Length < 8)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_Value = NetworkToHostLong8(*a_Data);
|
|
||||||
*a_Data += 8;
|
|
||||||
*a_Length -= 8;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadFloat(const char ** a_Data, int * a_Length, float & a_Value)
|
|
||||||
{
|
|
||||||
if (*a_Length < 4)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
// Read as a 32-bit integer, converting endianness, then reinterpret as float:
|
|
||||||
Int32 tmp = ntohl(*((Int32 *)*a_Data));
|
|
||||||
a_Value = *((float *)&tmp);
|
|
||||||
*a_Data += 4;
|
|
||||||
*a_Length -= 4;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadDouble(const char ** a_Data, int * a_Length, double & a_Value)
|
|
||||||
{
|
|
||||||
if (*a_Length < 8)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_Value = NetworkToHostDouble8(*a_Data);
|
|
||||||
*a_Data += 8;
|
|
||||||
*a_Length -= 8;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadByteArray(const char ** a_Data, int * a_Length, AString & a_String)
|
|
||||||
{
|
|
||||||
// Reads the short-counted string, adjusts a_Data and a_Length accordingly
|
|
||||||
Int32 Len;
|
|
||||||
RETURN_INT_IF_FAILED(ReadInt32(a_Data, a_Length, Len));
|
|
||||||
if (Len < 0)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_INVALIDLENGTH;
|
|
||||||
}
|
|
||||||
if (*a_Length < Len)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_String.assign(*a_Data, Len);
|
|
||||||
*a_Data += Len;
|
|
||||||
*a_Length -= Len;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadString(const char ** a_Data, int * a_Length, AString & a_String)
|
|
||||||
{
|
|
||||||
// Reads the short-counted string, adjusts a_Data and a_Length accordingly
|
|
||||||
if (*a_Length < 2)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
Int16 val = *((Int16 *)*a_Data);
|
|
||||||
Int16 Len = ntohs(val);
|
|
||||||
if (Len < 0)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_INVALIDLENGTH;
|
|
||||||
}
|
|
||||||
*a_Data += 2;
|
|
||||||
*a_Length -= 2;
|
|
||||||
if (*a_Length < Len)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
a_String.assign(*a_Data, Len);
|
|
||||||
*a_Data += Len;
|
|
||||||
*a_Length -= Len;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadList(const char ** a_Data, int * a_Length, cNBTList * a_List)
|
|
||||||
{
|
|
||||||
// Reads a_List's contents from a_Data; up to a_Length bytes may be used; adjusts a_Data and a_Length for after the list
|
|
||||||
Int32 ItemCount;
|
|
||||||
RETURN_INT_IF_FAILED(ReadInt32(a_Data, a_Length, ItemCount));
|
|
||||||
for (Int32 i = 0; i < ItemCount; i++)
|
|
||||||
{
|
|
||||||
cNBTTag * child = NULL;
|
|
||||||
RETURN_INT_IF_FAILED(ReadTag(a_Data, a_Length, a_List->GetChildrenType(), "", a_List, &child));
|
|
||||||
if (child == NULL)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_UNKNOWN;
|
|
||||||
}
|
|
||||||
RETURN_INT_IF_FAILED(a_List->Add(child));
|
|
||||||
} // for i - Items[]
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadCompound(const char ** a_Data, int * a_Length, cNBTCompound * a_Compound)
|
|
||||||
{
|
|
||||||
// Reads a_Compound's contents from a_Data; up to a_Length bytes may be used; adjusts a_Data and a_Length for after the compound
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
char TagType = **a_Data;
|
|
||||||
*a_Data += 1;
|
|
||||||
*a_Length -= 1;
|
|
||||||
if (TagType == cNBTTag::TAG_End)
|
|
||||||
{
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
AString Name;
|
|
||||||
RETURN_INT_IF_FAILED(ReadString(a_Data, a_Length, Name));
|
|
||||||
cNBTTag * child = NULL;
|
|
||||||
RETURN_INT_IF_FAILED(ReadTag(a_Data, a_Length, (cNBTTag::eTagType)TagType, Name, a_Compound, &child));
|
|
||||||
if (child == NULL)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_UNKNOWN;
|
|
||||||
}
|
|
||||||
RETURN_INT_IF_FAILED(a_Compound->Add(child));
|
|
||||||
} // while (true)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cNBTParser::ReadIntArray(const char ** a_Data, int * a_Length, cNBTIntArray * a_Array)
|
|
||||||
{
|
|
||||||
if (*a_Length < 4)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
int Count = ntohl(*((int *)*a_Data));
|
|
||||||
*a_Data += 4;
|
|
||||||
*a_Length -= 4;
|
|
||||||
if (*a_Length < 4 * Count)
|
|
||||||
{
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_TOOSHORT;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < Count; i++)
|
|
||||||
{
|
|
||||||
int Value = ntohl(*((int *)*a_Data));
|
|
||||||
a_Array->Add(Value);
|
|
||||||
*a_Data += 4;
|
|
||||||
}
|
|
||||||
*a_Length -= 4 * Count;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define CASE_SIMPLE_TAG(TAGTYPE,CTYPE,FUNC) \
|
|
||||||
case cNBTTag::TAG_##TAGTYPE: \
|
|
||||||
{ \
|
|
||||||
CTYPE val; \
|
|
||||||
RETURN_INT_IF_FAILED(Read##FUNC(a_Data, a_Length, val)); \
|
|
||||||
*a_Tag = new cNBT##TAGTYPE(a_Parent, a_Name, val); \
|
|
||||||
if (*a_Tag == NULL) \
|
|
||||||
{ \
|
|
||||||
return ERROR_NOT_ENOUGH_MEMORY; \
|
|
||||||
} \
|
|
||||||
return ERROR_SUCCESS;\
|
|
||||||
}
|
|
||||||
|
|
||||||
int cNBTParser::ReadTag(const char ** a_Data, int * a_Length, cNBTTag::eTagType a_Type, const AString & a_Name, cNBTTag * a_Parent, cNBTTag ** a_Tag)
|
|
||||||
{
|
|
||||||
switch (a_Type)
|
|
||||||
{
|
|
||||||
CASE_SIMPLE_TAG(Byte, char, Byte)
|
|
||||||
CASE_SIMPLE_TAG(Short, Int16, Int16)
|
|
||||||
CASE_SIMPLE_TAG(Int, Int32, Int32)
|
|
||||||
CASE_SIMPLE_TAG(Long, Int64, Int64)
|
|
||||||
CASE_SIMPLE_TAG(Float, float, Float)
|
|
||||||
CASE_SIMPLE_TAG(Double, double, Double)
|
|
||||||
CASE_SIMPLE_TAG(ByteArray, AString, ByteArray)
|
|
||||||
CASE_SIMPLE_TAG(String, AString, String)
|
|
||||||
|
|
||||||
case cNBTTag::TAG_List:
|
|
||||||
{
|
|
||||||
char ItemType;
|
|
||||||
RETURN_INT_IF_FAILED(ReadByte (a_Data, a_Length, ItemType));
|
|
||||||
cNBTList * List = new cNBTList(a_Parent, a_Name, (cNBTTag::eTagType)ItemType);
|
|
||||||
if (List == NULL)
|
|
||||||
{
|
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
}
|
|
||||||
RETURN_INT_IF_FAILED(ReadList(a_Data, a_Length, List));
|
|
||||||
*a_Tag = List;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_Compound:
|
|
||||||
{
|
|
||||||
cNBTCompound * Compound = new cNBTCompound(a_Parent, a_Name);
|
|
||||||
if (Compound == NULL)
|
|
||||||
{
|
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
}
|
|
||||||
RETURN_INT_IF_FAILED(ReadCompound(a_Data, a_Length, Compound));
|
|
||||||
*a_Tag = Compound;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_IntArray:
|
|
||||||
{
|
|
||||||
cNBTIntArray * Array = new cNBTIntArray(a_Parent, a_Name);
|
|
||||||
if (Array == NULL)
|
|
||||||
{
|
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
|
||||||
}
|
|
||||||
RETURN_INT_IF_FAILED(ReadIntArray(a_Data, a_Length, Array));
|
|
||||||
*a_Tag = Array;
|
|
||||||
return ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
#if (defined(_DEBUG) && defined(_WIN32))
|
|
||||||
OutputDebugString("Unhandled NBT tag type\n");
|
|
||||||
cNBTTag * Parent = a_Parent, * Cur = a_Parent;
|
|
||||||
while (Parent != NULL)
|
|
||||||
{
|
|
||||||
OutputDebugString("Parent:\n");
|
|
||||||
Cur = Parent;
|
|
||||||
Parent = Parent->GetParent();
|
|
||||||
DumpTree(Cur);
|
|
||||||
}
|
|
||||||
OutputDebugString("Done\n");
|
|
||||||
#endif // _DEBUG
|
|
||||||
ASSERT(!"Unhandled NBT tag type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // switch (iType)
|
|
||||||
|
|
||||||
return ERROR_PRIVATE_NBTPARSER_BADTYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CASE_SIMPLE_TAG
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cNBTTree * cNBTParser::Parse(const char * a_Data, int a_Length)
|
|
||||||
{
|
|
||||||
// Creates a NBT from a_Data
|
|
||||||
if (a_Length < 3)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (a_Data[0] != cNBTTag::TAG_Compound)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
a_Data++;
|
|
||||||
a_Length--;
|
|
||||||
AString Name;
|
|
||||||
if (ReadString(&a_Data, &a_Length, Name) != 0)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
std::auto_ptr<cNBTCompound> Root(new cNBTCompound(NULL, Name));
|
|
||||||
if (Root.get() == NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (ReadCompound(&a_Data, &a_Length, Root.get()) == 0)
|
|
||||||
{
|
|
||||||
return Root.release();
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cNBTSerializer:
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteByte(AString & a_Out, const char a_Value)
|
|
||||||
{
|
|
||||||
a_Out.push_back(a_Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteInt16(AString & a_Out, const Int16 a_Value)
|
|
||||||
{
|
|
||||||
Int16 Val = htons(a_Value);
|
|
||||||
a_Out.append((char *)&Val, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteInt32(AString & a_Out, const Int32 a_Value)
|
|
||||||
{
|
|
||||||
Int32 Val = htonl(a_Value);
|
|
||||||
a_Out.append((char *)&Val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteInt64(AString & a_Out, const Int64 a_Value)
|
|
||||||
{
|
|
||||||
Int64 Val = HostToNetwork8(&a_Value);
|
|
||||||
a_Out.append((char *)&Val, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteFloat(AString & a_Out, const float a_Value)
|
|
||||||
{
|
|
||||||
Int32 Val = htonl(*((u_long *)&a_Value));
|
|
||||||
a_Out.append((char *)&Val, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteDouble(AString & a_Out, const double a_Value)
|
|
||||||
{
|
|
||||||
Int64 Val = HostToNetwork8(&a_Value);
|
|
||||||
a_Out.append((char *)&Val, 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteByteArray(AString & a_Out, const AString & a_Value)
|
|
||||||
{
|
|
||||||
WriteInt32(a_Out, a_Value.size());
|
|
||||||
a_Out.append(a_Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteString(AString & a_Out, const AString & a_String)
|
|
||||||
{
|
|
||||||
WriteInt16(a_Out, a_String.length());
|
|
||||||
a_Out.append(a_String);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteList(AString & a_Out, const cNBTList * a_List)
|
|
||||||
{
|
|
||||||
WriteInt32(a_Out, a_List->GetChildrenCount());
|
|
||||||
const cNBTTags & Children = a_List->GetChildren();
|
|
||||||
for (cNBTTags::const_iterator itr = Children.begin(); itr != Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
WriteTag(a_Out, *itr);
|
|
||||||
} // for itr - Children[]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteIntArray(AString & a_Out, const cNBTIntArray * a_Array)
|
|
||||||
{
|
|
||||||
WriteInt32(a_Out, a_Array->GetValues().size());
|
|
||||||
const std::vector<int> & Values = a_Array->GetValues();
|
|
||||||
for (std::vector<int>::const_iterator itr = Values.begin(); itr != Values.end(); ++itr)
|
|
||||||
{
|
|
||||||
WriteInt32(a_Out, *itr);
|
|
||||||
} // for itr - Values[]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteCompound(AString & a_Out, const cNBTCompound * a_Compound)
|
|
||||||
{
|
|
||||||
const cNBTTags & Children = a_Compound->GetChildren();
|
|
||||||
for (cNBTTags::const_iterator itr = Children.begin(); itr != Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
a_Out.push_back((*itr)->GetType());
|
|
||||||
WriteString(a_Out, (*itr)->GetName());
|
|
||||||
WriteTag(a_Out, *itr);
|
|
||||||
} // for itr - Children[]
|
|
||||||
a_Out.push_back(cNBTTag::TAG_End);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define CASE_SIMPLE_TAG(TAGTYPE,CTYPE,FUNC) \
|
|
||||||
case cNBTTag::TAG_##TAGTYPE: \
|
|
||||||
{ \
|
|
||||||
Write##FUNC(a_Out, ((const cNBT##TAGTYPE *)a_Tag)->m_Value ); \
|
|
||||||
return;\
|
|
||||||
}
|
|
||||||
|
|
||||||
void cNBTSerializer::WriteTag(AString & a_Out, const cNBTTag * a_Tag)
|
|
||||||
{
|
|
||||||
switch (a_Tag->GetType())
|
|
||||||
{
|
|
||||||
CASE_SIMPLE_TAG(Byte, char, Byte)
|
|
||||||
CASE_SIMPLE_TAG(Short, Int16, Int16)
|
|
||||||
CASE_SIMPLE_TAG(Int, Int32, Int32)
|
|
||||||
CASE_SIMPLE_TAG(Long, Int64, Int64)
|
|
||||||
CASE_SIMPLE_TAG(Float, float, Float)
|
|
||||||
CASE_SIMPLE_TAG(Double, double, Double)
|
|
||||||
CASE_SIMPLE_TAG(ByteArray, AString, ByteArray)
|
|
||||||
CASE_SIMPLE_TAG(String, AString, String)
|
|
||||||
|
|
||||||
case cNBTTag::TAG_List:
|
|
||||||
{
|
|
||||||
a_Out.push_back((char)((const cNBTList *)a_Tag)->GetChildrenType());
|
|
||||||
WriteList(a_Out, (const cNBTList *)a_Tag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_Compound:
|
|
||||||
{
|
|
||||||
WriteCompound(a_Out, (const cNBTCompound *)a_Tag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_IntArray:
|
|
||||||
{
|
|
||||||
WriteIntArray(a_Out, (const cNBTIntArray *)a_Tag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} // switch (iType)
|
|
||||||
|
|
||||||
ASSERT(!"Unhandled NBT tag type");
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CASE_SIMPLE_TAG
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cNBTSerializer::Serialize(const cNBTTree * a_Tree, AString & a_Out)
|
|
||||||
{
|
|
||||||
a_Out.clear();
|
|
||||||
a_Out.push_back(cNBTTag::TAG_Compound);
|
|
||||||
WriteString(a_Out, a_Tree->GetName());
|
|
||||||
WriteCompound(a_Out, (const cNBTCompound *)a_Tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Dumping the NBT tree (debug-only)
|
|
||||||
|
|
||||||
#if (defined(_DEBUG) && defined(_WIN32))
|
|
||||||
|
|
||||||
#define CASE_SIMPLE_TAG(TYPE,FMT) \
|
|
||||||
case cNBTTag::TAG_##TYPE: \
|
|
||||||
{ \
|
|
||||||
AString out; \
|
|
||||||
Printf(out, "%sTAG_" TEXT(#TYPE) TEXT("(\"%hs\"): %") TEXT(FMT) TEXT("\n"), Indent.c_str(), a_Tree->GetName().c_str(), ((cNBT##TYPE *)a_Tree)->m_Value); \
|
|
||||||
OutputDebugString(out.c_str()); \
|
|
||||||
break; \
|
|
||||||
}
|
|
||||||
|
|
||||||
void DumpTree(const cNBTTree * a_Tree, int a_Level)
|
|
||||||
{
|
|
||||||
AString Indent(a_Level, TEXT(' '));
|
|
||||||
switch (a_Tree->GetType())
|
|
||||||
{
|
|
||||||
CASE_SIMPLE_TAG(Byte, "d")
|
|
||||||
CASE_SIMPLE_TAG(Short, "d")
|
|
||||||
CASE_SIMPLE_TAG(Int, "d")
|
|
||||||
CASE_SIMPLE_TAG(Long, "I64d")
|
|
||||||
CASE_SIMPLE_TAG(Float, "f")
|
|
||||||
CASE_SIMPLE_TAG(Double, "f")
|
|
||||||
|
|
||||||
case cNBTTag::TAG_ByteArray:
|
|
||||||
{
|
|
||||||
AString out;
|
|
||||||
Printf(out, "%sTAG_ByteArray(\"%hs\"): %d bytes\n", Indent.c_str(), a_Tree->GetName().c_str(), ((cNBTByteArray *)a_Tree)->m_Value.size());
|
|
||||||
OutputDebugString(out.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_String:
|
|
||||||
{
|
|
||||||
AString out;
|
|
||||||
Printf(out, "%sTAG_String(\"%hs\"): %d bytes: \"%hs\"\n", Indent.c_str(), a_Tree->GetName().c_str(), ((cNBTString *)a_Tree)->m_Value.size(), ((cNBTString *)a_Tree)->m_Value.c_str());
|
|
||||||
OutputDebugString(out.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_List:
|
|
||||||
{
|
|
||||||
const cNBTTags & Children = ((cNBTList *)a_Tree)->GetChildren();
|
|
||||||
AString out;
|
|
||||||
Printf(out, "%sTAG_List(\"%hs\"): %d items of type %d\n%s{\n", Indent.c_str(), a_Tree->GetName().c_str(), Children.size(), ((cNBTList *)a_Tree)->GetChildrenType(), Indent.c_str());
|
|
||||||
OutputDebugString(out.c_str());
|
|
||||||
for (cNBTTags::const_iterator itr = Children.begin(); itr != Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
DumpTree(*itr, a_Level + 1);
|
|
||||||
} // for itr - Children[]
|
|
||||||
Printf(out, "%s}\n", Indent.c_str());
|
|
||||||
OutputDebugString(out.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case cNBTTag::TAG_Compound:
|
|
||||||
{
|
|
||||||
const cNBTTags & Children = ((cNBTCompound *)a_Tree)->GetChildren();
|
|
||||||
AString out;
|
|
||||||
Printf(out, "%sTAG_Compound(\"%hs\"): %d items\n%s{\n", Indent.c_str(), a_Tree->GetName().c_str(), Children.size(), Indent.c_str());
|
|
||||||
OutputDebugString(out.c_str());
|
|
||||||
for (cNBTTags::const_iterator itr = Children.begin(); itr != Children.end(); ++itr)
|
|
||||||
{
|
|
||||||
DumpTree(*itr, a_Level + 1);
|
|
||||||
} // for itr - Children[]
|
|
||||||
Printf(out, "%s}\n", Indent.c_str());
|
|
||||||
OutputDebugString(out.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CASE_SIMPLE_TAG
|
|
||||||
|
|
||||||
#endif // (_DEBUG && _WIN32)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
232
source/NBT.h
232
source/NBT.h
|
@ -1,232 +0,0 @@
|
||||||
|
|
||||||
// NBT.h
|
|
||||||
|
|
||||||
// Interfaces to the classes used for NBT representation, parsing and serializing
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Representation classes:
|
|
||||||
|
|
||||||
class cNBTTag abstract // The base class for all NBT tags
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum eTagType
|
|
||||||
{
|
|
||||||
TAG_Min = 0, // The minimum value for a tag type
|
|
||||||
TAG_End = 0,
|
|
||||||
TAG_Byte = 1,
|
|
||||||
TAG_Short = 2,
|
|
||||||
TAG_Int = 3,
|
|
||||||
TAG_Long = 4,
|
|
||||||
TAG_Float = 5,
|
|
||||||
TAG_Double = 6,
|
|
||||||
TAG_ByteArray = 7,
|
|
||||||
TAG_String = 8,
|
|
||||||
TAG_List = 9,
|
|
||||||
TAG_Compound = 10,
|
|
||||||
TAG_IntArray = 11,
|
|
||||||
TAG_Max = 11, // The maximum value for a tag type
|
|
||||||
} ;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
cNBTTag * m_Parent;
|
|
||||||
eTagType m_Type;
|
|
||||||
AString m_Name; // tag name, in UTF-8
|
|
||||||
|
|
||||||
public:
|
|
||||||
cNBTTag(cNBTTag * a_Parent, eTagType a_Type) : m_Parent(a_Parent), m_Type(a_Type) {}
|
|
||||||
cNBTTag(cNBTTag * a_Parent, eTagType a_Type, const AString & a_Name) : m_Parent(a_Parent), m_Type(a_Type), m_Name(a_Name) {}
|
|
||||||
virtual ~cNBTTag() {} // Force a virtual destructor
|
|
||||||
|
|
||||||
cNBTTag * GetParent(void) const {return m_Parent; }
|
|
||||||
eTagType GetType (void) const {return m_Type; }
|
|
||||||
const AString & GetName (void) const {return m_Name; }
|
|
||||||
void SetName (const AString & a_Name) {m_Name = a_Name; }
|
|
||||||
|
|
||||||
static cNBTTag * CreateTag(cNBTTag * a_Parent, eTagType a_Type, const AString & a_Name); // Creates a new instance of a tag specified by iType, uses the correct class
|
|
||||||
|
|
||||||
virtual cNBTTag * FindChildByName(const AString & a_Name) const {return NULL; }
|
|
||||||
const cNBTTag * FindChildByPath(const AString & a_Path) const;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
typedef cNBTTag cNBTTree;
|
|
||||||
typedef std::vector<cNBTTag *> cNBTTags;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define DECLARE_SIMPLE_TAG(TAG,CTYPE) \
|
|
||||||
class cNBT##TAG : \
|
|
||||||
public cNBTTag \
|
|
||||||
{ \
|
|
||||||
public: \
|
|
||||||
cNBT##TAG(cNBTTag * a_Parent) : cNBTTag(a_Parent, TAG_##TAG) {} \
|
|
||||||
cNBT##TAG(cNBTTag * a_Parent, const AString & a_Name) : cNBTTag(a_Parent, TAG_##TAG, a_Name) {} \
|
|
||||||
cNBT##TAG(cNBTTag * a_Parent, const AString & a_Name, const CTYPE & a_Value) : cNBTTag(a_Parent, TAG_##TAG, a_Name), m_Value(a_Value) {} \
|
|
||||||
CTYPE m_Value; \
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DECLARE_SIMPLE_TAG(Byte, char);
|
|
||||||
DECLARE_SIMPLE_TAG(Short, Int16);
|
|
||||||
DECLARE_SIMPLE_TAG(Int, Int32);
|
|
||||||
DECLARE_SIMPLE_TAG(Long, Int64);
|
|
||||||
DECLARE_SIMPLE_TAG(Float, float);
|
|
||||||
DECLARE_SIMPLE_TAG(Double, double);
|
|
||||||
DECLARE_SIMPLE_TAG(ByteArray, AString); // Represent the array as a string for easier manipulation
|
|
||||||
DECLARE_SIMPLE_TAG(String, AString);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cNBTList :
|
|
||||||
public cNBTTag
|
|
||||||
{
|
|
||||||
cNBTTags m_Children;
|
|
||||||
eTagType m_ChildrenType;
|
|
||||||
|
|
||||||
public:
|
|
||||||
cNBTList(cNBTTag * a_Parent, eTagType a_ChildrenType) : cNBTTag(a_Parent, TAG_List), m_ChildrenType(a_ChildrenType) {}
|
|
||||||
cNBTList(cNBTTag * a_Parent, const AString & a_Name, eTagType a_ChildrenType) : cNBTTag(a_Parent, TAG_List, a_Name), m_ChildrenType(a_ChildrenType) {}
|
|
||||||
virtual ~cNBTList() {Clear(); }
|
|
||||||
|
|
||||||
void Clear (void);
|
|
||||||
int Add (cNBTTag * a_Tag);
|
|
||||||
cNBTTag * GetChildByIdx (size_t a_Index);
|
|
||||||
const cNBTTags & GetChildren (void) const {return m_Children; }
|
|
||||||
size_t GetChildrenCount(void) const {return m_Children.size(); }
|
|
||||||
virtual cNBTTag * FindChildByName (const AString & a_Name) const override;
|
|
||||||
|
|
||||||
int SetChildrenType(eTagType a_Type); // Only valid when list empty
|
|
||||||
eTagType GetChildrenType(void) const {return m_ChildrenType; }
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cNBTCompound :
|
|
||||||
public cNBTTag
|
|
||||||
{
|
|
||||||
cNBTTags m_Children;
|
|
||||||
public:
|
|
||||||
cNBTCompound(cNBTTag * a_Parent) : cNBTTag(a_Parent, TAG_Compound) {}
|
|
||||||
cNBTCompound(cNBTTag * a_Parent, const AString & a_Name) : cNBTTag(a_Parent, TAG_Compound, a_Name) {}
|
|
||||||
virtual ~cNBTCompound() {Clear(); }
|
|
||||||
|
|
||||||
void Clear (void);
|
|
||||||
int Add (cNBTTag * a_Tag);
|
|
||||||
cNBTTag * GetChildByIdx (size_t a_Index);
|
|
||||||
const cNBTTags & GetChildren (void) const {return m_Children; }
|
|
||||||
size_t GetChildrenCount(void) const {return m_Children.size(); }
|
|
||||||
virtual cNBTTag * FindChildByName (const AString & a_Name) const override;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cNBTIntArray :
|
|
||||||
public cNBTTag
|
|
||||||
{
|
|
||||||
typedef cNBTTag super;
|
|
||||||
|
|
||||||
std::vector<int> m_Values;
|
|
||||||
|
|
||||||
public:
|
|
||||||
cNBTIntArray(cNBTTag * a_Parent) : super(a_Parent, TAG_IntArray) {}
|
|
||||||
cNBTIntArray(cNBTTag * a_Parent, const AString & a_Name) : super(a_Parent, TAG_IntArray, a_Name) {}
|
|
||||||
|
|
||||||
void Clear(void) {m_Values.clear(); }
|
|
||||||
void Add (int a_Value) {m_Values.push_back(a_Value); }
|
|
||||||
int Get (int a_Index) const {return m_Values[a_Index]; }
|
|
||||||
int Size (void) const {return m_Values.size(); }
|
|
||||||
const std::vector<int> & GetValues(void) const {return m_Values; }
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// The parser:
|
|
||||||
|
|
||||||
class cNBTParser
|
|
||||||
{
|
|
||||||
static int ReadTag (const char ** Data, int * Length, cNBTTag::eTagType iType, const AString & a_Name, cNBTTag * iParent, cNBTTag ** oTag); // Helper
|
|
||||||
|
|
||||||
static int ReadByte (const char ** Data, int * Length, char & a_Value);
|
|
||||||
static int ReadInt16 (const char ** Data, int * Length, Int16 & a_Value);
|
|
||||||
static int ReadInt32 (const char ** Data, int * Length, Int32 & a_Value);
|
|
||||||
static int ReadInt64 (const char ** Data, int * Length, Int64 & a_Value);
|
|
||||||
static int ReadFloat (const char ** Data, int * Length, float & a_Value);
|
|
||||||
static int ReadDouble (const char ** Data, int * Length, double & a_Value);
|
|
||||||
static int ReadByteArray(const char ** Data, int * Length, AString & a_Value);
|
|
||||||
static int ReadString (const char ** Data, int * Length, AString & a_Value);
|
|
||||||
static int ReadList (const char ** Data, int * Length, cNBTList * a_List);
|
|
||||||
static int ReadCompound (const char ** Data, int * Length, cNBTCompound * a_Compound);
|
|
||||||
static int ReadIntArray (const char ** Data, int * Length, cNBTIntArray * a_Array);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Returns the parsed tree, or NULL on failure
|
|
||||||
static cNBTTree * Parse(const char * a_Data, int a_Length);
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// The serializer:
|
|
||||||
|
|
||||||
class cNBTSerializer
|
|
||||||
{
|
|
||||||
static void WriteTag (AString & a_Out, const cNBTTag * a_Tag);
|
|
||||||
|
|
||||||
static void WriteByte (AString & a_Out, const char a_Value);
|
|
||||||
static void WriteInt16 (AString & a_Out, const Int16 a_Value);
|
|
||||||
static void WriteInt32 (AString & a_Out, const Int32 a_Value);
|
|
||||||
static void WriteInt64 (AString & a_Out, const Int64 a_Value);
|
|
||||||
static void WriteFloat (AString & a_Out, const float a_Value);
|
|
||||||
static void WriteDouble (AString & a_Out, const double a_Value);
|
|
||||||
static void WriteByteArray(AString & a_Out, const AString & a_Value);
|
|
||||||
static void WriteString (AString & a_Out, const AString & a_Value);
|
|
||||||
static void WriteList (AString & a_Out, const cNBTList * a_List);
|
|
||||||
static void WriteCompound (AString & a_Out, const cNBTCompound * a_Compound);
|
|
||||||
static void WriteIntArray (AString & a_Out, const cNBTIntArray * a_Array);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static void Serialize(const cNBTTree * a_Tree, AString & a_Out);
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Dumping the tree (DEBUG-only)
|
|
||||||
|
|
||||||
#if (defined(_DEBUG) && defined(_WIN32))
|
|
||||||
void DumpTree(const cNBTTree * a_Tree, int a_Level = 0);
|
|
||||||
#endif // (_DEBUG && _WIN32)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,23 +38,15 @@ AString & AppendVPrintf(AString & str, const char *format, va_list args)
|
||||||
#endif // _MSC_VER
|
#endif // _MSC_VER
|
||||||
|
|
||||||
// Allocate a buffer and printf into it:
|
// Allocate a buffer and printf into it:
|
||||||
std::auto_ptr<char> tmp(new char[len + 1]);
|
str.resize(len + 1);
|
||||||
ASSERT(tmp.get() != NULL); // Why not alloced? Is the length reasonable?
|
// HACK: we're accessing AString's internal buffer in a way that is NOT guaranteed to always work. But it works on all STL implementations tested.
|
||||||
if (tmp.get() == NULL)
|
// I can't think of any other way that is safe, doesn't allocate twice as much space as needed and doesn't use C++11 features like the move constructor
|
||||||
{
|
|
||||||
throw std::bad_alloc();
|
|
||||||
}
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
if ((len = vsprintf_s(tmp.get(), len + 1, format, args)) != -1)
|
vsprintf_s((char *)str.data(), len + 1, format, args);
|
||||||
{
|
|
||||||
str.append(tmp.get(), len);
|
|
||||||
}
|
|
||||||
ASSERT(len != -1);
|
|
||||||
#else // _MSC_VER
|
#else // _MSC_VER
|
||||||
vsnprintf(tmp.get(), len + 1, format, args);
|
vsnprintf((char *)str.data(), len + 1, format, args);
|
||||||
str.append(tmp.get(), len);
|
|
||||||
#endif // else _MSC_VER
|
#endif // else _MSC_VER
|
||||||
|
str.resize(len);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
463
source/StructGen.cpp
Normal file
463
source/StructGen.cpp
Normal file
|
@ -0,0 +1,463 @@
|
||||||
|
|
||||||
|
// StructGen.h
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "StructGen.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
#include "Trees.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cStructGenOreNests configuration:
|
||||||
|
|
||||||
|
const int MAX_HEIGHT_COAL = 127;
|
||||||
|
const int NUM_NESTS_COAL = 60;
|
||||||
|
const int NEST_SIZE_COAL = 10;
|
||||||
|
|
||||||
|
const int MAX_HEIGHT_IRON = 70;
|
||||||
|
const int NUM_NESTS_IRON = 30;
|
||||||
|
const int NEST_SIZE_IRON = 6;
|
||||||
|
|
||||||
|
const int MAX_HEIGHT_REDSTONE = 40;
|
||||||
|
const int NUM_NESTS_REDSTONE = 10;
|
||||||
|
const int NEST_SIZE_REDSTONE = 6;
|
||||||
|
|
||||||
|
const int MAX_HEIGHT_GOLD = 35;
|
||||||
|
const int NUM_NESTS_GOLD = 6;
|
||||||
|
const int NEST_SIZE_GOLD = 6;
|
||||||
|
|
||||||
|
const int MAX_HEIGHT_DIAMOND = 16;
|
||||||
|
const int NUM_NESTS_DIAMOND = 6;
|
||||||
|
const int NEST_SIZE_DIAMOND = 5;
|
||||||
|
|
||||||
|
const int MAX_HEIGHT_LAPIS = 30;
|
||||||
|
const int NUM_NESTS_LAPIS = 6;
|
||||||
|
const int NEST_SIZE_LAPIS = 5;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T> T Clamp(T a_Value, T a_Min, T a_Max)
|
||||||
|
{
|
||||||
|
return (a_Value < a_Min) ? a_Min : ((a_Value > a_Max) ? a_Max : a_Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cStructGenTrees:
|
||||||
|
|
||||||
|
void cStructGenTrees::GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMetas, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cChunkDef::BlockTypes WorkerBlockTypes;
|
||||||
|
cChunkDef::BlockNibbles WorkerBlockMeta;
|
||||||
|
cChunkDef::HeightMap WorkerHeight;
|
||||||
|
|
||||||
|
cEntityList Entities;
|
||||||
|
cBlockEntityList BlockEntities;
|
||||||
|
|
||||||
|
// Generate trees:
|
||||||
|
for (int x = 0; x <= 2; x++)
|
||||||
|
{
|
||||||
|
int BaseX = a_ChunkX + x - 1;
|
||||||
|
for (int z = 0; z <= 2; z++)
|
||||||
|
{
|
||||||
|
int BaseZ = a_ChunkZ + z - 1;
|
||||||
|
sSetBlockVector Outside;
|
||||||
|
|
||||||
|
cChunkDef::BlockTypes * BlT;
|
||||||
|
cChunkDef::BlockNibbles * BlM;
|
||||||
|
cChunkDef::HeightMap * Hei;
|
||||||
|
|
||||||
|
if ((x != 1) || (z != 1))
|
||||||
|
{
|
||||||
|
BlT = &WorkerBlockTypes;
|
||||||
|
BlM = &WorkerBlockMeta;
|
||||||
|
Hei = &WorkerHeight;
|
||||||
|
|
||||||
|
m_HeightGen->GenHeightMap (BaseX, BaseZ, *Hei);
|
||||||
|
m_CompositionGen->ComposeTerrain(BaseX, BaseZ, *BlT, *BlM, *Hei, Entities, BlockEntities);
|
||||||
|
// TODO: Free the entity lists
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BlT = &a_BlockTypes;
|
||||||
|
BlM = &a_BlockMetas;
|
||||||
|
Hei = &a_HeightMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
cChunkDef::BiomeMap Biomes;
|
||||||
|
m_BiomeGen->GenBiomes(BaseX, BaseZ, Biomes);
|
||||||
|
int NumTrees = GetNumTrees(BaseX, BaseZ, Biomes);
|
||||||
|
|
||||||
|
for (int i = 0; i < NumTrees; i++)
|
||||||
|
{
|
||||||
|
GenerateSingleTree(BaseX, BaseZ, i, *BlT, *BlM, *Hei, Biomes, Outside);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Integrate blocks in Outside into chunk:
|
||||||
|
for (sSetBlockVector::const_iterator itr = Outside.begin(); itr != Outside.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((itr->ChunkX != a_ChunkX) || (itr->ChunkZ != a_ChunkZ))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (cChunkDef::GetBlock(a_BlockTypes, itr->x, itr->y, itr->z))
|
||||||
|
{
|
||||||
|
CASE_TREE_OVERWRITTEN_BLOCKS:
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock (a_BlockTypes, itr->x, itr->y, itr->z, itr->BlockType);
|
||||||
|
cChunkDef::SetNibble(a_BlockMetas, itr->x, itr->y, itr->z, itr->BlockMeta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (GetBlock())
|
||||||
|
} // for itr - Outside[]
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
|
||||||
|
// Update the heightmap:
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
for (int y = cChunkDef::Height - 1; y >= 0; y--)
|
||||||
|
{
|
||||||
|
if (cChunkDef::GetBlock(a_BlockTypes, x, y, z) != E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
cChunkDef::SetHeight(a_HeightMap, x, z, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cStructGenTrees::GenerateSingleTree(
|
||||||
|
int a_ChunkX, int a_ChunkZ, int a_Seq,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes,
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMetas,
|
||||||
|
const cChunkDef::HeightMap & a_Height,
|
||||||
|
const cChunkDef::BiomeMap & a_Biomes,
|
||||||
|
sSetBlockVector & a_Blocks
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int x = m_Noise.IntNoise3DInt(a_ChunkX + a_ChunkZ, a_ChunkZ, a_Seq) % cChunkDef::Width;
|
||||||
|
int z = m_Noise.IntNoise3DInt(a_ChunkX - a_ChunkZ, a_Seq, a_ChunkZ) % cChunkDef::Width;
|
||||||
|
|
||||||
|
int Height = a_Height[x + cChunkDef::Width * z];
|
||||||
|
|
||||||
|
if ((Height <= 0) || (Height > 240))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the block underneath the tree:
|
||||||
|
BLOCKTYPE TopBlock = cChunkDef::GetBlock(a_BlockTypes, x, Height, z);
|
||||||
|
if ((TopBlock != E_BLOCK_DIRT) && (TopBlock != E_BLOCK_GRASS) && (TopBlock != E_BLOCK_SOIL))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sSetBlockVector TreeBlocks;
|
||||||
|
GetTreeImageByBiome(a_ChunkX * cChunkDef::Width + x, Height + 1, a_ChunkZ * cChunkDef::Width + z, m_Noise, a_Seq, a_Biomes[x + cChunkDef::Width * z], TreeBlocks);
|
||||||
|
|
||||||
|
// Check if the generated image fits the terrain:
|
||||||
|
for (sSetBlockVector::const_iterator itr = TreeBlocks.begin(); itr != TreeBlocks.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((itr->ChunkX != a_ChunkX) || (itr->ChunkZ != a_ChunkZ) || (itr->BlockType != E_BLOCK_LOG))
|
||||||
|
{
|
||||||
|
// Outside the chunk, or not a log (we don't check non-logs)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BLOCKTYPE Block = cChunkDef::GetBlock(a_BlockTypes, itr->x, itr->y, itr->z);
|
||||||
|
switch (Block)
|
||||||
|
{
|
||||||
|
CASE_TREE_ALLOWED_BLOCKS:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
// There's something in the way, abort this tree altogether
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put the generated image into a_BlockTypes, push things outside this chunk into a_Blocks
|
||||||
|
for (sSetBlockVector::const_iterator itr = TreeBlocks.begin(); itr != TreeBlocks.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((itr->ChunkX == a_ChunkX) && (itr->ChunkZ == a_ChunkZ))
|
||||||
|
{
|
||||||
|
// Inside this chunk, integrate into a_BlockTypes:
|
||||||
|
switch (cChunkDef::GetBlock(a_BlockTypes, itr->x, itr->y, itr->z))
|
||||||
|
{
|
||||||
|
CASE_TREE_OVERWRITTEN_BLOCKS:
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock (a_BlockTypes, itr->x, itr->y, itr->z, itr->BlockType);
|
||||||
|
cChunkDef::SetNibble(a_BlockMetas, itr->x, itr->y, itr->z, itr->BlockMeta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (GetBlock())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Outside the chunk, push into a_Blocks; check if already present there:
|
||||||
|
bool Found = false;
|
||||||
|
for (sSetBlockVector::iterator itrB = a_Blocks.begin(); itrB != a_Blocks.end(); ++itrB)
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
(itr->ChunkX == itrB->ChunkX) &&
|
||||||
|
(itr->ChunkZ == itrB->ChunkZ) &&
|
||||||
|
(itr->x == itrB->x) &&
|
||||||
|
(itr->y == itrB->y) &&
|
||||||
|
(itr->z == itrB->z)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Same coords already found in a_Blocks, overwrite with wood, if requested:
|
||||||
|
if (itr->BlockType == E_BLOCK_LOG)
|
||||||
|
{
|
||||||
|
itrB->BlockType = itr->BlockType;
|
||||||
|
itrB->BlockMeta = itr->BlockMeta;
|
||||||
|
}
|
||||||
|
Found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for itrB - a_Blocks[]
|
||||||
|
if (!Found)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(*itr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cStructGenTrees::GetNumTrees(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
const cChunkDef::BiomeMap & a_Biomes
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int NumTrees = 0;
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++) for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
int Add = 0;
|
||||||
|
switch (a_Biomes[x + cChunkDef::Width * z])
|
||||||
|
{
|
||||||
|
case biPlains: Add = 1; break;
|
||||||
|
case biExtremeHills: Add = 3; break;
|
||||||
|
case biForest: Add = 30; break;
|
||||||
|
case biTaiga: Add = 30; break;
|
||||||
|
case biSwampland: Add = 8; break;
|
||||||
|
case biIcePlains: Add = 1; break;
|
||||||
|
case biIceMountains: Add = 1; break;
|
||||||
|
case biMushroomIsland: Add = 3; break;
|
||||||
|
case biMushroomShore: Add = 3; break;
|
||||||
|
case biForestHills: Add = 20; break;
|
||||||
|
case biTaigaHills: Add = 20; break;
|
||||||
|
case biExtremeHillsEdge: Add = 5; break;
|
||||||
|
case biJungle: Add = 120; break;
|
||||||
|
case biJungleHills: Add = 90; break;
|
||||||
|
}
|
||||||
|
NumTrees += Add;
|
||||||
|
}
|
||||||
|
return NumTrees / 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cStructGenMarbleCaves:
|
||||||
|
|
||||||
|
static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
|
||||||
|
{
|
||||||
|
static const float PI_2 = 1.57079633f;
|
||||||
|
float oct1 = (a_Noise.CubicNoise3D(x * 0.1f, y * 0.1f, z * 0.1f )) * 4;
|
||||||
|
|
||||||
|
oct1 = oct1 * oct1 * oct1;
|
||||||
|
if (oct1 < 0.f) oct1 = PI_2;
|
||||||
|
if (oct1 > PI_2) oct1 = PI_2;
|
||||||
|
|
||||||
|
return oct1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cStructGenMarbleCaves::GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
cNoise Noise(m_Seed);
|
||||||
|
for (int z = 0; z < cChunkDef::Width; z++)
|
||||||
|
{
|
||||||
|
const float zz = (float)(a_ChunkZ * cChunkDef::Width + z);
|
||||||
|
for (int x = 0; x < cChunkDef::Width; x++)
|
||||||
|
{
|
||||||
|
const float xx = (float)(a_ChunkX * cChunkDef::Width + x);
|
||||||
|
|
||||||
|
int Top = cChunkDef::GetHeight(a_HeightMap, x, z);
|
||||||
|
for (int y = 1; y < Top; ++y )
|
||||||
|
{
|
||||||
|
if (cChunkDef::GetBlock(a_BlockTypes, x, y, z) != E_BLOCK_STONE)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float yy = (float)y;
|
||||||
|
const float WaveNoise = 1;
|
||||||
|
if (cosf(GetMarbleNoise(xx, yy * 0.5f, zz, Noise)) * fabs(cosf(yy * 0.2f + WaveNoise * 2) * 0.75f + WaveNoise) > 0.0005f)
|
||||||
|
{
|
||||||
|
if (y > 4)
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_STATIONARY_LAVA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for y
|
||||||
|
} // for x
|
||||||
|
} // for z
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cStructGenOreNests:
|
||||||
|
|
||||||
|
void cStructGenOreNests::GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
)
|
||||||
|
{
|
||||||
|
GenerateOre(a_ChunkX, a_ChunkZ, E_BLOCK_COAL_ORE, MAX_HEIGHT_COAL, NUM_NESTS_COAL, NEST_SIZE_COAL, a_BlockTypes, 1);
|
||||||
|
GenerateOre(a_ChunkX, a_ChunkZ, E_BLOCK_IRON_ORE, MAX_HEIGHT_IRON, NUM_NESTS_IRON, NEST_SIZE_IRON, a_BlockTypes, 2);
|
||||||
|
GenerateOre(a_ChunkX, a_ChunkZ, E_BLOCK_REDSTONE_ORE, MAX_HEIGHT_REDSTONE, NUM_NESTS_REDSTONE, NEST_SIZE_REDSTONE, a_BlockTypes, 3);
|
||||||
|
GenerateOre(a_ChunkX, a_ChunkZ, E_BLOCK_GOLD_ORE, MAX_HEIGHT_GOLD, NUM_NESTS_GOLD, NEST_SIZE_GOLD, a_BlockTypes, 4);
|
||||||
|
GenerateOre(a_ChunkX, a_ChunkZ, E_BLOCK_DIAMOND_ORE, MAX_HEIGHT_DIAMOND, NUM_NESTS_DIAMOND, NEST_SIZE_DIAMOND, a_BlockTypes, 5);
|
||||||
|
GenerateOre(a_ChunkX, a_ChunkZ, E_BLOCK_LAPIS_ORE, MAX_HEIGHT_LAPIS, NUM_NESTS_LAPIS, NEST_SIZE_LAPIS, a_BlockTypes, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cStructGenOreNests::GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq)
|
||||||
|
{
|
||||||
|
// This function generates several "nests" of ore, each nest consisting of number of ore blocks relatively adjacent to each other.
|
||||||
|
// It does so by making a random XYZ walk and adding ore along the way in cuboids of different (random) sizes
|
||||||
|
// Only stone gets replaced with ore, all other blocks stay (so the nest can actually be smaller than specified).
|
||||||
|
|
||||||
|
for (int i = 0; i < a_NumNests; i++)
|
||||||
|
{
|
||||||
|
int rnd = m_Noise.IntNoise3DInt(a_ChunkX + i, a_Seq, a_ChunkZ + 64 * i) / 8;
|
||||||
|
int BaseX = rnd % cChunkDef::Width;
|
||||||
|
rnd /= cChunkDef::Width;
|
||||||
|
int BaseZ = rnd % cChunkDef::Width;
|
||||||
|
rnd /= cChunkDef::Width;
|
||||||
|
int BaseY = rnd % a_MaxHeight;
|
||||||
|
rnd /= a_MaxHeight;
|
||||||
|
int NestSize = a_NestSize + (rnd % (a_NestSize / 4)); // The actual nest size may be up to 1/4 larger
|
||||||
|
int Num = 0;
|
||||||
|
while (Num < NestSize)
|
||||||
|
{
|
||||||
|
// Put a cuboid around [BaseX, BaseY, BaseZ]
|
||||||
|
int rnd = m_Noise.IntNoise3DInt(a_ChunkX + 64 * i, 2 * a_Seq + Num, a_ChunkZ + 32 * i) / 8;
|
||||||
|
int xsize = rnd % 2;
|
||||||
|
int ysize = (rnd / 4) % 2;
|
||||||
|
int zsize = (rnd / 16) % 2;
|
||||||
|
rnd >>= 8;
|
||||||
|
for (int x = xsize; x >= 0; --x)
|
||||||
|
{
|
||||||
|
int BlockX = BaseX + x;
|
||||||
|
if ((BlockX < 0) || (BlockX >= cChunkDef::Width))
|
||||||
|
{
|
||||||
|
Num++; // So that the cycle finishes even if the base coords wander away from the chunk
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int y = ysize; y >= 0; --y)
|
||||||
|
{
|
||||||
|
int BlockY = BaseY + y;
|
||||||
|
if ((BlockY < 0) || (BlockY >= cChunkDef::Height))
|
||||||
|
{
|
||||||
|
Num++; // So that the cycle finishes even if the base coords wander away from the chunk
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int z = zsize; z >= 0; --z)
|
||||||
|
{
|
||||||
|
int BlockZ = BaseZ + z;
|
||||||
|
if ((BlockZ < 0) || (BlockZ >= cChunkDef::Width))
|
||||||
|
{
|
||||||
|
Num++; // So that the cycle finishes even if the base coords wander away from the chunk
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Index = cChunkDef::MakeIndexNoCheck(BlockX, BlockY, BlockZ);
|
||||||
|
if (a_BlockTypes[Index] == E_BLOCK_STONE)
|
||||||
|
{
|
||||||
|
a_BlockTypes[Index] = a_OreType;
|
||||||
|
}
|
||||||
|
Num++;
|
||||||
|
} // for z
|
||||||
|
} // for y
|
||||||
|
} // for x
|
||||||
|
|
||||||
|
// Move the base to a neighbor voxel
|
||||||
|
switch (rnd % 4)
|
||||||
|
{
|
||||||
|
case 0: BaseX--; break;
|
||||||
|
case 1: BaseX++; break;
|
||||||
|
}
|
||||||
|
switch ((rnd >> 3) % 4)
|
||||||
|
{
|
||||||
|
case 0: BaseY--; break;
|
||||||
|
case 1: BaseY++; break;
|
||||||
|
}
|
||||||
|
switch ((rnd >> 6) % 4)
|
||||||
|
{
|
||||||
|
case 0: BaseZ--; break;
|
||||||
|
case 1: BaseZ++; break;
|
||||||
|
}
|
||||||
|
} // while (Num < NumBlocks)
|
||||||
|
} // for i - NumNests
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
122
source/StructGen.h
Normal file
122
source/StructGen.h
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
|
||||||
|
// StructGen.h
|
||||||
|
|
||||||
|
/* Interfaces to the various structure generators:
|
||||||
|
- cStructGenTrees
|
||||||
|
- cStructGenMarbleCaves
|
||||||
|
- cStructGenOres
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cChunkGenerator.h"
|
||||||
|
#include "cNoise.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cStructGenTrees :
|
||||||
|
public cStructureGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cStructGenTrees(int a_Seed, cBiomeGen * a_BiomeGen, cTerrainHeightGen * a_HeightGen, cTerrainCompositionGen * a_CompositionGen) :
|
||||||
|
m_Seed(a_Seed),
|
||||||
|
m_Noise(a_Seed),
|
||||||
|
m_BiomeGen(a_BiomeGen),
|
||||||
|
m_HeightGen(a_HeightGen),
|
||||||
|
m_CompositionGen(a_CompositionGen)
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_Seed;
|
||||||
|
cNoise m_Noise;
|
||||||
|
cBiomeGen * m_BiomeGen;
|
||||||
|
cTerrainHeightGen * m_HeightGen;
|
||||||
|
cTerrainCompositionGen * m_CompositionGen;
|
||||||
|
|
||||||
|
void GenerateSingleTree(
|
||||||
|
int a_ChunkX, int a_ChunkZ, int a_Seq,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes,
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMetas,
|
||||||
|
const cChunkDef::HeightMap & a_Height,
|
||||||
|
const cChunkDef::BiomeMap & a_Biomes,
|
||||||
|
sSetBlockVector & a_Blocks
|
||||||
|
) ;
|
||||||
|
|
||||||
|
int GetNumTrees(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
const cChunkDef::BiomeMap & a_Biomes
|
||||||
|
);
|
||||||
|
|
||||||
|
// cStructureGen override:
|
||||||
|
virtual void GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMetas, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cStructGenMarbleCaves :
|
||||||
|
public cStructureGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cStructGenMarbleCaves(int a_Seed) : m_Seed(a_Seed) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
int m_Seed;
|
||||||
|
|
||||||
|
// cStructureGen override:
|
||||||
|
virtual void GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cStructGenOreNests :
|
||||||
|
public cStructureGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cStructGenOreNests(int a_Seed) : m_Noise(a_Seed), m_Seed(a_Seed) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cNoise m_Noise;
|
||||||
|
int m_Seed;
|
||||||
|
|
||||||
|
// cStructureGen override:
|
||||||
|
virtual void GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) override;
|
||||||
|
|
||||||
|
void GenerateOre(int a_ChunkX, int a_ChunkZ, BLOCKTYPE a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, cChunkDef::BlockTypes & a_BlockTypes, int a_Seq);
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
546
source/Trees.cpp
Normal file
546
source/Trees.cpp
Normal file
|
@ -0,0 +1,546 @@
|
||||||
|
|
||||||
|
// Trees.cpp
|
||||||
|
|
||||||
|
// Implements helper functions used for generating trees
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "Trees.h"
|
||||||
|
#include "BlockID.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x, z;
|
||||||
|
} sCoords;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int x, z;
|
||||||
|
NIBBLETYPE Meta;
|
||||||
|
} sMetaCoords;
|
||||||
|
|
||||||
|
static const sCoords Corners[] =
|
||||||
|
{
|
||||||
|
{-1, -1},
|
||||||
|
{-1, 1},
|
||||||
|
{1, -1},
|
||||||
|
{1, 1},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static const sCoords BigO1[] =
|
||||||
|
{
|
||||||
|
{0, -1},
|
||||||
|
{-1, 0}, {1, 0},
|
||||||
|
{0, 1},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static const sCoords BigO2[] =
|
||||||
|
{
|
||||||
|
{-1, -2}, {0, -2}, {1, -2},
|
||||||
|
{-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {2, -1},
|
||||||
|
{-2, 0}, {-1, 0}, {1, 0}, {2, 0},
|
||||||
|
{-2, 1}, {-1, 1}, {0, 1}, {1, 1}, {2, 1},
|
||||||
|
{-1, 2}, {0, 2}, {1, 2},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
static const sCoords BigO3[] =
|
||||||
|
{
|
||||||
|
{-2, -3}, {-1, -3}, {0, -3}, {1, -3}, {2, -3},
|
||||||
|
{-3, -2}, {-2, -2}, {-1, -2}, {0, -2}, {1, -2}, {2, -2}, {3, -2},
|
||||||
|
{-3, -1}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {2, -1}, {3, -1},
|
||||||
|
{-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {2, 0}, {3, 0},
|
||||||
|
{-3, 1}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}, {2, 1}, {3, 1},
|
||||||
|
{-3, 2}, {-2, 2}, {-1, 2}, {0, 2}, {1, 2}, {2, 2}, {3, 2},
|
||||||
|
{-2, 3}, {-1, 3}, {0, 3}, {1, 3}, {2, 3},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const sCoords * Coords;
|
||||||
|
size_t Count;
|
||||||
|
} sCoordsArr;
|
||||||
|
|
||||||
|
static const sCoordsArr BigOs[] =
|
||||||
|
{
|
||||||
|
{BigO1, ARRAYCOUNT(BigO1)},
|
||||||
|
{BigO2, ARRAYCOUNT(BigO2)},
|
||||||
|
{BigO3, ARRAYCOUNT(BigO3)},
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Pushes a specified layer of blocks of the same type around (x, h, z) into a_Blocks
|
||||||
|
inline void PushCoordBlocks(int a_BlockX, int a_Height, int a_BlockZ, sSetBlockVector & a_Blocks, const sCoords * a_Coords, size_t a_NumCoords, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < a_NumCoords; i++)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX + a_Coords[i].x, a_Height, a_BlockZ + a_Coords[i].z, a_BlockType, a_Meta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void PushCornerBlocks(int a_BlockX, int a_Height, int a_BlockZ, int a_Seq, cNoise & a_Noise, int a_Chance, sSetBlockVector & a_Blocks, int a_CornersDist, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAYCOUNT(Corners); i++)
|
||||||
|
{
|
||||||
|
int x = a_BlockX + Corners[i].x;
|
||||||
|
int z = a_BlockZ + Corners[i].z;
|
||||||
|
if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height, z + 64 * a_Seq) <= a_Chance)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(x, a_Height, z, a_BlockType, a_Meta));
|
||||||
|
}
|
||||||
|
} // for i - Corners[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline void PushSomeColumns(int a_BlockX, int a_Height, int a_BlockZ, int a_ColumnHeight, int a_Seq, cNoise & a_Noise, int a_Chance, sSetBlockVector & a_Blocks, const sMetaCoords * a_Coords, size_t a_NumCoords, BLOCKTYPE a_BlockType)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < a_NumCoords; i++)
|
||||||
|
{
|
||||||
|
int x = a_BlockX + a_Coords[i].x;
|
||||||
|
int z = a_BlockZ + a_Coords[i].z;
|
||||||
|
if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height + i, z + 64 * a_Seq) <= a_Chance)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < a_ColumnHeight; j++)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(x, a_Height - j, z, a_BlockType, a_Coords[i].Meta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for i - a_Coords[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, EMCSBiome a_Biome, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
switch (a_Biome)
|
||||||
|
{
|
||||||
|
case biPlains:
|
||||||
|
case biExtremeHills:
|
||||||
|
case biExtremeHillsEdge:
|
||||||
|
case biForest:
|
||||||
|
case biMushroomIsland:
|
||||||
|
case biMushroomShore:
|
||||||
|
case biForestHills:
|
||||||
|
{
|
||||||
|
// Apple or birch trees:
|
||||||
|
if (a_Noise.IntNoise3DInt(a_BlockX, a_BlockY + 16 * a_Seq, a_BlockZ + 16 * a_Seq) < 0x5fffffff)
|
||||||
|
{
|
||||||
|
GetAppleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biTaiga:
|
||||||
|
case biIcePlains:
|
||||||
|
case biIceMountains:
|
||||||
|
case biTaigaHills:
|
||||||
|
{
|
||||||
|
// Conifers
|
||||||
|
GetConiferTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biSwampland:
|
||||||
|
{
|
||||||
|
// Swamp trees:
|
||||||
|
GetSwampTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biJungle:
|
||||||
|
case biJungleHills:
|
||||||
|
{
|
||||||
|
// Apple bushes, jungle trees
|
||||||
|
if (a_Noise.IntNoise3DInt(a_BlockX, a_BlockY + 16 * a_Seq, a_BlockZ + 16 * a_Seq) < 0x5fffffff)
|
||||||
|
{
|
||||||
|
GetAppleBushImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetJungleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
if (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY + 32 * a_Seq, a_BlockZ) < 0x60000000)
|
||||||
|
{
|
||||||
|
GetSmallAppleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetLargeAppleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetSmallAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
/* Small apple tree has:
|
||||||
|
- a top plus (no log)
|
||||||
|
- optional BigO1 + random corners (log)
|
||||||
|
- 2 layers of BigO2 + random corners (log)
|
||||||
|
- 1 to 3 blocks of trunk
|
||||||
|
*/
|
||||||
|
|
||||||
|
int Random = a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ) >> 3;
|
||||||
|
|
||||||
|
// Pre-alloc so that we don't realloc too often later:
|
||||||
|
a_Blocks.reserve(ARRAYCOUNT(BigO2) * 2 + ARRAYCOUNT(BigO1) + ARRAYCOUNT(Corners) * 3 + 3 + 5);
|
||||||
|
|
||||||
|
int Heights[] = {1, 2, 2, 3} ;
|
||||||
|
int Height = 1 + Heights[Random & 3];
|
||||||
|
Random >>= 2;
|
||||||
|
|
||||||
|
// Trunk:
|
||||||
|
for (int i = 0; i < Height; i++)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_APPLE));
|
||||||
|
}
|
||||||
|
int Hei = a_BlockY + Height;
|
||||||
|
|
||||||
|
// 2 BigO2 + corners layers:
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
PushCoordBlocks (a_BlockX, Hei, a_BlockZ, a_Blocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
PushCornerBlocks(a_BlockX, Hei, a_BlockZ, a_Seq, a_Noise, 0x5000000 - i * 0x10000000, a_Blocks, 2, E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Hei, a_BlockZ, E_BLOCK_LOG, E_META_LOG_APPLE));
|
||||||
|
Hei++;
|
||||||
|
} // for i - 2*
|
||||||
|
|
||||||
|
// Optional BigO1 + corners layer:
|
||||||
|
if ((Random & 1) == 0)
|
||||||
|
{
|
||||||
|
PushCoordBlocks (a_BlockX, Hei, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
PushCornerBlocks(a_BlockX, Hei, a_BlockZ, a_Seq, a_Noise, 0x6000000, a_Blocks, 1, E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Hei, a_BlockZ, E_BLOCK_LOG, E_META_LOG_APPLE));
|
||||||
|
Hei++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Top plus:
|
||||||
|
PushCoordBlocks(a_BlockX, Hei, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Hei, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_APPLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetLargeAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
int Height = 5 + (a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ) % 3);
|
||||||
|
|
||||||
|
// Prealloc, so that we don't realloc too often later:
|
||||||
|
a_Blocks.reserve(Height + 80);
|
||||||
|
|
||||||
|
// The entire trunk, out of logs:
|
||||||
|
for (int i = Height - 1; i >= 0; --i)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_BIRCH));
|
||||||
|
}
|
||||||
|
int h = a_BlockY + Height;
|
||||||
|
|
||||||
|
// Top layer - just the Plus:
|
||||||
|
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, h, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH)); // There's no log at this layer
|
||||||
|
h--;
|
||||||
|
|
||||||
|
// Second layer - log, Plus and maybe Corners:
|
||||||
|
PushCoordBlocks (a_BlockX, h, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_Blocks, 1, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
h--;
|
||||||
|
|
||||||
|
// Third and fourth layers - BigO2 and maybe 2*Corners:
|
||||||
|
for (int Row = 0; Row < 2; Row++)
|
||||||
|
{
|
||||||
|
PushCoordBlocks (a_BlockX, h, a_BlockZ, a_Blocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
PushCornerBlocks(a_BlockX, h, a_BlockZ, a_Seq, a_Noise, 0x3fffffff + Row * 0x10000000, a_Blocks, 2, E_BLOCK_LEAVES, E_META_LEAVES_BIRCH);
|
||||||
|
h--;
|
||||||
|
} // for Row - 2*
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// Half chance for a spruce, half for a pine:
|
||||||
|
if (a_Noise.IntNoise3DInt(a_BlockX + 64 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) < 0x40000000)
|
||||||
|
{
|
||||||
|
GetSpruceTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GetPineTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_Blocks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetSpruceTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// Spruces have a top section with layer sizes of (0, 1, 0) or only (1, 0),
|
||||||
|
// then 1 - 3 sections of ascending sizes (1, 2) [most often], (1, 3) or (1, 2, 3)
|
||||||
|
// and an optional bottom section of size 1, followed by 1 - 3 clear trunk blocks
|
||||||
|
|
||||||
|
// We'll use bits from this number as partial random numbers; but the noise function has mod8 irregularities
|
||||||
|
// (each of the mod8 remainders has a very different chance of occurrence) - that's why we divide by 8
|
||||||
|
int MyRandom = a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY + 32 * a_Seq, a_BlockZ) / 8;
|
||||||
|
|
||||||
|
// Prealloc, so that we don't realloc too often later:
|
||||||
|
a_Blocks.reserve(180);
|
||||||
|
|
||||||
|
// Clear trunk blocks:
|
||||||
|
static const int sHeights[] = {1, 2, 2, 3};
|
||||||
|
int Height = sHeights[MyRandom & 3];
|
||||||
|
MyRandom >>= 2;
|
||||||
|
for (int i = 0; i < Height; i++)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
}
|
||||||
|
Height += a_BlockY;
|
||||||
|
|
||||||
|
// Optional size-1 bottom leaves layer:
|
||||||
|
if ((MyRandom & 1) == 0)
|
||||||
|
{
|
||||||
|
PushCoordBlocks(a_BlockX, Height, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
Height++;
|
||||||
|
}
|
||||||
|
MyRandom >>= 1;
|
||||||
|
|
||||||
|
// 1 to 3 sections of leaves layers:
|
||||||
|
static const int sNumSections[] = {1, 2, 2, 3};
|
||||||
|
int NumSections = sNumSections[MyRandom & 3];
|
||||||
|
MyRandom >>= 2;
|
||||||
|
for (int i = 0; i < NumSections; i++)
|
||||||
|
{
|
||||||
|
switch (MyRandom & 3) // SectionType; (1, 2) twice as often as the other two
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
PushCoordBlocks(a_BlockX, Height, a_BlockZ, a_Blocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
PushCoordBlocks(a_BlockX, Height + 1, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 1, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
Height += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
{
|
||||||
|
PushCoordBlocks(a_BlockX, Height, a_BlockZ, a_Blocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
PushCoordBlocks(a_BlockX, Height + 1, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 1, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
Height += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
{
|
||||||
|
PushCoordBlocks(a_BlockX, Height, a_BlockZ, a_Blocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
PushCoordBlocks(a_BlockX, Height + 1, a_BlockZ, a_Blocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
PushCoordBlocks(a_BlockX, Height + 2, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 1, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 2, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
Height += 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (SectionType)
|
||||||
|
MyRandom >>= 2;
|
||||||
|
} // for i - Sections
|
||||||
|
|
||||||
|
if ((MyRandom & 1) == 0)
|
||||||
|
{
|
||||||
|
// (0, 1, 0) top:
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
PushCoordBlocks (a_BlockX, Height + 1, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 1, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER));
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 2, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// (1, 0) top:
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER));
|
||||||
|
PushCoordBlocks (a_BlockX, Height + 1, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, Height + 1, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// Tall, little leaves on top. The top leaves are arranged in a shape of two cones joined by their bases.
|
||||||
|
// There can be one or two layers representing the cone bases (SameSizeMax)
|
||||||
|
|
||||||
|
int MyRandom = a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 8;
|
||||||
|
int TrunkHeight = 8 + (MyRandom % 3);
|
||||||
|
int SameSizeMax = ((MyRandom & 8) == 0) ? 1 : 0;
|
||||||
|
MyRandom >>= 3;
|
||||||
|
int NumLeavesLayers = 2 + (MyRandom % 3); // Number of layers that have leaves in them
|
||||||
|
if (NumLeavesLayers == 2)
|
||||||
|
{
|
||||||
|
SameSizeMax = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-allocate the vector:
|
||||||
|
a_Blocks.reserve(TrunkHeight + NumLeavesLayers * 25);
|
||||||
|
|
||||||
|
// The entire trunk, out of logs:
|
||||||
|
for (int i = TrunkHeight; i >= 0; --i)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_CONIFER));
|
||||||
|
}
|
||||||
|
int h = a_BlockY + TrunkHeight + 2;
|
||||||
|
|
||||||
|
// Top layer - just a single leaves block:
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, h, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER));
|
||||||
|
h--;
|
||||||
|
|
||||||
|
// One more layer is above the trunk, push the central leaves:
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, h, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER));
|
||||||
|
|
||||||
|
// Layers expanding in size, then collapsing again:
|
||||||
|
// LOGD("Generating %d layers of pine leaves, SameSizeMax = %d", NumLeavesLayers, SameSizeMax);
|
||||||
|
for (int i = 0; i < NumLeavesLayers; ++i)
|
||||||
|
{
|
||||||
|
int LayerSize = min(i, NumLeavesLayers - i + SameSizeMax - 1);
|
||||||
|
// LOGD("LayerSize %d: %d", i, LayerSize);
|
||||||
|
if (LayerSize < 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ASSERT(LayerSize < ARRAYCOUNT(BigOs));
|
||||||
|
PushCoordBlocks(a_BlockX, h, a_BlockZ, a_Blocks, BigOs[LayerSize].Coords, BigOs[LayerSize].Count, E_BLOCK_LEAVES, E_META_LEAVES_CONIFER);
|
||||||
|
h--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetSwampTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// Vines are around the BigO3, but not in the corners; need proper meta for direction
|
||||||
|
static const sMetaCoords Vines[] =
|
||||||
|
{
|
||||||
|
{-2, -4, 1}, {-1, -4, 1}, {0, -4, 1}, {1, -4, 1}, {2, -4, 1}, // North face
|
||||||
|
{-2, 4, 4}, {-1, 4, 4}, {0, 4, 4}, {1, 4, 4}, {2, 4, 4}, // South face
|
||||||
|
{4, -2, 2}, {4, -1, 2}, {4, 0, 2}, {4, 1, 2}, {4, 2, 2}, // East face
|
||||||
|
{-4, -2, 8}, {-4, -1, 8}, {-4, 0, 8}, {-4, 1, 8}, {-4, 2, 8}, // West face
|
||||||
|
} ;
|
||||||
|
|
||||||
|
int Height = 3 + (a_Noise.IntNoise3DInt(a_BlockX + 32 * a_Seq, a_BlockY, a_BlockZ + 32 * a_Seq) / 8) % 3;
|
||||||
|
|
||||||
|
a_Blocks.reserve(2 * ARRAYCOUNT(BigO2) + 2 * ARRAYCOUNT(BigO3) + Height * ARRAYCOUNT(Vines) + 20);
|
||||||
|
|
||||||
|
for (int i = 0; i < Height; i++)
|
||||||
|
{
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, a_BlockY + i, a_BlockZ, E_BLOCK_LOG, E_META_LOG_APPLE));
|
||||||
|
}
|
||||||
|
int hei = a_BlockY + Height - 2;
|
||||||
|
|
||||||
|
// Put vines around the lowermost leaves layer:
|
||||||
|
PushSomeColumns(a_BlockX, hei, a_BlockZ, Height, a_Seq, a_Noise, 0x3fffffff, a_Blocks, Vines, ARRAYCOUNT(Vines), E_BLOCK_VINES);
|
||||||
|
|
||||||
|
// The lower two leaves layers are BigO3 with log in the middle and possibly corners:
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_Blocks, BigO3, ARRAYCOUNT(BigO3), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_Blocks, 3, E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
hei++;
|
||||||
|
} // for i - 2*
|
||||||
|
|
||||||
|
// The upper two leaves layers are BigO2 with leaves in the middle and possibly corners:
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_Blocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
PushCornerBlocks(a_BlockX, hei, a_BlockZ, a_Seq, a_Noise, 0x5fffffff, a_Blocks, 3, E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_APPLE));
|
||||||
|
hei++;
|
||||||
|
} // for i - 2*
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetAppleBushImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
a_Blocks.reserve(3 + ARRAYCOUNT(BigO2) + ARRAYCOUNT(BigO1));
|
||||||
|
|
||||||
|
int hei = a_BlockY;
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_LOG, E_META_LOG_JUNGLE));
|
||||||
|
PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_Blocks, BigO2, ARRAYCOUNT(BigO2), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
hei++;
|
||||||
|
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_APPLE));
|
||||||
|
PushCoordBlocks(a_BlockX, hei, a_BlockZ, a_Blocks, BigO1, ARRAYCOUNT(BigO1), E_BLOCK_LEAVES, E_META_LEAVES_APPLE);
|
||||||
|
hei++;
|
||||||
|
|
||||||
|
a_Blocks.push_back(sSetBlock(a_BlockX, hei, a_BlockZ, E_BLOCK_LEAVES, E_META_LEAVES_APPLE));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void GetJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
85
source/Trees.h
Normal file
85
source/Trees.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
|
||||||
|
// Trees.h
|
||||||
|
|
||||||
|
// Interfaces to helper functions used for generating trees
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that all of these functions must generate the same tree image for the same input (x, y, z, seq)
|
||||||
|
- cStructGenTrees depends on this
|
||||||
|
To generate a random image for the (x, y, z) coords, pass an arbitrary value as (seq).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ChunkDef.h"
|
||||||
|
#include "cNoise.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Blocks that don't block tree growth:
|
||||||
|
#define CASE_TREE_ALLOWED_BLOCKS \
|
||||||
|
case E_BLOCK_AIR: \
|
||||||
|
case E_BLOCK_LEAVES: \
|
||||||
|
case E_BLOCK_SNOW: \
|
||||||
|
case E_BLOCK_TALL_GRASS: \
|
||||||
|
case E_BLOCK_DEAD_BUSH: \
|
||||||
|
case E_BLOCK_SAPLING: \
|
||||||
|
case E_BLOCK_VINES
|
||||||
|
|
||||||
|
// Blocks that a tree may overwrite when growing:
|
||||||
|
#define CASE_TREE_OVERWRITTEN_BLOCKS \
|
||||||
|
case E_BLOCK_AIR: \
|
||||||
|
case E_BLOCK_LEAVES: \
|
||||||
|
case E_BLOCK_SNOW: \
|
||||||
|
case E_BLOCK_TALL_GRASS: \
|
||||||
|
case E_BLOCK_DEAD_BUSH: \
|
||||||
|
case E_BLOCK_SAPLING: \
|
||||||
|
case E_BLOCK_VINES
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Generates an image of a tree at the specified coords (lowest trunk block) in the specified biome
|
||||||
|
void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, EMCSBiome a_Biome, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random apple tree
|
||||||
|
void GetAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a small (nonbranching) apple tree
|
||||||
|
void GetSmallAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a large (branching) apple tree
|
||||||
|
void GetLargeAppleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random birch tree
|
||||||
|
void GetBirchTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random conifer tree
|
||||||
|
void GetConiferTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random spruce (short conifer, two layers of leaves)
|
||||||
|
void GetSpruceTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random pine (tall conifer, little leaves at top)
|
||||||
|
void GetPineTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random swampland tree
|
||||||
|
void GetSwampTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random apple bush (for jungles)
|
||||||
|
void GetAppleBushImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
/// Generates an image of a random jungle tree
|
||||||
|
void GetJungleTreeImage(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_Noise, int a_Seq, sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
|
|
||||||
// WGFlat.cpp
|
|
||||||
|
|
||||||
// Implements the cWGFlat class representing the flat world generator
|
|
||||||
|
|
||||||
#include "Globals.h"
|
|
||||||
#include "WGFlat.h"
|
|
||||||
#include "../iniFile/iniFile.h"
|
|
||||||
#include "cWorld.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cWGFlat::cWGFlat(cWorld * a_World) :
|
|
||||||
super(a_World)
|
|
||||||
{
|
|
||||||
// Load the settings from the INI file:
|
|
||||||
cIniFile INI(a_World->GetIniFileName());
|
|
||||||
INI.ReadFile();
|
|
||||||
m_Height = INI.GetValueI("flat", "height", 5);
|
|
||||||
if (m_Height < 1)
|
|
||||||
{
|
|
||||||
m_Height = 1;
|
|
||||||
}
|
|
||||||
if (m_Height > 250)
|
|
||||||
{
|
|
||||||
m_Height = 250;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWGFlat::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
|
||||||
{
|
|
||||||
int SliceSize = cChunkDef::Width * cChunkDef::Width;
|
|
||||||
memset(a_BlockData, E_BLOCK_BEDROCK, SliceSize);
|
|
||||||
switch (m_Height)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// Just the bedrock layer
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
{
|
|
||||||
// Bedrock + 1 dirt layer:
|
|
||||||
memset(a_BlockData + SliceSize, E_BLOCK_GRASS, SliceSize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 3:
|
|
||||||
{
|
|
||||||
// Bedrock + 2 dirt layers:
|
|
||||||
memset(a_BlockData + SliceSize, E_BLOCK_DIRT, SliceSize);
|
|
||||||
memset(a_BlockData + 2 * SliceSize, E_BLOCK_GRASS, SliceSize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 4:
|
|
||||||
{
|
|
||||||
// Bedrock + 3 dirt layers:
|
|
||||||
memset(a_BlockData + SliceSize, E_BLOCK_DIRT, 2 * SliceSize);
|
|
||||||
memset(a_BlockData + 3 * SliceSize, E_BLOCK_GRASS, SliceSize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
// Bedrock + stone layers + 3 dirt layers:
|
|
||||||
memset(a_BlockData + SliceSize, E_BLOCK_STONE, SliceSize * (m_Height - 4));
|
|
||||||
memset(a_BlockData + SliceSize * (m_Height - 3), E_BLOCK_DIRT, SliceSize * 2);
|
|
||||||
memset(a_BlockData + SliceSize * (m_Height - 1), E_BLOCK_GRASS, SliceSize);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memset(a_BlockData + SliceSize * m_Height, E_BLOCK_AIR, cChunkDef::NumBlocks - SliceSize * m_Height);
|
|
||||||
|
|
||||||
SliceSize /= 2; // Nibbles from now on
|
|
||||||
BLOCKTYPE * Meta = a_BlockData + cChunkDef::NumBlocks;
|
|
||||||
memset(Meta, 0, cChunkDef::NumBlocks / 2);
|
|
||||||
|
|
||||||
BLOCKTYPE * SkyLight = Meta + cChunkDef::NumBlocks / 2;
|
|
||||||
memset(SkyLight, 0, m_Height * SliceSize);
|
|
||||||
memset(SkyLight + m_Height * SliceSize, 0xff, cChunkDef::NumBlocks / 2 - m_Height * SliceSize);
|
|
||||||
|
|
||||||
BLOCKTYPE * BlockLight = SkyLight + cChunkDef::NumBlocks / 2;
|
|
||||||
memset(BlockLight, 0, cChunkDef::NumBlocks / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWGFlat::PostGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|
||||||
{
|
|
||||||
// Nothing needed yet, just don't call the parent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
|
|
||||||
// WGFlat.h
|
|
||||||
|
|
||||||
// Interfaces to the cWGFlat class representing the flat world generator
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "cWorldGenerator.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cWGFlat :
|
|
||||||
public cWorldGenerator
|
|
||||||
{
|
|
||||||
typedef cWorldGenerator super;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
int m_Height;
|
|
||||||
|
|
||||||
virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities) override;
|
|
||||||
virtual void PostGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ) override;
|
|
||||||
|
|
||||||
public:
|
|
||||||
cWGFlat(cWorld * a_World);
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "WSSAnvil.h"
|
#include "WSSAnvil.h"
|
||||||
#include "cWorld.h"
|
#include "cWorld.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include "NBT.h"
|
|
||||||
#include "BlockID.h"
|
#include "BlockID.h"
|
||||||
#include "cChestEntity.h"
|
#include "cChestEntity.h"
|
||||||
#include "cItem.h"
|
#include "cItem.h"
|
||||||
|
@ -26,7 +25,7 @@ Since only the header is actually in the memory, this number can be high, but st
|
||||||
*/
|
*/
|
||||||
#define MAX_MCA_FILES 32
|
#define MAX_MCA_FILES 32
|
||||||
|
|
||||||
/// The maximum size of an inflated chunk
|
/// The maximum size of an inflated chunk; raw chunk data is 192 KiB, allow 64 KiB more of entities
|
||||||
#define CHUNK_INFLATE_MAX 256 KiB
|
#define CHUNK_INFLATE_MAX 256 KiB
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +44,8 @@ public:
|
||||||
m_Writer(a_Writer),
|
m_Writer(a_Writer),
|
||||||
m_IsTagOpen(false),
|
m_IsTagOpen(false),
|
||||||
m_HasHadEntity(false),
|
m_HasHadEntity(false),
|
||||||
m_HasHadBlockEntity(false)
|
m_HasHadBlockEntity(false),
|
||||||
|
m_IsLightValid(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,6 +59,9 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool IsLightValid(void) const {return m_IsLightValid; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/* From cChunkDataSeparateCollector we inherit:
|
/* From cChunkDataSeparateCollector we inherit:
|
||||||
|
@ -75,6 +78,7 @@ protected:
|
||||||
bool m_IsTagOpen; // True if a tag has been opened in the callbacks and not yet closed.
|
bool m_IsTagOpen; // True if a tag has been opened in the callbacks and not yet closed.
|
||||||
bool m_HasHadEntity; // True if any Entity has already been received and processed
|
bool m_HasHadEntity; // True if any Entity has already been received and processed
|
||||||
bool m_HasHadBlockEntity; // True if any BlockEntity has already been received and processed
|
bool m_HasHadBlockEntity; // True if any BlockEntity has already been received and processed
|
||||||
|
bool m_IsLightValid; // True if the chunk lighting is valid
|
||||||
|
|
||||||
|
|
||||||
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID)
|
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID)
|
||||||
|
@ -89,10 +93,10 @@ protected:
|
||||||
void AddItem(cItem * a_Item, int a_Slot)
|
void AddItem(cItem * a_Item, int a_Slot)
|
||||||
{
|
{
|
||||||
m_Writer.BeginCompound("");
|
m_Writer.BeginCompound("");
|
||||||
m_Writer.AddShort("id", a_Item->m_ItemID);
|
m_Writer.AddShort("id", (short)(a_Item->m_ItemID));
|
||||||
m_Writer.AddShort("Damage", a_Item->m_ItemHealth);
|
m_Writer.AddShort("Damage", a_Item->m_ItemHealth);
|
||||||
m_Writer.AddByte ("Count", a_Item->m_ItemCount);
|
m_Writer.AddByte ("Count", a_Item->m_ItemCount);
|
||||||
m_Writer.AddByte ("Slot", a_Slot);
|
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
|
||||||
m_Writer.EndCompound();
|
m_Writer.EndCompound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,6 +120,13 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virtual bool LightIsValid(bool a_IsLightValid) override
|
||||||
|
{
|
||||||
|
m_IsLightValid = a_IsLightValid;
|
||||||
|
return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
virtual void Entity(cEntity * a_Entity) override
|
virtual void Entity(cEntity * a_Entity) override
|
||||||
{
|
{
|
||||||
// TODO: Add entity into NBT:
|
// TODO: Add entity into NBT:
|
||||||
|
@ -363,12 +374,6 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Writer.Finish();
|
Writer.Finish();
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
cParsedNBT TestParse(Writer.GetResult().data(), Writer.GetResult().size());
|
|
||||||
ASSERT(TestParse.IsValid());
|
|
||||||
#endif // _DEBUG
|
|
||||||
|
|
||||||
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data);
|
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -380,13 +385,15 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||||
bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT)
|
bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT & a_NBT)
|
||||||
{
|
{
|
||||||
// The data arrays, in MCA-native y/z/x ordering (will be reordered for the final chunk data)
|
// The data arrays, in MCA-native y/z/x ordering (will be reordered for the final chunk data)
|
||||||
BLOCKTYPE BlockData[cChunkDef::BlockDataSize];
|
cChunkDef::BlockTypes BlockTypes;
|
||||||
BLOCKTYPE * MetaData = BlockData + cChunkDef::MetaOffset;
|
cChunkDef::BlockNibbles MetaData;
|
||||||
BLOCKTYPE * BlockLight = BlockData + cChunkDef::LightOffset;
|
cChunkDef::BlockNibbles BlockLight;
|
||||||
BLOCKTYPE * SkyLight = BlockData + cChunkDef::SkyLightOffset;
|
cChunkDef::BlockNibbles SkyLight;
|
||||||
|
|
||||||
memset(BlockData, E_BLOCK_AIR, sizeof(BlockData) - cChunkDef::NumBlocks / 2);
|
memset(BlockTypes, E_BLOCK_AIR, sizeof(BlockTypes));
|
||||||
memset(SkyLight, 0xff, cChunkDef::NumBlocks / 2); // By default, data not present in the NBT means air, which means full skylight
|
memset(MetaData, 0, sizeof(MetaData));
|
||||||
|
memset(SkyLight, 0xff, sizeof(SkyLight)); // By default, data not present in the NBT means air, which means full skylight
|
||||||
|
memset(BlockLight, 0x00, sizeof(BlockLight));
|
||||||
|
|
||||||
// Load the blockdata, blocklight and skylight:
|
// Load the blockdata, blocklight and skylight:
|
||||||
int Level = a_NBT.FindChildByName(0, "Level");
|
int Level = a_NBT.FindChildByName(0, "Level");
|
||||||
|
@ -412,56 +419,26 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CopyNBTData(a_NBT, Child, "Blocks", &(BlockData[y * 4096]), 4096);
|
CopyNBTData(a_NBT, Child, "Blocks", (char *)&(BlockTypes[y * 4096]), 4096);
|
||||||
CopyNBTData(a_NBT, Child, "Data", &(MetaData[y * 2048]), 2048);
|
CopyNBTData(a_NBT, Child, "Data", (char *)&(MetaData[y * 2048]), 2048);
|
||||||
CopyNBTData(a_NBT, Child, "SkyLight", &(SkyLight[y * 2048]), 2048);
|
CopyNBTData(a_NBT, Child, "SkyLight", (char *)&(SkyLight[y * 2048]), 2048);
|
||||||
CopyNBTData(a_NBT, Child, "BlockLight", &(BlockLight[y * 2048]), 2048);
|
CopyNBTData(a_NBT, Child, "BlockLight", (char *)&(BlockLight[y * 2048]), 2048);
|
||||||
} // for itr - LevelSections[]
|
} // for itr - LevelSections[]
|
||||||
|
|
||||||
cEntityList Entities;
|
// Load the biomes from NBT, if present and valid:
|
||||||
cBlockEntityList BlockEntities;
|
cChunkDef::BiomeMap BiomeMap;
|
||||||
|
cChunkDef::BiomeMap * Biomes = LoadBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes"));
|
||||||
|
|
||||||
// Load the entities from NBT:
|
// Load the entities from NBT:
|
||||||
|
cEntityList Entities;
|
||||||
|
cBlockEntityList BlockEntities;
|
||||||
LoadEntitiesFromNBT (Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities"));
|
LoadEntitiesFromNBT (Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities"));
|
||||||
LoadBlockEntitiesFromNBT(BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"));
|
LoadBlockEntitiesFromNBT(BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"));
|
||||||
|
|
||||||
#if (AXIS_ORDER == AXIS_ORDER_YZX)
|
bool IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0);
|
||||||
// Reorder the chunk data - walk the MCA-formatted data sequentially and copy it into the right place in the ChunkData:
|
|
||||||
BLOCKTYPE ChunkData[cChunkDef::BlockDataSize];
|
|
||||||
memset(ChunkData, 0, sizeof(ChunkData));
|
|
||||||
int Index = 0; // Index into the MCA-formatted data, incremented sequentially
|
|
||||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
ChunkData[cChunk::MakeIndex(x, y, z)] = BlockData[Index];
|
|
||||||
Index++;
|
|
||||||
} // for y/z/x
|
|
||||||
BLOCKTYPE * ChunkMeta = ChunkData + cChunkDef::NumBlocks;
|
|
||||||
Index = 0;
|
|
||||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
cChunk::SetNibble(ChunkMeta, x, y, z, MetaData[Index / 2] >> ((Index % 2) * 4));
|
|
||||||
Index++;
|
|
||||||
} // for y/z/x
|
|
||||||
BLOCKTYPE * ChunkBlockLight = ChunkMeta + cChunkDef::NumBlocks / 2;
|
|
||||||
Index = 0;
|
|
||||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
cChunk::SetNibble(ChunkBlockLight, x, y, z, BlockLight[Index / 2] >> ((Index % 2) * 4));
|
|
||||||
Index++;
|
|
||||||
} // for y/z/x
|
|
||||||
BLOCKTYPE * ChunkSkyLight = ChunkBlockLight + cChunkDef::NumBlocks / 2;
|
|
||||||
Index = 0;
|
|
||||||
for (int y = 0; y < cChunkDef::Height; y++) for (int z = 0; z < cChunkDef::Width; z++) for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
cChunk::SetNibble(ChunkSkyLight, x, y, z, SkyLight[Index / 2] >> ((Index % 2) * 4));
|
|
||||||
Index++;
|
|
||||||
} // for y/z/x
|
|
||||||
#else // AXIS_ORDER_YZX
|
|
||||||
BLOCKTYPE * ChunkData = BlockData;
|
|
||||||
#endif // else AXIS_ORDER_YZX
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Delete the comment above for really cool stuff :)
|
// Uncomment this block for really cool stuff :)
|
||||||
// DEBUG magic: Invert the underground, so that we can see the MC generator in action :)
|
// DEBUG magic: Invert the underground, so that we can see the MC generator in action :)
|
||||||
bool ShouldInvert[cChunkDef::Width * cChunkDef::Width];
|
bool ShouldInvert[cChunkDef::Width * cChunkDef::Width];
|
||||||
memset(ShouldInvert, 0, sizeof(ShouldInvert));
|
memset(ShouldInvert, 0, sizeof(ShouldInvert));
|
||||||
|
@ -484,15 +461,14 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||||
memset(ChunkData + cChunkDef::SkyLightOffset, 0xff, cChunkDef::NumBlocks / 2);
|
memset(ChunkData + cChunkDef::SkyLightOffset, 0xff, cChunkDef::NumBlocks / 2);
|
||||||
//*/
|
//*/
|
||||||
|
|
||||||
m_World->ChunkDataLoaded(
|
m_World->SetChunkData(
|
||||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ,
|
a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ,
|
||||||
ChunkData,
|
BlockTypes, MetaData,
|
||||||
ChunkData + cChunkDef::MetaOffset,
|
IsLightValid ? BlockLight : NULL,
|
||||||
ChunkData + cChunkDef::LightOffset,
|
IsLightValid ? SkyLight : NULL,
|
||||||
ChunkData + cChunkDef::SkyLightOffset,
|
NULL, Biomes,
|
||||||
NULL,
|
Entities, BlockEntities,
|
||||||
Entities,
|
false
|
||||||
BlockEntities
|
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -525,24 +501,37 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
|
||||||
}
|
}
|
||||||
Serializer.Finish(); // Close NBT tags
|
Serializer.Finish(); // Close NBT tags
|
||||||
|
|
||||||
// TODO: Save biomes:
|
// TODO: Save biomes, both MCS (IntArray) and MC-vanilla (ByteArray):
|
||||||
// Level->Add(new cNBTByteArray(Level, "Biomes", AString(Serializer.m_Biomes, sizeof(Serializer.m_Biomes));
|
// Level->Add(new cNBTByteArray(Level, "Biomes", AString(Serializer.m_Biomes, sizeof(Serializer.m_Biomes));
|
||||||
|
// Level->Add(new cNBTByteArray(Level, "MCSBiomes", AString(Serializer.m_Biomes, sizeof(Serializer.m_Biomes));
|
||||||
|
|
||||||
// Save blockdata:
|
// Save blockdata:
|
||||||
a_Writer.BeginList("Sections", TAG_Compound);
|
a_Writer.BeginList("Sections", TAG_Compound);
|
||||||
int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
|
int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
|
||||||
int SliceSizeNibble = SliceSizeBlock / 2;
|
int SliceSizeNibble = SliceSizeBlock / 2;
|
||||||
|
const char * BlockTypes = (const char *)(Serializer.m_BlockTypes);
|
||||||
|
const char * BlockMetas = (const char *)(Serializer.m_BlockMetas);
|
||||||
|
const char * BlockLight = (const char *)(Serializer.m_BlockLight);
|
||||||
|
const char * BlockSkyLight = (const char *)(Serializer.m_BlockSkyLight);
|
||||||
for (int Y = 0; Y < 16; Y++)
|
for (int Y = 0; Y < 16; Y++)
|
||||||
{
|
{
|
||||||
a_Writer.BeginCompound("");
|
a_Writer.BeginCompound("");
|
||||||
a_Writer.AddByteArray("Blocks", Serializer.m_BlockTypes + Y * SliceSizeBlock, SliceSizeBlock);
|
a_Writer.AddByteArray("Blocks", BlockTypes + Y * SliceSizeBlock, SliceSizeBlock);
|
||||||
a_Writer.AddByteArray("Data", Serializer.m_BlockMetas + Y * SliceSizeNibble, SliceSizeNibble);
|
a_Writer.AddByteArray("Data", BlockMetas + Y * SliceSizeNibble, SliceSizeNibble);
|
||||||
a_Writer.AddByteArray("SkyLight", Serializer.m_BlockSkyLight + Y * SliceSizeNibble, SliceSizeNibble);
|
a_Writer.AddByteArray("SkyLight", BlockSkyLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||||
a_Writer.AddByteArray("BlockLight", Serializer.m_BlockLight + Y * SliceSizeNibble, SliceSizeNibble);
|
a_Writer.AddByteArray("BlockLight", BlockLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||||
a_Writer.AddByte("Y", Y);
|
a_Writer.AddByte("Y", (unsigned char)Y);
|
||||||
a_Writer.EndCompound();
|
a_Writer.EndCompound();
|
||||||
}
|
}
|
||||||
a_Writer.EndList(); // "Sections"
|
a_Writer.EndList(); // "Sections"
|
||||||
|
|
||||||
|
// Store the information that the lighting is valid.
|
||||||
|
// For compatibility reason, the default is "invalid" (missing) - this means older data is re-lighted upon loading.
|
||||||
|
if (Serializer.IsLightValid())
|
||||||
|
{
|
||||||
|
a_Writer.AddByte("MCSIsLightValid", 1);
|
||||||
|
}
|
||||||
|
|
||||||
a_Writer.EndCompound(); // "Level"
|
a_Writer.EndCompound(); // "Level"
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -551,6 +540,33 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cChunkDef::BiomeMap * cWSSAnvil::LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
|
{
|
||||||
|
if ((a_TagIdx < 0) || (a_NBT.GetType(a_TagIdx) != TAG_ByteArray))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (a_NBT.GetDataLength(a_TagIdx) != sizeof(*a_BiomeMap))
|
||||||
|
{
|
||||||
|
// The biomes stored don't match in size
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memcpy(a_BiomeMap, a_NBT.GetData(a_TagIdx), sizeof(*a_BiomeMap));
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(*a_BiomeMap); i++)
|
||||||
|
{
|
||||||
|
if ((*a_BiomeMap)[i] == 0xff)
|
||||||
|
{
|
||||||
|
// Unassigned biomes
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a_BiomeMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_TagIdx)
|
void cWSSAnvil::LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||||
{
|
{
|
||||||
// TODO: Load the entities
|
// TODO: Load the entities
|
||||||
|
@ -672,12 +688,35 @@ bool cWSSAnvil::GetBlockEntityNBTPos(const cParsedNBT & a_NBT, int a_TagIdx, int
|
||||||
cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_RegionZ) :
|
cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_RegionZ) :
|
||||||
m_RegionX(a_RegionX),
|
m_RegionX(a_RegionX),
|
||||||
m_RegionZ(a_RegionZ),
|
m_RegionZ(a_RegionZ),
|
||||||
m_File(a_FileName, cFile::fmReadWrite),
|
|
||||||
m_FileName(a_FileName)
|
m_FileName(a_FileName)
|
||||||
{
|
{
|
||||||
if (!m_File.IsOpen())
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWSSAnvil::cMCAFile::OpenFile(bool a_IsForReading)
|
||||||
|
{
|
||||||
|
if (m_File.IsOpen())
|
||||||
{
|
{
|
||||||
return;
|
// Already open
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a_IsForReading)
|
||||||
|
{
|
||||||
|
if (!cFile::Exists(m_FileName))
|
||||||
|
{
|
||||||
|
// We want to read and the file doesn't exist. Fail.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_File.Open(m_FileName, cFile::fmReadWrite))
|
||||||
|
{
|
||||||
|
// The file failed to open
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the header:
|
// Load the header:
|
||||||
|
@ -687,15 +726,16 @@ cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_R
|
||||||
// Try writing a NULL header (both chunk offsets and timestamps):
|
// Try writing a NULL header (both chunk offsets and timestamps):
|
||||||
memset(m_Header, 0, sizeof(m_Header));
|
memset(m_Header, 0, sizeof(m_Header));
|
||||||
if (
|
if (
|
||||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) ||
|
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) || // Real header - chunk offsets
|
||||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header))
|
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) // Bogus data for the chunk timestamps
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
LOGWARNING("Cannot process MCA header in file \"%s\", chunks in that file will be lost", m_FileName.c_str());
|
LOGWARNING("Cannot process MCA header in file \"%s\", chunks in that file will be lost", m_FileName.c_str());
|
||||||
m_File.Close();
|
m_File.Close();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -704,10 +744,11 @@ cWSSAnvil::cMCAFile::cMCAFile(const AString & a_FileName, int a_RegionX, int a_R
|
||||||
|
|
||||||
bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data)
|
bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||||
{
|
{
|
||||||
if (!m_File.IsOpen())
|
if (!OpenFile(true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LocalX = a_Chunk.m_ChunkX % 32;
|
int LocalX = a_Chunk.m_ChunkX % 32;
|
||||||
if (LocalX < 0)
|
if (LocalX < 0)
|
||||||
{
|
{
|
||||||
|
@ -720,7 +761,6 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
|
||||||
}
|
}
|
||||||
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
|
unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]);
|
||||||
unsigned ChunkOffset = ChunkLocation >> 8;
|
unsigned ChunkOffset = ChunkLocation >> 8;
|
||||||
unsigned ChunkLen = ChunkLocation & 0xff;
|
|
||||||
|
|
||||||
m_File.Seek(ChunkOffset * 4096);
|
m_File.Seek(ChunkOffset * 4096);
|
||||||
|
|
||||||
|
@ -753,10 +793,11 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a
|
||||||
|
|
||||||
bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AString & a_Data)
|
||||||
{
|
{
|
||||||
if (!m_File.IsOpen())
|
if (!OpenFile(false))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LocalX = a_Chunk.m_ChunkX % 32;
|
int LocalX = a_Chunk.m_ChunkX % 32;
|
||||||
if (LocalX < 0)
|
if (LocalX < 0)
|
||||||
{
|
{
|
||||||
|
@ -782,7 +823,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_File.Write(a_Data.data(), a_Data.size()) != a_Data.size())
|
if (m_File.Write(a_Data.data(), a_Data.size()) != (int)(a_Data.size()))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ enum
|
||||||
class cNBTTag;
|
class cNBTTag;
|
||||||
class cNBTList;
|
class cNBTList;
|
||||||
class cNBTCompound;
|
class cNBTCompound;
|
||||||
|
class cNBTByteArray;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,6 +82,9 @@ protected:
|
||||||
|
|
||||||
/// Finds a free location large enough to hold a_Data. Gets a hint of the chunk coords, places the data there if it fits. Returns the sector number.
|
/// Finds a free location large enough to hold a_Data. Gets a hint of the chunk coords, places the data there if it fits. Returns the sector number.
|
||||||
unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, const AString & a_Data);
|
unsigned FindFreeLocation(int a_LocalX, int a_LocalZ, const AString & a_Data);
|
||||||
|
|
||||||
|
/// Opens a MCA file either for a Read operation (fails if doesn't exist) or for a Write operation (creates new if not found)
|
||||||
|
bool OpenFile(bool a_IsForReading);
|
||||||
} ;
|
} ;
|
||||||
typedef std::list<cMCAFile *> cMCAFiles;
|
typedef std::list<cMCAFile *> cMCAFiles;
|
||||||
|
|
||||||
|
@ -105,6 +109,9 @@ protected:
|
||||||
/// Saves the chunk into NBT data using a_Writer; returns true on success
|
/// Saves the chunk into NBT data using a_Writer; returns true on success
|
||||||
bool SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer);
|
bool SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_Writer);
|
||||||
|
|
||||||
|
/// Loads the chunk's biome map; returns a_BiomeMap if biomes present and valid, NULL otherwise
|
||||||
|
cChunkDef::BiomeMap * LoadBiomeMapFromNBT(cChunkDef::BiomeMap * a_BiomeMap, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||||
|
|
||||||
/// Loads the chunk's entities from NBT data (a_Tag is the Level\\Entities list tag; may be -1)
|
/// Loads the chunk's entities from NBT data (a_Tag is the Level\\Entities list tag; may be -1)
|
||||||
void LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_Tag);
|
void LoadEntitiesFromNBT(cEntityList & a_Entitites, const cParsedNBT & a_NBT, int a_Tag);
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,73 @@ const int MAX_DIRTY_CHUNKS = 16;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// cJsonChunkSerializer:
|
||||||
|
|
||||||
|
cJsonChunkSerializer::cJsonChunkSerializer(void) :
|
||||||
|
m_HasJsonData(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cJsonChunkSerializer::Entity(cEntity * a_Entity)
|
||||||
|
{
|
||||||
|
// TODO: a_Entity->SaveToJson(m_Root);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
|
||||||
|
{
|
||||||
|
const char * SaveInto = NULL;
|
||||||
|
switch (a_BlockEntity->GetBlockType())
|
||||||
|
{
|
||||||
|
case E_BLOCK_CHEST: SaveInto = "Chests"; break;
|
||||||
|
case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break;
|
||||||
|
case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break;
|
||||||
|
case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
ASSERT(!"Unhandled blocktype in BlockEntities list while saving to JSON");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (BlockEntity->GetBlockType())
|
||||||
|
if (SaveInto == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value val;
|
||||||
|
a_BlockEntity->SaveToJson(val);
|
||||||
|
m_Root[SaveInto].append(val);
|
||||||
|
m_HasJsonData = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cJsonChunkSerializer::LightIsValid(bool a_IsLightValid)
|
||||||
|
{
|
||||||
|
if (!a_IsLightValid)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_Root["IsLightValid"] = true;
|
||||||
|
m_HasJsonData = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWSSCompact:
|
// cWSSCompact:
|
||||||
|
|
||||||
|
@ -564,7 +631,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
|
||||||
Offset += Header->m_CompressedSize;
|
Offset += Header->m_CompressedSize;
|
||||||
|
|
||||||
// Crude data integrity check:
|
// Crude data integrity check:
|
||||||
int ExpectedSize = (16*256*16)*2 + (16*256*16)/2; // For version 2
|
const int ExpectedSize = (16*256*16)*2 + (16*256*16)/2; // For version 2
|
||||||
if (UncompressedSize < ExpectedSize)
|
if (UncompressedSize < ExpectedSize)
|
||||||
{
|
{
|
||||||
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing",
|
LOGWARNING("Chunk [%d, %d] has too short decompressed data (%d bytes out of %d needed), erasing",
|
||||||
|
@ -600,18 +667,18 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::auto_ptr<char> ConvertedData(new char[ ExpectedSize ]);
|
char ConvertedData[ExpectedSize];
|
||||||
memset( ConvertedData.get(), 0, ExpectedSize );
|
memset(ConvertedData, 0, ExpectedSize);
|
||||||
|
|
||||||
// Cannot use cChunk::MakeIndex because it might change again?????????
|
// Cannot use cChunk::MakeIndex because it might change again?????????
|
||||||
// For compatibility, use what we know is current
|
// For compatibility, use what we know is current
|
||||||
#define MAKE_2_INDEX( x, y, z ) ( y + (z * 256) + (x * 256 * 16) )
|
#define MAKE_2_INDEX( x, y, z ) ( y + (z * 256) + (x * 256 * 16) )
|
||||||
#define MAKE_3_INDEX( x, y, z ) ( x + (z * 16) + (y * 16 * 16) )
|
#define MAKE_3_INDEX( x, y, z ) ( x + (z * 16) + (y * 16 * 16) )
|
||||||
|
|
||||||
unsigned int InChunkOffset = 0;
|
unsigned int InChunkOffset = 0;
|
||||||
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y ) // YZX Loop order is important, in 1.1 Y was first then Z then X
|
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y ) // YZX Loop order is important, in 1.1 Y was first then Z then X
|
||||||
{
|
{
|
||||||
ConvertedData.get()[ MAKE_3_INDEX(x, y, z) ] = UncompressedData[InChunkOffset];
|
ConvertedData[ MAKE_3_INDEX(x, y, z) ] = UncompressedData[InChunkOffset];
|
||||||
++InChunkOffset;
|
++InChunkOffset;
|
||||||
} // for y, z, x
|
} // for y, z, x
|
||||||
|
|
||||||
|
@ -619,29 +686,29 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
|
||||||
unsigned int index2 = 0;
|
unsigned int index2 = 0;
|
||||||
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y )
|
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y )
|
||||||
{
|
{
|
||||||
ConvertedData.get()[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4) ) & 0x0f ) << ((x&1)*4);
|
ConvertedData[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4) ) & 0x0f ) << ((x&1)*4);
|
||||||
++index2;
|
++index2;
|
||||||
}
|
}
|
||||||
InChunkOffset += index2/2;
|
InChunkOffset += index2 / 2;
|
||||||
index2 = 0;
|
index2 = 0;
|
||||||
|
|
||||||
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y )
|
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y )
|
||||||
{
|
{
|
||||||
ConvertedData.get()[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4) ) & 0x0f ) << ((x&1)*4);
|
ConvertedData[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4) ) & 0x0f ) << ((x&1)*4);
|
||||||
++index2;
|
++index2;
|
||||||
}
|
}
|
||||||
InChunkOffset += index2/2;
|
InChunkOffset += index2 / 2;
|
||||||
index2 = 0;
|
index2 = 0;
|
||||||
|
|
||||||
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y )
|
for( int x = 0; x < 16; ++x ) for( int z = 0; z < 16; ++z ) for( int y = 0; y < 256; ++y )
|
||||||
{
|
{
|
||||||
ConvertedData.get()[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4) ) & 0x0f ) << ((x&1)*4);
|
ConvertedData[ InChunkOffset + MAKE_3_INDEX(x, y, z)/2 ] |= ( (UncompressedData[ InChunkOffset + index2/2 ] >> ((index2&1)*4) ) & 0x0f ) << ((x&1)*4);
|
||||||
++index2;
|
++index2;
|
||||||
}
|
}
|
||||||
InChunkOffset += index2/2;
|
InChunkOffset += index2 / 2;
|
||||||
index2 = 0;
|
index2 = 0;
|
||||||
|
|
||||||
AString Converted(ConvertedData.get(), ExpectedSize);
|
AString Converted(ConvertedData, ExpectedSize);
|
||||||
|
|
||||||
// Add JSON data afterwards
|
// Add JSON data afterwards
|
||||||
if (UncompressedData.size() > InChunkOffset)
|
if (UncompressedData.size() > InChunkOffset)
|
||||||
|
@ -717,6 +784,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
|
||||||
|
|
||||||
cEntityList Entities;
|
cEntityList Entities;
|
||||||
cBlockEntityList BlockEntities;
|
cBlockEntityList BlockEntities;
|
||||||
|
bool IsLightValid = false;
|
||||||
|
|
||||||
if (a_UncompressedSize > cChunkDef::BlockDataSize)
|
if (a_UncompressedSize > cChunkDef::BlockDataSize)
|
||||||
{
|
{
|
||||||
|
@ -731,20 +799,23 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LoadEntitiesFromJson(root, Entities, BlockEntities, a_World);
|
LoadEntitiesFromJson(root, Entities, BlockEntities, a_World);
|
||||||
|
IsLightValid = root.get("IsLightValid", false).asBool();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BLOCKTYPE * BlockData = (BLOCKTYPE *)UncompressedData.data();
|
BLOCKTYPE * BlockData = (BLOCKTYPE *)UncompressedData.data();
|
||||||
|
NIBBLETYPE * MetaData = (NIBBLETYPE *)(BlockData + cChunkDef::MetaOffset);
|
||||||
|
NIBBLETYPE * BlockLight = (NIBBLETYPE *)(BlockData + cChunkDef::LightOffset);
|
||||||
|
NIBBLETYPE * SkyLight = (NIBBLETYPE *)(BlockData + cChunkDef::SkyLightOffset);
|
||||||
|
|
||||||
a_World->ChunkDataLoaded(
|
a_World->SetChunkData(
|
||||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ,
|
a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ,
|
||||||
BlockData,
|
BlockData, MetaData,
|
||||||
BlockData + cChunkDef::MetaOffset,
|
IsLightValid ? BlockLight : NULL,
|
||||||
BlockData + cChunkDef::LightOffset,
|
IsLightValid ? SkyLight : NULL,
|
||||||
BlockData + cChunkDef::SkyLightOffset,
|
NULL, NULL,
|
||||||
NULL,
|
Entities, BlockEntities,
|
||||||
Entities,
|
false
|
||||||
BlockEntities
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -18,6 +18,36 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Helper class for serializing a chunk into Json
|
||||||
|
class cJsonChunkSerializer :
|
||||||
|
public cChunkDataCollector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cJsonChunkSerializer(void);
|
||||||
|
|
||||||
|
Json::Value & GetRoot (void) {return m_Root; }
|
||||||
|
BLOCKTYPE * GetBlockData(void) {return m_BlockData; }
|
||||||
|
bool HasJsonData (void) const {return m_HasJsonData; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// NOTE: block data is serialized into inherited cChunkDataCollector's m_BlockData[] array
|
||||||
|
|
||||||
|
// Entities and BlockEntities are serialized to Json
|
||||||
|
Json::Value m_Root;
|
||||||
|
bool m_HasJsonData;
|
||||||
|
|
||||||
|
// cChunkDataCollector overrides:
|
||||||
|
virtual void Entity (cEntity * a_Entity) override;
|
||||||
|
virtual void BlockEntity (cBlockEntity * a_Entity) override;
|
||||||
|
virtual bool LightIsValid (bool a_IsLightValid) override;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cWSSCompact :
|
class cWSSCompact :
|
||||||
public cWSSchema
|
public cWSSchema
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,61 +37,6 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cJsonChunkSerializer:
|
|
||||||
|
|
||||||
cJsonChunkSerializer::cJsonChunkSerializer(void) :
|
|
||||||
m_HasJsonData(false)
|
|
||||||
{
|
|
||||||
m_Root["Chests"] = m_AllChests;
|
|
||||||
m_Root["Furnaces"] = m_AllFurnaces;
|
|
||||||
m_Root["Signs"] = m_AllSigns;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cJsonChunkSerializer::Entity(cEntity * a_Entity)
|
|
||||||
{
|
|
||||||
// TODO: a_Entity->SaveToJson(m_Root);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity)
|
|
||||||
{
|
|
||||||
const char * SaveInto = NULL;
|
|
||||||
switch (a_BlockEntity->GetBlockType())
|
|
||||||
{
|
|
||||||
case E_BLOCK_CHEST: SaveInto = "Chests"; break;
|
|
||||||
case E_BLOCK_FURNACE: SaveInto = "Furnaces"; break;
|
|
||||||
case E_BLOCK_SIGN_POST: SaveInto = "Signs"; break;
|
|
||||||
case E_BLOCK_WALLSIGN: SaveInto = "Signs"; break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
ASSERT(!"Unhandled blocktype in BlockEntities list while saving to JSON");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // switch (BlockEntity->GetBlockType())
|
|
||||||
if (SaveInto == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Json::Value val;
|
|
||||||
a_BlockEntity->SaveToJson(val);
|
|
||||||
m_Root[SaveInto].append(val);
|
|
||||||
m_HasJsonData = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWorldStorage:
|
// cWorldStorage:
|
||||||
|
|
||||||
|
@ -332,13 +277,13 @@ bool cWorldStorage::LoadOneChunk(void)
|
||||||
bool ShouldLoad = false;
|
bool ShouldLoad = false;
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSQueues);
|
cCSLock Lock(m_CSQueues);
|
||||||
if (m_LoadQueue.size() > 0)
|
if (!m_LoadQueue.empty())
|
||||||
{
|
{
|
||||||
ToLoad = m_LoadQueue.front();
|
ToLoad = m_LoadQueue.front();
|
||||||
m_LoadQueue.pop_front();
|
m_LoadQueue.pop_front();
|
||||||
ShouldLoad = true;
|
ShouldLoad = true;
|
||||||
}
|
}
|
||||||
HasMore = (m_LoadQueue.size() > 0);
|
HasMore = !m_LoadQueue.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ))
|
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ))
|
||||||
|
@ -346,7 +291,7 @@ bool cWorldStorage::LoadOneChunk(void)
|
||||||
if (ToLoad.m_Generate)
|
if (ToLoad.m_Generate)
|
||||||
{
|
{
|
||||||
// The chunk couldn't be loaded, generate it:
|
// The chunk couldn't be loaded, generate it:
|
||||||
m_World->GetGenerator().GenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ);
|
m_World->GetGenerator().QueueGenerateChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -368,13 +313,13 @@ bool cWorldStorage::SaveOneChunk(void)
|
||||||
bool ShouldSave = false;
|
bool ShouldSave = false;
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSQueues);
|
cCSLock Lock(m_CSQueues);
|
||||||
if (m_SaveQueue.size() > 0)
|
if (!m_SaveQueue.empty())
|
||||||
{
|
{
|
||||||
Save = m_SaveQueue.front();
|
Save = m_SaveQueue.front();
|
||||||
m_SaveQueue.pop_front();
|
m_SaveQueue.pop_front();
|
||||||
ShouldSave = true;
|
ShouldSave = true;
|
||||||
}
|
}
|
||||||
HasMore = (m_SaveQueue.size() > 0);
|
HasMore = !m_SaveQueue.empty();
|
||||||
}
|
}
|
||||||
if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ))
|
if (ShouldSave && m_World->IsChunkValid(Save.m_ChunkX, Save.m_ChunkY, Save.m_ChunkZ))
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,38 +51,6 @@ typedef std::list<cWSSchema *> cWSSchemaList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Helper class for serializing a chunk into Json
|
|
||||||
class cJsonChunkSerializer :
|
|
||||||
public cChunkDataCollector
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
cJsonChunkSerializer(void);
|
|
||||||
|
|
||||||
Json::Value & GetRoot (void) {return m_Root; }
|
|
||||||
BLOCKTYPE * GetBlockData(void) {return m_BlockData; }
|
|
||||||
bool HasJsonData (void) const {return m_HasJsonData; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// NOTE: block data is serialized into inherited cChunkDataCollector's m_BlockData[] array
|
|
||||||
|
|
||||||
// Entities and BlockEntities are serialized to Json
|
|
||||||
Json::Value m_Root;
|
|
||||||
Json::Value m_AllChests;
|
|
||||||
Json::Value m_AllFurnaces;
|
|
||||||
Json::Value m_AllSigns;
|
|
||||||
bool m_HasJsonData;
|
|
||||||
|
|
||||||
// cChunkDataCollector overrides:
|
|
||||||
virtual void Entity (cEntity * a_Entity) override;
|
|
||||||
virtual void BlockEntity (cBlockEntity * a_Entity) override;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// The actual world storage class
|
/// The actual world storage class
|
||||||
class cWorldStorage :
|
class cWorldStorage :
|
||||||
public cIsThread
|
public cIsThread
|
||||||
|
|
|
@ -125,7 +125,7 @@ void cAuthenticator::Execute(void)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASSERT(m_Queue.size() > 0);
|
ASSERT(!m_Queue.empty());
|
||||||
|
|
||||||
int ClientID = m_Queue.front().mClientID;
|
int ClientID = m_Queue.front().mClientID;
|
||||||
AString UserName = m_Queue.front().mName;
|
AString UserName = m_Queue.front().mName;
|
||||||
|
|
|
@ -3,26 +3,31 @@
|
||||||
|
|
||||||
#include "cChatColor.h"
|
#include "cChatColor.h"
|
||||||
|
|
||||||
const std::string cChatColor::Color = "\xa7"; // Old color was "\xc2\xa7" or in other words: "§"
|
const std::string cChatColor::Color = "\xa7"; // Old color was "\xc2\xa7" or in other words: "§"
|
||||||
const std::string cChatColor::Delimiter = "\xa7";
|
const std::string cChatColor::Delimiter = "\xa7";
|
||||||
const std::string cChatColor::Black = cChatColor::Color + "0";
|
const std::string cChatColor::Black = cChatColor::Color + "0";
|
||||||
const std::string cChatColor::Navy = cChatColor::Color + "1";
|
const std::string cChatColor::Navy = cChatColor::Color + "1";
|
||||||
const std::string cChatColor::Green = cChatColor::Color + "2";
|
const std::string cChatColor::Green = cChatColor::Color + "2";
|
||||||
const std::string cChatColor::Blue = cChatColor::Color + "3";
|
const std::string cChatColor::Blue = cChatColor::Color + "3";
|
||||||
const std::string cChatColor::Red = cChatColor::Color + "4";
|
const std::string cChatColor::Red = cChatColor::Color + "4";
|
||||||
const std::string cChatColor::Purple = cChatColor::Color + "5";
|
const std::string cChatColor::Purple = cChatColor::Color + "5";
|
||||||
const std::string cChatColor::Gold = cChatColor::Color + "6";
|
const std::string cChatColor::Gold = cChatColor::Color + "6";
|
||||||
const std::string cChatColor::LightGray = cChatColor::Color + "7";
|
const std::string cChatColor::LightGray = cChatColor::Color + "7";
|
||||||
const std::string cChatColor::Gray = cChatColor::Color + "8";
|
const std::string cChatColor::Gray = cChatColor::Color + "8";
|
||||||
const std::string cChatColor::DarkPurple = cChatColor::Color + "9";
|
const std::string cChatColor::DarkPurple = cChatColor::Color + "9";
|
||||||
const std::string cChatColor::LightGreen = cChatColor::Color + "a";
|
const std::string cChatColor::LightGreen = cChatColor::Color + "a";
|
||||||
const std::string cChatColor::LightBlue = cChatColor::Color + "b";
|
const std::string cChatColor::LightBlue = cChatColor::Color + "b";
|
||||||
const std::string cChatColor::Rose = cChatColor::Color + "c";
|
const std::string cChatColor::Rose = cChatColor::Color + "c";
|
||||||
const std::string cChatColor::LightPurple = cChatColor::Color + "d";
|
const std::string cChatColor::LightPurple = cChatColor::Color + "d";
|
||||||
const std::string cChatColor::Yellow = cChatColor::Color + "e";
|
const std::string cChatColor::Yellow = cChatColor::Color + "e";
|
||||||
const std::string cChatColor::White = cChatColor::Color + "f";
|
const std::string cChatColor::White = cChatColor::Color + "f";
|
||||||
|
const std::string cChatColor::Funky = cChatColor::Color + "k";
|
||||||
|
|
||||||
const std::string cChatColor::MakeColor( char a_Color )
|
const std::string cChatColor::MakeColor( char a_Color )
|
||||||
{
|
{
|
||||||
return cChatColor::Color + a_Color;
|
return cChatColor::Color + a_Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
class cChatColor
|
class cChatColor
|
||||||
|
@ -25,6 +28,7 @@ public:
|
||||||
static const std::string LightPurple;
|
static const std::string LightPurple;
|
||||||
static const std::string Yellow;
|
static const std::string Yellow;
|
||||||
static const std::string White;
|
static const std::string White;
|
||||||
|
static const std::string Funky;
|
||||||
|
|
||||||
static const std::string MakeColor( char a_Color );
|
static const std::string MakeColor( char a_Color );
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include "cItem.h"
|
#include "cItem.h"
|
||||||
#include "cNoise.h"
|
#include "cNoise.h"
|
||||||
#include "cRoot.h"
|
#include "cRoot.h"
|
||||||
#include "cWorldGenerator.h"
|
|
||||||
#include "cBlockToPickup.h"
|
#include "cBlockToPickup.h"
|
||||||
#include "MersenneTwister.h"
|
#include "MersenneTwister.h"
|
||||||
#include "cPlayer.h"
|
#include "cPlayer.h"
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
#include "packets/cPacket_DestroyEntity.h"
|
#include "packets/cPacket_DestroyEntity.h"
|
||||||
#include "packets/cPacket_PreChunk.h"
|
#include "packets/cPacket_PreChunk.h"
|
||||||
#include "packets/cPacket_BlockChange.h"
|
#include "packets/cPacket_BlockChange.h"
|
||||||
#include "packets/cPacket_MapChunk.h"
|
|
||||||
#include "packets/cPacket_MultiBlock.h"
|
#include "packets/cPacket_MultiBlock.h"
|
||||||
|
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
@ -50,10 +48,10 @@ extern bool g_bWaterPhysics;
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// sSetBlock:
|
// sSetBlock:
|
||||||
|
|
||||||
sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) // absolute block position
|
sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) // absolute block position
|
||||||
: x( a_X )
|
: x( a_BlockX )
|
||||||
, y( a_Y )
|
, y( a_BlockY )
|
||||||
, z( a_Z )
|
, z( a_BlockZ )
|
||||||
, BlockType( a_BlockType )
|
, BlockType( a_BlockType )
|
||||||
, BlockMeta( a_BlockMeta )
|
, BlockMeta( a_BlockMeta )
|
||||||
{
|
{
|
||||||
|
@ -68,8 +66,7 @@ sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockM
|
||||||
// cChunk:
|
// cChunk:
|
||||||
|
|
||||||
cChunk::cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World)
|
cChunk::cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World)
|
||||||
: m_bCalculateLighting( false )
|
: m_PosX( a_ChunkX )
|
||||||
, m_PosX( a_ChunkX )
|
|
||||||
, m_PosY( a_ChunkY )
|
, m_PosY( a_ChunkY )
|
||||||
, m_PosZ( a_ChunkZ )
|
, m_PosZ( a_ChunkZ )
|
||||||
, m_BlockTickNum( 0 )
|
, m_BlockTickNum( 0 )
|
||||||
|
@ -79,6 +76,7 @@ cChunk::cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap,
|
||||||
, m_World( a_World )
|
, m_World( a_World )
|
||||||
, m_ChunkMap(a_ChunkMap)
|
, m_ChunkMap(a_ChunkMap)
|
||||||
, m_IsValid(false)
|
, m_IsValid(false)
|
||||||
|
, m_IsLightValid(false)
|
||||||
, m_IsDirty(false)
|
, m_IsDirty(false)
|
||||||
, m_IsSaving(false)
|
, m_IsSaving(false)
|
||||||
, m_StayCount(0)
|
, m_StayCount(0)
|
||||||
|
@ -203,8 +201,10 @@ void cChunk::MarkLoadFailed(void)
|
||||||
void cChunk::GetAllData(cChunkDataCallback & a_Callback)
|
void cChunk::GetAllData(cChunkDataCallback & a_Callback)
|
||||||
{
|
{
|
||||||
a_Callback.HeightMap (&m_HeightMap);
|
a_Callback.HeightMap (&m_HeightMap);
|
||||||
|
a_Callback.BiomeData (&m_BiomeMap);
|
||||||
a_Callback.BlockTypes (m_BlockTypes);
|
a_Callback.BlockTypes (m_BlockTypes);
|
||||||
a_Callback.BlockMeta (m_BlockMeta);
|
a_Callback.BlockMeta (m_BlockMeta);
|
||||||
|
a_Callback.LightIsValid (m_IsLightValid);
|
||||||
a_Callback.BlockLight (m_BlockLight);
|
a_Callback.BlockLight (m_BlockLight);
|
||||||
a_Callback.BlockSkyLight(m_BlockSkyLight);
|
a_Callback.BlockSkyLight(m_BlockSkyLight);
|
||||||
|
|
||||||
|
@ -224,24 +224,35 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback)
|
||||||
|
|
||||||
|
|
||||||
void cChunk::SetAllData(
|
void cChunk::SetAllData(
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const BLOCKTYPE * a_BlockTypes,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const NIBBLETYPE * a_BlockMeta,
|
||||||
const BLOCKTYPE * a_BlockLight,
|
const NIBBLETYPE * a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
const NIBBLETYPE * a_BlockSkyLight,
|
||||||
const HeightMap * a_HeightMap,
|
const HeightMap * a_HeightMap,
|
||||||
|
const BiomeMap & a_BiomeMap,
|
||||||
cEntityList & a_Entities,
|
cEntityList & a_Entities,
|
||||||
cBlockEntityList & a_BlockEntities
|
cBlockEntityList & a_BlockEntities
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
memcpy(m_BiomeMap, a_BiomeMap, sizeof(m_BiomeMap));
|
||||||
|
|
||||||
if (a_HeightMap != NULL)
|
if (a_HeightMap != NULL)
|
||||||
{
|
{
|
||||||
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
|
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
|
memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
|
||||||
memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta));
|
memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta));
|
||||||
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
if (a_BlockLight != NULL)
|
||||||
memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
|
{
|
||||||
|
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
||||||
|
}
|
||||||
|
if (a_BlockSkyLight != NULL)
|
||||||
|
{
|
||||||
|
memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL);
|
||||||
|
|
||||||
if (a_HeightMap == NULL)
|
if (a_HeightMap == NULL)
|
||||||
{
|
{
|
||||||
|
@ -290,6 +301,22 @@ void cChunk::SetAllData(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::SetLight(
|
||||||
|
const cChunkDef::BlockNibbles & a_BlockLight,
|
||||||
|
const cChunkDef::BlockNibbles & a_SkyLight
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// TODO: We might get cases of wrong lighting when a chunk changes in the middle of a lighting calculation.
|
||||||
|
// Postponing until we see how bad it is :)
|
||||||
|
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
||||||
|
memcpy(m_BlockSkyLight, a_SkyLight, sizeof(m_BlockSkyLight));
|
||||||
|
m_IsLightValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes)
|
void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes)
|
||||||
{
|
{
|
||||||
memcpy(a_BlockTypes, m_BlockTypes, NumBlocks);
|
memcpy(a_BlockTypes, m_BlockTypes, NumBlocks);
|
||||||
|
@ -345,11 +372,6 @@ void cChunk::Stay(bool a_Stay)
|
||||||
|
|
||||||
void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
{
|
{
|
||||||
if (m_bCalculateLighting)
|
|
||||||
{
|
|
||||||
CalculateLighting();
|
|
||||||
}
|
|
||||||
|
|
||||||
cCSLock Lock(m_CSBlockLists);
|
cCSLock Lock(m_CSBlockLists);
|
||||||
unsigned int PendingSendBlocks = m_PendingSendBlocks.size();
|
unsigned int PendingSendBlocks = m_PendingSendBlocks.size();
|
||||||
if( PendingSendBlocks > 1 )
|
if( PendingSendBlocks > 1 )
|
||||||
|
@ -407,7 +429,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
unsigned int NumTickBlocks = m_ToTickBlocks.size();
|
unsigned int NumTickBlocks = m_ToTickBlocks.size();
|
||||||
Lock2.Unlock();
|
Lock2.Unlock();
|
||||||
|
|
||||||
if( NumTickBlocks > 0 )
|
if ( NumTickBlocks > 0 )
|
||||||
{
|
{
|
||||||
Lock2.Lock();
|
Lock2.Lock();
|
||||||
std::deque< unsigned int > ToTickBlocks = m_ToTickBlocks;
|
std::deque< unsigned int > ToTickBlocks = m_ToTickBlocks;
|
||||||
|
@ -415,32 +437,34 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
Lock2.Unlock();
|
Lock2.Unlock();
|
||||||
|
|
||||||
bool isRedstone = false;
|
bool isRedstone = false;
|
||||||
for( std::deque< unsigned int >::iterator itr = ToTickBlocks.begin(); itr != ToTickBlocks.end(); ++itr )
|
for ( std::deque< unsigned int >::iterator itr = ToTickBlocks.begin(); itr != ToTickBlocks.end(); ++itr )
|
||||||
{
|
{
|
||||||
unsigned int index = (*itr);
|
unsigned int index = (*itr);
|
||||||
Vector3i BlockPos = IndexToCoordinate( index );
|
Vector3i BlockPos = IndexToCoordinate( index );
|
||||||
|
|
||||||
char BlockID = GetBlock( index );
|
char BlockID = GetBlock( index );
|
||||||
switch( BlockID )
|
switch ( BlockID )
|
||||||
{
|
{
|
||||||
case E_BLOCK_REDSTONE_REPEATER_OFF:
|
case E_BLOCK_REDSTONE_REPEATER_OFF:
|
||||||
case E_BLOCK_REDSTONE_REPEATER_ON:
|
case E_BLOCK_REDSTONE_REPEATER_ON:
|
||||||
case E_BLOCK_REDSTONE_WIRE:
|
case E_BLOCK_REDSTONE_WIRE:
|
||||||
{
|
{
|
||||||
isRedstone = true;
|
isRedstone = true;
|
||||||
|
// fallthrough
|
||||||
}
|
}
|
||||||
case E_BLOCK_CACTUS:
|
|
||||||
case E_BLOCK_REEDS:
|
case E_BLOCK_CACTUS:
|
||||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
case E_BLOCK_REEDS:
|
||||||
case E_BLOCK_STONE_PRESSURE_PLATE:
|
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||||
case E_BLOCK_MINECART_TRACKS:
|
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||||
case E_BLOCK_SIGN_POST:
|
case E_BLOCK_MINECART_TRACKS:
|
||||||
case E_BLOCK_CROPS:
|
case E_BLOCK_SIGN_POST:
|
||||||
case E_BLOCK_SAPLING:
|
case E_BLOCK_CROPS:
|
||||||
case E_BLOCK_YELLOW_FLOWER:
|
case E_BLOCK_SAPLING:
|
||||||
case E_BLOCK_RED_ROSE:
|
case E_BLOCK_YELLOW_FLOWER:
|
||||||
case E_BLOCK_RED_MUSHROOM:
|
case E_BLOCK_RED_ROSE:
|
||||||
case E_BLOCK_BROWN_MUSHROOM: // Stuff that drops when block below is destroyed
|
case E_BLOCK_RED_MUSHROOM:
|
||||||
|
case E_BLOCK_BROWN_MUSHROOM: // Stuff that drops when block below is destroyed
|
||||||
{
|
{
|
||||||
if( GetBlock( BlockPos.x, BlockPos.y-1, BlockPos.z ) == E_BLOCK_AIR )
|
if( GetBlock( BlockPos.x, BlockPos.y-1, BlockPos.z ) == E_BLOCK_AIR )
|
||||||
{
|
{
|
||||||
|
@ -453,12 +477,17 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
cPickup* Pickup = new cPickup( WorldPos.x * 32 + 16, WorldPos.y * 32 + 16, WorldPos.z * 32 + 16, cItem( cBlockToPickup::ToPickup( (ENUM_ITEM_ID)BlockID, E_ITEM_EMPTY) , 1 ) );
|
cPickup* Pickup = new cPickup( WorldPos.x * 32 + 16, WorldPos.y * 32 + 16, WorldPos.z * 32 + 16, cItem( cBlockToPickup::ToPickup( (ENUM_ITEM_ID)BlockID, E_ITEM_EMPTY) , 1 ) );
|
||||||
Pickup->Initialize( m_World );
|
Pickup->Initialize( m_World );
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case E_BLOCK_REDSTONE_TORCH_OFF:
|
case E_BLOCK_REDSTONE_TORCH_OFF:
|
||||||
case E_BLOCK_REDSTONE_TORCH_ON:
|
case E_BLOCK_REDSTONE_TORCH_ON:
|
||||||
|
{
|
||||||
isRedstone = true;
|
isRedstone = true;
|
||||||
case E_BLOCK_TORCH:
|
// fallthrough
|
||||||
|
}
|
||||||
|
|
||||||
|
case E_BLOCK_TORCH:
|
||||||
{
|
{
|
||||||
char Dir = cTorch::MetaDataToDirection( GetNibble( m_BlockMeta, BlockPos ) );
|
char Dir = cTorch::MetaDataToDirection( GetNibble( m_BlockMeta, BlockPos ) );
|
||||||
Vector3i WorldPos = PositionToWorldPosition( BlockPos );
|
Vector3i WorldPos = PositionToWorldPosition( BlockPos );
|
||||||
|
@ -474,9 +503,10 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
cPickup* Pickup = new cPickup( WorldPos.x * 32 + 16, WorldPos.y * 32 + 16, WorldPos.z * 32 + 16, cItem( cBlockToPickup::ToPickup( (ENUM_ITEM_ID)BlockID, E_ITEM_EMPTY) , 1 ) );
|
cPickup* Pickup = new cPickup( WorldPos.x * 32 + 16, WorldPos.y * 32 + 16, WorldPos.z * 32 + 16, cItem( cBlockToPickup::ToPickup( (ENUM_ITEM_ID)BlockID, E_ITEM_EMPTY) , 1 ) );
|
||||||
Pickup->Initialize( m_World );
|
Pickup->Initialize( m_World );
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case E_BLOCK_LADDER:
|
case E_BLOCK_LADDER:
|
||||||
{
|
{
|
||||||
char Dir = cLadder::MetaDataToDirection( GetNibble( m_BlockMeta, BlockPos ) );
|
char Dir = cLadder::MetaDataToDirection( GetNibble( m_BlockMeta, BlockPos ) );
|
||||||
Vector3i WorldPos = PositionToWorldPosition( BlockPos );
|
Vector3i WorldPos = PositionToWorldPosition( BlockPos );
|
||||||
|
@ -488,20 +518,35 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
cPickup* Pickup = new cPickup( WorldPos.x * 32 + 16, WorldPos.y * 32 + 16, WorldPos.z * 32 + 16, cItem( (ENUM_ITEM_ID)BlockID, 1 ) );
|
cPickup* Pickup = new cPickup( WorldPos.x * 32 + 16, WorldPos.y * 32 + 16, WorldPos.z * 32 + 16, cItem( (ENUM_ITEM_ID)BlockID, 1 ) );
|
||||||
Pickup->Initialize( m_World );
|
Pickup->Initialize( m_World );
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
} // switch (BlockType)
|
||||||
default:
|
} // for itr - ToTickBlocks[]
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TickBlocks(a_TickRandom);
|
||||||
|
|
||||||
|
// Tick block entities (furnaces)
|
||||||
|
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((*itr)->GetBlockType() == E_BLOCK_FURNACE)
|
||||||
|
{
|
||||||
|
((cFurnaceEntity *)(*itr))->Tick( a_Dt );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunk::TickBlocks(MTRand & a_TickRandom)
|
||||||
|
{
|
||||||
// Tick dem blocks
|
// Tick dem blocks
|
||||||
int RandomX = a_TickRandom.randInt();
|
int RandomX = a_TickRandom.randInt();
|
||||||
int RandomY = a_TickRandom.randInt();
|
int RandomY = a_TickRandom.randInt();
|
||||||
int RandomZ = a_TickRandom.randInt();
|
int RandomZ = a_TickRandom.randInt();
|
||||||
|
|
||||||
for(int i = 0; i < 50; i++)
|
for (int i = 0; i < 50; i++)
|
||||||
{
|
{
|
||||||
m_BlockTickX = (m_BlockTickX + RandomX) % Width;
|
m_BlockTickX = (m_BlockTickX + RandomX) % Width;
|
||||||
m_BlockTickY = (m_BlockTickY + RandomY) % Height;
|
m_BlockTickY = (m_BlockTickY + RandomY) % Height;
|
||||||
|
@ -533,38 +578,38 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||||
|
|
||||||
case E_BLOCK_GRASS:
|
case E_BLOCK_GRASS:
|
||||||
{
|
{
|
||||||
#if AXIS_ORDER == AXIS_ORDER_YZX
|
char AboveBlock = GetBlock( Index + (Width * Width) );
|
||||||
char AboveBlock = GetBlock( Index+1 );
|
if (!( (AboveBlock == E_BLOCK_AIR) || (g_BlockOneHitDig[AboveBlock]) || (g_BlockTransparent[AboveBlock]) ) )
|
||||||
#elif AXIS_ORDER == AXIS_ORDER_XZY
|
|
||||||
char AboveBlock = GetBlock( Index + (Width*Width) );
|
|
||||||
#endif
|
|
||||||
if (!( (AboveBlock == 0) || (g_BlockOneHitDig[AboveBlock]) || (g_BlockTransparent[AboveBlock]) ) ) //changed to not allow grass if any one hit object is on top
|
|
||||||
{
|
{
|
||||||
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_DIRT, GetNibble( m_BlockMeta, Index ) );
|
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_DIRT, GetNibble( m_BlockMeta, Index ) );
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case E_BLOCK_SAPLING: //todo: check meta of sapling. change m_World->GrowTree to look change trunk and leaves based on meta of sapling
|
case E_BLOCK_SAPLING: //todo: check meta of sapling. change m_World->GrowTree to look change trunk and leaves based on meta of sapling
|
||||||
{
|
{
|
||||||
FastSetBlock( m_BlockTickX, m_BlockTickY, m_BlockTickZ, E_BLOCK_AIR, GetNibble( m_BlockMeta, Index ) );
|
// Check the highest bit, if set, grow the tree, if not, set it (1-bit delay):
|
||||||
m_World->GrowTree( m_BlockTickX + m_PosX*Width, m_BlockTickY, m_BlockTickZ + m_PosZ*Width );
|
NIBBLETYPE Meta = GetMeta(m_BlockTickX, m_BlockTickY, m_BlockTickZ);
|
||||||
|
if ((Meta & 0x08) != 0)
|
||||||
|
{
|
||||||
|
m_World->GrowTree( m_BlockTickX + m_PosX*Width, m_BlockTickY, m_BlockTickZ + m_PosZ*Width );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetMeta(m_BlockTickX, m_BlockTickY, m_BlockTickZ, Meta | 0x08);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case E_BLOCK_LEAVES: //todo, http://www.minecraftwiki.net/wiki/Data_values#Leaves
|
case E_BLOCK_LEAVES: //todo, http://www.minecraftwiki.net/wiki/Data_values#Leaves
|
||||||
{
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tick block entities (furnaces)
|
|
||||||
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr)
|
|
||||||
{
|
|
||||||
if ((*itr)->GetBlockType() == E_BLOCK_FURNACE)
|
|
||||||
{
|
|
||||||
((cFurnaceEntity *)(*itr))->Tick( a_Dt );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,7 +641,7 @@ void cChunk::CreateBlockEntities(void)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < Height; y++)
|
for (int y = 0; y < Height; y++)
|
||||||
{
|
{
|
||||||
ENUM_BLOCK_ID BlockType = (ENUM_BLOCK_ID)m_BlockTypes[ MakeIndexNoCheck( x, y, z ) ];
|
ENUM_BLOCK_ID BlockType = (ENUM_BLOCK_ID)m_BlockTypes[ MakeIndex( x, y, z ) ];
|
||||||
switch ( BlockType )
|
switch ( BlockType )
|
||||||
{
|
{
|
||||||
case E_BLOCK_CHEST:
|
case E_BLOCK_CHEST:
|
||||||
|
@ -644,7 +689,7 @@ void cChunk::CalculateHeightmap()
|
||||||
{
|
{
|
||||||
for (int y = Height - 1; y > -1; y--)
|
for (int y = Height - 1; y > -1; y--)
|
||||||
{
|
{
|
||||||
int index = MakeIndexNoCheck( x, y, z );
|
int index = MakeIndex( x, y, z );
|
||||||
if (m_BlockTypes[index] != E_BLOCK_AIR)
|
if (m_BlockTypes[index] != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
m_HeightMap[x + z * Width] = (unsigned char)y;
|
m_HeightMap[x + z * Width] = (unsigned char)y;
|
||||||
|
@ -699,16 +744,13 @@ void cChunk::CalculateLighting()
|
||||||
SpreadLight(m_BlockLight);
|
SpreadLight(m_BlockLight);
|
||||||
|
|
||||||
MarkDirty();
|
MarkDirty();
|
||||||
|
|
||||||
// Stop it from calculating again :P
|
|
||||||
m_bCalculateLighting = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::SpreadLight(BLOCKTYPE * a_LightBuffer)
|
void cChunk::SpreadLight(NIBBLETYPE * a_LightBuffer)
|
||||||
{
|
{
|
||||||
// Spread the light
|
// Spread the light
|
||||||
for(int x = 0; x < Width; x++) for(int z = 0; z < Width; z++) for(int y = 0; y < Height; y++)
|
for(int x = 0; x < Width; x++) for(int z = 0; z < Width; z++) for(int y = 0; y < Height; y++)
|
||||||
|
@ -735,7 +777,7 @@ void cChunk::SpreadLight(BLOCKTYPE * a_LightBuffer)
|
||||||
// Spread to neighbour chunks X-axis
|
// Spread to neighbour chunks X-axis
|
||||||
cChunkPtr LeftChunk = m_ChunkMap->GetChunkNoGen( m_PosX - 1, m_PosY, m_PosZ );
|
cChunkPtr LeftChunk = m_ChunkMap->GetChunkNoGen( m_PosX - 1, m_PosY, m_PosZ );
|
||||||
cChunkPtr RightChunk = m_ChunkMap->GetChunkNoGen( m_PosX + 1, m_PosY, m_PosZ );
|
cChunkPtr RightChunk = m_ChunkMap->GetChunkNoGen( m_PosX + 1, m_PosY, m_PosZ );
|
||||||
BLOCKTYPE * LeftSky = NULL, *RightSky = NULL;
|
NIBBLETYPE * LeftSky = NULL, * RightSky = NULL;
|
||||||
if (LeftChunk->IsValid())
|
if (LeftChunk->IsValid())
|
||||||
{
|
{
|
||||||
LeftSky = (a_LightBuffer == m_BlockSkyLight) ? LeftChunk->m_BlockSkyLight : LeftChunk->m_BlockLight;
|
LeftSky = (a_LightBuffer == m_BlockSkyLight) ? LeftChunk->m_BlockSkyLight : LeftChunk->m_BlockLight;
|
||||||
|
@ -780,7 +822,7 @@ void cChunk::SpreadLight(BLOCKTYPE * a_LightBuffer)
|
||||||
// Spread to neighbour chunks Z-axis
|
// Spread to neighbour chunks Z-axis
|
||||||
cChunkPtr FrontChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ - 1 );
|
cChunkPtr FrontChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ - 1 );
|
||||||
cChunkPtr BackChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ + 1 );
|
cChunkPtr BackChunk = m_ChunkMap->GetChunkNoGen( m_PosX, m_PosY, m_PosZ + 1 );
|
||||||
BLOCKTYPE * FrontSky = NULL, * BackSky = NULL;
|
NIBBLETYPE * FrontSky = NULL, * BackSky = NULL;
|
||||||
if (FrontChunk->IsValid())
|
if (FrontChunk->IsValid())
|
||||||
{
|
{
|
||||||
FrontSky = (a_LightBuffer == m_BlockSkyLight) ? FrontChunk->m_BlockSkyLight : FrontChunk->m_BlockLight;
|
FrontSky = (a_LightBuffer == m_BlockSkyLight) ? FrontChunk->m_BlockSkyLight : FrontChunk->m_BlockLight;
|
||||||
|
@ -832,16 +874,16 @@ void cChunk::SpreadLight(BLOCKTYPE * a_LightBuffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunk::SetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta )
|
void cChunk::SetBlock( int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta )
|
||||||
{
|
{
|
||||||
if (a_X < 0 || a_X >= Width || a_Y < 0 || a_Y >= Height || a_Z < 0 || a_Z >= Width)
|
if (a_RelX < 0 || a_RelX >= Width || a_RelY < 0 || a_RelY >= Height || a_RelZ < 0 || a_RelZ >= Width)
|
||||||
{
|
{
|
||||||
return; // Clip
|
return; // Clip
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(IsValid()); // Is this chunk loaded / generated?
|
ASSERT(IsValid()); // Is this chunk loaded / generated?
|
||||||
|
|
||||||
int index = MakeIndexNoCheck( a_X, a_Y, a_Z );
|
int index = MakeIndexNoCheck( a_RelX, a_RelY, a_RelZ );
|
||||||
BLOCKTYPE OldBlockMeta = GetNibble( m_BlockMeta, index );
|
BLOCKTYPE OldBlockMeta = GetNibble( m_BlockMeta, index );
|
||||||
BLOCKTYPE OldBlockType = m_BlockTypes[index];
|
BLOCKTYPE OldBlockType = m_BlockTypes[index];
|
||||||
m_BlockTypes[index] = a_BlockType;
|
m_BlockTypes[index] = a_BlockType;
|
||||||
|
@ -867,38 +909,38 @@ void cChunk::SetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTY
|
||||||
(g_BlockTransparent[ OldBlockType ] != g_BlockTransparent[ a_BlockType ] )
|
(g_BlockTransparent[ OldBlockType ] != g_BlockTransparent[ a_BlockType ] )
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
RecalculateLighting();
|
m_IsLightValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update heightmap, if needed:
|
// Update heightmap, if needed:
|
||||||
if (a_Y >= m_HeightMap[a_X + a_Z * Width])
|
if (a_RelY >= m_HeightMap[a_RelX + a_RelZ * Width])
|
||||||
{
|
{
|
||||||
if (a_BlockType != E_BLOCK_AIR)
|
if (a_BlockType != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
m_HeightMap[a_X + a_Z * Width] = (unsigned char)a_Y;
|
SetHeight(m_HeightMap, a_RelX, a_RelZ, a_RelY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int y = a_Y - 1; y > 0; --y)
|
for (int y = a_RelY - 1; y > 0; --y)
|
||||||
{
|
{
|
||||||
if (m_BlockTypes[MakeIndex(a_X, y, a_Z)] != E_BLOCK_AIR)
|
if (cChunkDef::GetBlock(m_BlockTypes, a_RelX, y, a_RelZ) != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
m_HeightMap[a_X + a_Z * Width] = (unsigned char)y;
|
SetHeight(m_HeightMap, a_RelX, a_RelZ, y);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} // for y - column in m_BlockData
|
} // for y - column in m_BlockData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X, a_Y, a_Z ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY, a_RelZ ) );
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X+1, a_Y, a_Z ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX + 1, a_RelY, a_RelZ ) );
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X-1, a_Y, a_Z ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX - 1, a_RelY, a_RelZ ) );
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X, a_Y+1, a_Z ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY + 1, a_RelZ ) );
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X, a_Y-1, a_Z ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY - 1, a_RelZ ) );
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X, a_Y, a_Z+1 ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY, a_RelZ + 1 ) );
|
||||||
m_ToTickBlocks.push_back( MakeIndex( a_X, a_Y, a_Z-1 ) );
|
m_ToTickBlocks.push_back( MakeIndex( a_RelX, a_RelY, a_RelZ - 1 ) );
|
||||||
|
|
||||||
Vector3i WorldPos = PositionToWorldPosition( a_X, a_Y, a_Z );
|
Vector3i WorldPos = PositionToWorldPosition( a_RelX, a_RelY, a_RelZ );
|
||||||
cBlockEntity* BlockEntity = GetBlockEntity( WorldPos );
|
cBlockEntity* BlockEntity = GetBlockEntity( WorldPos );
|
||||||
if( BlockEntity )
|
if( BlockEntity )
|
||||||
{
|
{
|
||||||
|
@ -963,7 +1005,7 @@ void cChunk::FastSetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLO
|
||||||
(g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] )
|
(g_BlockTransparent[ OldBlock ] != g_BlockTransparent[ a_BlockType ] )
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
RecalculateLighting();
|
m_IsLightValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update heightmap, if needed:
|
// Update heightmap, if needed:
|
||||||
|
|
|
@ -54,13 +54,15 @@ public:
|
||||||
cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World);
|
cChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkMap * a_ChunkMap, cWorld * a_World);
|
||||||
~cChunk();
|
~cChunk();
|
||||||
|
|
||||||
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated)
|
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated)
|
||||||
void SetValid(void); // Also wakes up any calls to cChunkMap::GetHeight()
|
void SetValid(void); // Also wakes up any calls to cChunkMap::GetHeight()
|
||||||
void MarkRegenerating(void); // Marks all clients attached to this chunk as wanting this chunk
|
void MarkRegenerating(void); // Marks all clients attached to this chunk as wanting this chunk
|
||||||
bool IsDirty(void) const {return m_IsDirty; } // Returns true if the chunk has changed since it was last saved
|
bool IsDirty(void) const {return m_IsDirty; } // Returns true if the chunk has changed since it was last saved
|
||||||
bool HasLoadFailed(void) const {return m_HasLoadFailed; } // Returns true if the chunk failed to load and hasn't been generated since then
|
bool HasLoadFailed(void) const {return m_HasLoadFailed; } // Returns true if the chunk failed to load and hasn't been generated since then
|
||||||
bool CanUnload(void);
|
bool CanUnload(void);
|
||||||
|
|
||||||
|
bool IsLightValid(void) const {return m_IsLightValid; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
To save a chunk, the WSSchema must:
|
To save a chunk, the WSSchema must:
|
||||||
1. Mark the chunk as being saved (MarkSaving() )
|
1. Mark the chunk as being saved (MarkSaving() )
|
||||||
|
@ -78,15 +80,21 @@ public:
|
||||||
|
|
||||||
/// Sets all chunk data
|
/// Sets all chunk data
|
||||||
void SetAllData(
|
void SetAllData(
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const BLOCKTYPE * a_BlockTypes,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const NIBBLETYPE * a_BlockMeta,
|
||||||
const BLOCKTYPE * a_BlockLight,
|
const NIBBLETYPE * a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
const NIBBLETYPE * a_BlockSkyLight,
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
const cChunkDef::HeightMap * a_HeightMap,
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap,
|
||||||
cEntityList & a_Entities,
|
cEntityList & a_Entities,
|
||||||
cBlockEntityList & a_BlockEntities
|
cBlockEntityList & a_BlockEntities
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void SetLight(
|
||||||
|
const cChunkDef::BlockNibbles & a_BlockLight,
|
||||||
|
const cChunkDef::BlockNibbles & a_SkyLight
|
||||||
|
);
|
||||||
|
|
||||||
/// Copies m_BlockData into a_BlockTypes, only the block types
|
/// Copies m_BlockData into a_BlockTypes, only the block types
|
||||||
void GetBlockTypes(BLOCKTYPE * a_BlockTypes);
|
void GetBlockTypes(BLOCKTYPE * a_BlockTypes);
|
||||||
|
|
||||||
|
@ -100,6 +108,7 @@ public:
|
||||||
void Stay(bool a_Stay = true);
|
void Stay(bool a_Stay = true);
|
||||||
|
|
||||||
void Tick(float a_Dt, MTRand & a_TickRandom);
|
void Tick(float a_Dt, MTRand & a_TickRandom);
|
||||||
|
void TickBlocks(MTRand & a_TickRandom);
|
||||||
|
|
||||||
int GetPosX() { return m_PosX; }
|
int GetPosX() { return m_PosX; }
|
||||||
int GetPosY() { return m_PosY; }
|
int GetPosY() { return m_PosY; }
|
||||||
|
@ -108,12 +117,15 @@ public:
|
||||||
|
|
||||||
// OBSOLETE void SendTo( cClientHandle * a_Client );
|
// OBSOLETE void SendTo( cClientHandle * a_Client );
|
||||||
|
|
||||||
void SetBlock( int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta );
|
void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta );
|
||||||
void SetBlock( const Vector3i & a_BlockPos, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ) { SetBlock( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_BlockType, a_BlockMeta ); }
|
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
|
||||||
|
void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta ); }
|
||||||
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
|
void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
|
||||||
BLOCKTYPE GetBlock( int a_X, int a_Y, int a_Z );
|
BLOCKTYPE GetBlock( int a_X, int a_Y, int a_Z );
|
||||||
BLOCKTYPE GetBlock( int a_BlockIdx );
|
BLOCKTYPE GetBlock( int a_BlockIdx );
|
||||||
|
|
||||||
|
EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); }
|
||||||
|
|
||||||
void CollectPickupsByPlayer(cPlayer * a_Player);
|
void CollectPickupsByPlayer(cPlayer * a_Player);
|
||||||
void UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); // Also sends update packets to all clients in the chunk
|
void UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); // Also sends update packets to all clients in the chunk
|
||||||
|
|
||||||
|
@ -133,8 +145,6 @@ public:
|
||||||
|
|
||||||
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords
|
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords
|
||||||
|
|
||||||
inline void RecalculateLighting() { m_bCalculateLighting = true; } // Recalculate lighting next tick
|
|
||||||
|
|
||||||
void CalculateLighting(); // Recalculate right now
|
void CalculateLighting(); // Recalculate right now
|
||||||
void CalculateHeightmap();
|
void CalculateHeightmap();
|
||||||
|
|
||||||
|
@ -165,19 +175,21 @@ public:
|
||||||
inline void SpreadBlockSkyLight(void) {SpreadLight(m_BlockSkyLight); }
|
inline void SpreadBlockSkyLight(void) {SpreadLight(m_BlockSkyLight); }
|
||||||
inline void SpreadBlockLight (void) {SpreadLight(m_BlockLight); }
|
inline void SpreadBlockLight (void) {SpreadLight(m_BlockLight); }
|
||||||
|
|
||||||
inline BLOCKTYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
|
inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); }
|
||||||
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
|
inline NIBBLETYPE GetMeta(int a_BlockIdx) {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); }
|
||||||
|
inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); }
|
||||||
|
|
||||||
inline BLOCKTYPE GetLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
|
inline NIBBLETYPE GetLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); }
|
||||||
inline BLOCKTYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
|
inline NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class cChunkMap;
|
friend class cChunkMap;
|
||||||
|
|
||||||
bool m_IsValid; // True if the chunk is loaded / generated
|
bool m_IsValid; // True if the chunk is loaded / generated
|
||||||
bool m_IsDirty; // True if the chunk has changed since it was last saved
|
bool m_IsLightValid; // True if the blocklight and skylight are calculated
|
||||||
bool m_IsSaving; // True if the chunk is being saved
|
bool m_IsDirty; // True if the chunk has changed since it was last saved
|
||||||
|
bool m_IsSaving; // True if the chunk is being saved
|
||||||
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
|
bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then
|
||||||
|
|
||||||
cCriticalSection m_CSBlockLists;
|
cCriticalSection m_CSBlockLists;
|
||||||
|
@ -193,19 +205,18 @@ private:
|
||||||
/// Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded
|
/// Number of times the chunk has been requested to stay (by various cChunkStay objects); if zero, the chunk can be unloaded
|
||||||
int m_StayCount;
|
int m_StayCount;
|
||||||
|
|
||||||
bool m_bCalculateLighting;
|
|
||||||
|
|
||||||
int m_PosX, m_PosY, m_PosZ;
|
int m_PosX, m_PosY, m_PosZ;
|
||||||
cWorld * m_World;
|
cWorld * m_World;
|
||||||
cChunkMap * m_ChunkMap;
|
cChunkMap * m_ChunkMap;
|
||||||
|
|
||||||
// TODO: Make these pointers and don't allocate what isn't needed
|
// TODO: Make these pointers and don't allocate what isn't needed
|
||||||
BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks];
|
BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks];
|
||||||
BLOCKTYPE m_BlockMeta [cChunkDef::NumBlocks / 2];
|
NIBBLETYPE m_BlockMeta [cChunkDef::NumBlocks / 2];
|
||||||
BLOCKTYPE m_BlockLight [cChunkDef::NumBlocks / 2];
|
NIBBLETYPE m_BlockLight [cChunkDef::NumBlocks / 2];
|
||||||
BLOCKTYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2];
|
NIBBLETYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2];
|
||||||
|
|
||||||
cChunkDef::HeightMap m_HeightMap;
|
cChunkDef::HeightMap m_HeightMap;
|
||||||
|
cChunkDef::BiomeMap m_BiomeMap;
|
||||||
|
|
||||||
unsigned int m_BlockTickNum;
|
unsigned int m_BlockTickNum;
|
||||||
unsigned int m_BlockTickX, m_BlockTickY, m_BlockTickZ;
|
unsigned int m_BlockTickX, m_BlockTickY, m_BlockTickZ;
|
||||||
|
@ -215,14 +226,14 @@ private:
|
||||||
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z );
|
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z );
|
||||||
cBlockEntity * GetBlockEntity( const Vector3i & a_BlockPos ) { return GetBlockEntity( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); }
|
cBlockEntity * GetBlockEntity( const Vector3i & a_BlockPos ) { return GetBlockEntity( a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); }
|
||||||
|
|
||||||
void SpreadLightOfBlock(BLOCKTYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, BLOCKTYPE a_Falloff);
|
void SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);
|
||||||
|
|
||||||
void CreateBlockEntities(void);
|
void CreateBlockEntities(void);
|
||||||
|
|
||||||
// Makes a copy of the list
|
// Makes a copy of the list
|
||||||
cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
|
cClientHandleList GetAllClients(void) const {return m_LoadedByClient; }
|
||||||
|
|
||||||
void SpreadLight(BLOCKTYPE * a_LightBuffer);
|
void SpreadLight(NIBBLETYPE * a_LightBuffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef cChunk * cChunkPtr;
|
typedef cChunk * cChunkPtr;
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
|
|
||||||
__C_CHUNK_INLINE__
|
__C_CHUNK_INLINE__
|
||||||
void cChunk::SpreadLightOfBlock(BLOCKTYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, BLOCKTYPE a_Falloff)
|
void cChunk::SpreadLightOfBlock(NIBBLETYPE * a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff)
|
||||||
{
|
{
|
||||||
unsigned char CurrentLight = cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y, a_Z );
|
unsigned char CurrentLight = cChunkDef::GetNibble( a_LightBuffer, a_X, a_Y, a_Z );
|
||||||
cChunkDef::SetNibble( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X-1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) );
|
cChunkDef::SetNibble( a_LightBuffer, a_X-1, a_Y, a_Z, MAX(cChunkDef::GetNibble( a_LightBuffer, a_X-1, a_Y, a_Z ), MAX(0,CurrentLight-a_Falloff) ) );
|
||||||
|
|
|
@ -3,9 +3,12 @@
|
||||||
|
|
||||||
#include "cChunkGenerator.h"
|
#include "cChunkGenerator.h"
|
||||||
#include "cWorld.h"
|
#include "cWorld.h"
|
||||||
#include "cWorldGenerator.h"
|
#include "../iniFile/iniFile.h"
|
||||||
#include "cWorldGenerator_Test.h"
|
#include "BioGen.h"
|
||||||
#include "WGFlat.h"
|
#include "HeiGen.h"
|
||||||
|
#include "CompoGen.h"
|
||||||
|
#include "StructGen.h"
|
||||||
|
#include "FinishGen.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,7 +27,9 @@ const int QUEUE_SKIP_LIMIT = 500;
|
||||||
cChunkGenerator::cChunkGenerator(void)
|
cChunkGenerator::cChunkGenerator(void)
|
||||||
: super("cChunkGenerator")
|
: super("cChunkGenerator")
|
||||||
, m_World(NULL)
|
, m_World(NULL)
|
||||||
, m_pWorldGenerator(NULL)
|
, m_BiomeGen(NULL)
|
||||||
|
, m_HeightGen(NULL)
|
||||||
|
, m_CompositionGen(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,22 +46,24 @@ cChunkGenerator::~cChunkGenerator()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cChunkGenerator::Start(cWorld * a_World, const AString & a_WorldGeneratorName)
|
bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile)
|
||||||
{
|
{
|
||||||
|
MTRand rnd;
|
||||||
m_World = a_World;
|
m_World = a_World;
|
||||||
|
m_Seed = a_IniFile.GetValueI("Seed", "Seed", rnd.randInt());
|
||||||
|
|
||||||
if (NoCaseCompare(a_WorldGeneratorName, "Test") == 0 )
|
// TODO: Remove this after INI file interface changes ( http://forum.mc-server.org/showthread.php?tid=427 )
|
||||||
{
|
a_IniFile.DeleteValue("Seed", "Seed");
|
||||||
m_pWorldGenerator = new cWorldGenerator_Test(a_World);
|
|
||||||
}
|
a_IniFile.SetValueI("Seed", "Seed", m_Seed);
|
||||||
else if (NoCaseCompare(a_WorldGeneratorName, "flat") == 0)
|
|
||||||
{
|
InitBiomeGen(a_IniFile);
|
||||||
m_pWorldGenerator = new cWGFlat(a_World);
|
InitHeightGen(a_IniFile);
|
||||||
}
|
InitCompositionGen(a_IniFile);
|
||||||
else // Default
|
InitStructureGens(a_IniFile);
|
||||||
{
|
InitFinishGens(a_IniFile);
|
||||||
m_pWorldGenerator = new cWorldGenerator(a_World);
|
|
||||||
}
|
a_IniFile.WriteFile();
|
||||||
|
|
||||||
return super::Start();
|
return super::Start();
|
||||||
}
|
}
|
||||||
|
@ -71,16 +78,201 @@ void cChunkGenerator::Stop(void)
|
||||||
m_Event.Set();
|
m_Event.Set();
|
||||||
m_evtRemoved.Set(); // Wake up anybody waiting for empty queue
|
m_evtRemoved.Set(); // Wake up anybody waiting for empty queue
|
||||||
Wait();
|
Wait();
|
||||||
|
|
||||||
delete m_pWorldGenerator;
|
// Delete the generating composition:
|
||||||
m_pWorldGenerator = NULL;
|
for (cFinishGenList::const_iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
|
||||||
|
{
|
||||||
|
delete *itr;
|
||||||
|
}
|
||||||
|
m_FinishGens.clear();
|
||||||
|
for (cStructureGenList::const_iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
|
||||||
|
{
|
||||||
|
delete *itr;
|
||||||
|
}
|
||||||
|
m_StructureGens.clear();
|
||||||
|
delete m_CompositionGen;
|
||||||
|
m_CompositionGen = NULL;
|
||||||
|
delete m_HeightGen;
|
||||||
|
m_HeightGen = NULL;
|
||||||
|
delete m_BiomeGen;
|
||||||
|
m_BiomeGen = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cChunkGenerator::InitBiomeGen(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
AString BiomeGenName = a_IniFile.GetValue("Generator", "BiomeGen", "");
|
||||||
|
if (BiomeGenName.empty())
|
||||||
|
{
|
||||||
|
LOGWARN("[Generator]::BiomeGen value not found in world.ini, using \"constant\".");
|
||||||
|
BiomeGenName = "constant";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NoCaseCompare(BiomeGenName, "constant") == 0)
|
||||||
|
{
|
||||||
|
int Biome = a_IniFile.GetValueI("Generator", "ConstantBiome", biPlains);
|
||||||
|
m_BiomeGen = new cBioGenConstant((EMCSBiome)Biome);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(BiomeGenName, "checkerboard") == 0)
|
||||||
|
{
|
||||||
|
int BiomeSize = a_IniFile.GetValueI("Generator", "CheckerboardBiomeSize", 64);
|
||||||
|
m_BiomeGen = new cBioGenCheckerboard(BiomeSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (NoCaseCompare(BiomeGenName, "distortedvoronoi") != 0)
|
||||||
|
{
|
||||||
|
LOGWARNING("Unknown BiomeGen \"%s\", using \"distortedvoronoi\" instead.", BiomeGenName.c_str());
|
||||||
|
}
|
||||||
|
m_BiomeGen = new cBioGenDistortedVoronoi(m_Seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkGenerator::InitHeightGen(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
AString HeightGenName = a_IniFile.GetValue("Generator", "HeightGen", "");
|
||||||
|
if (HeightGenName.empty())
|
||||||
|
{
|
||||||
|
LOGWARN("[Generator]::HeightGen value not found in world.ini, using \"classic\".");
|
||||||
|
HeightGenName = "classic";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NoCaseCompare(HeightGenName, "flat") == 0)
|
||||||
|
{
|
||||||
|
int Height = a_IniFile.GetValueI("Generator", "FlatHeight", 5);
|
||||||
|
m_HeightGen = new cHeiGenFlat(Height);
|
||||||
|
}
|
||||||
|
else // "classic" or <not found>
|
||||||
|
{
|
||||||
|
if (NoCaseCompare(HeightGenName, "classic") != 0)
|
||||||
|
{
|
||||||
|
LOGWARN("Unknown HeightGen \"%s\", using \"classic\" instead.", HeightGenName.c_str());
|
||||||
|
}
|
||||||
|
// These used to be in terrain.ini, but now they are in world.ini (so that multiple worlds can have different values):
|
||||||
|
float HeightFreq1 = (float)a_IniFile.GetValueF("Generator", "ClassicHeightFreq1", 0.1);
|
||||||
|
float HeightFreq2 = (float)a_IniFile.GetValueF("Generator", "ClassicHeightFreq2", 1.0);
|
||||||
|
float HeightFreq3 = (float)a_IniFile.GetValueF("Generator", "ClassicHeightFreq3", 2.0);
|
||||||
|
float HeightAmp1 = (float)a_IniFile.GetValueF("Generator", "ClassicHeightAmp1", 1.0);
|
||||||
|
float HeightAmp2 = (float)a_IniFile.GetValueF("Generator", "ClassicHeightAmp2", 0.5);
|
||||||
|
float HeightAmp3 = (float)a_IniFile.GetValueF("Generator", "ClassicHeightAmp3", 0.5);
|
||||||
|
m_HeightGen = new cHeiGenClassic(m_Seed, HeightFreq1, HeightAmp1, HeightFreq2, HeightAmp2, HeightFreq3, HeightAmp3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkGenerator::InitCompositionGen(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
AString CompoGenName = a_IniFile.GetValue("Generator", "CompositionGen", "");
|
||||||
|
if (CompoGenName.empty())
|
||||||
|
{
|
||||||
|
LOGWARN("[Generator]::CompositionGen value not found in world.ini, using \"classic\".");
|
||||||
|
CompoGenName = "classic";
|
||||||
|
}
|
||||||
|
if (NoCaseCompare(CompoGenName, "sameblock") == 0)
|
||||||
|
{
|
||||||
|
AString BlockType = a_IniFile.GetValue("Generator", "SameBlockType", "");
|
||||||
|
if (BlockType.empty())
|
||||||
|
{
|
||||||
|
LOGWARN("[Generator]::SameBlockType value not found in world.ini, using \"stone\".");
|
||||||
|
BlockType = "stone";
|
||||||
|
}
|
||||||
|
int Block = BlockStringToType(BlockType);
|
||||||
|
if (Block < 0)
|
||||||
|
{
|
||||||
|
LOGWARN("World.ini: [Generator]::SameBlockType value \"%s\" not parseable (use a number or alias from items.ini), using \"stone\" (1).", BlockType.c_str());
|
||||||
|
Block = E_BLOCK_STONE;
|
||||||
|
}
|
||||||
|
bool Bedrocked = (a_IniFile.GetValueI("Generator", "SameBlockBedrocked", 1) != 0);
|
||||||
|
m_CompositionGen = new cCompoGenSameBlock((BLOCKTYPE)Block, Bedrocked);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
|
||||||
|
{
|
||||||
|
m_CompositionGen = new cCompoGenDebugBiomes(m_BiomeGen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (NoCaseCompare(CompoGenName, "classic") != 0)
|
||||||
|
{
|
||||||
|
LOGWARN("Unknown CompositionGen \"%s\", using \"classic\" instead.", CompoGenName.c_str());
|
||||||
|
}
|
||||||
|
int SeaLevel = a_IniFile.GetValueI("Generator", "ClassicSeaLevel", 60);
|
||||||
|
int BeachHeight = a_IniFile.GetValueI("Generator", "ClassicBeachHeight", 2);
|
||||||
|
int BeachDepth = a_IniFile.GetValueI("Generator", "ClassicBeachDepth", 4);
|
||||||
|
m_CompositionGen = new cCompoGenClassic(SeaLevel, BeachHeight, BeachDepth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkGenerator::InitStructureGens(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
AString Structures = a_IniFile.GetValue("Generator", "Structures", "Trees,MarbleCaves");
|
||||||
|
|
||||||
|
AStringVector Str = StringSplit(Structures, ",");
|
||||||
|
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (NoCaseCompare(*itr, "trees") == 0)
|
||||||
|
{
|
||||||
|
m_StructureGens.push_back(new cStructGenTrees(m_Seed, m_BiomeGen, m_HeightGen, m_CompositionGen));
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(*itr, "marblecaves") == 0)
|
||||||
|
{
|
||||||
|
m_StructureGens.push_back(new cStructGenMarbleCaves(m_Seed));
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(*itr, "orenests") == 0)
|
||||||
|
{
|
||||||
|
m_StructureGens.push_back(new cStructGenOreNests(m_Seed));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGWARNING("Unknown structure generator: \"%s\". Ignoring.", itr->c_str());
|
||||||
|
}
|
||||||
|
} // for itr - Str[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkGenerator::InitFinishGens(cIniFile & a_IniFile)
|
||||||
|
{
|
||||||
|
AString Structures = a_IniFile.GetValue("Generator", "Finishers", "SprinkleFoliage");
|
||||||
|
|
||||||
|
AStringVector Str = StringSplit(Structures, ",");
|
||||||
|
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
|
||||||
|
{
|
||||||
|
if (NoCaseCompare(*itr, "SprinkleFoliage") == 0)
|
||||||
|
{
|
||||||
|
m_FinishGens.push_back(new cFinishGenSprinkleFoliage(m_Seed));
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(*itr, "Snow") == 0)
|
||||||
|
{
|
||||||
|
m_FinishGens.push_back(new cFinishGenSnow);
|
||||||
|
}
|
||||||
|
else if (NoCaseCompare(*itr, "Ice") == 0)
|
||||||
|
{
|
||||||
|
m_FinishGens.push_back(new cFinishGenIce);
|
||||||
|
}
|
||||||
|
} // for itr - Str[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkGenerator::QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
|
@ -110,6 +302,15 @@ void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkGenerator::GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap)
|
||||||
|
{
|
||||||
|
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, a_BiomeMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkGenerator::WaitForQueueEmpty(void)
|
void cChunkGenerator::WaitForQueueEmpty(void)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CS);
|
cCSLock Lock(m_CS);
|
||||||
|
@ -134,6 +335,20 @@ int cChunkGenerator::GetQueueLength(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EMCSBiome cChunkGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
|
||||||
|
{
|
||||||
|
cChunkDef::BiomeMap Biomes;
|
||||||
|
int Y = 0;
|
||||||
|
int ChunkX, ChunkZ;
|
||||||
|
cWorld::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, Y, ChunkZ);
|
||||||
|
m_BiomeGen->GenBiomes(ChunkX, ChunkZ, Biomes);
|
||||||
|
return cChunkDef::GetBiome(Biomes, a_BlockX, a_BlockZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkGenerator::Execute(void)
|
void cChunkGenerator::Execute(void)
|
||||||
{
|
{
|
||||||
while (!m_ShouldTerminate)
|
while (!m_ShouldTerminate)
|
||||||
|
@ -182,22 +397,34 @@ void cChunkGenerator::Execute(void)
|
||||||
|
|
||||||
void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
{
|
{
|
||||||
BLOCKTYPE BlockData[cChunkDef::BlockDataSize];
|
cChunkDef::BiomeMap BiomeMap;
|
||||||
|
cChunkDef::BlockTypes BlockTypes;
|
||||||
|
cChunkDef::BlockNibbles BlockMeta;
|
||||||
|
cChunkDef::HeightMap HeightMap;
|
||||||
cEntityList Entities;
|
cEntityList Entities;
|
||||||
cBlockEntityList BlockEntities;
|
cBlockEntityList BlockEntities;
|
||||||
m_pWorldGenerator->GenerateChunk(a_ChunkX, a_ChunkY, a_ChunkZ, BlockData, Entities, BlockEntities);
|
|
||||||
|
|
||||||
m_World->ChunkDataGenerated(
|
// Use the composed generator:
|
||||||
|
m_BiomeGen->GenBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
|
||||||
|
m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, HeightMap);
|
||||||
|
m_CompositionGen->ComposeTerrain(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, Entities, BlockEntities);
|
||||||
|
for (cStructureGenList::iterator itr = m_StructureGens.begin(); itr != m_StructureGens.end(); ++itr)
|
||||||
|
{
|
||||||
|
(*itr)->GenStructures(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, Entities, BlockEntities);
|
||||||
|
} // for itr - m_StructureGens[]
|
||||||
|
for (cFinishGenList::iterator itr = m_FinishGens.begin(); itr != m_FinishGens.end(); ++itr)
|
||||||
|
{
|
||||||
|
(*itr)->GenFinish(a_ChunkX, a_ChunkZ, BlockTypes, BlockMeta, HeightMap, BiomeMap, Entities, BlockEntities);
|
||||||
|
} // for itr - m_FinishGens[]
|
||||||
|
|
||||||
|
m_World->SetChunkData(
|
||||||
a_ChunkX, a_ChunkY, a_ChunkZ,
|
a_ChunkX, a_ChunkY, a_ChunkZ,
|
||||||
BlockData,
|
BlockTypes, BlockMeta,
|
||||||
BlockData + cChunkDef::MetaOffset,
|
NULL, NULL, // We don't have lighting, chunk will be lighted when needed
|
||||||
BlockData + cChunkDef::LightOffset,
|
&HeightMap, &BiomeMap,
|
||||||
BlockData + cChunkDef::SkyLightOffset,
|
Entities, BlockEntities,
|
||||||
NULL,
|
true
|
||||||
Entities, BlockEntities
|
|
||||||
);
|
);
|
||||||
|
|
||||||
m_pWorldGenerator->PostGenerateChunk(a_ChunkX, a_ChunkY, a_ChunkZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,20 @@
|
||||||
|
|
||||||
// Interfaces to the cChunkGenerator class representing the thread that generates chunks
|
// Interfaces to the cChunkGenerator class representing the thread that generates chunks
|
||||||
|
|
||||||
// The object takes requests for generating chunks and processes them in a separate thread one by one.
|
/*
|
||||||
// The requests are not added to the queue if there is already a request with the same coords
|
The object takes requests for generating chunks and processes them in a separate thread one by one.
|
||||||
// Before generating, the thread checks if the chunk hasn't been already generated.
|
The requests are not added to the queue if there is already a request with the same coords
|
||||||
// It is theoretically possible to have multiple generator threads by having multiple instances of this object
|
Before generating, the thread checks if the chunk hasn't been already generated.
|
||||||
// but then it MAY happen that the chunk is generated twice
|
It is theoretically possible to have multiple generator threads by having multiple instances of this object,
|
||||||
// If the generator queue is overloaded, the generator skips chunks with no clients in them
|
but then it MAY happen that the chunk is generated twice.
|
||||||
|
If the generator queue is overloaded, the generator skips chunks with no clients in them
|
||||||
|
|
||||||
|
Generating works by composing several algorithms:
|
||||||
|
Biome, TerrainHeight, TerrainComposition, Ores, Structures and SmallFoliage
|
||||||
|
Each algorithm may be chosen from a pool of available algorithms in the same class and combined with others,
|
||||||
|
based on user's preferences in the world.ini.
|
||||||
|
See http://forum.mc-server.org/showthread.php?tid=409 for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,13 +31,130 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd:
|
||||||
class cWorld;
|
class cWorld;
|
||||||
|
class cIniFile;
|
||||||
|
|
||||||
|
// TODO: remove this:
|
||||||
class cWorldGenerator;
|
class cWorldGenerator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The interface that a biome generator must implement
|
||||||
|
A biome generator takes chunk coords on input and outputs an array of biome indices for that chunk on output.
|
||||||
|
The output array is sequenced in the same way as the MapChunk packet's biome data.
|
||||||
|
*/
|
||||||
|
class cBiomeGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~cBiomeGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
|
/// Generates biomes for the given chunk
|
||||||
|
virtual void GenBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The interface that a terrain height generator must implement
|
||||||
|
A terrain height generator takes chunk coords on input and outputs an array of terrain heights for that chunk.
|
||||||
|
The output array is sequenced in the same way as the BiomeGen's biome data.
|
||||||
|
The generator may request biome information from the underlying BiomeGen, it may even request information for
|
||||||
|
other chunks than the one it's currently generating (possibly neighbors - for averaging)
|
||||||
|
*/
|
||||||
|
class cTerrainHeightGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~cTerrainHeightGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
|
/// Generates heightmap for the given chunk
|
||||||
|
virtual void GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The interface that a terrain composition generator must implement
|
||||||
|
Terrain composition takes chunk coords on input and outputs the blockdata for that entire chunk, along with
|
||||||
|
the list of entities. It is supposed to make use of the underlying TerrainHeightGen and BiomeGen for that purpose,
|
||||||
|
but it may request information for other chunks than the one it's currently generating from them.
|
||||||
|
*/
|
||||||
|
class cTerrainCompositionGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~cTerrainCompositionGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
|
virtual void ComposeTerrain(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // BlockTypes to be generated (the whole array gets initialized, even air)
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // BlockMetas to be generated (the whole array gets initialized)
|
||||||
|
const cChunkDef::HeightMap & a_HeightMap, // The height map to fit
|
||||||
|
cEntityList & a_Entities, // Entitites may be generated along with the terrain
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entitites may be generated (chests / furnaces / ...)
|
||||||
|
) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The interface that a structure generator must implement
|
||||||
|
Structures are generated after the terrain composition took place. It should modify the blocktype data to account
|
||||||
|
for whatever structures the generator is generating.
|
||||||
|
Note that ores are considered structures too, at least from the interface point of view.
|
||||||
|
Also note that a worldgenerator may contain multiple structure generators, one for each type of structure
|
||||||
|
*/
|
||||||
|
class cStructureGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~cStructureGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
|
virtual void GenStructures(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef std::list<cStructureGen *> cStructureGenList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** The interface that a finisher must implement
|
||||||
|
Finisher implements small additions after all structures have been generated.
|
||||||
|
*/
|
||||||
|
class cFinishGen
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~cFinishGen() {} // Force a virtual destructor in descendants
|
||||||
|
|
||||||
|
virtual void GenFinish(
|
||||||
|
int a_ChunkX, int a_ChunkZ,
|
||||||
|
cChunkDef::BlockTypes & a_BlockTypes, // Block types to read and change
|
||||||
|
cChunkDef::BlockNibbles & a_BlockMeta, // Block meta to read and change
|
||||||
|
cChunkDef::HeightMap & a_HeightMap, // Height map to read and change by the current data
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap, // Biomes to adhere to
|
||||||
|
cEntityList & a_Entities, // Entities may be added or deleted
|
||||||
|
cBlockEntityList & a_BlockEntities // Block entities may be added or deleted
|
||||||
|
) = 0;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef std::list<cFinishGen *> cFinishGenList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// The chunk generator itself
|
||||||
class cChunkGenerator :
|
class cChunkGenerator :
|
||||||
cIsThread
|
cIsThread
|
||||||
{
|
{
|
||||||
|
@ -40,25 +165,55 @@ public:
|
||||||
cChunkGenerator (void);
|
cChunkGenerator (void);
|
||||||
~cChunkGenerator();
|
~cChunkGenerator();
|
||||||
|
|
||||||
bool Start(cWorld * a_World, const AString & a_WorldGeneratorName);
|
bool Start(cWorld * a_World, cIniFile & a_IniFile);
|
||||||
void Stop(void);
|
void Stop(void);
|
||||||
|
|
||||||
void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests
|
void QueueGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests
|
||||||
|
|
||||||
|
/// Generates the biomes for the specified chunk (directly, not in a separate thread)
|
||||||
|
void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap);
|
||||||
|
|
||||||
void WaitForQueueEmpty(void);
|
void WaitForQueueEmpty(void);
|
||||||
|
|
||||||
int GetQueueLength(void);
|
int GetQueueLength(void);
|
||||||
|
|
||||||
|
int GetSeed(void) const { return m_Seed; }
|
||||||
|
|
||||||
|
EMCSBiome GetBiomeAt(int a_BlockX, int a_BlockZ);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
cWorld * m_World;
|
cWorld * m_World;
|
||||||
cWorldGenerator * m_pWorldGenerator;
|
|
||||||
|
// The generation composition:
|
||||||
|
cBiomeGen * m_BiomeGen;
|
||||||
|
cTerrainHeightGen * m_HeightGen;
|
||||||
|
cTerrainCompositionGen * m_CompositionGen;
|
||||||
|
cStructureGenList m_StructureGens;
|
||||||
|
cFinishGenList m_FinishGens;
|
||||||
|
|
||||||
|
int m_Seed;
|
||||||
|
|
||||||
cCriticalSection m_CS;
|
cCriticalSection m_CS;
|
||||||
cChunkCoordsList m_Queue;
|
cChunkCoordsList m_Queue;
|
||||||
cEvent m_Event; // Set when an item is added to the queue or the thread should terminate
|
cEvent m_Event; // Set when an item is added to the queue or the thread should terminate
|
||||||
cEvent m_evtRemoved; // Set when an item is removed from the queue
|
cEvent m_evtRemoved; // Set when an item is removed from the queue
|
||||||
|
|
||||||
|
/// Reads the biome gen settings from the ini and initializes m_BiomeGen accordingly
|
||||||
|
void InitBiomeGen(cIniFile & a_IniFile);
|
||||||
|
|
||||||
|
/// Reads the HeightGen settings from the ini and initializes m_HeightGen accordingly
|
||||||
|
void InitHeightGen(cIniFile & a_IniFile);
|
||||||
|
|
||||||
|
/// Reads the CompositionGen settings from the ini and initializes m_CompositionGen accordingly
|
||||||
|
void InitCompositionGen(cIniFile & a_IniFile);
|
||||||
|
|
||||||
|
/// Reads the structures to generate from the ini and initializes m_StructureGens accordingly
|
||||||
|
void InitStructureGens(cIniFile & a_IniFile);
|
||||||
|
|
||||||
|
/// Reads the finishers from the ini and initializes m_FinishGens accordingly
|
||||||
|
void InitFinishGens(cIniFile & a_IniFile);
|
||||||
|
|
||||||
// cIsThread override:
|
// cIsThread override:
|
||||||
virtual void Execute(void) override;
|
virtual void Execute(void) override;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "cItem.h"
|
#include "cItem.h"
|
||||||
#include "cPickup.h"
|
#include "cPickup.h"
|
||||||
#include "cChunk.h"
|
#include "cChunk.h"
|
||||||
|
#include "Trees.h" // used in cChunkMap::ReplaceTreeBlocks() for tree block discrimination
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <cstdlib> // abs
|
#include <cstdlib> // abs
|
||||||
|
@ -276,15 +277,17 @@ void cChunkMap::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::ChunkDataLoaded(
|
void cChunkMap::SetChunkData(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const BLOCKTYPE * a_BlockTypes,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const NIBBLETYPE * a_BlockMeta,
|
||||||
const BLOCKTYPE * a_BlockLight,
|
const NIBBLETYPE * a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
const NIBBLETYPE * a_BlockSkyLight,
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
const cChunkDef::HeightMap * a_HeightMap,
|
||||||
cEntityList & a_Entities,
|
const cChunkDef::BiomeMap & a_BiomeMap,
|
||||||
cBlockEntityList & a_BlockEntities
|
cEntityList & a_Entities,
|
||||||
|
cBlockEntityList & a_BlockEntities,
|
||||||
|
bool a_MarkDirty
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
|
@ -293,37 +296,32 @@ void cChunkMap::ChunkDataLoaded(
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Chunk->SetAllData(a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_Entities, a_BlockEntities);
|
Chunk->SetAllData(a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_BiomeMap, a_Entities, a_BlockEntities);
|
||||||
Chunk->MarkLoaded();
|
Chunk->SetValid();
|
||||||
|
|
||||||
|
if (a_MarkDirty)
|
||||||
|
{
|
||||||
|
Chunk->MarkDirty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::ChunkDataGenerated(
|
void cChunkMap::ChunkLighted(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const cChunkDef::BlockNibbles & a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const cChunkDef::BlockNibbles & a_SkyLight
|
||||||
const BLOCKTYPE * a_BlockLight,
|
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
|
||||||
cEntityList & a_Entities,
|
|
||||||
cBlockEntityList & a_BlockEntities
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkY, a_ChunkZ);
|
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
if (Chunk == NULL)
|
if (Chunk == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Chunk->SetAllData(a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_Entities, a_BlockEntities);
|
Chunk->SetLight(a_BlockLight, a_SkyLight);
|
||||||
|
|
||||||
// TODO: This has to go - lighting takes way too long to execute in a locked ChunkMap!
|
|
||||||
Chunk->CalculateLighting();
|
|
||||||
|
|
||||||
Chunk->SetValid();
|
|
||||||
Chunk->MarkDirty();
|
Chunk->MarkDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,9 +592,9 @@ void cChunkMap::SetBlockMeta(int a_X, int a_Y, int a_Z, char a_BlockMeta)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::SetBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta)
|
void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta)
|
||||||
{
|
{
|
||||||
int ChunkX, ChunkZ, X = a_X, Y = a_Y, Z = a_Z;
|
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
|
||||||
cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ );
|
cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ );
|
||||||
|
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
|
@ -611,6 +609,100 @@ void cChunkMap::SetBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCK
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
|
||||||
|
{
|
||||||
|
cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ );
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Chunk->GetBlock(itr->x, itr->y, itr->z) == a_FilterBlockType)
|
||||||
|
{
|
||||||
|
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::ReplaceTreeBlocks(const sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
|
||||||
|
{
|
||||||
|
cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ );
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
switch (Chunk->GetBlock(itr->x, itr->y, itr->z))
|
||||||
|
{
|
||||||
|
CASE_TREE_OVERWRITTEN_BLOCKS:
|
||||||
|
{
|
||||||
|
Chunk->SetBlock(itr->x, itr->y, itr->z, itr->BlockType, itr->BlockMeta);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for itr - a_Blocks[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EMCSBiome cChunkMap::GetBiomeAt (int a_BlockX, int a_BlockZ)
|
||||||
|
{
|
||||||
|
int ChunkX, ChunkZ, X = a_BlockX, Y = 0, Z = a_BlockZ;
|
||||||
|
cChunkDef::AbsoluteToRelative( X, Y, Z, ChunkX, ChunkZ );
|
||||||
|
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunk( ChunkX, ZERO_CHUNK_Y, ChunkZ );
|
||||||
|
if ((Chunk != NULL) && Chunk->IsValid())
|
||||||
|
{
|
||||||
|
return Chunk->GetBiomeAt(X, Z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_World->GetGenerator().GetBiomeAt(a_BlockX, a_BlockZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
|
||||||
|
{
|
||||||
|
bool res = true;
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
for (sSetBlockVector::iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
|
||||||
|
{
|
||||||
|
cChunkPtr Chunk = GetChunk(itr->ChunkX, ZERO_CHUNK_Y, itr->ChunkZ );
|
||||||
|
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
if (!a_ContinueOnFailure)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
res = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z);
|
||||||
|
itr->BlockType = Chunk->GetBlock(idx);
|
||||||
|
itr->BlockMeta = Chunk->GetMeta(idx);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z, cItem & a_PickupItem)
|
bool cChunkMap::DigBlock(int a_X, int a_Y, int a_Z, cItem & a_PickupItem)
|
||||||
{
|
{
|
||||||
int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkZ;
|
int PosX = a_X, PosY = a_Y, PosZ = a_Z, ChunkX, ChunkZ;
|
||||||
|
@ -913,6 +1005,40 @@ void cChunkMap::MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cChunkMap::IsChunkLighted(int a_ChunkX, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
|
if (Chunk == NULL)
|
||||||
|
{
|
||||||
|
// Not present
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return Chunk->IsLightValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty)
|
||||||
|
{
|
||||||
|
a_NumChunksValid = 0;
|
||||||
|
a_NumChunksDirty = 0;
|
||||||
|
cCSLock Lock(m_CSLayers);
|
||||||
|
for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||||
|
{
|
||||||
|
int NumValid = 0, NumDirty = 0;
|
||||||
|
(*itr)->GetChunkStats(NumValid, NumDirty);
|
||||||
|
a_NumChunksValid += NumValid;
|
||||||
|
a_NumChunksDirty += NumDirty;
|
||||||
|
} // for itr - m_Layers[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
|
@ -1053,6 +1179,30 @@ int cChunkMap::cChunkLayer::GetNumChunksLoaded(void) const
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkMap::cChunkLayer::GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const
|
||||||
|
{
|
||||||
|
int NumValid = 0;
|
||||||
|
int NumDirty = 0;
|
||||||
|
for ( int i = 0; i < ARRAYCOUNT(m_Chunks); ++i )
|
||||||
|
{
|
||||||
|
if (m_Chunks[i] == NULL)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NumValid++;
|
||||||
|
if (m_Chunks[i]->IsDirty())
|
||||||
|
{
|
||||||
|
NumDirty++;
|
||||||
|
}
|
||||||
|
} // for i - m_Chunks[]
|
||||||
|
a_NumChunksValid = NumValid;
|
||||||
|
a_NumChunksDirty = NumDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkMap::cChunkLayer::Save(void)
|
void cChunkMap::cChunkLayer::Save(void)
|
||||||
{
|
{
|
||||||
cWorld * World = m_Parent->GetWorld();
|
cWorld * World = m_Parent->GetWorld();
|
||||||
|
@ -1178,7 +1328,7 @@ void cChunkStay::Remove(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
m_Chunks.erase(itr);
|
m_Chunks.erase(itr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} // for itr - Chunks[]
|
} // for itr - m_Chunks[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1197,6 +1347,18 @@ void cChunkStay::Enable(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cChunkStay::Load(void)
|
||||||
|
{
|
||||||
|
for (cChunkCoordsList::iterator itr = m_Chunks.begin(); itr != m_Chunks.end(); ++itr)
|
||||||
|
{
|
||||||
|
m_World->TouchChunk(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
||||||
|
} // for itr - m_Chunks[]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cChunkStay::Disable(void)
|
void cChunkStay::Disable(void)
|
||||||
{
|
{
|
||||||
ASSERT(m_IsEnabled);
|
ASSERT(m_IsEnabled);
|
||||||
|
|
|
@ -49,26 +49,29 @@ public:
|
||||||
void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void MarkChunkSaving (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
|
||||||
void ChunkDataLoaded(
|
/** 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_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const BLOCKTYPE * a_BlockTypes,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const NIBBLETYPE * a_BlockMeta,
|
||||||
const BLOCKTYPE * a_BlockLight,
|
const NIBBLETYPE * a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
const NIBBLETYPE * a_BlockSkyLight,
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
const cChunkDef::HeightMap * a_HeightMap,
|
||||||
|
const cChunkDef::BiomeMap & a_BiomeMap,
|
||||||
cEntityList & a_Entities,
|
cEntityList & a_Entities,
|
||||||
cBlockEntityList & a_BlockEntities
|
cBlockEntityList & a_BlockEntities,
|
||||||
|
bool a_MarkDirty
|
||||||
);
|
);
|
||||||
|
|
||||||
void ChunkDataGenerated (
|
void ChunkLighted(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const cChunkDef::BlockNibbles & a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const cChunkDef::BlockNibbles & a_SkyLight
|
||||||
const BLOCKTYPE * a_BlockLight,
|
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
|
||||||
cEntityList & a_Entities,
|
|
||||||
cBlockEntityList & a_BlockEntities
|
|
||||||
);
|
);
|
||||||
|
|
||||||
bool GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback);
|
bool GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback);
|
||||||
|
@ -90,6 +93,18 @@ public:
|
||||||
BLOCKTYPE GetBlockSkyLight (int a_X, int a_Y, int a_Z);
|
BLOCKTYPE GetBlockSkyLight (int a_X, int a_Y, int a_Z);
|
||||||
void SetBlockMeta (int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockMeta);
|
void SetBlockMeta (int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockMeta);
|
||||||
void SetBlock (int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta);
|
void SetBlock (int a_X, int a_Y, int a_Z, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta);
|
||||||
|
|
||||||
|
/// Replaces world blocks with a_Blocks, if they are of type a_FilterBlockType
|
||||||
|
void ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType);
|
||||||
|
|
||||||
|
/// Special function used for growing trees, replaces only blocks that tree may overwrite
|
||||||
|
void ReplaceTreeBlocks(const sSetBlockVector & a_Blocks);
|
||||||
|
|
||||||
|
EMCSBiome GetBiomeAt (int a_BlockX, int a_BlockZ);
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
bool DigBlock (int a_X, int a_Y, int a_Z, cItem & a_PickupItem);
|
bool DigBlock (int a_X, int a_Y, int a_Z, cItem & a_PickupItem);
|
||||||
void SendBlockTo (int a_X, int a_Y, int a_Z, cPlayer * a_Player);
|
void SendBlockTo (int a_X, int a_Y, int a_Z, cPlayer * a_Player);
|
||||||
|
|
||||||
|
@ -130,6 +145,11 @@ public:
|
||||||
|
|
||||||
/// Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::RegenerateChunk() )
|
/// Marks the chunk as being regenerated - all its clients want that chunk again (used by cWorld::RegenerateChunk() )
|
||||||
void MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ);
|
void MarkChunkRegenerating(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
|
bool IsChunkLighted(int a_ChunkX, int a_ChunkZ);
|
||||||
|
|
||||||
|
/// Returns the number of valid chunks and the number of dirty chunks
|
||||||
|
void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty);
|
||||||
|
|
||||||
void Tick( float a_Dt, MTRand & a_TickRand );
|
void Tick( float a_Dt, MTRand & a_TickRand );
|
||||||
|
|
||||||
|
@ -160,6 +180,8 @@ private:
|
||||||
|
|
||||||
int GetNumChunksLoaded(void) const ;
|
int GetNumChunksLoaded(void) const ;
|
||||||
|
|
||||||
|
void GetChunkStats(int & a_NumChunksValid, int & a_NumChunksDirty) const;
|
||||||
|
|
||||||
void Save(void);
|
void Save(void);
|
||||||
void UnloadUnusedChunks(void);
|
void UnloadUnusedChunks(void);
|
||||||
|
|
||||||
|
@ -218,6 +240,9 @@ public:
|
||||||
void Enable(void);
|
void Enable(void);
|
||||||
void Disable(void);
|
void Disable(void);
|
||||||
|
|
||||||
|
/// Queues each chunk in m_Chunks[] for loading / generating
|
||||||
|
void Load(void);
|
||||||
|
|
||||||
// Allow cChunkStay be passed to functions expecting a const cChunkCoordsList &
|
// Allow cChunkStay be passed to functions expecting a const cChunkCoordsList &
|
||||||
operator const cChunkCoordsList(void) const {return m_Chunks; }
|
operator const cChunkCoordsList(void) const {return m_Chunks; }
|
||||||
|
|
||||||
|
|
|
@ -436,9 +436,11 @@ void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
|
||||||
if (World->AddChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, this))
|
if (World->AddChunkClient(a_ChunkX, a_ChunkY, a_ChunkZ, this))
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSChunkLists);
|
{
|
||||||
m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
cCSLock Lock(m_CSChunkLists);
|
||||||
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||||
|
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkY, a_ChunkZ));
|
||||||
|
}
|
||||||
World->SendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, this);
|
World->SendChunkTo(a_ChunkX, a_ChunkY, a_ChunkZ, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1708,6 +1710,7 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter out map chunks that the client doesn't want anymore:
|
||||||
if (a_Packet.m_PacketID == E_MAP_CHUNK)
|
if (a_Packet.m_PacketID == E_MAP_CHUNK)
|
||||||
{
|
{
|
||||||
// Check chunks being sent, erase them from m_ChunksToSend:
|
// Check chunks being sent, erase them from m_ChunksToSend:
|
||||||
|
@ -1727,7 +1730,33 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* =
|
||||||
} // for itr - m_ChunksToSend[]
|
} // for itr - m_ChunksToSend[]
|
||||||
if (!Found)
|
if (!Found)
|
||||||
{
|
{
|
||||||
LOGD("Refusing to send chunk [%d, %d] - no longer wanted by client \"%s\".", ChunkX, ChunkZ, m_Username.c_str());
|
// This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it
|
||||||
|
// It's not a big issue anyway, just means that some chunks may be compressed several times
|
||||||
|
// LOGD("Refusing to send chunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter out pre chunks that the client doesn't want anymore:
|
||||||
|
if ((a_Packet.m_PacketID == E_PRE_CHUNK) && ((cPacket_PreChunk &)a_Packet).m_bLoad)
|
||||||
|
{
|
||||||
|
int ChunkX = ((cPacket_PreChunk &)a_Packet).m_PosX;
|
||||||
|
int ChunkZ = ((cPacket_PreChunk &)a_Packet).m_PosZ;
|
||||||
|
bool Found = false;
|
||||||
|
cCSLock Lock(m_CSChunkLists);
|
||||||
|
for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr)
|
||||||
|
{
|
||||||
|
if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
|
||||||
|
{
|
||||||
|
Found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for itr - m_ChunksToSend[]
|
||||||
|
if (!Found)
|
||||||
|
{
|
||||||
|
// This just sometimes happens. If you have a reliably replicatable situation for this, go ahead and fix it
|
||||||
|
// It's not a big issue anyway, just means that some chunks may be compressed several times
|
||||||
|
// LOGD("Refusing to send PREchunk [%d, %d] to client \"%s\" at [%d, %d].", ChunkX, ChunkZ, m_Username.c_str(), m_Player->GetChunkX(), m_Player->GetChunkZ());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ bool cFireSimulator::IsForeverBurnable( char a_BlockID )
|
||||||
|
|
||||||
bool cFireSimulator::IsBurnable( char a_BlockID )
|
bool cFireSimulator::IsBurnable( char a_BlockID )
|
||||||
{
|
{
|
||||||
return a_BlockID == E_BLOCK_WOOD
|
return a_BlockID == E_BLOCK_PLANKS
|
||||||
|| a_BlockID == E_BLOCK_LEAVES
|
|| a_BlockID == E_BLOCK_LEAVES
|
||||||
|| a_BlockID == E_BLOCK_LOG
|
|| a_BlockID == E_BLOCK_LOG
|
||||||
|| a_BlockID == E_BLOCK_WHITE_CLOTH
|
|| a_BlockID == E_BLOCK_WHITE_CLOTH
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cSimulator.h"
|
#include "cSimulator.h"
|
||||||
#include "cBlockEntity.h"
|
#include "cBlockEntity.h"
|
||||||
#include <list>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Vector3i;
|
class Vector3i;
|
||||||
class cWorld;
|
class cWorld;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cFireSimulator : public cSimulator
|
class cFireSimulator : public cSimulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -30,4 +40,8 @@ protected:
|
||||||
BlockList *m_Buffer;
|
BlockList *m_Buffer;
|
||||||
|
|
||||||
BlockList *m_BurningBlocks;
|
BlockList *m_BurningBlocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cItem;
|
class cItem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cFurnaceRecipe
|
class cFurnaceRecipe
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -31,4 +39,8 @@ private:
|
||||||
|
|
||||||
struct sFurnaceRecipeState;
|
struct sFurnaceRecipeState;
|
||||||
sFurnaceRecipeState* m_pState;
|
sFurnaceRecipeState* m_pState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
|
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
||||||
|
|
||||||
#include "cGenSettings.h"
|
|
||||||
|
|
||||||
|
|
||||||
float cGenSettings::HeightFreq1 = 0.1f;
|
|
||||||
float cGenSettings::HeightFreq2 = 1.f;
|
|
||||||
float cGenSettings::HeightFreq3 = 2.f;
|
|
||||||
|
|
||||||
float cGenSettings::HeightAmp1 = 1.f;
|
|
||||||
float cGenSettings::HeightAmp2 = 0.5f;
|
|
||||||
float cGenSettings::HeightAmp3 = 0.5f;
|
|
|
@ -1,9 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class cGenSettings
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static float HeightFreq1, HeightAmp1;
|
|
||||||
static float HeightFreq2, HeightAmp2;
|
|
||||||
static float HeightFreq3, HeightAmp3;
|
|
||||||
};
|
|
|
@ -1,8 +1,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
class cGroup //tolua_export
|
class cGroup //tolua_export
|
||||||
{ //tolua_export
|
{ //tolua_export
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cTCPLink.h"
|
#include "cTCPLink.h"
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cHeartBeat : public cTCPLink
|
class cHeartBeat : public cTCPLink
|
||||||
{
|
{
|
||||||
|
@ -18,4 +21,8 @@ private:
|
||||||
void SendUpdate();
|
void SendUpdate();
|
||||||
|
|
||||||
std::string m_ServerID;
|
std::string m_ServerID;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
#pragma once
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
struct lua_State;
|
struct lua_State;
|
||||||
class cPlugin;
|
class cPlugin;
|
||||||
class cPlayer;
|
class cPlayer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cLuaCommandBinder
|
class cLuaCommandBinder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -32,5 +34,9 @@ private:
|
||||||
|
|
||||||
typedef std::map< std::string, BoundFunction > CommandMap;
|
typedef std::map< std::string, BoundFunction > CommandMap;
|
||||||
CommandMap m_BoundCommands;
|
CommandMap m_BoundCommands;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cPawn.h"
|
#include "cPawn.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
#include "cWorld.h"
|
#include "cWorld.h"
|
||||||
#include "BlockID.h"
|
#include "BlockID.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Vector3f;
|
class Vector3f;
|
||||||
class cClientHandle;
|
class cClientHandle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cMonster : public cPawn //tolua_export
|
class cMonster : public cPawn //tolua_export
|
||||||
{ //tolua_export
|
{ //tolua_export
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -37,6 +37,11 @@ public:
|
||||||
__NOISE_INLINE__ float IntNoise2D( int a_X, int a_Y ) const;
|
__NOISE_INLINE__ float IntNoise2D( int a_X, int a_Y ) const;
|
||||||
__NOISE_INLINE__ float IntNoise3D( int a_X, int a_Y, int a_Z ) const;
|
__NOISE_INLINE__ float IntNoise3D( int a_X, int a_Y, int a_Z ) const;
|
||||||
|
|
||||||
|
// Note: These functions have a mod8-irregular chance - each of the mod8 remainders has different chance of occurrence. Divide by 8 to rectify.
|
||||||
|
__NOISE_INLINE__ int IntNoise1DInt( int a_X ) const;
|
||||||
|
__NOISE_INLINE__ int IntNoise2DInt( int a_X, int a_Y ) const;
|
||||||
|
__NOISE_INLINE__ int IntNoise3DInt( int a_X, int a_Y, int a_Z ) const;
|
||||||
|
|
||||||
float LinearNoise1D( float a_X ) const;
|
float LinearNoise1D( float a_X ) const;
|
||||||
float CosineNoise1D( float a_X ) const;
|
float CosineNoise1D( float a_X ) const;
|
||||||
float CubicNoise1D( float a_X ) const;
|
float CubicNoise1D( float a_X ) const;
|
||||||
|
|
|
@ -1,34 +1,85 @@
|
||||||
|
|
||||||
#ifndef __C_NOISE_INC__
|
#ifndef __C_NOISE_INC__
|
||||||
#define __C_NOISE_INC__
|
#define __C_NOISE_INC__
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Random value generator
|
* Random value generator
|
||||||
**/
|
**/
|
||||||
|
|
||||||
float cNoise::IntNoise( int a_X ) const
|
float cNoise::IntNoise( int a_X ) const
|
||||||
{
|
{
|
||||||
int x = ((a_X*m_Seed)<<13) ^ a_X;
|
int x = ((a_X*m_Seed)<<13) ^ a_X;
|
||||||
return ( 1.0f - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
return ( 1.0f - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float cNoise::IntNoise2D( int a_X, int a_Y ) const
|
float cNoise::IntNoise2D( int a_X, int a_Y ) const
|
||||||
{
|
{
|
||||||
int n = a_X + a_Y * 57 + m_Seed*57*57;
|
int n = a_X + a_Y * 57 + m_Seed*57*57;
|
||||||
n = (n<<13) ^ n;
|
n = (n<<13) ^ n;
|
||||||
return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float cNoise::IntNoise3D( int a_X, int a_Y, int a_Z ) const
|
float cNoise::IntNoise3D( int a_X, int a_Y, int a_Z ) const
|
||||||
{
|
{
|
||||||
int n = a_X + a_Y * 57 + a_Z * 57*57 + m_Seed*57*57*57;
|
int n = a_X + a_Y * 57 + a_Z * 57*57 + m_Seed*57*57*57;
|
||||||
n = (n<<13) ^ n;
|
n = (n<<13) ^ n;
|
||||||
return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cNoise::IntNoise1DInt( int a_X ) const
|
||||||
|
{
|
||||||
|
int x = ((a_X*m_Seed)<<13) ^ a_X;
|
||||||
|
return ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cNoise::IntNoise2DInt( int a_X, int a_Y ) const
|
||||||
|
{
|
||||||
|
int n = a_X + a_Y * 57 + m_Seed*57*57;
|
||||||
|
n = (n<<13) ^ n;
|
||||||
|
return ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cNoise::IntNoise3DInt( int a_X, int a_Y, int a_Z ) const
|
||||||
|
{
|
||||||
|
int n = a_X + a_Y * 57 + a_Z * 57*57 + m_Seed*57*57*57;
|
||||||
|
n = (n<<13) ^ n;
|
||||||
|
return ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Interpolation functions
|
* Interpolation functions
|
||||||
**/
|
**/
|
||||||
|
|
||||||
float cNoise::CubicInterpolate( float a_A, float a_B, float a_C, float a_D, float a_Pct ) const
|
float cNoise::CubicInterpolate( float a_A, float a_B, float a_C, float a_D, float a_Pct ) const
|
||||||
{
|
{
|
||||||
float P = (a_D - a_C) - (a_A - a_B);
|
float P = (a_D - a_C) - (a_A - a_B);
|
||||||
|
@ -39,6 +90,10 @@ float cNoise::CubicInterpolate( float a_A, float a_B, float a_C, float a_D, floa
|
||||||
return ((P * a_Pct + Q) * a_Pct + R) * a_Pct + S;
|
return ((P * a_Pct + Q) * a_Pct + R) * a_Pct + S;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float cNoise::CosineInterpolate( float a_A, float a_B, float a_Pct ) const
|
float cNoise::CosineInterpolate( float a_A, float a_B, float a_Pct ) const
|
||||||
{
|
{
|
||||||
const float ft = a_Pct * 3.1415927f;
|
const float ft = a_Pct * 3.1415927f;
|
||||||
|
@ -46,9 +101,21 @@ float cNoise::CosineInterpolate( float a_A, float a_B, float a_Pct ) const
|
||||||
return a_A*(1-f) + a_B*f;
|
return a_A*(1-f) + a_B*f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
float cNoise::LinearInterpolate( float a_A, float a_B, float a_Pct ) const
|
float cNoise::LinearInterpolate( float a_A, float a_B, float a_Pct ) const
|
||||||
{
|
{
|
||||||
return a_A*(1.f-a_Pct) + a_B*a_Pct;
|
return a_A*(1.f-a_Pct) + a_B*a_Pct;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "MemoryLeak.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class cPacket_BlockPlace;
|
class cPacket_BlockPlace;
|
||||||
class cPacket_PickupSpawn;
|
class cPacket_PickupSpawn;
|
||||||
class cPacket_EntityEquipment;
|
class cPacket_EntityEquipment;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
#pragma once
|
||||||
#include <list>
|
|
||||||
|
|
||||||
class cPickup;
|
class cPickup;
|
||||||
class cPlayer;
|
class cPlayer;
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cPlugin.h"
|
#include "cPlugin.h"
|
||||||
#include <string>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct lua_State lua_State;
|
typedef struct lua_State lua_State;
|
||||||
class cWebPlugin_Lua;
|
class cWebPlugin_Lua;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cPlugin_NewLua : public cPlugin //tolua_export
|
class cPlugin_NewLua : public cPlugin //tolua_export
|
||||||
{ //tolua_export
|
{ //tolua_export
|
||||||
public: //tolua_export
|
public: //tolua_export
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cEntity;
|
class cEntity;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cReferenceManager
|
class cReferenceManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -19,4 +27,8 @@ public:
|
||||||
private:
|
private:
|
||||||
ENUM_REFERENCE_MANAGER_TYPE m_Type;
|
ENUM_REFERENCE_MANAGER_TYPE m_Type;
|
||||||
std::list< cEntity** > m_References;
|
std::list< cEntity** > m_References;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include "cSleep.h"
|
#include "cSleep.h"
|
||||||
#include "cThread.h"
|
#include "cThread.h"
|
||||||
#include "cFileFormatUpdater.h"
|
#include "cFileFormatUpdater.h"
|
||||||
#include "cGenSettings.h"
|
|
||||||
#include "cRedstone.h"
|
#include "cRedstone.h"
|
||||||
|
|
||||||
#include "../iniFile/iniFile.h"
|
#include "../iniFile/iniFile.h"
|
||||||
|
@ -193,31 +192,6 @@ void cRoot::LoadGlobalSettings()
|
||||||
{
|
{
|
||||||
cRedstone::s_UseRedstone = IniFile.GetValueB("Redstone", "SimulateRedstone", true );
|
cRedstone::s_UseRedstone = IniFile.GetValueB("Redstone", "SimulateRedstone", true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// I think this should be removed? I can't believe anybody is using it anyway
|
|
||||||
cIniFile GenSettings("terrain.ini");
|
|
||||||
if( GenSettings.ReadFile() )
|
|
||||||
{
|
|
||||||
#define READ_INI_TERRAIN_VAL( var, type ) cGenSettings::var = (type)GenSettings.GetValueF("Terrain", #var, cGenSettings::var )
|
|
||||||
READ_INI_TERRAIN_VAL( HeightFreq1, float );
|
|
||||||
READ_INI_TERRAIN_VAL( HeightFreq2, float );
|
|
||||||
READ_INI_TERRAIN_VAL( HeightFreq3, float );
|
|
||||||
READ_INI_TERRAIN_VAL( HeightAmp1, float );
|
|
||||||
READ_INI_TERRAIN_VAL( HeightAmp2, float );
|
|
||||||
READ_INI_TERRAIN_VAL( HeightAmp3, float );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#define SET_INI_TERRAIN_VAL( var ) GenSettings.SetValueF("Terrain", #var, cGenSettings::var )
|
|
||||||
SET_INI_TERRAIN_VAL( HeightFreq1 );
|
|
||||||
SET_INI_TERRAIN_VAL( HeightFreq2 );
|
|
||||||
SET_INI_TERRAIN_VAL( HeightFreq3 );
|
|
||||||
SET_INI_TERRAIN_VAL( HeightAmp1 );
|
|
||||||
SET_INI_TERRAIN_VAL( HeightAmp2 );
|
|
||||||
SET_INI_TERRAIN_VAL( HeightAmp3 );
|
|
||||||
GenSettings.WriteFile();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -237,15 +211,15 @@ void cRoot::LoadWorlds()
|
||||||
// Then load the other worlds
|
// Then load the other worlds
|
||||||
unsigned int KeyNum = IniFile.FindKey("Worlds");
|
unsigned int KeyNum = IniFile.FindKey("Worlds");
|
||||||
unsigned int NumWorlds = IniFile.GetNumValues( KeyNum );
|
unsigned int NumWorlds = IniFile.GetNumValues( KeyNum );
|
||||||
if( NumWorlds > 0 )
|
if ( NumWorlds > 0 )
|
||||||
{
|
{
|
||||||
for(unsigned int i = 0; i < NumWorlds; i++)
|
for (unsigned int i = 0; i < NumWorlds; i++)
|
||||||
{
|
{
|
||||||
std::string ValueName = IniFile.GetValueName(KeyNum, i );
|
std::string ValueName = IniFile.GetValueName(KeyNum, i );
|
||||||
if( ValueName.compare("World") == 0 )
|
if( ValueName.compare("World") == 0 )
|
||||||
{
|
{
|
||||||
std::string WorldName = IniFile.GetValue(KeyNum, i );
|
std::string WorldName = IniFile.GetValue(KeyNum, i );
|
||||||
if( WorldName.size() > 0 )
|
if (!WorldName.empty())
|
||||||
{
|
{
|
||||||
cWorld* NewWorld = new cWorld( WorldName.c_str() );
|
cWorld* NewWorld = new cWorld( WorldName.c_str() );
|
||||||
NewWorld->InitializeSpawn();
|
NewWorld->InitializeSpawn();
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
|
|
||||||
void TickWorlds( float a_Dt );
|
void TickWorlds( float a_Dt );
|
||||||
|
|
||||||
|
/// Returns the number of chunks loaded
|
||||||
int GetTotalChunkCount(void); // tolua_export
|
int GetTotalChunkCount(void); // tolua_export
|
||||||
|
|
||||||
/// Saves all chunks in all worlds
|
/// Saves all chunks in all worlds
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "cSimulator.h"
|
#include "cSimulator.h"
|
||||||
#include "cBlockEntity.h"
|
#include "cBlockEntity.h"
|
||||||
#include <list>
|
|
||||||
#include "Vector3i.h"
|
#include "Vector3i.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cWorld;
|
class cWorld;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cSandSimulator : public cSimulator
|
class cSandSimulator : public cSimulator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -23,4 +33,8 @@ protected:
|
||||||
typedef std::list <Vector3i> BlockList;
|
typedef std::list <Vector3i> BlockList;
|
||||||
BlockList * m_Blocks;
|
BlockList * m_Blocks;
|
||||||
BlockList * m_Buffer;
|
BlockList * m_Buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -475,77 +475,92 @@ void cServer::ServerCommand( const char * a_Cmd )
|
||||||
{
|
{
|
||||||
AString Command( a_Cmd );
|
AString Command( a_Cmd );
|
||||||
AStringVector split = StringSplit( Command, " " );
|
AStringVector split = StringSplit( Command, " " );
|
||||||
if( split.size() > 0 )
|
if( split.empty())
|
||||||
{
|
{
|
||||||
if( split[0].compare( "help" ) == 0 )
|
return;
|
||||||
{
|
|
||||||
printf("================== ALL COMMANDS ===================\n");
|
|
||||||
printf("help - Shows this message\n");
|
|
||||||
printf("save-all - Saves all loaded chunks to disk\n");
|
|
||||||
printf("list - Lists all players currently in server\n");
|
|
||||||
printf("unload - Unloads all unused chunks\n");
|
|
||||||
printf("numchunks - Shows number of chunks currently loaded\n");
|
|
||||||
printf("say - Sends a chat message to all players\n");
|
|
||||||
printf("restart - Kicks all clients, and saves everything\n");
|
|
||||||
printf(" and clears memory\n");
|
|
||||||
printf("stop - Saves everything and closes server\n");
|
|
||||||
printf("===================================================\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( split[0].compare( "stop" ) == 0 || split[0].compare( "restart" ) == 0 )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( split[0].compare( "save-all" ) == 0 )
|
|
||||||
{
|
|
||||||
cRoot::Get()->SaveAllChunks(); // TODO - Force ALL worlds to save their chunks
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (split[0].compare("unload") == 0)
|
|
||||||
{
|
|
||||||
LOG("Num loaded chunks before: %i", cRoot::Get()->GetTotalChunkCount() );
|
|
||||||
cRoot::Get()->GetDefaultWorld()->UnloadUnusedChunks(); // TODO: Iterate through ALL worlds
|
|
||||||
LOG("Num loaded chunks after: %i", cRoot::Get()->GetTotalChunkCount() );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( split[0].compare( "list" ) == 0 )
|
|
||||||
{
|
|
||||||
class cPlayerLogger : public cPlayerListCallback
|
|
||||||
{
|
|
||||||
virtual bool Item(cPlayer * a_Player) override
|
|
||||||
{
|
|
||||||
LOG("\t%s @ %s", a_Player->GetName().c_str(), a_Player->GetClientHandle()->GetSocket().GetIPString().c_str());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} Logger;
|
|
||||||
cRoot::Get()->ForEachPlayer(Logger);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if( split[0].compare( "numchunks" ) == 0 )
|
|
||||||
{
|
|
||||||
LOG("Num loaded chunks: %i", cRoot::Get()->GetTotalChunkCount() );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(split[0].compare("monsters") == 0 )
|
|
||||||
{
|
|
||||||
// TODO: cWorld::ListMonsters();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(split.size() > 1)
|
|
||||||
{
|
|
||||||
if( split[0].compare( "say" ) == 0 )
|
|
||||||
{
|
|
||||||
std::string Message = cChatColor::Purple + "[SERVER] " + Command.substr( Command.find_first_of("say") + 4 );
|
|
||||||
LOG("%s", Message.c_str() );
|
|
||||||
Broadcast( cPacket_Chat(Message) );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf("Unknown command, type 'help' for all commands.\n");
|
|
||||||
}
|
}
|
||||||
//LOG("You didn't enter anything? (%s)", a_Cmd.c_str() );
|
|
||||||
|
if( split[0].compare( "help" ) == 0 )
|
||||||
|
{
|
||||||
|
printf("================== ALL COMMANDS ===================\n");
|
||||||
|
printf("help - Shows this message\n");
|
||||||
|
printf("save-all - Saves all loaded chunks to disk\n");
|
||||||
|
printf("list - Lists all players currently in server\n");
|
||||||
|
printf("unload - Unloads all unused chunks\n");
|
||||||
|
printf("numchunks - Shows number of chunks currently loaded\n");
|
||||||
|
printf("chunkstats - Shows chunks statistics\n");
|
||||||
|
printf("say - Sends a chat message to all players\n");
|
||||||
|
printf("restart - Kicks all clients, and saves everything\n");
|
||||||
|
printf(" and clears memory\n");
|
||||||
|
printf("stop - Saves everything and closes server\n");
|
||||||
|
printf("===================================================\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( split[0].compare( "stop" ) == 0 || split[0].compare( "restart" ) == 0 )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( split[0].compare( "save-all" ) == 0 )
|
||||||
|
{
|
||||||
|
cRoot::Get()->SaveAllChunks(); // TODO - Force ALL worlds to save their chunks
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (split[0].compare("unload") == 0)
|
||||||
|
{
|
||||||
|
LOG("Num loaded chunks before: %i", cRoot::Get()->GetTotalChunkCount() );
|
||||||
|
cRoot::Get()->GetDefaultWorld()->UnloadUnusedChunks(); // TODO: Iterate through ALL worlds
|
||||||
|
LOG("Num loaded chunks after: %i", cRoot::Get()->GetTotalChunkCount() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( split[0].compare( "list" ) == 0 )
|
||||||
|
{
|
||||||
|
class cPlayerLogger : public cPlayerListCallback
|
||||||
|
{
|
||||||
|
virtual bool Item(cPlayer * a_Player) override
|
||||||
|
{
|
||||||
|
LOG("\t%s @ %s", a_Player->GetName().c_str(), a_Player->GetClientHandle()->GetSocket().GetIPString().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} Logger;
|
||||||
|
cRoot::Get()->ForEachPlayer(Logger);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( split[0].compare( "numchunks" ) == 0 )
|
||||||
|
{
|
||||||
|
LOG("Num loaded chunks: %i", cRoot::Get()->GetTotalChunkCount() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (split[0].compare("chunkstats") == 0)
|
||||||
|
{
|
||||||
|
// TODO: For each world
|
||||||
|
int NumValid = 0;
|
||||||
|
int NumDirty = 0;
|
||||||
|
int NumInLighting = 0;
|
||||||
|
cRoot::Get()->GetDefaultWorld()->GetChunkStats(NumValid, NumDirty, NumInLighting);
|
||||||
|
LOG("Num loaded chunks: %d", NumValid);
|
||||||
|
LOG("Num dirty chunks: %d", NumDirty);
|
||||||
|
LOG("Num chunks in lighting queue: %d", NumInLighting);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(split[0].compare("monsters") == 0 )
|
||||||
|
{
|
||||||
|
// TODO: cWorld::ListMonsters();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(split.size() > 1)
|
||||||
|
{
|
||||||
|
if( split[0].compare( "say" ) == 0 )
|
||||||
|
{
|
||||||
|
std::string Message = cChatColor::Purple + "[SERVER] " + Command.substr( Command.find_first_of("say") + 4 );
|
||||||
|
LOG("%s", Message.c_str() );
|
||||||
|
Broadcast( cPacket_Chat(Message) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Unknown command, type 'help' for all commands.\n");
|
||||||
|
// LOG("You didn't enter anything? (%s)", a_Cmd.c_str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -249,7 +249,7 @@ cSocket cSocket::Accept()
|
||||||
return SClient;
|
return SClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -310,6 +310,10 @@ bool cWebAdmin::Init( int a_Port )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DWORD WINAPI cWebAdmin::ListenThread(LPVOID lpParam)
|
DWORD WINAPI cWebAdmin::ListenThread(LPVOID lpParam)
|
||||||
#else
|
#else
|
||||||
|
@ -319,7 +323,10 @@ void *cWebAdmin::ListenThread( void *lpParam )
|
||||||
cWebAdmin* self = (cWebAdmin*)lpParam;
|
cWebAdmin* self = (cWebAdmin*)lpParam;
|
||||||
|
|
||||||
self->m_WebServer = new webserver(self->m_Port, Request_Handler );
|
self->m_WebServer = new webserver(self->m_Port, Request_Handler );
|
||||||
self->m_WebServer->Begin();
|
if (!self->m_WebServer->Begin())
|
||||||
|
{
|
||||||
|
LOGWARN("WebServer failed to start! WebAdmin is disabled");
|
||||||
|
}
|
||||||
|
|
||||||
self->m_Event->Set();
|
self->m_Event->Set();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -341,20 +348,8 @@ std::string cWebAdmin::GetTemplate()
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// obtain file size:
|
|
||||||
int lSize = f.GetSize();
|
|
||||||
|
|
||||||
// allocate memory to contain the whole file:
|
|
||||||
std::auto_ptr<char> buffer(new char[lSize]); // auto_ptr deletes the memory in its destructor
|
|
||||||
|
|
||||||
// copy the file into the buffer:
|
// copy the file into the buffer:
|
||||||
if (f.Read(buffer.get(), lSize) != lSize)
|
f.ReadRestOfFile(retVal);
|
||||||
{
|
|
||||||
LOG ("WEBADMIN: Could not read file \"%s\"", SourceFile);
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
retVal.assign(buffer.get(), lSize );
|
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,11 @@
|
||||||
#include "cCavespider.h" //cavespider
|
#include "cCavespider.h" //cavespider
|
||||||
#include "cGhast.h" //Ghast
|
#include "cGhast.h" //Ghast
|
||||||
#include "cZombiepigman.h" //Zombiepigman
|
#include "cZombiepigman.h" //Zombiepigman
|
||||||
#include "cGenSettings.h"
|
|
||||||
#include "cMakeDir.h"
|
#include "cMakeDir.h"
|
||||||
#include "cChunkGenerator.h"
|
#include "cChunkGenerator.h"
|
||||||
#include "MersenneTwister.h"
|
#include "MersenneTwister.h"
|
||||||
#include "cWorldGenerator_Test.h"
|
|
||||||
#include "cTracer.h"
|
#include "cTracer.h"
|
||||||
|
#include "Trees.h"
|
||||||
|
|
||||||
|
|
||||||
#include "packets/cPacket_TimeUpdate.h"
|
#include "packets/cPacket_TimeUpdate.h"
|
||||||
|
@ -71,12 +70,6 @@ const int MAX_LIGHTING_SPREAD_PER_TICK = 10;
|
||||||
|
|
||||||
float cWorld::m_Time = 0.f;
|
float cWorld::m_Time = 0.f;
|
||||||
|
|
||||||
char g_BlockLightValue[128];
|
|
||||||
char g_BlockSpreadLightFalloff[128];
|
|
||||||
bool g_BlockTransparent[128];
|
|
||||||
bool g_BlockOneHitDig[128];
|
|
||||||
bool g_BlockPistonBreakable[128];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -96,6 +89,12 @@ public:
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Stop(void)
|
||||||
|
{
|
||||||
|
m_ShouldTerminate = true;
|
||||||
|
Wait();
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
cWorld * m_World;
|
cWorld * m_World;
|
||||||
|
@ -127,6 +126,53 @@ protected:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// A simple thread that displays the progress of world lighting in cWorld::InitializeSpawn()
|
||||||
|
class cWorldLightingProgress :
|
||||||
|
public cIsThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cWorldLightingProgress(cLightingThread * a_Lighting) :
|
||||||
|
cIsThread("cWorldLightingProgress"),
|
||||||
|
m_Lighting(a_Lighting)
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop(void)
|
||||||
|
{
|
||||||
|
m_ShouldTerminate = true;
|
||||||
|
Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
cLightingThread * m_Lighting;
|
||||||
|
|
||||||
|
virtual void Execute(void) override
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
LOG("%d chunks remaining to light", m_Lighting->GetQueueLength()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Wait for 2 sec, but be "reasonably wakeable" when the thread is to finish
|
||||||
|
for (int i = 0; i < 20; i++)
|
||||||
|
{
|
||||||
|
cSleep::MilliSleep(100);
|
||||||
|
if (m_ShouldTerminate)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // for (-ever)
|
||||||
|
}
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cWorld:
|
// cWorld:
|
||||||
|
|
||||||
|
@ -182,21 +228,6 @@ cWorld::cWorld( const AString & a_WorldName )
|
||||||
, m_RSList ( 0 )
|
, m_RSList ( 0 )
|
||||||
, m_Weather ( eWeather_Sunny )
|
, m_Weather ( eWeather_Sunny )
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
// DEBUG:
|
|
||||||
DWORD Tick = GetTickCount();
|
|
||||||
for (int i = 0; i < 3000; i++)
|
|
||||||
{
|
|
||||||
BLOCKTYPE Playground[cChunkDef::NumBlocks / 2];
|
|
||||||
for (int x = 0; x < 16; x++) for (int z = 0; z < 16; z++) for (int y = 0; y < 256; y++)
|
|
||||||
{
|
|
||||||
cChunkDef::SetNibble(Playground, x, y, z, x);
|
|
||||||
} // for x, y, z
|
|
||||||
} // for i
|
|
||||||
Tick = GetTickCount() - Tick;
|
|
||||||
LOGINFO("3000 chunkfulls of SetNibble() took %d ticks", Tick);
|
|
||||||
//*/
|
|
||||||
|
|
||||||
LOG("cWorld::cWorld(%s)", a_WorldName.c_str());
|
LOG("cWorld::cWorld(%s)", a_WorldName.c_str());
|
||||||
m_WorldName = a_WorldName;
|
m_WorldName = a_WorldName;
|
||||||
m_IniFileName = m_WorldName + "/world.ini";
|
m_IniFileName = m_WorldName + "/world.ini";
|
||||||
|
@ -207,10 +238,8 @@ cWorld::cWorld( const AString & a_WorldName )
|
||||||
m_SpawnX = (double)((r1.randInt()%1000)-500);
|
m_SpawnX = (double)((r1.randInt()%1000)-500);
|
||||||
m_SpawnY = cChunkDef::Height;
|
m_SpawnY = cChunkDef::Height;
|
||||||
m_SpawnZ = (double)((r1.randInt()%1000)-500);
|
m_SpawnZ = (double)((r1.randInt()%1000)-500);
|
||||||
m_WorldSeed = r1.randInt();
|
|
||||||
m_GameMode = eGameMode_Creative;
|
m_GameMode = eGameMode_Creative;
|
||||||
|
|
||||||
AString GeneratorName;
|
|
||||||
AString StorageSchema("Default");
|
AString StorageSchema("Default");
|
||||||
|
|
||||||
cIniFile IniFile(m_IniFileName);
|
cIniFile IniFile(m_IniFileName);
|
||||||
|
@ -219,9 +248,7 @@ cWorld::cWorld( const AString & a_WorldName )
|
||||||
m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX );
|
m_SpawnX = IniFile.GetValueF("SpawnPosition", "X", m_SpawnX );
|
||||||
m_SpawnY = IniFile.GetValueF("SpawnPosition", "Y", m_SpawnY );
|
m_SpawnY = IniFile.GetValueF("SpawnPosition", "Y", m_SpawnY );
|
||||||
m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ );
|
m_SpawnZ = IniFile.GetValueF("SpawnPosition", "Z", m_SpawnZ );
|
||||||
m_WorldSeed = IniFile.GetValueI("Seed", "Seed", m_WorldSeed );
|
|
||||||
m_GameMode = (eGameMode)IniFile.GetValueI("GameMode", "GameMode", m_GameMode );
|
m_GameMode = (eGameMode)IniFile.GetValueI("GameMode", "GameMode", m_GameMode );
|
||||||
GeneratorName = IniFile.GetValue("Generator", "GeneratorName", GeneratorName);
|
|
||||||
StorageSchema = IniFile.GetValue("Storage", "Schema", StorageSchema);
|
StorageSchema = IniFile.GetValue("Storage", "Schema", StorageSchema);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -229,19 +256,17 @@ cWorld::cWorld( const AString & a_WorldName )
|
||||||
IniFile.SetValueF("SpawnPosition", "X", m_SpawnX );
|
IniFile.SetValueF("SpawnPosition", "X", m_SpawnX );
|
||||||
IniFile.SetValueF("SpawnPosition", "Y", m_SpawnY );
|
IniFile.SetValueF("SpawnPosition", "Y", m_SpawnY );
|
||||||
IniFile.SetValueF("SpawnPosition", "Z", m_SpawnZ );
|
IniFile.SetValueF("SpawnPosition", "Z", m_SpawnZ );
|
||||||
IniFile.SetValueI("Seed", "Seed", m_WorldSeed );
|
|
||||||
IniFile.SetValueI("GameMode", "GameMode", m_GameMode );
|
IniFile.SetValueI("GameMode", "GameMode", m_GameMode );
|
||||||
IniFile.SetValue("Generator", "GeneratorName", GeneratorName);
|
|
||||||
IniFile.SetValue("Storage", "Schema", StorageSchema);
|
IniFile.SetValue("Storage", "Schema", StorageSchema);
|
||||||
if( !IniFile.WriteFile() )
|
if( !IniFile.WriteFile() )
|
||||||
{
|
{
|
||||||
LOG("WARNING: Could not write to %s", m_IniFileName.c_str());
|
LOG("WARNING: Could not write to %s", m_IniFileName.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOGINFO("Seed: %i", m_WorldSeed );
|
|
||||||
|
m_Lighting.Start(this);
|
||||||
m_Storage.Start(this, StorageSchema);
|
m_Storage.Start(this, StorageSchema);
|
||||||
m_Generator.Start(this, GeneratorName);
|
m_Generator.Start(this, IniFile);
|
||||||
|
|
||||||
m_bAnimals = true;
|
m_bAnimals = true;
|
||||||
m_SpawnMonsterRate = 10;
|
m_SpawnMonsterRate = 10;
|
||||||
|
@ -277,105 +302,6 @@ cWorld::cWorld( const AString & a_WorldName )
|
||||||
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
|
m_SimulatorManager->RegisterSimulator(m_SandSimulator, 1);
|
||||||
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10);
|
m_SimulatorManager->RegisterSimulator(m_FireSimulator, 10);
|
||||||
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
|
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
|
||||||
|
|
||||||
memset( g_BlockLightValue, 0x0, sizeof( g_BlockLightValue ) );
|
|
||||||
memset( g_BlockSpreadLightFalloff, 0xf, sizeof( g_BlockSpreadLightFalloff ) ); // 0xf means total falloff
|
|
||||||
memset( g_BlockTransparent, 0x0, sizeof( g_BlockTransparent ) );
|
|
||||||
memset( g_BlockOneHitDig, 0x0, sizeof( g_BlockOneHitDig ) );
|
|
||||||
memset( g_BlockPistonBreakable, 0x0, sizeof( g_BlockPistonBreakable ) );
|
|
||||||
|
|
||||||
// Emissive blocks
|
|
||||||
g_BlockLightValue[ E_BLOCK_TORCH ] = 14;
|
|
||||||
g_BlockLightValue[ E_BLOCK_FIRE ] = 15;
|
|
||||||
g_BlockLightValue[ E_BLOCK_LAVA ] = 15;
|
|
||||||
g_BlockLightValue[ E_BLOCK_STATIONARY_LAVA ] = 15;
|
|
||||||
g_BlockLightValue[ E_BLOCK_GLOWSTONE ] = 15;
|
|
||||||
|
|
||||||
// Spread blocks
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_AIR ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_TORCH ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_FIRE ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_LAVA ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_STATIONARY_LAVA ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_WATER ] = 4; // Light in water dissapears faster
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_STATIONARY_WATER ] = 4;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_LEAVES ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_GLASS ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_GLOWSTONE ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_SIGN_POST ] = 1;
|
|
||||||
g_BlockSpreadLightFalloff[ E_BLOCK_WALLSIGN ] = 1;
|
|
||||||
|
|
||||||
// Transparent blocks
|
|
||||||
g_BlockTransparent[ E_BLOCK_AIR ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_GLASS ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_FIRE ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_ICE ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_TORCH ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_SIGN_POST ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_WALLSIGN ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_TALL_GRASS ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_YELLOW_FLOWER ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_RED_ROSE ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_RED_MUSHROOM ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_BROWN_MUSHROOM ] = true;
|
|
||||||
g_BlockTransparent[ E_BLOCK_SNOW ] = true;
|
|
||||||
|
|
||||||
// TODO: Any other transparent blocks?
|
|
||||||
|
|
||||||
// One hit break blocks
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_SAPLING ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_YELLOW_FLOWER ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_RED_ROSE ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_BROWN_MUSHROOM ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_RED_MUSHROOM ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_TNT ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_TORCH ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REDSTONE_WIRE ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_CROPS ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REDSTONE_TORCH_OFF ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REDSTONE_TORCH_ON ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REEDS ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REDSTONE_WIRE ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REDSTONE_REPEATER_OFF ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_REDSTONE_REPEATER_ON ] = true;
|
|
||||||
g_BlockOneHitDig[ E_BLOCK_LOCKED_CHEST ] = true;
|
|
||||||
g_BlockOneHitDig [ E_BLOCK_FIRE ] = true;
|
|
||||||
|
|
||||||
// Blocks that breaks when pushed by piston
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_AIR ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_STATIONARY_WATER ] = false; //This gave pistons the ability to drop water :D
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_WATER ] = false;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_STATIONARY_LAVA ] = false;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_LAVA ] = false;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_BED ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_COBWEB ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_TALL_GRASS ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_YELLOW_FLOWER ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_BROWN_MUSHROOM ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_RED_ROSE ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_RED_MUSHROOM ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_DEAD_BUSH ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_TORCH ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_FIRE ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_REDSTONE_WIRE ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_CROPS ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_LADDER ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_WOODEN_DOOR ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_IRON_DOOR ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_LEVER ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_STONE_BUTTON ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_REDSTONE_TORCH_ON ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_REDSTONE_TORCH_OFF ]= true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_SNOW ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_REEDS ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_PUMPKIN_STEM ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_MELON_STEM ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_MELON ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_PUMPKIN ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_JACK_O_LANTERN ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_VINES ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_STONE_PRESSURE_PLATE ] = true;
|
|
||||||
g_BlockPistonBreakable[ E_BLOCK_WOODEN_PRESSURE_PLATE ] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,7 +360,7 @@ void cWorld::CastThunderbolt ( int a_X, int a_Y, int a_Z )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::InitializeSpawn()
|
void cWorld::InitializeSpawn(void)
|
||||||
{
|
{
|
||||||
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
|
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
|
||||||
BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ );
|
BlockToChunk( (int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ );
|
||||||
|
@ -446,24 +372,51 @@ void cWorld::InitializeSpawn()
|
||||||
int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
|
int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is
|
||||||
#endif // _DEBUG
|
#endif // _DEBUG
|
||||||
|
|
||||||
LOG("Preparing spawn area in world \"%s\"", m_WorldName.c_str());
|
LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str());
|
||||||
for (int x = 0; x < ViewDist; x++)
|
for (int x = 0; x < ViewDist; x++)
|
||||||
{
|
{
|
||||||
for (int z = 0; z < ViewDist; z++)
|
for (int z = 0; z < ViewDist; z++)
|
||||||
{
|
{
|
||||||
m_ChunkMap->TouchChunk( x + ChunkX-(ViewDist - 1) / 2, 0, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader
|
m_ChunkMap->TouchChunk( x + ChunkX-(ViewDist - 1) / 2, ZERO_CHUNK_Y, z + ChunkZ-(ViewDist - 1) / 2 ); // Queue the chunk in the generator / loader
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display progress during this process:
|
{
|
||||||
cWorldLoadProgress Progress(this);
|
// Display progress during this process:
|
||||||
|
cWorldLoadProgress Progress(this);
|
||||||
|
|
||||||
|
// Wait for the loader to finish loading
|
||||||
|
m_Storage.WaitForQueuesEmpty();
|
||||||
|
|
||||||
|
// Wait for the generator to finish generating
|
||||||
|
m_Generator.WaitForQueueEmpty();
|
||||||
|
|
||||||
|
Progress.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for the loader to finish loading
|
// Light all chunks that have been newly generated:
|
||||||
m_Storage.WaitForQueuesEmpty();
|
LOG("Lighting spawn area in world \"%s\"...", m_WorldName.c_str());
|
||||||
|
|
||||||
// Wait for the generator to finish generating
|
for (int x = 0; x < ViewDist; x++)
|
||||||
m_Generator.WaitForQueueEmpty();
|
{
|
||||||
|
int ChX = x + ChunkX-(ViewDist - 1) / 2;
|
||||||
|
for (int z = 0; z < ViewDist; z++)
|
||||||
|
{
|
||||||
|
int ChZ = z + ChunkZ-(ViewDist - 1) / 2;
|
||||||
|
if (!m_ChunkMap->IsChunkLighted(ChX, ChZ))
|
||||||
|
{
|
||||||
|
m_Lighting.QueueChunk(ChX, ChZ); // Queue the chunk in the lighting thread
|
||||||
|
}
|
||||||
|
} // for z
|
||||||
|
} // for x
|
||||||
|
|
||||||
|
{
|
||||||
|
cWorldLightingProgress Progress(&m_Lighting);
|
||||||
|
m_Lighting.WaitForQueueEmpty();
|
||||||
|
Progress.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Better spawn detection - move spawn out of the water if it isn't set in the INI already
|
||||||
m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height
|
m_SpawnY = (double)GetHeight( (int)m_SpawnX, (int)m_SpawnZ ) + 1.6f; // +1.6f eye height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,8 +461,6 @@ void cWorld::Tick(float a_Dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TickLighting();
|
|
||||||
|
|
||||||
m_ChunkMap->Tick(a_Dt, m_TickRand);
|
m_ChunkMap->Tick(a_Dt, m_TickRand);
|
||||||
|
|
||||||
GetSimulatorManager()->Simulate(a_Dt);
|
GetSimulatorManager()->Simulate(a_Dt);
|
||||||
|
@ -523,7 +474,7 @@ void cWorld::Tick(float a_Dt)
|
||||||
std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue);
|
std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue);
|
||||||
}
|
}
|
||||||
m_ChunkMap->FastSetBlocks(FastSetBlockQueueCopy);
|
m_ChunkMap->FastSetBlocks(FastSetBlockQueueCopy);
|
||||||
if (FastSetBlockQueueCopy.size() > 0)
|
if (!FastSetBlockQueueCopy.empty())
|
||||||
{
|
{
|
||||||
// Some blocks failed, store them for next tick:
|
// Some blocks failed, store them for next tick:
|
||||||
cCSLock Lock(m_CSFastSetBlock);
|
cCSLock Lock(m_CSFastSetBlock);
|
||||||
|
@ -716,30 +667,17 @@ void cWorld::TickSpawnMobs(float a_Dt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::TickLighting(void)
|
void cWorld::GrowTree( int a_X, int a_Y, int a_Z )
|
||||||
{
|
{
|
||||||
// To avoid a deadlock, we lock the spread queue only long enough to pick the chunk coords to spread
|
if (GetBlock(a_X, a_Y, a_Z) == E_BLOCK_SAPLING)
|
||||||
// The spreading itself will run unlocked
|
|
||||||
cChunkCoordsList SpreadQueue;
|
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLighting);
|
// There is a sapling here, grow a tree according to its type:
|
||||||
if (m_SpreadQueue.size() == 0)
|
GrowTreeFromSapling(a_X, a_Y, a_Z, GetBlockMeta(a_X, a_Y, a_Z));
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (m_SpreadQueue.size() >= MAX_LIGHTING_SPREAD_PER_TICK )
|
|
||||||
{
|
|
||||||
LOGWARN("cWorld: Lots of lighting to do! Still %i chunks left!", m_SpreadQueue.size() );
|
|
||||||
}
|
|
||||||
// Move up to MAX_LIGHTING_SPREAD_PER_TICK elements from m_SpreadQueue out into SpreadQueue:
|
|
||||||
cChunkCoordsList::iterator itr = m_SpreadQueue.begin();
|
|
||||||
std::advance(itr, MIN(m_SpreadQueue.size(), MAX_LIGHTING_SPREAD_PER_TICK));
|
|
||||||
SpreadQueue.splice(SpreadQueue.begin(), m_SpreadQueue, m_SpreadQueue.begin(), itr);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
for (cChunkCoordsList::iterator itr = SpreadQueue.begin(); itr != SpreadQueue.end(); ++itr)
|
|
||||||
{
|
{
|
||||||
m_ChunkMap->SpreadChunkLighting(itr->m_ChunkX, itr->m_ChunkY, itr->m_ChunkZ);
|
// There is nothing here, grow a tree based on the current biome here:
|
||||||
|
GrowTreeByBiome(a_X, a_Y, a_Z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,73 +685,84 @@ void cWorld::TickLighting(void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::GrowTree( int a_X, int a_Y, int a_Z )
|
void cWorld::GrowTreeFromSapling(int a_X, int a_Y, int a_Z, char a_SaplingMeta)
|
||||||
{
|
{
|
||||||
// new tree code, looks much better
|
cNoise Noise(m_Generator.GetSeed());
|
||||||
// with help from seanj
|
sSetBlockVector Blocks;
|
||||||
// converted from php to lua then lua to c++
|
switch (a_SaplingMeta & 0x07)
|
||||||
|
|
||||||
// build trunk
|
|
||||||
MTRand r1;
|
|
||||||
int trunk = r1.randInt() % (7 - 5 + 1) + 5;
|
|
||||||
for (int i = 0; i < trunk; i++)
|
|
||||||
{
|
{
|
||||||
FastSetBlock( a_X, a_Y + i, a_Z, E_BLOCK_LOG, 0 );
|
case E_META_SAPLING_APPLE: GetAppleTreeImage (a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break;
|
||||||
|
case E_META_SAPLING_BIRCH: GetBirchTreeImage (a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break;
|
||||||
|
case E_META_SAPLING_CONIFER: GetConiferTreeImage(a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break;
|
||||||
|
case E_META_SAPLING_JUNGLE: GetJungleTreeImage (a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), Blocks); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GrowTreeImage(Blocks);
|
||||||
|
}
|
||||||
|
|
||||||
// build tree
|
|
||||||
for (int j = 0; j < trunk; j++)
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::GrowTreeByBiome(int a_X, int a_Y, int a_Z)
|
||||||
|
{
|
||||||
|
cNoise Noise(m_Generator.GetSeed());
|
||||||
|
sSetBlockVector Blocks;
|
||||||
|
GetTreeImageByBiome(a_X, a_Y, a_Z, Noise, (int)(m_WorldTime & 0xffffffff), (EMCSBiome)GetBiomeAt(a_X, a_Z), Blocks);
|
||||||
|
GrowTreeImage(Blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::GrowTreeImage(const sSetBlockVector & a_Blocks)
|
||||||
|
{
|
||||||
|
// Check that the tree has place to grow
|
||||||
|
|
||||||
|
// Make a copy of the log blocks:
|
||||||
|
sSetBlockVector b2;
|
||||||
|
for (sSetBlockVector::const_iterator itr = a_Blocks.begin(); itr != a_Blocks.end(); ++itr)
|
||||||
{
|
{
|
||||||
int radius = trunk - j;
|
if (itr->BlockType == E_BLOCK_LOG)
|
||||||
if (radius < 4)
|
|
||||||
{
|
{
|
||||||
if (radius > 2)
|
b2.push_back(*itr);
|
||||||
|
}
|
||||||
|
} // for itr - a_Blocks[]
|
||||||
|
|
||||||
|
// Query blocktypes and metas at those log blocks:
|
||||||
|
if (!GetBlocks(b2, false))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that at each log's coord there's an block allowed to be overwritten:
|
||||||
|
for (sSetBlockVector::const_iterator itr = b2.begin(); itr != b2.end(); ++itr)
|
||||||
|
{
|
||||||
|
switch (itr->BlockType)
|
||||||
|
{
|
||||||
|
CASE_TREE_ALLOWED_BLOCKS:
|
||||||
{
|
{
|
||||||
radius = 2;
|
break;
|
||||||
}
|
}
|
||||||
for (int i = a_X - radius; i <= a_X + radius; i++)
|
default:
|
||||||
{
|
{
|
||||||
for (int k = a_Z-radius; k <= a_Z + radius; k++)
|
return;
|
||||||
{
|
|
||||||
// small chance to be missing a block to add a little random
|
|
||||||
if (k != a_Z || i != a_X && (r1.randInt() % 100 + 1) > 20)
|
|
||||||
{
|
|
||||||
if( GetBlock( i, a_Y + j, k ) == E_BLOCK_AIR )
|
|
||||||
{
|
|
||||||
FastSetBlock(i, a_Y+j, k, E_BLOCK_LEAVES, 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//if( m_BlockType[ MakeIndex(i, TopY+j, k) ] == E_BLOCK_AIR )
|
|
||||||
// m_BlockType[ MakeIndex(i, TopY+j, k) ] = E_BLOCK_LEAVES;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GetBlock( a_X, a_Y+j, a_Z ) == E_BLOCK_AIR )
|
|
||||||
{
|
|
||||||
FastSetBlock( a_X, a_Y+j, a_Z, E_BLOCK_LOG, 0 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // for itr - b2[]
|
||||||
|
|
||||||
|
// All ok, replace blocks with the tree image:
|
||||||
|
m_ChunkMap->ReplaceTreeBlocks(a_Blocks);
|
||||||
|
}
|
||||||
|
|
||||||
// do the top
|
|
||||||
if( GetBlock( a_X+1, a_Y+trunk, a_Z ) == E_BLOCK_AIR )
|
|
||||||
FastSetBlock( a_X+1, a_Y+trunk, a_Z, E_BLOCK_LEAVES, 0 );
|
|
||||||
|
|
||||||
if( GetBlock( a_X-1, a_Y+trunk, a_Z ) == E_BLOCK_AIR )
|
|
||||||
FastSetBlock( a_X-1, a_Y+trunk, a_Z, E_BLOCK_LEAVES, 0 );
|
|
||||||
|
|
||||||
if( GetBlock( a_X, a_Y+trunk, a_Z+1 ) == E_BLOCK_AIR )
|
|
||||||
FastSetBlock( a_X, a_Y+trunk, a_Z+1, E_BLOCK_LEAVES, 0 );
|
|
||||||
|
|
||||||
if( GetBlock( a_X, a_Y+trunk, a_Z-1 ) == E_BLOCK_AIR )
|
|
||||||
FastSetBlock( a_X, a_Y+trunk, a_Z-1, E_BLOCK_LEAVES, 0 );
|
|
||||||
|
|
||||||
if( GetBlock( a_X, a_Y+trunk, a_Z ) == E_BLOCK_AIR )
|
int cWorld::GetBiomeAt (int a_BlockX, int a_BlockZ)
|
||||||
FastSetBlock( a_X, a_Y+trunk, a_Z, E_BLOCK_LEAVES, 0 );
|
{
|
||||||
|
return m_ChunkMap->GetBiomeAt(a_BlockX, a_BlockZ);
|
||||||
// end new tree code
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -905,6 +854,24 @@ char cWorld::GetBlockSkyLight( int a_X, int a_Y, int a_Z )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::ReplaceBlocks(const sSetBlockVector & a_Blocks, BLOCKTYPE a_FilterBlockType)
|
||||||
|
{
|
||||||
|
m_ChunkMap->ReplaceBlocks(a_Blocks, a_FilterBlockType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWorld::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure)
|
||||||
|
{
|
||||||
|
return m_ChunkMap->GetBlocks(a_Blocks, a_ContinueOnFailure);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem )
|
bool cWorld::DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem )
|
||||||
{
|
{
|
||||||
bool res = m_ChunkMap->DigBlock(a_X, a_Y, a_Z, a_PickupItem);
|
bool res = m_ChunkMap->DigBlock(a_X, a_Y, a_Z, a_PickupItem);
|
||||||
|
@ -1018,38 +985,58 @@ void cWorld::MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::ChunkDataLoaded(
|
void cWorld::SetChunkData(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const BLOCKTYPE * a_BlockTypes,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const NIBBLETYPE * a_BlockMeta,
|
||||||
const BLOCKTYPE * a_BlockLight,
|
const NIBBLETYPE * a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
const NIBBLETYPE * a_BlockSkyLight,
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
const cChunkDef::HeightMap * a_HeightMap,
|
||||||
|
const cChunkDef::BiomeMap * a_BiomeMap,
|
||||||
cEntityList & a_Entities,
|
cEntityList & a_Entities,
|
||||||
cBlockEntityList & a_BlockEntities
|
cBlockEntityList & a_BlockEntities,
|
||||||
|
bool a_MarkDirty
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_ChunkMap->ChunkDataLoaded(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_Entities, a_BlockEntities);
|
// Validate biomes, if needed:
|
||||||
m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ);
|
cChunkDef::BiomeMap BiomeMap;
|
||||||
|
const cChunkDef::BiomeMap * Biomes = a_BiomeMap;
|
||||||
|
if (a_BiomeMap == NULL)
|
||||||
|
{
|
||||||
|
// The biomes are not assigned, get them from the generator:
|
||||||
|
Biomes = &BiomeMap;
|
||||||
|
m_Generator.GenerateBiomes(a_ChunkX, a_ChunkZ, BiomeMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ChunkMap->SetChunkData(
|
||||||
|
a_ChunkX, a_ChunkY, a_ChunkZ,
|
||||||
|
a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight,
|
||||||
|
a_HeightMap, *Biomes,
|
||||||
|
a_Entities, a_BlockEntities,
|
||||||
|
a_MarkDirty
|
||||||
|
);
|
||||||
|
|
||||||
|
// If a client is requesting this chunk, send it to them:
|
||||||
|
if (m_ChunkMap->HasChunkAnyClients(a_ChunkX, a_ChunkY, a_ChunkZ))
|
||||||
|
{
|
||||||
|
m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the lighting thread that the chunk has become valid (in case it is a neighbor of a postponed chunk):
|
||||||
|
m_Lighting.ChunkReady(a_ChunkX, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::ChunkDataGenerated(
|
void cWorld::ChunkLighted(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const cChunkDef::BlockNibbles & a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const cChunkDef::BlockNibbles & a_SkyLight
|
||||||
const BLOCKTYPE * a_BlockLight,
|
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
|
||||||
cEntityList & a_Entities,
|
|
||||||
cBlockEntityList & a_BlockEntities
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
m_ChunkMap->ChunkDataGenerated(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockTypes, a_BlockMeta, a_BlockLight, a_BlockSkyLight, a_HeightMap, a_Entities, a_BlockEntities);
|
m_ChunkMap->ChunkLighted(a_ChunkX, a_ChunkZ, a_BlockLight, a_SkyLight);
|
||||||
m_ChunkSender.ChunkReady(a_ChunkX, a_ChunkY, a_ChunkZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1431,14 +1418,41 @@ void cWorld::RegenerateChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
|
m_ChunkMap->MarkChunkRegenerating(a_ChunkX, a_ChunkZ);
|
||||||
|
|
||||||
// Trick: use Y=1 to force the chunk generation even though the chunk data is already present
|
// Trick: use Y=1 to force the chunk generation even though the chunk data is already present
|
||||||
m_Generator.GenerateChunk(a_ChunkX, 1, a_ChunkZ);
|
m_Generator.QueueGenerateChunk(a_ChunkX, 1, a_ChunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorld::SaveAllChunks()
|
void cWorld::GenerateChunk(int a_ChunkX, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
m_Generator.QueueGenerateChunk(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::QueueLightChunk(int a_ChunkX, int a_ChunkZ, cChunkCoordCallback * a_Callback)
|
||||||
|
{
|
||||||
|
m_Lighting.QueueChunk(a_ChunkX, a_ChunkZ, a_Callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cWorld::IsChunkLighted(int a_ChunkX, int a_ChunkZ)
|
||||||
|
{
|
||||||
|
return m_ChunkMap->IsChunkLighted(a_ChunkX, a_ChunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::SaveAllChunks(void)
|
||||||
{
|
{
|
||||||
LOG("Saving all chunks...");
|
LOG("Saving all chunks...");
|
||||||
m_LastSave = m_Time;
|
m_LastSave = m_Time;
|
||||||
|
@ -1514,3 +1528,13 @@ int cWorld::GetNumChunks(void) const
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cWorld::GetChunkStats(int & a_NumValid, int & a_NumDirty, int & a_NumInLightingQueue)
|
||||||
|
{
|
||||||
|
m_ChunkMap->GetChunkStats(a_NumValid, a_NumDirty);
|
||||||
|
a_NumInLightingQueue = (int) m_Lighting.GetQueueLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "Vector3f.h"
|
#include "Vector3f.h"
|
||||||
#include "ChunkSender.h"
|
#include "ChunkSender.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
|
#include "LightingThread.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,26 +73,29 @@ public:
|
||||||
void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void MarkChunkSaving(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void MarkChunkSaved (int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
|
||||||
void ChunkDataLoaded(
|
/** 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_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const BLOCKTYPE * a_BlockTypes,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const NIBBLETYPE * a_BlockMeta,
|
||||||
const BLOCKTYPE * a_BlockLight,
|
const NIBBLETYPE * a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
const NIBBLETYPE * a_BlockSkyLight,
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
const cChunkDef::HeightMap * a_HeightMap,
|
||||||
|
const cChunkDef::BiomeMap * a_BiomeMap,
|
||||||
cEntityList & a_Entities,
|
cEntityList & a_Entities,
|
||||||
cBlockEntityList & a_BlockEntities
|
cBlockEntityList & a_BlockEntities,
|
||||||
|
bool a_MarkDirty
|
||||||
);
|
);
|
||||||
|
|
||||||
void ChunkDataGenerated (
|
void ChunkLighted(
|
||||||
int a_ChunkX, int a_ChunkY, int a_ChunkZ,
|
int a_ChunkX, int a_ChunkZ,
|
||||||
const BLOCKTYPE * a_BlockTypes,
|
const cChunkDef::BlockNibbles & a_BlockLight,
|
||||||
const BLOCKTYPE * a_BlockMeta,
|
const cChunkDef::BlockNibbles & a_SkyLight
|
||||||
const BLOCKTYPE * a_BlockLight,
|
|
||||||
const BLOCKTYPE * a_BlockSkyLight,
|
|
||||||
const cChunkDef::HeightMap * a_HeightMap,
|
|
||||||
cEntityList & a_Entities,
|
|
||||||
cBlockEntityList & a_BlockEntities
|
|
||||||
);
|
);
|
||||||
|
|
||||||
bool GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback);
|
bool GetChunkData (int a_ChunkX, int a_ChunkY, int a_ChunkZ, cChunkDataCallback & a_Callback);
|
||||||
|
@ -153,7 +157,7 @@ public:
|
||||||
/// Removes the client from all chunks it is present in
|
/// Removes the client from all chunks it is present in
|
||||||
void RemoveClientFromChunks(cClientHandle * a_Client);
|
void RemoveClientFromChunks(cClientHandle * a_Client);
|
||||||
|
|
||||||
/// Sends the chunk to the client specified, if the chunk is valid. If not valid, the request is ignored (ChunkSender will send that chunk when it becomes valid)
|
/// 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_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
|
void SendChunkTo(int a_ChunkX, int a_ChunkY, int a_ChunkZ, cClientHandle * a_Client);
|
||||||
|
|
||||||
/// Removes client from ChunkSender's queue of chunks to be sent
|
/// Removes client from ChunkSender's queue of chunks to be sent
|
||||||
|
@ -178,6 +182,14 @@ public:
|
||||||
|
|
||||||
/// Regenerate the given chunk:
|
/// Regenerate the given chunk:
|
||||||
void RegenerateChunk(int a_ChunkX, int a_ChunkZ); //tolua_export
|
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);
|
||||||
|
|
||||||
// TODO: Export to Lua
|
// TODO: Export to Lua
|
||||||
bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback );
|
bool DoWithEntity( int a_UniqueID, cEntityCallback & a_Callback );
|
||||||
|
@ -191,6 +203,14 @@ public:
|
||||||
void SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData ); //tolua_export
|
void SetBlockMeta( int a_X, int a_Y, int a_Z, char a_MetaData ); //tolua_export
|
||||||
void SetBlockMeta( const Vector3i & a_Pos, char a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); } //tolua_export
|
void SetBlockMeta( const Vector3i & a_Pos, char a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); } //tolua_export
|
||||||
char GetBlockSkyLight( int a_X, int a_Y, int a_Z ); //tolua_export
|
char GetBlockSkyLight( int a_X, int a_Y, int a_Z ); //tolua_export
|
||||||
|
// TODO: char GetBlockActualLight(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export
|
||||||
|
|
||||||
|
/// 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);
|
||||||
|
|
||||||
bool DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem ); //tolua_export
|
bool DigBlock( int a_X, int a_Y, int a_Z, cItem & a_PickupItem ); //tolua_export
|
||||||
void SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer* a_Player ); //tolua_export
|
void SendBlockTo( int a_X, int a_Y, int a_Z, cPlayer* a_Player ); //tolua_export
|
||||||
|
|
||||||
|
@ -209,9 +229,14 @@ public:
|
||||||
/// a_Player is using block entity at [x, y, z], handle that:
|
/// a_Player is using block entity at [x, y, z], handle that:
|
||||||
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z) {m_ChunkMap->UseBlockEntity(a_Player, a_X, a_Y, a_Z); }
|
void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z) {m_ChunkMap->UseBlockEntity(a_Player, a_X, a_Y, a_Z); }
|
||||||
|
|
||||||
void GrowTree( int a_X, int a_Y, int a_Z ); //tolua_export
|
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);
|
||||||
|
|
||||||
|
int GetBiomeAt (int a_BlockX, int a_BlockZ); // tolua_export
|
||||||
|
|
||||||
unsigned int GetWorldSeed(void) const { return m_WorldSeed; } //tolua_export
|
|
||||||
const AString & GetName(void) const { return m_WorldName; } //tolua_export
|
const AString & GetName(void) const { return m_WorldName; } //tolua_export
|
||||||
const AString & GetIniFileName(void) const {return m_IniFileName; }
|
const AString & GetIniFileName(void) const {return m_IniFileName; }
|
||||||
|
|
||||||
|
@ -242,9 +267,15 @@ public:
|
||||||
if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
|
if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveAllChunks(); //tolua_export
|
void SaveAllChunks(void); //tolua_export
|
||||||
|
|
||||||
|
/// Returns the number of chunks loaded
|
||||||
int GetNumChunks() const; //tolua_export
|
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);
|
||||||
|
|
||||||
|
|
||||||
void Tick(float a_Dt);
|
void Tick(float a_Dt);
|
||||||
|
|
||||||
void ReSpreadLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
void ReSpreadLighting(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
||||||
|
@ -263,7 +294,7 @@ public:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class cRoot;
|
friend class cRoot;
|
||||||
|
|
||||||
// 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)
|
// 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;
|
MTRand m_TickRand;
|
||||||
|
|
||||||
|
@ -306,8 +337,6 @@ private:
|
||||||
float m_SpawnMonsterTime;
|
float m_SpawnMonsterTime;
|
||||||
float m_SpawnMonsterRate;
|
float m_SpawnMonsterRate;
|
||||||
|
|
||||||
unsigned int m_WorldSeed;
|
|
||||||
|
|
||||||
eWeather m_Weather;
|
eWeather m_Weather;
|
||||||
|
|
||||||
cEntityList m_RemoveEntityQueue;
|
cEntityList m_RemoveEntityQueue;
|
||||||
|
@ -324,6 +353,7 @@ private:
|
||||||
cChunkGenerator m_Generator;
|
cChunkGenerator m_Generator;
|
||||||
|
|
||||||
cChunkSender m_ChunkSender;
|
cChunkSender m_ChunkSender;
|
||||||
|
cLightingThread m_Lighting;
|
||||||
|
|
||||||
AString m_WorldName;
|
AString m_WorldName;
|
||||||
AString m_IniFileName;
|
AString m_IniFileName;
|
||||||
|
@ -333,7 +363,6 @@ private:
|
||||||
|
|
||||||
void TickWeather(float a_Dt); // Handles weather each tick
|
void TickWeather(float a_Dt); // Handles weather each tick
|
||||||
void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick
|
void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick
|
||||||
void TickLighting(void); // Handles lighting re-spreading
|
|
||||||
|
|
||||||
void RemoveEntity( cEntity * a_Entity );
|
void RemoveEntity( cEntity * a_Entity );
|
||||||
}; //tolua_export
|
}; //tolua_export
|
||||||
|
|
|
@ -1,438 +0,0 @@
|
||||||
|
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
||||||
|
|
||||||
#include "cWorldGenerator.h"
|
|
||||||
#include "cNoise.h"
|
|
||||||
#include "cWorld.h"
|
|
||||||
#include "cGenSettings.h"
|
|
||||||
|
|
||||||
#include "BlockID.h"
|
|
||||||
#include "Vector3i.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// An array describing an 8-way neighbor coords deltas
|
|
||||||
static struct
|
|
||||||
{
|
|
||||||
int m_X;
|
|
||||||
int m_Z;
|
|
||||||
} g_NeighborCoords[] =
|
|
||||||
{
|
|
||||||
{-1, -1},
|
|
||||||
{-1, 0},
|
|
||||||
{-1, 1},
|
|
||||||
{0, -1},
|
|
||||||
{0, 1},
|
|
||||||
{1, -1},
|
|
||||||
{1, 0},
|
|
||||||
{1, 1},
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// You can use GLASS for these instead for debugging ore generation ;)
|
|
||||||
// Beware though, client has problems with this much glass!
|
|
||||||
const char BLOCK_STONE = E_BLOCK_STONE;
|
|
||||||
const char BLOCK_DIRT = E_BLOCK_DIRT;
|
|
||||||
const char BLOCK_GRASS = E_BLOCK_GRASS;
|
|
||||||
|
|
||||||
const int MAX_HEIGHT_COAL = 127;
|
|
||||||
const int NUM_NESTS_COAL = 40;
|
|
||||||
const int NEST_SIZE_COAL = 10;
|
|
||||||
|
|
||||||
const int MAX_HEIGHT_IRON = 70;
|
|
||||||
const int NUM_NESTS_IRON = 10;
|
|
||||||
const int NEST_SIZE_IRON = 6;
|
|
||||||
|
|
||||||
const int MAX_HEIGHT_REDSTONE = 40;
|
|
||||||
const int NUM_NESTS_REDSTONE = 10;
|
|
||||||
const int NEST_SIZE_REDSTONE = 6;
|
|
||||||
|
|
||||||
const int MAX_HEIGHT_GOLD = 35;
|
|
||||||
const int NUM_NESTS_GOLD = 6;
|
|
||||||
const int NEST_SIZE_GOLD = 6;
|
|
||||||
|
|
||||||
const int MAX_HEIGHT_DIAMOND = 16;
|
|
||||||
const int NUM_NESTS_DIAMOND = 6;
|
|
||||||
const int NEST_SIZE_DIAMOND = 5;
|
|
||||||
|
|
||||||
const int MAX_HEIGHT_LAPIS = 16;
|
|
||||||
const int NUM_NESTS_LAPIS = 6;
|
|
||||||
const int NEST_SIZE_LAPIS = 5;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cWorldGenerator::cWorldGenerator(cWorld * a_World) :
|
|
||||||
m_World(a_World)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cWorldGenerator::~cWorldGenerator()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator::GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities)
|
|
||||||
{
|
|
||||||
GenerateTerrain(a_ChunkX, a_ChunkY, a_ChunkZ, a_BlockData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator::PostGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|
||||||
{
|
|
||||||
// Check the chunk just generated and all its 8-way neighbors
|
|
||||||
|
|
||||||
// Make the chunks stay loaded in the surrounding 5x5 area:
|
|
||||||
cChunkStay Stay(m_World);
|
|
||||||
Stay.Add(a_ChunkX, a_ChunkY, a_ChunkZ);
|
|
||||||
for (int x = -2; x <= 2; x++)
|
|
||||||
{
|
|
||||||
for (int z = -2; z <= 2; z++)
|
|
||||||
{
|
|
||||||
Stay.Add(a_ChunkX + x, a_ChunkY, a_ChunkZ + z);
|
|
||||||
} // for z
|
|
||||||
} // for x
|
|
||||||
Stay.Enable();
|
|
||||||
|
|
||||||
m_World->LoadChunks(Stay);
|
|
||||||
|
|
||||||
CheckNeighbors(a_ChunkX, a_ChunkY, a_ChunkZ);
|
|
||||||
for (int i = 0; i < ARRAYCOUNT(g_NeighborCoords); i++)
|
|
||||||
{
|
|
||||||
CheckNeighbors(a_ChunkX + g_NeighborCoords[i].m_X, a_ChunkY, a_ChunkZ + g_NeighborCoords[i].m_Z);
|
|
||||||
} // for i - g_NeighborCoords[]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator::CheckNeighbors(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|
||||||
{
|
|
||||||
if (!m_World->IsChunkValid(a_ChunkX, a_ChunkY, a_ChunkZ))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all 8-way neighbors, if they are all valid, generate foliage in this chunk:
|
|
||||||
int NumNeighbors = 0;
|
|
||||||
for (int i = 0; i < ARRAYCOUNT(g_NeighborCoords); i++)
|
|
||||||
{
|
|
||||||
if (m_World->IsChunkValid(a_ChunkX + g_NeighborCoords[i].m_X, a_ChunkY, a_ChunkZ + g_NeighborCoords[i].m_Z))
|
|
||||||
{
|
|
||||||
NumNeighbors++;
|
|
||||||
}
|
|
||||||
} // for i - g_NeighborCoords[]
|
|
||||||
if (NumNeighbors == 8)
|
|
||||||
{
|
|
||||||
GenerateFoliage(a_ChunkX, a_ChunkY, a_ChunkZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static float GetNoise( float x, float y, cNoise & a_Noise )
|
|
||||||
{
|
|
||||||
float oct1 = a_Noise.CubicNoise2D( x*cGenSettings::HeightFreq1, y*cGenSettings::HeightFreq1 )*cGenSettings::HeightAmp1;
|
|
||||||
float oct2 = a_Noise.CubicNoise2D( x*cGenSettings::HeightFreq2, y*cGenSettings::HeightFreq2 )*cGenSettings::HeightAmp2;
|
|
||||||
float oct3 = a_Noise.CubicNoise2D( x*cGenSettings::HeightFreq3, y*cGenSettings::HeightFreq3 )*cGenSettings::HeightAmp3;
|
|
||||||
|
|
||||||
float height = a_Noise.CubicNoise2D( x*0.1f, y*0.1f )*2;
|
|
||||||
|
|
||||||
float flatness = ((a_Noise.CubicNoise2D( x*0.5f, y*0.5f ) + 1.f ) * 0.5f) * 1.1f; // 0 ... 1.5
|
|
||||||
flatness *= flatness * flatness;
|
|
||||||
|
|
||||||
return (oct1 + oct2 + oct3) * flatness + height;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define PI_2 (1.57079633f)
|
|
||||||
static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
|
|
||||||
{
|
|
||||||
float oct1 = (a_Noise.CubicNoise3D( x*0.1f, y*0.1f, z*0.1f ))*4;
|
|
||||||
|
|
||||||
oct1 = oct1 * oct1 * oct1;
|
|
||||||
if( oct1 < 0.f ) oct1 = PI_2;
|
|
||||||
if( oct1 > PI_2 ) oct1 = PI_2;
|
|
||||||
|
|
||||||
return oct1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned int cWorldGenerator::MakeIndex(int x, int y, int z )
|
|
||||||
{
|
|
||||||
ASSERT((x < cChunkDef::Width) && (x > -1) && (y < cChunkDef::Height) && (y > -1) && (z < cChunkDef::Width) && (z > -1));
|
|
||||||
|
|
||||||
return cChunkDef::MakeIndexNoCheck( x, y, z );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData)
|
|
||||||
{
|
|
||||||
const int WATER_LEVEL = 60;
|
|
||||||
const int SAND_LEVEL = 3;
|
|
||||||
|
|
||||||
memset(a_BlockData, E_BLOCK_AIR, cChunkDef::BlockDataSize);
|
|
||||||
|
|
||||||
cNoise Noise(m_World->GetWorldSeed());
|
|
||||||
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
const float zz = (float)(a_ChunkZ * cChunkDef::Width + z);
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
// Place bedrock on bottom layer
|
|
||||||
a_BlockData[MakeIndex(x, 0, z)] = E_BLOCK_BEDROCK;
|
|
||||||
|
|
||||||
const float xx = (float)(a_ChunkX * cChunkDef::Width + x);
|
|
||||||
|
|
||||||
int Height = (int)(GetNoise( xx * 0.05f, zz * 0.05f, Noise ) * 16);
|
|
||||||
const int Lower = 64;
|
|
||||||
if ( Height + Lower > 127 )
|
|
||||||
{
|
|
||||||
Height = 127 - Lower;
|
|
||||||
}
|
|
||||||
if (Height < -63)
|
|
||||||
{
|
|
||||||
Height = -63;
|
|
||||||
}
|
|
||||||
const int Top = Lower + Height;
|
|
||||||
const float WaveNoise = 1; // m_Noise.CubicNoise2D( xx*0.01f, zz*0.01f ) + 0.5f;
|
|
||||||
for( int y = 1; y < Top; ++y )
|
|
||||||
{
|
|
||||||
const float yy = (float)y;
|
|
||||||
// V prevent caves from getting too close to the surface
|
|
||||||
if( (Top - y > (WaveNoise*2) ) && cosf(GetMarbleNoise( xx, yy*0.5f, zz, Noise )) * fabs( cosf( yy*0.2f + WaveNoise*2 )*0.75f + WaveNoise ) > 0.5f )
|
|
||||||
{
|
|
||||||
if( y > 4 )
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_AIR;
|
|
||||||
if( z > 0 ) a_BlockData[ MakeIndex(x, y, z-1) ] = E_BLOCK_AIR;
|
|
||||||
if( z < 15 ) a_BlockData[ MakeIndex(x, y, z+1) ] = E_BLOCK_AIR;
|
|
||||||
if( x > 0 ) a_BlockData[ MakeIndex(x-1, y, z) ] = E_BLOCK_AIR;
|
|
||||||
if( x < 15 ) a_BlockData[ MakeIndex(x+1, y, z) ] = E_BLOCK_AIR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_LAVA;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((y < 61) && (Top - y < SAND_LEVEL ))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_SAND;
|
|
||||||
}
|
|
||||||
else if ((y < 61) && (Top - y < 4 ))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_SANDSTONE;
|
|
||||||
}
|
|
||||||
else if (Top - y > ((WaveNoise + 1.5f) * 1.5f)) // rock and ores between 1.5 .. 4.5 deep
|
|
||||||
{
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = BLOCK_STONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = BLOCK_DIRT;
|
|
||||||
}
|
|
||||||
} // for y
|
|
||||||
|
|
||||||
if (Top + 1 >= WATER_LEVEL + SAND_LEVEL)
|
|
||||||
{
|
|
||||||
// Replace top dirt with grass:
|
|
||||||
a_BlockData[MakeIndex(x, Top - 1, z)] = BLOCK_GRASS;
|
|
||||||
|
|
||||||
// Generate small foliage (1-block):
|
|
||||||
int TopY = Top - 1;
|
|
||||||
float val1 = Noise.CubicNoise2D(xx * 0.1f, zz * 0.1f );
|
|
||||||
float val2 = Noise.CubicNoise2D(xx * 0.01f, zz * 0.01f );
|
|
||||||
float val3 = Noise.CubicNoise2D(xx * 0.01f + 10, zz * 0.01f + 10 );
|
|
||||||
float val4 = Noise.CubicNoise2D(xx * 0.05f + 20, zz * 0.05f + 20 );
|
|
||||||
if ((val3 > 0.2f) && ((r1.randInt()%128) > 124))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, TopY + 1, z) ] = E_BLOCK_YELLOW_FLOWER;
|
|
||||||
}
|
|
||||||
else if ((val4 > 0.2f) && ((r1.randInt() % 128) > 124))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, TopY + 1, z) ] = E_BLOCK_RED_ROSE;
|
|
||||||
}
|
|
||||||
else if ((val1 + val2 + val3 + val4 > 0.2f) && ((r1.randInt() % 128) > 124))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, TopY + 1, z) ] = E_BLOCK_RED_MUSHROOM;
|
|
||||||
}
|
|
||||||
else if ((val1 + val2 + val3 + val4 > 0.2f) && ((r1.randInt() % 128) > 124))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, TopY + 1, z) ] = E_BLOCK_BROWN_MUSHROOM;
|
|
||||||
}
|
|
||||||
} // if (Top above beach-level)
|
|
||||||
else if (Top > WATER_LEVEL)
|
|
||||||
{
|
|
||||||
// This is the sandy shore, generate cacti here
|
|
||||||
int TopY = Top - 1;
|
|
||||||
float val1 = Noise.CubicNoise2D(xx * 0.1f, zz * 0.1f );
|
|
||||||
float val2 = Noise.CubicNoise2D(xx * 0.01f, zz * 0.01f );
|
|
||||||
if ((val1 + val2 > 0.f) && ((r1.randInt() % 128) > 124))
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, TopY + 1, z) ] = E_BLOCK_CACTUS;
|
|
||||||
if ((r1.randInt() & 3) == 3)
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, TopY + 2, z) ] = E_BLOCK_CACTUS;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Add water up to the WATER_LEVEL:
|
|
||||||
for (int y = Top; y < WATER_LEVEL; ++y )
|
|
||||||
{
|
|
||||||
a_BlockData[ MakeIndex(x, y, z) ] = E_BLOCK_STATIONARY_WATER;
|
|
||||||
}
|
|
||||||
} // else (Top is under waterlevel)
|
|
||||||
} // for x
|
|
||||||
} // for z
|
|
||||||
|
|
||||||
// Generate ores:
|
|
||||||
GenerateOre(E_BLOCK_COAL_ORE, MAX_HEIGHT_COAL, NUM_NESTS_COAL, NEST_SIZE_COAL, a_BlockData);
|
|
||||||
GenerateOre(E_BLOCK_IRON_ORE, MAX_HEIGHT_IRON, NUM_NESTS_IRON, NEST_SIZE_IRON, a_BlockData);
|
|
||||||
GenerateOre(E_BLOCK_REDSTONE_ORE, MAX_HEIGHT_REDSTONE, NUM_NESTS_REDSTONE, NEST_SIZE_REDSTONE, a_BlockData);
|
|
||||||
GenerateOre(E_BLOCK_GOLD_ORE, MAX_HEIGHT_GOLD, NUM_NESTS_GOLD, NEST_SIZE_GOLD, a_BlockData);
|
|
||||||
GenerateOre(E_BLOCK_DIAMOND_ORE, MAX_HEIGHT_DIAMOND, NUM_NESTS_DIAMOND, NEST_SIZE_DIAMOND, a_BlockData);
|
|
||||||
GenerateOre(E_BLOCK_LAPIS_ORE, MAX_HEIGHT_LAPIS, NUM_NESTS_LAPIS, NEST_SIZE_LAPIS, a_BlockData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator::GenerateOre(char a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, BLOCKTYPE * a_BlockData)
|
|
||||||
{
|
|
||||||
// This function generates several "nests" of ore, each nest consisting of number of ore blocks relatively adjacent to each other.
|
|
||||||
// It does so by making a random XYZ walk and adding ore along the way in cuboids of different (random) sizes
|
|
||||||
// Only stone gets replaced with ore, all other blocks stay (so the nest can actually be smaller than specified).
|
|
||||||
for (int i = 0; i < a_NumNests; i++)
|
|
||||||
{
|
|
||||||
int BaseX = r1.randInt(cChunkDef::Width);
|
|
||||||
int BaseY = r1.randInt(a_MaxHeight);
|
|
||||||
int BaseZ = r1.randInt(cChunkDef::Width);
|
|
||||||
sSetBlockList OreBlocks;
|
|
||||||
size_t NestSize = (size_t)(a_NestSize + r1.randInt(a_NestSize / 4)); // The actual nest size may be up to 1/4 larger
|
|
||||||
while (OreBlocks.size() < NestSize)
|
|
||||||
{
|
|
||||||
// Put a cuboid around [BaseX, BaseY, BaseZ]
|
|
||||||
for (int x = r1.randInt(2); x >= 0; --x)
|
|
||||||
{
|
|
||||||
for (int y = r1.randInt(2); y >= 0; --y)
|
|
||||||
{
|
|
||||||
for (int z = r1.randInt(2); z >= 0; --z)
|
|
||||||
{
|
|
||||||
if (OreBlocks.size() < NestSize)
|
|
||||||
{
|
|
||||||
OreBlocks.push_back(sSetBlock(BaseX + x, BaseY + y, BaseZ + z, a_OreType, 0));
|
|
||||||
}
|
|
||||||
} // for z
|
|
||||||
} // for y
|
|
||||||
} // for x
|
|
||||||
|
|
||||||
// Move the base to a neighbor voxel
|
|
||||||
switch (r1.randInt(4))
|
|
||||||
{
|
|
||||||
case 0: BaseX--; break;
|
|
||||||
case 1: BaseX++; break;
|
|
||||||
}
|
|
||||||
switch (r1.randInt(4))
|
|
||||||
{
|
|
||||||
case 0: BaseY--; break;
|
|
||||||
case 1: BaseY++; break;
|
|
||||||
}
|
|
||||||
switch (r1.randInt(4))
|
|
||||||
{
|
|
||||||
case 0: BaseZ--; break;
|
|
||||||
case 1: BaseZ++; break;
|
|
||||||
}
|
|
||||||
} // while (OreBlocks.size() < NumBlocks)
|
|
||||||
|
|
||||||
// Replace stone with the queued ore blocks:
|
|
||||||
for (sSetBlockList::iterator itr = OreBlocks.begin(); itr != OreBlocks.end(); ++itr)
|
|
||||||
{
|
|
||||||
if ((itr->x < 0) || (itr->y < 0) || (itr->z < 0) || (itr->x >= cChunkDef::Width) || (itr->y >= cChunkDef::Height-1) || (itr->z >= cChunkDef::Width))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int Index = MakeIndex(itr->x, itr->y, itr->z);
|
|
||||||
if (a_BlockData[Index] == BLOCK_STONE)
|
|
||||||
{
|
|
||||||
a_BlockData[Index] = a_OreType;
|
|
||||||
}
|
|
||||||
} // for itr - OreBlocks[]
|
|
||||||
OreBlocks.clear();
|
|
||||||
} // for i
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator::GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|
||||||
{
|
|
||||||
BLOCKTYPE BlockType[cChunkDef::NumBlocks];
|
|
||||||
|
|
||||||
if (!m_World->GetChunkBlockTypes(a_ChunkX, a_ChunkY, a_ChunkZ, BlockType))
|
|
||||||
{
|
|
||||||
LOGWARNING("Cannot generate foliage on chunk [%d, %d]", a_ChunkX, a_ChunkZ);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cNoise Noise(m_World->GetWorldSeed());
|
|
||||||
for (int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
int zz = z + a_ChunkZ * cChunkDef::Width;
|
|
||||||
for (int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
int xx = x + a_ChunkX * cChunkDef::Width;
|
|
||||||
|
|
||||||
int TopY = m_World->GetHeight(xx, zz);
|
|
||||||
int index = cChunkDef::MakeIndexNoCheck(x, MAX(TopY - 1, 0), z);
|
|
||||||
if (BlockType[index] == BLOCK_GRASS)
|
|
||||||
{
|
|
||||||
float val1 = Noise.CubicNoise2D( xx * 0.1f, zz * 0.1f );
|
|
||||||
float val2 = Noise.CubicNoise2D( xx * 0.01f, zz * 0.01f );
|
|
||||||
if ((val1 + val2 > 0.2f) && ((r1.randInt() % 128) > 124))
|
|
||||||
{
|
|
||||||
m_World->GrowTree( xx, TopY, zz );
|
|
||||||
}
|
|
||||||
} // if (Grass)
|
|
||||||
} // for x
|
|
||||||
} // for z
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,53 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "ChunkDef.h"
|
|
||||||
#include "MersenneTwister.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// fwd:
|
|
||||||
class cWorld;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cWorldGenerator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cWorldGenerator(cWorld * a_World);
|
|
||||||
~cWorldGenerator();
|
|
||||||
|
|
||||||
virtual void GenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities);
|
|
||||||
|
|
||||||
virtual void PostGenerateChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ); // Called when the chunk has been already generated and set valid
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
cWorld * m_World;
|
|
||||||
|
|
||||||
// Thread-unsafe:
|
|
||||||
MTRand r1;
|
|
||||||
|
|
||||||
void GenerateOre(char a_OreType, int a_MaxHeight, int a_NumNests, int a_NestSize, BLOCKTYPE * a_BlockData);
|
|
||||||
|
|
||||||
static unsigned int MakeIndex(int x, int y, int z );
|
|
||||||
|
|
||||||
virtual void GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData);
|
|
||||||
|
|
||||||
virtual void GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
|
||||||
|
|
||||||
/// Checks if the chunk has all 8 neighbors valid, if so, foliage is generated on that chunk
|
|
||||||
void CheckNeighbors(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
|
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
||||||
|
|
||||||
#include "cWorldGenerator_Test.h"
|
|
||||||
#include "BlockID.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator_Test::GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData)
|
|
||||||
{
|
|
||||||
memset(a_BlockData, E_BLOCK_DIRT, cChunkDef::NumBlocks);
|
|
||||||
for(int x = 0; x < cChunkDef::Width; x++)
|
|
||||||
{
|
|
||||||
for(int z = 0; z < cChunkDef::Width; z++)
|
|
||||||
{
|
|
||||||
a_BlockData[MakeIndex(x, 0, z)] = E_BLOCK_BEDROCK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWorldGenerator_Test::GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
|
|
||||||
{
|
|
||||||
(void)a_ChunkX;
|
|
||||||
(void)a_ChunkY;
|
|
||||||
(void)a_ChunkZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "cWorldGenerator.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cWorldGenerator_Test :
|
|
||||||
public cWorldGenerator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
cWorldGenerator_Test(cWorld * a_World) : cWorldGenerator(a_World) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
virtual void GenerateTerrain(int a_ChunkX, int a_ChunkY, int a_ChunkZ, BLOCKTYPE * a_BlockData) override;
|
|
||||||
virtual void GenerateFoliage(int a_ChunkX, int a_ChunkY, int a_ChunkZ) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -195,13 +195,14 @@ void cPacket::AppendString(AString & a_Dst, const AString & a_String)
|
||||||
void cPacket::AppendString16(AString & a_Dst, const AString & a_String)
|
void cPacket::AppendString16(AString & a_Dst, const AString & a_String)
|
||||||
{
|
{
|
||||||
AppendShort(a_Dst, (unsigned short)a_String.size());
|
AppendShort(a_Dst, (unsigned short)a_String.size());
|
||||||
std::auto_ptr<char> UTF16(new char[a_String.size() * sizeof( short ) ]);
|
AString UTF16;
|
||||||
|
UTF16.resize(a_String.size() * sizeof(short));
|
||||||
for( unsigned int i = 0; i < a_String.size(); ++i )
|
for( unsigned int i = 0; i < a_String.size(); ++i )
|
||||||
{
|
{
|
||||||
UTF16.get()[i * sizeof( short )] = 0x00;
|
UTF16[i * sizeof( short )] = 0x00;
|
||||||
UTF16.get()[i * sizeof( short ) + 1] = a_String[i];
|
UTF16[i * sizeof( short ) + 1] = a_String[i];
|
||||||
}
|
}
|
||||||
a_Dst.append(UTF16.get(), a_String.size() * sizeof(short));
|
a_Dst.append(UTF16.data(), a_String.size() * sizeof(short));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ cPacket_MapChunk::~cPacket_MapChunk()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPacket_MapChunk::cPacket_MapChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const BLOCKTYPE * a_BlockData, const BIOMETYPE * a_BiomeData)
|
cPacket_MapChunk::cPacket_MapChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const BLOCKTYPE * a_BlockData, const unsigned char * a_BiomeData)
|
||||||
{
|
{
|
||||||
m_PacketID = E_MAP_CHUNK;
|
m_PacketID = E_MAP_CHUNK;
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
{ m_PacketID = E_MAP_CHUNK; }
|
{ m_PacketID = E_MAP_CHUNK; }
|
||||||
|
|
||||||
cPacket_MapChunk( const cPacket_MapChunk & a_Copy );
|
cPacket_MapChunk( const cPacket_MapChunk & a_Copy );
|
||||||
cPacket_MapChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const BLOCKTYPE * a_BlockData, const BIOMETYPE * a_BiomeData);
|
cPacket_MapChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, const BLOCKTYPE * a_BlockData, const unsigned char * a_BiomeData);
|
||||||
~cPacket_MapChunk();
|
~cPacket_MapChunk();
|
||||||
virtual cPacket* Clone() const { return new cPacket_MapChunk(*this); }
|
virtual cPacket* Clone() const { return new cPacket_MapChunk(*this); }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user