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:
@@ -264,6 +264,10 @@
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\source\BlockID.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\BlockID.h"
|
||||
>
|
||||
@@ -336,14 +340,6 @@
|
||||
RelativePath="..\source\cFurnaceRecipe.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cGenSettings.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cGenSettings.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cGroup.cpp"
|
||||
>
|
||||
@@ -462,22 +458,6 @@
|
||||
RelativePath="..\source\cPiston.h"
|
||||
>
|
||||
</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
|
||||
RelativePath="..\source\cRecipeChecker.cpp"
|
||||
>
|
||||
@@ -1659,6 +1639,14 @@
|
||||
RelativePath="..\source\cLuaCommandBinder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPlugin.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPlugin.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPlugin_Lua.cpp"
|
||||
>
|
||||
@@ -1675,6 +1663,14 @@
|
||||
RelativePath="..\source\cPlugin_NewLua.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPluginManager.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPluginManager.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cStringMap.cpp"
|
||||
>
|
||||
@@ -1747,14 +1743,6 @@
|
||||
RelativePath="..\source\FastNBT.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\NBT.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\NBT.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\WorldStorage.cpp"
|
||||
>
|
||||
@@ -1783,6 +1771,14 @@
|
||||
<Filter
|
||||
Name="Generating"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\source\BioGen.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\BioGen.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cChunkGenerator.cpp"
|
||||
>
|
||||
@@ -1792,31 +1788,87 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cWorldGenerator.cpp"
|
||||
RelativePath="..\source\CompoGen.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cWorldGenerator.h"
|
||||
RelativePath="..\source\CompoGen.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cWorldGenerator_Test.cpp"
|
||||
RelativePath="..\source\FinishGen.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cWorldGenerator_Test.h"
|
||||
RelativePath="..\source\FinishGen.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\WGFlat.cpp"
|
||||
RelativePath="..\source\HeiGen.cpp"
|
||||
>
|
||||
</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>
|
||||
</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
|
||||
RelativePath="..\makefile"
|
||||
>
|
||||
|
||||
@@ -302,6 +302,8 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\source\BioGen.cpp" />
|
||||
<ClCompile Include="..\source\BlockID.cpp" />
|
||||
<ClCompile Include="..\source\cAggressiveMonster.cpp" />
|
||||
<ClCompile Include="..\Source\cAuthenticator.cpp" />
|
||||
<ClCompile Include="..\source\cBlockingTCPLink.cpp" />
|
||||
@@ -324,7 +326,6 @@
|
||||
<ClCompile Include="..\source\cFurnaceEntity.cpp" />
|
||||
<ClCompile Include="..\Source\cFurnaceRecipe.cpp" />
|
||||
<ClCompile Include="..\source\cFurnaceWindow.cpp" />
|
||||
<ClCompile Include="..\source\cGenSettings.cpp" />
|
||||
<ClCompile Include="..\source\cGhast.cpp" />
|
||||
<ClCompile Include="..\Source\cGroup.cpp" />
|
||||
<ClCompile Include="..\Source\cGroupManager.cpp" />
|
||||
@@ -347,6 +348,7 @@
|
||||
<BasicRuntimeChecks Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">Default</BasicRuntimeChecks>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\CompoGen.cpp" />
|
||||
<ClCompile Include="..\source\cPassiveAggressiveMonster.cpp" />
|
||||
<ClCompile Include="..\source\cPassiveMonster.cpp" />
|
||||
<ClCompile Include="..\Source\cPawn.cpp" />
|
||||
@@ -386,16 +388,16 @@
|
||||
<ClCompile Include="..\source\cWebPlugin_Lua.cpp" />
|
||||
<ClCompile Include="..\source\cWindow.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\cZombiepigman.cpp" />
|
||||
<ClCompile Include="..\source\FinishGen.cpp" />
|
||||
<ClCompile Include="..\source\FastNBT.cpp" />
|
||||
<ClCompile Include="..\source\Globals.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\HeiGen.cpp" />
|
||||
<ClCompile Include="..\source\LeakFinder.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
@@ -422,7 +424,6 @@
|
||||
<ClCompile Include="..\source\cLog.cpp" />
|
||||
<ClCompile Include="..\source\Bindings.cpp" />
|
||||
<ClCompile Include="..\source\main.cpp" />
|
||||
<ClCompile Include="..\source\NBT.cpp" />
|
||||
<ClCompile Include="..\source\packets\cPacket.cpp" />
|
||||
<ClCompile Include="..\source\packets\cPacket_13.cpp" />
|
||||
<ClCompile Include="..\source\packets\cPacket_AddToInventory.cpp" />
|
||||
@@ -480,15 +481,17 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\StringCompression.cpp" />
|
||||
<ClCompile Include="..\source\StringUtils.cpp" />
|
||||
<ClCompile Include="..\source\StructGen.cpp" />
|
||||
<ClCompile Include="..\source\Trees.cpp" />
|
||||
<ClCompile Include="..\source\Vector3d.cpp" />
|
||||
<ClCompile Include="..\source\Vector3f.cpp" />
|
||||
<ClCompile Include="..\source\Vector3i.cpp" />
|
||||
<ClCompile Include="..\source\WGFlat.cpp" />
|
||||
<ClCompile Include="..\source\WorldStorage.cpp" />
|
||||
<ClCompile Include="..\source\WSSAnvil.cpp" />
|
||||
<ClCompile Include="..\source\WSSCompact.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\source\BioGen.h" />
|
||||
<ClInclude Include="..\Source\BlockID.h" />
|
||||
<ClInclude Include="..\source\cAggressiveMonster.h" />
|
||||
<ClInclude Include="..\Source\cAuthenticator.h" />
|
||||
@@ -526,6 +529,7 @@
|
||||
<ClInclude Include="..\Source\cMonster.h" />
|
||||
<ClInclude Include="..\source\cMonsterConfig.h" />
|
||||
<ClInclude Include="..\source\cNoise.h" />
|
||||
<ClInclude Include="..\source\CompoGen.h" />
|
||||
<ClInclude Include="..\source\cPassiveAggressiveMonster.h" />
|
||||
<ClInclude Include="..\source\cPassiveMonster.h" />
|
||||
<ClInclude Include="..\Source\cPawn.h" />
|
||||
@@ -558,7 +562,6 @@
|
||||
<ClInclude Include="..\source\cStringMap.h" />
|
||||
<ClInclude Include="..\source\cSurvivalInventory.h" />
|
||||
<ClInclude Include="..\Source\cTCPLink.h" />
|
||||
<ClInclude Include="..\source\cGenSettings.h" />
|
||||
<ClInclude Include="..\source\cThread.h" />
|
||||
<ClInclude Include="..\source\cTimer.h" />
|
||||
<ClInclude Include="..\source\cTorch.h" />
|
||||
@@ -571,14 +574,14 @@
|
||||
<ClInclude Include="..\source\cWindow.h" />
|
||||
<ClInclude Include="..\source\cWindowOwner.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\cZombiepigman.h" />
|
||||
<ClInclude Include="..\source\Endianness.h" />
|
||||
<ClInclude Include="..\source\FastNBT.h" />
|
||||
<ClInclude Include="..\Source\FileDefine.h" />
|
||||
<ClInclude Include="..\source\FinishGen.h" />
|
||||
<ClInclude Include="..\source\Globals.h" />
|
||||
<ClInclude Include="..\source\HeiGen.h" />
|
||||
<ClInclude Include="..\source\LeakFinder.h" />
|
||||
<ClInclude Include="..\source\LightingThread.h" />
|
||||
<ClInclude Include="..\Source\LuaFunctions.h" />
|
||||
@@ -605,7 +608,6 @@
|
||||
<ClInclude Include="..\source\Bindings.h" />
|
||||
<ClInclude Include="..\source\Defines.h" />
|
||||
<ClInclude Include="..\source\MCSocket.h" />
|
||||
<ClInclude Include="..\source\NBT.h" />
|
||||
<ClInclude Include="..\Source\PacketID.h" />
|
||||
<ClInclude Include="..\source\packets\cPacket.h" />
|
||||
<ClInclude Include="..\source\packets\cPacket_13.h" />
|
||||
@@ -656,15 +658,15 @@
|
||||
<ClInclude Include="..\source\packets\cPacket_WindowClick.h" />
|
||||
<ClInclude Include="..\source\packets\cPacket_WindowClose.h" />
|
||||
<ClInclude Include="..\source\packets\cPacket_WindowOpen.h" />
|
||||
<ClInclude Include="..\source\ptr_cChunk.h" />
|
||||
<ClInclude Include="..\source\SquirrelBindings.h" />
|
||||
<ClInclude Include="..\source\StackWalker.h" />
|
||||
<ClInclude Include="..\source\StringCompression.h" />
|
||||
<ClInclude Include="..\source\StringUtils.h" />
|
||||
<ClInclude Include="..\source\StructGen.h" />
|
||||
<ClInclude Include="..\source\Trees.h" />
|
||||
<ClInclude Include="..\source\Vector3d.h" />
|
||||
<ClInclude Include="..\source\Vector3f.h" />
|
||||
<ClInclude Include="..\source\Vector3i.h" />
|
||||
<ClInclude Include="..\source\WGFlat.h" />
|
||||
<ClInclude Include="..\source\WorldStorage.h" />
|
||||
<ClInclude Include="..\source\WSSAnvil.h" />
|
||||
<ClInclude Include="..\source\WSSCompact.h" />
|
||||
|
||||
@@ -217,9 +217,6 @@
|
||||
<Filter Include="cNoise">
|
||||
<UniqueIdentifier>{58d6aa00-beab-4654-bbbd-c3b0397a9549}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cGenSettings">
|
||||
<UniqueIdentifier>{731dfafd-78a6-47d4-8494-a8e024f24c07}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cMakeDir">
|
||||
<UniqueIdentifier>{102fff22-0eb3-4977-9de3-307534954fbc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -379,9 +376,6 @@
|
||||
<Filter Include="Packets\cPacket_ItemData">
|
||||
<UniqueIdentifier>{fcc08e08-8dba-47b4-89b0-5dc255bb9b8a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cChunkGenerator">
|
||||
<UniqueIdentifier>{0d6f822b-71eb-406f-b17a-d188c4924283}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cEntity\cPawn\cMonster\Personalities">
|
||||
<UniqueIdentifier>{b0f7c883-e2ca-4bba-89e3-c36656c3de39}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -394,15 +388,9 @@
|
||||
<Filter Include="cEntity\cPawn\cMonster\Personalities\PassiveAggressive">
|
||||
<UniqueIdentifier>{71574b1c-a518-4a17-92c1-e3ea340f73bc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cWorldGenerator">
|
||||
<UniqueIdentifier>{72727ea7-779f-439e-8f30-53bd6985c9e7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="!LuaPlugins">
|
||||
<UniqueIdentifier>{4b86e1cf-ea3c-40b6-82b2-82fa9e6eb35e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cWorldGenerator\cWorldGenerator_Test">
|
||||
<UniqueIdentifier>{c86f4c53-af06-4b42-97dd-ffb7035041ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Simulator">
|
||||
<UniqueIdentifier>{ad41fc50-2d3d-4f6f-addd-a8bcb15b8518}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -433,9 +421,6 @@
|
||||
<Filter Include="cInventory\cCreativeInventory">
|
||||
<UniqueIdentifier>{69e6a927-8e49-4d39-af88-f587d17bb8a3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="!Smart_Pointers">
|
||||
<UniqueIdentifier>{9bd7a65c-b60f-4905-ae2b-7c3c7586eaef}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="cPlugin\cPlugin_NewLua">
|
||||
<UniqueIdentifier>{fb282bd3-cf18-44b3-8ccc-9a5a89701a6d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -445,6 +430,9 @@
|
||||
<Filter Include="Simulator\cSimulator\cRedstoneSimulator">
|
||||
<UniqueIdentifier>{4b3b7b43-8e8b-4823-b112-2259fdfff7d3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Generating">
|
||||
<UniqueIdentifier>{833e49bd-848d-42de-ac60-6cd7656474e3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Storage">
|
||||
<UniqueIdentifier>{038cf4bd-108e-44e2-bdcb-9d48fb26676e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -664,9 +652,6 @@
|
||||
<ClCompile Include="..\source\cNoise.cpp">
|
||||
<Filter>cNoise</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\cGenSettings.cpp">
|
||||
<Filter>cGenSettings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\cMakeDir.cpp">
|
||||
<Filter>cMakeDir</Filter>
|
||||
</ClCompile>
|
||||
@@ -835,9 +820,6 @@
|
||||
<ClCompile Include="..\source\packets\cPacket_ItemData.cpp">
|
||||
<Filter>Packets\cPacket_ItemData</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\cChunkGenerator.cpp">
|
||||
<Filter>cChunkGenerator</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\cFluidSimulator.cpp">
|
||||
<Filter>Simulator\cSimulator\cFluidSimulator</Filter>
|
||||
</ClCompile>
|
||||
@@ -850,12 +832,6 @@
|
||||
<ClCompile Include="..\source\cPassiveMonster.cpp">
|
||||
<Filter>cEntity\cPawn\cMonster\Personalities\Passive</Filter>
|
||||
</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">
|
||||
<Filter>Simulator</Filter>
|
||||
</ClCompile>
|
||||
@@ -896,12 +872,30 @@
|
||||
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\ChunkSender.cpp" />
|
||||
<ClCompile Include="..\source\WGFlat.cpp" />
|
||||
<ClCompile Include="..\source\packets\cPacket_Player.cpp">
|
||||
<Filter>Packets</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\NBT.cpp">
|
||||
<Filter>Storage</Filter>
|
||||
<ClCompile Include="..\source\cChunkGenerator.cpp">
|
||||
<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 Include="..\source\WorldStorage.cpp">
|
||||
<Filter>Storage</Filter>
|
||||
@@ -1163,9 +1157,6 @@
|
||||
<ClInclude Include="..\source\cNoise.h">
|
||||
<Filter>cNoise</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\cGenSettings.h">
|
||||
<Filter>cGenSettings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\cMakeDir.h">
|
||||
<Filter>cMakeDir</Filter>
|
||||
</ClInclude>
|
||||
@@ -1337,9 +1328,6 @@
|
||||
<ClInclude Include="..\source\packets\cPacket_ItemData.h">
|
||||
<Filter>Packets\cPacket_ItemData</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\cChunkGenerator.h">
|
||||
<Filter>cChunkGenerator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\cFluidSimulator.h">
|
||||
<Filter>Simulator\cSimulator\cFluidSimulator</Filter>
|
||||
</ClInclude>
|
||||
@@ -1352,12 +1340,6 @@
|
||||
<ClInclude Include="..\source\cPassiveMonster.h">
|
||||
<Filter>cEntity\cPawn\cMonster\Personalities\Passive</Filter>
|
||||
</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">
|
||||
<Filter>Simulator</Filter>
|
||||
</ClInclude>
|
||||
@@ -1379,9 +1361,6 @@
|
||||
<ClInclude Include="..\source\cSurvivalInventory.h">
|
||||
<Filter>cInventory\cSurvivalInventory</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\ptr_cChunk.h">
|
||||
<Filter>!Smart_Pointers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\cPlugin_NewLua.h">
|
||||
<Filter>cPlugin\cPlugin_NewLua</Filter>
|
||||
</ClInclude>
|
||||
@@ -1401,13 +1380,30 @@
|
||||
<Filter>Simulator\cSimulator\cRedstoneSimulator</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\ChunkSender.h" />
|
||||
<ClInclude Include="..\source\WGFlat.h" />
|
||||
<ClInclude Include="..\source\ChunkDef.h" />
|
||||
<ClInclude Include="..\source\packets\cPacket_Player.h">
|
||||
<Filter>Packets</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\source\NBT.h">
|
||||
<Filter>Storage</Filter>
|
||||
<ClInclude Include="..\source\cChunkGenerator.h">
|
||||
<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 Include="..\source\WorldStorage.h">
|
||||
<Filter>Storage</Filter>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#ifndef _WIN32
|
||||
#include <cstring>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#define SD_SEND 0x01
|
||||
#else
|
||||
#define MSG_NOSIGNAL (0)
|
||||
|
||||
@@ -47,7 +47,15 @@
|
||||
#include "UrlHelper.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 )
|
||||
{
|
||||
@@ -76,6 +84,10 @@ static std::string EatLine( std::string& a_String )
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Turns
|
||||
// "blabla my string with \"quotes\"!"
|
||||
// into
|
||||
@@ -116,6 +128,10 @@ static std::string GetQuotedString( const std::string& a_String )
|
||||
return RetVal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ParseMultipartFormData( webserver::http_request& req, Socket* s)
|
||||
{
|
||||
static const std::string multipart_form_data = "multipart/form-data";
|
||||
@@ -229,6 +245,10 @@ void ParseMultipartFormData( webserver::http_request& req, Socket* s)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
unsigned webserver::Request(void* ptr_s)
|
||||
#else
|
||||
@@ -395,6 +415,10 @@ void* webserver::Request(void* ptr_s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void webserver::Stop()
|
||||
{
|
||||
m_bStop = true;
|
||||
@@ -402,46 +426,72 @@ void webserver::Stop()
|
||||
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;
|
||||
while ( !m_bStop )
|
||||
{
|
||||
Socket* ptr_s=m_Socket->Accept();
|
||||
if( m_bStop )
|
||||
Socket * ptr_s = m_Socket->Accept();
|
||||
if (m_bStop)
|
||||
{
|
||||
if( ptr_s != 0 )
|
||||
if (ptr_s != 0)
|
||||
{
|
||||
ptr_s->Close();
|
||||
delete ptr_s;
|
||||
}
|
||||
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
|
||||
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);
|
||||
#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);
|
||||
#endif
|
||||
}
|
||||
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;
|
||||
m_Events = new cEvents();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
webserver::~webserver()
|
||||
{
|
||||
delete m_Socket;
|
||||
delete m_Events;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -89,16 +89,18 @@ public:
|
||||
webserver(unsigned int port_to_listen, request_func);
|
||||
~webserver();
|
||||
|
||||
void Begin();
|
||||
bool Begin();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
bool m_bStop;
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifdef _WIN32
|
||||
static unsigned __stdcall Request(void*);
|
||||
#else
|
||||
#else
|
||||
static void* Request(void*);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static request_func request_func_;
|
||||
|
||||
cEvents * m_Events;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
** 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
|
||||
@@ -2344,7 +2344,7 @@ static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S)
|
||||
if (tolua_index<0)
|
||||
tolua_error(tolua_S,"array indexing out of range.",NULL);
|
||||
#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;
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
@@ -2388,7 +2388,7 @@ static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S)
|
||||
if (tolua_index<0)
|
||||
tolua_error(tolua_S,"array indexing out of range.",NULL);
|
||||
#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;
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
@@ -2897,6 +2897,15 @@ static int tolua_get_cChatColor_White(lua_State* tolua_S)
|
||||
}
|
||||
#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 */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cChatColor_MakeColor00
|
||||
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
|
||||
|
||||
/* 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 */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cClientHandle_GetUniqueID00
|
||||
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
|
||||
|
||||
/* 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 */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cEntity_SetPosX00
|
||||
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
|
||||
tolua_Error tolua_err;
|
||||
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_isnoobj(tolua_S,3,&tolua_err)
|
||||
)
|
||||
@@ -6389,7 +6526,7 @@ static int tolua_AllToLua_cPluginManager_GetPlugin00(lua_State* tolua_S)
|
||||
else
|
||||
#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));
|
||||
#ifndef TOLUA_RELEASE
|
||||
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
|
||||
tolua_Error tolua_err;
|
||||
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)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
||||
const cPluginManager* self = (const cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumPlugins'", NULL);
|
||||
#endif
|
||||
@@ -9855,6 +9992,76 @@ static int tolua_AllToLua_cWorld_UpdateSign00(lua_State* tolua_S)
|
||||
}
|
||||
#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 */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_SetBlock00
|
||||
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
|
||||
{
|
||||
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
int a_X = ((int) tolua_tonumber(tolua_S,2,0));
|
||||
int a_Y = ((int) tolua_tonumber(tolua_S,3,0));
|
||||
int a_Z = ((int) tolua_tonumber(tolua_S,4,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 'GrowTree'", NULL);
|
||||
#endif
|
||||
{
|
||||
self->GrowTree(a_X,a_Y,a_Z);
|
||||
self->GrowTree(a_BlockX,a_BlockY,a_BlockZ);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -10428,33 +10635,113 @@ static int tolua_AllToLua_cWorld_GrowTree00(lua_State* tolua_S)
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
|
||||
/* method: GetWorldSeed of class cWorld */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GetWorldSeed00
|
||||
static int tolua_AllToLua_cWorld_GetWorldSeed00(lua_State* tolua_S)
|
||||
/* method: GrowTreeFromSapling of class cWorld */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cWorld_GrowTreeFromSapling00
|
||||
static int tolua_AllToLua_cWorld_GrowTreeFromSapling00(lua_State* tolua_S)
|
||||
{
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
!tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
|
||||
!tolua_isnumber(tolua_S,2,0,&tolua_err) ||
|
||||
!tolua_isnumber(tolua_S,3,0,&tolua_err) ||
|
||||
!tolua_isnumber(tolua_S,4,0,&tolua_err) ||
|
||||
!tolua_isnumber(tolua_S,5,0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,6,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#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
|
||||
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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'GetWorldSeed'.",&tolua_err);
|
||||
tolua_error(tolua_S,"#ferror in function 'GetBiomeAt'.",&tolua_err);
|
||||
return 0;
|
||||
#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_DIRT",E_BLOCK_DIRT);
|
||||
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_SAPLING",E_BLOCK_SAPLING);
|
||||
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_GLOWSTONE",E_BLOCK_GLOWSTONE);
|
||||
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_CAKE",E_BLOCK_CAKE);
|
||||
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_FRAME",E_BLOCK_END_PORTAL_FRAME);
|
||||
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_ITEM_EMPTY",E_ITEM_EMPTY);
|
||||
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_WARD_DISC",E_ITEM_WARD_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_LOGIN",E_LOGIN);
|
||||
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,"Yellow",tolua_get_cChatColor_Yellow,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_endmodule(tolua_S);
|
||||
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,"GetPing",tolua_AllToLua_cClientHandle_GetPing00);
|
||||
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_endmodule(tolua_S);
|
||||
#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,"GetRoll",tolua_AllToLua_cEntity_GetRoll00);
|
||||
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,"SetPosY",tolua_AllToLua_cEntity_SetPosY00);
|
||||
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,"GetPlayer",tolua_AllToLua_cWorld_GetPlayer00);
|
||||
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,"FastSetBlock",tolua_AllToLua_cWorld_FastSetBlock00);
|
||||
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,"GetBlockEntity",tolua_AllToLua_cWorld_GetBlockEntity00);
|
||||
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,"SaveAllChunks",tolua_AllToLua_cWorld_SaveAllChunks00);
|
||||
tolua_function(tolua_S,"GetNumChunks",tolua_AllToLua_cWorld_GetNumChunks00);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
** 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 */
|
||||
|
||||
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_DIRT = 3,
|
||||
E_BLOCK_COBBLESTONE = 4,
|
||||
E_BLOCK_WOOD = 5,
|
||||
E_BLOCK_PLANKS = 5,
|
||||
E_BLOCK_WOOD = E_BLOCK_PLANKS,
|
||||
E_BLOCK_SAPLING = 6,
|
||||
E_BLOCK_BEDROCK = 7,
|
||||
E_BLOCK_WATER = 8,
|
||||
@@ -93,7 +94,8 @@ enum ENUM_BLOCK_ID
|
||||
E_BLOCK_BLOODSTONE = 87,
|
||||
E_BLOCK_SOULSAND = 88,
|
||||
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_CAKE = 92,
|
||||
E_BLOCK_REDSTONE_REPEATER_OFF = 93,
|
||||
@@ -125,6 +127,9 @@ enum ENUM_BLOCK_ID
|
||||
E_BLOCK_END_PORTAL = 119,
|
||||
E_BLOCK_END_PORTAL_FRAME = 120,
|
||||
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,
|
||||
};
|
||||
//tolua_end
|
||||
@@ -394,38 +399,60 @@ enum ENUM_ITEM_ID
|
||||
E_ITEM_WARD_DISC = 2265,
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
/// Biome IDs, as stored in the Anvil format and sent in the MapChunk packet
|
||||
enum eBiomeID
|
||||
{
|
||||
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,
|
||||
} ;
|
||||
// Translates a blocktype string into blocktype. Takes either a number or an items.ini alias as input. Returns -1 on failure.
|
||||
extern int BlockStringToType(const AString & a_BlockTypeString);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Block properties:
|
||||
extern NIBBLETYPE g_BlockLightValue[256];
|
||||
extern NIBBLETYPE g_BlockSpreadLightFalloff[256];
|
||||
extern bool g_BlockTransparent[256];
|
||||
extern bool g_BlockOneHitDig[256];
|
||||
extern bool g_BlockPistonBreakable[256];
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 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;
|
||||
|
||||
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:
|
||||
@@ -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))
|
||||
{
|
||||
@@ -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))
|
||||
{
|
||||
@@ -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))
|
||||
{
|
||||
@@ -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))
|
||||
{
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
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 );
|
||||
}
|
||||
@@ -207,17 +304,23 @@ public:
|
||||
/// Called once to provide heightmap data
|
||||
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
|
||||
virtual void BlockTypes (const BLOCKTYPE * a_Type) {};
|
||||
|
||||
/// 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
|
||||
virtual void BlockLight (const BLOCKTYPE * a_Meta) {};
|
||||
virtual void BlockLight (const NIBBLETYPE * a_Meta) {};
|
||||
|
||||
/// 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
|
||||
virtual void Entity(cEntity * a_Entity) {};
|
||||
@@ -237,29 +340,30 @@ class cChunkDataCollector :
|
||||
{
|
||||
public:
|
||||
|
||||
BLOCKTYPE m_BlockData[cChunkDef::BlockDataSize];
|
||||
// Must be char instead of BLOCKTYPE or NIBBLETYPE, because it houses both.
|
||||
char m_BlockData[cChunkDef::BlockDataSize];
|
||||
|
||||
protected:
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -276,12 +380,10 @@ class cChunkDataSeparateCollector :
|
||||
{
|
||||
public:
|
||||
|
||||
BLOCKTYPE m_BlockTypes[cChunkDef::NumBlocks];
|
||||
|
||||
// TODO: These should be NIBBLETYPE:
|
||||
BLOCKTYPE m_BlockMetas[cChunkDef::NumBlocks / 2];
|
||||
BLOCKTYPE m_BlockLight[cChunkDef::NumBlocks / 2];
|
||||
BLOCKTYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2];
|
||||
cChunkDef::BlockTypes m_BlockTypes;
|
||||
cChunkDef::BlockNibbles m_BlockMetas;
|
||||
cChunkDef::BlockNibbles m_BlockLight;
|
||||
cChunkDef::BlockNibbles m_BlockSkyLight;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
virtual void BlockLight(const BLOCKTYPE * a_BlockLight) override
|
||||
virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override
|
||||
{
|
||||
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));
|
||||
}
|
||||
@@ -334,12 +436,20 @@ struct sSetBlock
|
||||
{
|
||||
int x, y, z;
|
||||
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) :
|
||||
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))
|
||||
{
|
||||
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:
|
||||
if( !m_World->GetChunkData(a_ChunkX, a_ChunkY, a_ChunkZ, *this) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
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:
|
||||
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:
|
||||
public cIsThread,
|
||||
public cChunkDataCollector
|
||||
@@ -101,9 +128,11 @@ protected:
|
||||
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)
|
||||
|
||||
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:
|
||||
// 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
|
||||
|
||||
// cIsThread override:
|
||||
@@ -111,6 +140,7 @@ protected:
|
||||
|
||||
// cChunkDataCollector overrides:
|
||||
// (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 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
|
||||
// emissive blocks
|
||||
extern char g_BlockLightValue[];
|
||||
extern unsigned char g_BlockLightValue[];
|
||||
// whether blocks allow spreading
|
||||
extern char g_BlockSpreadLightFalloff[];
|
||||
extern unsigned char g_BlockSpreadLightFalloff[];
|
||||
// whether blocks are transparent (light can shine though)
|
||||
extern bool g_BlockTransparent[];
|
||||
// one hit break blocks
|
||||
|
||||
@@ -259,7 +259,7 @@ protected:
|
||||
{
|
||||
// Compound: add the type and name:
|
||||
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
|
||||
{
|
||||
|
||||
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 "cSleep.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 "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(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)
|
||||
{
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
for (cLightingBufferQueue::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
} // for itr - m_Queue[]
|
||||
m_Queue.clear();
|
||||
}
|
||||
m_ShouldTerminate = true;
|
||||
m_Event.Set();
|
||||
m_evtItemAdded.Set();
|
||||
|
||||
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)
|
||||
{
|
||||
// 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) :
|
||||
m_MinX(a_MinX),
|
||||
m_MaxX(a_MaxX),
|
||||
m_MinY(a_MinY),
|
||||
m_MaxY(a_MaxY),
|
||||
m_MinZ(a_MinZ),
|
||||
m_MaxZ(a_MaxZ)
|
||||
void cLightingThread::LightChunk(cLightingThread::sItem & a_Item)
|
||||
{
|
||||
// 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
|
||||
|
||||
// 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
|
||||
|
||||
#include "cIsThread.h"
|
||||
#include "ChunkDef.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
// fwd: "cWorld.h"
|
||||
class cWorld;
|
||||
|
||||
// fwd: "cChunkMap.h"
|
||||
class cChunkStay;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -28,53 +54,121 @@ class cLightingThread :
|
||||
typedef cIsThread super;
|
||||
|
||||
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();
|
||||
|
||||
bool Start(cWorld * a_World);
|
||||
|
||||
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:
|
||||
|
||||
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;
|
||||
cLightingBufferQueue m_Queue;
|
||||
cEvent m_Event; // Set when queue is appended or to stop the thread
|
||||
typedef std::list<sItem> sItems;
|
||||
|
||||
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;
|
||||
|
||||
/// 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
|
||||
|
||||
// Allocate a buffer and printf into it:
|
||||
std::auto_ptr<char> tmp(new char[len + 1]);
|
||||
ASSERT(tmp.get() != NULL); // Why not alloced? Is the length reasonable?
|
||||
if (tmp.get() == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
str.resize(len + 1);
|
||||
// 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.
|
||||
// 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
|
||||
#ifdef _MSC_VER
|
||||
if ((len = vsprintf_s(tmp.get(), len + 1, format, args)) != -1)
|
||||
{
|
||||
str.append(tmp.get(), len);
|
||||
}
|
||||
ASSERT(len != -1);
|
||||
vsprintf_s((char *)str.data(), len + 1, format, args);
|
||||
#else // _MSC_VER
|
||||
vsnprintf(tmp.get(), len + 1, format, args);
|
||||
str.append(tmp.get(), len);
|
||||
vsnprintf((char *)str.data(), len + 1, format, args);
|
||||
#endif // else _MSC_VER
|
||||
|
||||
str.resize(len);
|
||||
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 "cWorld.h"
|
||||
#include "zlib.h"
|
||||
#include "NBT.h"
|
||||
#include "BlockID.h"
|
||||
#include "cChestEntity.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
|
||||
|
||||
/// 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
|
||||
|
||||
|
||||
@@ -45,7 +44,8 @@ public:
|
||||
m_Writer(a_Writer),
|
||||
m_IsTagOpen(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:
|
||||
|
||||
/* 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_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_IsLightValid; // True if the chunk lighting is valid
|
||||
|
||||
|
||||
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID)
|
||||
@@ -89,10 +93,10 @@ protected:
|
||||
void AddItem(cItem * a_Item, int a_Slot)
|
||||
{
|
||||
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.AddByte ("Count", a_Item->m_ItemCount);
|
||||
m_Writer.AddByte ("Slot", a_Slot);
|
||||
m_Writer.AddByte ("Slot", (unsigned char)a_Slot);
|
||||
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
|
||||
{
|
||||
// TODO: Add entity into NBT:
|
||||
@@ -363,12 +374,6 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
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)
|
||||
{
|
||||
// The data arrays, in MCA-native y/z/x ordering (will be reordered for the final chunk data)
|
||||
BLOCKTYPE BlockData[cChunkDef::BlockDataSize];
|
||||
BLOCKTYPE * MetaData = BlockData + cChunkDef::MetaOffset;
|
||||
BLOCKTYPE * BlockLight = BlockData + cChunkDef::LightOffset;
|
||||
BLOCKTYPE * SkyLight = BlockData + cChunkDef::SkyLightOffset;
|
||||
cChunkDef::BlockTypes BlockTypes;
|
||||
cChunkDef::BlockNibbles MetaData;
|
||||
cChunkDef::BlockNibbles BlockLight;
|
||||
cChunkDef::BlockNibbles SkyLight;
|
||||
|
||||
memset(BlockData, E_BLOCK_AIR, sizeof(BlockData) - cChunkDef::NumBlocks / 2);
|
||||
memset(SkyLight, 0xff, cChunkDef::NumBlocks / 2); // By default, data not present in the NBT means air, which means full skylight
|
||||
memset(BlockTypes, E_BLOCK_AIR, sizeof(BlockTypes));
|
||||
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:
|
||||
int Level = a_NBT.FindChildByName(0, "Level");
|
||||
@@ -412,56 +419,26 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT
|
||||
{
|
||||
continue;
|
||||
}
|
||||
CopyNBTData(a_NBT, Child, "Blocks", &(BlockData[y * 4096]), 4096);
|
||||
CopyNBTData(a_NBT, Child, "Data", &(MetaData[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "SkyLight", &(SkyLight[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "BlockLight", &(BlockLight[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "Blocks", (char *)&(BlockTypes[y * 4096]), 4096);
|
||||
CopyNBTData(a_NBT, Child, "Data", (char *)&(MetaData[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "SkyLight", (char *)&(SkyLight[y * 2048]), 2048);
|
||||
CopyNBTData(a_NBT, Child, "BlockLight", (char *)&(BlockLight[y * 2048]), 2048);
|
||||
} // for itr - LevelSections[]
|
||||
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
// Load the biomes from NBT, if present and valid:
|
||||
cChunkDef::BiomeMap BiomeMap;
|
||||
cChunkDef::BiomeMap * Biomes = LoadBiomeMapFromNBT(&BiomeMap, a_NBT, a_NBT.FindChildByName(Level, "Biomes"));
|
||||
|
||||
// Load the entities from NBT:
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
LoadEntitiesFromNBT (Entities, a_NBT, a_NBT.FindChildByName(Level, "Entities"));
|
||||
LoadBlockEntitiesFromNBT(BlockEntities, a_NBT, a_NBT.FindChildByName(Level, "TileEntities"));
|
||||
|
||||
#if (AXIS_ORDER == AXIS_ORDER_YZX)
|
||||
// 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
|
||||
bool IsLightValid = (a_NBT.FindChildByName(Level, "MCSIsLightValid") > 0);
|
||||
|
||||
/*
|
||||
// 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 :)
|
||||
bool ShouldInvert[cChunkDef::Width * cChunkDef::Width];
|
||||
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);
|
||||
//*/
|
||||
|
||||
m_World->ChunkDataLoaded(
|
||||
m_World->SetChunkData(
|
||||
a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ,
|
||||
ChunkData,
|
||||
ChunkData + cChunkDef::MetaOffset,
|
||||
ChunkData + cChunkDef::LightOffset,
|
||||
ChunkData + cChunkDef::SkyLightOffset,
|
||||
NULL,
|
||||
Entities,
|
||||
BlockEntities
|
||||
BlockTypes, MetaData,
|
||||
IsLightValid ? BlockLight : NULL,
|
||||
IsLightValid ? SkyLight : NULL,
|
||||
NULL, Biomes,
|
||||
Entities, BlockEntities,
|
||||
false
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -525,24 +501,37 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_
|
||||
}
|
||||
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, "MCSBiomes", AString(Serializer.m_Biomes, sizeof(Serializer.m_Biomes));
|
||||
|
||||
// Save blockdata:
|
||||
a_Writer.BeginList("Sections", TAG_Compound);
|
||||
int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16;
|
||||
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++)
|
||||
{
|
||||
a_Writer.BeginCompound("");
|
||||
a_Writer.AddByteArray("Blocks", Serializer.m_BlockTypes + Y * SliceSizeBlock, SliceSizeBlock);
|
||||
a_Writer.AddByteArray("Data", Serializer.m_BlockMetas + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("SkyLight", Serializer.m_BlockSkyLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("BlockLight", Serializer.m_BlockLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByte("Y", Y);
|
||||
a_Writer.AddByteArray("Blocks", BlockTypes + Y * SliceSizeBlock, SliceSizeBlock);
|
||||
a_Writer.AddByteArray("Data", BlockMetas + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("SkyLight", BlockSkyLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByteArray("BlockLight", BlockLight + Y * SliceSizeNibble, SliceSizeNibble);
|
||||
a_Writer.AddByte("Y", (unsigned char)Y);
|
||||
a_Writer.EndCompound();
|
||||
}
|
||||
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"
|
||||
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)
|
||||
{
|
||||
// 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) :
|
||||
m_RegionX(a_RegionX),
|
||||
m_RegionZ(a_RegionZ),
|
||||
m_File(a_FileName, cFile::fmReadWrite),
|
||||
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:
|
||||
@@ -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):
|
||||
memset(m_Header, 0, sizeof(m_Header));
|
||||
if (
|
||||
(m_File.Write(m_Header, sizeof(m_Header)) != sizeof(m_Header)) ||
|
||||
(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)) // 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());
|
||||
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)
|
||||
{
|
||||
if (!m_File.IsOpen())
|
||||
if (!OpenFile(true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int LocalX = a_Chunk.m_ChunkX % 32;
|
||||
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 ChunkOffset = ChunkLocation >> 8;
|
||||
unsigned ChunkLen = ChunkLocation & 0xff;
|
||||
|
||||
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)
|
||||
{
|
||||
if (!m_File.IsOpen())
|
||||
if (!OpenFile(false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int LocalX = a_Chunk.m_ChunkX % 32;
|
||||
if (LocalX < 0)
|
||||
{
|
||||
@@ -782,7 +823,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ enum
|
||||
class cNBTTag;
|
||||
class cNBTList;
|
||||
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.
|
||||
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;
|
||||
|
||||
@@ -105,6 +109,9 @@ protected:
|
||||
/// Saves the chunk into NBT data using a_Writer; returns true on success
|
||||
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)
|
||||
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:
|
||||
|
||||
@@ -564,7 +631,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
|
||||
Offset += Header->m_CompressedSize;
|
||||
|
||||
// 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
std::auto_ptr<char> ConvertedData(new char[ ExpectedSize ]);
|
||||
memset( ConvertedData.get(), 0, ExpectedSize );
|
||||
char ConvertedData[ExpectedSize];
|
||||
memset(ConvertedData, 0, ExpectedSize);
|
||||
|
||||
// Cannot use cChunk::MakeIndex because it might change again?????????
|
||||
// For compatibility, use what we know is current
|
||||
#define MAKE_2_INDEX( x, y, z ) ( y + (z * 256) + (x * 256 * 16) )
|
||||
#define MAKE_3_INDEX( x, y, z ) ( x + (z * 16) + (y * 16 * 16) )
|
||||
#define MAKE_2_INDEX( x, y, z ) ( y + (z * 256) + (x * 256 * 16) )
|
||||
#define MAKE_3_INDEX( x, y, z ) ( x + (z * 16) + (y * 16 * 16) )
|
||||
|
||||
unsigned int InChunkOffset = 0;
|
||||
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;
|
||||
} // for y, z, x
|
||||
|
||||
@@ -619,29 +686,29 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
InChunkOffset += index2/2;
|
||||
InChunkOffset += index2 / 2;
|
||||
index2 = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
InChunkOffset += index2/2;
|
||||
InChunkOffset += index2 / 2;
|
||||
index2 = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
InChunkOffset += index2/2;
|
||||
InChunkOffset += index2 / 2;
|
||||
index2 = 0;
|
||||
|
||||
AString Converted(ConvertedData.get(), ExpectedSize);
|
||||
AString Converted(ConvertedData, ExpectedSize);
|
||||
|
||||
// Add JSON data afterwards
|
||||
if (UncompressedData.size() > InChunkOffset)
|
||||
@@ -717,6 +784,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
|
||||
|
||||
cEntityList Entities;
|
||||
cBlockEntityList BlockEntities;
|
||||
bool IsLightValid = false;
|
||||
|
||||
if (a_UncompressedSize > cChunkDef::BlockDataSize)
|
||||
{
|
||||
@@ -731,20 +799,23 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp
|
||||
else
|
||||
{
|
||||
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,
|
||||
BlockData,
|
||||
BlockData + cChunkDef::MetaOffset,
|
||||
BlockData + cChunkDef::LightOffset,
|
||||
BlockData + cChunkDef::SkyLightOffset,
|
||||
NULL,
|
||||
Entities,
|
||||
BlockEntities
|
||||
BlockData, MetaData,
|
||||
IsLightValid ? BlockLight : NULL,
|
||||
IsLightValid ? SkyLight : NULL,
|
||||
NULL, NULL,
|
||||
Entities, BlockEntities,
|
||||
false
|
||||
);
|
||||
|
||||
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 :
|
||||
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:
|
||||
|
||||
@@ -332,13 +277,13 @@ bool cWorldStorage::LoadOneChunk(void)
|
||||
bool ShouldLoad = false;
|
||||
{
|
||||
cCSLock Lock(m_CSQueues);
|
||||
if (m_LoadQueue.size() > 0)
|
||||
if (!m_LoadQueue.empty())
|
||||
{
|
||||
ToLoad = m_LoadQueue.front();
|
||||
m_LoadQueue.pop_front();
|
||||
ShouldLoad = true;
|
||||
}
|
||||
HasMore = (m_LoadQueue.size() > 0);
|
||||
HasMore = !m_LoadQueue.empty();
|
||||
}
|
||||
|
||||
if (ShouldLoad && !LoadChunk(ToLoad.m_ChunkX, ToLoad.m_ChunkY, ToLoad.m_ChunkZ))
|
||||
@@ -346,7 +291,7 @@ bool cWorldStorage::LoadOneChunk(void)
|
||||
if (ToLoad.m_Generate)
|
||||
{
|
||||
// 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
|
||||
{
|
||||
@@ -368,13 +313,13 @@ bool cWorldStorage::SaveOneChunk(void)
|
||||
bool ShouldSave = false;
|
||||
{
|
||||
cCSLock Lock(m_CSQueues);
|
||||
if (m_SaveQueue.size() > 0)
|
||||
if (!m_SaveQueue.empty())
|
||||
{
|
||||
Save = m_SaveQueue.front();
|
||||
m_SaveQueue.pop_front();
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
class cWorldStorage :
|
||||
public cIsThread
|
||||
|
||||
@@ -125,7 +125,7 @@ void cAuthenticator::Execute(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ASSERT(m_Queue.size() > 0);
|
||||
ASSERT(!m_Queue.empty());
|
||||
|
||||
int ClientID = m_Queue.front().mClientID;
|
||||
AString UserName = m_Queue.front().mName;
|
||||
|
||||
@@ -3,26 +3,31 @@
|
||||
|
||||
#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::Black = cChatColor::Color + "0";
|
||||
const std::string cChatColor::Navy = cChatColor::Color + "1";
|
||||
const std::string cChatColor::Green = cChatColor::Color + "2";
|
||||
const std::string cChatColor::Blue = cChatColor::Color + "3";
|
||||
const std::string cChatColor::Red = cChatColor::Color + "4";
|
||||
const std::string cChatColor::Purple = cChatColor::Color + "5";
|
||||
const std::string cChatColor::Gold = cChatColor::Color + "6";
|
||||
const std::string cChatColor::LightGray = cChatColor::Color + "7";
|
||||
const std::string cChatColor::Gray = cChatColor::Color + "8";
|
||||
const std::string cChatColor::DarkPurple = cChatColor::Color + "9";
|
||||
const std::string cChatColor::LightGreen = cChatColor::Color + "a";
|
||||
const std::string cChatColor::LightBlue = cChatColor::Color + "b";
|
||||
const std::string cChatColor::Rose = cChatColor::Color + "c";
|
||||
const std::string cChatColor::LightPurple = cChatColor::Color + "d";
|
||||
const std::string cChatColor::Yellow = cChatColor::Color + "e";
|
||||
const std::string cChatColor::White = cChatColor::Color + "f";
|
||||
const std::string cChatColor::Black = cChatColor::Color + "0";
|
||||
const std::string cChatColor::Navy = cChatColor::Color + "1";
|
||||
const std::string cChatColor::Green = cChatColor::Color + "2";
|
||||
const std::string cChatColor::Blue = cChatColor::Color + "3";
|
||||
const std::string cChatColor::Red = cChatColor::Color + "4";
|
||||
const std::string cChatColor::Purple = cChatColor::Color + "5";
|
||||
const std::string cChatColor::Gold = cChatColor::Color + "6";
|
||||
const std::string cChatColor::LightGray = cChatColor::Color + "7";
|
||||
const std::string cChatColor::Gray = cChatColor::Color + "8";
|
||||
const std::string cChatColor::DarkPurple = cChatColor::Color + "9";
|
||||
const std::string cChatColor::LightGreen = cChatColor::Color + "a";
|
||||
const std::string cChatColor::LightBlue = cChatColor::Color + "b";
|
||||
const std::string cChatColor::Rose = cChatColor::Color + "c";
|
||||
const std::string cChatColor::LightPurple = cChatColor::Color + "d";
|
||||
const std::string cChatColor::Yellow = cChatColor::Color + "e";
|
||||
const std::string cChatColor::White = cChatColor::Color + "f";
|
||||
const std::string cChatColor::Funky = cChatColor::Color + "k";
|
||||
|
||||
const std::string cChatColor::MakeColor( char a_Color )
|
||||
{
|
||||
return cChatColor::Color + a_Color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
class cChatColor
|
||||
@@ -25,6 +28,7 @@ public:
|
||||
static const std::string LightPurple;
|
||||
static const std::string Yellow;
|
||||
static const std::string White;
|
||||
static const std::string Funky;
|
||||
|
||||
static const std::string MakeColor( char a_Color );
|
||||
};
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "cItem.h"
|
||||
#include "cNoise.h"
|
||||
#include "cRoot.h"
|
||||
#include "cWorldGenerator.h"
|
||||
#include "cBlockToPickup.h"
|
||||
#include "MersenneTwister.h"
|
||||
#include "cPlayer.h"
|
||||
@@ -32,7 +31,6 @@
|
||||
#include "packets/cPacket_DestroyEntity.h"
|
||||
#include "packets/cPacket_PreChunk.h"
|
||||
#include "packets/cPacket_BlockChange.h"
|
||||
#include "packets/cPacket_MapChunk.h"
|
||||
#include "packets/cPacket_MultiBlock.h"
|
||||
|
||||
#include <json/json.h>
|
||||
@@ -50,10 +48,10 @@ extern bool g_bWaterPhysics;
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// sSetBlock:
|
||||
|
||||
sSetBlock::sSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ) // absolute block position
|
||||
: x( a_X )
|
||||
, y( a_Y )
|
||||
, z( a_Z )
|
||||
sSetBlock::sSetBlock( int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta ) // absolute block position
|
||||
: x( a_BlockX )
|
||||
, y( a_BlockY )
|
||||
, z( a_BlockZ )
|
||||
, BlockType( a_BlockType )
|
||||
, 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(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_PosZ( a_ChunkZ )
|
||||
, 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_ChunkMap(a_ChunkMap)
|
||||
, m_IsValid(false)
|
||||
, m_IsLightValid(false)
|
||||
, m_IsDirty(false)
|
||||
, m_IsSaving(false)
|
||||
, m_StayCount(0)
|
||||
@@ -203,8 +201,10 @@ void cChunk::MarkLoadFailed(void)
|
||||
void cChunk::GetAllData(cChunkDataCallback & a_Callback)
|
||||
{
|
||||
a_Callback.HeightMap (&m_HeightMap);
|
||||
a_Callback.BiomeData (&m_BiomeMap);
|
||||
a_Callback.BlockTypes (m_BlockTypes);
|
||||
a_Callback.BlockMeta (m_BlockMeta);
|
||||
a_Callback.LightIsValid (m_IsLightValid);
|
||||
a_Callback.BlockLight (m_BlockLight);
|
||||
a_Callback.BlockSkyLight(m_BlockSkyLight);
|
||||
|
||||
@@ -224,24 +224,35 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback)
|
||||
|
||||
|
||||
void cChunk::SetAllData(
|
||||
const BLOCKTYPE * a_BlockTypes,
|
||||
const BLOCKTYPE * a_BlockMeta,
|
||||
const BLOCKTYPE * a_BlockLight,
|
||||
const BLOCKTYPE * a_BlockSkyLight,
|
||||
const HeightMap * a_HeightMap,
|
||||
const BLOCKTYPE * a_BlockTypes,
|
||||
const NIBBLETYPE * a_BlockMeta,
|
||||
const NIBBLETYPE * a_BlockLight,
|
||||
const NIBBLETYPE * a_BlockSkyLight,
|
||||
const HeightMap * a_HeightMap,
|
||||
const BiomeMap & a_BiomeMap,
|
||||
cEntityList & a_Entities,
|
||||
cBlockEntityList & a_BlockEntities
|
||||
)
|
||||
{
|
||||
memcpy(m_BiomeMap, a_BiomeMap, sizeof(m_BiomeMap));
|
||||
|
||||
if (a_HeightMap != NULL)
|
||||
{
|
||||
memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap));
|
||||
}
|
||||
|
||||
memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
|
||||
memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta));
|
||||
memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight));
|
||||
memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight));
|
||||
memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes));
|
||||
memcpy(m_BlockMeta, a_BlockMeta, sizeof(m_BlockMeta));
|
||||
if (a_BlockLight != NULL)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (m_bCalculateLighting)
|
||||
{
|
||||
CalculateLighting();
|
||||
}
|
||||
|
||||
cCSLock Lock(m_CSBlockLists);
|
||||
unsigned int PendingSendBlocks = m_PendingSendBlocks.size();
|
||||
if( PendingSendBlocks > 1 )
|
||||
@@ -407,7 +429,7 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||
unsigned int NumTickBlocks = m_ToTickBlocks.size();
|
||||
Lock2.Unlock();
|
||||
|
||||
if( NumTickBlocks > 0 )
|
||||
if ( NumTickBlocks > 0 )
|
||||
{
|
||||
Lock2.Lock();
|
||||
std::deque< unsigned int > ToTickBlocks = m_ToTickBlocks;
|
||||
@@ -415,32 +437,34 @@ void cChunk::Tick(float a_Dt, MTRand & a_TickRandom)
|
||||
Lock2.Unlock();
|
||||
|
||||
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);
|
||||
Vector3i BlockPos = IndexToCoordinate( index );
|
||||
|
||||
char BlockID = GetBlock( index );
|
||||
switch( BlockID )
|
||||
switch ( BlockID )
|
||||
{
|
||||
case E_BLOCK_REDSTONE_REPEATER_OFF:
|
||||
case E_BLOCK_REDSTONE_REPEATER_ON:
|
||||
case E_BLOCK_REDSTONE_WIRE:
|
||||
case E_BLOCK_REDSTONE_REPEATER_OFF:
|
||||
case E_BLOCK_REDSTONE_REPEATER_ON:
|
||||
case E_BLOCK_REDSTONE_WIRE:
|
||||
{
|
||||
isRedstone = true;
|
||||
// fallthrough
|
||||
}
|
||||
case E_BLOCK_CACTUS:
|
||||
case E_BLOCK_REEDS:
|
||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||
case E_BLOCK_MINECART_TRACKS:
|
||||
case E_BLOCK_SIGN_POST:
|
||||
case E_BLOCK_CROPS:
|
||||
case E_BLOCK_SAPLING:
|
||||
case E_BLOCK_YELLOW_FLOWER:
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
case E_BLOCK_BROWN_MUSHROOM: // Stuff that drops when block below is destroyed
|
||||
|
||||
case E_BLOCK_CACTUS:
|
||||
case E_BLOCK_REEDS:
|
||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||
case E_BLOCK_MINECART_TRACKS:
|
||||
case E_BLOCK_SIGN_POST:
|
||||
case E_BLOCK_CROPS:
|
||||
case E_BLOCK_SAPLING:
|
||||
case E_BLOCK_YELLOW_FLOWER:
|
||||
case E_BLOCK_RED_ROSE:
|
||||
case E_BLOCK_RED_MUSHROOM:
|
||||
case E_BLOCK_BROWN_MUSHROOM: // Stuff that drops when block below is destroyed
|
||||