1
0

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:
madmaxoft@gmail.com
2012-05-25 07:18:52 +00:00
parent 5f29a3e134
commit a4a418a679
82 changed files with 5422 additions and 2961 deletions

View File

@@ -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"
>

View File

@@ -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" />

View File

@@ -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>

View File

@@ -37,6 +37,7 @@
#ifndef _WIN32
#include <cstring>
#include <sys/time.h>
#include <unistd.h>
#define SD_SEND 0x01
#else
#define MSG_NOSIGNAL (0)

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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
View 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
View 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
View 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;

View File

@@ -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];

View File

@@ -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;
} ;

View File

@@ -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[]
}

View File

@@ -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
View 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
View 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;
} ;

View File

@@ -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

View File

@@ -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
View 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
View 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;
} ;

View File

@@ -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
View 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
View 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;
} ;

View File

@@ -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;
}
}

View File

@@ -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;
}
}
} ;

View File

@@ -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)

View File

@@ -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)

View File

@@ -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
View 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
View 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
View 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
View 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);

View File

@@ -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
}

View File

@@ -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);
} ;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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))
{

View File

@@ -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

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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 );
};

View File

@@ -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