diff options
Diffstat (limited to '')
380 files changed, 37608 insertions, 6209 deletions
diff --git a/src/Authenticator.cpp b/src/Authenticator.cpp deleted file mode 100644 index bd6db1c11..000000000 --- a/src/Authenticator.cpp +++ /dev/null @@ -1,267 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "Authenticator.h" -#include "OSSupport/BlockingTCPLink.h" -#include "Root.h" -#include "Server.h" - -#include "inifile/iniFile.h" - -#include <sstream> - - - - - -#define DEFAULT_AUTH_SERVER "session.minecraft.net" -#define DEFAULT_AUTH_ADDRESS "/game/checkserver.jsp?user=%USERNAME%&serverId=%SERVERID%" -#define MAX_REDIRECTS 10 - - - - - -cAuthenticator::cAuthenticator(void) : - super("cAuthenticator"), - m_Server(DEFAULT_AUTH_SERVER), - m_Address(DEFAULT_AUTH_ADDRESS), - m_ShouldAuthenticate(true) -{ -} - - - - - -cAuthenticator::~cAuthenticator() -{ - Stop(); -} - - - - - -void cAuthenticator::ReadINI(cIniFile & IniFile) -{ - m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER); - m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS); - m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); -} - - - - - -void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash) -{ - if (!m_ShouldAuthenticate) - { - cRoot::Get()->AuthenticateUser(a_ClientID); - return; - } - - cCSLock Lock(m_CS); - m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash)); - m_QueueNonempty.Set(); -} - - - - - -void cAuthenticator::Start(cIniFile & IniFile) -{ - ReadINI(IniFile); - m_ShouldTerminate = false; - super::Start(); -} - - - - - -void cAuthenticator::Stop(void) -{ - m_ShouldTerminate = true; - m_QueueNonempty.Set(); - Wait(); -} - - - - - -void cAuthenticator::Execute(void) -{ - for (;;) - { - cCSLock Lock(m_CS); - while (!m_ShouldTerminate && (m_Queue.size() == 0)) - { - cCSUnlock Unlock(Lock); - m_QueueNonempty.Wait(); - } - if (m_ShouldTerminate) - { - return; - } - ASSERT(!m_Queue.empty()); - - int ClientID = m_Queue.front().m_ClientID; - AString UserName = m_Queue.front().m_Name; - AString ActualAddress = m_Address; - ReplaceString(ActualAddress, "%USERNAME%", UserName); - ReplaceString(ActualAddress, "%SERVERID%", m_Queue.front().m_ServerID); - m_Queue.pop_front(); - Lock.Unlock(); - - if (!AuthFromAddress(m_Server, ActualAddress, UserName)) - { - cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!"); - } - else - { - cRoot::Get()->AuthenticateUser(ClientID); - } - } // for (-ever) -} - - - - - -bool cAuthenticator::AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level /* = 1 */) -{ - // Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep) - - cBlockingTCPLink Link; - if (!Link.Connect(a_Server.c_str(), 80)) - { - LOGWARNING("%s: cannot connect to auth server \"%s\", kicking user \"%s\"", - __FUNCTION__, a_Server.c_str(), a_UserName.c_str() - ); - return false; - } - - Link.SendMessage( AString( "GET " + a_Address + " HTTP/1.1\r\n" ).c_str()); - Link.SendMessage( AString( "User-Agent: MCServer\r\n" ).c_str()); - Link.SendMessage( AString( "Host: " + a_Server + "\r\n" ).c_str()); - //Link.SendMessage( AString( "Host: session.minecraft.net\r\n" ).c_str()); - Link.SendMessage( AString( "Accept: */*\r\n" ).c_str()); - Link.SendMessage( AString( "Connection: close\r\n" ).c_str()); //Close so we don´t have to mess with the Content-Length :) - Link.SendMessage( AString( "\r\n" ).c_str()); - AString DataRecvd; - Link.ReceiveData(DataRecvd); - Link.CloseSocket(); - - std::stringstream ss(DataRecvd); - - // Parse the data received: - std::string temp; - ss >> temp; - bool bRedirect = false; - bool bOK = false; - if ((temp.compare("HTTP/1.1") == 0) || (temp.compare("HTTP/1.0") == 0)) - { - int code; - ss >> code; - if (code == 302) - { - // redirect blabla - LOGD("%s: Need to redirect, current level %d!", __FUNCTION__, a_Level); - if (a_Level > MAX_REDIRECTS) - { - LOGERROR("cAuthenticator: received too many levels of redirection from auth server \"%s\" for user \"%s\", bailing out and kicking the user", a_Server.c_str(), a_UserName.c_str()); - return false; - } - bRedirect = true; - } - else if (code == 200) - { - LOGD("cAuthenticator: Received status 200 OK! :D"); - bOK = true; - } - } - else - { - LOGERROR("cAuthenticator: cannot parse auth reply from server \"%s\" for user \"%s\", kicking the user.", a_Server.c_str(), a_UserName.c_str()); - return false; - } - - if( bRedirect ) - { - AString Location; - // Search for "Location:" - bool bFoundLocation = false; - while( !bFoundLocation && ss.good() ) - { - char c = 0; - while( c != '\n' ) - { - ss.get( c ); - } - AString Name; - ss >> Name; - if (Name.compare("Location:") == 0) - { - bFoundLocation = true; - ss >> Location; - } - } - if (!bFoundLocation) - { - LOGERROR("cAuthenticator: received invalid redirection from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str()); - return false; - } - - Location = Location.substr(strlen("http://"), std::string::npos); // Strip http:// - std::string Server = Location.substr( 0, Location.find( "/" ) ); // Only leave server address - Location = Location.substr( Server.length(), std::string::npos); - return AuthFromAddress(Server, Location, a_UserName, a_Level + 1); - } - - if (!bOK) - { - LOGERROR("cAuthenticator: received an error from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str()); - return false; - } - - // Header says OK, so receive the rest. - // Go past header, double \n means end of headers - char c = 0; - while (ss.good()) - { - while (c != '\n') - { - ss.get(c); - } - ss.get(c); - if( c == '\n' || c == '\r' || ss.peek() == '\r' || ss.peek() == '\n' ) - break; - } - if (!ss.good()) - { - LOGERROR("cAuthenticator: error while parsing response body from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str()); - return false; - } - - std::string Result; - ss >> Result; - LOGD("cAuthenticator: Authentication result was %s", Result.c_str()); - - if (Result.compare("YES") == 0) //Works well - { - LOGINFO("Authentication result \"YES\", player authentication success!"); - return true; - } - - - LOGINFO("Authentication result was \"%s\", player authentication failure!", Result.c_str()); - return false; -} - - - - diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg index 1cd7c74f8..4fe86e1c5 100644 --- a/src/Bindings/AllToLua.pkg +++ b/src/Bindings/AllToLua.pkg @@ -76,6 +76,7 @@ $cfile "../CompositeChat.h" $cfile "../Map.h" $cfile "../MapManager.h" $cfile "../Scoreboard.h" +$cfile "../Statistics.h" diff --git a/src/Bindings/DeprecatedBindings.cpp b/src/Bindings/DeprecatedBindings.cpp index 408b1b84a..d51ba2da3 100644 --- a/src/Bindings/DeprecatedBindings.cpp +++ b/src/Bindings/DeprecatedBindings.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "DeprecatedBindings.h" +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" #include "Plugin.h" @@ -20,47 +21,23 @@ #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockLightValue static int tolua_get_AllToLua_g_BlockLightValue(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) + { tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + } } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockLightValue */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockLightValue -static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_LightValue = ((unsigned char) tolua_tonumber(tolua_S,3,0)); - return 0; + tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetLightValue((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -72,7 +49,7 @@ static int tolua_set_AllToLua_g_BlockLightValue(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockSpreadLightFalloff static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -80,39 +57,13 @@ static int tolua_get_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushnumber(tolua_S,(lua_Number)cBlockInfo::GetSpreadLightFalloff(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockSpreadLightFalloff */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockSpreadLightFalloff -static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_SpreadLightFalloff = ((unsigned char) tolua_tonumber(tolua_S,3,0)); - return 0; + tolua_pushnumber(tolua_S, (lua_Number)cBlockInfo::GetSpreadLightFalloff((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -124,7 +75,7 @@ static int tolua_set_AllToLua_g_BlockSpreadLightFalloff(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockTransparent static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -132,39 +83,13 @@ static int tolua_get_AllToLua_g_BlockTransparent(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockTransparent */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockTransparent -static int tolua_set_AllToLua_g_BlockTransparent(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_Transparent = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, cBlockInfo::IsTransparent((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -176,7 +101,7 @@ static int tolua_set_AllToLua_g_BlockTransparent(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockOneHitDig static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -184,39 +109,13 @@ static int tolua_get_AllToLua_g_BlockOneHitDig(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsOneHitDig(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockOneHitDig */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockOneHitDig -static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_OneHitDig = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, cBlockInfo::IsOneHitDig((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -228,7 +127,7 @@ static int tolua_set_AllToLua_g_BlockOneHitDig(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockPistonBreakable static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -236,39 +135,13 @@ static int tolua_get_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsPistonBreakable(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockPistonBreakable */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockPistonBreakable -static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_PistonBreakable = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, cBlockInfo::IsPistonBreakable((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -280,7 +153,7 @@ static int tolua_set_AllToLua_g_BlockPistonBreakable(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSnowable static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -288,39 +161,13 @@ static int tolua_get_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsSnowable(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockIsSnowable */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSnowable -static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_IsSnowable = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, cBlockInfo::IsSnowable((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -332,7 +179,7 @@ static int tolua_set_AllToLua_g_BlockIsSnowable(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockRequiresSpecialTool static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -340,39 +187,13 @@ static int tolua_get_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S,(bool)cBlockInfo::RequiresSpecialTool(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockRequiresSpecialTool */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockRequiresSpecialTool -static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_RequiresSpecialTool = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, cBlockInfo::RequiresSpecialTool((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -384,7 +205,7 @@ static int tolua_set_AllToLua_g_BlockRequiresSpecialTool(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockIsSolid static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -392,39 +213,13 @@ static int tolua_get_AllToLua_g_BlockIsSolid(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S,(bool)cBlockInfo::IsSolid(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockIsSolid */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockIsSolid -static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_IsSolid = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, (bool)cBlockInfo::IsSolid((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -436,7 +231,7 @@ static int tolua_set_AllToLua_g_BlockIsSolid(lua_State* tolua_S) #ifndef TOLUA_DISABLE_tolua_get_AllToLua_g_BlockFullyOccupiesVoxel static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S) { - int tolua_index; + int BlockType; #ifndef TOLUA_RELEASE { tolua_Error tolua_err; @@ -444,39 +239,13 @@ static int tolua_get_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S) tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); } #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - tolua_pushboolean(tolua_S,(bool)cBlockInfo::FullyOccupiesVoxel(tolua_index)); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - - - - - -/* set function: g_BlockFullyOccupiesVoxel */ -#ifndef TOLUA_DISABLE_tolua_set_AllToLua_g_BlockFullyOccupiesVoxel -static int tolua_set_AllToLua_g_BlockFullyOccupiesVoxel(lua_State* tolua_S) -{ - int tolua_index; - #ifndef TOLUA_RELEASE + BlockType = (int)tolua_tonumber(tolua_S, 2, 0); + if ((BlockType < 0) || (BlockType > E_BLOCK_MAX_TYPE_ID)) { - tolua_Error tolua_err; - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in array indexing.",&tolua_err); + tolua_error(tolua_S, "array indexing out of range.", NULL); } - #endif - tolua_index = (int)tolua_tonumber(tolua_S,2,0); - #ifndef TOLUA_RELEASE - if (tolua_index<0 || tolua_index>=256) - tolua_error(tolua_S,"array indexing out of range.",NULL); - #endif - cBlockInfo::Get(tolua_index).m_FullyOccupiesVoxel = (tolua_toboolean(tolua_S,3,0) != 0); - return 0; + tolua_pushboolean(tolua_S, (bool)cBlockInfo::FullyOccupiesVoxel((BLOCKTYPE)BlockType)); + return 1; } #endif //#ifndef TOLUA_DISABLE @@ -488,15 +257,15 @@ void DeprecatedBindings::Bind(lua_State * tolua_S) { tolua_beginmodule(tolua_S, NULL); - tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, tolua_set_AllToLua_g_BlockLightValue); - tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, tolua_set_AllToLua_g_BlockSpreadLightFalloff); - tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, tolua_set_AllToLua_g_BlockTransparent); - tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, tolua_set_AllToLua_g_BlockOneHitDig); - tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, tolua_set_AllToLua_g_BlockPistonBreakable); - tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, tolua_set_AllToLua_g_BlockIsSnowable); - tolua_array(tolua_S, "g_BlockRequiresSpecialTool", tolua_get_AllToLua_g_BlockRequiresSpecialTool, tolua_set_AllToLua_g_BlockRequiresSpecialTool); - tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, tolua_set_AllToLua_g_BlockIsSolid); - tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, tolua_set_AllToLua_g_BlockFullyOccupiesVoxel); + tolua_array(tolua_S, "g_BlockLightValue", tolua_get_AllToLua_g_BlockLightValue, NULL); + tolua_array(tolua_S, "g_BlockSpreadLightFalloff", tolua_get_AllToLua_g_BlockSpreadLightFalloff, NULL); + tolua_array(tolua_S, "g_BlockTransparent", tolua_get_AllToLua_g_BlockTransparent, NULL); + tolua_array(tolua_S, "g_BlockOneHitDig", tolua_get_AllToLua_g_BlockOneHitDig, NULL); + tolua_array(tolua_S, "g_BlockPistonBreakable", tolua_get_AllToLua_g_BlockPistonBreakable, NULL); + tolua_array(tolua_S, "g_BlockIsSnowable", tolua_get_AllToLua_g_BlockIsSnowable, NULL); + tolua_array(tolua_S, "g_BlockRequiresSpecialTool", tolua_get_AllToLua_g_BlockRequiresSpecialTool, NULL); + tolua_array(tolua_S, "g_BlockIsSolid", tolua_get_AllToLua_g_BlockIsSolid, NULL); + tolua_array(tolua_S, "g_BlockFullyOccupiesVoxel", tolua_get_AllToLua_g_BlockFullyOccupiesVoxel, NULL); tolua_endmodule(tolua_S); } diff --git a/src/Bindings/LuaChunkStay.cpp b/src/Bindings/LuaChunkStay.cpp index db865cfa4..985a18a95 100644 --- a/src/Bindings/LuaChunkStay.cpp +++ b/src/Bindings/LuaChunkStay.cpp @@ -42,7 +42,7 @@ bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos) // Add each set of coords: int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos); - m_Chunks.reserve(NumChunks); + m_Chunks.reserve((size_t)NumChunks); for (int idx = 1; idx <= NumChunks; idx++) { // Push the idx-th element of the array onto stack top, check that it's a table: diff --git a/src/Bindings/LuaFunctions.h b/src/Bindings/LuaFunctions.h index 4f9eab86d..629e2d77d 100644 --- a/src/Bindings/LuaFunctions.h +++ b/src/Bindings/LuaFunctions.h @@ -4,12 +4,12 @@ #include <time.h> // tolua_begin -unsigned int GetTime() +inline unsigned int GetTime() { return (unsigned int)time(0); } -std::string GetChar( std::string & a_Str, unsigned int a_Idx ) +inline std::string GetChar( std::string & a_Str, unsigned int a_Idx ) { return std::string(1, a_Str[ a_Idx ]); } diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp index 13eb17f7d..a33459ad2 100644 --- a/src/Bindings/LuaState.cpp +++ b/src/Bindings/LuaState.cpp @@ -11,6 +11,7 @@ extern "C" #include "lua/src/lualib.h" } +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" #include "Bindings.h" #include "ManualBindings.h" diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 20bbc48f2..14d9d16fc 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "ManualBindings.h" +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" #include "Plugin.h" @@ -36,7 +37,7 @@ /**************************** * Better error reporting for Lua **/ -int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError) +static int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError) { // Retrieve current function name lua_Debug entry; @@ -56,7 +57,7 @@ int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaErro -int lua_do_error(lua_State* L, const char * a_pFormat, ...) +static int lua_do_error(lua_State* L, const char * a_pFormat, ...) { // Retrieve current function name lua_Debug entry; @@ -115,10 +116,44 @@ static int tolua_StringSplitAndTrim(lua_State * tolua_S) -static int tolua_LOG(lua_State* tolua_S) +/** Retrieves the log message from the first param on the Lua stack. +Can take either a string or a cCompositeChat. +*/ +static AString GetLogMessage(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 0 ); + tolua_Error err; + if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) + { + return ((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->ExtractText(); + } + else + { + size_t len = 0; + const char * str = lua_tolstring(tolua_S, 1, &len); + if (str != NULL) + { + return AString(str, len); + } + } + return ""; +} + + + + + +static int tolua_LOG(lua_State * tolua_S) +{ + // If the param is a cCompositeChat, read the log level from it: + cMCLogger::eLogLevel LogLevel = cMCLogger::llRegular; + tolua_Error err; + if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err)) + { + LogLevel = cCompositeChat::MessageTypeToLogLevel(((cCompositeChat *)tolua_tousertype(tolua_S, 1, NULL))->GetMessageType()); + } + + // Log the message: + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel); return 0; } @@ -126,10 +161,9 @@ static int tolua_LOG(lua_State* tolua_S) -static int tolua_LOGINFO(lua_State* tolua_S) +static int tolua_LOGINFO(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 1 ); + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llInfo); return 0; } @@ -137,10 +171,9 @@ static int tolua_LOGINFO(lua_State* tolua_S) -static int tolua_LOGWARN(lua_State* tolua_S) +static int tolua_LOGWARN(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 2 ); + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llWarning); return 0; } @@ -148,10 +181,9 @@ static int tolua_LOGWARN(lua_State* tolua_S) -static int tolua_LOGERROR(lua_State* tolua_S) +static int tolua_LOGERROR(lua_State * tolua_S) { - const char* str = tolua_tocppstring(tolua_S,1,0); - cMCLogger::GetInstance()->LogSimple( str, 3 ); + cMCLogger::GetInstance()->LogSimple(GetLogMessage(tolua_S).c_str(), cMCLogger::llError); return 0; } @@ -159,7 +191,51 @@ static int tolua_LOGERROR(lua_State* tolua_S) -cPluginLua * GetLuaPlugin(lua_State * L) +static int tolua_Base64Encode(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamString(1) || + !L.CheckParamEnd(2) + ) + { + return 0; + } + + AString Src; + L.GetStackValue(1, Src); + AString res = Base64Encode(Src); + L.Push(res); + return 1; +} + + + + + +static int tolua_Base64Decode(lua_State * tolua_S) +{ + cLuaState L(tolua_S); + if ( + !L.CheckParamString(1) || + !L.CheckParamEnd(2) + ) + { + return 0; + } + + AString Src; + L.GetStackValue(1, Src); + AString res = Base64Decode(Src); + L.Push(res); + return 1; +} + + + + + +static cPluginLua * GetLuaPlugin(lua_State * L) { // Get the plugin identification out of LuaState: lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME); @@ -1674,7 +1750,6 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) { return 0; } - cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); // Read the params: cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL); @@ -1684,8 +1759,12 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) L.LogStackTrace(); return 0; } + + cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin); + if (!ChunkStay->AddChunks(2)) { + delete ChunkStay; return 0; } @@ -1697,20 +1776,20 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S) -static int tolua_cPlayer_GetGroups(lua_State* tolua_S) +static int tolua_cPlayer_GetGroups(lua_State * tolua_S) { - cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); + cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL); const cPlayer::GroupList & AllGroups = self->GetGroups(); - lua_createtable(tolua_S, AllGroups.size(), 0); + lua_createtable(tolua_S, (int)AllGroups.size(), 0); int newTable = lua_gettop(tolua_S); int index = 1; cPlayer::GroupList::const_iterator iter = AllGroups.begin(); - while(iter != AllGroups.end()) + while (iter != AllGroups.end()) { - const cGroup* Group = *iter; - tolua_pushusertype( tolua_S, (void*)Group, "const cGroup" ); + const cGroup * Group = *iter; + tolua_pushusertype(tolua_S, (void *)Group, "const cGroup"); lua_rawseti(tolua_S, newTable, index); ++iter; ++index; @@ -1722,20 +1801,20 @@ static int tolua_cPlayer_GetGroups(lua_State* tolua_S) -static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S) +static int tolua_cPlayer_GetResolvedPermissions(lua_State * tolua_S) { - cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); + cPlayer * self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL); cPlayer::StringList AllPermissions = self->GetResolvedPermissions(); - lua_createtable(tolua_S, AllPermissions.size(), 0); + lua_createtable(tolua_S, (int)AllPermissions.size(), 0); int newTable = lua_gettop(tolua_S); int index = 1; cPlayer::StringList::iterator iter = AllPermissions.begin(); - while(iter != AllPermissions.end()) + while (iter != AllPermissions.end()) { - std::string& Permission = *iter; - tolua_pushstring( tolua_S, Permission.c_str() ); + std::string & Permission = *iter; + lua_pushlstring(tolua_S, Permission.c_str(), Permission.length()); lua_rawseti(tolua_S, newTable, index); ++iter; ++index; @@ -1997,18 +2076,18 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S) static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S) { - cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S, 1, NULL); + cWebAdmin * self = (cWebAdmin *)tolua_tousertype(tolua_S, 1, NULL); const cWebAdmin::PluginList & AllPlugins = self->GetPlugins(); - lua_createtable(tolua_S, AllPlugins.size(), 0); + lua_createtable(tolua_S, (int)AllPlugins.size(), 0); int newTable = lua_gettop(tolua_S); int index = 1; cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin(); - while(iter != AllPlugins.end()) + while (iter != AllPlugins.end()) { - const cWebPlugin* Plugin = *iter; - tolua_pushusertype( tolua_S, (void*)Plugin, "const cWebPlugin" ); + const cWebPlugin * Plugin = *iter; + tolua_pushusertype(tolua_S, (void *)Plugin, "const cWebPlugin"); lua_rawseti(tolua_S, newTable, index); ++iter; ++index; @@ -2785,8 +2864,8 @@ static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S) } // Set the type: - int MessageType; - L.GetStackValue(1, MessageType); + int MessageType = mtCustom; + L.GetStackValue(2, MessageType); self->SetMessageType((eMessageType)MessageType); // Cut away everything from the stack except for the cCompositeChat instance; return that: @@ -2838,6 +2917,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "LOGWARN", tolua_LOGWARN); tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_function(tolua_S, "Base64Encode", tolua_Base64Encode); + tolua_function(tolua_S, "Base64Decode", tolua_Base64Decode); tolua_beginmodule(tolua_S, "cFile"); tolua_function(tolua_S, "GetFolderContents", tolua_cFile_GetFolderContents); diff --git a/src/Bindings/ManualBindings.h b/src/Bindings/ManualBindings.h index e6594947e..f38e26267 100644 --- a/src/Bindings/ManualBindings.h +++ b/src/Bindings/ManualBindings.h @@ -5,4 +5,4 @@ class ManualBindings { public: static void Bind( lua_State* tolua_S ); -};
\ No newline at end of file +}; diff --git a/src/Bindings/Plugin.h b/src/Bindings/Plugin.h index 837b1ae13..c6461c861 100644 --- a/src/Bindings/Plugin.h +++ b/src/Bindings/Plugin.h @@ -56,7 +56,7 @@ public: virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0; virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) = 0; virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0; - virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) = 0; + virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0; diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp index 46ee7da9e..625931931 100644 --- a/src/Bindings/PluginLua.cpp +++ b/src/Bindings/PluginLua.cpp @@ -5,7 +5,11 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#ifdef __APPLE__ +#define LUA_USE_MACOSX +#else #define LUA_USE_POSIX +#endif #include "PluginLua.h" #include "../CommandOutput.h" @@ -14,6 +18,7 @@ extern "C" #include "lua/src/lualib.h" } +#undef TOLUA_TEMPLATE_BIND #include "tolua++/include/tolua++.h" @@ -395,14 +400,14 @@ bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGri -bool cPluginLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason) { cCSLock Lock(m_CriticalSection); bool res = false; cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), a_Player, a_Reason, cLuaState::Return, res); + m_LuaState.Call((int)(**itr), &a_Client, a_Reason, cLuaState::Return, res); if (res) { return true; @@ -1037,7 +1042,7 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE]; for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr) { - m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message); + m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message, cLuaState::Return, res); if (res) { return true; diff --git a/src/Bindings/PluginLua.h b/src/Bindings/PluginLua.h index ec74f07c6..598e031c0 100644 --- a/src/Bindings/PluginLua.h +++ b/src/Bindings/PluginLua.h @@ -79,7 +79,7 @@ public: virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override; virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override; virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override; - virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) override; + virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override; virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override; virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override; diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp index 4f528c2ae..acfc91bf8 100644 --- a/src/Bindings/PluginManager.cpp +++ b/src/Bindings/PluginManager.cpp @@ -143,13 +143,14 @@ void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) } } - if (GetNumPlugins() == 0) + size_t NumLoadedPlugins = GetNumPlugins(); + if (NumLoadedPlugins == 0) { LOG("-- No Plugins Loaded --"); } - else if (GetNumPlugins() > 1) + else if (NumLoadedPlugins > 1) { - LOG("-- Loaded %i Plugins --", GetNumPlugins()); + LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins); } else { @@ -442,7 +443,7 @@ bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const cC -bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Reason) +bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason) { HookMap::iterator Plugins = m_Hooks.find(HOOK_DISCONNECT); if (Plugins == m_Hooks.end()) @@ -451,7 +452,7 @@ bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Re } for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr) { - if ((*itr)->OnDisconnect(a_Player, a_Reason)) + if ((*itr)->OnDisconnect(a_Client, a_Reason)) { return true; } @@ -1869,7 +1870,7 @@ void cPluginManager::AddHook(cPlugin * a_Plugin, int a_Hook) -unsigned int cPluginManager::GetNumPlugins() const +size_t cPluginManager::GetNumPlugins() const { return m_Plugins.size(); } diff --git a/src/Bindings/PluginManager.h b/src/Bindings/PluginManager.h index 6c4e8bae7..be40bd2f7 100644 --- a/src/Bindings/PluginManager.h +++ b/src/Bindings/PluginManager.h @@ -159,7 +159,7 @@ public: // tolua_export /** Adds the plugin to the list of plugins called for the specified hook type. Handles multiple adds as a single add */ void AddHook(cPlugin * a_Plugin, int a_HookType); - unsigned int GetNumPlugins() const; // tolua_export + size_t GetNumPlugins() const; // tolua_export // Calls for individual hooks. Each returns false if the action is to continue or true if the plugin wants to abort bool CallHookBlockSpread (cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ, eSpreadSource a_Source); @@ -172,7 +172,7 @@ public: // tolua_export bool CallHookChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ); bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup); bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe); - bool CallHookDisconnect (cPlayer * a_Player, const AString & a_Reason); + bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason); bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData); diff --git a/src/Bindings/WebPlugin.cpp b/src/Bindings/WebPlugin.cpp index 3b71d553c..bf45405ba 100644 --- a/src/Bindings/WebPlugin.cpp +++ b/src/Bindings/WebPlugin.cpp @@ -110,4 +110,4 @@ AString cWebPlugin::SafeString( const AString & a_String ) RetVal.push_back( c ); } return RetVal; -}
\ No newline at end of file +} diff --git a/src/Bindings/lua5.1.dll b/src/Bindings/lua51.dll Binary files differindex 515cf8b30..515cf8b30 100644 --- a/src/Bindings/lua5.1.dll +++ b/src/Bindings/lua51.dll diff --git a/src/Bindings/tolua++.exe b/src/Bindings/tolua++.exe Binary files differindex 1e3cc7789..ba3a6b0c7 100644 --- a/src/Bindings/tolua++.exe +++ b/src/Bindings/tolua++.exe diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp index 3fba93e8a..9852b3dd9 100644 --- a/src/BiomeDef.cpp +++ b/src/BiomeDef.cpp @@ -7,6 +7,88 @@ #include "BiomeDef.h" + + +// The "map" used for biome <-> string conversions: +static struct { + EMCSBiome m_Biome; + const char * m_String; +} g_BiomeMap[] = +{ + {biOcean, "Ocean"} , + {biPlains, "Plains"}, + {biDesert, "Desert"}, + {biExtremeHills, "ExtremeHills"}, + {biForest, "Forest"}, + {biTaiga, "Taiga"}, + {biSwampland, "Swampland"}, + {biRiver, "River"}, + {biNether, "Hell"}, + {biNether, "Nether"}, + {biEnd, "Sky"}, + {biEnd, "End"}, + {biFrozenOcean, "FrozenOcean"}, + {biFrozenRiver, "FrozenRiver"}, + {biIcePlains, "IcePlains"}, + {biIcePlains, "Tundra"}, + {biIceMountains, "IceMountains"}, + {biMushroomIsland, "MushroomIsland"}, + {biMushroomShore, "MushroomShore"}, + {biBeach, "Beach"}, + {biDesertHills, "DesertHills"}, + {biForestHills, "ForestHills"}, + {biTaigaHills, "TaigaHills"}, + {biExtremeHillsEdge, "ExtremeHillsEdge"}, + {biJungle, "Jungle"}, + {biJungleHills, "JungleHills"}, + + // Release 1.7 biomes: + {biJungleEdge, "JungleEdge"}, + {biDeepOcean, "DeepOcean"}, + {biStoneBeach, "StoneBeach"}, + {biColdBeach, "ColdBeach"}, + {biBirchForest, "BirchForest"}, + {biBirchForestHills, "BirchForestHills"}, + {biRoofedForest, "RoofedForest"}, + {biColdTaiga, "ColdTaiga"}, + {biColdTaigaHills, "ColdTaigaHills"}, + {biMegaTaiga, "MegaTaiga"}, + {biMegaTaigaHills, "MegaTaigaHills"}, + {biExtremeHillsPlus, "ExtremeHillsPlus"}, + {biSavanna, "Savanna"}, + {biSavannaPlateau, "SavannaPlateau"}, + {biMesa, "Mesa"}, + {biMesaPlateauF, "MesaPlateauF"}, + {biMesaPlateau, "MesaPlateau"}, + + // Release 1.7 variants: + {biSunflowerPlains, "SunflowerPlains"}, + {biDesertM, "DesertM"}, + {biExtremeHillsM, "ExtremeHillsM"}, + {biFlowerForest, "FlowerForest"}, + {biTaigaM, "TaigaM"}, + {biSwamplandM, "SwamplandM"}, + {biIcePlainsSpikes, "IcePlainsSpikes"}, + {biJungleM, "JungleM"}, + {biJungleEdgeM, "JungleEdgeM"}, + {biBirchForestM, "BirchForestM"}, + {biBirchForestHillsM, "BirchForestHillsM"}, + {biRoofedForestM, "RoofedForestM"}, + {biColdTaigaM, "ColdTaigaM"}, + {biMegaSpruceTaiga, "MegaSpruceTaiga"}, + {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"}, + {biExtremeHillsPlusM, "ExtremeHillsPlusM"}, + {biSavannaM, "SavannaM"}, + {biSavannaPlateauM, "SavannaPlateauM"}, + {biMesaBryce, "MesaBryce"}, + {biMesaPlateauFM, "MesaPlateauFM"}, + {biMesaPlateauM, "MesaPlateauM"}, +} ; + + + + + EMCSBiome StringToBiome(const AString & a_BiomeString) { // If it is a number, return it: @@ -25,87 +107,11 @@ EMCSBiome StringToBiome(const AString & a_BiomeString) return biInvalidBiome; } - // Convert using the built-in map: - static struct { - EMCSBiome m_Biome; - const char * m_String; - } BiomeMap[] = - { - {biOcean, "Ocean"} , - {biPlains, "Plains"}, - {biDesert, "Desert"}, - {biExtremeHills, "ExtremeHills"}, - {biForest, "Forest"}, - {biTaiga, "Taiga"}, - {biSwampland, "Swampland"}, - {biRiver, "River"}, - {biNether, "Hell"}, - {biNether, "Nether"}, - {biEnd, "Sky"}, - {biEnd, "End"}, - {biFrozenOcean, "FrozenOcean"}, - {biFrozenRiver, "FrozenRiver"}, - {biIcePlains, "IcePlains"}, - {biIcePlains, "Tundra"}, - {biIceMountains, "IceMountains"}, - {biMushroomIsland, "MushroomIsland"}, - {biMushroomShore, "MushroomShore"}, - {biBeach, "Beach"}, - {biDesertHills, "DesertHills"}, - {biForestHills, "ForestHills"}, - {biTaigaHills, "TaigaHills"}, - {biExtremeHillsEdge, "ExtremeHillsEdge"}, - {biJungle, "Jungle"}, - {biJungleHills, "JungleHills"}, - - // Release 1.7 biomes: - {biJungleEdge, "JungleEdge"}, - {biDeepOcean, "DeepOcean"}, - {biStoneBeach, "StoneBeach"}, - {biColdBeach, "ColdBeach"}, - {biBirchForest, "BirchForest"}, - {biBirchForestHills, "BirchForestHills"}, - {biRoofedForest, "RoofedForest"}, - {biColdTaiga, "ColdTaiga"}, - {biColdTaigaHills, "ColdTaigaHills"}, - {biMegaTaiga, "MegaTaiga"}, - {biMegaTaigaHills, "MegaTaigaHills"}, - {biExtremeHillsPlus, "ExtremeHillsPlus"}, - {biSavanna, "Savanna"}, - {biSavannaPlateau, "SavannaPlateau"}, - {biMesa, "Mesa"}, - {biMesaPlateauF, "MesaPlateauF"}, - {biMesaPlateau, "MesaPlateau"}, - - // Release 1.7 variants: - {biSunflowerPlains, "SunflowerPlains"}, - {biDesertM, "DesertM"}, - {biExtremeHillsM, "ExtremeHillsM"}, - {biFlowerForest, "FlowerForest"}, - {biTaigaM, "TaigaM"}, - {biSwamplandM, "SwamplandM"}, - {biIcePlainsSpikes, "IcePlainsSpikes"}, - {biJungleM, "JungleM"}, - {biJungleEdgeM, "JungleEdgeM"}, - {biBirchForestM, "BirchForestM"}, - {biBirchForestHillsM, "BirchForestHillsM"}, - {biRoofedForestM, "RoofedForestM"}, - {biColdTaigaM, "ColdTaigaM"}, - {biMegaSpruceTaiga, "MegaSpruceTaiga"}, - {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"}, - {biExtremeHillsPlusM, "ExtremeHillsPlusM"}, - {biSavannaM, "SavannaM"}, - {biSavannaPlateauM, "SavannaPlateauM"}, - {biMesaBryce, "MesaBryce"}, - {biMesaPlateauFM, "MesaPlateauFM"}, - {biMesaPlateauM, "MesaPlateauM"}, - } ; - - for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++) + for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++) { - if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0) + if (NoCaseCompare(g_BiomeMap[i].m_String, a_BiomeString) == 0) { - return BiomeMap[i].m_Biome; + return g_BiomeMap[i].m_Biome; } } // for i - BiomeMap[] return biInvalidBiome; @@ -115,6 +121,22 @@ EMCSBiome StringToBiome(const AString & a_BiomeString) +AString BiomeToString(int a_Biome) +{ + for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++) + { + if (g_BiomeMap[i].m_Biome == a_Biome) + { + return g_BiomeMap[i].m_String; + } + } + return AString(); +} + + + + + bool IsBiomeNoDownfall(EMCSBiome a_Biome) { switch (a_Biome) diff --git a/src/BiomeDef.h b/src/BiomeDef.h index 474d4df76..f929596e9 100644 --- a/src/BiomeDef.h +++ b/src/BiomeDef.h @@ -10,7 +10,7 @@ #pragma once - +#include "StringUtils.h" // tolua_begin @@ -104,10 +104,13 @@ enum EMCSBiome biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value } ; -/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. +/** Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. */ extern EMCSBiome StringToBiome(const AString & a_BiomeString); -/// Returns true if the biome has no downfall - deserts and savannas +/** Translates biome enum into biome string. Returns empty string on failure (unknown biome). */ +extern AString BiomeToString(int a_Biome); + +/** Returns true if the biome has no downfall - deserts and savannas */ extern bool IsBiomeNoDownfall(EMCSBiome a_Biome); diff --git a/src/BlockArea.cpp b/src/BlockArea.cpp index f6d54e41c..40fdd68c0 100644 --- a/src/BlockArea.cpp +++ b/src/BlockArea.cpp @@ -9,22 +9,34 @@ #include "OSSupport/GZipFile.h" #include "Blocks/BlockHandler.h" #include "Cuboid.h" +#include "ChunkData.h" +// Disable MSVC warnings: "conditional expression is constant" +#ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable:4127) +#endif + + + + + +typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta); // This wild construct allows us to pass a function argument and still have it inlined by the compiler :) /// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function -template<typename Combinator> void InternalMergeBlocks( +template<bool MetasValid, CombinatorFunc Combinator> +void InternalMergeBlocks( BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes, NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas, int a_SizeX, int a_SizeY, int a_SizeZ, int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ, int a_DstOffX, int a_DstOffY, int a_DstOffZ, int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ, - int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ, - Combinator a_Combinator + int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ ) { UNUSED(a_SrcSizeY); @@ -41,7 +53,15 @@ template<typename Combinator> void InternalMergeBlocks( int DstIdx = DstBaseZ + a_DstOffX; for (int x = 0; x < a_SizeX; x++) { - a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); + if (MetasValid) + { + Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]); + } + else + { + BLOCKTYPE FakeDestMeta = 0; + Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0); + } ++DstIdx; ++SrcIdx; } // for x @@ -54,10 +74,14 @@ template<typename Combinator> void InternalMergeBlocks( /// Combinator used for cBlockArea::msOverwrite merging -static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } @@ -65,12 +89,16 @@ static void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, /// Combinator used for cBlockArea::msFillAir merging -static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if (a_DstType == E_BLOCK_AIR) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } // "else" is the default, already in place } @@ -80,12 +108,16 @@ static void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N /// Combinator used for cBlockArea::msImprint merging -static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { if (a_SrcType != E_BLOCK_AIR) { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } } // "else" is the default, already in place } @@ -95,7 +127,8 @@ static void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, N /// Combinator used for cBlockArea::msLake merging -static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +template<bool MetaValid> +void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) { // Sponge is the NOP block if (a_SrcType == E_BLOCK_SPONGE) @@ -107,7 +140,10 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB if (a_SrcType == E_BLOCK_AIR) { a_DstType = E_BLOCK_AIR; - a_DstMeta = 0; + if (MetaValid) + { + a_DstMeta = 0; + } return; } @@ -132,7 +168,10 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB case E_BLOCK_STATIONARY_LAVA: { a_DstType = a_SrcType; - a_DstMeta = a_SrcMeta; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } return; } } @@ -146,7 +185,10 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB case E_BLOCK_MYCELIUM: { a_DstType = E_BLOCK_STONE; - a_DstMeta = 0; + if (MetaValid) + { + a_DstMeta = 0; + } return; } } @@ -158,6 +200,75 @@ static void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBB +/** Combinator used for cBlockArea::msSpongePrint merging */ +template<bool MetaValid> +void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + // Sponge overwrites nothing, everything else overwrites anything + if (a_SrcType != E_BLOCK_SPONGE) + { + a_DstType = a_SrcType; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } + } +} + + + + + +/** Combinator used for cBlockArea::msDifference merging */ +template<bool MetaValid> +void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta))) + { + a_DstType = E_BLOCK_AIR; + if (MetaValid) + { + a_DstMeta = 0; + } + } + else + { + a_DstType = a_SrcType; + if (MetaValid) + { + a_DstMeta = a_SrcMeta; + } + } +} + + + + + +/** Combinator used for cBlockArea::msMask merging */ +template<bool MetaValid> +void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta) +{ + // If the blocks are the same, keep the dest; otherwise replace with air + if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta)) + { + a_DstType = E_BLOCK_AIR; + if (MetaValid) + { + a_DstMeta = 0; + } + } +} + +// Re-enable previously disabled MSVC warnings +#ifdef _MSC_VER + #pragma warning(pop) +#endif + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cBlockArea: @@ -435,7 +546,7 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const a_Into.Clear(); a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes()); a_Into.m_Origin = m_Origin; - int BlockCount = GetBlockCount(); + size_t BlockCount = GetBlockCount(); if (HasBlockTypes()) { memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE)); @@ -481,9 +592,9 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName) f.Write(&SizeX, 4); f.Write(&SizeY, 4); f.Write(&SizeZ, 4); - unsigned char DataTypes = GetDataTypes(); + unsigned char DataTypes = (unsigned char)GetDataTypes(); f.Write(&DataTypes, 1); - int NumBlocks = GetBlockCount(); + size_t NumBlocks = GetBlockCount(); if (HasBlockTypes()) { f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE)); @@ -588,110 +699,19 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy) { - // Block types are compulsory, block metas are voluntary - if (!HasBlockTypes() || !a_Src.HasBlockTypes()) - { - LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__); - return; - } - - // Dst is *this, Src is a_Src - int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading - int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing - int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy - - int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading - int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing - int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy - - int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading - int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing - int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas(); NIBBLETYPE * DstMetas = m_BlockMetas; + bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL)); if (IsDummyMetas) { - SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()]; - DstMetas = new NIBBLETYPE[GetBlockCount()]; + MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); } - - switch (a_Strategy) - { - case msOverwrite: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorOverwrite - ); - break; - } // case msOverwrite - - case msFillAir: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorFillAir - ); - break; - } // case msFillAir - - case msImprint: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorImprint - ); - break; - } // case msImprint - - case msLake: - { - InternalMergeBlocks( - m_BlockTypes, a_Src.GetBlockTypes(), - DstMetas, SrcMetas, - SizeX, SizeY, SizeZ, - SrcOffX, SrcOffY, SrcOffZ, - DstOffX, DstOffY, DstOffZ, - a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), - m_Size.x, m_Size.y, m_Size.z, - MergeCombinatorLake - ); - break; - } // case msLake - - default: - { - LOGWARNING("Unknown block area merge strategy: %d", a_Strategy); - ASSERT(!"Unknown block area merge strategy"); - break; - } - } // switch (a_Strategy) - - if (IsDummyMetas) + else { - delete[] SrcMetas; - delete[] DstMetas; + MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas); } } @@ -718,31 +738,31 @@ void cBlockArea::Fill(int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_Block a_DataTypes = a_DataTypes & GetDataTypes(); } - int BlockCount = GetBlockCount(); + size_t BlockCount = GetBlockCount(); if ((a_DataTypes & baTypes) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockTypes[i] = a_BlockType; } } if ((a_DataTypes & baMetas) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockMetas[i] = a_BlockMeta; } } if ((a_DataTypes & baLight) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockLight[i] = a_BlockLight; } } if ((a_DataTypes & baSkyLight) != 0) { - for (int i = 0; i < BlockCount; i++) + for (size_t i = 0; i < BlockCount; i++) { m_BlockSkyLight[i] = a_BlockSkyLight; } @@ -1815,116 +1835,88 @@ bool cBlockArea::cChunkReader::Coords(int a_ChunkX, int a_ChunkZ) -void cBlockArea::cChunkReader::BlockTypes(const BLOCKTYPE * a_BlockTypes) +void cBlockArea::cChunkReader::ChunkData(const cChunkData & a_BlockBuffer) { - if (m_Area.m_BlockTypes == NULL) - { - // Don't want BlockTypes - return; - } - - int SizeY = m_Area.m_Size.y; - int MinY = m_Origin.y; - - // SizeX, SizeZ are the dmensions of the block data to copy from the current chunk (size of the geometric union) - // OffX, OffZ are the offsets of the current chunk data from the area origin - // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders - int SizeX = cChunkDef::Width; - int SizeZ = cChunkDef::Width; - int OffX, OffZ; - int BaseX, BaseZ; - OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x; - if (OffX < 0) - { - BaseX = -OffX; - SizeX += OffX; // SizeX is decreased, OffX is negative - OffX = 0; - } - else - { - BaseX = 0; - } - OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z; - if (OffZ < 0) - { - BaseZ = -OffZ; - SizeZ += OffZ; // SizeZ is decreased, OffZ is negative - OffZ = 0; - } - else - { - BaseZ = 0; - } - // If the chunk extends beyond the area in the X or Z axis, cut off the Size: - if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x) - { - SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x); - } - if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z) { - SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z); - } - - for (int y = 0; y < SizeY; y++) - { - int ChunkY = MinY + y; - int AreaY = y; - for (int z = 0; z < SizeZ; z++) + if (m_Area.m_BlockTypes != NULL) { - int ChunkZ = BaseZ + z; - int AreaZ = OffZ + z; - for (int x = 0; x < SizeX; x++) + int SizeY = m_Area.m_Size.y; + int MinY = m_Origin.y; + + // SizeX, SizeZ are the dimensions of the block data to copy from the current chunk (size of the geometric union) + // OffX, OffZ are the offsets of the current chunk data from the area origin + // BaseX, BaseZ are the offsets of the area data within the current chunk from the chunk borders + int SizeX = cChunkDef::Width; + int SizeZ = cChunkDef::Width; + int OffX, OffZ; + int BaseX, BaseZ; + OffX = m_CurrentChunkX * cChunkDef::Width - m_Origin.x; + if (OffX < 0) { - int ChunkX = BaseX + x; - int AreaX = OffX + x; - m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = cChunkDef::GetBlock(a_BlockTypes, ChunkX, ChunkY, ChunkZ); - } // for x - } // for z - } // for y -} - - - + BaseX = -OffX; + SizeX += OffX; // SizeX is decreased, OffX is negative + OffX = 0; + } + else + { + BaseX = 0; + } + OffZ = m_CurrentChunkZ * cChunkDef::Width - m_Origin.z; + if (OffZ < 0) + { + BaseZ = -OffZ; + SizeZ += OffZ; // SizeZ is decreased, OffZ is negative + OffZ = 0; + } + else + { + BaseZ = 0; + } + // If the chunk extends beyond the area in the X or Z axis, cut off the Size: + if ((m_CurrentChunkX + 1) * cChunkDef::Width > m_Origin.x + m_Area.m_Size.x) + { + SizeX -= (m_CurrentChunkX + 1) * cChunkDef::Width - (m_Origin.x + m_Area.m_Size.x); + } + if ((m_CurrentChunkZ + 1) * cChunkDef::Width > m_Origin.z + m_Area.m_Size.z) + { + SizeZ -= (m_CurrentChunkZ + 1) * cChunkDef::Width - (m_Origin.z + m_Area.m_Size.z); + } + for (int y = 0; y < SizeY; y++) + { + int ChunkY = MinY + y; + int AreaY = y; + for (int z = 0; z < SizeZ; z++) + { + int ChunkZ = BaseZ + z; + int AreaZ = OffZ + z; + for (int x = 0; x < SizeX; x++) + { + int ChunkX = BaseX + x; + int AreaX = OffX + x; + m_Area.m_BlockTypes[m_Area.MakeIndex(AreaX, AreaY, AreaZ)] = a_BlockBuffer.GetBlock(ChunkX, ChunkY, ChunkZ); + } // for x + } // for z + } // for y + } + } -void cBlockArea::cChunkReader::BlockMeta(const NIBBLETYPE * a_BlockMetas) -{ - if (m_Area.m_BlockMetas == NULL) + if (m_Area.m_BlockMetas != NULL) { - // Don't want metas - return; + a_BlockBuffer.CopyMetas(m_Area.m_BlockMetas); } - CopyNibbles(m_Area.m_BlockMetas, a_BlockMetas); -} - - - - -void cBlockArea::cChunkReader::BlockLight(const NIBBLETYPE * a_BlockLight) -{ - if (m_Area.m_BlockLight == NULL) + if (m_Area.m_BlockLight != NULL) { - // Don't want light - return; + a_BlockBuffer.CopyBlockLight(m_Area.m_BlockLight); } - CopyNibbles(m_Area.m_BlockLight, a_BlockLight); -} - - - - -void cBlockArea::cChunkReader::BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) -{ - if (m_Area.m_BlockSkyLight == NULL) + if (m_Area.m_BlockSkyLight != NULL) { - // Don't want skylight - return; + a_BlockBuffer.CopySkyLight(m_Area.m_BlockSkyLight); } - CopyNibbles(m_Area.m_BlockSkyLight, a_BlockSkyLight); -} +} @@ -1985,7 +1977,7 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX; int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY; int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ; - int BlockCount = NewSizeX * NewSizeY * NewSizeZ; + size_t BlockCount = (size_t)(NewSizeX * NewSizeY * NewSizeZ); BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount]; memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE)); int OldIndex = 0; @@ -2015,7 +2007,7 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX; int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY; int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ; - int BlockCount = NewSizeX * NewSizeY * NewSizeZ; + size_t BlockCount = (size_t)(NewSizeX * NewSizeY * NewSizeZ); NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount]; memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE)); int OldIndex = 0; @@ -2067,4 +2059,134 @@ void cBlockArea::RelSetData( +template<bool MetasValid> +void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas) +{ + // Block types are compulsory, block metas are voluntary + if (!HasBlockTypes() || !a_Src.HasBlockTypes()) + { + LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__); + return; + } + + // Dst is *this, Src is a_Src + int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading + int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing + int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy + + int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading + int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing + int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy + + int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading + int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing + int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy + + switch (a_Strategy) + { + case cBlockArea::msOverwrite: + { + InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msOverwrite + + case cBlockArea::msFillAir: + { + InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msFillAir + + case cBlockArea::msImprint: + { + InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msImprint + + case cBlockArea::msLake: + { + InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msLake + + case cBlockArea::msSpongePrint: + { + InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msSpongePrint + + case cBlockArea::msDifference: + { + InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msDifference + + case cBlockArea::msMask: + { + InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >( + m_BlockTypes, a_Src.GetBlockTypes(), + DstMetas, SrcMetas, + SizeX, SizeY, SizeZ, + SrcOffX, SrcOffY, SrcOffZ, + DstOffX, DstOffY, DstOffZ, + a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(), + m_Size.x, m_Size.y, m_Size.z + ); + return; + } // case msMask + } // switch (a_Strategy) + + LOGWARNING("Unknown block area merge strategy: %d", a_Strategy); + ASSERT(!"Unknown block area merge strategy"); + return; +} + + diff --git a/src/BlockArea.h b/src/BlockArea.h index d28325d7d..2bd26facd 100644 --- a/src/BlockArea.h +++ b/src/BlockArea.h @@ -14,6 +14,7 @@ #include "ForEachChunkProvider.h" #include "Vector3.h" +#include "ChunkDataCallback.h" @@ -51,6 +52,9 @@ public: msFillAir, msImprint, msLake, + msSpongePrint, + msDifference, + msMask, } ; cBlockArea(void); @@ -127,8 +131,8 @@ public: - msFillAir overwrites only those blocks that were air - msImprint overwrites with only those blocks that are non-air - Special strategies: - msLake (evaluate top-down, first match wins): + Special strategies (evaluate top-down, first match wins): + msLake: | area block | | | this | Src | result | +----------+--------+--------+ @@ -143,6 +147,22 @@ public: | mycelium | stone | stone | ... and mycelium | A | stone | A | ... but nothing else | A | * | A | Everything else is left as it is + + msSpongePrint: + Used for most generators, it allows carving out air pockets, too, and uses the Sponge as the NOP block + | area block | | + | this | Src | result | + +----------+--------+--------+ + | A | sponge | A | Sponge is the NOP block + | * | B | B | Everything else overwrites anything + + msMask: + Combines two areas, the blocks that are the same are kept, differing ones are reset to air + | area block | | + | this | Src | result | + +------+-------+--------+ + | A | A | A | Same blocks are kept + | A | non-A | air | Everything else is replaced with air */ void Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy); @@ -275,7 +295,7 @@ public: NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block! NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block! NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block! - int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; } + size_t GetBlockCount(void) const { return (size_t)(m_Size.x * m_Size.y * m_Size.z); } int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const; protected: @@ -297,11 +317,8 @@ protected: void CopyNibbles(NIBBLETYPE * a_AreaDst, const NIBBLETYPE * a_ChunkSrc); // cChunkDataCallback overrides: - virtual bool Coords (int a_ChunkX, int a_ChunkZ) override; - virtual void BlockTypes (const BLOCKTYPE * a_BlockTypes) override; - virtual void BlockMeta (const NIBBLETYPE * a_BlockMetas) override; - virtual void BlockLight (const NIBBLETYPE * a_BlockLight) override; - virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override; + virtual bool Coords(int a_ChunkX, int a_ChunkZ) override; + virtual void ChunkData(const cChunkData & a_BlockTypes) override; } ; typedef NIBBLETYPE * NIBBLEARRAY; @@ -344,6 +361,9 @@ protected: int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight ); + + template<bool MetasValid> + void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas); // tolua_begin } ; // tolua_end diff --git a/src/BlockEntities/BeaconEntity.cpp b/src/BlockEntities/BeaconEntity.cpp new file mode 100644 index 000000000..0914353eb --- /dev/null +++ b/src/BlockEntities/BeaconEntity.cpp @@ -0,0 +1,116 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "BeaconEntity.h" +#include "../BlockArea.h" + + + + + +cBeaconEntity::cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : + super(E_BLOCK_BEACON, a_BlockX, a_BlockY, a_BlockZ, a_World) +{ +} + + + + + +int cBeaconEntity::GetPyramidLevel(void) +{ + cBlockArea Area; + int MinY = GetPosY() - 4; + if (MinY < 0) + { + MinY = 0; + } + int MaxY = GetPosY() - 1; + if (MaxY < 0) + { + MaxY = 0; + } + + Area.Read( + m_World, + GetPosX() - 4, GetPosX() + 4, + MinY, MaxY, + GetPosZ() - 4, GetPosZ() + 4, + cBlockArea::baTypes + ); + + int Layer = 1; + int MiddleXZ = 4; + + for (int Y = Area.GetSizeY() - 1; Y > 0; Y--) + { + for (int X = MiddleXZ - Layer; X <= (MiddleXZ + Layer); X++) + { + for (int Z = MiddleXZ - Layer; Z <= (MiddleXZ + Layer); Z++) + { + if (!IsMineralBlock(Area.GetRelBlockType(X, Y, Z))) + { + return Layer - 1; + } + } + } + Layer++; + } + + return Layer - 1; +} + + + + + +bool cBeaconEntity::IsMineralBlock(BLOCKTYPE a_BlockType) +{ + switch(a_BlockType) + { + case E_BLOCK_DIAMOND_BLOCK: + case E_BLOCK_GOLD_BLOCK: + case E_BLOCK_IRON_BLOCK: + case E_BLOCK_EMERALD_BLOCK: + { + return true; + } + } + return false; +} + + + + + +bool cBeaconEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + return false; +} + + + + + +void cBeaconEntity::SaveToJson(Json::Value& a_Value) +{ +} + + + + +void cBeaconEntity::SendTo(cClientHandle & a_Client) +{ +} + + + + + +void cBeaconEntity::UsedBy(cPlayer * a_Player) +{ +} + + + + diff --git a/src/BlockEntities/BeaconEntity.h b/src/BlockEntities/BeaconEntity.h new file mode 100644 index 000000000..b1df68bc4 --- /dev/null +++ b/src/BlockEntities/BeaconEntity.h @@ -0,0 +1,44 @@ + +#pragma once + +#include "BlockEntity.h" + + + + + +namespace Json +{ + class Value; +} + + + + + +class cBeaconEntity : + public cBlockEntity +{ + typedef cBlockEntity super; + +public: + + /** The initial constructor */ + cBeaconEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); + + /** Returns the amount of layers the pyramid below the beacon has. */ + int GetPyramidLevel(void); + + /** Returns true if the block is a diamond block, a golden block, an iron block or an emerald block. */ + static bool IsMineralBlock(BLOCKTYPE a_BlockType); + + // cBlockEntity overrides: + virtual void SaveToJson(Json::Value& a_Value ) override; + virtual void SendTo(cClientHandle & a_Client) override; + virtual void UsedBy(cPlayer * a_Player) override; + virtual bool Tick(float a_Dt, cChunk & /* a_Chunk */) override; +} ; + + + + diff --git a/src/BlockEntities/BlockEntity.cpp b/src/BlockEntities/BlockEntity.cpp index b42318c2f..430f04551 100644 --- a/src/BlockEntities/BlockEntity.cpp +++ b/src/BlockEntities/BlockEntity.cpp @@ -4,6 +4,7 @@ // Implements the cBlockEntity class that is the common ancestor for all block entities #include "Globals.h" +#include "BeaconEntity.h" #include "BlockEntity.h" #include "ChestEntity.h" #include "CommandBlockEntity.h" @@ -26,6 +27,7 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE { switch (a_BlockType) { + case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); diff --git a/src/BlockEntities/CMakeLists.txt b/src/BlockEntities/CMakeLists.txt index 920767f5c..3e3d17f86 100644 --- a/src/BlockEntities/CMakeLists.txt +++ b/src/BlockEntities/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(BlockEntities ${SOURCE}) diff --git a/src/BlockEntities/CommandBlockEntity.cpp b/src/BlockEntities/CommandBlockEntity.cpp index d395997a6..146ad915b 100644 --- a/src/BlockEntities/CommandBlockEntity.cpp +++ b/src/BlockEntities/CommandBlockEntity.cpp @@ -21,7 +21,8 @@ cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) : super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World), m_ShouldExecute(false), - m_IsPowered(false) + m_IsPowered(false), + m_Result(0) {} @@ -160,7 +161,7 @@ bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value) m_Command = a_Value.get("Command", "").asString(); m_LastOutput = a_Value.get("LastOutput", "").asString(); - m_Result = a_Value.get("SuccessCount", 0).asInt(); + m_Result = (NIBBLETYPE)a_Value.get("SuccessCount", 0).asInt(); return true; } diff --git a/src/BlockEntities/DispenserEntity.cpp b/src/BlockEntities/DispenserEntity.cpp index e03bf776d..2a32f69d9 100644 --- a/src/BlockEntities/DispenserEntity.cpp +++ b/src/BlockEntities/DispenserEntity.cpp @@ -128,10 +128,11 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum) if (DispChunk->GetBlock(DispX, DispY, DispZ) == E_BLOCK_AIR) { DispChunk->SetBlock(DispX, DispY, DispZ, E_BLOCK_FIRE, 0); - m_Contents.SetSlot(a_SlotNum, m_Contents.GetSlot(a_SlotNum).m_ItemType, m_Contents.GetSlot(a_SlotNum).m_ItemCount, m_Contents.GetSlot(a_SlotNum).m_ItemDamage + 1); - // If the durability has run out destroy the item. - if (m_Contents.GetSlot(a_SlotNum).m_ItemDamage > 64) - { + + bool ItemBroke = m_Contents.DamageItem(a_SlotNum, 1); + + if (ItemBroke) + { m_Contents.ChangeSlotCount(a_SlotNum, -1); } } diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp index 7d6d1f89e..1b1741713 100644 --- a/src/BlockEntities/FurnaceEntity.cpp +++ b/src/BlockEntities/FurnaceEntity.cpp @@ -413,19 +413,20 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const return false; } - if (m_Contents.GetSlot(fsOutput).IsEmpty()) + const cItem & Slot = m_Contents.GetSlot(fsOutput); + if (Slot.IsEmpty()) { // The output is empty, can cook return true; } - if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out)) + if (!Slot.IsEqual(*m_CurrentRecipe->Out)) { // The output slot is blocked with something that cannot be stacked with the recipe's output return false; } - if (m_Contents.GetSlot(fsOutput).IsFullStack()) + if (Slot.IsFullStack()) { // Cannot add any more items to the output slot return false; diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp index 41fb9f811..7f001c739 100644 --- a/src/BlockEntities/HopperEntity.cpp +++ b/src/BlockEntities/HopperEntity.cpp @@ -234,24 +234,27 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick) bool TrySuckPickupIn(cPickup * a_Pickup) { + cItem & Item = a_Pickup->GetItem(); + for (int i = 0; i < ContentsWidth * ContentsHeight; i++) { if (m_Contents.IsSlotEmpty(i)) { m_bFoundPickupsAbove = true; - m_Contents.SetSlot(i, a_Pickup->GetItem()); + m_Contents.SetSlot(i, Item); a_Pickup->Destroy(); // Kill pickup return true; } - else if (m_Contents.GetSlot(i).IsEqual(a_Pickup->GetItem()) && !m_Contents.GetSlot(i).IsFullStack()) + else if (m_Contents.GetSlot(i).IsEqual(Item) && !m_Contents.GetSlot(i).IsFullStack()) { m_bFoundPickupsAbove = true; int PreviousCount = m_Contents.GetSlot(i).m_ItemCount; - a_Pickup->GetItem().m_ItemCount -= m_Contents.ChangeSlotCount(i, a_Pickup->GetItem().m_ItemCount) - PreviousCount; // Set count to however many items were added - if (a_Pickup->GetItem().IsEmpty()) + Item.m_ItemCount -= m_Contents.ChangeSlotCount(i, Item.m_ItemCount) - PreviousCount; // Set count to however many items were added + + if (Item.IsEmpty()) { a_Pickup->Destroy(); // Kill pickup if all items were added } diff --git a/src/BlockEntities/MobHeadEntity.cpp b/src/BlockEntities/MobHeadEntity.cpp index c0a1781f6..dc9c18d58 100644 --- a/src/BlockEntities/MobHeadEntity.cpp +++ b/src/BlockEntities/MobHeadEntity.cpp @@ -14,6 +14,8 @@ cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World), + m_Type(SKULL_TYPE_SKELETON), + m_Rotation(SKULL_ROTATION_NORTH), m_Owner("") { } diff --git a/src/BlockID.cpp b/src/BlockID.cpp index 79e122032..bfe826f40 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -102,7 +102,7 @@ public: return true; } - a_Item.m_ItemDamage = atoi(Split[1].c_str()); + a_Item.m_ItemDamage = (short)atoi(Split[1].c_str()); if ((a_Item.m_ItemDamage == 0) && (Split[1] != "0")) { // Parsing the number failed @@ -324,7 +324,7 @@ eDimension StringToDimension(const AString & a_DimensionString) { dimOverworld, "Normal"}, { dimOverworld, "World"}, { dimNether, "Nether"}, - { dimNether, "Hell"}, // Alternate name for End + { dimNether, "Hell"}, // Alternate name for Nether { dimEnd, "End"}, { dimEnd, "Sky"}, // Old name for End } ; @@ -337,7 +337,8 @@ eDimension StringToDimension(const AString & a_DimensionString) } // for i - DimensionMap[] // Not found - return (eDimension)-1000; + LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", a_DimensionString.c_str()); + return dimOverworld; } diff --git a/src/BlockID.h b/src/BlockID.h index 2fec512e2..a227245aa 100644 --- a/src/BlockID.h +++ b/src/BlockID.h @@ -503,6 +503,10 @@ enum E_META_PLANKS_CONIFER = 1, E_META_PLANKS_BIRCH = 2, E_META_PLANKS_JUNGLE = 3, + + // E_BLOCK_(XXX_WEIGHTED)_PRESSURE_PLATE metas: + E_META_PRESSURE_PLATE_RAISED = 0, + E_META_PRESSURE_PLATE_DEPRESSED = 1, // E_BLOCK_QUARTZ_BLOCK metas: E_META_QUARTZ_NORMAL = 0, diff --git a/src/BlockInfo.cpp b/src/BlockInfo.cpp index 7d438ba3e..e8d9a7ec4 100644 --- a/src/BlockInfo.cpp +++ b/src/BlockInfo.cpp @@ -110,10 +110,13 @@ void cBlockInfo::Initialize(void) // Transparent blocks ms_Info[E_BLOCK_ACTIVATOR_RAIL ].m_Transparent = true; ms_Info[E_BLOCK_AIR ].m_Transparent = true; + ms_Info[E_BLOCK_ANVIL ].m_Transparent = true; ms_Info[E_BLOCK_BIG_FLOWER ].m_Transparent = true; ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_Transparent = true; + ms_Info[E_BLOCK_CAKE ].m_Transparent = true; ms_Info[E_BLOCK_CARROTS ].m_Transparent = true; ms_Info[E_BLOCK_CHEST ].m_Transparent = true; + ms_Info[E_BLOCK_COBBLESTONE_WALL ].m_Transparent = true; ms_Info[E_BLOCK_COBWEB ].m_Transparent = true; ms_Info[E_BLOCK_CROPS ].m_Transparent = true; ms_Info[E_BLOCK_DANDELION ].m_Transparent = true; @@ -126,9 +129,11 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_FLOWER_POT ].m_Transparent = true; ms_Info[E_BLOCK_GLASS ].m_Transparent = true; ms_Info[E_BLOCK_GLASS_PANE ].m_Transparent = true; + ms_Info[E_BLOCK_HEAD ].m_Transparent = true; ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true; ms_Info[E_BLOCK_ICE ].m_Transparent = true; ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true; + ms_Info[E_BLOCK_LADDER ].m_Transparent = true; ms_Info[E_BLOCK_LAVA ].m_Transparent = true; ms_Info[E_BLOCK_LEAVES ].m_Transparent = true; ms_Info[E_BLOCK_LEVER ].m_Transparent = true; @@ -195,12 +200,14 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_BED ].m_PistonBreakable = true; ms_Info[E_BLOCK_BIG_FLOWER ].m_PistonBreakable = true; ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_PistonBreakable = true; + ms_Info[E_BLOCK_CAKE ].m_PistonBreakable = true; ms_Info[E_BLOCK_COBWEB ].m_PistonBreakable = true; ms_Info[E_BLOCK_CROPS ].m_PistonBreakable = true; ms_Info[E_BLOCK_DANDELION ].m_PistonBreakable = true; ms_Info[E_BLOCK_DEAD_BUSH ].m_PistonBreakable = true; ms_Info[E_BLOCK_FIRE ].m_PistonBreakable = true; ms_Info[E_BLOCK_FLOWER ].m_PistonBreakable = true; + ms_Info[E_BLOCK_HEAD ].m_PistonBreakable = true; ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_PistonBreakable = true; ms_Info[E_BLOCK_INACTIVE_COMPARATOR ].m_PistonBreakable = true; ms_Info[E_BLOCK_IRON_DOOR ].m_PistonBreakable = true; @@ -242,6 +249,7 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_CACTUS ].m_IsSnowable = false; ms_Info[E_BLOCK_CHEST ].m_IsSnowable = false; ms_Info[E_BLOCK_CROPS ].m_IsSnowable = false; + ms_Info[E_BLOCK_COBBLESTONE_WALL ].m_IsSnowable = false; ms_Info[E_BLOCK_DANDELION ].m_IsSnowable = false; ms_Info[E_BLOCK_FIRE ].m_IsSnowable = false; ms_Info[E_BLOCK_FLOWER ].m_IsSnowable = false; @@ -275,6 +283,7 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_POWERED_RAIL ].m_IsSnowable = false; ms_Info[E_BLOCK_DETECTOR_RAIL ].m_IsSnowable = false; ms_Info[E_BLOCK_COBWEB ].m_IsSnowable = false; + ms_Info[E_BLOCK_HEAD ].m_IsSnowable = false; // Blocks that don't drop without a special tool: @@ -282,6 +291,7 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_CAULDRON ].m_RequiresSpecialTool = true; ms_Info[E_BLOCK_COAL_ORE ].m_RequiresSpecialTool = true; ms_Info[E_BLOCK_COBBLESTONE ].m_RequiresSpecialTool = true; + ms_Info[E_BLOCK_COBBLESTONE_WALL ].m_RequiresSpecialTool = true; ms_Info[E_BLOCK_COBBLESTONE_STAIRS ].m_RequiresSpecialTool = true; ms_Info[E_BLOCK_COBWEB ].m_RequiresSpecialTool = true; ms_Info[E_BLOCK_DIAMOND_BLOCK ].m_RequiresSpecialTool = true; @@ -324,6 +334,7 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_AIR ].m_IsSolid = false; ms_Info[E_BLOCK_BIG_FLOWER ].m_IsSolid = false; ms_Info[E_BLOCK_BROWN_MUSHROOM ].m_IsSolid = false; + ms_Info[E_BLOCK_CAKE ].m_IsSolid = false; ms_Info[E_BLOCK_CARROTS ].m_IsSolid = false; ms_Info[E_BLOCK_COBWEB ].m_IsSolid = false; ms_Info[E_BLOCK_CROPS ].m_IsSolid = false; @@ -365,7 +376,7 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_WOODEN_SLAB ].m_IsSolid = false; - // Torch placeable blocks: + // Blocks that fully occupy their voxel - used as a guide for torch placeable blocks, amongst other things: ms_Info[E_BLOCK_NEW_LOG ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_BEDROCK ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_BLOCK_OF_COAL ].m_FullyOccupiesVoxel = true; @@ -397,6 +408,7 @@ void cBlockInfo::Initialize(void) ms_Info[E_BLOCK_HAY_BALE ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_HUGE_BROWN_MUSHROOM ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_HUGE_RED_MUSHROOM ].m_FullyOccupiesVoxel = true; + ms_Info[E_BLOCK_ICE ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_IRON_BLOCK ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_IRON_ORE ].m_FullyOccupiesVoxel = true; ms_Info[E_BLOCK_JACK_O_LANTERN ].m_FullyOccupiesVoxel = true; diff --git a/src/BlockTracer.h b/src/BlockTracer.h index 40d80da1a..a18c8df4d 100644 --- a/src/BlockTracer.h +++ b/src/BlockTracer.h @@ -28,6 +28,9 @@ public: class cCallbacks abstract { public: + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + /** Called on each block encountered along the path, including the first block (path start) When this callback returns true, the tracing is aborted. */ diff --git a/src/Blocks/BlockAnvil.h b/src/Blocks/BlockAnvil.h index 9f5f84be0..35a356678 100644 --- a/src/Blocks/BlockAnvil.h +++ b/src/Blocks/BlockAnvil.h @@ -18,10 +18,19 @@ public: { } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { a_Pickups.push_back(cItem(E_BLOCK_ANVIL, 1, a_BlockMeta >> 2)); } + + + virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + { + cWindow * Window = new cAnvilWindow(a_BlockX, a_BlockY, a_BlockZ); + a_Player->OpenWindow(Window); + } + virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, @@ -31,27 +40,23 @@ public: ) override { a_BlockType = m_BlockType; - - int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3; - int RawMeta = a_BlockMeta >> 2; - - Direction++; - Direction %= 4; + NIBBLETYPE HighBits = a_BlockMeta & 0x0c; // Only highest two bits are preserved + int Direction = (int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 1.5) & 0x3; switch (Direction) { - case 0: a_BlockMeta = 0x2 | RawMeta << 2; break; - case 1: a_BlockMeta = 0x3 | RawMeta << 2; break; - case 2: a_BlockMeta = 0x0 | RawMeta << 2; break; - case 3: a_BlockMeta = 0x1 | RawMeta << 2; break; + case 0: a_BlockMeta = 0x2 | HighBits; break; + case 1: a_BlockMeta = 0x3 | HighBits; break; + case 2: a_BlockMeta = 0x0 | HighBits; break; + case 3: a_BlockMeta = 0x1 | HighBits; break; default: { return false; } } - return true; } + virtual bool IsUseable() override { return true; diff --git a/src/Blocks/BlockBed.h b/src/Blocks/BlockBed.h index 6daa94730..51e79b888 100644 --- a/src/Blocks/BlockBed.h +++ b/src/Blocks/BlockBed.h @@ -4,7 +4,7 @@ #include "BlockHandler.h" #include "ChunkInterface.h" #include "WorldInterface.h" -#include "MetaRotater.h" +#include "MetaRotator.h" #include "../Entities/Player.h" @@ -12,11 +12,11 @@ class cBlockBedHandler : - public cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true> + public cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01, true> { public: cBlockBedHandler(BLOCKTYPE a_BlockType) - : cMetaRotater<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType) + : cMetaRotator<cBlockHandler, 0x3, 0x02, 0x03, 0x00, 0x01,true>(a_BlockType) { } @@ -39,6 +39,13 @@ public: } + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return true; + } + + + // Bed specific helper functions static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/src/Blocks/BlockBigFlower.h b/src/Blocks/BlockBigFlower.h new file mode 100644 index 000000000..39fd3cac8 --- /dev/null +++ b/src/Blocks/BlockBigFlower.h @@ -0,0 +1,131 @@ + +#pragma once + +#include "BlockHandler.h" + + + + + +class cBlockBigFlowerHandler : + public cBlockHandler +{ +public: + typedef cBlockHandler super; + + cBlockBigFlowerHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + + virtual void DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_BlockPluginInterface, cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (Meta & 0x8) + { + super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY - 1, a_BlockZ); + } + else + { + super::DropBlock(a_ChunkInterface, a_WorldInterface, a_BlockPluginInterface, a_Digger, a_BlockX, a_BlockY, a_BlockZ); + } + } + + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + NIBBLETYPE Meta = a_BlockMeta & 0x7; + + if ((Meta == 2) || (Meta == 3)) + { + return; + } + + a_Pickups.push_back(cItem(E_BLOCK_BIG_FLOWER, 1, Meta)); + } + + + virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (Meta & 0x8) + { + Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ); + } + + NIBBLETYPE FlowerMeta = Meta & 0x7; + if (!a_Player->IsGameModeCreative()) + { + if (((FlowerMeta == 2) || (FlowerMeta == 3)) && (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SHEARS)) + { + MTRand r1; + if (r1.randInt(10) == 5) + { + cItems Pickups; + if (FlowerMeta == 2) + { + Pickups.Add(E_BLOCK_TALL_GRASS, 2, 1); + } + else if (FlowerMeta == 3) + { + Pickups.Add(E_BLOCK_TALL_GRASS, 2, 2); + } + a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ); + } + a_Player->UseEquippedItem(); + } + } + } + + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + { + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR) && (a_RelY < cChunkDef::Height) && ((a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_AIR) || (a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ) == E_BLOCK_BIG_FLOWER))); + } + + + virtual void OnPlacedByPlayer( + cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, + int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, + int a_CursorX, int a_CursorY, int a_CursorZ, + BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta + ) override + { + int Meta = (((int)floor(a_Player->GetYaw() * 4.0 / 360.0 + 0.5) & 0x3) + 2) % 4; + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, m_BlockType, 0x8 | Meta); + } + + + virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + + if (OldMeta & 0x8) + { + // Was upper part of flower + if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ) == m_BlockType) + { + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + } + } + else + { + // Was lower part + if (a_ChunkInterface.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ) == m_BlockType) + { + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY + 1, a_BlockZ, E_BLOCK_AIR, 0); + } + } + } + + + virtual const char * GetStepSound(void) override + { + return "step.grass"; + } +} ; + + + + diff --git a/src/Blocks/BlockButton.h b/src/Blocks/BlockButton.h index 740cbe3c4..4b2f6f618 100644 --- a/src/Blocks/BlockButton.h +++ b/src/Blocks/BlockButton.h @@ -2,17 +2,17 @@ #include "BlockHandler.h" #include "Chunk.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockButtonHandler : - public cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true> + public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true> { public: cBlockButtonHandler(BLOCKTYPE a_BlockType) - : cMetaRotater<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType) + : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType) { } diff --git a/src/Blocks/BlockCauldron.h b/src/Blocks/BlockCauldron.h index 2e1032d2b..41b79b6c3 100644 --- a/src/Blocks/BlockCauldron.h +++ b/src/Blocks/BlockCauldron.h @@ -23,7 +23,7 @@ public: virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override { - char Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); switch (a_Player->GetEquippedItem().m_ItemType) { case E_ITEM_WATER_BUCKET: diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index 30588d8fc..c9a769c75 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -4,18 +4,18 @@ #include "BlockEntity.h" #include "../BlockArea.h" #include "../Entities/Player.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockChestHandler : - public cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true> + public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { public: cBlockChestHandler(BLOCKTYPE a_BlockType) - : cMetaRotater<cBlockEntityHandler, 0x07, 0x04, 0x01, 0x03, 0x02, true>(a_BlockType) + : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) { } @@ -56,6 +56,7 @@ public: (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) ) { + // FIXME: This is unreachable, as the condition is the same as the above one a_BlockMeta = (yaw < 0) ? 4 : 5; return true; } diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h index e570ff302..4dd05366d 100644 --- a/src/Blocks/BlockComparator.h +++ b/src/Blocks/BlockComparator.h @@ -3,18 +3,18 @@ #include "BlockHandler.h" #include "BlockRedstoneRepeater.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockComparatorHandler : - public cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true> + public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true> { public: cBlockComparatorHandler(BLOCKTYPE a_BlockType) - : cMetaRotater<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType) + : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType) { } diff --git a/src/Blocks/BlockCrops.h b/src/Blocks/BlockCrops.h index ffc2b3f8b..8606cf3f3 100644 --- a/src/Blocks/BlockCrops.h +++ b/src/Blocks/BlockCrops.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" @@ -21,7 +21,7 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override { - MTRand rand; + cFastRandom rand; if (a_Meta == 0x7) { @@ -31,18 +31,18 @@ public: case E_BLOCK_CROPS: { a_Pickups.push_back(cItem(E_ITEM_WHEAT, 1, 0)); - a_Pickups.push_back(cItem(E_ITEM_SEEDS, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2 + a_Pickups.push_back(cItem(E_ITEM_SEEDS, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_CARROTS: { - a_Pickups.push_back(cItem(E_ITEM_CARROT, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2 + a_Pickups.push_back(cItem(E_ITEM_CARROT, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2 break; } case E_BLOCK_POTATOES: { - a_Pickups.push_back(cItem(E_ITEM_POTATO, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); // [1 .. 3] with high preference of 2 - if (rand.randInt(20) == 0) + a_Pickups.push_back(cItem(E_ITEM_POTATO, (char)(1 + (rand.NextInt(3) + rand.NextInt(3)) / 2), 0)); // [1 .. 3] with high preference of 2 + if (rand.NextInt(21) == 0) { // With a 5% chance, drop a poisonous potato as well a_Pickups.push_back(cItem(E_ITEM_POISONOUS_POTATO, 1, 0)); diff --git a/src/Blocks/BlockDirt.h b/src/Blocks/BlockDirt.h index a1ab74257..2d4fccbac 100644 --- a/src/Blocks/BlockDirt.h +++ b/src/Blocks/BlockDirt.h @@ -2,7 +2,7 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" @@ -35,8 +35,10 @@ public: // Grass becomes dirt if there is something on top of it: if (a_RelY < cChunkDef::Height - 1) { - BLOCKTYPE Above = a_Chunk.GetBlock(a_RelX, a_RelY + 1, a_RelZ); - if ((!cBlockInfo::IsTransparent(Above) && !cBlockInfo::IsOneHitDig(Above)) || IsBlockWater(Above)) + BLOCKTYPE Above; + NIBBLETYPE AboveMeta; + a_Chunk.GetBlockTypeMeta(a_RelX, a_RelY + 1, a_RelZ, Above, AboveMeta); + if (!cBlockInfo::GetHandler(Above)->CanDirtGrowGrass(AboveMeta)) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_DIRT, E_META_DIRT_NORMAL); return; @@ -44,12 +46,12 @@ public: } // Grass spreads to adjacent dirt blocks: - MTRand rand; // TODO: Replace with cFastRandom + cFastRandom rand; for (int i = 0; i < 2; i++) // Pick two blocks to grow to { - int OfsX = rand.randInt(2) - 1; // [-1 .. 1] - int OfsY = rand.randInt(4) - 3; // [-3 .. 1] - int OfsZ = rand.randInt(2) - 1; // [-1 .. 1] + int OfsX = rand.NextInt(3, a_RelX) - 1; // [-1 .. 1] + int OfsY = rand.NextInt(5, a_RelY) - 3; // [-3 .. 1] + int OfsZ = rand.NextInt(3, a_RelZ) - 1; // [-1 .. 1] BLOCKTYPE DestBlock; NIBBLETYPE DestMeta; @@ -77,7 +79,7 @@ public: BLOCKTYPE AboveDest; NIBBLETYPE AboveMeta; Chunk->GetBlockTypeMeta(BlockX, BlockY + 1, BlockZ, AboveDest, AboveMeta); - if ((cBlockInfo::IsOneHitDig(AboveDest) || cBlockInfo::IsTransparent(AboveDest)) && !IsBlockWater(AboveDest)) + if (cBlockInfo::GetHandler(AboveDest)->CanDirtGrowGrass(AboveMeta)) { if (!cRoot::Get()->GetPluginManager()->CallHookBlockSpread((cWorld*) &a_WorldInterface, BlockX * cChunkDef::Width, BlockY, BlockZ * cChunkDef::Width, ssGrassSpread)) { diff --git a/src/Blocks/BlockDoor.cpp b/src/Blocks/BlockDoor.cpp index 4e38ef334..479c68153 100644 --- a/src/Blocks/BlockDoor.cpp +++ b/src/Blocks/BlockDoor.cpp @@ -110,3 +110,87 @@ const char * cBlockDoorHandler::GetStepSound(void) + +NIBBLETYPE cBlockDoorHandler::MetaRotateCCW(NIBBLETYPE a_Meta) +{ + if (a_Meta & 0x08) + { + return a_Meta; + } + else + { + return super::MetaRotateCCW(a_Meta); + } +} + + + +NIBBLETYPE cBlockDoorHandler::MetaRotateCW(NIBBLETYPE a_Meta) +{ + if (a_Meta & 0x08) + { + return a_Meta; + } + else + { + return super::MetaRotateCW(a_Meta); + } +} + + + +NIBBLETYPE cBlockDoorHandler::MetaMirrorXY(NIBBLETYPE a_Meta) +{ + // Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data + // Return a_Meta if panel is a top panel (0x08 bit is set to 1) + + // Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored + // in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time, + // so the function can only see either the hinge position or orientation, but not both, at any given time. The class itself + // needs extra datamembers. + if (a_Meta & 0x08) return a_Meta; + + // Holds open/closed meta data. 0x0C == 1100. + NIBBLETYPE OtherMeta = a_Meta & 0x0C; + + // Mirrors according to a table. 0x03 == 0011. + switch (a_Meta & 0x03) + { + case 0x03: return 0x01 + OtherMeta; // South -> North + case 0x01: return 0x03 + OtherMeta; // North -> South + } + + // Not Facing North or South; No change. + return a_Meta; +} + + + +NIBBLETYPE cBlockDoorHandler::MetaMirrorYZ(NIBBLETYPE a_Meta) +{ + // Top bit (0x08) contains door panel type (Top/Bottom panel) Only Bottom panels contain position data + // Return a_Meta if panel is a top panel (0x08 bit is set to 1) + + // Note: Currently, you can not properly mirror the hinges on a double door. The orientation of the door is stored + // in only the bottom tile while the hinge position is in the top tile. This function only operates on one tile at a time, + // so the function can only see either the hinge position or orientation, but not both, at any given time.The class itself + // needs extra datamembers. + + if (a_Meta & 0x08) return a_Meta; + + // Holds open/closed meta data. 0x0C == 1100. + NIBBLETYPE OtherMeta = a_Meta & 0x0C; + + // Mirrors according to a table. 0x03 == 0011. + switch (a_Meta & 0x03) + { + case 0x00: return 0x02 + OtherMeta; // West -> East + case 0x02: return 0x00 + OtherMeta; // East -> West + } + + // Not Facing North or South; No change. + return a_Meta; +} + + + diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h index 981774c17..797fe484c 100644 --- a/src/Blocks/BlockDoor.h +++ b/src/Blocks/BlockDoor.h @@ -4,15 +4,15 @@ #include "BlockHandler.h" #include "../Entities/Player.h" #include "Chunk.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockDoorHandler : - public cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> + public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> { - typedef cMetaRotater<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super; + typedef cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x03, 0x00, true> super; public: cBlockDoorHandler(BLOCKTYPE a_BlockType); @@ -21,6 +21,10 @@ public: virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override; virtual const char * GetStepSound(void) override; + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override; + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override; + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override; + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override; virtual bool GetPlacementBlockTypeMeta( cChunkInterface & a_ChunkInterface, cPlayer * a_Player, @@ -142,14 +146,14 @@ public: static void ChangeDoor(cChunkInterface & a_ChunkInterface, int a_X, int a_Y, int a_Z) { NIBBLETYPE OldMetaData = a_ChunkInterface.GetBlockMeta(a_X, a_Y, a_Z); - + a_ChunkInterface.SetBlockMeta(a_X, a_Y, a_Z, ChangeStateMetaData(OldMetaData)); - + if (OldMetaData & 8) { // Current block is top of the door BLOCKTYPE BottomBlock = a_ChunkInterface.GetBlock(a_X, a_Y - 1, a_Z); - NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z); + NIBBLETYPE BottomMeta = a_ChunkInterface.GetBlockMeta(a_X, a_Y - 1, a_Z); if (IsDoor(BottomBlock) && !(BottomMeta & 8)) { @@ -168,62 +172,6 @@ public: } } } - - - virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override - { - if (a_Meta & 0x08) - { - return a_Meta; - } - else - { - return super::MetaRotateCCW(a_Meta); - } - } - - - - virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override - { - if (a_Meta & 0x08) - { - return a_Meta; - } - else - { - return super::MetaRotateCW(a_Meta); - } - } - - - - virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override - { - if (a_Meta & 0x08) - { - return a_Meta; - } - else - { - return super::MetaMirrorXY(a_Meta); - } - } - - - - virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override - { - if (a_Meta & 0x08) - { - return a_Meta; - } - else - { - return super::MetaMirrorYZ(a_Meta); - } - } - } ; diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h index 7e0ad0e55..88b61a418 100644 --- a/src/Blocks/BlockDropSpenser.h +++ b/src/Blocks/BlockDropSpenser.h @@ -6,18 +6,18 @@ #pragma once #include "../Piston.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockDropSpenserHandler : - public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> + public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { public: cBlockDropSpenserHandler(BLOCKTYPE a_BlockType) : - cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) + cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) { } diff --git a/src/Blocks/BlockEnchantmentTable.h b/src/Blocks/BlockEnchantmentTable.h new file mode 100644 index 000000000..81d2cb9a0 --- /dev/null +++ b/src/Blocks/BlockEnchantmentTable.h @@ -0,0 +1,37 @@ + +#pragma once + +#include "BlockHandler.h" +#include "../UI/Window.h" +#include "../Entities/Player.h" + + + + + +class cBlockEnchantmentTableHandler : + public cBlockHandler +{ +public: + cBlockEnchantmentTableHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + + virtual void OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override + { + cWindow * Window = new cEnchantingWindow(a_BlockX, a_BlockY, a_BlockZ); + a_Player->OpenWindow(Window); + } + + + virtual bool IsUseable(void) override + { + return true; + } +}; + + + + diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h index 97cf484fb..67955f8ce 100644 --- a/src/Blocks/BlockEnderchest.h +++ b/src/Blocks/BlockEnderchest.h @@ -2,17 +2,17 @@ #pragma once #include "BlockEntity.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockEnderchestHandler : - public cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> + public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { public: cBlockEnderchestHandler(BLOCKTYPE a_BlockType) - : cMetaRotater<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) + : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) { } diff --git a/src/Blocks/BlockFarmland.h b/src/Blocks/BlockFarmland.h index b720ccd14..3dd5bcd1d 100644 --- a/src/Blocks/BlockFarmland.h +++ b/src/Blocks/BlockFarmland.h @@ -52,9 +52,9 @@ public: return; } - int NumBlocks = Area.GetBlockCount(); + size_t NumBlocks = Area.GetBlockCount(); BLOCKTYPE * BlockTypes = Area.GetBlockTypes(); - for (int i = 0; i < NumBlocks; i++) + for (size_t i = 0; i < NumBlocks; i++) { if ( (BlockTypes[i] == E_BLOCK_WATER) || diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h index e3162bbd6..e202c6610 100644 --- a/src/Blocks/BlockFenceGate.h +++ b/src/Blocks/BlockFenceGate.h @@ -2,17 +2,17 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockFenceGateHandler : - public cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true> + public cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true> { public: cBlockFenceGateHandler(BLOCKTYPE a_BlockType) : - cMetaRotater<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType) + cMetaRotator<cBlockHandler, 0x03, 0x02, 0x03, 0x00, 0x01, true>(a_BlockType) { } diff --git a/src/Blocks/BlockFire.h b/src/Blocks/BlockFire.h index a25b87858..f9f32eb50 100644 --- a/src/Blocks/BlockFire.h +++ b/src/Blocks/BlockFire.h @@ -17,25 +17,27 @@ public: } /// Portal boundary and direction variables - int XZP, XZM, Dir; // For wont of a better name... + // 2014_03_30 _X: What are these used for? Why do we need extra variables? + int XZP, XZM; + NIBBLETYPE Dir; virtual void OnPlaced(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override { /* PORTAL FINDING ALGORITH ======================= - -Get clicked base block - -Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered. - Uses this value as a reference (the 'ceiling') - -For both directions (if one fails, try the other), BASE (clicked) block: - -Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1) - -If a border was encountered, go the other direction and repeat above - -Write borders to XZP and XZM, write direction portal faces to Dir - -Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir + - Get clicked base block + - Trace upwards to find first obsidian block; aborts if anything other than obsidian or air is encountered. + Uses this value as a reference (the 'ceiling') + - For both directions (if one fails, try the other), BASE (clicked) block: + - Go in one direction, only stop if a non obsidian block is encountered (abort) OR a portal border is encountered (FindObsidianCeiling returns -1) + - If a border was encountered, go the other direction and repeat above + - Write borders to XZP and XZM, write direction portal faces to Dir + - Loop through boundary variables, and fill with portal blocks based on Dir with meta from Dir */ a_BlockY--; // Because we want the block below the fire - FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface); // Brought to you by Aperture Science + FindAndSetPortalFrame(a_BlockX, a_BlockY, a_BlockZ, a_ChunkInterface, a_WorldInterface); } virtual void OnDigging(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override @@ -66,7 +68,6 @@ public: { return 0; } - for (int newY = Y + 1; newY < cChunkDef::Height; newY++) { @@ -82,7 +83,7 @@ public: // This is because the frame is a solid obsidian pillar if ((MaxY != 0) && (newY == Y + 1)) { - return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface); + return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0; } else { @@ -97,18 +98,18 @@ public: } /// Evaluates if coords have a valid border on top, based on MaxY - int EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) + bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface) { for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners { if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN) { // Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal - return 0; + return false; } } // Everything was obsidian, found a border! - return -1; // Return -1 for a frame border + return true; } /// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE) @@ -167,7 +168,7 @@ public: { return false; // Not valid slice, no portal can be formed } - } XZP = X1 - 1; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there + } XZP = X1 - 1; // Set boundary of frame interior for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM) { int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY); @@ -197,13 +198,13 @@ public: if ((Value == -1) || (ValueTwo == -1)) { FoundFrameZP = true; - continue; + break; } else if ((Value != MaxY) && (ValueTwo != MaxY)) { return false; } - } XZP = Z1 - 2; + } XZP = Z1 - 1; for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--) { int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY); @@ -211,13 +212,13 @@ public: if ((Value == -1) || (ValueTwo == -1)) { FoundFrameZM = true; - continue; + break; } else if ((Value != MaxY) && (ValueTwo != MaxY)) { return false; } - } XZM = Z2 + 2; + } XZM = Z2 + 1; return (FoundFrameZP && FoundFrameZM); } }; diff --git a/src/Blocks/BlockFluid.h b/src/Blocks/BlockFluid.h index 37885e4de..d0c4ea55b 100644 --- a/src/Blocks/BlockFluid.h +++ b/src/Blocks/BlockFluid.h @@ -49,6 +49,12 @@ public: } super::Check(a_ChunkInterface, a_PluginInterface, a_RelX, a_RelY, a_RelZ, a_Chunk); } + + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return false; + } } ; @@ -93,6 +99,7 @@ public: // Check if it's fuel: BLOCKTYPE BlockType; if ( + ((a_RelY + y < 0) || (a_RelY + y > cChunkDef::Height)) || !a_Chunk.UnboundedRelGetBlockType(a_RelX + x, a_RelY + y, a_RelZ + z, BlockType) || !cFireSimulator::IsFuel(BlockType) ) @@ -119,6 +126,7 @@ public: for (size_t i = 0; i < ARRAYCOUNT(CrossCoords); i++) { if ( + ((RelY + CrossCoords[i].y >= 0) && (RelY + CrossCoords[i].y <= cChunkDef::Height)) && a_Chunk.UnboundedRelGetBlockType(RelX + CrossCoords[i].x, RelY + CrossCoords[i].y, RelZ + CrossCoords[i].z, BlockType) && (BlockType == E_BLOCK_AIR) ) diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h index 27ef2689f..a7a807957 100644 --- a/src/Blocks/BlockFurnace.h +++ b/src/Blocks/BlockFurnace.h @@ -4,17 +4,17 @@ #include "BlockEntity.h" #include "../World.h" #include "../Piston.h" - +#include "MetaRotator.h" class cBlockFurnaceHandler : - public cBlockEntityHandler + public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { public: - cBlockFurnaceHandler(BLOCKTYPE a_BlockType) : - cBlockEntityHandler(a_BlockType) + cBlockFurnaceHandler(BLOCKTYPE a_BlockType) + : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) { } diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 4f74e2f45..304e35e84 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -8,6 +8,7 @@ #include "../Chunk.h" #include "BlockAnvil.h" #include "BlockBed.h" +#include "BlockBigFlower.h" #include "BlockBrewingStand.h" #include "BlockButton.h" #include "BlockCactus.h" @@ -24,6 +25,7 @@ #include "BlockDirt.h" #include "BlockDoor.h" #include "BlockDropSpenser.h" +#include "BlockEnchantmentTable.h" #include "BlockEnderchest.h" #include "BlockEntity.h" #include "BlockFarmland.h" @@ -41,6 +43,7 @@ #include "BlockIce.h" #include "BlockLadder.h" #include "BlockLeaves.h" +#include "BlockLilypad.h" #include "BlockNewLeaves.h" #include "BlockLever.h" #include "BlockMelon.h" @@ -89,6 +92,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType); case E_BLOCK_BED: return new cBlockBedHandler (a_BlockType); + case E_BLOCK_BIG_FLOWER: return new cBlockBigFlowerHandler (a_BlockType); case E_BLOCK_BIRCH_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_BREWING_STAND: return new cBlockBrewingStandHandler (a_BlockType); case E_BLOCK_BRICK_STAIRS: return new cBlockStairsHandler (a_BlockType); @@ -116,6 +120,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_DOUBLE_WOODEN_SLAB: return new cBlockDoubleSlabHandler (a_BlockType); case E_BLOCK_DROPPER: return new cBlockDropSpenserHandler (a_BlockType); case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType); + case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType); case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType); case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( ); case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType); @@ -142,6 +147,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType) case E_BLOCK_LAPIS_ORE: return new cBlockOreHandler (a_BlockType); case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType); case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType); + case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType); case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType); case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType); case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType); @@ -394,6 +400,15 @@ bool cBlockHandler::CanBeAt(cChunkInterface & a_ChunkInterface, int a_BlockX, in +bool cBlockHandler::CanDirtGrowGrass(NIBBLETYPE a_Meta) +{ + return ((cBlockInfo::IsTransparent(m_BlockType)) || (cBlockInfo::IsOneHitDig(m_BlockType))); +} + + + + + bool cBlockHandler::IsUseable() { return false; diff --git a/src/Blocks/BlockHandler.h b/src/Blocks/BlockHandler.h index 3a3efb3cc..fb6cae729 100644 --- a/src/Blocks/BlockHandler.h +++ b/src/Blocks/BlockHandler.h @@ -85,6 +85,9 @@ public: /// Checks if the block can stay at the specified relative coords in the chunk virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk); + + /** Can the dirt under this block grow to grass? */ + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta); /** Checks if the block can be placed at this point. Default: CanBeAt(...) diff --git a/src/Blocks/BlockHopper.h b/src/Blocks/BlockHopper.h index 59b84aa0e..a882bb077 100644 --- a/src/Blocks/BlockHopper.h +++ b/src/Blocks/BlockHopper.h @@ -3,16 +3,16 @@ // Declares the cBlockHopperHandler class representing the handler for the Hopper block - +#include "MetaRotator.h" class cBlockHopperHandler : - public cBlockEntityHandler + public cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { public: cBlockHopperHandler(BLOCKTYPE a_BlockType) - : cBlockEntityHandler(a_BlockType) + : cMetaRotator<cBlockEntityHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) { } @@ -39,6 +39,21 @@ public: } return true; } + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override + { + // Bit 0x08 is a flag. Lowest three bits are position. 0x08 == 1000 + NIBBLETYPE OtherMeta = a_Meta & 0x08; + // Mirrors defined by by a table. (Source, mincraft.gamepedia.com) 0x07 == 0111 + switch (a_Meta & 0x07) + { + case 0x00: return 0x01 + OtherMeta; // Down -> Up + case 0x01: return 0x00 + OtherMeta; // Up -> Down + } + // Not Facing Up or Down; No change. + return a_Meta; + } } ; diff --git a/src/Blocks/BlockLadder.h b/src/Blocks/BlockLadder.h index a3e9edc6b..a605edf3f 100644 --- a/src/Blocks/BlockLadder.h +++ b/src/Blocks/BlockLadder.h @@ -9,11 +9,11 @@ class cBlockLadderHandler : - public cBlockHandler + public cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04> { public: cBlockLadderHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : cMetaRotator<cBlockHandler, 0x07, 0x02, 0x05, 0x03, 0x04>(a_BlockType) { } diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index a6d3373c1..495e849fa 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.h @@ -1,6 +1,6 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" #include "../World.h" #include "../BlockArea.h" @@ -16,6 +16,7 @@ { \ case E_BLOCK_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \ case E_BLOCK_LOG: return true; \ + case E_BLOCK_NEW_LEAVES: a_Area.SetBlockType(x, y, z, (BLOCKTYPE)(E_BLOCK_SPONGE + i + 1)); break; \ case E_BLOCK_NEW_LOG: return true; \ } @@ -37,16 +38,18 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - MTRand rand; + cFastRandom rand; // Only the first 2 bits contain the display information, the others are for growing - if (rand.randInt(5) == 0) + if (rand.NextInt(6) == 0) { a_Pickups.push_back(cItem(E_BLOCK_SAPLING, 1, a_BlockMeta & 3)); } - if ((a_BlockMeta & 3) == E_META_SAPLING_APPLE) + + // 1 % chance of dropping an apple, if the leaves' type is Apple Leaves + if ((a_BlockMeta & 3) == E_META_LEAVES_APPLE) { - if (rand.rand(100) == 0) + if (rand.NextInt(101) == 0) { a_Pickups.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); } @@ -58,11 +61,10 @@ public: { cBlockHandler::OnDestroyed(a_ChunkInterface, a_WorldInterface, a_BlockX, a_BlockY, a_BlockZ); - //0.5% chance of dropping an apple + // 0.5% chance of dropping an apple, if the leaves' type is Apple Leaves: NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - //check if Oak (0x1 and 0x2 bit not set) - MTRand rand; - if(!(Meta & 3) && rand.randInt(200) == 100) + cFastRandom rand; + if (((Meta & 3) == E_META_LEAVES_APPLE) && (rand.NextInt(201) == 100)) { cItems Drops; Drops.push_back(cItem(E_ITEM_RED_APPLE, 1, 0)); @@ -136,14 +138,14 @@ bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ) { // Filter the blocks into a {leaves, log, other (air)} set: BLOCKTYPE * Types = a_Area.GetBlockTypes(); - for (int i = a_Area.GetBlockCount() - 1; i > 0; i--) + for (size_t i = a_Area.GetBlockCount() - 1; i > 0; i--) { switch (Types[i]) { - case E_BLOCK_NEW_LEAVES: - case E_BLOCK_NEW_LOG: case E_BLOCK_LEAVES: case E_BLOCK_LOG: + case E_BLOCK_NEW_LEAVES: + case E_BLOCK_NEW_LOG: { break; } diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h index ef6e102cd..ad2ae29e5 100644 --- a/src/Blocks/BlockLever.h +++ b/src/Blocks/BlockLever.h @@ -1,17 +1,18 @@ #pragma once #include "BlockHandler.h" - +#include "MetaRotator.h" class cBlockLeverHandler : - public cBlockHandler + public cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false> { + typedef cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false> super; public: cBlockLeverHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : cMetaRotator<cBlockHandler, 0x07, 0x04, 0x02, 0x03, 0x01, false>(a_BlockType) { } @@ -104,6 +105,36 @@ public: return (a_RelY > 0) && cBlockInfo::IsSolid(BlockIsOn); } + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + switch (a_Meta) + { + case 0x00: return 0x07; // Ceiling rotation + case 0x07: return 0x00; + + case 0x05: return 0x06; // Ground rotation + case 0x06: return 0x05; + + default: return super::MetaRotateCCW(a_Meta); // Wall Rotation + } + } + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + switch (a_Meta) + { + case 0x00: return 0x07; // Ceiling rotation + case 0x07: return 0x00; + + case 0x05: return 0x06; // Ground rotation + case 0x06: return 0x05; + + default: return super::MetaRotateCCW(a_Meta); // Wall Rotation + } + } } ; diff --git a/src/Blocks/BlockLilypad.h b/src/Blocks/BlockLilypad.h new file mode 100644 index 000000000..2dd4ec768 --- /dev/null +++ b/src/Blocks/BlockLilypad.h @@ -0,0 +1,28 @@ + +#pragma once + +#include "BlockHandler.h" +#include "Entities/Pickup.h" + + + + +class cBlockLilypadHandler : + public cBlockHandler +{ +public: + cBlockLilypadHandler(BLOCKTYPE a_BlockType) + : cBlockHandler(a_BlockType) + { + } + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + // Reset meta to zero + a_Pickups.push_back(cItem(E_BLOCK_LILY_PAD, 1, 0)); + } +}; + + + + diff --git a/src/Blocks/BlockMobHead.h b/src/Blocks/BlockMobHead.h index 6aa01f986..b7629b07c 100644 --- a/src/Blocks/BlockMobHead.h +++ b/src/Blocks/BlockMobHead.h @@ -22,14 +22,127 @@ public: a_Pickups.push_back(cItem(E_ITEM_HEAD, 1, 0)); } - bool TrySpawnWither(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ) + bool TrySpawnWither(cChunkInterface & a_ChunkInterface, cWorld * a_World, int a_BlockX, int a_BlockY, int a_BlockZ) { if (a_BlockY < 2) { return false; } + + class cCallback : public cMobHeadCallback + { + bool m_IsWither; + + virtual bool Item (cMobHeadEntity * a_MobHeadEntity) + { + m_IsWither = (a_MobHeadEntity->GetType() == SKULL_TYPE_WITHER); + + return false; + } + + public: + cCallback () : m_IsWither(false) {} + + bool IsWither(void) const { return m_IsWither; } + + void Reset(void) { m_IsWither = false; } + + } CallbackA, CallbackB; + + class cPlayerCallback : public cPlayerListCallback + { + Vector3f m_Pos; + + virtual bool Item(cPlayer * a_Player) + { + // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one + double Dist = (a_Player->GetPosition() - m_Pos).Length(); + if (Dist < 50.0) + { + // If player is close, award achievement + a_Player->AwardAchievement(achSpawnWither); + } + return false; + } + + public: + cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {} + + } PlayerCallback(Vector3f(a_BlockX, a_BlockY, a_BlockZ)); + + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, CallbackA); + + if (!CallbackA.IsWither()) + { + return false; + } + + CallbackA.Reset(); + + BLOCKTYPE BlockY1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + BLOCKTYPE BlockY2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 2, a_BlockZ); + + if ((BlockY1 != E_BLOCK_SOULSAND) || (BlockY2 != E_BLOCK_SOULSAND)) + { + return false; + } + + a_World->DoWithMobHeadAt(a_BlockX - 1, a_BlockY, a_BlockZ, CallbackA); + a_World->DoWithMobHeadAt(a_BlockX + 1, a_BlockY, a_BlockZ, CallbackB); + + BLOCKTYPE Block1 = a_ChunkInterface.GetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ); + BLOCKTYPE Block2 = a_ChunkInterface.GetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ); + + if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither()) + { + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX + 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX - 1, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + + // Block entities + a_World->SetBlock(a_BlockX + 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX - 1, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + + // Spawn the wither: + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither); + + // Award Achievement + a_World->ForEachPlayer(PlayerCallback); + + return true; + } + + CallbackA.Reset(); + CallbackB.Reset(); - // TODO 2014-03-24 xdot + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ - 1, CallbackA); + a_World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ + 1, CallbackB); + + Block1 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1); + Block2 = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1); + + if ((Block1 == E_BLOCK_SOULSAND) && (Block2 == E_BLOCK_SOULSAND) && CallbackA.IsWither() && CallbackB.IsWither()) + { + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ + 1, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 1, a_BlockZ - 1, E_BLOCK_AIR, 0); + a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY - 2, a_BlockZ, E_BLOCK_AIR, 0); + + // Block entities + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ + 1, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ - 1, E_BLOCK_AIR, 0); + + // Spawn the wither: + a_World->SpawnMob(a_BlockX + 0.5, a_BlockY - 2, a_BlockZ + 0.5, cMonster::mtWither); + + // Award Achievement + a_World->ForEachPlayer(PlayerCallback); + + return true; + } return false; } @@ -62,20 +175,37 @@ public: } public: - cCallback (cPlayer * a_Player, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) : - m_Player(a_Player), + cCallback (cPlayer * a_CBPlayer, NIBBLETYPE a_OldBlockMeta, NIBBLETYPE a_NewBlockMeta) : + m_Player(a_CBPlayer), m_OldBlockMeta(a_OldBlockMeta), m_NewBlockMeta(a_NewBlockMeta) {} }; cCallback Callback(a_Player, a_BlockMeta, static_cast<NIBBLETYPE>(a_BlockFace)); - a_BlockMeta = a_BlockFace; + a_BlockMeta = (NIBBLETYPE)a_BlockFace; cWorld * World = (cWorld *) &a_WorldInterface; World->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, Callback); a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); - TrySpawnWither(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); + if (a_BlockMeta == SKULL_TYPE_WITHER) + { + static const Vector3i Coords[] = + { + Vector3i( 0, 0, 0), + Vector3i( 1, 0, 0), + Vector3i(-1, 0, 0), + Vector3i( 0, 0, 1), + Vector3i( 0, 0, -1), + }; + for (size_t i = 0; i < ARRAYCOUNT(Coords); ++i) + { + if (TrySpawnWither(a_ChunkInterface, World, a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z)) + { + break; + } + } // for i - Coords[] + } } } ; diff --git a/src/Blocks/BlockNetherWart.h b/src/Blocks/BlockNetherWart.h index 923180e19..812cf906f 100644 --- a/src/Blocks/BlockNetherWart.h +++ b/src/Blocks/BlockNetherWart.h @@ -2,14 +2,13 @@ #pragma once #include "BlockHandler.h" -#include "../MersenneTwister.h" +#include "../FastRandom.h" #include "../World.h" -/// Common class that takes care of carrots, potatoes and wheat class cBlockNetherWartHandler : public cBlockHandler { @@ -22,12 +21,12 @@ public: virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_Meta) override { - MTRand rand; + cFastRandom rand; if (a_Meta == 0x7) { - // Is fully grown, drop the entire produce: - a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, 1 + (int)(rand.randInt(2) + rand.randInt(2)) / 2, 0)); + // Fully grown, drop the entire produce: + a_Pickups.push_back(cItem(E_ITEM_NETHER_WART, (char)(1 + (rand.NextInt(3) + rand.NextInt(3))) / 2, 0)); } else { @@ -35,18 +34,20 @@ public: } } + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override { - NIBBLETYPE Meta = a_Chunk.GetMeta (a_RelX, a_RelY, a_RelZ); - + NIBBLETYPE Meta = a_Chunk.GetMeta(a_RelX, a_RelY, a_RelZ); if (Meta < 7) { a_Chunk.FastSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_NETHER_WART, ++Meta); } } + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { + // Needs to be placed on top of a Soulsand block: return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) == E_BLOCK_SOULSAND)); } } ; diff --git a/src/Blocks/BlockPluginInterface.h b/src/Blocks/BlockPluginInterface.h index 7428c9a7a..3a36c40b1 100644 --- a/src/Blocks/BlockPluginInterface.h +++ b/src/Blocks/BlockPluginInterface.h @@ -1,8 +1,14 @@ #pragma once +/** This interface is used to decouple block handlers from the cPluginManager dependancy through cWorld. +The block handlers call this interface, which is then implemented by the specific classes that +the caller provides. +*/ class cBlockPluginInterface { public: + virtual ~cBlockPluginInterface() {} + virtual bool CallHookBlockToPickups(cEntity * a_Digger, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, cItems & a_Pickups) = 0; }; diff --git a/src/Blocks/BlockPortal.h b/src/Blocks/BlockPortal.h index 21bcbdeea..3b8030028 100644 --- a/src/Blocks/BlockPortal.h +++ b/src/Blocks/BlockPortal.h @@ -2,6 +2,7 @@ #pragma once #include "BlockHandler.h" +#include "../Mobs/Monster.h" @@ -38,6 +39,19 @@ public: return; // No pickups } + virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override + { + cFastRandom Random; + if (Random.NextInt(2000) != 0) + { + return; + } + + int PosX = a_Chunk.GetPosX() * 16 + a_RelX; + int PosZ = a_Chunk.GetPosZ() * 16 + a_RelZ; + + a_WorldInterface.SpawnMob(PosX, a_RelY, PosZ, cMonster::mtZombiePigman); + } virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h index 349f52605..ac2b9817a 100644 --- a/src/Blocks/BlockPumpkin.h +++ b/src/Blocks/BlockPumpkin.h @@ -1,16 +1,16 @@ #pragma once #include "BlockHandler.h" - +#include "MetaRotator.h" class cBlockPumpkinHandler : - public cBlockHandler + public cMetaRotator<cBlockHandler, 0x07, 0x02, 0x03, 0x00, 0x01, false> { public: cBlockPumpkinHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : cMetaRotator<cBlockHandler, 0x07, 0x02, 0x03, 0x00, 0x01, false>(a_BlockType) { } diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index 07e9814cd..358b5ca11 100644 --- a/src/Blocks/BlockRail.h +++ b/src/Blocks/BlockRail.h @@ -141,7 +141,7 @@ public: NIBBLETYPE Meta = 0; char RailsCnt = 0; bool Neighbors[8]; // 0 - EAST, 1 - WEST, 2 - NORTH, 3 - SOUTH, 4 - EAST UP, 5 - WEST UP, 6 - NORTH UP, 7 - SOUTH UP - memset(Neighbors, false, sizeof(Neighbors)); + memset(Neighbors, 0, sizeof(Neighbors)); Neighbors[0] = (IsUnstable(a_ChunkInterface, a_BlockX + 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_EAST, E_PURE_DOWN)); Neighbors[1] = (IsUnstable(a_ChunkInterface, a_BlockX - 1, a_BlockY, a_BlockZ) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_WEST, E_PURE_DOWN)); Neighbors[2] = (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ - 1) || !IsNotConnected(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_NORTH, E_PURE_DOWN)); @@ -431,9 +431,145 @@ public: } break; } + default: break; } return true; } + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + // Bit 0x08 is a flag when a_Meta is in the range 0x00--0x05 and 0x0A--0x0F. + // Bit 0x08 specifies direction when a_Meta is in the range 0x06-0x09. + if ((a_Meta < 0x06) || (a_Meta > 0x09)) + { + // Save powered rail flag. + NIBBLETYPE OtherMeta = a_Meta & 0x08; + // Rotates according to table; 0x07 == 0111. + // Rails can either be flat (North/South) or Ascending (Asc. East) + switch (a_Meta & 0x07) + { + case 0x00: return 0x01 + OtherMeta; // North/South -> East/West + case 0x01: return 0x00 + OtherMeta; // East/West -> North/South + + case 0x02: return 0x04 + OtherMeta; // Asc. East -> Asc. North + case 0x04: return 0x03 + OtherMeta; // Asc. North -> Asc. West + case 0x03: return 0x05 + OtherMeta; // Asc. West -> Asc. South + case 0x05: return 0x02 + OtherMeta; // Asc. South -> Asc. East + } + } + else + { + switch (a_Meta) + { + // Corner Directions + case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr. + case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr. + case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr. + case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr. + } + } + // To avoid a compiler warning; + return a_Meta; + } + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09. + if ((a_Meta < 0x06) || (a_Meta > 0x09)) + { + // Save powered rail flag. + NIBBLETYPE OtherMeta = a_Meta & 0x08; + // Rotates according to table; 0x07 == 0111. + // Rails can either be flat (North/South) or Ascending (Asc. East) + switch (a_Meta & 0x07) + { + case 0x00: return 0x01 + OtherMeta; // North/South -> East/West + case 0x01: return 0x00 + OtherMeta; // East/West -> North/South + + case 0x02: return 0x05 + OtherMeta; // Asc. East -> Asc. South + case 0x05: return 0x03 + OtherMeta; // Asc. South -> Asc. West + case 0x03: return 0x04 + OtherMeta; // Asc. West -> Asc. North + case 0x04: return 0x02 + OtherMeta; // Asc. North -> Asc. East + } + } + else + { + switch (a_Meta) + { + // Corner Directions + case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr. + case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr. + case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr. + case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr. + } + } + // To avoid a compiler warning; + return a_Meta; + } + + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09. + if ((a_Meta < 0x06) || (a_Meta > 0x09)) + { + // Save powered rail flag. + NIBBLETYPE OtherMeta = a_Meta & 0x08; + // Mirrors according to table; 0x07 == 0111. + // Rails can either be flat (North/South) or Ascending (Asc. East) + switch (a_Meta & 0x07) + { + case 0x05: return 0x04 + OtherMeta; // Asc. South -> Asc. North + case 0x04: return 0x05 + OtherMeta; // Asc. North -> Asc. South + } + } + else + { + switch (a_Meta) + { + // Corner Directions + case 0x06: return 0x09; // Northwest Cnr. -> Southwest Cnr. + case 0x07: return 0x08; // Northeast Cnr. -> Southeast Cnr. + case 0x08: return 0x07; // Southeast Cnr. -> Northeast Cnr. + case 0x09: return 0x06; // Southwest Cnr. -> Northwest Cnr. + } + } + // To avoid a compiler warning; + return a_Meta; + } + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + // Bit 0x08 is a flag for value in the range 0x00--0x05 and specifies direction for values withint 0x006--0x09. + if ((a_Meta < 0x06) || (a_Meta > 0x09)) + { + // Save powered rail flag. + NIBBLETYPE OtherMeta = a_Meta & 0x08; + // Mirrors according to table; 0x07 == 0111. + // Rails can either be flat (North/South) or Ascending (Asc. East) + switch (a_Meta & 0x07) + { + case 0x02: return 0x03 + OtherMeta; // Asc. East -> Asc. West + case 0x03: return 0x02 + OtherMeta; // Asc. West -> Asc. East + } + } + else + { + switch (a_Meta) + { + // Corner Directions + case 0x06: return 0x07; // Northwest Cnr. -> Northeast Cnr. + case 0x07: return 0x06; // Northeast Cnr. -> Northwest Cnr. + case 0x08: return 0x09; // Southeast Cnr. -> Southwest Cnr. + case 0x09: return 0x08; // Southwest Cnr. -> Southeast Cnr. + } + } + // To avoid a compiler warning; + return a_Meta; + } } ; diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h index 1e2a86949..fe6cd21b9 100644 --- a/src/Blocks/BlockRedstoneRepeater.h +++ b/src/Blocks/BlockRedstoneRepeater.h @@ -3,17 +3,17 @@ #include "BlockHandler.h" #include "Chunk.h" - +#include "MetaRotator.h" class cBlockRedstoneRepeaterHandler : - public cBlockHandler + public cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true> { public: cBlockRedstoneRepeaterHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : cMetaRotator<cBlockHandler, 0x03, 0x00, 0x01, 0x02, 0x03, true>(a_BlockType) { } diff --git a/src/Blocks/BlockSign.h b/src/Blocks/BlockSign.h index cd0c02a40..9d6fede21 100644 --- a/src/Blocks/BlockSign.h +++ b/src/Blocks/BlockSign.h @@ -31,7 +31,7 @@ public: } - static char RotationToMetaData(double a_Rotation) + static NIBBLETYPE RotationToMetaData(double a_Rotation) { a_Rotation += 180 + (180 / 16); // So it's not aligned with axis if (a_Rotation > 360) @@ -45,7 +45,7 @@ public: } - static char DirectionToMetaData(eBlockFace a_Direction) + static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) { switch (a_Direction) { @@ -71,6 +71,37 @@ public: { a_Player->GetClientHandle()->SendEditSign(a_BlockX, a_BlockY, a_BlockZ); } + + + virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override + { + return (++a_Meta) & 0x0F; + } + + + virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override + { + return (--a_Meta) & 0x0F; + } + + virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override + { + // Mirrors signs over the XY plane (North-South Mirroring) + + // There are 16 meta values which correspond to different directions. + // These values are equated to angles on a circle; 0x08 = 180 degrees. + return (a_Meta < 0x08) ? 0x08 + a_Meta : 0x08 - a_Meta; + } + + + virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override + { + // Mirrors signs over the YZ plane (East-West Mirroring) + + // There are 16 meta values which correspond to different directions. + // These values are equated to angles on a circle; 0x10 = 360 degrees. + return 0x10 - a_Meta; + } } ; diff --git a/src/Blocks/BlockSlab.h b/src/Blocks/BlockSlab.h index 7cd2c97b2..80841b094 100644 --- a/src/Blocks/BlockSlab.h +++ b/src/Blocks/BlockSlab.h @@ -11,8 +11,7 @@ #include "BlockHandler.h" #include "../Items/ItemHandler.h" - - +#include "Root.h" @@ -40,41 +39,9 @@ public: ) override { a_BlockType = m_BlockType; - BLOCKTYPE Type = (BLOCKTYPE) (a_Player->GetEquippedItem().m_ItemType); NIBBLETYPE Meta = (NIBBLETYPE) a_Player->GetEquippedItem().m_ItemDamage; - // HandlePlaceBlock wants a cItemHandler pointer thing, so let's give it one - cItemHandler * ItemHandler = cItemHandler::GetItemHandler(GetDoubleSlabType(Type)); - - // Check if the block at the coordinates is a slab. Eligibility for combining has already been processed in ClientHandle - if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))) - { - // Call the function in ClientHandle that places a block when the client sends the packet, - // so that plugins may interfere with the placement. - - if ((a_BlockFace == BLOCK_FACE_TOP) || (a_BlockFace == BLOCK_FACE_BOTTOM)) - { - // Top and bottom faces need no parameter modification - a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); - } - else - { - // The other faces need to distinguish between top and bottom cursor positions - if (a_CursorY > 7) - { - // Edit the call to use BLOCK_FACE_BOTTOM, otherwise it places incorrectly - a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_TOP, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); - } - else - { - // Edit the call to use BLOCK_FACE_TOP, otherwise it places incorrectly - a_Player->GetClientHandle()->HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_BOTTOM, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); - } - } - return false; // Cancel the event, because dblslabs were already placed, nothing else needed - } - - // Place the single-slab with correct metas: + // Set the correct metadata based on player equipped item (i.e. a_BlockMeta not initialised yet) switch (a_BlockFace) { case BLOCK_FACE_TOP: @@ -105,7 +72,16 @@ public: a_BlockMeta = Meta & 0x7; break; } } + case BLOCK_FACE_NONE: return false; } // switch (a_BlockFace) + + // Check if the block at the coordinates is a single slab. Eligibility for combining has already been processed in ClientHandle + // Changed to-be-placed to a double slab if we are clicking on a single slab, as opposed to placing one for the first time + if (IsAnySlabType(a_ChunkInterface.GetBlock(a_BlockX, a_BlockY, a_BlockZ))) + { + a_BlockType = GetDoubleSlabType(m_BlockType); + } + return true; } @@ -121,6 +97,12 @@ public: return ""; } + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return ((a_Meta & 0x8) != 0); + } + /// Returns true if the specified blocktype is one of the slabs handled by this handler static bool IsAnySlabType(BLOCKTYPE a_BlockType) @@ -184,6 +166,15 @@ public: ASSERT(!"Unhandled double slab type!"); return ""; } + + + virtual NIBBLETYPE MetaMirrorXZ(NIBBLETYPE a_Meta) override + { + NIBBLETYPE OtherMeta = a_Meta & 0x07; // Contains unrelated meta data. + + // 8th bit is up/down. 1 right-side-up, 0 is up-side-down. + return (a_Meta & 0x08) ? 0x00 + OtherMeta : 0x01 + OtherMeta; + } } ; diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h index ea8405597..a49fda5ae 100644 --- a/src/Blocks/BlockStairs.h +++ b/src/Blocks/BlockStairs.h @@ -2,17 +2,17 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockStairsHandler : - public cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true> + public cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true> { public: cBlockStairsHandler(BLOCKTYPE a_BlockType) : - cMetaRotater<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType) + cMetaRotator<cBlockHandler, 0x03, 0x03, 0x00, 0x02, 0x01, true>(a_BlockType) { } @@ -30,9 +30,7 @@ public: UNUSED(a_BlockY); UNUSED(a_BlockZ); UNUSED(a_CursorX); - UNUSED(a_CursorY); UNUSED(a_CursorZ); - UNUSED(a_BlockMeta); a_BlockType = m_BlockType; a_BlockMeta = RotationToMetaData(a_Player->GetYaw()); switch (a_BlockFace) @@ -51,10 +49,12 @@ public: } break; } + case BLOCK_FACE_NONE: return false; } return true; } + virtual const char * GetStepSound(void) override { if ( @@ -77,6 +77,11 @@ public: // Reset meta to 0 a_Pickups.push_back(cItem(m_BlockType, 1, 0)); } + + virtual bool CanDirtGrowGrass(NIBBLETYPE a_Meta) override + { + return true; + } static NIBBLETYPE RotationToMetaData(double a_Rotation) { diff --git a/src/Blocks/BlockStems.h b/src/Blocks/BlockStems.h index 705436345..b726a0901 100644 --- a/src/Blocks/BlockStems.h +++ b/src/Blocks/BlockStems.h @@ -17,9 +17,10 @@ public: { } + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { - int ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; + short ItemType = (m_BlockType == E_BLOCK_MELON_STEM) ? E_ITEM_MELON_SEEDS : E_ITEM_PUMPKIN_SEEDS; a_Pickups.push_back(cItem(ItemType, 1, 0)); } diff --git a/src/Blocks/BlockTallGrass.h b/src/Blocks/BlockTallGrass.h index b8af1f1da..ba1f2e0f6 100644 --- a/src/Blocks/BlockTallGrass.h +++ b/src/Blocks/BlockTallGrass.h @@ -15,14 +15,14 @@ public: : cBlockHandler(a_BlockType) { } - - + + virtual bool DoesIgnoreBuildCollision(void) override { return true; } - - + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override { // Drop seeds, sometimes @@ -34,11 +34,25 @@ public: } + virtual void OnDestroyedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) override + { + NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + + if ((!a_Player->IsGameModeCreative()) && (a_Player->GetEquippedItem().m_ItemType == E_ITEM_SHEARS)) + { + cItems Pickups; + Pickups.Add(E_BLOCK_TALL_GRASS, 1, Meta); + a_WorldInterface.SpawnItemPickups(Pickups, a_BlockX, a_BlockY, a_BlockZ); + } + a_Player->UseEquippedItem(); + } + + virtual bool CanBeAt(cChunkInterface & a_ChunkInterface, int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override { return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); } - + virtual const char * GetStepSound(void) override { diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h index d32c77629..8ddec8de1 100644 --- a/src/Blocks/BlockTorch.h +++ b/src/Blocks/BlockTorch.h @@ -2,17 +2,17 @@ #include "BlockHandler.h" #include "../Chunk.h" -#include "MetaRotater.h" +#include "MetaRotator.h" class cBlockTorchHandler : - public cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2> + public cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2> { public: cBlockTorchHandler(BLOCKTYPE a_BlockType) - : cMetaRotater<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType) + : cMetaRotator<cBlockHandler, 0x7, 0x4, 0x1, 0x3, 0x2>(a_BlockType) { } diff --git a/src/Blocks/BlockTrapdoor.h b/src/Blocks/BlockTrapdoor.h index 9bae92c4d..6a36ab874 100644 --- a/src/Blocks/BlockTrapdoor.h +++ b/src/Blocks/BlockTrapdoor.h @@ -2,17 +2,17 @@ #pragma once #include "BlockHandler.h" - +#include "MetaRotator.h" class cBlockTrapdoorHandler : - public cBlockHandler + public cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false> { public: cBlockTrapdoorHandler(BLOCKTYPE a_BlockType) - : cBlockHandler(a_BlockType) + : cMetaRotator<cBlockHandler, 0x03, 0x01, 0x02, 0x00, 0x03, false>(a_BlockType) { } diff --git a/src/Blocks/BlockVine.h b/src/Blocks/BlockVine.h index d096c81a8..7bb9dc484 100644 --- a/src/Blocks/BlockVine.h +++ b/src/Blocks/BlockVine.h @@ -1,7 +1,7 @@ #pragma once #include "BlockHandler.h" -#include "MetaRotater.h" +#include "MetaRotator.h" @@ -83,7 +83,7 @@ public: static const struct { int x, z; - int Bit; + NIBBLETYPE Bit; } Coords[] = { { 0, 1, 1}, // south, ZP @@ -91,7 +91,7 @@ public: { 0, -1, 4}, // north, ZM { 1, 0, 8}, // east, XP } ; - int res = 0; + NIBBLETYPE res = 0; for (size_t i = 0; i < ARRAYCOUNT(Coords); i++) { BLOCKTYPE BlockType; @@ -197,14 +197,14 @@ public: virtual NIBBLETYPE MetaMirrorXY(NIBBLETYPE a_Meta) override { // Bits 2 and 4 stay, bits 1 and 3 swap - return ((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); + return (NIBBLETYPE)((a_Meta & 0x0a) | ((a_Meta & 0x01) << 2) | ((a_Meta & 0x04) >> 2)); } virtual NIBBLETYPE MetaMirrorYZ(NIBBLETYPE a_Meta) override { // Bits 1 and 3 stay, bits 2 and 4 swap - return ((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); + return (NIBBLETYPE)((a_Meta & 0x05) | ((a_Meta & 0x02) << 2) | ((a_Meta & 0x08) >> 2)); } } ; diff --git a/src/Blocks/CMakeLists.txt b/src/Blocks/CMakeLists.txt index 082ff41ac..4b8c745ad 100644 --- a/src/Blocks/CMakeLists.txt +++ b/src/Blocks/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Blocks ${SOURCE}) diff --git a/src/Blocks/MetaRotater.h b/src/Blocks/MetaRotator.h index dde88e6db..899c583e1 100644 --- a/src/Blocks/MetaRotater.h +++ b/src/Blocks/MetaRotator.h @@ -1,4 +1,4 @@ -// MetaRotater.h +// MetaRotator.h // Provides a mixin for rotations and reflections @@ -21,15 +21,15 @@ Inherit from this class providing your base class as Base, the BitMask for the d */ template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched = false> -class cMetaRotater : public Base +class cMetaRotator : public Base { public: - cMetaRotater(BLOCKTYPE a_BlockType) : + cMetaRotator(BLOCKTYPE a_BlockType) : Base(a_BlockType) {} - virtual ~cMetaRotater() {} + virtual ~cMetaRotator() {} virtual NIBBLETYPE MetaRotateCCW(NIBBLETYPE a_Meta) override; virtual NIBBLETYPE MetaRotateCW(NIBBLETYPE a_Meta) override; @@ -42,7 +42,7 @@ public: template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta) +NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCW(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); switch (a_Meta & BitMask) @@ -64,7 +64,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta) +NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaRotateCCW(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); switch (a_Meta & BitMask) @@ -86,7 +86,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta) +NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorXY(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); switch (a_Meta & BitMask) @@ -103,7 +103,7 @@ NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatc template<class Base, NIBBLETYPE BitMask, NIBBLETYPE North, NIBBLETYPE East, NIBBLETYPE South, NIBBLETYPE West, bool AssertIfNotMatched> -NIBBLETYPE cMetaRotater<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta) +NIBBLETYPE cMetaRotator<Base, BitMask, North, East, South, West, AssertIfNotMatched>::MetaMirrorYZ(NIBBLETYPE a_Meta) { NIBBLETYPE OtherMeta = a_Meta & (~BitMask); switch (a_Meta & BitMask) diff --git a/src/BoundingBox.cpp b/src/BoundingBox.cpp index 482f9923f..ce831c200 100644 --- a/src/BoundingBox.cpp +++ b/src/BoundingBox.cpp @@ -288,7 +288,7 @@ bool cBoundingBox::CalcLineIntersection(const Vector3d & a_Min, const Vector3d & Coeff = c; } c = a_Line1.LineCoeffToXZPlane(a_Line2, a_Max.y); - if ((c >= 0) && (c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) + if ((c >= 0) && (c < Coeff) && IsInside(a_Min, a_Max, a_Line1 + (a_Line2 - a_Line1) * c)) { Face = (a_Line1.y > a_Line2.y) ? BLOCK_FACE_YP : BLOCK_FACE_YM; Coeff = c; diff --git a/src/ByteBuffer.cpp b/src/ByteBuffer.cpp index 1893d89a8..4de89f7c1 100644 --- a/src/ByteBuffer.cpp +++ b/src/ByteBuffer.cpp @@ -143,7 +143,7 @@ protected: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cByteBuffer: -cByteBuffer::cByteBuffer(int a_BufferSize) : +cByteBuffer::cByteBuffer(size_t a_BufferSize) : m_Buffer(new char[a_BufferSize + 1]), m_BufferSize(a_BufferSize + 1), #ifdef _DEBUG @@ -171,7 +171,7 @@ cByteBuffer::~cByteBuffer() -bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count) +bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count) { CHECK_THREAD; CheckValid(); @@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count) } ASSERT(m_BufferSize >= m_WritePos); size_t TillEnd = m_BufferSize - m_WritePos; + const char * Bytes = (const char *)a_Bytes; if (TillEnd <= a_Count) { // Need to wrap around the ringbuffer end if (TillEnd > 0) { - memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd); - a_Bytes += TillEnd; + memcpy(m_Buffer + m_WritePos, Bytes, TillEnd); + Bytes += TillEnd; a_Count -= TillEnd; WrittenBytes = TillEnd; } @@ -203,7 +204,7 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count) // We're guaranteed that we'll fit in a single write op if (a_Count > 0) { - memcpy(m_Buffer + m_WritePos, a_Bytes, a_Count); + memcpy(m_Buffer + m_WritePos, Bytes, a_Count); m_WritePos += a_Count; WrittenBytes += a_Count; } @@ -326,7 +327,7 @@ bool cByteBuffer::ReadBEShort(short & a_Value) CheckValid(); NEEDBYTES(2); ReadBuf(&a_Value, 2); - a_Value = ntohs(a_Value); + a_Value = (short)ntohs((u_short)a_Value); return true; } @@ -340,7 +341,7 @@ bool cByteBuffer::ReadBEInt(int & a_Value) CheckValid(); NEEDBYTES(4); ReadBuf(&a_Value, 4); - a_Value = ntohl(a_Value); + a_Value = (int)ntohl((u_long)a_Value); return true; } @@ -419,7 +420,7 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value) ASSERT(!"Negative string length? Are you sure?"); return true; } - return ReadUTF16String(a_Value, Length); + return ReadUTF16String(a_Value, (size_t)Length); } @@ -437,7 +438,7 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value) { NEEDBYTES(1); ReadBuf(&b, 1); - Value = Value | (((Int64)(b & 0x7f)) << Shift); + Value = Value | (((UInt32)(b & 0x7f)) << Shift); Shift += 7; } while ((b & 0x80) != 0); a_Value = Value; @@ -461,7 +462,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value) { LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024); } - return ReadString(a_Value, (int)Size); + return ReadString(a_Value, (size_t)Size); } @@ -516,7 +517,7 @@ bool cByteBuffer::WriteBEShort(short a_Value) CHECK_THREAD; CheckValid(); PUTBYTES(2); - short Converted = htons(a_Value); + u_short Converted = htons((u_short)a_Value); return WriteBuf(&Converted, 2); } @@ -529,7 +530,7 @@ bool cByteBuffer::WriteBEInt(int a_Value) CHECK_THREAD; CheckValid(); PUTBYTES(4); - int Converted = HostToNetwork4(&a_Value); + UInt32 Converted = HostToNetwork4(&a_Value); return WriteBuf(&Converted, 4); } @@ -542,7 +543,7 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value) CHECK_THREAD; CheckValid(); PUTBYTES(8); - Int64 Converted = HostToNetwork8(&a_Value); + UInt64 Converted = HostToNetwork8(&a_Value); return WriteBuf(&Converted, 8); } @@ -555,7 +556,7 @@ bool cByteBuffer::WriteBEFloat(float a_Value) CHECK_THREAD; CheckValid(); PUTBYTES(4); - int Converted = HostToNetwork4(&a_Value); + UInt32 Converted = HostToNetwork4(&a_Value); return WriteBuf(&Converted, 4); } @@ -568,7 +569,7 @@ bool cByteBuffer::WriteBEDouble(double a_Value) CHECK_THREAD; CheckValid(); PUTBYTES(8); - Int64 Converted = HostToNetwork8(&a_Value); + UInt64 Converted = HostToNetwork8(&a_Value); return WriteBuf(&Converted, 8); } @@ -612,7 +613,7 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value) // A 32-bit integer can be encoded by at most 5 bytes: unsigned char b[5]; - int idx = 0; + size_t idx = 0; do { b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); @@ -631,7 +632,7 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) CHECK_THREAD; CheckValid(); PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early. - bool res = WriteVarInt(a_Value.size()); + bool res = WriteVarInt((UInt32)(a_Value.size())); if (!res) { return false; @@ -756,7 +757,7 @@ bool cByteBuffer::ReadString(AString & a_String, size_t a_Count) -bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars) +bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars) { // Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String CHECK_THREAD; @@ -887,9 +888,7 @@ void cByteBuffer::AdvanceReadPos(size_t a_Count) void cByteBuffer::CheckValid(void) const { - ASSERT(m_ReadPos >= 0); ASSERT(m_ReadPos < m_BufferSize); - ASSERT(m_WritePos >= 0); ASSERT(m_WritePos < m_BufferSize); } diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 1915467f3..adaa00330 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -27,28 +27,28 @@ their own synchronization. class cByteBuffer { public: - cByteBuffer(int a_BufferSize); + cByteBuffer(size_t a_BufferSize); ~cByteBuffer(); - /// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not - bool Write(const char * a_Bytes, size_t a_Count); + /** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */ + bool Write(const void * a_Bytes, size_t a_Count); - /// Returns the number of bytes that can be successfully written to the ringbuffer + /** Returns the number of bytes that can be successfully written to the ringbuffer */ size_t GetFreeSpace(void) const; - /// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() + /** Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() */ size_t GetUsedSpace(void) const; - /// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) + /** Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) */ size_t GetReadableSpace(void) const; - /// Returns the current data start index. For debugging purposes. + /** Returns the current data start index. For debugging purposes. */ size_t GetDataStart(void) const { return m_DataStart; } - /// Returns true if the specified amount of bytes are available for reading + /** Returns true if the specified amount of bytes are available for reading */ bool CanReadBytes(size_t a_Count) const; - /// Returns true if the specified amount of bytes are available for writing + /** Returns true if the specified amount of bytes are available for writing */ bool CanWriteBytes(size_t a_Count) const; // Read the specified datatype and advance the read pointer; return true if successfully read: @@ -65,7 +65,7 @@ public: bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8 bool ReadLEInt (int & a_Value); - /// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) + /** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */ template <typename T> bool ReadVarInt(T & a_Value) { UInt32 v; @@ -91,37 +91,37 @@ public: bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 bool WriteLEInt (int a_Value); - /// Reads a_Count bytes into a_Buffer; returns true if successful + /** Reads a_Count bytes into a_Buffer; returns true if successful */ bool ReadBuf(void * a_Buffer, size_t a_Count); - /// Writes a_Count bytes into a_Buffer; returns true if successful + /** Writes a_Count bytes into a_Buffer; returns true if successful */ bool WriteBuf(const void * a_Buffer, size_t a_Count); - /// Reads a_Count bytes into a_String; returns true if successful + /** Reads a_Count bytes into a_String; returns true if successful */ bool ReadString(AString & a_String, size_t a_Count); - /// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String - bool ReadUTF16String(AString & a_String, int a_NumChars); + /** Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String */ + bool ReadUTF16String(AString & a_String, size_t a_NumChars); - /// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer + /** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */ bool SkipRead(size_t a_Count); - /// Reads all available data into a_Data + /** Reads all available data into a_Data */ void ReadAll(AString & a_Data); - /// Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. + /** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */ bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes); - /// Removes the bytes that have been read from the ringbuffer + /** Removes the bytes that have been read from the ringbuffer */ void CommitRead(void); - /// Restarts next reading operation at the start of the ringbuffer + /** Restarts next reading operation at the start of the ringbuffer */ void ResetRead(void); - /// Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication + /** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */ void ReadAgain(AString & a_Out); - /// Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs + /** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */ void CheckValid(void) const; protected: @@ -136,7 +136,7 @@ protected: size_t m_WritePos; // Where the data ends in the ringbuffer size_t m_ReadPos; // Where the next read will start in the ringbuffer - /// Advances the m_ReadPos by a_Count bytes + /** Advances the m_ReadPos by a_Count bytes */ void AdvanceReadPos(size_t a_Count); } ; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 448dc4b70..900577526 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,15 +5,15 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/") include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include") include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include") -set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating) -set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities) +set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++) +set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs) if (NOT MSVC) - #Bindings needs to reference other folders so are done here + # Bindings need to reference other folders, so they are done here instead - #lib dependecies are not included + # lib dependencies are not included set(BINDING_DEPENDECIES tolua @@ -57,6 +57,14 @@ if (NOT MSVC) Entities/Pickup.h Entities/Player.h Entities/ProjectileEntity.h + Entities/ArrowEntity.h + Entities/ThrownEggEntity.h + Entities/ThrownEnderPearlEntity.h + Entities/ExpBottleEntity.h + Entities/ThrownSnowballEntity.h + Entities/FireChargeEntity.h + Entities/FireworkEntity.h + Entities/GhastFireballEntity.h Entities/TNTEntity.h Entities/ExpOrb.h Entities/HangingEntity.h @@ -104,7 +112,6 @@ if (NOT MSVC) Bindings/PluginLua Bindings/PluginManager Bindings/WebPlugin - Bindings/WebPlugin ) target_link_libraries(Bindings lua sqlite tolualib) @@ -124,6 +131,7 @@ if (NOT MSVC) file(GLOB SOURCE "*.cpp" + "*.h" ) list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp") @@ -138,6 +146,7 @@ if (NOT MSVC) else () + # MSVC-specific handling: Put all files into one project, separate by the folders: # Generate the Bindings if they don't exist: if (NOT EXISTS "${PROJECT_SOURCE_DIR}/Bindings/Bindings.cpp") @@ -149,6 +158,14 @@ else () ) endif() + # Get all files in this folder: + file(GLOB_RECURSE SOURCE + "*.cpp" + "*.h" + "*.pkg" + ) + source_group("" FILES ${SOURCE}) + # Add all subfolders as solution-folders: list(APPEND FOLDERS "Resources") list(APPEND FOLDERS "Bindings") @@ -159,23 +176,16 @@ else () "${PATH}/*.rc" "${PATH}/*.pkg" ) - source_group("${PATH}" FILES ${FOLDER_FILES}) + string(REPLACE "/" "\\" PROJECT_PATH ${PATH}) + source_group("${PROJECT_PATH}" FILES ${FOLDER_FILES}) endfunction(includefolder) foreach(folder ${FOLDERS}) includefolder(${folder}) endforeach(folder) - file(GLOB_RECURSE SOURCE - "*.cpp" - "*.h" - "*.pkg" - ) - include_directories("${PROJECT_SOURCE_DIR}") - source_group("" FILES ${SOURCE}) - # Precompiled headers (1st part) SET_SOURCE_FILES_PROPERTIES( Globals.cpp PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\"" @@ -231,8 +241,8 @@ endif () if (NOT MSVC) target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks) - target_link_libraries(${EXECUTABLE} Protocol Generating WorldStorage) - target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities) + target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage) + target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities PolarSSL++) endif () if (WIN32) target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib) diff --git a/src/Chunk.cpp b/src/Chunk.cpp index bd4cb9937..23412a4c3 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -238,13 +238,12 @@ 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); + a_Callback.HeightMap(&m_HeightMap); + a_Callback.BiomeData(&m_BiomeMap); + + a_Callback.LightIsValid(m_IsLightValid); + + a_Callback.ChunkData(m_ChunkData); for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { @@ -262,7 +261,7 @@ void cChunk::GetAllData(cChunkDataCallback & a_Callback) void cChunk::SetAllData( - const BLOCKTYPE * a_BlockTypes, + const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, const NIBBLETYPE * a_BlockSkyLight, @@ -272,29 +271,23 @@ void cChunk::SetAllData( ) { 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)); - if (a_BlockLight != NULL) - { - memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); - } - if (a_BlockSkyLight != NULL) + + if (a_HeightMap == NULL) { - memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight)); + CalculateHeightmap(a_BlockTypes); } + + m_ChunkData.SetBlockTypes(a_BlockTypes); + m_ChunkData.SetMetas(a_BlockMeta); + m_ChunkData.SetBlockLight(a_BlockLight); + m_ChunkData.SetSkyLight(a_BlockSkyLight); m_IsLightValid = (a_BlockLight != NULL) && (a_BlockSkyLight != NULL); - - if (a_HeightMap == NULL) - { - CalculateHeightmap(); - } // Clear the block entities present - either the loader / saver has better, or we'll create empty ones: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(); itr != m_BlockEntities.end(); ++itr) @@ -332,8 +325,11 @@ void cChunk::SetLight( { // 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_ChunkData.SetBlockLight(a_BlockLight); + + m_ChunkData.SetSkyLight(a_SkyLight); + m_IsLightValid = true; } @@ -343,7 +339,7 @@ void cChunk::SetLight( void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes) { - memcpy(a_BlockTypes, m_BlockTypes, NumBlocks); + m_ChunkData.CopyBlockTypes(a_BlockTypes); } @@ -452,7 +448,7 @@ void cChunk::CollectMobCensus(cMobCensus& toFill) { cMonster& Monster = (cMonster&)(**itr); currentPosition = Monster.GetPosition(); - for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++) + for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); ++itr2) { toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength()); } @@ -600,7 +596,7 @@ void cChunk::Tick(float a_Dt) delete ToDelete; continue; } - itr++; + ++itr; } // for itr - m_Entitites[] // If any entity moved out of the chunk, move it to the neighbor: @@ -629,8 +625,7 @@ void cChunk::Tick(float a_Dt) void cChunk::TickBlock(int a_RelX, int a_RelY, int a_RelZ) { - unsigned Index = MakeIndex(a_RelX, a_RelY, a_RelZ); - cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(a_RelX, a_RelY, a_RelZ)); ASSERT(Handler != NULL); // Happenned on server restart, FS #243 cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); @@ -694,7 +689,7 @@ void cChunk::ProcessQueuedSetBlocks(void) { if (itr->m_Tick <= CurrTick) { - if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to -1 if not specified + if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to 0 if not specified { if (GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == itr->m_PreviousType) { @@ -751,23 +746,22 @@ void cChunk::BroadcastPendingBlockChanges(void) void cChunk::CheckBlocks() { - if (m_ToTickBlocks.size() == 0) + if (m_ToTickBlocks.empty()) { return; } - std::vector<unsigned int> ToTickBlocks; + std::vector<Vector3i> ToTickBlocks; std::swap(m_ToTickBlocks, ToTickBlocks); cChunkInterface ChunkInterface(m_World->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*m_World); - for (std::vector<unsigned int>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr) + for (std::vector<Vector3i>::const_iterator itr = ToTickBlocks.begin(), end = ToTickBlocks.end(); itr != end; ++itr) { - unsigned int index = (*itr); - Vector3i BlockPos = IndexToCoordinate(index); + Vector3i Pos = (*itr); - cBlockHandler * Handler = BlockHandler(GetBlock(index)); - Handler->Check(ChunkInterface, PluginInterface, BlockPos.x, BlockPos.y, BlockPos.z, *this); + cBlockHandler * Handler = BlockHandler(GetBlock(Pos)); + Handler->Check(ChunkInterface, PluginInterface, Pos.x, Pos.y, Pos.z, *this); } // for itr - ToTickBlocks[] } @@ -810,8 +804,7 @@ void cChunk::TickBlocks(void) continue; // It's all air up here } - unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ); - cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(m_BlockTickX, m_BlockTickY, m_BlockTickZ)); ASSERT(Handler != NULL); // Happenned on server restart, FS #243 Handler->OnUpdate(ChunkInterface, *this->GetWorld(), PluginInterface, *this, m_BlockTickX, m_BlockTickY, m_BlockTickZ); } // for i - tickblocks @@ -884,7 +877,7 @@ void cChunk::ApplyWeatherToTop() FastSetBlock(X, Height, Z, E_BLOCK_SNOW, TopMeta - 1); } } - else if (cBlockInfo::IsSnowable(TopBlock)) + else if (cBlockInfo::IsSnowable(TopBlock) && (Height + 1 < cChunkDef::Height)) { SetBlock(X, Height + 1, Z, E_BLOCK_SNOW, 0); } @@ -1203,9 +1196,8 @@ bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBB // The chunk is not available, bail out return false; } - int idx = Chunk->MakeIndex(a_RelX, a_RelY, a_RelZ); - a_BlockLight = Chunk->GetBlockLight(idx); - a_SkyLight = Chunk->GetSkyLight(idx); + a_BlockLight = Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ); + a_SkyLight = Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ); return true; } @@ -1296,9 +1288,10 @@ void cChunk::CreateBlockEntities(void) { for (int y = 0; y < Height; y++) { - BLOCKTYPE BlockType = cChunkDef::GetBlock(m_BlockTypes, x, y, z); + BLOCKTYPE BlockType = GetBlock(x, y, z); switch (BlockType) { + case E_BLOCK_BEACON: case E_BLOCK_CHEST: case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: @@ -1348,7 +1341,7 @@ void cChunk::WakeUpSimulators(void) int BlockZ = z + BaseZ; for (int y = GetHeight(x, z); y >= 0; y--) { - BLOCKTYPE Block = cChunkDef::GetBlock(m_BlockTypes, x, y, z); + BLOCKTYPE Block = GetBlock(x, y, z); // The redstone sim takes multiple blocks, use the inbuilt checker if (RedstoneSimulator->IsAllowedBlock(Block)) @@ -1383,7 +1376,7 @@ void cChunk::WakeUpSimulators(void) -void cChunk::CalculateHeightmap() +void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) { for (int x = 0; x < Width; x++) { @@ -1392,7 +1385,7 @@ void cChunk::CalculateHeightmap() for (int y = Height - 1; y > -1; y--) { int index = MakeIndex( x, y, z ); - if (m_BlockTypes[index] != E_BLOCK_AIR) + if (a_BlockTypes[index] != E_BLOCK_AIR) { m_HeightMap[x + z * Width] = (unsigned char)y; break; @@ -1409,11 +1402,9 @@ void cChunk::CalculateHeightmap() void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - - const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); // Tick this block and its neighbors: - m_ToTickBlocks.push_back(index); + m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ)); QueueTickBlockNeighbors(a_RelX, a_RelY, a_RelZ); // If there was a block entity, remove it: @@ -1429,6 +1420,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, // If the new block is a block entity, create the entity object: switch (a_BlockType) { + case E_BLOCK_BEACON: case E_BLOCK_CHEST: case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_DISPENSER: @@ -1476,7 +1468,7 @@ void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) return; } - m_ToTickBlocks.push_back(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)); + m_ToTickBlocks.push_back(Vector3i(a_RelX, a_RelY, a_RelZ)); } @@ -1514,17 +1506,16 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT ASSERT(IsValid()); - const int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - const BLOCKTYPE OldBlockType = cChunkDef::GetBlock(m_BlockTypes, index); - const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index); + const BLOCKTYPE OldBlockType = GetBlock(a_RelX, a_RelY, a_RelZ); + const BLOCKTYPE OldBlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) { return; } MarkDirty(); - - m_BlockTypes[index] = a_BlockType; + + m_ChunkData.SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType); // The client doesn't need to distinguish between stationary and nonstationary fluids: if ( @@ -1540,7 +1531,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta)); } - SetNibble(m_BlockMeta, index, a_BlockMeta); + m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_BlockMeta); // ONLY recalculate lighting if it's necessary! if ( @@ -1563,7 +1554,7 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT { for (int y = a_RelY - 1; y > 0; --y) { - if (m_BlockTypes[MakeIndexNoCheck(a_RelX, y, a_RelZ)] != E_BLOCK_AIR) + if (GetBlock(a_RelX, y, a_RelZ) != E_BLOCK_AIR) { m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y; break; @@ -1579,19 +1570,16 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT void cChunk::SendBlockTo(int a_RelX, int a_RelY, int a_RelZ, cClientHandle * a_Client) { - // The coords must be valid, because the upper level already does chunk lookup. No need to check them again. - // There's an debug-time assert in MakeIndexNoCheck anyway - unsigned int index = MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); if (a_Client == NULL) { // Queue the block for all clients in the chunk (will be sent in Tick()) - m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(index), GetMeta(index))); + m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ))); return; } Vector3i wp = PositionToWorldPosition(a_RelX, a_RelY, a_RelZ); - a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(index), GetMeta(index)); + a_Client->SendBlockChange(wp.x, wp.y, wp.z, GetBlock(a_RelX, a_RelY, a_RelZ), GetMeta(a_RelX, a_RelY, a_RelZ)); // FS #268 - if a BlockEntity digging is cancelled by a plugin, the entire block entity must be re-sent to the client: for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), end = m_BlockEntities.end(); itr != end; ++itr) @@ -2450,22 +2438,7 @@ BLOCKTYPE cChunk::GetBlock(int a_RelX, int a_RelY, int a_RelZ) const return 0; // Clip } - return m_BlockTypes[MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)]; -} - - - - - -BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const -{ - if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks)) - { - ASSERT(!"GetBlock(idx) out of bounds!"); - return 0; - } - - return m_BlockTypes[ a_BlockIdx ]; + return m_ChunkData.GetBlock(a_RelX, a_RelY, a_RelZ); } @@ -2474,9 +2447,8 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) { - int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx); - a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx); + a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ); + a_BlockMeta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); } @@ -2485,11 +2457,10 @@ void cChunk::GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_ void cChunk::GetBlockInfo(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight) { - int Idx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = cChunkDef::GetBlock (m_BlockTypes, Idx); - a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx); - a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx); - a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx); + a_BlockType = GetBlock(a_RelX, a_RelY, a_RelZ); + a_Meta = m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); + a_SkyLight = m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ); + a_BlockLight = m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ); } @@ -2511,7 +2482,7 @@ cChunk * cChunk::GetNeighborChunk(int a_BlockX, int a_BlockZ) cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) { // If the relative coords are too far away, use the parent's chunk lookup instead: - if ((a_RelX < 128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128)) + if ((a_RelX < -128) || (a_RelX > 128) || (a_RelZ < -128) || (a_RelZ > 128)) { int BlockX = m_PosX * cChunkDef::Width + a_RelX; int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ; diff --git a/src/Chunk.h b/src/Chunk.h index b3fa563cc..d95537acf 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -3,6 +3,7 @@ #include "Entities/Entity.h" #include "ChunkDef.h" +#include "ChunkData.h" #include "Simulator/FireSimulator.h" #include "Simulator/SandSimulator.h" @@ -66,6 +67,7 @@ public: cChunkMap * a_ChunkMap, cWorld * a_World, // Parent objects cChunk * a_NeighborXM, cChunk * a_NeighborXP, cChunk * a_NeighborZM, cChunk * a_NeighborZP // Neighbor chunks ); + cChunk(cChunk & other); ~cChunk(); bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk block data is valid (loaded / generated) @@ -154,7 +156,7 @@ public: void FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc. BLOCKTYPE GetBlock(int a_RelX, int a_RelY, int a_RelZ) const; - BLOCKTYPE GetBlock(int a_BlockIdx) const; + BLOCKTYPE GetBlock(Vector3i a_cords) const { return GetBlock(a_cords.x, a_cords.y, a_cords.z);} void GetBlockTypeMeta(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta); void GetBlockInfo (int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight); @@ -267,7 +269,7 @@ public: void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); // [x, y, z] in world block coords void CalculateLighting(); // Recalculate right now - void CalculateHeightmap(); + void CalculateHeightmap(const BLOCKTYPE * a_BlockTypes); // Broadcast various packets to all clients of this chunk: // (Please keep these alpha-sorted) @@ -320,15 +322,23 @@ public: m_BlockTickZ = a_RelZ; } - inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ); } - inline NIBBLETYPE GetMeta(int a_BlockIdx) const {return cChunkDef::GetNibble(m_BlockMeta, a_BlockIdx); } - inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_RelX, a_RelY, a_RelZ, a_Meta); } - inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, a_Meta); } + inline NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const + { + return m_ChunkData.GetMeta(a_RelX, a_RelY, a_RelZ); + } + inline void SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Meta) + { + bool hasChanged = m_ChunkData.SetMeta(a_RelX, a_RelY, a_RelZ, a_Meta); + if (hasChanged) + { + MarkDirty(); + + m_PendingSendBlocks.push_back(sSetBlock(m_PosX, m_PosZ, a_RelX, a_RelY, a_RelZ, GetBlock(a_RelX, a_RelY, a_RelZ), a_Meta)); + } + } - inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); } - inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); } - inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); } - inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx); } + inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetBlockLight(a_RelX, a_RelY, a_RelZ); } + inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return m_ChunkData.GetSkyLight(a_RelX, a_RelY, a_RelZ); } /** Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success */ bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; @@ -382,14 +392,14 @@ private: struct sSetBlockQueueItem { + Int64 m_Tick; int m_RelX, m_RelY, m_RelZ; BLOCKTYPE m_BlockType; NIBBLETYPE m_BlockMeta; - Int64 m_Tick; BLOCKTYPE m_PreviousType; sSetBlockQueueItem(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType) : - m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_Tick(a_Tick), m_PreviousType(a_PreviousBlockType) + m_Tick(a_Tick), m_RelX(a_RelX), m_RelY(a_RelY), m_RelZ(a_RelZ), m_BlockType(a_BlockType), m_BlockMeta(a_BlockMeta), m_PreviousType(a_PreviousBlockType) { } } ; @@ -403,8 +413,8 @@ private: bool m_IsSaving; // True if the chunk is being saved bool m_HasLoadFailed; // True if chunk failed to load and hasn't been generated yet since then - std::vector<unsigned int> m_ToTickBlocks; - sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients + std::vector<Vector3i> m_ToTickBlocks; + sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick @@ -420,11 +430,7 @@ private: cWorld * m_World; cChunkMap * m_ChunkMap; - // TODO: Make these pointers and don't allocate what isn't needed - BLOCKTYPE m_BlockTypes [cChunkDef::NumBlocks]; - NIBBLETYPE m_BlockMeta [cChunkDef::NumBlocks / 2]; - NIBBLETYPE m_BlockLight [cChunkDef::NumBlocks / 2]; - NIBBLETYPE m_BlockSkyLight[cChunkDef::NumBlocks / 2]; + cChunkData m_ChunkData; cChunkDef::HeightMap m_HeightMap; cChunkDef::BiomeMap m_BiomeMap; diff --git a/src/ChunkData.cpp b/src/ChunkData.cpp new file mode 100644 index 000000000..142c141c4 --- /dev/null +++ b/src/ChunkData.cpp @@ -0,0 +1,592 @@ + +// ChunkData.cpp + +// Implements the cChunkData class that represents the block's type, meta, blocklight and skylight storage for a chunk + +#include "Globals.h" +#include "ChunkData.h" + + + + + +/** Returns true if all a_Array's elements between [0] and [a_NumElements - 1] are equal to a_Value. */ +template <typename T> inline bool IsAllValue(const T * a_Array, size_t a_NumElements, T a_Value) +{ + for (size_t i = 0; i < a_NumElements; i++) + { + if (a_Array[i] != a_Value) + { + return false; + } + } + return true; +} + + + + + +cChunkData::cChunkData(void) +#if __cplusplus < 201103L + // auto_ptr style interface for memory management + : m_IsOwner(true) +#endif +{ + for (size_t i = 0; i < NumSections; i++) + { + m_Sections[i] = NULL; + } +} + + + + + +cChunkData::~cChunkData() +{ + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + if (!m_IsOwner) + { + return; + } + #endif + for (size_t i = 0; i < NumSections; i++) + { + Free(m_Sections[i]); + m_Sections[i] = NULL; + } +} + + + + + +#if __cplusplus < 201103L + // auto_ptr style interface for memory management + cChunkData::cChunkData(const cChunkData & a_Other) : + m_IsOwner(true) + { + // Move contents and ownership from a_Other to this, pointer-wise: + for (size_t i = 0; i < NumSections; i++) + { + m_Sections[i] = a_Other.m_Sections[i]; + } + a_Other.m_IsOwner = false; + } + + + + + + cChunkData & cChunkData::operator =(const cChunkData & a_Other) + { + // If assigning to self, no-op + if (&a_Other == this) + { + return *this; + } + + // Free any currently held contents: + if (m_IsOwner) + { + for (size_t i = 0; i < NumSections; i++) + { + Free(m_Sections[i]); + m_Sections[i] = NULL; + } + } + + // Move contents and ownership from a_Other to this, pointer-wise: + m_IsOwner = true; + for (size_t i = 0; i < NumSections; i++) + { + m_Sections[i] = a_Other.m_Sections[i]; + } + a_Other.m_IsOwner = false; + return *this; + } + +#else + + // unique_ptr style interface for memory management + cChunkData::cChunkData(cChunkData && other) + { + for (size_t i = 0; i < NumSections; i++) + { + m_Sections[i] = other.m_Sections[i]; + other.m_Sections[i] = NULL; + } + } + + + + + + cChunkData & cChunkData::operator =(cChunkData && other) + { + if (&other != this) + { + for (size_t i = 0; i < NumSections; i++) + { + Free(m_Sections[i]); + m_Sections[i] = other.m_Sections[i]; + other.m_Sections[i] = NULL; + } + } + return *this; + } +#endif + + + + + +BLOCKTYPE cChunkData::GetBlock(int a_X, int a_Y, int a_Z) const +{ + ASSERT((a_X >= 0) && (a_X < cChunkDef::Width)); + ASSERT((a_Y >= 0) && (a_Y < cChunkDef::Height)); + ASSERT((a_Z >= 0) && (a_Z < cChunkDef::Width)); + int Section = a_Y / SectionHeight; + if (m_Sections[Section] != NULL) + { + int Index = cChunkDef::MakeIndexNoCheck(a_X, a_Y - (Section * SectionHeight), a_Z); + return m_Sections[Section]->m_BlockTypes[Index]; + } + else + { + return 0; + } +} + + + + + +void cChunkData::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block) +{ + if ( + (a_RelX >= cChunkDef::Width) || (a_RelX < 0) || + (a_RelY >= cChunkDef::Height) || (a_RelY < 0) || + (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0) + ) + { + ASSERT(!"cChunkData::SetMeta(): index out of range!"); + return; + } + + int Section = a_RelY / SectionHeight; + if (m_Sections[Section] == NULL) + { + if (a_Block == 0x00) + { + return; + } + m_Sections[Section] = Allocate(); + if (m_Sections[Section] == NULL) + { + ASSERT(!"Failed to allocate a new section in Chunkbuffer"); + return; + } + ZeroSection(m_Sections[Section]); + } + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); + m_Sections[Section]->m_BlockTypes[Index] = a_Block; +} + + + + + +NIBBLETYPE cChunkData::GetMeta(int a_RelX, int a_RelY, int a_RelZ) const +{ + if ( + (a_RelX < cChunkDef::Width) && (a_RelX > -1) && + (a_RelY < cChunkDef::Height) && (a_RelY > -1) && + (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) + { + int Section = a_RelY / SectionHeight; + if (m_Sections[Section] != NULL) + { + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); + return (m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + } + else + { + return 0; + } + } + ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!"); + return 0; +} + + + + + +bool cChunkData::SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble) +{ + if ( + (a_RelX >= cChunkDef::Width) || (a_RelX < 0) || + (a_RelY >= cChunkDef::Height) || (a_RelY < 0) || + (a_RelZ >= cChunkDef::Width) || (a_RelZ < 0) + ) + { + ASSERT(!"cChunkData::SetMeta(): index out of range!"); + return false; + } + + int Section = a_RelY / SectionHeight; + if (m_Sections[Section] == NULL) + { + if ((a_Nibble & 0xf) == 0x00) + { + return false; + } + m_Sections[Section] = Allocate(); + if (m_Sections[Section] == NULL) + { + ASSERT(!"Failed to allocate a new section in Chunkbuffer"); + return false; + } + ZeroSection(m_Sections[Section]); + } + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); + NIBBLETYPE oldval = m_Sections[Section]->m_BlockMetas[Index / 2] >> ((Index & 1) * 4) & 0xf; + m_Sections[Section]->m_BlockMetas[Index / 2] = static_cast<NIBBLETYPE>( + (m_Sections[Section]->m_BlockMetas[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set + ); + return oldval == a_Nibble; +} + + + + + +NIBBLETYPE cChunkData::GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const +{ + if ( + (a_RelX < cChunkDef::Width) && (a_RelX > -1) && + (a_RelY < cChunkDef::Height) && (a_RelY > -1) && + (a_RelZ < cChunkDef::Width) && (a_RelZ > -1) + ) + { + int Section = a_RelY / SectionHeight; + if (m_Sections[Section] != NULL) + { + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); + return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + } + else + { + return 0; + } + } + ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!"); + return 0; +} + + + + + +NIBBLETYPE cChunkData::GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const +{ + if ((a_RelX < cChunkDef::Width) && (a_RelX > -1) && (a_RelY < cChunkDef::Height) && (a_RelY > -1) && (a_RelZ < cChunkDef::Width) && (a_RelZ > -1)) + { + int Section = a_RelY / SectionHeight; + if (m_Sections[Section] != NULL) + { + int Index = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY - (Section * SectionHeight), a_RelZ); + return (m_Sections[Section]->m_BlockLight[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + } + else + { + return 0xF; + } + } + ASSERT(!"cChunkData::GetMeta(): coords out of chunk range!"); + return 0; +} + + + + + +cChunkData cChunkData::Copy(void) const +{ + cChunkData copy; + for (size_t i = 0; i < NumSections; i++) + { + if (m_Sections[i] != NULL) + { + copy.m_Sections[i] = Allocate(); + *copy.m_Sections[i] = *m_Sections[i]; + } + } + return copy; +} + + + + + +void cChunkData::CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx, size_t a_Length) const +{ + size_t ToSkip = a_Idx; + + for (size_t i = 0; i < NumSections; i++) + { + size_t StartPos = 0; + if (ToSkip > 0) + { + StartPos = std::min(ToSkip, +SectionBlockCount); + ToSkip -= StartPos; + } + if (StartPos < SectionBlockCount) + { + size_t ToCopy = std::min(+SectionBlockCount - StartPos, a_Length); + a_Length -= ToCopy; + if (m_Sections[i] != NULL) + { + BLOCKTYPE * blockbuffer = m_Sections[i]->m_BlockTypes; + memcpy(&a_Dest[(i * SectionBlockCount) + StartPos - a_Idx], blockbuffer + StartPos, sizeof(BLOCKTYPE) * ToCopy); + } + else + { + memset(&a_Dest[(i * SectionBlockCount) - a_Idx], 0, sizeof(BLOCKTYPE) * ToCopy); + } + } + } +} + + + + + +void cChunkData::CopyMetas(NIBBLETYPE * a_Dest) const +{ + for (size_t i = 0; i < NumSections; i++) + { + if (m_Sections[i] != NULL) + { + memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockMetas, sizeof(m_Sections[i]->m_BlockMetas)); + } + else + { + memset(&a_Dest[i * SectionBlockCount / 2], 0, sizeof(m_Sections[i]->m_BlockMetas)); + } + } +} + + + + + +void cChunkData::CopyBlockLight(NIBBLETYPE * a_Dest) const +{ + for (size_t i = 0; i < NumSections; i++) + { + if (m_Sections[i] != NULL) + { + memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockLight, sizeof(m_Sections[i]->m_BlockLight)); + } + else + { + memset(&a_Dest[i * SectionBlockCount / 2], 0, sizeof(m_Sections[i]->m_BlockLight)); + } + } +} + + + + + +void cChunkData::CopySkyLight(NIBBLETYPE * a_Dest) const +{ + for (size_t i = 0; i < NumSections; i++) + { + if (m_Sections[i] != NULL) + { + memcpy(&a_Dest[i * SectionBlockCount / 2], &m_Sections[i]->m_BlockSkyLight, sizeof(m_Sections[i]->m_BlockSkyLight)); + } + else + { + memset(&a_Dest[i * SectionBlockCount / 2], 0xff, sizeof(m_Sections[i]->m_BlockSkyLight)); + } + } +} + + + + + +void cChunkData::SetBlockTypes(const BLOCKTYPE * a_Src) +{ + ASSERT(a_Src != NULL); + + for (size_t i = 0; i < NumSections; i++) + { + // If the section is already allocated, copy the data into it: + if (m_Sections[i] != NULL) + { + memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes)); + continue; + } + + // The section doesn't exist, find out if it is needed: + if (IsAllValue(a_Src + i * SectionBlockCount, SectionBlockCount, (const BLOCKTYPE)0)) + { + // No need for the section, the data is all-air + continue; + } + + // Allocate the section and copy the data into it: + m_Sections[i] = Allocate(); + memcpy(m_Sections[i]->m_BlockTypes, &a_Src[i * SectionBlockCount], sizeof(m_Sections[i]->m_BlockTypes)); + memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas)); + memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight)); + memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight)); + } // for i - m_Sections[] +} + + + + +void cChunkData::SetMetas(const NIBBLETYPE * a_Src) +{ + ASSERT(a_Src != NULL); + + for (size_t i = 0; i < NumSections; i++) + { + // If the section is already allocated, copy the data into it: + if (m_Sections[i] != NULL) + { + memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas)); + continue; + } + + // The section doesn't exist, find out if it is needed: + if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0)) + { + // No need for the section, the data is all zeroes + continue; + } + + // Allocate the section and copy the data into it: + m_Sections[i] = Allocate(); + memcpy(m_Sections[i]->m_BlockMetas, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockMetas)); + memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes)); + memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight)); + memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight)); + } // for i - m_Sections[] +} + + + + + +void cChunkData::SetBlockLight(const NIBBLETYPE * a_Src) +{ + if (a_Src == NULL) + { + return; + } + + for (size_t i = 0; i < NumSections; i++) + { + // If the section is already allocated, copy the data into it: + if (m_Sections[i] != NULL) + { + memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight)); + continue; + } + + // The section doesn't exist, find out if it is needed: + if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0)) + { + // No need for the section, the data is all zeroes + continue; + } + + // Allocate the section and copy the data into it: + m_Sections[i] = Allocate(); + memcpy(m_Sections[i]->m_BlockLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockLight)); + memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes)); + memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas)); + memset(m_Sections[i]->m_BlockSkyLight, 0xff, sizeof(m_Sections[i]->m_BlockSkyLight)); + } // for i - m_Sections[] +} + + + + +void cChunkData::SetSkyLight(const NIBBLETYPE * a_Src) +{ + if (a_Src == NULL) + { + return; + } + + for (size_t i = 0; i < NumSections; i++) + { + // If the section is already allocated, copy the data into it: + if (m_Sections[i] != NULL) + { + memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight)); + continue; + } + + // The section doesn't exist, find out if it is needed: + if (IsAllValue(a_Src + i * SectionBlockCount / 2, SectionBlockCount / 2, (NIBBLETYPE)0xff)) + { + // No need for the section, the data is all zeroes + continue; + } + + // Allocate the section and copy the data into it: + m_Sections[i] = Allocate(); + memcpy(m_Sections[i]->m_BlockSkyLight, &a_Src[i * SectionBlockCount / 2], sizeof(m_Sections[i]->m_BlockSkyLight)); + memset(m_Sections[i]->m_BlockTypes, 0x00, sizeof(m_Sections[i]->m_BlockTypes)); + memset(m_Sections[i]->m_BlockMetas, 0x00, sizeof(m_Sections[i]->m_BlockMetas)); + memset(m_Sections[i]->m_BlockLight, 0x00, sizeof(m_Sections[i]->m_BlockLight)); + } // for i - m_Sections[] +} + + + + + +cChunkData::sChunkSection * cChunkData::Allocate(void) +{ + // TODO: Use an allocation pool + return new cChunkData::sChunkSection; +} + + + + + +void cChunkData::Free(cChunkData::sChunkSection * a_Section) +{ + // TODO: Use an allocation pool + delete a_Section; +} + + + + + +void cChunkData::ZeroSection(cChunkData::sChunkSection * a_Section) const +{ + memset(a_Section->m_BlockTypes, 0x00, sizeof(a_Section->m_BlockTypes)); + memset(a_Section->m_BlockMetas, 0x00, sizeof(a_Section->m_BlockMetas)); + memset(a_Section->m_BlockLight, 0x00, sizeof(a_Section->m_BlockLight)); + memset(a_Section->m_BlockSkyLight, 0xff, sizeof(a_Section->m_BlockSkyLight)); +} + + + + diff --git a/src/ChunkData.h b/src/ChunkData.h new file mode 100644 index 000000000..fef31b5ad --- /dev/null +++ b/src/ChunkData.h @@ -0,0 +1,125 @@ + +// ChunkData.h + +// Declares the cChunkData class that represents the block's type, meta, blocklight and skylight storage for a chunk + + + + + +#pragma once + + +#include <cstring> + + +#include "ChunkDef.h" + + + + +#if __cplusplus < 201103L +// auto_ptr style interface for memory management +#else +// unique_ptr style interface for memory management +#endif + +class cChunkData +{ +public: + + cChunkData(void); + ~cChunkData(); + + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + cChunkData(const cChunkData & a_Other); + cChunkData & operator =(const cChunkData & a_Other); + #else + // unique_ptr style interface for memory management + cChunkData(cChunkData && a_Other); + cChunkData & operator =(cChunkData && a_ther); + #endif + + BLOCKTYPE GetBlock(int a_X, int a_Y, int a_Z) const; + void SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_Block); + + NIBBLETYPE GetMeta(int a_RelX, int a_RelY, int a_RelZ) const; + bool SetMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_Nibble); + + NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const; + + NIBBLETYPE GetSkyLight(int a_RelX, int a_RelY, int a_RelZ) const; + + /** Creates a (deep) copy of self. */ + cChunkData Copy(void) const; + + /** Copies the blocktype data into the specified flat array. + Optionally, only a part of the data is copied, as specified by the a_Idx and a_Length parameters. */ + void CopyBlockTypes(BLOCKTYPE * a_Dest, size_t a_Idx = 0, size_t a_Length = cChunkDef::NumBlocks) const; + + /** Copies the metadata into the specified flat array. */ + void CopyMetas(NIBBLETYPE * a_Dest) const; + + /** Copies the block light data into the specified flat array. */ + void CopyBlockLight(NIBBLETYPE * a_Dest) const; + + /** Copies the skylight data into the specified flat array. */ + void CopySkyLight (NIBBLETYPE * a_Dest) const; + + /** Copies the blocktype data from the specified flat array into the internal representation. + Allocates sections that are needed for the operation. + Requires that a_Src is a valid pointer. */ + void SetBlockTypes(const BLOCKTYPE * a_Src); + + /** Copies the metadata from the specified flat array into the internal representation. + Allocates sectios that are needed for the operation. + Requires that a_Src is a valid pointer. */ + void SetMetas(const NIBBLETYPE * a_Src); + + /** Copies the blocklight data from the specified flat array into the internal representation. + Allocates sectios that are needed for the operation. + Allows a_Src to be NULL, in which case it doesn't do anything. */ + void SetBlockLight(const NIBBLETYPE * a_Src); + + /** Copies the skylight data from the specified flat array into the internal representation. + Allocates sectios that are needed for the operation. + Allows a_Src to be NULL, in which case it doesn't do anything. */ + void SetSkyLight(const NIBBLETYPE * a_Src); + +private: + + static const size_t SectionHeight = 16; + static const size_t NumSections = (cChunkDef::Height / SectionHeight); + static const size_t SectionBlockCount = SectionHeight * cChunkDef::Width * cChunkDef::Width; + + #if __cplusplus < 201103L + // auto_ptr style interface for memory management + mutable bool m_IsOwner; + #endif + + struct sChunkSection { + BLOCKTYPE m_BlockTypes [SectionBlockCount]; + NIBBLETYPE m_BlockMetas [SectionBlockCount / 2]; + NIBBLETYPE m_BlockLight [SectionBlockCount / 2]; + NIBBLETYPE m_BlockSkyLight[SectionBlockCount / 2]; + }; + + sChunkSection * m_Sections[NumSections]; + + /** Allocates a new section. Entry-point to custom allocators. */ + static sChunkSection * Allocate(void); + + /** Frees the specified section, previously allocated using Allocate(). + Note that a_Section may be NULL. */ + static void Free(sChunkSection * a_Section); + + /** Sets the data in the specified section to their default values. */ + void ZeroSection(sChunkSection * a_Section) const; +}; + + + + + + diff --git a/src/ChunkDataCallback.h b/src/ChunkDataCallback.h new file mode 100644 index 000000000..0c8b1098f --- /dev/null +++ b/src/ChunkDataCallback.h @@ -0,0 +1,127 @@ + +// ChunkDataCallback.h + +// Declares the cChunkDataCallback interface and several trivial descendants, for reading chunk data + + + + + +#pragma once + +#include "ChunkData.h" + + + + + +/** Interface class used for getting data out of a chunk using the GetAllData() function. +Implementation must use the pointers immediately and NOT store any of them for later use +The virtual methods are called in the same order as they're declared here. +*/ +class cChunkDataCallback abstract +{ +public: + + virtual ~cChunkDataCallback() {} + + /** Called before any other callbacks to inform of the current coords + (only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()). + If false is returned, the chunk is skipped. + */ + virtual bool Coords(int a_ChunkX, int a_ChunkZ) { UNUSED(a_ChunkX); UNUSED(a_ChunkZ); return true; }; + + /// Called once to provide heightmap data + virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {UNUSED(a_HeightMap); }; + + /// Called once to provide biome data + virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); }; + + /// Called once to let know if the chunk lighting is valid. Return value is ignored + virtual void LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); }; + + /// Called once to export block info + virtual void ChunkData(const cChunkData & a_Buffer) {UNUSED(a_Buffer); }; + + /// Called for each entity in the chunk + virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); }; + + /// Called for each blockentity in the chunk + virtual void BlockEntity(cBlockEntity * a_Entity) {UNUSED(a_Entity); }; +} ; + + + + + +/** A simple implementation of the cChunkDataCallback interface that collects all block data into a buffer +*/ +class cChunkDataCollector : + public cChunkDataCallback +{ +public: + + cChunkData m_BlockData; + +protected: + + virtual void ChunkData(const cChunkData & a_BlockData) override + { + m_BlockData = a_BlockData.Copy(); + } +}; + + + + + +/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer +*/ +class cChunkDataArrayCollector : + public cChunkDataCallback +{ +public: + + // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both. + unsigned char m_BlockData[cChunkDef::BlockDataSize]; + +protected: + + virtual void ChunkData(const cChunkData & a_ChunkBuffer) override + { + a_ChunkBuffer.CopyBlockTypes(m_BlockData); + a_ChunkBuffer.CopyMetas(m_BlockData + cChunkDef::NumBlocks); + a_ChunkBuffer.CopyBlockLight(m_BlockData + 3 * cChunkDef::NumBlocks / 2); + a_ChunkBuffer.CopySkyLight(m_BlockData + 2 * cChunkDef::NumBlocks); + } +}; + + + + + +/** A simple implementation of the cChunkDataCallback interface that collects all block data into separate buffers */ +class cChunkDataSeparateCollector : + public cChunkDataCallback +{ +public: + + cChunkDef::BlockTypes m_BlockTypes; + cChunkDef::BlockNibbles m_BlockMetas; + cChunkDef::BlockNibbles m_BlockLight; + cChunkDef::BlockNibbles m_BlockSkyLight; + +protected: + + virtual void ChunkData(const cChunkData & a_ChunkBuffer) override + { + a_ChunkBuffer.CopyBlockTypes(m_BlockTypes); + a_ChunkBuffer.CopyMetas(m_BlockMetas); + a_ChunkBuffer.CopyBlockLight(m_BlockLight); + a_ChunkBuffer.CopySkyLight(m_BlockSkyLight); + } +} ; + + + + diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 9c7753820..f89e16ed1 100644 --- a/src/ChunkDef.h +++ b/src/ChunkDef.h @@ -77,13 +77,19 @@ public: 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]; + /** The storage wrapper used for compressed blockdata residing in RAMz */ + typedef std::vector<BLOCKTYPE> COMPRESSED_BLOCKTYPE; + + /** The storage wrapper used for compressed nibbledata residing in RAMz */ + typedef std::vector<NIBBLETYPE> COMPRESSED_NIBBLETYPE; + /// Converts absolute block coords into relative (chunk + block) coords: inline static void AbsoluteToRelative(/* in-out */ int & a_X, int & a_Y, int & a_Z, /* out */ int & a_ChunkX, int & a_ChunkZ ) @@ -219,46 +225,67 @@ public: ASSERT((a_Z >= 0) && (a_Z <= Width)); a_BiomeMap[a_X + Width * a_Z] = a_Biome; } - - - static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int a_BlockIdx) + + + static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, bool a_IsSkyLightNibble = false) { if ((a_BlockIdx > -1) && (a_BlockIdx < NumBlocks)) { - return (a_Buffer[a_BlockIdx / 2] >> ((a_BlockIdx & 1) * 4)) & 0x0f; + if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + { + return (a_IsSkyLightNibble ? 0xff : 0); + } + return (a_Buffer[(size_t)(a_BlockIdx / 2)] >> ((a_BlockIdx & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): index out of chunk range!"); return 0; } - - + + + static NIBBLETYPE GetNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, bool a_IsSkyLightNibble = false) + { + if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) + { + size_t Index = (size_t)MakeIndexNoCheck(x, y, z); + if ((Index / 2) >= a_Buffer.size()) + { + return (a_IsSkyLightNibble ? 0xff : 0); + } + return ExpandNibble(a_Buffer, Index); + } + ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); + return 0; + } + + static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int x, int y, int z) { if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1)) { int Index = MakeIndexNoCheck(x, y, z); - return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f; + return (a_Buffer[(size_t)(Index / 2)] >> ((Index & 1) * 4)) & 0x0f; } ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); return 0; } - static void SetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) + static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) { if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks)) { ASSERT(!"cChunkDef::SetNibble(): index out of range!"); return; } - a_Buffer[a_BlockIdx / 2] = static_cast<NIBBLETYPE>( - (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set - ); + if ((size_t)(a_BlockIdx / 2) >= a_Buffer.size()) + { + a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1)); + } + a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, (size_t)a_BlockIdx, a_Nibble); } - - - static void SetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) + + + static void SetNibble(COMPRESSED_NIBBLETYPE & a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) { if ( (x >= Width) || (x < 0) || @@ -270,155 +297,33 @@ public: return; } - int Index = MakeIndexNoCheck(x, y, z); - a_Buffer[Index / 2] = static_cast<NIBBLETYPE>( - (a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set - ); - } - - - inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos ) - { - return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); - } - - - inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value ) - { - SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value ); - } - -} ; - - - - - -/** Interface class used for getting data out of a chunk using the GetAllData() function. -Implementation must use the pointers immediately and NOT store any of them for later use -The virtual methods are called in the same order as they're declared here. -*/ -class cChunkDataCallback abstract -{ -public: - - virtual ~cChunkDataCallback() {} - - /** Called before any other callbacks to inform of the current coords - (only in processes where multiple chunks can be processed, such as cWorld::ForEachChunkInRect()). - If false is returned, the chunk is skipped. - */ - virtual bool Coords(int a_ChunkX, int a_ChunkZ) { UNUSED(a_ChunkX); UNUSED(a_ChunkZ); return true; }; - - /// Called once to provide heightmap data - virtual void HeightMap(const cChunkDef::HeightMap * a_HeightMap) {UNUSED(a_HeightMap); }; - - /// Called once to provide biome data - virtual void BiomeData (const cChunkDef::BiomeMap * a_BiomeMap) {UNUSED(a_BiomeMap); }; - - /// Called once to export block types - virtual void BlockTypes (const BLOCKTYPE * a_Type) {UNUSED(a_Type); }; - - /// Called once to export block meta - virtual void BlockMeta (const NIBBLETYPE * a_Meta) {UNUSED(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 (if true) - virtual bool LightIsValid(bool a_IsLightValid) {UNUSED(a_IsLightValid); return true; }; - - /// Called once to export block light - virtual void BlockLight (const NIBBLETYPE * a_BlockLight) {UNUSED(a_BlockLight); }; - - /// Called once to export sky light - virtual void BlockSkyLight(const NIBBLETYPE * a_SkyLight) {UNUSED(a_SkyLight); }; - - /// Called for each entity in the chunk - virtual void Entity(cEntity * a_Entity) {UNUSED(a_Entity); }; - - /// Called for each blockentity in the chunk - virtual void BlockEntity(cBlockEntity * a_Entity) {UNUSED(a_Entity); }; -} ; - - - - - -/** A simple implementation of the cChunkDataCallback interface that collects all block data into a single buffer -*/ -class cChunkDataCollector : - public cChunkDataCallback -{ -public: - - // Must be unsigned char instead of BLOCKTYPE or NIBBLETYPE, because it houses both. - unsigned char m_BlockData[cChunkDef::BlockDataSize]; - -protected: - - virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override - { - memcpy(m_BlockData, a_BlockTypes, sizeof(cChunkDef::BlockTypes)); - } - - - virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override - { - memcpy(m_BlockData + cChunkDef::NumBlocks, a_BlockMeta, cChunkDef::NumBlocks / 2); - } - - - virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override - { - memcpy(m_BlockData + 3 * cChunkDef::NumBlocks / 2, a_BlockLight, cChunkDef::NumBlocks / 2); - } - - - virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override - { - memcpy(m_BlockData + 2 * cChunkDef::NumBlocks, a_BlockSkyLight, cChunkDef::NumBlocks / 2); + size_t Index = (size_t)MakeIndexNoCheck(x, y, z); + if ((Index / 2) >= a_Buffer.size()) + { + a_Buffer.resize(((Index / 2) + 1)); + } + a_Buffer[(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble); } -} ; - +private: -/** A simple implementation of the cChunkDataCallback interface that collects all block data into a separate buffers -*/ -class cChunkDataSeparateCollector : - public cChunkDataCallback -{ -public: - - cChunkDef::BlockTypes m_BlockTypes; - cChunkDef::BlockNibbles m_BlockMetas; - cChunkDef::BlockNibbles m_BlockLight; - cChunkDef::BlockNibbles m_BlockSkyLight; - -protected: - - virtual void BlockTypes(const BLOCKTYPE * a_BlockTypes) override + inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index, NIBBLETYPE a_Nibble) { - memcpy(m_BlockTypes, a_BlockTypes, sizeof(m_BlockTypes)); - } - - - virtual void BlockMeta(const NIBBLETYPE * a_BlockMeta) override - { - memcpy(m_BlockMetas, a_BlockMeta, sizeof(m_BlockMetas)); + return static_cast<NIBBLETYPE>( + (a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((a_Index & 1) * 4)) // The nibble being set + ); } - virtual void BlockLight(const NIBBLETYPE * a_BlockLight) override + inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index) { - memcpy(m_BlockLight, a_BlockLight, sizeof(m_BlockLight)); + return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f; } - virtual void BlockSkyLight(const NIBBLETYPE * a_BlockSkyLight) override - { - memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight)); - } } ; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index e695f0ab2..d3f44bef8 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -219,9 +219,8 @@ bool cChunkMap::LockedGetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTY return false; } - int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ); - a_BlockType = Chunk->GetBlock(Index); - a_BlockMeta = Chunk->GetMeta(Index); + a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); + a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); return true; } @@ -242,8 +241,7 @@ bool cChunkMap::LockedGetBlockType(int a_BlockX, int a_BlockY, int a_BlockZ, BLO return false; } - int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ); - a_BlockType = Chunk->GetBlock(Index); + a_BlockType = Chunk->GetBlock(a_BlockX, a_BlockY, a_BlockZ); return true; } @@ -264,8 +262,7 @@ bool cChunkMap::LockedGetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB return false; } - int Index = cChunkDef::MakeIndexNoCheck(a_BlockX, a_BlockY, a_BlockZ); - a_BlockMeta = Chunk->GetMeta(Index); + a_BlockMeta = Chunk->GetMeta(a_BlockX, a_BlockY, a_BlockZ); return true; } @@ -346,9 +343,8 @@ void cChunkMap::BroadcastAttachEntity(const cEntity & a_Entity, const cEntity * void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType, const cClientHandle * a_Exclude) { cCSLock Lock(m_CSLayers); - int x, y, z, ChunkX, ChunkZ; + int x, z, ChunkX, ChunkZ; x = a_BlockX; - y = a_BlockY; z = a_BlockZ; cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); @@ -916,19 +912,21 @@ void cChunkMap::SetChunkData( } // Notify relevant ChunkStays: - for (cChunkStays::iterator itr = m_ChunkStays.begin(); itr != m_ChunkStays.end(); ) + cChunkStays ToBeDisabled; + for (cChunkStays::iterator itr = m_ChunkStays.begin(), end = m_ChunkStays.end(); itr != end; ++itr) { if ((*itr)->ChunkAvailable(a_ChunkX, a_ChunkZ)) { - cChunkStays::iterator cur = itr; - ++itr; - m_ChunkStays.erase(cur); - } - else - { - ++itr; + // The chunkstay wants to be disabled, add it to a list of to-be-disabled chunkstays for later processing: + ToBeDisabled.push_back(*itr); } } // for itr - m_ChunkStays[] + + // Disable (and possibly remove) the chunkstays that chose to get disabled: + for (cChunkStays::iterator itr = ToBeDisabled.begin(), end = ToBeDisabled.end(); itr != end; ++itr) + { + (*itr)->Disable(); + } } // Notify plugins of the chunk becoming available @@ -1144,9 +1142,8 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ) // First check if it isn't queued in the m_FastSetBlockQueue: { int X = a_BlockX, Y = a_BlockY, Z = a_BlockZ; - int ChunkX, ChunkY, ChunkZ; + int ChunkX, ChunkZ; cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ); - ChunkY = 0; cCSLock Lock(m_CSFastSetBlock); for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr) { @@ -1248,8 +1245,6 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP if ((Chunk != NULL) && Chunk->IsValid()) { Chunk->SetMeta(a_BlockX, a_BlockY, a_BlockZ, a_BlockMeta); - Chunk->MarkDirty(); - Chunk->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, NULL); } } @@ -1486,9 +1481,8 @@ bool cChunkMap::GetBlocks(sSetBlockVector & a_Blocks, bool a_ContinueOnFailure) res = false; continue; } - int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z); - itr->BlockType = Chunk->GetBlock(idx); - itr->BlockMeta = Chunk->GetMeta(idx); + itr->BlockType = Chunk->GetBlock(itr->x, itr->y, itr->z); + itr->BlockMeta = Chunk->GetMeta(itr->x, itr->y, itr->z); } return res; } @@ -1654,7 +1648,10 @@ void cChunkMap::AddEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ( + (Chunk == NULL) || // Chunk not present at all + (!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953) + ) { LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.", a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID() @@ -1689,7 +1686,7 @@ void cChunkMap::RemoveEntity(cEntity * a_Entity) { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ()); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return; } @@ -1721,7 +1718,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -1971,7 +1968,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEnti { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -1986,7 +1983,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2001,7 +1998,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCa { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2016,7 +2013,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallba { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2031,7 +2028,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpens { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2046,7 +2043,7 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallba { cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2064,7 +2061,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cB cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2082,7 +2079,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCa cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2100,7 +2097,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDis cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2118,7 +2115,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropp cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2136,7 +2133,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cD cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2154,7 +2151,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurna cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2171,7 +2168,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2188,7 +2185,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2206,7 +2203,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHe cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2224,7 +2221,7 @@ bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlo cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2242,7 +2239,7 @@ bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); cCSLock Lock(m_CSLayers); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); - if ((Chunk == NULL) && !Chunk->IsValid()) + if ((Chunk == NULL) || !Chunk->IsValid()) { return false; } @@ -2974,7 +2971,12 @@ void cChunkMap::AddChunkStay(cChunkStay & a_ChunkStay) Chunk->Stay(true); if (Chunk->IsValid()) { - a_ChunkStay.ChunkAvailable(itr->m_ChunkX, itr->m_ChunkZ); + if (a_ChunkStay.ChunkAvailable(itr->m_ChunkX, itr->m_ChunkZ)) + { + // The chunkstay wants to be deactivated, disable it and bail out: + a_ChunkStay.Disable(); + return; + } } } // for itr - WantedChunks[] } @@ -3017,6 +3019,7 @@ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay) } Chunk->Stay(false); } // for itr - Chunks[] + a_ChunkStay.OnDisabled(); } diff --git a/src/ChunkMap.h b/src/ChunkMap.h index 9d973f2a9..c3deda088 100644 --- a/src/ChunkMap.h +++ b/src/ChunkMap.h @@ -5,7 +5,8 @@ #pragma once -#include "ChunkDef.h" + +#include "ChunkDataCallback.h" diff --git a/src/ChunkSender.h b/src/ChunkSender.h index a26f764a7..00565d7c3 100644 --- a/src/ChunkSender.h +++ b/src/ChunkSender.h @@ -27,6 +27,7 @@ Note that it may be called by world's BroadcastToChunk() if the client is still #include "OSSupport/IsThread.h" #include "ChunkDef.h" +#include "ChunkDataCallback.h" diff --git a/src/ChunkStay.cpp b/src/ChunkStay.cpp index 6b1d5ee34..b5002a63d 100644 --- a/src/ChunkStay.cpp +++ b/src/ChunkStay.cpp @@ -31,10 +31,7 @@ cChunkStay::~cChunkStay() void cChunkStay::Clear(void) { - if (m_ChunkMap != NULL) - { - Disable(); - } + ASSERT(m_ChunkMap == NULL); m_Chunks.clear(); } @@ -97,8 +94,9 @@ void cChunkStay::Disable(void) { ASSERT(m_ChunkMap != NULL); - m_ChunkMap->DelChunkStay(*this); + cChunkMap * ChunkMap = m_ChunkMap; m_ChunkMap = NULL; + ChunkMap->DelChunkStay(*this); } diff --git a/src/ChunkStay.h b/src/ChunkStay.h index 2510cb490..29893befc 100644 --- a/src/ChunkStay.h +++ b/src/ChunkStay.h @@ -36,8 +36,12 @@ class cChunkStay { public: cChunkStay(void); + + /** Deletes the object. Note that this calls Clear(), which means that the ChunkStay needs to be disabled. */ virtual ~cChunkStay(); + /** Clears all the chunks that have been added. + To be used only while the ChunkStay object is not enabled. */ void Clear(void); /** Adds a chunk to be locked from unloading. diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 46c10ae82..9b03bead9 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -24,13 +24,15 @@ #include "Root.h" -#include "Authenticator.h" +#include "Protocol/Authenticator.h" #include "MersenneTwister.h" #include "Protocol/ProtocolRecognizer.h" #include "CompositeChat.h" #include "Items/ItemSword.h" +#include "md5/md5.h" + /** Maximum number of explosions to send this tick, server will start dropping if exceeded */ @@ -175,6 +177,84 @@ void cClientHandle::Destroy(void) +void cClientHandle::GenerateOfflineUUID(void) +{ + m_UUID = GenerateOfflineUUID(m_Username); +} + + + + + +AString cClientHandle::FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2) +{ + if (ShouldAppendChatPrefixes) + return Printf("%s[%s] %s", m_Color1.c_str(), a_ChatPrefixS.c_str(), m_Color2.c_str()); + else + return Printf("%s", m_Color1.c_str()); +} + + + + + +AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString &a_AdditionalData) +{ + switch (a_ChatPrefix) + { + case mtCustom: return ""; + case mtFailure: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Rose, cChatColor::White); + case mtInformation: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Yellow, cChatColor::White); + case mtSuccess: return FormatChatPrefix(ShouldAppendChatPrefixes, "INFO", cChatColor::Green, cChatColor::White); + case mtWarning: return FormatChatPrefix(ShouldAppendChatPrefixes, "WARN", cChatColor::Rose, cChatColor::White); + case mtFatal: return FormatChatPrefix(ShouldAppendChatPrefixes, "FATAL", cChatColor::Red, cChatColor::White); + case mtDeath: return FormatChatPrefix(ShouldAppendChatPrefixes, "DEATH", cChatColor::Gray, cChatColor::White); + case mtJoin: return FormatChatPrefix(ShouldAppendChatPrefixes, "JOIN", cChatColor::Yellow, cChatColor::White); + case mtLeave: return FormatChatPrefix(ShouldAppendChatPrefixes, "LEAVE", cChatColor::Yellow, cChatColor::White); + case mtPrivateMessage: + { + if (ShouldAppendChatPrefixes) + { + return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str()); + } + else + { + return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str()); + } + } + } + ASSERT(!"Unhandled chat prefix type!"); + return ""; +} + + + + + +AString cClientHandle::GenerateOfflineUUID(const AString & a_Username) +{ + // Proper format for a version 3 UUID is: + // xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B + + // Generate an md5 checksum, and use it as base for the ID: + MD5 Checksum(a_Username); + AString UUID = Checksum.hexdigest(); + UUID[12] = '3'; // Version 3 UUID + UUID[16] = '8'; // Variant 1 UUID + + // Now the digest doesn't have the UUID slashes, but the client requires them, so add them into the appropriate positions: + UUID.insert(8, "-"); + UUID.insert(13, "-"); + UUID.insert(18, "-"); + UUID.insert(23, "-"); + + return UUID; +} + + + + + void cClientHandle::Kick(const AString & a_Reason) { if (m_State >= csAuthenticating) // Don't log pings @@ -188,7 +268,7 @@ void cClientHandle::Kick(const AString & a_Reason) -void cClientHandle::Authenticate(void) +void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID) { if (m_State != csAuthenticating) { @@ -197,6 +277,12 @@ void cClientHandle::Authenticate(void) ASSERT( m_Player == NULL ); + m_Username = a_Name; + m_UUID = a_UUID; + + // Send login success (if the protocol supports it): + m_Protocol->SendLoginSuccess(); + // Spawn player (only serversided, so data is loaded) m_Player = new cPlayer(this, GetUsername()); @@ -251,6 +337,11 @@ void cClientHandle::Authenticate(void) // Send scoreboard data World->GetScoreBoard().SendTo(*this); + // Delay the first ping until the client "settles down" + // This should fix #889, "BadCast exception, cannot convert bit to fm" error in client + cTimer t1; + m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds + cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player); } @@ -412,14 +503,16 @@ void cClientHandle::HandlePing(void) { // Somebody tries to retrieve information about the server AString Reply; + const cServer & Server = *cRoot::Get()->GetServer(); + Printf(Reply, "%s%s%i%s%i", - cRoot::Get()->GetServer()->GetDescription().c_str(), + Server.GetDescription().c_str(), cChatColor::Delimiter.c_str(), - cRoot::Get()->GetServer()->GetNumPlayers(), + Server.GetNumPlayers(), cChatColor::Delimiter.c_str(), - cRoot::Get()->GetServer()->GetMaxPlayers() + Server.GetMaxPlayers() ); - Kick(Reply.c_str()); + Kick(Reply); } @@ -540,6 +633,10 @@ void cClientHandle::HandlePluginMessage(const AString & a_Channel, const AString // Client <-> Server branding exchange SendPluginMessage("MC|Brand", "MCServer"); } + else if (a_Channel == "MC|ItemName") + { + HandleAnvilItemName(a_Message.c_str(), a_Message.size()); + } else if (a_Channel == "REGISTER") { if (HasPluginChannel(a_Channel)) @@ -623,7 +720,7 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList -void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length) +void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length) { if (a_Length < 14) { @@ -681,6 +778,29 @@ void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int +void cClientHandle::HandleAnvilItemName(const char * a_Data, size_t a_Length) +{ + if (a_Length < 1) + { + return; + } + + if ((m_Player->GetWindow() == NULL) || (m_Player->GetWindow()->GetWindowType() != cWindow::wtAnvil)) + { + return; + } + + AString Name(a_Data, a_Length); + if (Name.length() <= 30) + { + ((cAnvilWindow *)m_Player->GetWindow())->SetRepairedItemName(Name, m_Player); + } +} + + + + + void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, char a_Status) { LOGD("HandleLeftClick: {%i, %i, %i}; Face: %i; Stat: %i", @@ -695,6 +815,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB return; } + if ( + ((a_Status == DIG_STATUS_STARTED) || (a_Status == DIG_STATUS_FINISHED)) && // Only do a radius check for block destruction - things like pickup tossing send coordinates that are to be ignored + ((Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) || + (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) || + (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)) + ) + { + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + return; + } + cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status)) { @@ -758,6 +889,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB case DIG_STATUS_CANCELLED: { // Block breaking cancelled by player + FinishDigAnimation(); return; } @@ -796,7 +928,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc // It is a duplicate packet, drop it right away return; } - + if ( m_Player->IsGameModeCreative() && ItemCategory::IsSword(m_Player->GetInventory().GetEquippedItem().m_ItemType) @@ -805,14 +937,17 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc // Players can't destroy blocks with a Sword in the hand. return; } - - if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta)) + + if ( + (Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) || + (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) || + (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6) + ) { - // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows: m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); return; } - + // Set the last digging coords to the block being dug, so that they can be checked in DIG_FINISHED to avoid dig/aim bug in the client: m_HasStartedDigging = true; m_LastDigBlockX = a_BlockX; @@ -884,24 +1019,24 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo return; } - m_HasStartedDigging = false; - if (m_BlockDigAnimStage != -1) + FinishDigAnimation(); + + cWorld * World = m_Player->GetWorld(); + cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); + + if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta)) { - // End dig animation - m_BlockDigAnimStage = -1; - // It seems that 10 ends block animation - m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, 10, this); + // A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows: + m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + return; } - cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); - if (a_OldBlock == E_BLOCK_AIR) { LOGD("Dug air - what the function?"); return; } - - cWorld * World = m_Player->GetWorld(); + ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ); // The ItemHandler is also responsible for spawning the pickups cChunkInterface ChunkInterface(World->GetChunkMap()); @@ -916,6 +1051,36 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo +void cClientHandle::FinishDigAnimation() +{ + if ( + !m_HasStartedDigging || // Hasn't received the DIG_STARTED packet + (m_LastDigBlockX == -1) || + (m_LastDigBlockY == -1) || + (m_LastDigBlockZ == -1) + ) + { + return; + } + + m_HasStartedDigging = false; + if (m_BlockDigAnimStage != -1) + { + // End dig animation + m_BlockDigAnimStage = -1; + // It seems that 10 ends block animation + m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ, 10, this); + } + + m_BlockDigAnimX = -1; + m_BlockDigAnimY = -1; + m_BlockDigAnimZ = -1; +} + + + + + void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem) { LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s", @@ -923,7 +1088,23 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e ); cWorld * World = m_Player->GetWorld(); - + + if ( + (Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) || + (Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) || + (Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6) + ) + { + if (a_BlockFace != BLOCK_FACE_NONE) + { + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things + m_Player->GetInventory().SendEquippedSlot(); + } + return; + } + cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager(); if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ)) { @@ -937,10 +1118,13 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); - World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things + World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things + m_Player->GetInventory().SendEquippedSlot(); } return; } + + m_NumBlockChangeInteractionsThisTick++; if (!CheckBlockInteractionsRate()) { @@ -960,7 +1144,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e ); // Let's send the current world block to the client, so that it can immediately "let the user know" that they haven't placed the block - if (a_BlockFace > -1) + if (a_BlockFace != BLOCK_FACE_NONE) { AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); @@ -988,11 +1172,11 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Equipped.m_ItemType); - if (ItemHandler->IsPlaceable() && (a_BlockFace > -1)) + if (ItemHandler->IsPlaceable() && (a_BlockFace != BLOCK_FACE_NONE)) { HandlePlaceBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, *ItemHandler); } - else if (ItemHandler->IsFood()) + else if (ItemHandler->IsFood() && !m_Player->IsGameModeCreative()) { if (m_Player->IsSatiated()) { @@ -1026,6 +1210,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler) { + BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); if (a_BlockFace < 0) { // Clicked in air @@ -1036,7 +1221,6 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e BLOCKTYPE ClickedBlock; NIBBLETYPE ClickedBlockMeta; - BLOCKTYPE EquippedBlock = (BLOCKTYPE)(m_Player->GetEquippedItem().m_ItemType); NIBBLETYPE EquippedBlockDamage = (NIBBLETYPE)(m_Player->GetEquippedItem().m_ItemDamage); if ((a_BlockY < 0) || (a_BlockY >= cChunkDef::Height)) @@ -1053,8 +1237,8 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e cBlockSlabHandler::IsAnySlabType(EquippedBlock) && // Is the player placing another slab? ((ClickedBlockMeta & 0x07) == EquippedBlockDamage) && // Is it the same slab type? ( - (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab - (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab + (a_BlockFace == BLOCK_FACE_TOP) || // Clicking the top of a bottom slab + (a_BlockFace == BLOCK_FACE_BOTTOM) // Clicking the bottom of a top slab ) ) { @@ -1062,7 +1246,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e // If clicked top face and slab occupies the top voxel, we want a slab to be placed above it (therefore increment Y) // Else if clicked bottom face and slab occupies the bottom voxel, decrement Y for the same reason // Don't touch coordinates if anything else because a dblslab opportunity is present - if((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP)) + if ((ClickedBlockMeta & 0x08) && (a_BlockFace == BLOCK_FACE_TOP)) { ++a_BlockY; } @@ -1124,6 +1308,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e { // Handler refused the placement, send that information back to the client: World->SendBlockTo(a_BlockX, a_BlockY, a_BlockY, m_Player); + m_Player->GetInventory().SendEquippedSlot(); return; } @@ -1133,12 +1318,13 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e { // A plugin doesn't agree with placing the block, revert the block on the client: World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player); + m_Player->GetInventory().SendEquippedSlot(); return; } // The actual block placement: World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, BlockType, BlockMeta); - if (m_Player->GetGameMode() != gmCreative) + if (!m_Player->IsGameModeCreative()) { m_Player->GetInventory().RemoveOneEquippedItem(); } @@ -1173,8 +1359,8 @@ void cClientHandle::HandleChat(const AString & a_Message) Color = AString("@") + Color[2]; } else - { - Color.empty(); + { + Color.clear(); } Msg.AddTextPart(AString("<") + m_Player->GetName() + "> ", Color); Msg.ParseText(a_Message); @@ -1205,28 +1391,8 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_PosZ, double a_Stance, float a_Rotation, float a_Pitch, bool a_IsOnGround) { - if ((m_Player == NULL) || (m_State != csPlaying)) - { - // The client hasn't been spawned yet and sends nonsense, we know better - return; - } - - /* - // TODO: Invalid stance check - if ((a_PosY >= a_Stance) || (a_Stance > a_PosY + 1.65)) - { - LOGD("Invalid stance"); - SendPlayerMoveLook(); - return; - } - */ - - m_Player->MoveTo(Vector3d(a_PosX, a_PosY, a_PosZ)); - m_Player->SetStance (a_Stance); - m_Player->SetTouchGround(a_IsOnGround); - m_Player->SetHeadYaw (a_Rotation); - m_Player->SetYaw (a_Rotation); - m_Player->SetPitch (a_Pitch); + HandlePlayerLook(a_Rotation, a_Pitch, a_IsOnGround); + HandlePlayerPos(a_PosX, a_PosY, a_PosZ, a_Stance, a_IsOnGround); } @@ -1415,7 +1581,7 @@ void cClientHandle::HandleDisconnect(const AString & a_Reason) { LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str()); - cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason); + cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason); m_HasSentDC = true; Destroy(); @@ -1530,7 +1696,7 @@ void cClientHandle::HandleTabCompletion(const AString & a_Text) -void cClientHandle::SendData(const char * a_Data, int a_Size) +void cClientHandle::SendData(const char * a_Data, size_t a_Size) { if (m_HasSentDC) { @@ -1545,7 +1711,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size) if (m_OutgoingDataOverflow.empty()) { // No queued overflow data; if this packet fits into the ringbuffer, put it in, otherwise put it in the overflow buffer: - int CanFit = m_OutgoingData.GetFreeSpace(); + size_t CanFit = m_OutgoingData.GetFreeSpace(); if (CanFit > a_Size) { CanFit = a_Size; @@ -1563,7 +1729,7 @@ void cClientHandle::SendData(const char * a_Data, int a_Size) { // There is a queued overflow. Append to it, then send as much from its front as possible m_OutgoingDataOverflow.append(a_Data, a_Size); - int CanFit = m_OutgoingData.GetFreeSpace(); + size_t CanFit = m_OutgoingData.GetFreeSpace(); if (CanFit > 128) { // No point in moving the data over if it's not large enough - too much effort for too little an effect @@ -1606,10 +1772,8 @@ void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket) m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ); } // for itr - Chunks[] - // Do NOT stream new chunks, the new world runs its own tick thread and may deadlock - // Instead, the chunks will be streamed when the client is moved to the new world's Tick list, - // by setting state to csAuthenticated - m_State = csAuthenticated; + // StreamChunks() called in cPlayer::MoveToWorld() after new world has been set + // Meanwhile here, we set last streamed values to bogus ones so everything is resent m_LastStreamedChunkX = 0x7fffffff; m_LastStreamedChunkZ = 0x7fffffff; m_HasSentPlayerChunk = false; @@ -1677,13 +1841,16 @@ void cClientHandle::Tick(float a_Dt) } // Send a ping packet: - cTimer t1; - if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) + if (m_State == csPlaying) { - m_PingID++; - m_PingStartTime = t1.GetNowTime(); - m_Protocol->SendKeepAlive(m_PingID); - m_LastPingTime = m_PingStartTime; + cTimer t1; + if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())) + { + m_PingID++; + m_PingStartTime = t1.GetNowTime(); + m_Protocol->SendKeepAlive(m_PingID); + m_LastPingTime = m_PingStartTime; + } } // Handle block break animation: @@ -1803,7 +1970,7 @@ void cClientHandle::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlock void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefix, const AString & a_AdditionalData) { bool ShouldAppendChatPrefixes = true; - + if (GetPlayer()->GetWorld() == NULL) { cWorld * World = cRoot::Get()->GetWorld(GetPlayer()->GetLoadedWorldName()); @@ -1822,89 +1989,9 @@ void cClientHandle::SendChat(const AString & a_Message, eMessageType a_ChatPrefi ShouldAppendChatPrefixes = false; } - AString Message; + AString Message = FormatMessageType(ShouldAppendChatPrefixes, a_ChatPrefix, a_AdditionalData); - switch (a_ChatPrefix) - { - case mtCustom: break; - case mtFailure: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Rose.c_str()); - break; - } - case mtInformation: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - case mtSuccess: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[INFO] %s", cChatColor::Green.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Green.c_str()); - break; - } - case mtWarning: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[WARN] %s", cChatColor::Rose.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Rose.c_str()); - break; - } - case mtFatal: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[FATAL] %s", cChatColor::Red.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Red.c_str()); - break; - } - case mtDeath: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[DEATH] %s", cChatColor::Gray.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Gray.c_str()); - break; - } - case mtPrivateMessage: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str()); - else - Message = Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str()); - break; - } - case mtJoin: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[JOIN] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - case mtLeave: - { - if (ShouldAppendChatPrefixes) - Message = Printf("%s[LEAVE] %s", cChatColor::Yellow.c_str(), cChatColor::White.c_str()); - else - Message = Printf("%s", cChatColor::Yellow.c_str()); - break; - } - default: ASSERT(!"Unhandled chat prefix type!"); return; - } - - Message.append(a_Message); - - m_Protocol->SendChat(Message); + m_Protocol->SendChat(Message.append(a_Message)); } @@ -2101,7 +2188,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo } // Update the statistics: - m_NumExplosionsThisTick += 1; + m_NumExplosionsThisTick++; m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion); } @@ -2394,6 +2481,15 @@ void cClientHandle::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTy +void cClientHandle::SendStatistics(const cStatManager & a_Manager) +{ + m_Protocol->SendStatistics(a_Manager); +} + + + + + void cClientHandle::SendTabCompletionResults(const AStringVector & a_Results) { m_Protocol->SendTabCompletionResults(a_Results); @@ -2633,12 +2729,13 @@ void cClientHandle::PacketError(unsigned char a_PacketType) -void cClientHandle::DataReceived(const char * a_Data, int a_Size) +bool cClientHandle::DataReceived(const char * a_Data, size_t a_Size) { // Data is received from the client, store it in the buffer to be processed by the Tick thread: m_TimeSinceLastPacket = 0; cCSLock Lock(m_CSIncomingData); m_IncomingData.append(a_Data, a_Size); + return false; } @@ -2673,9 +2770,9 @@ void cClientHandle::SocketClosed(void) LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str()); - if (m_Username != "") // Ignore client pings + if (!m_Username.empty()) // Ignore client pings { - cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected"); + cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, "Player disconnected"); } Destroy(); @@ -2685,4 +2782,27 @@ void cClientHandle::SocketClosed(void) +void cClientHandle::HandleEnchantItem(Byte & WindowID, Byte & Enchantment) +{ + cEnchantingWindow * Window = (cEnchantingWindow*)m_Player->GetWindow(); + cItem Item = *Window->m_SlotArea->GetSlot(0, *m_Player); + int BaseEnchantmentLevel = Window->GetPropertyValue(Enchantment); + + if (Item.EnchantByXPLevels(BaseEnchantmentLevel)) + { + if (m_Player->IsGameModeCreative() || m_Player->DeltaExperience(-m_Player->XpForLevel(BaseEnchantmentLevel)) >= 0) + { + Window->m_SlotArea->SetSlot(0, *m_Player, Item); + Window->SendSlot(*m_Player, Window->m_SlotArea, 0); + Window->BroadcastWholeWindow(); + + Window->SetProperty(0, 0, *m_Player); + Window->SetProperty(1, 0, *m_Player); + Window->SetProperty(2, 0, *m_Player); + } + } +} + + + diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 8366caa16..659c67658 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -18,6 +18,8 @@ #include "ByteBuffer.h" #include "Scoreboard.h" #include "Map.h" +#include "Enchantments.h" +#include "UI/SlotArea.h" @@ -37,6 +39,7 @@ class cFallingBlock; class cItemHandler; class cWorld; class cCompositeChat; +class cStatManager; @@ -62,8 +65,27 @@ public: cPlayer* GetPlayer() { return m_Player; } // tolua_export + const AString & GetUUID(void) const { return m_UUID; } // tolua_export + void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; } + + /** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member. + This is used for the offline (non-auth) mode, when there's no UUID source. + Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. + Internally calls the GenerateOfflineUUID static function. */ + void GenerateOfflineUUID(void); + + /** Generates an UUID based on the player name provided. + This is used for the offline (non-auth) mode, when there's no UUID source. + Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */ + static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export + + /** Formats the type of message with the proper color and prefix for sending to the client. **/ + static AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData); + + static AString FormatChatPrefix(bool ShouldAppendChatPrefixes, AString a_ChatPrefixS, AString m_Color1, AString m_Color2); + void Kick(const AString & a_Reason); // tolua_export - void Authenticate(void); // Called by cAuthenticator when the user passes authentication + void Authenticate(const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator when the user passes authentication void StreamChunks(void); @@ -139,6 +161,7 @@ public: void SendSpawnMob (const cMonster & a_Mob); void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch); void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType = 0); + void SendStatistics (const cStatManager & a_Manager); void SendTabCompletionResults(const AStringVector & a_Results); void SendTeleportEntity (const cEntity & a_Entity); void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ); @@ -225,16 +248,19 @@ public: */ bool HandleLogin(int a_ProtocolVersion, const AString & a_Username); - void SendData(const char * a_Data, int a_Size); + void SendData(const char * a_Data, size_t a_Size); /** Called when the player moves into a different world; queues sreaming the new chunks */ void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket); - /** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */ - void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler); + /** Called when the player will enchant a Item */ + void HandleEnchantItem(Byte & WindowID, Byte & Enchantment); private: + /** Handles the block placing packet when it is a real block placement (not block-using, item-using or eating) */ + void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler); + /** The type used for storing the names of registered plugin channels. */ typedef std::set<AString> cChannels; @@ -326,6 +352,7 @@ private: static int s_ClientCount; int m_UniqueID; + AString m_UUID; /** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */ bool m_HasSentPlayerChunk; @@ -349,6 +376,9 @@ private: /** Handles the DIG_FINISHED dig packet: */ void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta); + /** The clients will receive a finished dig animation */ + void FinishDigAnimation(); + /** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */ AStringVector BreakApartPluginChannels(const AString & a_PluginChannels); @@ -359,10 +389,13 @@ private: void UnregisterPluginChannels(const AStringVector & a_ChannelList); /** Handles the "MC|AdvCdm" plugin message */ - void HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length); + void HandleCommandBlockMessage(const char * a_Data, size_t a_Length); + + /** Handles the "MC|ItemName" plugin message */ + void HandleAnvilItemName(const char * a_Data, size_t a_Length); // cSocketThreads::cCallback overrides: - virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client + virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client virtual void SocketClosed (void) override; // The socket has been closed for any reason }; // tolua_export diff --git a/src/CompositeChat.cpp b/src/CompositeChat.cpp index a917ee70f..a3612983a 100644 --- a/src/CompositeChat.cpp +++ b/src/CompositeChat.cpp @@ -112,8 +112,8 @@ cCompositeChat::cCompositeChat(void) : -cCompositeChat::cCompositeChat(const AString & a_ParseText) : - m_MessageType(mtCustom) +cCompositeChat::cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType) : + m_MessageType(a_MessageType) { ParseText(a_ParseText); } @@ -189,6 +189,15 @@ void cCompositeChat::AddSuggestCommandPart(const AString & a_Text, const AString +void cCompositeChat::AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style) +{ + m_Parts.push_back(new cShowAchievementPart(a_PlayerName, a_Achievement, a_Style)); +} + + + + + void cCompositeChat::ParseText(const AString & a_ParseText) { size_t len = a_ParseText.length(); @@ -290,9 +299,10 @@ void cCompositeChat::ParseText(const AString & a_ParseText) -void cCompositeChat::SetMessageType(eMessageType a_MessageType) +void cCompositeChat::SetMessageType(eMessageType a_MessageType, const AString & a_AdditionalMessageTypeData) { m_MessageType = a_MessageType; + m_AdditionalMessageTypeData = a_AdditionalMessageTypeData; } @@ -314,6 +324,58 @@ void cCompositeChat::UnderlineUrls(void) +AString cCompositeChat::ExtractText(void) const +{ + AString Msg; + for (cParts::const_iterator itr = m_Parts.begin(), end = m_Parts.end(); itr != end; ++itr) + { + switch ((*itr)->m_PartType) + { + case ptText: + case ptClientTranslated: + case ptRunCommand: + case ptSuggestCommand: + { + Msg.append((*itr)->m_Text); + break; + } + case ptUrl: + { + Msg.append(((cUrlPart *)(*itr))->m_Url); + break; + } + } // switch (PartType) + } // for itr - m_Parts[] + return Msg; +} + + + + + +cMCLogger::eLogLevel cCompositeChat::MessageTypeToLogLevel(eMessageType a_MessageType) +{ + switch (a_MessageType) + { + case mtCustom: return cMCLogger::llRegular; + case mtFailure: return cMCLogger::llWarning; + case mtInformation: return cMCLogger::llInfo; + case mtSuccess: return cMCLogger::llRegular; + case mtWarning: return cMCLogger::llWarning; + case mtFatal: return cMCLogger::llError; + case mtDeath: return cMCLogger::llRegular; + case mtPrivateMessage: return cMCLogger::llRegular; + case mtJoin: return cMCLogger::llRegular; + case mtLeave: return cMCLogger::llRegular; + } + ASSERT(!"Unhandled MessageType"); + return cMCLogger::llError; +} + + + + + void cCompositeChat::AddStyle(AString & a_Style, const AString & a_AddStyle) { if (a_AddStyle.empty()) @@ -424,3 +486,16 @@ cCompositeChat::cSuggestCommandPart::cSuggestCommandPart(const AString & a_Text, + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cCompositeChat::cShowAchievementPart: + +cCompositeChat::cShowAchievementPart::cShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style) : + super(ptShowAchievement, a_Achievement, a_Style), + m_PlayerName(a_PlayerName) +{ +} + + + + diff --git a/src/CompositeChat.h b/src/CompositeChat.h index 27319490d..1ad196f1d 100644 --- a/src/CompositeChat.h +++ b/src/CompositeChat.h @@ -38,6 +38,7 @@ public: ptUrl, ptRunCommand, ptSuggestCommand, + ptShowAchievement, } ; class cBasePart @@ -46,6 +47,7 @@ public: ePartType m_PartType; AString m_Text; AString m_Style; + AString m_AdditionalStyleData; cBasePart(ePartType a_PartType, const AString & a_Text, const AString & a_Style = ""); @@ -106,6 +108,15 @@ public: public: cSuggestCommandPart(const AString & a_Text, const AString & a_Command, const AString & a_Style = ""); } ; + + class cShowAchievementPart : + public cBasePart + { + typedef cBasePart super; + public: + AString m_PlayerName; + cShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = ""); + } ; typedef std::vector<cBasePart *> cParts; @@ -117,7 +128,7 @@ public: /** Creates a new chat message and parses the text into parts. Recognizes "http:" and "https:" links and @color-codes. Uses ParseText() for the actual parsing. */ - cCompositeChat(const AString & a_ParseText); + cCompositeChat(const AString & a_ParseText, eMessageType a_MessageType = mtCustom); ~cCompositeChat(); @@ -148,13 +159,20 @@ public: /** Adds a part that suggests a command (enters it into the chat message area, but doesn't send) when clicked. The default style is underlined yellow text. */ void AddSuggestCommandPart(const AString & a_Text, const AString & a_SuggestedCommand, const AString & a_Style = "u@b"); + + /** Adds a part that fully formats a specified achievement using client translatable strings + Takes achievement name and player awarded to. Displays as {player} has earned the achievement {achievement_name}. + */ + void AddShowAchievementPart(const AString & a_PlayerName, const AString & a_Achievement, const AString & a_Style = ""); /** Parses text into various parts, adds those. Recognizes "http:" and "https:" URLs and @color-codes. */ void ParseText(const AString & a_ParseText); - /** Sets the message type, which is indicated by prefixes added to the message when serializing. */ - void SetMessageType(eMessageType a_MessageType); + /** Sets the message type, which is indicated by prefixes added to the message when serializing + Takes optional AdditionalMessageTypeData to set m_AdditionalMessageTypeData. See said variable for more documentation. + */ + void SetMessageType(eMessageType a_MessageType, const AString & a_AdditionalMessageTypeData = ""); /** Adds the "underline" style to each part that is an URL. */ void UnderlineUrls(void); @@ -163,11 +181,23 @@ public: /** Returns the message type set previously by SetMessageType(). */ eMessageType GetMessageType(void) const { return m_MessageType; } + + /** Returns additional data pertaining to message type, for example, the name of a mtPrivateMsg sender */ + AString GetAdditionalMessageTypeData(void) const { return m_AdditionalMessageTypeData; } + + /** Returns the text from the parts that comprises the human-readable data. + Used for older protocols that don't support composite chat + and for console-logging. */ + AString ExtractText(void) const; // tolua_end const cParts & GetParts(void) const { return m_Parts; } + /** Converts the MessageType to a LogLevel value. + Used by the logging bindings when logging a cCompositeChat object. */ + static cMCLogger::eLogLevel MessageTypeToLogLevel(eMessageType a_MessageType); + protected: /** All the parts that */ cParts m_Parts; @@ -175,6 +205,9 @@ protected: /** The message type, as indicated by prefixes. */ eMessageType m_MessageType; + /** Additional data pertaining to message type, for example, the name of a mtPrivateMsg sender */ + AString m_AdditionalMessageTypeData; + /** Adds a_AddStyle to a_Style; overwrites the existing style if appropriate. If the style already contains something that a_AddStyle overrides, it is erased first. */ diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 30e7a8733..53a638ee5 100644 --- a/src/CraftingRecipes.cpp +++ b/src/CraftingRecipes.cpp @@ -661,14 +661,16 @@ cCraftingRecipes::cRecipe * cCraftingRecipes::MatchRecipe(const cItem * a_Crafti ASSERT(itrS->x + a_OffsetX < a_GridWidth); ASSERT(itrS->y + a_OffsetY < a_GridHeight); int GridID = (itrS->x + a_OffsetX) + a_GridStride * (itrS->y + a_OffsetY); + + const cItem & Item = itrS->m_Item; if ( (itrS->x >= a_GridWidth) || (itrS->y >= a_GridHeight) || - (itrS->m_Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) || // same item type? - (itrS->m_Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items + (Item.m_ItemType != a_CraftingGrid[GridID].m_ItemType) || // same item type? + (Item.m_ItemCount > a_CraftingGrid[GridID].m_ItemCount) || // not enough items ( - (itrS->m_Item.m_ItemDamage > 0) && // should compare damage values? - (itrS->m_Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage) + (Item.m_ItemDamage > 0) && // should compare damage values? + (Item.m_ItemDamage != a_CraftingGrid[GridID].m_ItemDamage) ) ) { @@ -800,7 +802,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe break; } case E_ITEM_PAPER: break; - default: LOG("Unexpected item in firework rocket a_Recipe, was the crafting file fireworks section changed?"); break; + default: LOG("Unexpected item in firework rocket recipe, was the crafting file's fireworks section changed?"); break; } } } @@ -824,7 +826,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe case E_ITEM_DYE: { int GridID = (itr->x + a_OffsetX) + a_GridStride * (itr->y + a_OffsetY); - DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye(a_CraftingGrid[GridID].m_ItemDamage)); + DyeColours.push_back(cFireworkItem::GetVanillaColourCodeFromDye((NIBBLETYPE)(a_CraftingGrid[GridID].m_ItemDamage & 0x0f))); break; } case E_ITEM_GUNPOWDER: break; @@ -835,7 +837,7 @@ void cCraftingRecipes::HandleFireworks(const cItem * a_CraftingGrid, cCraftingRe case E_ITEM_GOLD_NUGGET: a_Recipe->m_Result.m_FireworkItem.m_Type = 2; break; case E_ITEM_FEATHER: a_Recipe->m_Result.m_FireworkItem.m_Type = 4; break; case E_ITEM_HEAD: a_Recipe->m_Result.m_FireworkItem.m_Type = 3; break; - default: LOG("Unexpected item in firework star a_Recipe, was the crafting file fireworks section changed?"); break; // ermahgerd BARD ardmins + default: LOG("Unexpected item in firework star recipe, was the crafting file's fireworks section changed?"); break; // ermahgerd BARD ardmins } } diff --git a/src/Crypto.cpp b/src/Crypto.cpp deleted file mode 100644 index 26500f263..000000000 --- a/src/Crypto.cpp +++ /dev/null @@ -1,509 +0,0 @@ - -// Crypto.cpp - -// Implements classes that wrap the cryptographic code library - -#include "Globals.h" -#include "Crypto.h" - -#include "polarssl/pk.h" - - - - - -/* -// Self-test the hash formatting for known values: -// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48 -// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1 -// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6 - -class Test -{ -public: - Test(void) - { - AString DigestNotch, DigestJeb, DigestSimon; - Byte Digest[20]; - cSHA1Checksum Checksum; - Checksum.Update((const Byte *)"Notch", 5); - Checksum.Finalize(Digest); - cSHA1Checksum::DigestToJava(Digest, DigestNotch); - Checksum.Restart(); - Checksum.Update((const Byte *)"jeb_", 4); - Checksum.Finalize(Digest); - cSHA1Checksum::DigestToJava(Digest, DigestJeb); - Checksum.Restart(); - Checksum.Update((const Byte *)"simon", 5); - Checksum.Finalize(Digest); - cSHA1Checksum::DigestToJava(Digest, DigestSimon); - printf("Notch: \"%s\"\n", DigestNotch.c_str()); - printf("jeb_: \"%s\"\n", DigestJeb.c_str()); - printf("simon: \"%s\"\n", DigestSimon.c_str()); - assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48"); - assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1"); - assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6"); - } -} test; -*/ - - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cRSAPrivateKey: - -cRSAPrivateKey::cRSAPrivateKey(void) -{ - rsa_init(&m_Rsa, RSA_PKCS_V15, 0); - InitRnd(); -} - - - - - -cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other) -{ - rsa_init(&m_Rsa, RSA_PKCS_V15, 0); - rsa_copy(&m_Rsa, &a_Other.m_Rsa); - InitRnd(); -} - - - - - -cRSAPrivateKey::~cRSAPrivateKey() -{ - entropy_free(&m_Entropy); - rsa_free(&m_Rsa); -} - - - - - -void cRSAPrivateKey::InitRnd(void) -{ - entropy_init(&m_Entropy); - const unsigned char pers[] = "rsa_genkey"; - ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1); -} - - - - - -bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits) -{ - if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0) - { - // Key generation failed - return false; - } - - return true; -} - - - - - -AString cRSAPrivateKey::GetPubKeyDER(void) -{ - class cPubKey - { - public: - cPubKey(rsa_context * a_Rsa) : - m_IsValid(false) - { - pk_init(&m_Key); - if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0) - { - ASSERT(!"Cannot init PrivKey context"); - return; - } - if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0) - { - ASSERT(!"Cannot copy PrivKey to PK context"); - return; - } - m_IsValid = true; - } - - ~cPubKey() - { - if (m_IsValid) - { - pk_free(&m_Key); - } - } - - operator pk_context * (void) { return &m_Key; } - - protected: - bool m_IsValid; - pk_context m_Key; - } PkCtx(&m_Rsa); - - unsigned char buf[3000]; - int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf)); - if (res < 0) - { - return AString(); - } - return AString((const char *)(buf + sizeof(buf) - res), (size_t)res); -} - - - - - -int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) -{ - if (a_EncryptedLength < m_Rsa.len) - { - LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u", - __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len) - ); - ASSERT(!"Invalid a_DecryptedMaxLength!"); - return -1; - } - if (a_DecryptedMaxLength < m_Rsa.len) - { - LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u", - __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len) - ); - ASSERT(!"Invalid a_DecryptedMaxLength!"); - return -1; - } - size_t DecryptedLength; - int res = rsa_pkcs1_decrypt( - &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength, - a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength - ); - if (res != 0) - { - return -1; - } - return (int)DecryptedLength; -} - - - - - -int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) -{ - if (a_EncryptedMaxLength < m_Rsa.len) - { - LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u", - __FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len) - ); - ASSERT(!"Invalid a_DecryptedMaxLength!"); - return -1; - } - if (a_EncryptedMaxLength < m_Rsa.len) - { - LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u", - __FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len) - ); - ASSERT(!"Invalid a_PlainLength!"); - return -1; - } - int res = rsa_pkcs1_encrypt( - &m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, - a_PlainLength, a_PlainData, a_EncryptedData - ); - if (res != 0) - { - return -1; - } - return (int)m_Rsa.len; -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cPublicKey: - -cPublicKey::cPublicKey(const AString & a_PublicKeyDER) -{ - pk_init(&m_Pk); - if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0) - { - ASSERT(!"Cannot parse PubKey"); - return; - } - InitRnd(); -} - - - - - -cPublicKey::~cPublicKey() -{ - pk_free(&m_Pk); -} - - - - - -int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) -{ - size_t DecryptedLen = a_DecryptedMaxLength; - int res = pk_decrypt(&m_Pk, - a_EncryptedData, a_EncryptedLength, - a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength, - ctr_drbg_random, &m_Ctr_drbg - ); - if (res != 0) - { - return res; - } - return (int)DecryptedLen; -} - - - - - -int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) -{ - size_t EncryptedLength = a_EncryptedMaxLength; - int res = pk_encrypt(&m_Pk, - a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, - ctr_drbg_random, &m_Ctr_drbg - ); - if (res != 0) - { - return res; - } - return (int)EncryptedLength; -} - - - - - -void cPublicKey::InitRnd(void) -{ - entropy_init(&m_Entropy); - const unsigned char pers[] = "rsa_genkey"; - ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cAESCFBDecryptor: - -cAESCFBDecryptor::cAESCFBDecryptor(void) : - m_IVOffset(0), - m_IsValid(false) -{ -} - - - - - -cAESCFBDecryptor::~cAESCFBDecryptor() -{ - // Clear the leftover in-memory data, so that they can't be accessed by a backdoor - memset(&m_Aes, 0, sizeof(m_Aes)); -} - - - - - -void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) -{ - ASSERT(!IsValid()); // Cannot Init twice - - memcpy(m_IV, a_IV, 16); - aes_setkey_enc(&m_Aes, a_Key, 128); - m_IsValid = true; -} - - - - - -void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length) -{ - ASSERT(IsValid()); // Must Init() first - - // PolarSSL doesn't support AES-CFB8, need to implement it manually: - for (size_t i = 0; i < a_Length; i++) - { - Byte Buffer[sizeof(m_IV)]; - aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer); - for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++) - { - m_IV[idx] = m_IV[idx + 1]; - } - m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i]; - a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0]; - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cAESCFBEncryptor: - -cAESCFBEncryptor::cAESCFBEncryptor(void) : - m_IVOffset(0), - m_IsValid(false) -{ -} - - - - - -cAESCFBEncryptor::~cAESCFBEncryptor() -{ - // Clear the leftover in-memory data, so that they can't be accessed by a backdoor - memset(&m_Aes, 0, sizeof(m_Aes)); -} - - - - - -void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) -{ - ASSERT(!IsValid()); // Cannot Init twice - ASSERT(m_IVOffset == 0); - - memcpy(m_IV, a_IV, 16); - aes_setkey_enc(&m_Aes, a_Key, 128); - m_IsValid = true; -} - - - - - -void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length) -{ - ASSERT(IsValid()); // Must Init() first - - // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves: - for (size_t i = 0; i < a_Length; i++) - { - Byte Buffer[sizeof(m_IV)]; - aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer); - for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++) - { - m_IV[idx] = m_IV[idx + 1]; - } - a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0]; - m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i]; - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cSHA1Checksum: - -cSHA1Checksum::cSHA1Checksum(void) : - m_DoesAcceptInput(true) -{ - sha1_starts(&m_Sha1); -} - - - - - -void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length) -{ - ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed - - sha1_update(&m_Sha1, a_Data, a_Length); -} - - - - - -void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output) -{ - ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed - - sha1_finish(&m_Sha1, a_Output); - m_DoesAcceptInput = false; -} - - - - - -void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out) -{ - Checksum Digest; - memcpy(Digest, a_Digest, sizeof(Digest)); - - bool IsNegative = (Digest[0] >= 0x80); - if (IsNegative) - { - // Two's complement: - bool carry = true; // Add one to the whole number - for (int i = 19; i >= 0; i--) - { - Digest[i] = ~Digest[i]; - if (carry) - { - carry = (Digest[i] == 0xff); - Digest[i]++; - } - } - } - a_Out.clear(); - a_Out.reserve(40); - for (int i = 0; i < 20; i++) - { - AppendPrintf(a_Out, "%02x", Digest[i]); - } - while ((a_Out.length() > 0) && (a_Out[0] == '0')) - { - a_Out.erase(0, 1); - } - if (IsNegative) - { - a_Out.insert(0, "-"); - } -} - - - - - - -void cSHA1Checksum::Restart(void) -{ - sha1_starts(&m_Sha1); - m_DoesAcceptInput = true; -} - - - - diff --git a/src/Crypto.h b/src/Crypto.h deleted file mode 100644 index a9ec2c6d4..000000000 --- a/src/Crypto.h +++ /dev/null @@ -1,198 +0,0 @@ - -// Crypto.h - -// Declares classes that wrap the cryptographic code library - - - - - -#pragma once - -#include "polarssl/rsa.h" -#include "polarssl/aes.h" -#include "polarssl/entropy.h" -#include "polarssl/ctr_drbg.h" -#include "polarssl/sha1.h" -#include "polarssl/pk.h" - - - - - -/** Encapsulates an RSA private key used in PKI cryptography */ -class cRSAPrivateKey -{ -public: - /** Creates a new empty object, the key is not assigned */ - cRSAPrivateKey(void); - - /** Deep-copies the key from a_Other */ - cRSAPrivateKey(const cRSAPrivateKey & a_Other); - - ~cRSAPrivateKey(); - - /** Generates a new key within this object, with the specified size in bits. - Returns true on success, false on failure. */ - bool Generate(unsigned a_KeySizeBits = 1024); - - /** Returns the public key part encoded in ASN1 DER encoding */ - AString GetPubKeyDER(void); - - /** Decrypts the data using RSAES-PKCS#1 algorithm. - Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); - - /** Encrypts the data using RSAES-PKCS#1 algorithm. - Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); - -protected: - rsa_context m_Rsa; - entropy_context m_Entropy; - ctr_drbg_context m_Ctr_drbg; - - /** Initializes the m_Entropy and m_Ctr_drbg contexts - Common part of this object's construction, called from all constructors. */ - void InitRnd(void); -} ; - - - - - -class cPublicKey -{ -public: - cPublicKey(const AString & a_PublicKeyDER); - ~cPublicKey(); - - /** Decrypts the data using the stored public key - Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); - - /** Encrypts the data using the stored public key - Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. - Returns the number of bytes decrypted, or negative number for error. */ - int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); - -protected: - pk_context m_Pk; - entropy_context m_Entropy; - ctr_drbg_context m_Ctr_drbg; - - /** Initializes the m_Entropy and m_Ctr_drbg contexts - Common part of this object's construction, called from all constructors. */ - void InitRnd(void); -} ; - - - - - -/** Decrypts data using the AES / CFB (128) algorithm */ -class cAESCFBDecryptor -{ -public: - Byte test; - - cAESCFBDecryptor(void); - ~cAESCFBDecryptor(); - - /** Initializes the decryptor with the specified Key / IV */ - void Init(const Byte a_Key[16], const Byte a_IV[16]); - - /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */ - void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length); - - /** Returns true if the object has been initialized with the Key / IV */ - bool IsValid(void) const { return m_IsValid; } - -protected: - aes_context m_Aes; - - /** The InitialVector, used by the CFB mode decryption */ - Byte m_IV[16]; - - /** Current offset in the m_IV, used by the CFB mode decryption */ - size_t m_IVOffset; - - /** Indicates whether the object has been initialized with the Key / IV */ - bool m_IsValid; -} ; - - - - - -/** Encrypts data using the AES / CFB (128) algorithm */ -class cAESCFBEncryptor -{ -public: - cAESCFBEncryptor(void); - ~cAESCFBEncryptor(); - - /** Initializes the decryptor with the specified Key / IV */ - void Init(const Byte a_Key[16], const Byte a_IV[16]); - - /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */ - void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length); - - /** Returns true if the object has been initialized with the Key / IV */ - bool IsValid(void) const { return m_IsValid; } - -protected: - aes_context m_Aes; - - /** The InitialVector, used by the CFB mode encryption */ - Byte m_IV[16]; - - /** Current offset in the m_IV, used by the CFB mode encryption */ - size_t m_IVOffset; - - /** Indicates whether the object has been initialized with the Key / IV */ - bool m_IsValid; -} ; - - - - - -/** Calculates a SHA1 checksum for data stream */ -class cSHA1Checksum -{ -public: - typedef Byte Checksum[20]; // The type used for storing the checksum - - cSHA1Checksum(void); - - /** Adds the specified data to the checksum */ - void Update(const Byte * a_Data, size_t a_Length); - - /** Calculates and returns the final checksum */ - void Finalize(Checksum & a_Output); - - /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ - bool DoesAcceptInput(void) const { return m_DoesAcceptInput; } - - /** Converts a raw 160-bit SHA1 digest into a Java Hex representation - According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802 - */ - static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut); - - /** Clears the current context and start a new checksum calculation */ - void Restart(void); - -protected: - /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ - bool m_DoesAcceptInput; - - sha1_context m_Sha1; -} ; - - - - diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp index 322084dc4..f73a45555 100644 --- a/src/DeadlockDetect.cpp +++ b/src/DeadlockDetect.cpp @@ -109,21 +109,24 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age) WorldAges::iterator itr = m_WorldAges.find(a_WorldName); if (itr == m_WorldAges.end()) { - ASSERT(!"Unknown world in cDeadlockDetect"); + SetWorldAge(a_WorldName, a_Age); return; } - if (itr->second.m_Age == a_Age) + + cDeadlockDetect::sWorldAge & WorldAge = itr->second; + + if (WorldAge.m_Age == a_Age) { - itr->second.m_NumCyclesSame += 1; - if (itr->second.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS) + WorldAge.m_NumCyclesSame += 1; + if (WorldAge.m_NumCyclesSame > (1000 * m_IntervalSec) / CYCLE_MILLISECONDS) { DeadlockDetected(); } } else { - itr->second.m_Age = a_Age; - itr->second.m_NumCyclesSame = 0; + WorldAge.m_Age = a_Age; + WorldAge.m_NumCyclesSame = 0; } } diff --git a/src/Defines.h b/src/Defines.h index 1a8b3fa4a..563fc308c 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -3,6 +3,7 @@ #include "ChatColor.h" #include <limits> +#include <cmath> @@ -493,15 +494,17 @@ inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch) { - if (fabs(a_X) < std::numeric_limits<double>::epsilon()) + double r = sqrt((a_X * a_X) + (a_Z * a_Z)); + if (r < std::numeric_limits<double>::epsilon()) { - a_Pan = atan2(a_Z, a_X) * 180 / PI - 90; + a_Pan = 0; } else { - a_Pan = 0; + a_Pan = atan2(a_Z, a_X) * 180 / PI - 90; } - a_Pitch = atan2(a_Y, sqrt((a_X * a_X) + (a_Z * a_Z))) * 180 / PI; + + a_Pitch = atan2(a_Y, r) * 180 / PI; } @@ -526,6 +529,15 @@ inline float GetSpecialSignf( float a_Val ) +template<class T> inline T Diff(T a_Val1, T a_Val2) +{ + return std::abs(a_Val1 - a_Val2); +} + + + + + // tolua_begin enum eMessageType diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp index 1d8188e96..264878c22 100644 --- a/src/Enchantments.cpp +++ b/src/Enchantments.cpp @@ -5,6 +5,7 @@ #include "Globals.h" #include "Enchantments.h" #include "WorldStorage/FastNBT.h" +#include "FastRandom.h" @@ -28,6 +29,18 @@ cEnchantments::cEnchantments(const AString & a_StringSpec) +void cEnchantments::Add(const cEnchantments & a_Other) +{ + for (cEnchantments::cMap::const_iterator itr = a_Other.m_Enchantments.begin(), end = a_Other.m_Enchantments.end(); itr != end; ++itr) + { + SetLevel(itr->first, itr->second); + } // for itr - a_Other.m_Enchantments[] +} + + + + + void cEnchantments::AddFromString(const AString & a_StringSpec) { // Add enchantments in the stringspec; if a specified enchantment already exists, overwrites it @@ -49,21 +62,17 @@ void cEnchantments::AddFromString(const AString & a_StringSpec) LOG("%s: Malformed enchantment decl: \"%s\", skipping.", __FUNCTION__, itr->c_str()); continue; } - int id = atoi(Split[0].c_str()); - if ((id == 0) && (Split[0] != "0")) + int id = StringToEnchantmentID(Split[0]); + if (id < 0) { - id = StringToEnchantmentID(Split[0]); + LOG("%s: Failed to parse enchantment \"%s\", skipping.", __FUNCTION__, Split[0].c_str()); + continue; } int lvl = atoi(Split[1].c_str()); - if ( - ((id <= 0) && (Split[0] != "0")) || - ((lvl == 0) && (Split[1] != "0")) - ) - { - // Numbers failed to parse - LOG("%s: Failed to parse enchantment declaration for numbers: \"%s\" and \"%s\", skipping.", - __FUNCTION__, Split[0].c_str(), Split[1].c_str() - ); + if ((lvl == 0) && (Split[1] != "0")) + { + // Level failed to parse + LOG("%s: Failed to parse enchantment level \"%s\", skipping.", __FUNCTION__, Split[1].c_str()); continue; } SetLevel(id, lvl); @@ -74,6 +83,15 @@ void cEnchantments::AddFromString(const AString & a_StringSpec) +size_t cEnchantments::Count(void) +{ + return m_Enchantments.size(); +} + + + + + AString cEnchantments::ToString(void) const { // Serialize all the enchantments into a string @@ -150,7 +168,7 @@ bool cEnchantments::IsEmpty(void) const int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName) { - struct + static const struct { int m_Value; const char * m_Name; @@ -181,6 +199,15 @@ int cEnchantments::StringToEnchantmentID(const AString & a_EnchantmentName) { enchLuckOfTheSea, "LuckOfTheSea"}, { enchLure, "Lure"}, } ; + + // First try to parse as a number: + int id = atoi(a_EnchantmentName.c_str()); + if ((id != 0) || (a_EnchantmentName == "0")) + { + return id; + } + + // It wasn't a number, do a lookup: for (size_t i = 0; i < ARRAYCOUNT(EnchantmentNames); i++) { if (NoCaseCompare(EnchantmentNames[i].m_Name, a_EnchantmentName) == 0) @@ -213,7 +240,781 @@ bool cEnchantments::operator !=(const cEnchantments & a_Other) const +void cEnchantments::AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantments, short a_ItemType, int a_EnchantmentLevel) +{ + if (ItemCategory::IsSword(a_ItemType)) + { + // Sharpness + if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 4); + } + else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 3); + } + else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 1); + } + + // Smite + if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 1); + } + + // Bane of Arthropods + if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 1); + } + + // Knockback + if ((a_EnchantmentLevel >= 25) && (a_EnchantmentLevel <= 75)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 1); + } + + // Fire Aspect + if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 1); + } + + // Looting + if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 3); + } + else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 2); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 1); + } + } + + else if (ItemCategory::IsTool(a_ItemType)) + { + // Efficiency + if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 81)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 3); + } + else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 61)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 51)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 1); + } + + // Silk Touch + if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchSilkTouch, 1); + } + + // Fortune + if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 3); + } + else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 2); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 1); + } + } + + else if (ItemCategory::IsArmor(a_ItemType)) + { + // Protection + if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 4); + } + else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 3); + } + else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 1); + } + // Fire Protection + if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 46)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 4); + } + else if ((a_EnchantmentLevel >= 26) && (a_EnchantmentLevel <= 38)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 3); + } + else if ((a_EnchantmentLevel >= 18) && (a_EnchantmentLevel <= 30)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 22)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 1); + } + + // Blast Protection + if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 25)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 17)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 1); + } + + // Projectile Protection + if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 4); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 30)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 3); + } + else if ((a_EnchantmentLevel >= 9) && (a_EnchantmentLevel <= 24)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 2); + } + else if ((a_EnchantmentLevel >= 3) && (a_EnchantmentLevel <= 18)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 1); + } + + // Thorns + if ((a_EnchantmentLevel >= 50) && (a_EnchantmentLevel <= 100)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 3); + } + else if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 1); + } + + + if (ItemCategory::IsHelmet(a_ItemType)) + { + // Respiration + if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 60)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 3); + } + else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 40)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 1); + } + + // Aqua Affinity + if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchAquaAffinity, 1); + } + } + + else if (ItemCategory::IsBoots(a_ItemType)) + { + // Feather Fall + if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 4); + } + else if ((a_EnchantmentLevel >= 17) && (a_EnchantmentLevel <= 27)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 3); + } + else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 21)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 15)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1); + } + } + } + + else if (a_ItemType == E_ITEM_BOW) + { + // Power + if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 46)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 3); + } + else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 26)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 16)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 1); + } + + // Punch + if ((a_EnchantmentLevel >= 32) && (a_EnchantmentLevel <= 57)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 2); + } + else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 37)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 1); + } + + // Flame and Infinity + if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFlame, 1); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchInfinity, 1); + } + } + + else if (a_ItemType == E_ITEM_FISHING_ROD) + { + // Luck of the Sea and Lure + if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 3); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 3); + } + else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 2); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 2); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 1); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 1); + } + } + + else if (a_ItemType == E_ITEM_BOOK) + { + // All Enchantments + + // Sharpness + if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 4); + } + else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 3); + } + else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchSharpness, 1); + } + + // Smite + if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchSmite, 1); + } + + // Bane of Arthropods + if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 49)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 25)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchBaneOfArthropods, 1); + } + + // Knockback + if ((a_EnchantmentLevel >= 25) && (a_EnchantmentLevel <= 75)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchKnockback, 1); + } + + // Fire Aspect + if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFireAspect, 1); + } + + // Looting + if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 3); + } + else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 2); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchLooting, 1); + } + + // Efficiency + if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 81)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 3); + } + else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 61)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 51)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchEfficiency, 1); + } + + // Silk Touch + if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchSilkTouch, 1); + } + + // Fortune + if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 3); + } + else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 2); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFortune, 1); + } + + // Protection + if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 54)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 4); + } + else if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 43)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 3); + } + else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 32)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 21)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchProtection, 1); + } + + // Fire Protection + if ((a_EnchantmentLevel >= 34) && (a_EnchantmentLevel <= 46)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 4); + } + else if ((a_EnchantmentLevel >= 26) && (a_EnchantmentLevel <= 38)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 3); + } + else if ((a_EnchantmentLevel >= 18) && (a_EnchantmentLevel <= 30)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 22)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFireProtection, 1); + } + + // Blast Protection + if ((a_EnchantmentLevel >= 29) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 25)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 17)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchBlastProtection, 1); + } + + // Projectile Protection + if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 4); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 30)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 3); + } + else if ((a_EnchantmentLevel >= 9) && (a_EnchantmentLevel <= 24)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 2); + } + else if ((a_EnchantmentLevel >= 3) && (a_EnchantmentLevel <= 18)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchProjectileProtection, 1); + } + + // Thorns + if ((a_EnchantmentLevel >= 50) && (a_EnchantmentLevel <= 100)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 3); + } + else if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 80)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 60)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchThorns, 1); + } + + // Respiration + if ((a_EnchantmentLevel >= 30) && (a_EnchantmentLevel <= 60)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 3); + } + else if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 2); + } + else if ((a_EnchantmentLevel >= 10) && (a_EnchantmentLevel <= 40)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchRespiration, 1); + } + + // Aqua Affinity + if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 41)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchAquaAffinity, 1); + } + + // Feather Fall + if ((a_EnchantmentLevel >= 23) && (a_EnchantmentLevel <= 33)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 4); + } + else if ((a_EnchantmentLevel >= 17) && (a_EnchantmentLevel <= 27)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 3); + } + else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 21)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 15)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchFeatherFalling, 1); + } + + // Power + if ((a_EnchantmentLevel >= 31) && (a_EnchantmentLevel <= 46)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 4); + } + else if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 36)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 3); + } + else if ((a_EnchantmentLevel >= 11) && (a_EnchantmentLevel <= 26)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 2); + } + else if ((a_EnchantmentLevel >= 1) && (a_EnchantmentLevel <= 16)) + { + AddEnchantmentWeightToVector(a_Enchantments, 10, enchPower, 1); + } + + // Punch + if ((a_EnchantmentLevel >= 32) && (a_EnchantmentLevel <= 57)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 2); + } + else if ((a_EnchantmentLevel >= 12) && (a_EnchantmentLevel <= 37)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchPunch, 1); + } + + // Flame and Infinity + if ((a_EnchantmentLevel >= 20) && (a_EnchantmentLevel <= 50)) + { + AddEnchantmentWeightToVector(a_Enchantments, 2, enchFlame, 1); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchInfinity, 1); + } + + // Luck of the Sea and Lure + if ((a_EnchantmentLevel >= 33) && (a_EnchantmentLevel <= 83)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 3); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 3); + } + else if ((a_EnchantmentLevel >= 24) && (a_EnchantmentLevel <= 74)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 2); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 2); + } + else if ((a_EnchantmentLevel >= 15) && (a_EnchantmentLevel <= 65)) + { + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLuckOfTheSea, 1); + AddEnchantmentWeightToVector(a_Enchantments, 1, enchLure, 1); + } + } + + // Unbreaking + if ((a_EnchantmentLevel >= 21) && (a_EnchantmentLevel <= 71)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 3); + } + else if ((a_EnchantmentLevel >= 13) && (a_EnchantmentLevel <= 63)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 2); + } + else if ((a_EnchantmentLevel >= 5) && (a_EnchantmentLevel <= 55)) + { + AddEnchantmentWeightToVector(a_Enchantments, 5, enchUnbreaking, 1); + } +} + + + + + +void cEnchantments::AddEnchantmentWeightToVector(cWeightedEnchantments & a_Enchantments, int a_Weight, int a_EnchantmentID, int a_EnchantmentLevel) +{ + cWeightedEnchantment weightedenchantment; + weightedenchantment.m_Weight = a_Weight; + cEnchantments enchantment; + enchantment.SetLevel(a_EnchantmentID, a_EnchantmentLevel); + weightedenchantment.m_Enchantments = enchantment; + a_Enchantments.push_back(weightedenchantment); +} + + + + + +void cEnchantments::RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, int a_EnchantmentID) +{ + for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it) + { + if ((*it).m_Enchantments.GetLevel(a_EnchantmentID) > 0) + { + a_Enchantments.erase(it); + break; + } + } +} + + + + + +void cEnchantments::RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, const cEnchantments & a_Enchantment) +{ + for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it) + { + if ((*it).m_Enchantments == a_Enchantment) + { + a_Enchantments.erase(it); + break; + } + } +} + + + + + +void cEnchantments::CheckEnchantmentConflictsFromVector(cWeightedEnchantments & a_Enchantments, cEnchantments a_FirstEnchantment) +{ + if (a_FirstEnchantment.GetLevel(cEnchantments::enchProtection) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchFireProtection) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchBlastProtection) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProjectileProtection); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchProjectileProtection) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFireProtection); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBlastProtection); + } + + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSharpness) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSmite); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBaneOfArthropods); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSmite) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSharpness); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchBaneOfArthropods); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchBaneOfArthropods) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSharpness); + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSmite); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchSilkTouch) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchFortune); + } + else if (a_FirstEnchantment.GetLevel(cEnchantments::enchFortune) > 0) + { + RemoveEnchantmentWeightFromVector(a_Enchantments, cEnchantments::enchSilkTouch); + } +} + + + + + +cEnchantments cEnchantments::GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments) +{ + cFastRandom Random; + + int AllWeights = 0; + for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it) + { + AllWeights += (*it).m_Weight; + } + int RandomNumber = Random.GenerateRandomInteger(0, AllWeights - 1); + for (cWeightedEnchantments::iterator it = a_Enchantments.begin(); it != a_Enchantments.end(); ++it) + { + RandomNumber -= (*it).m_Weight; + if (RandomNumber < 0) + { + return (*it).m_Enchantments; + } + } + + return cEnchantments(); +} diff --git a/src/Enchantments.h b/src/Enchantments.h index f77b535d8..85a316414 100644 --- a/src/Enchantments.h +++ b/src/Enchantments.h @@ -8,6 +8,7 @@ #pragma once +#include "Defines.h" #include "WorldStorage/EnchantmentSerializer.h" @@ -18,6 +19,11 @@ class cFastNBTWriter; class cParsedNBT; +// fwd: +struct cWeightedEnchantment; + +typedef std::vector<cWeightedEnchantment> cWeightedEnchantments; + @@ -28,11 +34,14 @@ mapping each enchantment's id onto its level. ID may be either a number or the e Level value of 0 means no such enchantment, and it will not be stored in the m_Enchantments. Serialization will never put zero-level enchantments into the stringspec and will always use numeric IDs. */ + + // tolua_begin class cEnchantments { public: - /// Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs ) + /** Individual enchantment IDs, corresponding to their NBT IDs ( http://www.minecraftwiki.net/wiki/Data_Values#Enchantment_IDs ) + */ enum { @@ -61,56 +70,90 @@ public: enchLuckOfTheSea = 61, enchLure = 62, } ; - - /// Creates an empty enchantments container + + /** Creates an empty enchantments container */ cEnchantments(void); - /// Creates an enchantments container filled with enchantments parsed from stringspec + /** Creates an enchantments container filled with enchantments parsed from stringspec */ cEnchantments(const AString & a_StringSpec); - /// Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it + /** Adds the enchantments contained in a_Other into this object. + Existing enchantments are preserved, unless a_Other specifies a different level, in which case the level is changed. */ + void Add(const cEnchantments & a_Other); + + /** Adds enchantments in the stringspec; if a specified enchantment already exists, overwrites it */ void AddFromString(const AString & a_StringSpec); - /// Serializes all the enchantments into a string + /** Get the count of enchantments */ + size_t Count(void); + + /** Serializes all the enchantments into a string */ AString ToString(void) const; - /// Returns the level for the specified enchantment; 0 if not stored + /** Returns the level for the specified enchantment; 0 if not stored */ int GetLevel(int a_EnchantmentID) const; - /// Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0 + /** Sets the level for the specified enchantment, adding it if not stored before or removing it if level <= 0 */ void SetLevel(int a_EnchantmentID, int a_Level); - /// Removes all enchantments + /** Removes all enchantments */ void Clear(void); - /// Returns true if there are no enchantments + /** Returns true if there are no enchantments */ bool IsEmpty(void) const; - /// Converts enchantment name to the numeric representation; returns -1 if enchantment name not found; case insensitive + /** Converts enchantment name or ID (number in string) to the numeric representation; returns -1 if enchantment name not found; case insensitive */ static int StringToEnchantmentID(const AString & a_EnchantmentName); - /// Returns true if a_Other contains exactly the same enchantments and levels + /** Returns true if a_Other contains exactly the same enchantments and levels */ bool operator ==(const cEnchantments & a_Other) const; - + // tolua_end + + /** Add enchantment weights from item to the vector */ + static void AddItemEnchantmentWeights(cWeightedEnchantments & a_Enchantments, short a_ItemType, int a_EnchantmentLevel); + + /** Add a enchantment with weight to the vector */ + static void AddEnchantmentWeightToVector(cWeightedEnchantments & a_Enchantments, int a_Weight, int a_EnchantmentID, int a_EnchantmentLevel); + + /** Remove the entire enchantment (with weight) from the vector */ + static void RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, int a_EnchantmentID); - /// Returns true if a_Other doesn't contain exactly the same enchantments and levels + /** Remove the entire enchantment (with weight) from the vector */ + static void RemoveEnchantmentWeightFromVector(cWeightedEnchantments & a_Enchantments, const cEnchantments & a_Enchantment); + + /** Check enchantment conflicts from enchantments from the vector */ + static void CheckEnchantmentConflictsFromVector(cWeightedEnchantments & a_Enchantments, cEnchantments a_FirstEnchantment); + + /** Gets random enchantment from Vector and returns it */ + static cEnchantments GetRandomEnchantmentFromVector(cWeightedEnchantments & a_Enchantments); + + /** Returns true if a_Other doesn't contain exactly the same enchantments and levels */ bool operator !=(const cEnchantments & a_Other) const; - /// Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") + /** Writes the enchantments into the specified NBT writer; begins with the LIST tag of the specified name ("ench" or "StoredEnchantments") */ friend void EnchantmentSerializer::WriteToNBTCompound(cEnchantments const& a_Enchantments, cFastNBTWriter & a_Writer, const AString & a_ListTagName); - /// Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) + /** Reads the enchantments from the specified NBT list tag (ench or StoredEnchantments) */ friend void EnchantmentSerializer::ParseFromNBT(cEnchantments& a_Enchantments, const cParsedNBT & a_NBT, int a_EnchListTagIdx); - + protected: - /// Maps enchantment ID -> enchantment level + /** Maps enchantment ID -> enchantment level */ typedef std::map<int, int> cMap; - /// Currently stored enchantments + /** Currently stored enchantments */ cMap m_Enchantments; } ; // tolua_export +// Define the cWeightedEnchantment struct for the Enchanting System to store the EnchantmentWeights: +struct cWeightedEnchantment +{ + int m_Weight; + cEnchantments m_Enchantments; +}; + + + diff --git a/src/Endianness.h b/src/Endianness.h index 86eb369f5..78f9a5d99 100644 --- a/src/Endianness.h +++ b/src/Endianness.h @@ -1,12 +1,14 @@ #pragma once +#define ntohll(x) ((((UInt64)ntohl((u_long)x)) << 32) + ntohl(x >> 32)) + // Changes endianness -inline unsigned long long HostToNetwork8(const void* a_Value ) +inline UInt64 HostToNetwork8(const void * a_Value) { unsigned long long __HostToNetwork8; memcpy( &__HostToNetwork8, a_Value, sizeof( __HostToNetwork8 ) ); @@ -18,7 +20,7 @@ inline unsigned long long HostToNetwork8(const void* a_Value ) -inline unsigned int HostToNetwork4(const void* a_Value ) +inline UInt32 HostToNetwork4(const void* a_Value ) { unsigned int __HostToNetwork4; memcpy( &__HostToNetwork4, a_Value, sizeof( __HostToNetwork4 ) ); @@ -30,11 +32,10 @@ inline unsigned int HostToNetwork4(const void* a_Value ) -inline double NetworkToHostDouble8(const void* a_Value ) +inline double NetworkToHostDouble8(const void * a_Value) { -#define ntohll(x) ((((unsigned long long)ntohl((u_long)x)) << 32) + ntohl(x >> 32)) - unsigned long long buf = 0;//(*(unsigned long long*)a_Value); - memcpy( &buf, a_Value, 8 ); + UInt64 buf = 0; + memcpy(&buf, a_Value, 8); buf = ntohll(buf); double x; memcpy(&x, &buf, sizeof(double)); @@ -45,23 +46,25 @@ inline double NetworkToHostDouble8(const void* a_Value ) -inline long long NetworkToHostLong8(const void * a_Value ) +inline Int64 NetworkToHostLong8(const void * a_Value) { - unsigned long long buf = *(unsigned long long*)a_Value; + UInt64 buf; + memcpy(&buf, a_Value, 8); buf = ntohll(buf); - return *reinterpret_cast<long long *>(&buf); + return *reinterpret_cast<Int64 *>(&buf); } -inline float NetworkToHostFloat4(const void* a_Value ) +inline float NetworkToHostFloat4(const void * a_Value) { - u_long buf = *(u_long*)a_Value; - buf = ntohl( buf ); - float x = 0; - memcpy( &x, &buf, sizeof(float) ); + UInt32 buf; + float x; + memcpy(&buf, a_Value, 4); + buf = ntohl(buf); + memcpy(&x, &buf, sizeof(float)); return x; } diff --git a/src/Entities/ArrowEntity.cpp b/src/Entities/ArrowEntity.cpp new file mode 100644 index 000000000..8d2569125 --- /dev/null +++ b/src/Entities/ArrowEntity.cpp @@ -0,0 +1,194 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Player.h" +#include "ArrowEntity.h" +#include "../Chunk.h" + + + + + +cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), + m_PickupState(psNoPickup), + m_DamageCoeff(2), + m_IsCritical(false), + m_Timer(0), + m_HitGroundTimer(0), + m_HasTeleported(false), + m_bIsCollected(false), + m_HitBlockPos(Vector3i(0, 0, 0)) +{ + SetSpeed(a_Speed); + SetMass(0.1); + SetYawFromSpeed(); + SetPitchFromSpeed(); + LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", + m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), + GetYaw(), GetPitch() + ); +} + + + + + +cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : + super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), + m_PickupState(psInSurvivalOrCreative), + m_DamageCoeff(2), + m_IsCritical((a_Force >= 1)), + m_Timer(0), + m_HitGroundTimer(0), + m_HasTeleported(false), + m_bIsCollected(false), + m_HitBlockPos(0, 0, 0) +{ +} + + + + + +bool cArrowEntity::CanPickup(const cPlayer & a_Player) const +{ + switch (m_PickupState) + { + case psNoPickup: return false; + case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative()); + case psInCreative: return a_Player.IsGameModeCreative(); + } + ASSERT(!"Unhandled pickup state"); + return false; +} + + + + + +void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + if (a_HitFace == BLOCK_FACE_NONE) { return; } + + super::OnHitSolidBlock(a_HitPos, a_HitFace); + int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; + + switch (a_HitFace) + { + case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed + case BLOCK_FACE_YM: + { + break; + } + default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); + } + + m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); + + // Broadcast arrow hit sound + m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); +} + + + + + +void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) + { + // Not an entity that interacts with an arrow + return; + } + + int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); + if (m_IsCritical) + { + Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); + } + a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); + + // Broadcast successful hit sound + m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + + Destroy(); +} + + + + + +void cArrowEntity::CollectedBy(cPlayer * a_Dest) +{ + if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest))) + { + int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); + if (NumAdded > 0) // Only play effects if there was space in inventory + { + m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest); + // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) + m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); + m_bIsCollected = true; + } + } +} + + + + + +void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + m_Timer += a_Dt; + + if (m_bIsCollected) + { + if (m_Timer > 500.f) // 0.5 seconds + { + Destroy(); + return; + } + } + else if (m_Timer > 1000 * 60 * 5) // 5 minutes + { + Destroy(); + return; + } + + if (m_IsInGround) + { + // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL + // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) + // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync + // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position + + if (!m_HasTeleported) // Sent a teleport already, don't do again + { + if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case + { + m_World->BroadcastTeleportEntity(*this); + m_HasTeleported = true; + } + else + { + m_HitGroundTimer += a_Dt; + } + } + + int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; + int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; + cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); + + if (Chunk == NULL) + { + // Inside an unloaded chunk, abort + return; + } + + if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed? + { + m_IsInGround = false; // Yes, begin simulating physics again + } + } +} diff --git a/src/Entities/ArrowEntity.h b/src/Entities/ArrowEntity.h new file mode 100644 index 000000000..1fe3032ee --- /dev/null +++ b/src/Entities/ArrowEntity.h @@ -0,0 +1,96 @@ +// +// ArrowEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cArrowEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field + enum ePickupState + { + psNoPickup = 0, + psInSurvivalOrCreative = 1, + psInCreative = 2, + } ; + + // tolua_end + + CLASS_PROTODEF(cArrowEntity); + + /// Creates a new arrow with psNoPickup state and default damage modifier coeff + cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + + /// Creates a new arrow as shot by a player, initializes it from the player object + cArrowEntity(cPlayer & a_Player, double a_Force); + + // tolua_begin + + /// Returns whether the arrow can be picked up by players + ePickupState GetPickupState(void) const { return m_PickupState; } + + /// Sets a new pickup state + void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; } + + /// Returns the damage modifier coeff. + double GetDamageCoeff(void) const { return m_DamageCoeff; } + + /// Sets the damage modifier coeff + void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } + + /// Returns true if the specified player can pick the arrow up + bool CanPickup(const cPlayer & a_Player) const; + + /// Returns true if the arrow is set as critical + bool IsCritical(void) const { return m_IsCritical; } + + /// Sets the IsCritical flag + void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } + + // tolua_end + +protected: + + /// Determines when the arrow can be picked up by players + ePickupState m_PickupState; + + /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow + double m_DamageCoeff; + + /// If true, the arrow deals more damage + bool m_IsCritical; + + /// Timer for pickup collection animation or five minute timeout + float m_Timer; + + /// Timer for client arrow position confirmation via TeleportEntity + float m_HitGroundTimer; + + // Whether the arrow has already been teleported into the proper position in the ground. + bool m_HasTeleported; + + /// If true, the arrow is in the process of being collected - don't go to anyone else + bool m_bIsCollected; + + /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air + Vector3i m_HitBlockPos; + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + virtual void CollectedBy(cPlayer * a_Player) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + +}; // tolua_export diff --git a/src/Entities/Boat.cpp b/src/Entities/Boat.cpp index 94b24c5af..31bfe3dc3 100644 --- a/src/Entities/Boat.cpp +++ b/src/Entities/Boat.cpp @@ -33,9 +33,12 @@ void cBoat::SpawnOn(cClientHandle & a_ClientHandle) -void cBoat::DoTakeDamage(TakeDamageInfo & TDI) +bool cBoat::DoTakeDamage(TakeDamageInfo & TDI) { - super::DoTakeDamage(TDI); + if (!super::DoTakeDamage(TDI)) + { + return false; + } if (GetHealth() == 0) { @@ -50,6 +53,7 @@ void cBoat::DoTakeDamage(TakeDamageInfo & TDI) } Destroy(true); } + return true; } @@ -122,5 +126,3 @@ void cBoat::HandleSpeedFromAttachee(float a_Forward, float a_Sideways) AddSpeed(ToAddSpeed); } - -
\ No newline at end of file diff --git a/src/Entities/Boat.h b/src/Entities/Boat.h index c4c9afe7a..0fcfbd602 100644 --- a/src/Entities/Boat.h +++ b/src/Entities/Boat.h @@ -26,7 +26,7 @@ public: // cEntity overrides: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void OnRightClicked(cPlayer & a_Player) override; - virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override; diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt index 85cc45494..205cb2cca 100644 --- a/src/Entities/CMakeLists.txt +++ b/src/Entities/CMakeLists.txt @@ -6,6 +6,9 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Entities ${SOURCE}) + +target_link_libraries(Entities WorldStorage) diff --git a/src/Entities/Effects.h b/src/Entities/Effects.h index e7611847d..baf3302fb 100644 --- a/src/Entities/Effects.h +++ b/src/Entities/Effects.h @@ -27,4 +27,4 @@ enum ENUM_ENTITY_EFFECT E_EFFECT_ABSORPTION = 22, E_EFFECT_SATURATION = 23, } ; -// tolua_end
\ No newline at end of file +// tolua_end diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 221cbbea7..1226a2319 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Entity.h" @@ -10,7 +11,6 @@ #include "../Simulator/FluidSimulator.h" #include "../Bindings/PluginManager.h" #include "../Tracer.h" -#include "Minecart.h" #include "Player.h" @@ -32,19 +32,14 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Attachee(NULL) , m_bDirtyHead(true) , m_bDirtyOrientation(true) - , m_bDirtyPosition(true) - , m_bDirtySpeed(true) - , m_bOnGround( false ) - , m_Gravity( -9.81f ) - , m_LastPosX( 0.0 ) - , m_LastPosY( 0.0 ) - , m_LastPosZ( 0.0 ) - , m_TimeLastTeleportPacket(0) - , m_TimeLastMoveReltPacket(0) - , m_TimeLastSpeedPacket(0) + , m_bHasSentNoSpeed(true) + , m_bOnGround(false) + , m_Gravity(-9.81f) + , m_LastPos(a_X, a_Y, a_Z) , m_IsInitialized(false) , m_EntityType(a_EntityType) , m_World(NULL) + , m_IsFireproof(false) , m_TicksSinceLastBurnDamage(0) , m_TicksSinceLastLavaDamage(0) , m_TicksSinceLastFireDamage(0) @@ -52,13 +47,16 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_TicksSinceLastVoidDamage(0) , m_IsSwimming(false) , m_IsSubmerged(false) - , m_HeadYaw( 0.0 ) + , m_AirLevel(0) + , m_AirTickTimer(0) + , m_HeadYaw(0.0) , m_Rot(0.0, 0.0, 0.0) , m_Pos(a_X, a_Y, a_Z) , m_WaterSpeed(0, 0, 0) , m_Mass (0.001) // Default 1g , m_Width(a_Width) , m_Height(a_Height) + , m_InvulnerableTicks(0) { cCSLock Lock(m_CSCount); m_EntityCount++; @@ -293,27 +291,37 @@ void cEntity::SetPitchFromSpeed(void) -void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) { if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI)) { - return; + return false; } if (m_Health <= 0) { // Can't take damage if already dead - return; + return false; + } + + if (m_InvulnerableTicks > 0) + { + // Entity is invulnerable + return false; } if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) { + cPlayer * Player = (cPlayer *)a_TDI.Attacker; + // IsOnGround() only is false if the player is moving downwards - if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) + if (!Player->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) { a_TDI.FinalDamage += 2; m_World->BroadcastEntityAnimation(*this, 4); // Critical hit } + + Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); } m_Health -= (short)a_TDI.FinalDamage; @@ -325,17 +333,54 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_Health = 0; } - if (IsMob() || IsPlayer()) // Knockback for only players and mobs + if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs { - AddSpeed(a_TDI.Knockback * 2); + int KnockbackLevel = 0; + if (a_TDI.Attacker->GetEquippedWeapon().m_ItemType == E_ITEM_BOW) + { + KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchPunch); + } + else + { + KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); + } + + Vector3d additionalSpeed(0, 0, 0); + switch (KnockbackLevel) + { + case 1: + { + additionalSpeed.Set(5, .3, 5); + break; + } + case 2: + { + additionalSpeed.Set(8, .3, 8); + break; + } + default: + { + additionalSpeed.Set(2, .3, 2); + break; + } + } + AddSpeed(a_TDI.Knockback * additionalSpeed); } - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT); + m_World->BroadcastEntityStatus(*this, esGenericHurt); + + m_InvulnerableTicks = 10; if (m_Health <= 0) { KilledBy(a_TDI.Attacker); + + if (a_TDI.Attacker != NULL) + { + a_TDI.Attacker->Killed(this); + } } + return true; } @@ -380,11 +425,8 @@ int cEntity::GetRawDamageAgainst(const cEntity & a_Receiver) -int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) +bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType) { - // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover - - // Filter out damage types that are not protected by armor: // Ref.: http://www.minecraftwiki.net/wiki/Armor#Effects as of 2012_12_20 switch (a_DamageType) { @@ -399,9 +441,34 @@ int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_Dama case dtLightning: case dtPlugin: { - return 0; + return false; + } + + case dtAttack: + case dtArrowAttack: + case dtCactusContact: + case dtLavaContact: + case dtFireContact: + case dtEnderPearl: + case dtExplosion: + { + return true; } } + ASSERT(!"Invalid damage type!"); + return false; +} + + + + + +int cEntity::GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) +{ + // Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover + + // Filter out damage types that are not protected by armor: + if (!ArmorCoversAgainst(a_DamageType)) return 0; // Add up all armor points: // Ref.: http://www.minecraftwiki.net/wiki/Armor#Defense_points as of 2012_12_20 @@ -479,7 +546,7 @@ void cEntity::KilledBy(cEntity * a_Killer) GetDrops(Drops, a_Killer); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD); + m_World->BroadcastEntityStatus(*this, esGenericDead); } @@ -510,46 +577,61 @@ void cEntity::SetHealth(int a_Health) void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { + if (m_InvulnerableTicks > 0) + { + m_InvulnerableTicks--; + } + if (m_AttachedTo != NULL) { - if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5) + Vector3d DeltaPos = m_Pos - m_AttachedTo->GetPosition(); + if (DeltaPos.Length() > 0.5) { SetPosition(m_AttachedTo->GetPosition()); + + if (IsPlayer()) + { + cPlayer * Player = (cPlayer *)this; + Player->UpdateMovementStats(DeltaPos); + } } } else { - if (a_Chunk.IsValid()) + if (!a_Chunk.IsValid()) { - cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT); - - if ((NextChunk == NULL) || !NextChunk->IsValid()) - { - return; - } + return; + } - TickBurning(*NextChunk); + // Position changed -> super::Tick() called + GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, POSX_TOINT, POSZ_TOINT) - if (GetPosY() < VOID_BOUNDARY) - { - TickInVoid(*NextChunk); - } - else - { - m_TicksSinceLastVoidDamage = 0; - } + TickBurning(*NextChunk); - if (IsMob() || IsPlayer()) - { - // Set swimming state - SetSwimState(*NextChunk); + if (GetPosY() < VOID_BOUNDARY) + { + TickInVoid(*NextChunk); + } + else + { + m_TicksSinceLastVoidDamage = 0; + } - // Handle drowning - HandleAir(); - } + if (IsMob() || IsPlayer() || IsPickup() || IsExpOrb()) + { + DetectCacti(); + } + if (IsMob() || IsPlayer()) + { + // Set swimming state + SetSwimState(*NextChunk); - HandlePhysics(a_Dt, *NextChunk); + // Handle drowning + HandleAir(); } + + // None of the above functions change position, we remain in the chunk of NextChunk + HandlePhysics(a_Dt, *NextChunk); } } @@ -559,34 +641,30 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) { + int BlockX = POSX_TOINT; + int BlockY = POSY_TOINT; + int BlockZ = POSZ_TOINT; + + // Position changed -> super::HandlePhysics() called + GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ) + // TODO Add collision detection with entities. a_Dt /= 1000; // Convert from msec to sec - Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ()); - Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ()); - int BlockX = (int) floor(NextPos.x); - int BlockY = (int) floor(NextPos.y); - int BlockZ = (int) floor(NextPos.z); + Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ()); + Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ()); if ((BlockY >= cChunkDef::Height) || (BlockY < 0)) { - // Outside of the world - - cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); - // See if we can commit our changes. If not, we will discard them. - if (NextChunk != NULL) - { - SetSpeed(NextSpeed); - NextPos += (NextSpeed * a_Dt); - SetPosition(NextPos); - } - + // Outside of the world + AddSpeedY(m_Gravity * a_Dt); + AddPosition(GetSpeed() * a_Dt); return; } - int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width); - int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width); - BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ ); - BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; + int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width); + int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width); + BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ ); + BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block { if (m_bOnGround) // check if it's still on the ground @@ -616,7 +694,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) bool IsNoAirSurrounding = true; for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) + if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock)) { // The pickup is too close to an unloaded chunk, bail out of any physics handling return; @@ -730,30 +808,43 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) NextSpeed += m_WaterSpeed; - if( NextSpeed.SqrLength() > 0.f ) + if (NextSpeed.SqrLength() > 0.f) { - cTracer Tracer( GetWorld() ); - bool HasHit = Tracer.Trace( NextPos, NextSpeed, 2 ); - if (HasHit) // Oh noez! we hit something + cTracer Tracer(GetWorld()); + // Distance traced is an integer, so we round up from the distance we should go (Speed * Delta), else we will encounter collision detection failurse + int DistanceToTrace = (int)(ceil((NextSpeed * a_Dt).SqrLength()) * 2); + bool HasHit = Tracer.Trace(NextPos, NextSpeed, DistanceToTrace); + + if (HasHit) { - // Set to hit position + // Oh noez! We hit something: verify that the (hit position - current) was smaller or equal to the (position that we should travel without obstacles - current) + // This is because previously, we traced with a length that was rounded up (due to integer limitations), and in the case that something was hit, we don't want to overshoot our projected movement if ((Tracer.RealHit - NextPos).SqrLength() <= (NextSpeed * a_Dt).SqrLength()) { + // Block hit was within our projected path + // Begin by stopping movement in the direction that we hit something. The Normal is the line perpendicular to a 2D face and in this case, stores what block face was hit through either -1 or 1. + // For example: HitNormal.y = -1 : BLOCK_FACE_YM; HitNormal.y = 1 : BLOCK_FACE_YP if (Tracer.HitNormal.x != 0.f) NextSpeed.x = 0.f; if (Tracer.HitNormal.y != 0.f) NextSpeed.y = 0.f; if (Tracer.HitNormal.z != 0.f) NextSpeed.z = 0.f; - if (Tracer.HitNormal.y > 0) // means on ground + if (Tracer.HitNormal.y == 1) // Hit BLOCK_FACE_YP, we are on the ground { m_bOnGround = true; } - NextPos.Set(Tracer.RealHit.x,Tracer.RealHit.y,Tracer.RealHit.z); - NextPos.x += Tracer.HitNormal.x * 0.3f; - NextPos.y += Tracer.HitNormal.y * 0.05f; // Any larger produces entity vibration-upon-the-spot - NextPos.z += Tracer.HitNormal.z * 0.3f; + + // Now, set our position to the hit block (i.e. move part way along our intended trajectory) + NextPos.Set(Tracer.RealHit.x, Tracer.RealHit.y, Tracer.RealHit.z); + NextPos.x += Tracer.HitNormal.x * 0.1; + NextPos.y += Tracer.HitNormal.y * 0.05; + NextPos.z += Tracer.HitNormal.z * 0.1; } else { + // We have hit a block but overshot our intended trajectory, move normally, safe in the warm cocoon of knowledge that we won't appear to teleport forwards on clients, + // and that this piece of software will come to be hailed as the epitome of performance and functionality in C++, never before seen, and of such a like that will never + // be henceforth seen again in the time of programmers and man alike + // </&sensationalist> NextPos += (NextSpeed * a_Dt); } } @@ -764,20 +855,8 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) } } - BlockX = (int) floor(NextPos.x); - BlockZ = (int) floor(NextPos.z); - - cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); - // See if we can commit our changes. If not, we will discard them. - if (NextChunk != NULL) - { - if (NextPos.x != GetPosX()) SetPosX(NextPos.x); - if (NextPos.y != GetPosY()) SetPosY(NextPos.y); - if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z); - if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x); - if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y); - if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z); - } + SetPosition(NextPos); + SetSpeed(NextSpeed); } @@ -788,6 +867,14 @@ void cEntity::TickBurning(cChunk & a_Chunk) { // Remember the current burning state: bool HasBeenBurning = (m_TicksLeftBurning > 0); + + if (m_World->IsWeatherWet()) + { + if (POSY_TOINT > m_World->GetHeight(POSX_TOINT, POSZ_TOINT)) + { + m_TicksLeftBurning = 0; + } + } // Do the burning damage: if (m_TicksLeftBurning > 0) @@ -795,7 +882,10 @@ void cEntity::TickBurning(cChunk & a_Chunk) m_TicksSinceLastBurnDamage++; if (m_TicksSinceLastBurnDamage >= BURN_TICKS_PER_DAMAGE) { - TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0); + if (!m_IsFireproof) + { + TakeDamage(dtOnFire, NULL, BURN_DAMAGE, 0); + } m_TicksSinceLastBurnDamage = 0; } m_TicksLeftBurning--; @@ -806,7 +896,7 @@ void cEntity::TickBurning(cChunk & a_Chunk) int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width; int MinRelZ = (int)floor(GetPosZ() - m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width; int MaxRelZ = (int)floor(GetPosZ() + m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width; - int MinY = std::max(0, std::min(cChunkDef::Height - 1, (int)floor(GetPosY()))); + int MinY = std::max(0, std::min(cChunkDef::Height - 1, POSY_TOINT)); int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height))); bool HasWater = false; bool HasLava = false; @@ -863,7 +953,10 @@ void cEntity::TickBurning(cChunk & a_Chunk) m_TicksSinceLastLavaDamage++; if (m_TicksSinceLastLavaDamage >= LAVA_TICKS_PER_DAMAGE) { - TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0); + if (!m_IsFireproof) + { + TakeDamage(dtLavaContact, NULL, LAVA_DAMAGE, 0); + } m_TicksSinceLastLavaDamage = 0; } } @@ -881,7 +974,10 @@ void cEntity::TickBurning(cChunk & a_Chunk) m_TicksSinceLastFireDamage++; if (m_TicksSinceLastFireDamage >= FIRE_TICKS_PER_DAMAGE) { - TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0); + if (!m_IsFireproof) + { + TakeDamage(dtFireContact, NULL, FIRE_DAMAGE, 0); + } m_TicksSinceLastFireDamage = 0; } } @@ -922,6 +1018,27 @@ void cEntity::TickInVoid(cChunk & a_Chunk) +void cEntity::DetectCacti(void) +{ + int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; + double w = m_Width / 2; + if ( + ((Y > 0) && (Y < cChunkDef::Height)) && + ((((X + 1) - GetPosX() < w) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) || + ((GetPosX() - X < w) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) || + (((Z + 1) - GetPosZ() < w) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS)) || + ((GetPosZ() - Z < w) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS)) || + (((GetPosY() - Y < 1) && (GetWorld()->GetBlock(X, Y, Z) == E_BLOCK_CACTUS)))) + ) + { + TakeDamage(dtCactusContact, NULL, 1, 0); + } +} + + + + + void cEntity::SetSwimState(cChunk & a_Chunk) { int RelY = (int)floor(GetPosY() + 0.1); @@ -941,9 +1058,9 @@ void cEntity::SetSwimState(cChunk & a_Chunk) { // This sometimes happens on Linux machines // Ref.: http://forum.mc-server.org/showthread.php?tid=1244 - LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}", - RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ() - ); + LOGD("SetSwimState failure: RelX = %d, RelZ = %d, Pos = %.02f, %.02f}", + RelX, RelY, GetPosX(), GetPosZ() + ); m_IsSwimming = false; m_IsSubmerged = false; return; @@ -981,13 +1098,13 @@ void cEntity::HandleAir(void) } else { - m_AirTickTimer -= 1; + m_AirTickTimer--; } } else { // Reduce air supply - m_AirLevel -= 1; + m_AirLevel--; } } else @@ -1040,6 +1157,16 @@ void cEntity::SetMaxHealth(int a_MaxHealth) +/// Sets whether the entity is fireproof +void cEntity::SetIsFireproof(bool a_IsFireproof) +{ + m_IsFireproof = a_IsFireproof; +} + + + + + /// Puts the entity on fire for the specified amount of ticks void cEntity::StartBurning(int a_TicksLeftBurning) { @@ -1099,72 +1226,70 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) { - //We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks - if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2)) - { - m_World->BroadcastEntityVelocity(*this,a_Exclude); - m_bDirtySpeed = false; - m_TimeLastSpeedPacket = m_World->GetWorldAge(); - } - - //Have to process position related packets this every two ticks - if (m_World->GetWorldAge() % 2 == 0) + // Process packet sending every two ticks + if (GetWorld()->GetWorldAge() % 2 == 0) { - int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0)); - int DiffY = (int) (floor(GetPosY() * 32.0) - floor(m_LastPosY * 32.0)); - int DiffZ = (int) (floor(GetPosZ() * 32.0) - floor(m_LastPosZ * 32.0)); - Int64 DiffTeleportPacket = m_World->GetWorldAge() - m_TimeLastTeleportPacket; - // 4 blocks is max Relative So if the Diff is greater than 127 or. Send an absolute position every 20 seconds - if (DiffTeleportPacket >= 400 || - ((DiffX > 127) || (DiffX < -128) || - (DiffY > 127) || (DiffY < -128) || - (DiffZ > 127) || (DiffZ < -128))) + double SpeedSqr = GetSpeed().SqrLength(); + if (SpeedSqr == 0.0) { - // - m_World->BroadcastTeleportEntity(*this,a_Exclude); - m_TimeLastTeleportPacket = m_World->GetWorldAge(); - m_TimeLastMoveReltPacket = m_TimeLastTeleportPacket; //Must synchronize. - m_LastPosX = GetPosX(); - m_LastPosY = GetPosY(); - m_LastPosZ = GetPosZ(); - m_bDirtyPosition = false; - m_bDirtyOrientation = false; + // Speed is zero, send this to clients once only as well as an absolute position + if (!m_bHasSentNoSpeed) + { + m_World->BroadcastEntityVelocity(*this, a_Exclude); + m_World->BroadcastTeleportEntity(*this, a_Exclude); + m_bHasSentNoSpeed = true; + } } else { - Int64 DiffMoveRelPacket = m_World->GetWorldAge() - m_TimeLastMoveReltPacket; - //if the change is big enough. - if ((abs(DiffX) >= 4 || abs(DiffY) >= 4 || abs(DiffZ) >= 4 || DiffMoveRelPacket >= 60) && m_bDirtyPosition) + // Movin' + m_World->BroadcastEntityVelocity(*this, a_Exclude); + m_bHasSentNoSpeed = false; + } + + // TODO: Pickups move disgracefully if relative move packets are sent as opposed to just velocity. Have a system to send relmove only when SetPosXXX() is called with a large difference in position + int DiffX = (int)(floor(GetPosX() * 32.0) - floor(m_LastPos.x * 32.0)); + int DiffY = (int)(floor(GetPosY() * 32.0) - floor(m_LastPos.y * 32.0)); + int DiffZ = (int)(floor(GetPosZ() * 32.0) - floor(m_LastPos.z * 32.0)); + + if ((DiffX != 0) || (DiffY != 0) || (DiffZ != 0)) // Have we moved? + { + if ((abs(DiffX) <= 127) && (abs(DiffY) <= 127) && (abs(DiffZ) <= 127)) // Limitations of a Byte { + // Difference within Byte limitations, use a relative move packet if (m_bDirtyOrientation) { - m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude); + m_World->BroadcastEntityRelMoveLook(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude); m_bDirtyOrientation = false; } else { - m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ,a_Exclude); + m_World->BroadcastEntityRelMove(*this, (char)DiffX, (char)DiffY, (char)DiffZ, a_Exclude); } - m_LastPosX = GetPosX(); - m_LastPosY = GetPosY(); - m_LastPosZ = GetPosZ(); - m_bDirtyPosition = false; - m_TimeLastMoveReltPacket = m_World->GetWorldAge(); + // Clients seem to store two positions, one for the velocity packet and one for the teleport/relmove packet + // The latter is only changed with a relmove/teleport, and m_LastPos stores this position + m_LastPos = GetPosition(); } else { - if (m_bDirtyOrientation) - { - m_World->BroadcastEntityLook(*this,a_Exclude); - m_bDirtyOrientation = false; - } - } + // Too big a movement, do a teleport + m_World->BroadcastTeleportEntity(*this, a_Exclude); + m_LastPos = GetPosition(); // See above + m_bDirtyOrientation = false; + } } + if (m_bDirtyHead) { - m_World->BroadcastEntityHeadLook(*this,a_Exclude); + m_World->BroadcastEntityHeadLook(*this, a_Exclude); m_bDirtyHead = false; } + if (m_bDirtyOrientation) + { + // Send individual update in case above (sending with rel-move packet) wasn't done + GetWorld()->BroadcastEntityLook(*this, a_Exclude); + m_bDirtyOrientation = false; + } } } @@ -1304,7 +1429,7 @@ void cEntity::SetRoll(double a_Roll) void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) { m_Speed.Set(a_SpeedX, a_SpeedY, a_SpeedZ); - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1314,7 +1439,7 @@ void cEntity::SetSpeed(double a_SpeedX, double a_SpeedY, double a_SpeedZ) void cEntity::SetSpeedX(double a_SpeedX) { m_Speed.x = a_SpeedX; - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1324,7 +1449,7 @@ void cEntity::SetSpeedX(double a_SpeedX) void cEntity::SetSpeedY(double a_SpeedY) { m_Speed.y = a_SpeedY; - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1334,7 +1459,7 @@ void cEntity::SetSpeedY(double a_SpeedY) void cEntity::SetSpeedZ(double a_SpeedZ) { m_Speed.z = a_SpeedZ; - m_bDirtySpeed = true; + WrapSpeed(); } @@ -1354,7 +1479,7 @@ void cEntity::SetWidth(double a_Width) void cEntity::AddPosX(double a_AddPosX) { m_Pos.x += a_AddPosX; - m_bDirtyPosition = true; + } @@ -1363,7 +1488,7 @@ void cEntity::AddPosX(double a_AddPosX) void cEntity::AddPosY(double a_AddPosY) { m_Pos.y += a_AddPosY; - m_bDirtyPosition = true; + } @@ -1372,7 +1497,7 @@ void cEntity::AddPosY(double a_AddPosY) void cEntity::AddPosZ(double a_AddPosZ) { m_Pos.z += a_AddPosZ; - m_bDirtyPosition = true; + } @@ -1383,7 +1508,7 @@ void cEntity::AddPosition(double a_AddPosX, double a_AddPosY, double a_AddPosZ) m_Pos.x += a_AddPosX; m_Pos.y += a_AddPosY; m_Pos.z += a_AddPosZ; - m_bDirtyPosition = true; + } @@ -1393,8 +1518,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed { m_Speed.x += a_AddSpeedX; m_Speed.y += a_AddSpeedY; - m_Speed.z += a_AddSpeedZ; - m_bDirtySpeed = true; + m_Speed.z += a_AddSpeedZ; WrapSpeed(); } @@ -1404,8 +1528,7 @@ void cEntity::AddSpeed(double a_AddSpeedX, double a_AddSpeedY, double a_AddSpeed void cEntity::AddSpeedX(double a_AddSpeedX) { - m_Speed.x += a_AddSpeedX; - m_bDirtySpeed = true; + m_Speed.x += a_AddSpeedX; WrapSpeed(); } @@ -1415,8 +1538,7 @@ void cEntity::AddSpeedX(double a_AddSpeedX) void cEntity::AddSpeedY(double a_AddSpeedY) { - m_Speed.y += a_AddSpeedY; - m_bDirtySpeed = true; + m_Speed.y += a_AddSpeedY; WrapSpeed(); } @@ -1426,8 +1548,7 @@ void cEntity::AddSpeedY(double a_AddSpeedY) void cEntity::AddSpeedZ(double a_AddSpeedZ) { - m_Speed.z += a_AddSpeedZ; - m_bDirtySpeed = true; + m_Speed.z += a_AddSpeedZ; WrapSpeed(); } @@ -1469,7 +1590,7 @@ void cEntity::SteerVehicle(float a_Forward, float a_Sideways) Vector3d cEntity::GetLookVector(void) const { Matrix4d m; - m.Init(Vector3f(), 0, m_Rot.x, -m_Rot.y); + m.Init(Vector3d(), 0, m_Rot.x, -m_Rot.y); Vector3d Look = m.Transform(Vector3d(0, 0, 1)); return Look; } @@ -1482,8 +1603,7 @@ Vector3d cEntity::GetLookVector(void) const // Set position void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ) { - m_Pos.Set(a_PosX, a_PosY, a_PosZ); - m_bDirtyPosition = true; + m_Pos.Set(a_PosX, a_PosY, a_PosZ); } @@ -1492,8 +1612,7 @@ void cEntity::SetPosition(double a_PosX, double a_PosY, double a_PosZ) void cEntity::SetPosX(double a_PosX) { - m_Pos.x = a_PosX; - m_bDirtyPosition = true; + m_Pos.x = a_PosX; } @@ -1502,8 +1621,7 @@ void cEntity::SetPosX(double a_PosX) void cEntity::SetPosY(double a_PosY) { - m_Pos.y = a_PosY; - m_bDirtyPosition = true; + m_Pos.y = a_PosY; } @@ -1513,7 +1631,6 @@ void cEntity::SetPosY(double a_PosY) void cEntity::SetPosZ(double a_PosZ) { m_Pos.z = a_PosZ; - m_bDirtyPosition = true; } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index e41f74b09..0c393c0f5 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -32,6 +32,8 @@ #define POSZ_TOINT (int)floor(GetPosZ()) #define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT) +#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); if ((ChunkVarName == NULL) || !ChunkVarName->IsValid()) { return; } + @@ -88,23 +90,42 @@ public: } ; // tolua_end - - enum + + enum eEntityStatus { - ENTITY_STATUS_HURT = 2, - ENTITY_STATUS_DEAD = 3, - ENTITY_STATUS_WOLF_TAMING = 6, - ENTITY_STATUS_WOLF_TAMED = 7, - ENTITY_STATUS_WOLF_SHAKING = 8, - ENTITY_STATUS_EATING_ACCEPTED = 9, - ENTITY_STATUS_SHEEP_EATING = 10, - ENTITY_STATUS_GOLEM_ROSING = 11, - ENTITY_STATUS_VILLAGER_HEARTS = 12, - ENTITY_STATUS_VILLAGER_ANGRY = 13, - ENTITY_STATUS_VILLAGER_HAPPY = 14, - ENTITY_STATUS_WITCH_MAGICKING = 15, + // TODO: Investiagate 0, 1, and 5 as Wiki.vg is not certain + + // Entity becomes coloured red + esGenericHurt = 2, + // Entity plays death animation (entity falls to ground) + esGenericDead = 3, + // Iron Golem plays attack animation (arms lift and fall) + esIronGolemAttacking = 4, + // Wolf taming particles spawn (smoke) + esWolfTaming = 6, + // Wolf tamed particles spawn (hearts) + esWolfTamed = 7, + // Wolf plays water removal animation (shaking and water particles) + esWolfDryingWater = 8, + // Informs client that eating was accepted + esPlayerEatingAccepted = 9, + // Sheep plays eating animation (head lowers to ground) + esSheepEating = 10, + // Iron Golem holds gift to villager children + esIronGolemGivingPlant = 11, + // Villager spawns heart particles + esVillagerBreeding = 12, + // Villager spawns thunderclound particles + esVillagerAngry = 13, + // Villager spawns green crosses + esVillagerHappy = 14, + // Witch spawns magic particle (TODO: investigation into what this is) + esWitchMagicking = 15, + // It seems 16 (zombie conversion) is now done with metadata - ENTITY_STATUS_FIREWORK_EXPLODE= 17, + + // Informs client to explode a firework based on its metadata + esFireworkExploding = 17, } ; enum @@ -118,7 +139,8 @@ public: BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have DROWNING_TICKS = 20, ///< Number of ticks per heart of damage - VOID_BOUNDARY = -46 ///< At what position Y to begin applying void damage + VOID_BOUNDARY = -46, ///< At what position Y to begin applying void damage + FALL_DAMAGE_HEIGHT = 4 ///< At what position Y fall damage is applied } ; cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); @@ -159,7 +181,7 @@ public: cWorld * GetWorld(void) const { return m_World; } - double GetHeadYaw (void) const { return m_HeadYaw; } + double GetHeadYaw (void) const { return m_HeadYaw; } // In degrees double GetHeight (void) const { return m_Height; } double GetMass (void) const { return m_Mass; } const Vector3d & GetPosition (void) const { return m_Pos; } @@ -167,9 +189,9 @@ public: double GetPosY (void) const { return m_Pos.y; } double GetPosZ (void) const { return m_Pos.z; } const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components - double GetYaw (void) const { return m_Rot.x; } - double GetPitch (void) const { return m_Rot.y; } - double GetRoll (void) const { return m_Rot.z; } + double GetYaw (void) const { return m_Rot.x; } // In degrees, [-180, +180) + double GetPitch (void) const { return m_Rot.y; } // In degrees, [-180, +180), but normal client clips to [-90, +90] + double GetRoll (void) const { return m_Rot.z; } // In degrees, unused in current client Vector3d GetLookVector(void) const; const Vector3d & GetSpeed (void) const { return m_Speed; } double GetSpeedX (void) const { return m_Speed.x; } @@ -189,9 +211,9 @@ public: void SetPosition(double a_PosX, double a_PosY, double a_PosZ); void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); } void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components - void SetYaw (double a_Yaw); - void SetPitch (double a_Pitch); - void SetRoll (double a_Roll); + void SetYaw (double a_Yaw); // In degrees, normalizes to [-180, +180) + void SetPitch (double a_Pitch); // In degrees, normalizes to [-180, +180) + void SetRoll (double a_Roll); // In degrees, normalizes to [-180, +180) void SetSpeed (double a_SpeedX, double a_SpeedY, double a_SpeedZ); void SetSpeed (const Vector3d & a_Speed) { SetSpeed(a_Speed.x, a_Speed.y, a_Speed.z); } void SetSpeedX (double a_SpeedX); @@ -240,14 +262,19 @@ public: // tolua_end - /// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied - virtual void DoTakeDamage(TakeDamageInfo & a_TDI); + /** Makes this entity take damage specified in the a_TDI. + The TDI is sent through plugins first, then applied. + If it returns false, the entity hasn't receive any damage. */ + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI); // tolua_begin /// Returns the hitpoints that this pawn can deal to a_Receiver using its equipped items virtual int GetRawDamageAgainst(const cEntity & a_Receiver); + /** Returns whether armor will protect against the passed damage type **/ + virtual bool ArmorCoversAgainst(eDamageType a_DamageType); + /// Returns the hitpoints out of a_RawDamage that the currently equipped armor would cover virtual int GetArmorCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_RawDamage); @@ -272,6 +299,9 @@ public: /// Called when the health drops below zero. a_Killer may be NULL (environmental damage) virtual void KilledBy(cEntity * a_Killer); + /// Called when the entity kills another entity + virtual void Killed(cEntity * a_Victim) {} + /// Heals the specified amount of HPs void Heal(int a_HitPoints); @@ -290,6 +320,9 @@ public: /// Updates the state related to this entity being on fire virtual void TickBurning(cChunk & a_Chunk); + + /** Detects the time for application of cacti damage */ + virtual void DetectCacti(void); /// Handles when the entity is in the void virtual void TickInVoid(cChunk & a_Chunk); @@ -307,6 +340,11 @@ public: int GetMaxHealth(void) const { return m_MaxHealth; } + /// Sets whether the entity is fireproof + void SetIsFireproof(bool a_IsFireproof); + + bool IsFireproof(void) const { return m_IsFireproof; } + /// Puts the entity on fire for the specified amount of ticks void StartBurning(int a_TicksLeftBurning); @@ -364,6 +402,12 @@ public: virtual bool IsSubmerged(void) const{ return m_IsSubmerged; } /** Gets remaining air of a monster */ int GetAirLevel(void) const { return m_AirLevel; } + + /** Gets the invulnerable ticks from the entity */ + int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; } + + /** Set the invulnerable ticks from the entity */ + void SetInvulnerableTicks(int a_InvulnerableTicks) { m_InvulnerableTicks = a_InvulnerableTicks; } // tolua_end @@ -392,27 +436,37 @@ protected: /// The entity which is attached to this entity (rider), NULL if none cEntity * m_Attachee; - // Flags that signal that we haven't updated the clients with the latest. - bool m_bDirtyHead; - bool m_bDirtyOrientation; - bool m_bDirtyPosition; - bool m_bDirtySpeed; - - bool m_bOnGround; - float m_Gravity; + /** Stores whether head yaw has been set manually */ + bool m_bDirtyHead; + + /** Stores whether our yaw/pitch/roll (body orientation) has been set manually */ + bool m_bDirtyOrientation; - // Last Position. - double m_LastPosX, m_LastPosY, m_LastPosZ; + /** Stores whether we have sent a Velocity packet with a speed of zero (no speed) to the client + Ensures that said packet is sent only once */ + bool m_bHasSentNoSpeed; - // This variables keep track of the last time a packet was sent - Int64 m_TimeLastTeleportPacket, m_TimeLastMoveReltPacket, m_TimeLastSpeedPacket; // In ticks + /** Stores if the entity is on the ground */ + bool m_bOnGround; + + /** Stores gravity that is applied to an entity every tick + For realistic effects, this should be negative. For spaaaaaaace, this can be zero or even positive */ + float m_Gravity; + + /** Last position sent to client via the Relative Move or Teleport packets (not Velocity) + Only updated if cEntity::BroadcastMovementUpdate() is called! */ + Vector3d m_LastPos; - bool m_IsInitialized; // Is set to true when it's initialized, until it's destroyed (Initialize() till Destroy() ) + /** True when entity is initialised (Initialize()) and false when destroyed pending deletion (Destroy()) */ + bool m_IsInitialized; eEntityType m_EntityType; cWorld * m_World; + /// Whether the entity is capable of taking fire or lava damage. + bool m_IsFireproof; + /// Time, in ticks, since the last damage dealt by being on fire. Valid only if on fire (IsOnFire()) int m_TicksSinceLastBurnDamage; @@ -428,12 +482,14 @@ protected: /// Time, in ticks, since the last damage dealt by the void. Reset to zero when moving out of the void. int m_TicksSinceLastVoidDamage; + virtual void Destroyed(void) {} // Called after the entity has been destroyed void SetWorld(cWorld * a_World) { m_World = a_World; } /** Called in each tick to handle air-related processing i.e. drowning */ virtual void HandleAir(); + /** Called once per tick to set IsSwimming and IsSubmerged */ virtual void SetSwimState(cChunk & a_Chunk); @@ -445,29 +501,33 @@ protected: int m_AirTickTimer; private: - // Measured in degrees, [-180, +180) + /** Measured in degrees, [-180, +180) */ double m_HeadYaw; - // Measured in meter/second (m/s) + /** Measured in meter/second (m/s) */ Vector3d m_Speed; - // Measured in degrees, [-180, +180) + /** Measured in degrees, [-180, +180) */ Vector3d m_Rot; - /// Position of the entity's XZ center and Y bottom + /** Position of the entity's XZ center and Y bottom */ Vector3d m_Pos; - // Measured in meter / second + /** Measured in meter / second */ Vector3d m_WaterSpeed; - // Measured in Kilograms (Kg) + /** Measured in Kilograms (Kg) */ double m_Mass; - /// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. + /** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */ double m_Width; - /// Height of the entity (Y axis) + /** Height of the entity (Y axis) */ double m_Height; + + /** If a player hit a entity, the entity receive a invulnerable of 10 ticks. + While this ticks, a player can't hit this entity. */ + int m_InvulnerableTicks; } ; // tolua_export typedef std::list<cEntity *> cEntityList; diff --git a/src/Entities/ExpBottleEntity.cpp b/src/Entities/ExpBottleEntity.cpp new file mode 100644 index 000000000..202dde942 --- /dev/null +++ b/src/Entities/ExpBottleEntity.cpp @@ -0,0 +1,27 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ExpBottleEntity.h" +#include "../World.h" + + + + + +cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + // Spawn an experience orb with a reward between 3 and 11. + m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0); + m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8)); + + Destroy(); +} diff --git a/src/Entities/ExpBottleEntity.h b/src/Entities/ExpBottleEntity.h new file mode 100644 index 000000000..b2043d8f1 --- /dev/null +++ b/src/Entities/ExpBottleEntity.h @@ -0,0 +1,33 @@ +// +// ExpBottleEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cExpBottleEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cExpBottleEntity); + + cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + +}; // tolua_export diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp index 3623c869a..10f79aedc 100644 --- a/src/Entities/ExpOrb.cpp +++ b/src/Entities/ExpOrb.cpp @@ -34,8 +34,6 @@ cExpOrb::cExpOrb(const Vector3d & a_Pos, int a_Reward) void cExpOrb::SpawnOn(cClientHandle & a_Client) { a_Client.SendExperienceOrb(*this); - m_bDirtyPosition = false; - m_bDirtySpeed = false; m_bDirtyOrientation = false; m_bDirtyHead = false; } diff --git a/src/Entities/ExpOrb.h b/src/Entities/ExpOrb.h index c1150bd03..e76274ac9 100644 --- a/src/Entities/ExpOrb.h +++ b/src/Entities/ExpOrb.h @@ -42,4 +42,4 @@ protected: /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */ float m_Timer; -} ; // tolua_export
\ No newline at end of file +} ; // tolua_export diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index a66c7e4ae..111c5fa84 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -55,9 +55,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) return; } - int idx = a_Chunk.MakeIndexNoCheck(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); - BLOCKTYPE BlockBelow = a_Chunk.GetBlock(idx); - NIBBLETYPE BelowMeta = a_Chunk.GetMeta(idx); + BLOCKTYPE BlockBelow = a_Chunk.GetBlock(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); + NIBBLETYPE BelowMeta = a_Chunk.GetMeta(BlockX - a_Chunk.GetPosX() * cChunkDef::Width, BlockY, BlockZ - a_Chunk.GetPosZ() * cChunkDef::Width); if (cSandSimulator::DoesBreakFallingThrough(BlockBelow, BelowMeta)) { // Fallen onto a block that breaks this into pickups (e. g. half-slab) @@ -87,7 +86,8 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk) AddSpeedY(MilliDt * -9.8f); AddPosition(GetSpeed() * MilliDt); - if ((GetSpeedX() != 0) || (GetSpeedZ() != 0)) + // If not static (one billionth precision) broadcast movement + if ((fabs(GetSpeedX()) > std::numeric_limits<double>::epsilon()) || (fabs(GetSpeedZ()) > std::numeric_limits<double>::epsilon())) { BroadcastMovementUpdate(); } diff --git a/src/Entities/FireChargeEntity.cpp b/src/Entities/FireChargeEntity.cpp new file mode 100644 index 000000000..aba32602f --- /dev/null +++ b/src/Entities/FireChargeEntity.cpp @@ -0,0 +1,50 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "FireChargeEntity.h" +#include "../World.h" + + + + + +cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) + { + m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1); + } +} + + + + + +void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); + + // TODO: Some entities are immune to hits + a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning +} diff --git a/src/Entities/FireChargeEntity.h b/src/Entities/FireChargeEntity.h new file mode 100644 index 000000000..3924c337c --- /dev/null +++ b/src/Entities/FireChargeEntity.h @@ -0,0 +1,36 @@ +// +// FireChargeEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cFireChargeEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireChargeEntity); + + cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + +} ; // tolua_export diff --git a/src/Entities/FireworkEntity.cpp b/src/Entities/FireworkEntity.cpp new file mode 100644 index 000000000..403a53c84 --- /dev/null +++ b/src/Entities/FireworkEntity.cpp @@ -0,0 +1,73 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "FireworkEntity.h" +#include "../World.h" +#include "../Chunk.h" + + + + + +cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) : + super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), + m_ExplodeTimer(0), + m_FireworkItem(a_Item) +{ +} + + + + + +void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +{ + int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; + int PosY = POSY_TOINT; + + if ((PosY < 0) || (PosY >= cChunkDef::Height)) + { + goto setspeed; + } + + if (m_IsInGround) + { + if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR) + { + m_IsInGround = false; + } + else + { + return; + } + } + else + { + if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR) + { + OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM); + return; + } + } + +setspeed: + AddSpeedY(1); + AddPosition(GetSpeed() * (a_Dt / 1000)); +} + + + + + +void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); + + if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) + { + m_World->BroadcastEntityStatus(*this, esFireworkExploding); + Destroy(); + } + + m_ExplodeTimer++; +} diff --git a/src/Entities/FireworkEntity.h b/src/Entities/FireworkEntity.h new file mode 100644 index 000000000..c62ca9402 --- /dev/null +++ b/src/Entities/FireworkEntity.h @@ -0,0 +1,40 @@ +// +// FireworkEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cFireworkEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cFireworkEntity); + + cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item); + const cItem & GetItem(void) const { return m_FireworkItem; } + +protected: + + // cProjectileEntity overrides: + virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + +private: + + int m_ExplodeTimer; + cItem m_FireworkItem; + +}; // tolua_export diff --git a/src/Entities/Floater.h b/src/Entities/Floater.h index f3b51d77b..547d503f1 100644 --- a/src/Entities/Floater.h +++ b/src/Entities/Floater.h @@ -43,4 +43,4 @@ protected: // Entity IDs int m_PlayerID; int m_AttachedMobID; -} ; // tolua_export
\ No newline at end of file +} ; // tolua_export diff --git a/src/Entities/GhastFireballEntity.cpp b/src/Entities/GhastFireballEntity.cpp new file mode 100644 index 000000000..9e4cb387e --- /dev/null +++ b/src/Entities/GhastFireballEntity.cpp @@ -0,0 +1,44 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "GhastFireballEntity.h" +#include "../World.h" + + + + + +cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1) +{ + SetSpeed(a_Speed); + SetGravity(0); +} + + + + + +void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) +{ + m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this); +} + + + + + +void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} + + + + + +void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + Destroy(); + Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); +} diff --git a/src/Entities/GhastFireballEntity.h b/src/Entities/GhastFireballEntity.h new file mode 100644 index 000000000..9e4572c78 --- /dev/null +++ b/src/Entities/GhastFireballEntity.h @@ -0,0 +1,38 @@ +// +// GhastFireballEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cGhastFireballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cGhastFireballEntity); + + cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // TODO: Deflecting the fireballs by arrow- or sword- hits + +} ; // tolua_export diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 7f38aa35a..7bd440d6d 100644 --- a/src/Entities/Minecart.cpp +++ b/src/Entities/Minecart.cpp @@ -132,7 +132,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) return; } - int PosY = (int)floor(GetPosY()); + int PosY = POSY_TOINT; if ((PosY <= 0) || (PosY >= cChunkDef::Height)) { // Outside the world, just process normal falling physics @@ -141,8 +141,8 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) return; } - int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; - int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; + int RelPosX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; + int RelPosZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); if (Chunk == NULL) { @@ -195,7 +195,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) super::HandlePhysics(a_Dt, *Chunk); } - if (m_bIsOnDetectorRail && !Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())).Equals(m_DetectorRailPosition)) + if (m_bIsOnDetectorRail && !Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT).Equals(m_DetectorRailPosition)) { m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07); m_bIsOnDetectorRail = false; @@ -203,7 +203,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk) else if (WasDetectorRail) { m_bIsOnDetectorRail = true; - m_DetectorRailPosition = Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); + m_DetectorRailPosition = Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT); } // Broadcast positioning changes to client @@ -719,11 +719,11 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) { if (GetSpeedZ() > 0) { - BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())); + BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ())); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { // We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P - cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1); + cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ())), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); if (bbBlock.DoesIntersect(bbMinecart)) @@ -736,10 +736,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } else if (GetSpeedZ() < 0) { - BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1); + BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { - cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1); + cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight()); if (bbBlock.DoesIntersect(bbMinecart)) @@ -756,10 +756,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) { if (GetSpeedX() > 0) { - BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); + BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { - cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1); + cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); if (bbBlock.DoesIntersect(bbMinecart)) @@ -772,10 +772,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) } else if (GetSpeedX() < 0) { - BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); + BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block)) { - cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1); + cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 0.5, 1); cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight()); if (bbBlock.DoesIntersect(bbMinecart)) @@ -793,10 +793,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) case E_META_RAIL_CURVED_ZP_XM: case E_META_RAIL_CURVED_ZP_XP: { - BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); - BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); - BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); - BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); + BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT); + BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT); + BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1); + BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1); if ( (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) || (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) || @@ -805,7 +805,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta) ) { SetSpeed(0, 0, 0); - SetPosition((int)floor(GetPosX()) + 0.5, GetPosY(), (int)floor(GetPosZ()) + 0.5); + SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5); return true; } break; @@ -822,7 +822,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) { cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID())); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk((int)floor(GetPosX()), (int)floor(GetPosZ()), ChunkX, ChunkZ); + cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ); m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback); if (!MinecartCollisionCallback.FoundIntersection()) @@ -902,18 +902,21 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta) -void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) +bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI) { if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative()) { Destroy(); TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative - super::DoTakeDamage(TDI); - return; // No drops for creative + SetInvulnerableTicks(0); + return super::DoTakeDamage(TDI); // No drops for creative } m_LastDamage = TDI.FinalDamage; - super::DoTakeDamage(TDI); + if (!super::DoTakeDamage(TDI)) + { + return false; + } m_World->BroadcastEntityMetadata(*this); @@ -952,12 +955,13 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI) default: { ASSERT(!"Unhandled minecart type when spawning pickup!"); - return; + return true; } } m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); } + return true; } diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h index ebdb576e0..1e60f091c 100644 --- a/src/Entities/Minecart.h +++ b/src/Entities/Minecart.h @@ -36,7 +36,7 @@ public: // cEntity overrides: virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; - virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; virtual void Destroyed() override; int LastDamage(void) const { return m_LastDamage; } diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 7fc89b62b..0fd006485 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -98,45 +98,44 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk) if (!m_bCollected) { - int BlockY = (int) floor(GetPosY()); + int BlockY = POSY_TOINT; + int BlockX = POSX_TOINT; + int BlockZ = POSZ_TOINT; + if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world { - int BlockX = (int) floor(GetPosX()); - int BlockZ = (int) floor(GetPosZ()); // Position might have changed due to physics. So we have to make sure we have the correct chunk. - cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); - if (CurrentChunk != NULL) // Make sure the chunk is loaded - { - int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width); - int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width); + GET_AND_VERIFY_CURRENT_CHUNK(CurrentChunk, BlockX, BlockZ) + + int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width); + int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width); - // If the pickup is on the bottommost block position, make it think the void is made of air: (#131) - BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; - BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ); - - if ( - IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) || - IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE) - ) + // If the pickup is on the bottommost block position, make it think the void is made of air: (#131) + BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; + BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ); + + if ( + IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) || + IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE) + ) + { + m_bCollected = true; + m_Timer = 0; // We have to reset the timer. + m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick. + if (m_Timer > 500.f) { - m_bCollected = true; - m_Timer = 0; // We have to reset the timer. - m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick. - if (m_Timer > 500.f) - { - Destroy(true); - return; - } + Destroy(true); + return; } + } - if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me + if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me + { + cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this); + m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries + if (PickupCombiningCallback.FoundMatchingPickup()) { - cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this); - m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries - if (PickupCombiningCallback.FoundMatchingPickup()) - { - m_World->BroadcastEntityMetadata(*this); - } + m_World->BroadcastEntityMetadata(*this); } } } @@ -156,7 +155,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk) return; } - if (GetPosY() < -8) // Out of this world and no more visible! + if (GetPosY() < VOID_BOUNDARY) // Out of this world and no more visible! { Destroy(true); return; @@ -193,6 +192,16 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) int NumAdded = a_Dest->GetInventory().AddItem(m_Item); if (NumAdded > 0) { + // Check achievements + switch (m_Item.m_ItemType) + { + case E_BLOCK_LOG: a_Dest->AwardAchievement(achMineWood); break; + case E_ITEM_LEATHER: a_Dest->AwardAchievement(achKillCow); break; + case E_ITEM_DIAMOND: a_Dest->AwardAchievement(achDiamonds); break; + case E_ITEM_BLAZE_ROD: a_Dest->AwardAchievement(achBlazeRod); break; + default: break; + } + m_Item.m_ItemCount -= NumAdded; m_World->BroadcastCollectPickup(*this, *a_Dest); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) diff --git a/src/Entities/Pickup.h b/src/Entities/Pickup.h index 74b917bce..2dcbecaaf 100644 --- a/src/Entities/Pickup.h +++ b/src/Entities/Pickup.h @@ -49,9 +49,6 @@ public: bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export private: - Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;) - - Vector3d m_WaterSpeed; /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */ float m_Timer; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 863aaa799..0dfdcfd8b 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -16,6 +16,9 @@ #include "../Items/ItemHandler.h" #include "../Vector3.h" +#include "../WorldStorage/StatSerializer.h" +#include "../CompositeChat.h" + #include "inifile/iniFile.h" #include "json/json.h" @@ -76,18 +79,16 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) cTimer t1; m_LastPlayerListTime = t1.GetNowTime(); - - m_TimeLastTeleportPacket = 0; m_PlayerName = a_PlayerName; - m_bDirtyPosition = true; // So chunks are streamed to player at spawn if (!LoadFromDisk()) { m_Inventory.Clear(); - SetPosX(cRoot::Get()->GetDefaultWorld()->GetSpawnX()); - SetPosY(cRoot::Get()->GetDefaultWorld()->GetSpawnY()); - SetPosZ(cRoot::Get()->GetDefaultWorld()->GetSpawnZ()); + cWorld * DefaultWorld = cRoot::Get()->GetDefaultWorld(); + SetPosX(DefaultWorld->GetSpawnX()); + SetPosY(DefaultWorld->GetSpawnY()); + SetPosZ(DefaultWorld->GetSpawnZ()); LOGD("Player \"%s\" is connecting for the first time, spawning at default world spawn {%.2f, %.2f, %.2f}", a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() @@ -193,6 +194,8 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) return; } } + + m_Stats.AddValue(statMinutesPlayed, 1); if (!a_Chunk.IsValid()) { @@ -208,25 +211,22 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) m_BowCharge += 1; } - //handle updating experience + // Handle updating experience if (m_bDirtyExperience) { SendExperience(); } - if (m_bDirtyPosition) + if (GetPosition() != m_LastPos) // Change in position from last tick? { // Apply food exhaustion from movement: ApplyFoodExhaustionFromMovement(); cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this); - BroadcastMovementUpdate(m_ClientHandle); m_ClientHandle->StreamChunks(); } - else - { - BroadcastMovementUpdate(m_ClientHandle); - } + + BroadcastMovementUpdate(m_ClientHandle); if (m_Health > 0) // make sure player is alive { @@ -377,7 +377,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta) } LOGD("Player \"%s\" gained/lost %d experience, total is now: %d", - m_PlayerName.c_str(), a_Xp_delta, m_CurrentXp); + GetName().c_str(), a_Xp_delta, m_CurrentXp); // Set experience to be updated m_bDirtyExperience = true; @@ -391,7 +391,7 @@ short cPlayer::DeltaExperience(short a_Xp_delta) void cPlayer::StartChargingBow(void) { - LOGD("Player \"%s\" started charging their bow", m_PlayerName.c_str()); + LOGD("Player \"%s\" started charging their bow", GetName().c_str()); m_IsChargingBow = true; m_BowCharge = 0; } @@ -402,7 +402,7 @@ void cPlayer::StartChargingBow(void) int cPlayer::FinishChargingBow(void) { - LOGD("Player \"%s\" finished charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge); + LOGD("Player \"%s\" finished charging their bow at a charge of %d", GetName().c_str(), m_BowCharge); int res = m_BowCharge; m_IsChargingBow = false; m_BowCharge = 0; @@ -415,7 +415,7 @@ int cPlayer::FinishChargingBow(void) void cPlayer::CancelChargingBow(void) { - LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", m_PlayerName.c_str(), m_BowCharge); + LOGD("Player \"%s\" cancelled charging their bow at a charge of %d", GetName().c_str(), m_BowCharge); m_IsChargingBow = false; m_BowCharge = 0; } @@ -437,7 +437,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) cWorld * World = GetWorld(); if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height)) { - BLOCKTYPE BlockType = World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); + BLOCKTYPE BlockType = World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT); if (BlockType != E_BLOCK_AIR) { m_bTouchGround = true; @@ -456,8 +456,18 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) else { float Dist = (float)(m_LastGroundHeight - floor(GetPosY())); + + if (Dist >= 2.0) // At least two blocks - TODO: Use m_LastJumpHeight instead of m_LastGroundHeight above + { + // Increment statistic + m_Stats.AddValue(statDistFallen, (StatValue)floor(Dist * 100 + 0.5)); + } + int Damage = (int)(Dist - 3.f); - if (m_LastJumpHeight > m_LastGroundHeight) Damage++; + if (m_LastJumpHeight > m_LastGroundHeight) + { + Damage++; + } m_LastJumpHeight = (float)GetPosY(); if (Damage > 0) @@ -466,7 +476,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) TakeDamage(dtFalling, NULL, Damage, Damage, 0); // Fall particles - GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */); + GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, (int)GetPosY() - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */); } m_LastGroundHeight = (float)GetPosY(); @@ -590,7 +600,7 @@ void cPlayer::FinishEating(void) m_EatingFinishTick = -1; // Send the packets: - m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED); + m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted); m_World->BroadcastEntityAnimation(*this, 0); m_World->BroadcastEntityMetadata(*this); @@ -807,37 +817,41 @@ void cPlayer::SetFlying(bool a_IsFlying) -void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) { if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin)) { if (IsGameModeCreative()) { // No damage / health in creative mode if not void or plugin damage - return; + return false; } } if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) { - cPlayer* Attacker = (cPlayer*) a_TDI.Attacker; + cPlayer * Attacker = (cPlayer *)a_TDI.Attacker; if ((m_Team != NULL) && (m_Team == Attacker->m_Team)) { if (!m_Team->AllowsFriendlyFire()) { // Friendly fire is disabled - return; + return false; } } } - super::DoTakeDamage(a_TDI); - - // Any kind of damage adds food exhaustion - AddFoodExhaustion(0.3f); - - SendHealth(); + if (super::DoTakeDamage(a_TDI)) + { + // Any kind of damage adds food exhaustion + AddFoodExhaustion(0.3f); + SendHealth(); + + m_Stats.AddValue(statDamageTaken, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); + return true; + } + return false; } @@ -865,6 +879,8 @@ void cPlayer::KilledBy(cEntity * a_Killer) Pickups.Add(cItem(E_ITEM_RED_APPLE)); } + m_Stats.AddValue(statItemsDropped, Pickups.Size()); + m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! @@ -874,9 +890,9 @@ void cPlayer::KilledBy(cEntity * a_Killer) } else if (a_Killer->IsPlayer()) { - GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str())); + cPlayer * Killer = (cPlayer *)a_Killer; - m_World->GetScoreBoard().AddPlayerScore(((cPlayer *)a_Killer)->GetName(), cObjective::otPlayerKillCount, 1); + GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str())); } else { @@ -886,6 +902,8 @@ void cPlayer::KilledBy(cEntity * a_Killer) GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str())); } + m_Stats.AddValue(statDeaths); + m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1); } @@ -893,9 +911,37 @@ void cPlayer::KilledBy(cEntity * a_Killer) +void cPlayer::Killed(cEntity * a_Victim) +{ + cScoreboard & ScoreBoard = m_World->GetScoreBoard(); + + if (a_Victim->IsPlayer()) + { + m_Stats.AddValue(statPlayerKills); + + ScoreBoard.AddPlayerScore(GetName(), cObjective::otPlayerKillCount, 1); + } + else if (a_Victim->IsMob()) + { + if (((cMonster *)a_Victim)->GetMobFamily() == cMonster::mfHostile) + { + AwardAchievement(achKillMonster); + } + + m_Stats.AddValue(statMobKills); + } + + ScoreBoard.AddPlayerScore(GetName(), cObjective::otTotalKillCount, 1); +} + + + + + void cPlayer::Respawn(void) { m_Health = GetMaxHealth(); + SetInvulnerableTicks(20); // Reset food level: m_FoodLevel = MAX_FOOD_LEVEL; @@ -1110,6 +1156,47 @@ void cPlayer::SetIP(const AString & a_IP) +unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach) +{ + eStatistic Prerequisite = cStatInfo::GetPrerequisite(a_Ach); + + // Check if the prerequisites are met + if (Prerequisite != statInvalid) + { + if (m_Stats.GetValue(Prerequisite) == 0) + { + return 0; + } + } + + StatValue Old = m_Stats.GetValue(a_Ach); + + if (Old > 0) + { + return m_Stats.AddValue(a_Ach); + } + else + { + // First time, announce it + cCompositeChat Msg; + Msg.SetMessageType(mtSuccess); + Msg.AddShowAchievementPart(GetName(), cStatInfo::GetName(a_Ach)); + m_World->BroadcastChat(Msg); + + // Increment the statistic + StatValue New = m_Stats.AddValue(a_Ach); + + // Achievement Get! + m_ClientHandle->SendStatistics(m_Stats); + + return New; + } +} + + + + + void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) { SetPosition(a_PosX, a_PosY, a_PosZ); @@ -1124,6 +1211,17 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) +void cPlayer::SendRotation(double a_YawDegrees, double a_PitchDegrees) +{ + SetYaw(a_YawDegrees); + SetPitch(a_PitchDegrees); + m_ClientHandle->SendPlayerMoveLook(); +} + + + + + Vector3d cPlayer::GetThrowStartPos(void) const { Vector3d res = GetEyePosition(); @@ -1154,9 +1252,9 @@ Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const -void cPlayer::ForceSetSpeed(Vector3d a_Direction) +void cPlayer::ForceSetSpeed(const Vector3d & a_Speed) { - SetSpeed(a_Direction); + SetSpeed(a_Speed); m_ClientHandle->SendEntityVelocity(*this); } @@ -1183,6 +1281,9 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos ) // TODO: should do some checks to see if player is not moving through terrain // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too + + Vector3d DeltaPos = a_NewPos - GetPosition(); + UpdateMovementStats(DeltaPos); SetPosition( a_NewPos ); SetStance(a_NewPos.y + 1.62); @@ -1214,7 +1315,7 @@ void cPlayer::AddToGroup( const AString & a_GroupName ) { cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName ); m_Groups.push_back( Group ); - LOGD("Added %s to group %s", m_PlayerName.c_str(), a_GroupName.c_str() ); + LOGD("Added %s to group %s", GetName().c_str(), a_GroupName.c_str() ); ResolveGroups(); ResolvePermissions(); } @@ -1238,13 +1339,13 @@ void cPlayer::RemoveFromGroup( const AString & a_GroupName ) if( bRemoved ) { - LOGD("Removed %s from group %s", m_PlayerName.c_str(), a_GroupName.c_str() ); + LOGD("Removed %s from group %s", GetName().c_str(), a_GroupName.c_str() ); ResolveGroups(); ResolvePermissions(); } else { - LOGWARN("Tried to remove %s from group %s but was not in that group", m_PlayerName.c_str(), a_GroupName.c_str() ); + LOGWARN("Tried to remove %s from group %s but was not in that group", GetName().c_str(), a_GroupName.c_str() ); } } @@ -1350,7 +1451,7 @@ void cPlayer::ResolveGroups() if( AllGroups.find( CurrentGroup ) != AllGroups.end() ) { LOGWARNING("ERROR: Player \"%s\" is in the group multiple times (\"%s\"). Please fix your settings in users.ini!", - m_PlayerName.c_str(), CurrentGroup->GetName().c_str() + GetName().c_str(), CurrentGroup->GetName().c_str() ); } else @@ -1362,7 +1463,7 @@ void cPlayer::ResolveGroups() { if( AllGroups.find( *itr ) != AllGroups.end() ) { - LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", m_PlayerName.c_str(), (*itr)->GetName().c_str() ); + LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", GetName().c_str(), (*itr)->GetName().c_str() ); continue; } ToIterate.push_back( *itr ); @@ -1413,10 +1514,7 @@ void cPlayer::TossEquippedItem(char a_Amount) Drops.push_back(DroppedItem); } - double vX = 0, vY = 0, vZ = 0; - EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); - vY = -vY * 2 + 1.f; - m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player + TossItems(Drops); } @@ -1432,6 +1530,7 @@ void cPlayer::TossHeldItem(char a_Amount) char OriginalItemAmount = Item.m_ItemCount; Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount); Drops.push_back(Item); + if (OriginalItemAmount > a_Amount) { Item.m_ItemCount = OriginalItemAmount - a_Amount; @@ -1442,10 +1541,7 @@ void cPlayer::TossHeldItem(char a_Amount) } } - double vX = 0, vY = 0, vZ = 0; - EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); - vY = -vY * 2 + 1.f; - m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player + TossItems(Drops); } @@ -1457,10 +1553,21 @@ void cPlayer::TossPickup(const cItem & a_Item) cItems Drops; Drops.push_back(a_Item); + TossItems(Drops); +} + + + + + +void cPlayer::TossItems(const cItems & a_Items) +{ + m_Stats.AddValue(statItemsDropped, a_Items.Size()); + double vX = 0, vY = 0, vZ = 0; EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); vY = -vY * 2 + 1.f; - m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player + m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player } @@ -1489,6 +1596,7 @@ bool cPlayer::MoveToWorld(const char * a_WorldName) // Add player to all the necessary parts of the new world SetWorld(World); + m_ClientHandle->StreamChunks(); World->AddEntity(this); World->AddPlayer(this); @@ -1507,25 +1615,19 @@ void cPlayer::LoadPermissionsFromDisk() cIniFile IniFile; if (IniFile.ReadFile("users.ini")) { - std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", ""); - if (!Groups.empty()) + AString Groups = IniFile.GetValueSet(GetName(), "Groups", "Default"); + AStringVector Split = StringSplitAndTrim(Groups, ","); + + for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr) { - AStringVector Split = StringSplitAndTrim(Groups, ","); - for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr) + if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr)) { - if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr)) - { - LOGWARNING("The group %s for player %s was not found!", itr->c_str(), m_PlayerName.c_str()); - } - AddToGroup(*itr); + LOGWARNING("The group %s for player %s was not found!", itr->c_str(), GetName().c_str()); } - } - else - { - AddToGroup("Default"); + AddToGroup(*itr); } - AString Color = IniFile.GetValue(m_PlayerName, "Color", "-"); + AString Color = IniFile.GetValue(GetName(), "Color", "-"); if (!Color.empty()) { m_Color = Color[0]; @@ -1534,8 +1636,10 @@ void cPlayer::LoadPermissionsFromDisk() else { cGroupManager::GenerateDefaultUsersIni(IniFile); + IniFile.AddValue("Groups", GetName(), "Default"); AddToGroup("Default"); } + IniFile.WriteFile("users.ini"); ResolvePermissions(); } @@ -1547,14 +1651,14 @@ bool cPlayer::LoadFromDisk() LoadPermissionsFromDisk(); // Log player permissions, cause it's what the cool kids do - LOGINFO("Player %s has permissions:", m_PlayerName.c_str() ); + LOGINFO("Player %s has permissions:", GetName().c_str() ); for( PermissionMap::iterator itr = m_ResolvedPermissions.begin(); itr != m_ResolvedPermissions.end(); ++itr ) { if( itr->second ) LOG(" - %s", itr->first.c_str() ); } AString SourceFile; - Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() ); + Printf(SourceFile, "players/%s.json", GetName().c_str() ); cFile f; if (!f.Open(SourceFile, cFile::fmRead)) @@ -1584,10 +1688,7 @@ bool cPlayer::LoadFromDisk() SetPosX(JSON_PlayerPosition[(unsigned int)0].asDouble()); SetPosY(JSON_PlayerPosition[(unsigned int)1].asDouble()); SetPosZ(JSON_PlayerPosition[(unsigned int)2].asDouble()); - m_LastPosX = GetPosX(); - m_LastPosY = GetPosY(); - m_LastPosZ = GetPosZ(); - m_LastFoodPos = GetPosition(); + m_LastPos = GetPosition(); } Json::Value & JSON_PlayerRotation = root["rotation"]; @@ -1618,9 +1719,14 @@ bool cPlayer::LoadFromDisk() m_Inventory.LoadFromJson(root["inventory"]); m_LoadedWorldName = root.get("world", "world").asString(); + + // Load the player stats. + // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. + cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); + StatSerializer.Load(); LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", - m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() + GetName().c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() ); return true; @@ -1676,12 +1782,12 @@ bool cPlayer::SaveToDisk() std::string JsonData = writer.write(root); AString SourceFile; - Printf(SourceFile, "players/%s.json", m_PlayerName.c_str() ); + Printf(SourceFile, "players/%s.json", GetName().c_str() ); cFile f; if (!f.Open(SourceFile, cFile::fmWrite)) { - LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", m_PlayerName.c_str(), SourceFile.c_str()); + LOGERROR("ERROR WRITING PLAYER \"%s\" TO FILE \"%s\" - cannot open file", GetName().c_str(), SourceFile.c_str()); return false; } if (f.Write(JsonData.c_str(), JsonData.size()) != (int)JsonData.size()) @@ -1689,6 +1795,16 @@ bool cPlayer::SaveToDisk() LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str()); return false; } + + // Save the player stats. + // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. + cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); + if (!StatSerializer.Save()) + { + LOGERROR("Could not save stats for player %s", GetName().c_str()); + return false; + } + return true; } @@ -1703,7 +1819,10 @@ cPlayer::StringList cPlayer::GetResolvedPermissions() const PermissionMap& ResolvedPermissions = m_ResolvedPermissions; for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr ) { - if( itr->second ) Permissions.push_back( itr->first ); + if (itr->second) + { + Permissions.push_back( itr->first ); + } } return Permissions; @@ -1842,23 +1961,108 @@ void cPlayer::HandleFloater() +bool cPlayer::IsClimbing(void) const +{ + int PosX = POSX_TOINT; + int PosY = POSY_TOINT; + int PosZ = POSZ_TOINT; + + if ((PosY < 0) || (PosY >= cChunkDef::Height)) + { + return false; + } + + BLOCKTYPE Block = m_World->GetBlock(PosX, PosY, PosZ); + switch (Block) + { + case E_BLOCK_LADDER: + case E_BLOCK_VINES: + { + return true; + } + default: return false; + } +} + + + + + +void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) +{ + StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5); + + if (m_AttachedTo == NULL) + { + if (IsClimbing()) + { + if (a_DeltaPos.y > 0.0) // Going up + { + m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5)); + } + } + else if (IsSubmerged()) + { + m_Stats.AddValue(statDistDove, Value); + } + else if (IsSwimming()) + { + m_Stats.AddValue(statDistSwum, Value); + } + else if (IsOnGround()) + { + m_Stats.AddValue(statDistWalked, Value); + } + else + { + if (Value >= 25) // Ignore small/slow movement + { + m_Stats.AddValue(statDistFlown, Value); + } + } + } + else + { + switch (m_AttachedTo->GetEntityType()) + { + case cEntity::etMinecart: m_Stats.AddValue(statDistMinecart, Value); break; + case cEntity::etBoat: m_Stats.AddValue(statDistBoat, Value); break; + case cEntity::etMonster: + { + cMonster * Monster = (cMonster *)m_AttachedTo; + switch (Monster->GetMobType()) + { + case cMonster::mtPig: m_Stats.AddValue(statDistPig, Value); break; + case cMonster::mtHorse: m_Stats.AddValue(statDistHorse, Value); break; + default: break; + } + break; + } + default: break; + } + } +} + + + + + void cPlayer::ApplyFoodExhaustionFromMovement() { if (IsGameModeCreative()) { return; } - - // Calculate the distance travelled, update the last pos: - Vector3d Movement(GetPosition() - m_LastFoodPos); - Movement.y = 0; // Only take XZ movement into account - m_LastFoodPos = GetPosition(); - + // If riding anything, apply no food exhaustion if (m_AttachedTo != NULL) { return; } + + // Calculate the distance travelled, update the last pos: + Vector3d Movement(GetPosition() - m_LastPos); + Movement.y = 0; // Only take XZ movement into account // Apply the exhaustion based on distance travelled: double BaseExhaustion = Movement.Length(); @@ -1887,9 +2091,9 @@ void cPlayer::ApplyFoodExhaustionFromMovement() void cPlayer::Detach() { super::Detach(); - int PosX = (int)floor(GetPosX()); - int PosY = (int)floor(GetPosY()); - int PosZ = (int)floor(GetPosZ()); + int PosX = POSX_TOINT; + int PosY = POSY_TOINT; + int PosZ = POSZ_TOINT; // Search for a position within an area to teleport player after detachment // Position must be solid land, and occupied by a nonsolid block diff --git a/src/Entities/Player.h b/src/Entities/Player.h index ea32dbfb9..b7cb27d6c 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -7,6 +7,8 @@ #include "../World.h" #include "../ClientHandle.h" +#include "../Statistics.h" + @@ -125,10 +127,19 @@ public: inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export + /** Returns whether the player is climbing (ladders, vines e.t.c). */ + bool IsClimbing(void) const; + virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override; // tolua_begin + /** Sends the "look" packet to the player, forcing them to set their rotation to the specified values. + a_YawDegrees is clipped to range [-180, +180), + a_PitchDegrees is clipped to range [-180, +180) but the client only uses [-90, +90] + */ + void SendRotation(double a_YawDegrees, double a_PitchDegrees); + /** Returns the position where projectiles thrown by this player should start, player eye position + adjustment */ Vector3d GetThrowStartPos(void) const; @@ -168,6 +179,15 @@ public: cTeam * UpdateTeam(void); // tolua_end + + /** Return the associated statistic and achievement manager. */ + cStatManager & GetStatManager() { return m_Stats; } + + /** Awards the player an achievement. + If all prerequisites are met, this method will award the achievement and will broadcast a chat message. + If the achievement has been already awarded to the player, this method will just increment the stat counter. + Returns the _new_ stat value. (0 = Could not award achievement) */ + unsigned int AwardAchievement(const eStatistic a_Ach); void SetIP(const AString & a_IP); @@ -175,7 +195,7 @@ public: void LoginSetGameMode(eGameMode a_GameMode); /** Forces the player to move in the given direction. */ - void ForceSetSpeed(Vector3d a_Direction); // tolua_export + void ForceSetSpeed(const Vector3d & a_Speed); // tolua_export /** Tries to move to a new position, with attachment-related checks (y == -999) */ void MoveTo(const Vector3d & a_NewPos); // tolua_export @@ -300,6 +320,8 @@ public: void AbortEating(void); virtual void KilledBy(cEntity * a_Killer) override; + + virtual void Killed(cEntity * a_Victim) override; void Respawn(void); // tolua_export @@ -369,6 +391,9 @@ public: /** If true the player can fly even when he's not in creative. */ void SetCanFly(bool a_CanFly); + /** Update movement-related statistics. */ + void UpdateMovementStats(const Vector3d & a_DeltaPos); + /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } // tolua_end @@ -417,9 +442,6 @@ protected: /** Number of ticks remaining for the foodpoisoning effect; zero if not foodpoisoned */ int m_FoodPoisonedTicksRemaining; - /** Last position that has been recorded for food-related processing: */ - Vector3d m_LastFoodPos; - float m_LastJumpHeight; float m_LastGroundHeight; bool m_bTouchGround; @@ -484,6 +506,8 @@ protected: cTeam * m_Team; + cStatManager m_Stats; + void ResolvePermissions(void); @@ -492,7 +516,7 @@ protected: virtual void Destroyed(void); /** Filters out damage for creative mode/friendly fire */ - virtual void DoTakeDamage(TakeDamageInfo & TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & TDI) override; /** Stops players from burning in creative mode */ virtual void TickBurning(cChunk & a_Chunk) override; @@ -503,6 +527,9 @@ protected: /** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */ void HandleFloater(void); + /** Tosses a list of items. */ + void TossItems(const cItems & a_Items); + /** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */ void ApplyFoodExhaustionFromMovement(); diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index acb10539d..95c494569 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -4,15 +4,24 @@ // Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types #include "Globals.h" + #include "../Bindings/PluginManager.h" #include "ProjectileEntity.h" #include "../ClientHandle.h" -#include "Player.h" #include "../LineBlockTracer.h" #include "../BoundingBox.h" #include "../ChunkMap.h" #include "../Chunk.h" +#include "ArrowEntity.h" +#include "ThrownEggEntity.h" +#include "ThrownEnderPearlEntity.h" +#include "ExpBottleEntity.h" +#include "ThrownSnowballEntity.h" +#include "FireChargeEntity.h" +#include "FireworkEntity.h" +#include "GhastFireballEntity.h" + @@ -371,13 +380,14 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) SetYawFromSpeed(); SetPitchFromSpeed(); - // DEBUG: + /* LOGD("Projectile %d: pos {%.02f, %.02f, %.02f}, speed {%.02f, %.02f, %.02f}, rot {%.02f, %.02f}", m_UniqueID, GetPosX(), GetPosY(), GetPosZ(), GetSpeedX(), GetSpeedY(), GetSpeedZ(), GetYaw(), GetPitch() ); + */ } @@ -400,495 +410,3 @@ void cProjectileEntity::CollectedBy(cPlayer * a_Dest) // Overriden in arrow UNUSED(a_Dest); } - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cArrowEntity: - -cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), - m_PickupState(psNoPickup), - m_DamageCoeff(2), - m_IsCritical(false), - m_Timer(0), - m_HitGroundTimer(0), - m_bIsCollected(false), - m_HitBlockPos(Vector3i(0, 0, 0)) -{ - SetSpeed(a_Speed); - SetMass(0.1); - SetYawFromSpeed(); - SetPitchFromSpeed(); - LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}", - m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(), - GetYaw(), GetPitch() - ); -} - - - - - -cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : - super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), - m_PickupState(psInSurvivalOrCreative), - m_DamageCoeff(2), - m_IsCritical((a_Force >= 1)), - m_Timer(0), - m_HitGroundTimer(0), - m_bIsCollected(false), - m_HitBlockPos(0, 0, 0) -{ -} - - - - - -bool cArrowEntity::CanPickup(const cPlayer & a_Player) const -{ - switch (m_PickupState) - { - case psNoPickup: return false; - case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative()); - case psInCreative: return a_Player.IsGameModeCreative(); - } - ASSERT(!"Unhandled pickup state"); - return false; -} - - - - - -void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - if (a_HitFace == BLOCK_FACE_NONE) { return; } - - super::OnHitSolidBlock(a_HitPos, a_HitFace); - int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z; - - switch (a_HitFace) - { - case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed - case BLOCK_FACE_YM: - { - break; - } - default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true); - } - - m_HitBlockPos = Vector3i(a_X, a_Y, a_Z); - - // Broadcast arrow hit sound - m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); -} - - - - - -void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat()) - { - // Not an entity that interacts with an arrow - return; - } - - int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5); - if (m_IsCritical) - { - Damage += m_World->GetTickRandomNumber(Damage / 2 + 2); - } - a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1); - - // Broadcast successful hit sound - m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - - Destroy(); -} - - - - - -void cArrowEntity::CollectedBy(cPlayer * a_Dest) -{ - if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest))) - { - int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW); - if (NumAdded > 0) // Only play effects if there was space in inventory - { - m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest); - // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) - m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); - m_bIsCollected = true; - } - } -} - - - - - -void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - m_Timer += a_Dt; - - if (m_bIsCollected) - { - if (m_Timer > 500.f) // 0.5 seconds - { - Destroy(); - return; - } - } - else if (m_Timer > 1000 * 60 * 5) // 5 minutes - { - Destroy(); - return; - } - - if (m_IsInGround) - { - // When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL - // Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing) - // We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync - // Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position - - if (m_HitGroundTimer != -1) // Sent a teleport already, don't do again - { - if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case - { - m_World->BroadcastTeleportEntity(*this); - m_HitGroundTimer = -1; - } - else - { - m_HitGroundTimer += a_Dt; - } - } - - int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width; - int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width; - cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); - - if (Chunk == NULL) - { - // Inside an unloaded chunk, abort - return; - } - - if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed? - { - m_IsInGround = false; // Yes, begin simulating physics again - } - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cThrownEggEntity: - -cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - if (m_World->GetTickRandomNumber(7) == 1) - { - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - } - else if (m_World->GetTickRandomNumber(32) == 1) - { - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); - } - Destroy(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cThrownEnderPearlEntity : - -cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - // Teleport the creator here, make them take 5 damage: - if (m_Creator != NULL) - { - // TODO: The coords might need some tweaking based on the block face - m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); - m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); - } - - Destroy(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cThrownSnowballEntity : - -cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - Destroy(); -} - - - - - -void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - int TotalDamage = 0; - if (a_EntityHit.IsMob()) - { - cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType(); - if (MobType == cMonster::mtBlaze) - { - TotalDamage = 3; - } - else if (MobType == cMonster::mtEnderDragon) - { - TotalDamage = 1; - } - } - a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); - - Destroy(true); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cBottleOEnchantingEntity : - -cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : -super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) -{ - SetSpeed(a_Speed); -} - - - - - -void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - // Spawn an experience orb with a reward between 3 and 11. - m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0); - m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8)); - - Destroy(); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cFireworkEntity : - -cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) : -super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25), - m_ExplodeTimer(0), - m_FireworkItem(a_Item) -{ -} - - - - - -void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) -{ - int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width; - int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width; - int PosY = POSY_TOINT; - - if ((PosY < 0) || (PosY >= cChunkDef::Height)) - { - goto setspeed; - } - - if (m_IsInGround) - { - if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR) - { - m_IsInGround = false; - } - else - { - return; - } - } - else - { - if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR) - { - OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM); - return; - } - } - -setspeed: - AddSpeedY(1); - AddPosition(GetSpeed() * (a_Dt / 1000)); -} - - - - - -void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) -{ - super::Tick(a_Dt, a_Chunk); - - if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) - { - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE); - Destroy(); - } - - m_ExplodeTimer++; -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cGhastFireballEntity : - -cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1) -{ - SetSpeed(a_Speed); - SetGravity(0); -} - - - - - -void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this); -} - - - - - -void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); -} - - - - - -void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cFireChargeEntity : - -cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : - super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125) -{ - SetSpeed(a_Speed); - SetGravity(0); -} - - - - - -void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ) -{ - if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR) - { - m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1); - } -} - - - - - -void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); -} - - - - - -void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) -{ - Destroy(); - Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z)); - - // TODO: Some entities are immune to hits - a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning -} - - - - diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index efb7ae783..ae06b072f 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -94,300 +94,4 @@ protected: virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; virtual void SpawnOn(cClientHandle & a_Client) override; - // tolua_begin -} ; - - - - - -class cArrowEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - /// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field - enum ePickupState - { - psNoPickup = 0, - psInSurvivalOrCreative = 1, - psInCreative = 2, - } ; - - // tolua_end - - CLASS_PROTODEF(cArrowEntity); - - /// Creates a new arrow with psNoPickup state and default damage modifier coeff - cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - - /// Creates a new arrow as shot by a player, initializes it from the player object - cArrowEntity(cPlayer & a_Player, double a_Force); - - // tolua_begin - - /// Returns whether the arrow can be picked up by players - ePickupState GetPickupState(void) const { return m_PickupState; } - - /// Sets a new pickup state - void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; } - - /// Returns the damage modifier coeff. - double GetDamageCoeff(void) const { return m_DamageCoeff; } - - /// Sets the damage modifier coeff - void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } - - /// Returns true if the specified player can pick the arrow up - bool CanPickup(const cPlayer & a_Player) const; - - /// Returns true if the arrow is set as critical - bool IsCritical(void) const { return m_IsCritical; } - - /// Sets the IsCritical flag - void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; } - - // tolua_end - -protected: - - /// Determines when the arrow can be picked up by players - ePickupState m_PickupState; - - /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow - double m_DamageCoeff; - - /// If true, the arrow deals more damage - bool m_IsCritical; - - /// Timer for pickup collection animation or five minute timeout - float m_Timer; - - /// Timer for client arrow position confirmation via TeleportEntity - float m_HitGroundTimer; - - /// If true, the arrow is in the process of being collected - don't go to anyone else - bool m_bIsCollected; - - /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air - Vector3i m_HitBlockPos; - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - virtual void CollectedBy(cPlayer * a_Player) override; - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - - // tolua_begin -} ; - - - - - -class cThrownEggEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cThrownEggEntity); - - cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // tolua_end - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - - // tolua_begin - -} ; - - - - - -class cThrownEnderPearlEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cThrownEnderPearlEntity); - - cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // tolua_end - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - - // tolua_begin - -} ; - - - - - -class cThrownSnowballEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cThrownSnowballEntity); - - cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // tolua_begin - -} ; - - - - - -class cExpBottleEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cExpBottleEntity); - - cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - - // tolua_begin - -}; - - - - - -class cFireworkEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cFireworkEntity); - - cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item); - const cItem & GetItem(void) const { return m_FireworkItem; } - -protected: - - // cProjectileEntity overrides: - virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; - virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - -private: - - int m_ExplodeTimer; - cItem m_FireworkItem; - - // tolua_begin - -}; - - - - - -class cGhastFireballEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cGhastFireballEntity); - - cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // TODO: Deflecting the fireballs by arrow- or sword- hits - - // tolua_begin - -} ; - - - - - -class cFireChargeEntity : - public cProjectileEntity -{ - typedef cProjectileEntity super; - -public: - - // tolua_end - - CLASS_PROTODEF(cFireChargeEntity); - - cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); - -protected: - - void Explode(int a_BlockX, int a_BlockY, int a_BlockZ); - - // cProjectileEntity overrides: - virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; - virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override; - - // tolua_begin - -} ; - - - - -// tolua_end - - - +} ; // tolua_export diff --git a/src/Entities/TNTEntity.cpp b/src/Entities/TNTEntity.cpp index 02f31f5bb..fd9a4e7ac 100644 --- a/src/Entities/TNTEntity.cpp +++ b/src/Entities/TNTEntity.cpp @@ -30,8 +30,6 @@ cTNTEntity::cTNTEntity(const Vector3d & a_Pos, int a_FuseTicks) : void cTNTEntity::SpawnOn(cClientHandle & a_ClientHandle) { a_ClientHandle.SendSpawnObject(*this, 50, 1, 0, 0); // 50 means TNT - m_bDirtyPosition = false; - m_bDirtySpeed = false; m_bDirtyOrientation = false; m_bDirtyHead = false; } diff --git a/src/Entities/ThrownEggEntity.cpp b/src/Entities/ThrownEggEntity.cpp new file mode 100644 index 000000000..224019091 --- /dev/null +++ b/src/Entities/ThrownEggEntity.cpp @@ -0,0 +1,59 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ThrownEggEntity.h" +#include "../World.h" + + + + + +cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + TrySpawnChicken(a_HitPos); + + Destroy(); +} + + + + + +void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + int TotalDamage = 0; + // TODO: If entity is Ender Crystal, destroy it + + TrySpawnChicken(a_HitPos); + a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + + Destroy(true); +} + + + + + +void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos) +{ + if (m_World->GetTickRandomNumber(7) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } + else if (m_World->GetTickRandomNumber(32) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } +} diff --git a/src/Entities/ThrownEggEntity.h b/src/Entities/ThrownEggEntity.h new file mode 100644 index 000000000..5ba8f051b --- /dev/null +++ b/src/Entities/ThrownEggEntity.h @@ -0,0 +1,37 @@ +// +// ThrownEggEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cThrownEggEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEggEntity); + + cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // Randomly decides whether to spawn a chicken where the egg lands. + void TrySpawnChicken(const Vector3d & a_HitPos); + +} ; // tolua_export diff --git a/src/Entities/ThrownEnderPearlEntity.cpp b/src/Entities/ThrownEnderPearlEntity.cpp new file mode 100644 index 000000000..c37161145 --- /dev/null +++ b/src/Entities/ThrownEnderPearlEntity.cpp @@ -0,0 +1,54 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ThrownEnderPearlEntity.h" + + + + + +cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + // TODO: Tweak a_HitPos based on block face. + TeleportCreator(a_HitPos); + + Destroy(); +} + + + + + +void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + int TotalDamage = 0; + // TODO: If entity is Ender Crystal, destroy it + + TeleportCreator(a_HitPos); + a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + + Destroy(true); +} + + + + + +void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos) +{ + // Teleport the creator here, make them take 5 damage: + if (m_Creator != NULL) + { + m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5); + m_Creator->TakeDamage(dtEnderPearl, this, 5, 0); + } +} diff --git a/src/Entities/ThrownEnderPearlEntity.h b/src/Entities/ThrownEnderPearlEntity.h new file mode 100644 index 000000000..ddee5babe --- /dev/null +++ b/src/Entities/ThrownEnderPearlEntity.h @@ -0,0 +1,37 @@ +// +// ThrownEnderPearlEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cThrownEnderPearlEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEnderPearlEntity); + + cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + + // Teleports the creator where the ender pearl lands. + void TeleportCreator(const Vector3d & a_HitPos); + +} ; // tolua_export diff --git a/src/Entities/ThrownSnowballEntity.cpp b/src/Entities/ThrownSnowballEntity.cpp new file mode 100644 index 000000000..427f630f7 --- /dev/null +++ b/src/Entities/ThrownSnowballEntity.cpp @@ -0,0 +1,48 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "ThrownSnowballEntity.h" +#include "../World.h" + + + + + +cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) +{ + Destroy(); +} + + + + + +void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) +{ + int TotalDamage = 0; + if (a_EntityHit.IsMob()) + { + cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType(); + if (MobType == cMonster::mtBlaze) + { + TotalDamage = 3; + } + else if (MobType == cMonster::mtEnderDragon) + { + TotalDamage = 1; + } + } + // TODO: If entity is Ender Crystal, destroy it + a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); + + Destroy(true); +} diff --git a/src/Entities/ThrownSnowballEntity.h b/src/Entities/ThrownSnowballEntity.h new file mode 100644 index 000000000..a09512e37 --- /dev/null +++ b/src/Entities/ThrownSnowballEntity.h @@ -0,0 +1,34 @@ +// +// ThrownSnowballEntity.h +// + +#pragma once + +#include "ProjectileEntity.h" + + + + + +// tolua_begin + +class cThrownSnowballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownSnowballEntity); + + cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override; + virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override; + +} ; // tolua_export diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp index e6634bb0d..42bf5f3f9 100644 --- a/src/FastRandom.cpp +++ b/src/FastRandom.cpp @@ -91,7 +91,8 @@ int cFastRandom::m_SeedCounter = 0; cFastRandom::cFastRandom(void) : - m_Seed(m_SeedCounter++) + m_Seed(m_SeedCounter++), + m_Counter(0) { } @@ -172,3 +173,13 @@ float cFastRandom::NextFloat(float a_Range, int a_Salt) + +int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End) +{ + cFastRandom Random; + return Random.NextInt(a_End - a_Begin + 1) + a_Begin; +} + + + + diff --git a/src/FastRandom.h b/src/FastRandom.h index bf70822cf..567198a31 100644 --- a/src/FastRandom.h +++ b/src/FastRandom.h @@ -43,6 +43,9 @@ public: /// Returns a random float in the range [0 .. a_Range]; a_Range must be less than 1M; a_Salt is additional source of randomness float NextFloat(float a_Range, int a_Salt); + + /** Returns a random int in the range [a_Begin .. a_End] */ + int GenerateRandomInteger(int a_Begin, int a_End); protected: int m_Seed; diff --git a/src/FurnaceRecipe.cpp b/src/FurnaceRecipe.cpp index 1810d7c49..bd7fd8079 100644 --- a/src/FurnaceRecipe.cpp +++ b/src/FurnaceRecipe.cpp @@ -56,7 +56,6 @@ void cFurnaceRecipe::ReloadRecipes(void) std::ifstream f; char a_File[] = "furnace.txt"; f.open(a_File, std::ios::in); - std::string input; if (!f.good()) { diff --git a/src/Generating/BioGen.cpp b/src/Generating/BioGen.cpp index 32a687201..47ba080c6 100644 --- a/src/Generating/BioGen.cpp +++ b/src/Generating/BioGen.cpp @@ -212,7 +212,7 @@ void cBioGenCache::InitializeBiomeGen(cIniFile & a_IniFile) void cBiomeGenList::InitializeBiomes(const AString & a_Biomes) { - AStringVector Split = StringSplit(a_Biomes, ","); + AStringVector Split = StringSplitAndTrim(a_Biomes, ","); // Convert each string in the list into biome: for (AStringVector::const_iterator itr = Split.begin(); itr != Split.end(); ++itr) diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt index 1147744c0..3dacb5066 100644 --- a/src/Generating/CMakeLists.txt +++ b/src/Generating/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Generating ${SOURCE}) diff --git a/src/Generating/Caves.cpp b/src/Generating/Caves.cpp index 98b7c8681..872e3341d 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -35,13 +35,6 @@ reduced in complexity in order for this generator to be useful, so the caves' sh -/// How many nests in each direction are generated for a given chunk. Must be an even number -#define NEIGHBORHOOD_SIZE 8 - - - - - const int MIN_RADIUS = 3; const int MAX_RADIUS = 8; @@ -122,27 +115,19 @@ typedef std::vector<cCaveTunnel *> cCaveTunnels; /// A collection of connected tunnels, possibly branching. -class cStructGenWormNestCaves::cCaveSystem +class cStructGenWormNestCaves::cCaveSystem : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + public: // The generating block position; is read directly in cStructGenWormNestCaves::GetCavesForChunk() int m_BlockX; int m_BlockZ; - cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise); + cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise); ~cCaveSystem(); - /// Carves the cave system into the chunk specified - void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap - ); - - #ifdef _DEBUG - AString ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const; - #endif // _DEBUG - protected: int m_Size; cCaveTunnels m_Tunnels; @@ -157,6 +142,9 @@ protected: /// Returns a radius based on the location provided. int GetRadius(cNoise & a_Noise, int a_OriginX, int a_OriginY, int a_OriginZ); + + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override; } ; @@ -200,13 +188,14 @@ void cCaveTunnel::Randomize(cNoise & a_Noise) for (int i = 0; i < 4; i++) { // For each already present point, insert a point in between it and its predecessor, shifted randomly. - int PrevX = m_Points.front().m_BlockX; - int PrevY = m_Points.front().m_BlockY; - int PrevZ = m_Points.front().m_BlockZ; - int PrevR = m_Points.front().m_Radius; + cCaveDefPoint & Point = m_Points.front(); + int PrevX = Point.m_BlockX; + int PrevY = Point.m_BlockY; + int PrevZ = Point.m_BlockZ; + int PrevR = Point.m_Radius; cCaveDefPoints Pts; Pts.reserve(m_Points.size() * 2 + 1); - Pts.push_back(m_Points.front()); + Pts.push_back(Point); for (cCaveDefPoints::const_iterator itr = m_Points.begin() + 1, end = m_Points.end(); itr != end; ++itr) { int Random = a_Noise.IntNoise3DInt(PrevX, PrevY, PrevZ + i) / 11; @@ -238,18 +227,25 @@ void cCaveTunnel::Randomize(cNoise & a_Noise) bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & a_Dst) { + if (a_Src.size() < 2) + { + // There are no midpoints, nothing to smooth + return true; + } + // Smoothing: for each line segment, add points on its 1/4 lengths bool res = false; - int Num = a_Src.size() - 2; // this many intermediary points + size_t Num = a_Src.size() - 2; // this many intermediary points a_Dst.clear(); a_Dst.reserve(Num * 2 + 2); cCaveDefPoints::const_iterator itr = a_Src.begin() + 1; - a_Dst.push_back(a_Src.front()); - int PrevX = a_Src.front().m_BlockX; - int PrevY = a_Src.front().m_BlockY; - int PrevZ = a_Src.front().m_BlockZ; - int PrevR = a_Src.front().m_Radius; - for (int i = 0; i <= Num; ++i, ++itr) + const cCaveDefPoint & Source = a_Src.front(); + a_Dst.push_back(Source); + int PrevX = Source.m_BlockX; + int PrevY = Source.m_BlockY; + int PrevZ = Source.m_BlockZ; + int PrevR = Source.m_Radius; + for (size_t i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; int dy = itr->m_BlockY - PrevY; @@ -310,9 +306,10 @@ void cCaveTunnel::FinishLinear(void) std::swap(Pts, m_Points); m_Points.reserve(Pts.size() * 3); - int PrevX = Pts.front().m_BlockX; - int PrevY = Pts.front().m_BlockY; - int PrevZ = Pts.front().m_BlockZ; + cCaveDefPoint & PrevPoint = Pts.front(); + int PrevX = PrevPoint.m_BlockX; + int PrevY = PrevPoint.m_BlockY; + int PrevZ = PrevPoint.m_BlockZ; for (cCaveDefPoints::const_iterator itr = Pts.begin() + 1, end = Pts.end(); itr != end; ++itr) { int x1 = itr->m_BlockX; @@ -433,9 +430,10 @@ void cCaveTunnel::FinishLinear(void) void cCaveTunnel::CalcBoundingBox(void) { - m_MinBlockX = m_MaxBlockX = m_Points.front().m_BlockX; - m_MinBlockY = m_MaxBlockY = m_Points.front().m_BlockY; - m_MinBlockZ = m_MaxBlockZ = m_Points.front().m_BlockZ; + cCaveDefPoint & Point = m_Points.front(); + m_MinBlockX = m_MaxBlockX = Point.m_BlockX; + m_MinBlockY = m_MaxBlockY = Point.m_BlockY; + m_MinBlockZ = m_MaxBlockZ = Point.m_BlockZ; for (cCaveDefPoints::const_iterator itr = m_Points.begin() + 1, end = m_Points.end(); itr != end; ++itr) { m_MinBlockX = std::min(m_MinBlockX, itr->m_BlockX - itr->m_Radius); @@ -576,17 +574,16 @@ AString cCaveTunnel::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) cons /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cStructGenWormNestCaves::cCaveSystem: -cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_BlockX, int a_BlockZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) : - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ), +cStructGenWormNestCaves::cCaveSystem::cCaveSystem(int a_OriginX, int a_OriginZ, int a_MaxOffset, int a_Size, cNoise & a_Noise) : + super(a_OriginX, a_OriginZ), m_Size(a_Size) { - int Num = 1 + a_Noise.IntNoise2DInt(a_BlockX, a_BlockZ) % 3; + int Num = 1 + a_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) % 3; for (int i = 0; i < Num; i++) { - int OriginX = a_BlockX + (a_Noise.IntNoise3DInt(13 * a_BlockX, 17 * a_BlockZ, 11 * i) / 19) % a_MaxOffset; - int OriginZ = a_BlockZ + (a_Noise.IntNoise3DInt(17 * a_BlockX, 13 * a_BlockZ, 11 * i) / 23) % a_MaxOffset; - int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_BlockX, 13 * a_BlockZ, 11 * i) / 17) % 20; + int OriginX = a_OriginX + (a_Noise.IntNoise3DInt(13 * a_OriginX, 17 * a_OriginZ, 11 * i) / 19) % a_MaxOffset; + int OriginZ = a_OriginZ + (a_Noise.IntNoise3DInt(17 * a_OriginX, 13 * a_OriginZ, 11 * i) / 23) % a_MaxOffset; + int OriginY = 20 + (a_Noise.IntNoise3DInt(19 * a_OriginX, 13 * a_OriginZ, 11 * i) / 17) % 20; // Generate three branches from the origin point: // The tunnels generated depend on X, Y, Z and Branches, @@ -612,64 +609,17 @@ cStructGenWormNestCaves::cCaveSystem::~cCaveSystem() -void cStructGenWormNestCaves::cCaveSystem::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap -) -{ - for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr) - { - (*itr)->ProcessChunk(a_ChunkX, a_ChunkZ, a_BlockTypes, a_HeightMap); - } // for itr - m_Tunnels[] -} - - - - - -#ifdef _DEBUG -AString cStructGenWormNestCaves::cCaveSystem::ExportAsSVG(int a_Color, int a_OffsetX, int a_OffsetZ) const +void cStructGenWormNestCaves::cCaveSystem::DrawIntoChunk(cChunkDesc & a_ChunkDesc) { - AString SVG; - SVG.reserve(512 * 1024); + int ChunkX = a_ChunkDesc.GetChunkX(); + int ChunkZ = a_ChunkDesc.GetChunkZ(); + cChunkDef::BlockTypes & BlockTypes = a_ChunkDesc.GetBlockTypes(); + cChunkDef::HeightMap & HeightMap = a_ChunkDesc.GetHeightMap(); for (cCaveTunnels::const_iterator itr = m_Tunnels.begin(), end = m_Tunnels.end(); itr != end; ++itr) { - SVG.append((*itr)->ExportAsSVG(a_Color, a_OffsetX, a_OffsetZ)); + (*itr)->ProcessChunk(ChunkX, ChunkZ, BlockTypes, HeightMap); } // for itr - m_Tunnels[] - - // Base point highlight: - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ - ); - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5 - ); - - // A gray line from the base point to the first point of the ravine, for identification: - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, - a_OffsetX + m_Tunnels.front()->m_Points.front().m_BlockX, - a_OffsetZ + m_Tunnels.front()->m_Points.front().m_BlockZ - ); - - // Offset guides: - if (a_OffsetX > 0) - { - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M %d,0 L %d,1024\"/>\n", - a_OffsetX, a_OffsetX - ); - } - if (a_OffsetZ > 0) - { - AppendPrintf(SVG, "<path style=\"fill:none;stroke:#0000ff;stroke-width:1px;\"\nd=\"M 0,%d L 1024,%d\"/>\n", - a_OffsetZ, a_OffsetZ - ); - } - - return SVG; } -#endif // _DEBUG @@ -740,142 +690,9 @@ int cStructGenWormNestCaves::cCaveSystem::GetRadius(cNoise & a_Noise, int a_Orig /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cStructGenWormNestCaves: -cStructGenWormNestCaves::~cStructGenWormNestCaves() -{ - ClearCache(); -} - - - - - -void cStructGenWormNestCaves::ClearCache(void) +cGridStructGen::cStructurePtr cStructGenWormNestCaves::CreateStructure(int a_OriginX, int a_OriginZ) { - for (cCaveSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_Cache[] - m_Cache.clear(); -} - - - - - -void cStructGenWormNestCaves::GenFinish(cChunkDesc & a_ChunkDesc) -{ - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cCaveSystems Caves; - GetCavesForChunk(ChunkX, ChunkZ, Caves); - for (cCaveSystems::const_iterator itr = Caves.begin(); itr != Caves.end(); ++itr) - { - (*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); - } // for itr - Caves[] -} - - - - - -void cStructGenWormNestCaves::GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenWormNestCaves::cCaveSystems & a_Caves) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_Grid; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_Grid; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= NEIGHBORHOOD_SIZE / 2; - BaseZ -= NEIGHBORHOOD_SIZE / 2; - - // Walk the cache, move each cave system that we want into a_Caves: - int StartX = BaseX * m_Grid; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Grid; - int StartZ = BaseZ * m_Grid; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Grid; - for (cCaveSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_Caves.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_Grid; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_Grid; - bool Found = false; - for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } - if (!Found) - { - a_Caves.push_back(new cCaveSystem(RealX, RealZ, m_MaxOffset, m_Size, m_Noise)); - } - } - } - - // Copy a_Caves into m_Cache to the beginning: - cCaveSystems CavesCopy(a_Caves); - m_Cache.splice(m_Cache.begin(), CavesCopy, CavesCopy.begin(), CavesCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cCaveSystems::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cCaveSystems::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } - - /* - // Uncomment this block for debugging the caves' shapes in 2D using an SVG export - #ifdef _DEBUG - AString SVG; - SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n"); - SVG.reserve(2 * 1024 * 1024); - for (cCaveSystems::const_iterator itr = a_Caves.begin(), end = a_Caves.end(); itr != end; ++itr) - { - int Color = 0x10 * abs((*itr)->m_BlockX / m_Grid); - Color |= 0x1000 * abs((*itr)->m_BlockZ / m_Grid); - SVG.append((*itr)->ExportAsSVG(Color, 512, 512)); - } - SVG.append("</svg>\n"); - - AString fnam; - Printf(fnam, "wnc\\%03d_%03d.svg", a_ChunkX, a_ChunkZ); - cFile File(fnam, cFile::fmWrite); - File.Write(SVG.c_str(), SVG.size()); - #endif // _DEBUG - //*/ + return cStructurePtr(new cCaveSystem(a_OriginX, a_OriginZ, m_MaxOffset, m_Size, m_Noise)); } diff --git a/src/Generating/Caves.h b/src/Generating/Caves.h index 7c45c056b..254dcddbd 100644 --- a/src/Generating/Caves.h +++ b/src/Generating/Caves.h @@ -12,7 +12,7 @@ #pragma once -#include "ComposableGenerator.h" +#include "GridStructGen.h" #include "../Noise.h" @@ -64,10 +64,12 @@ protected: class cStructGenWormNestCaves : - public cFinishGen + public cGridStructGen { + typedef cGridStructGen super; public: cStructGenWormNestCaves(int a_Seed, int a_Size = 64, int a_Grid = 96, int a_MaxOffset = 128) : + super(a_Seed, a_Grid, a_Grid, a_Size + a_MaxOffset, a_Size + a_MaxOffset, 100), m_Noise(a_Seed), m_Size(a_Size), m_MaxOffset(a_MaxOffset), @@ -75,26 +77,16 @@ public: { } - ~cStructGenWormNestCaves(); - protected: class cCaveSystem; // fwd: Caves.cpp - typedef std::list<cCaveSystem *> cCaveSystems; cNoise m_Noise; int m_Size; // relative size of the cave systems' caves. Average number of blocks of each initial tunnel int m_MaxOffset; // maximum offset of the cave nest origin from the grid cell the nest belongs to int m_Grid; // average spacing of the nests - cCaveSystems m_Cache; - - /// Clears everything from the cache - void ClearCache(void); - - /// Returns all caves that *may* intersect the given chunk. All the caves are valid until the next call to this function. - void GetCavesForChunk(int a_ChunkX, int a_ChunkZ, cCaveSystems & a_Caves); - - // cStructGen override: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // cGridStructGen override: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp index 6c00b5905..4dd626ed4 100644 --- a/src/Generating/ComposableGenerator.cpp +++ b/src/Generating/ComposableGenerator.cpp @@ -21,9 +21,11 @@ #include "DistortedHeightmap.h" #include "EndGen.h" #include "MineShafts.h" +#include "NetherFortGen.h" #include "Noise3DGenerator.h" #include "POCPieceGenerator.h" #include "Ravines.h" +#include "VillageGen.h" @@ -31,6 +33,7 @@ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cTerrainCompositionGen: + cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed) { AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", ""); @@ -191,9 +194,11 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a m_HeightGen->GenHeightMap(a_ChunkX, a_ChunkZ, a_ChunkDesc.GetHeightMap()); } + bool ShouldUpdateHeightmap = false; if (a_ChunkDesc.IsUsingDefaultComposition()) { m_CompositionGen->ComposeTerrain(a_ChunkDesc); + ShouldUpdateHeightmap = true; } if (a_ChunkDesc.IsUsingDefaultFinish()) @@ -202,6 +207,12 @@ void cComposableGenerator::DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a { (*itr)->GenFinish(a_ChunkDesc); } // for itr - m_FinishGens[] + ShouldUpdateHeightmap = true; + } + + if (ShouldUpdateHeightmap) + { + a_ChunkDesc.UpdateHeightmap(); } } @@ -349,7 +360,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) int ChanceCrossing = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceCrossing", 200); int ChanceStaircase = a_IniFile.GetValueSetI("Generator", "MineShaftsChanceStaircase", 200); m_FinishGens.push_back(new cStructGenMineShafts( - Seed, GridSize, MaxSystemSize, + Seed, GridSize, MaxSystemSize, ChanceCorridor, ChanceCrossing, ChanceStaircase )); } @@ -361,6 +372,12 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { m_FinishGens.push_back(new cFinishGenNetherClumpFoliage(Seed)); } + else if (NoCaseCompare(*itr, "NetherForts") == 0) + { + int GridSize = a_IniFile.GetValueSetI("Generator", "NetherFortsGridSize", 512); + int MaxDepth = a_IniFile.GetValueSetI("Generator", "NetherFortsMaxDepth", 12); + m_FinishGens.push_back(new cNetherFortGen(Seed, GridSize, MaxDepth)); + } else if (NoCaseCompare(*itr, "OreNests") == 0) { m_FinishGens.push_back(new cStructGenOreNests(Seed)); @@ -389,6 +406,15 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile) { m_FinishGens.push_back(new cStructGenTrees(Seed, m_BiomeGen, m_HeightGen, m_CompositionGen)); } + else if (NoCaseCompare(*itr, "Villages") == 0) + { + int GridSize = a_IniFile.GetValueSetI("Generator", "VillageGridSize", 384); + int MaxDepth = a_IniFile.GetValueSetI("Generator", "VillageMaxDepth", 2); + int MaxSize = a_IniFile.GetValueSetI("Generator", "VillageMaxSize", 128); + int MinDensity = a_IniFile.GetValueSetI("Generator", "VillageMinDensity", 50); + int MaxDensity = a_IniFile.GetValueSetI("Generator", "VillageMaxDensity", 80); + m_FinishGens.push_back(new cVillageGen(Seed, GridSize, MaxDepth, MaxSize, MinDensity, MaxDensity, *m_BiomeGen, *m_HeightGen)); + } else if (NoCaseCompare(*itr, "WaterLakes") == 0) { int Probability = a_IniFile.GetValueSetI("Generator", "WaterLakesProbability", 25); diff --git a/src/Generating/GridStructGen.cpp b/src/Generating/GridStructGen.cpp new file mode 100644 index 000000000..474242557 --- /dev/null +++ b/src/Generating/GridStructGen.cpp @@ -0,0 +1,168 @@ + +// GridStructGen.cpp + +// Implements the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid + +#include "Globals.h" +#include "GridStructGen.h" + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cEmptyStructure: + +/** A cStructure descendant representing an empty structure. +Used when the generator descended from cGridStructGen doesn't return any structure, to keep at least the +Origin coords so that the structure isn't queried over and over again. */ +class cEmptyStructure : + public cGridStructGen::cStructure +{ + typedef cGridStructGen::cStructure super; + +public: + cEmptyStructure(int a_OriginX, int a_OriginZ) : + super(a_OriginX, a_OriginZ) + { + } + +protected: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override + { + // Do nothing + } +} ; + + + + + +cGridStructGen::cGridStructGen( + int a_Seed, + int a_GridSizeX, int a_GridSizeZ, + int a_MaxStructureSizeX, int a_MaxStructureSizeZ, + size_t a_MaxCacheSize +) : + m_Seed(a_Seed), + m_GridSizeX(a_GridSizeX), + m_GridSizeZ(a_GridSizeZ), + m_MaxStructureSizeX(a_MaxStructureSizeX), + m_MaxStructureSizeZ(a_MaxStructureSizeZ), + m_MaxCacheSize(a_MaxCacheSize) +{ + size_t NumStructuresPerQuery = (size_t)((m_MaxStructureSizeX / m_GridSizeX + 1) * (m_MaxStructureSizeZ / m_GridSizeZ + 1)); + if (NumStructuresPerQuery > m_MaxCacheSize) + { + m_MaxCacheSize = NumStructuresPerQuery * 4; + LOGINFO( + "cGridStructGen: The cache size is too small (%u), increasing the cache size to %u to avoid inefficiency.", + (unsigned)a_MaxCacheSize, (unsigned)m_MaxCacheSize + ); + } +} + + + + + +void cGridStructGen::GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures) +{ + // Calculate the min and max grid coords of the structures to be returned: + int MinBlockX = a_ChunkX * cChunkDef::Width - m_MaxStructureSizeX; + int MinBlockZ = a_ChunkZ * cChunkDef::Width - m_MaxStructureSizeZ; + int MaxBlockX = a_ChunkX * cChunkDef::Width + m_MaxStructureSizeX + cChunkDef::Width - 1; + int MaxBlockZ = a_ChunkZ * cChunkDef::Width + m_MaxStructureSizeZ + cChunkDef::Width - 1; + int MinGridX = MinBlockX / m_GridSizeX; + int MinGridZ = MinBlockZ / m_GridSizeZ; + int MaxGridX = (MaxBlockX + m_GridSizeX - 1) / m_GridSizeX; + int MaxGridZ = (MaxBlockZ + m_GridSizeZ - 1) / m_GridSizeZ; + int MinX = MinGridX * m_GridSizeX; + int MaxX = MaxGridX * m_GridSizeX; + int MinZ = MinGridZ * m_GridSizeZ; + int MaxZ = MaxGridZ * m_GridSizeZ; + + // Walk the cache, move each structure that we want into a_Structures: + for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) + { + if ( + ((*itr)->m_OriginX >= MinX) && ((*itr)->m_OriginX < MaxX) && + ((*itr)->m_OriginZ >= MinZ) && ((*itr)->m_OriginZ < MaxZ) + ) + { + // want + a_Structures.push_back(*itr); + itr = m_Cache.erase(itr); + } + else + { + // don't want + ++itr; + } + } // for itr - m_Cache[] + + // Create those structures that haven't been in the cache: + for (int x = MinGridX; x < MaxGridX; x++) + { + int OriginX = x * m_GridSizeX; + for (int z = MinGridZ; z < MaxGridZ; z++) + { + int OriginZ = z * m_GridSizeZ; + bool Found = false; + for (cStructurePtrs::const_iterator itr = a_Structures.begin(), end = a_Structures.end(); itr != end; ++itr) + { + if (((*itr)->m_OriginX == OriginX) && ((*itr)->m_OriginZ == OriginZ)) + { + Found = true; + break; + } + } // for itr - a_Structures[] + if (!Found) + { + cStructurePtr Structure = CreateStructure(OriginX, OriginZ); + if (Structure.get() == NULL) + { + Structure.reset(new cEmptyStructure(OriginX, OriginZ)); + } + a_Structures.push_back(Structure); + } + } // for z + } // for x + + // Copy a_Forts into m_Cache to the beginning: + cStructurePtrs StructuresCopy (a_Structures); + m_Cache.splice(m_Cache.begin(), StructuresCopy, StructuresCopy.begin(), StructuresCopy.end()); + + // Trim the cache if it's too long: + size_t CacheSize = 0; + for (cStructurePtrs::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) + { + CacheSize += (*itr)->GetCacheCost(); + if (CacheSize > m_MaxCacheSize) + { + // Erase all items from this one till the cache end + m_Cache.erase(itr, m_Cache.end()); + break; + } + } +} + + + + + +void cGridStructGen::GenFinish(cChunkDesc & a_ChunkDesc) +{ + int ChunkX = a_ChunkDesc.GetChunkX(); + int ChunkZ = a_ChunkDesc.GetChunkZ(); + cStructurePtrs Structures; + GetStructuresForChunk(ChunkX, ChunkZ, Structures); + for (cStructurePtrs::const_iterator itr = Structures.begin(); itr != Structures.end(); ++itr) + { + (*itr)->DrawIntoChunk(a_ChunkDesc); + } // for itr - Structures[] +} + + + + + diff --git a/src/Generating/GridStructGen.h b/src/Generating/GridStructGen.h new file mode 100644 index 000000000..630a5e44e --- /dev/null +++ b/src/Generating/GridStructGen.h @@ -0,0 +1,124 @@ + +// GridStructGen.h + +// Declares the cGridStructGen class representing a common base class for structure generators that place structures in a semi-random grid + + + + + +#pragma once + +#include "ComposableGenerator.h" + + + + + +/** Generates structures in a semi-random grid. +Defines a grid in the XZ space with predefined cell size in each direction. Each cell then receives exactly +one structure (provided by the descendant class). The structure is placed within the cell, but doesn't need +to be bounded by the cell, it can be well outside the cell; the generator uses the MaxStructureSize parameter +to determine how far away from the cell the structure can be at most. +This class provides a cache for the structures generated for successive chunks and manages that cache. It +also provides the cFinishGen override that uses the cache to actually generate the structure into chunk data. + +After generating each chunk the cache is checked for size, each item in the cache has a cost associated with +it and the cache is trimmed (from its least-recently-used end) so that the sum of the cost in the cache is +less than m_MaxCacheSize + +To use this class, declare a descendant class that implements the overridable methods, then create an +instance of that class. The descendant must provide the CreateStructure() function that is called to generate +a structure at the specific grid cell. + +The descendant must use a specific cStructure descendant to provide the actual structure that gets generated. +The structure must provide the DrawIntoChunk() function that generates the structure into the chunk data, and +can override the GetCacheCost() function that returns the cost of that structure in the cache. +*/ +class cGridStructGen : + public cFinishGen +{ +public: + /** Represents a single structure that occupies the grid point. Knows how to draw itself into a chunk. */ + class cStructure + { + public: + /** The origin (the coords of the gridpoint for which the structure is generated) */ + int m_OriginX, m_OriginZ; + + + /** Creates a structure that has its originset at the specified coords. */ + cStructure (int a_OriginX, int a_OriginZ) : + m_OriginX(a_OriginX), + m_OriginZ(a_OriginZ) + { + } + + // Force a virtual destructor in descendants: + virtual ~cStructure() {} + + /** Draws self into the specified chunk */ + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) = 0; + + /** Returns the cost of keeping this structure in the cache */ + virtual size_t GetCacheCost(void) const { return 1; } + } ; + typedef SharedPtr<cStructure> cStructurePtr; + typedef std::list<cStructurePtr> cStructurePtrs; + + + cGridStructGen( + int a_Seed, + int a_GridSizeX, int a_GridSizeZ, + int a_MaxStructureSizeX, int a_MaxStructureSizeZ, + size_t a_MaxCacheSize + ); + +protected: + /** Seed for generating the semi-random grid. */ + int m_Seed; + + /** The size of each grid's cell in the X axis */ + int m_GridSizeX; + + /** The size of each grid's cell in the Z axis */ + int m_GridSizeZ; + + /** Maximum theoretical size of the structure in the X axis. + This limits the structures considered for a single chunk, so the lesser the number, the better performance. + Structures large than this may get cropped. */ + int m_MaxStructureSizeX; + + /** Maximum theoretical size of the structure in the Z axis. + This limits the structures considered for a single chunk, so the lesser the number, the better performance. + Structures large than this may get cropped. */ + int m_MaxStructureSizeZ; + + /** Maximum allowed sum of costs for items in the cache. Items that are over this cost are removed from the + cache, oldest-first */ + size_t m_MaxCacheSize; + + /** Cache for the most recently generated structures, ordered by the recentness. */ + cStructurePtrs m_Cache; + + + /** Clears everything from the cache */ + void ClearCache(void); + + /** Returns all structures that may intersect the given chunk. + The structures are considered as intersecting iff their bounding box (defined by m_MaxStructureSize) + around their gridpoint intersects the chunk. */ + void GetStructuresForChunk(int a_ChunkX, int a_ChunkZ, cStructurePtrs & a_Structures); + + // cFinishGen overrides: + virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // Functions for the descendants to override: + /** Create a new structure at the specified gridpoint */ + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) = 0; +} ; + + + + + diff --git a/src/Generating/MineShafts.cpp b/src/Generating/MineShafts.cpp index 28dc37567..81ae6481d 100644 --- a/src/Generating/MineShafts.cpp +++ b/src/Generating/MineShafts.cpp @@ -25,12 +25,6 @@ in a depth-first processing. Each of the descendants will branch randomly, if no -static const int NEIGHBORHOOD_SIZE = 3; - - - - - class cMineShaft abstract { public: @@ -234,10 +228,12 @@ protected: -class cStructGenMineShafts::cMineShaftSystem +class cStructGenMineShafts::cMineShaftSystem : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + public: - int m_BlockX, m_BlockZ; ///< The pivot point on which the system is generated int m_GridSize; ///< Maximum offset of the dirtroom from grid center, * 2, in each direction int m_MaxRecursion; ///< Maximum recursion level (initialized from cStructGenMineShafts::m_MaxRecursion) int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor @@ -249,17 +245,15 @@ public: cMineShafts m_MineShafts; ///< List of cMineShaft descendants that comprise this system cCuboid m_BoundingBox; ///< Bounding box into which all of the components need to fit - /// Creates and generates the entire system + + /** Creates and generates the entire system */ cMineShaftSystem( - int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, + int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase ); ~cMineShaftSystem(); - /// Carves the system into the chunk data - void ProcessChunk(cChunkDesc & a_Chunk); - /** Creates new cMineShaft descendant connected at the specified point, heading the specified direction, if it fits, appends it to the list and calls its AppendBranches() */ @@ -269,8 +263,11 @@ public: int a_RecursionLevel ); - /// Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid + /** Returns true if none of the objects in m_MineShafts intersect with the specified bounding box and the bounding box is valid */ bool CanAppend(const cCuboid & a_BoundingBox); + + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_Chunk); } ; @@ -281,11 +278,10 @@ public: // cStructGenMineShafts::cMineShaftSystem: cStructGenMineShafts::cMineShaftSystem::cMineShaftSystem( - int a_BlockX, int a_BlockZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, + int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxSystemSize, cNoise & a_Noise, int a_ProbLevelCorridor, int a_ProbLevelCrossing, int a_ProbLevelStaircase ) : - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ), + super(a_OriginX, a_OriginZ), m_GridSize(a_GridSize), m_MaxRecursion(8), // TODO: settable m_ProbLevelCorridor(a_ProbLevelCorridor), @@ -330,7 +326,7 @@ cStructGenMineShafts::cMineShaftSystem::~cMineShaftSystem() -void cStructGenMineShafts::cMineShaftSystem::ProcessChunk(cChunkDesc & a_Chunk) +void cStructGenMineShafts::cMineShaftSystem::DrawIntoChunk(cChunkDesc & a_Chunk) { for (cMineShafts::const_iterator itr = m_MineShafts.begin(), end = m_MineShafts.end(); itr != end; ++itr) { @@ -409,15 +405,15 @@ cMineShaftDirtRoom::cMineShaftDirtRoom(cStructGenMineShafts::cMineShaftSystem & super(a_Parent, mskDirtRoom) { // Make the room of random size, min 10 x 4 x 10; max 18 x 12 x 18: - int rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 0, a_Parent.m_BlockZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 0, a_Parent.m_OriginZ) / 7; int OfsX = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2; rnd >>= 12; int OfsZ = (rnd % a_Parent.m_GridSize) - a_Parent.m_GridSize / 2; - rnd = a_Noise.IntNoise3DInt(a_Parent.m_BlockX, 1000, a_Parent.m_BlockZ) / 11; - m_BoundingBox.p1.x = a_Parent.m_BlockX + OfsX; + rnd = a_Noise.IntNoise3DInt(a_Parent.m_OriginX, 1000, a_Parent.m_OriginZ) / 11; + m_BoundingBox.p1.x = a_Parent.m_OriginX + OfsX; m_BoundingBox.p2.x = m_BoundingBox.p1.x + 10 + (rnd % 8); rnd >>= 4; - m_BoundingBox.p1.z = a_Parent.m_BlockZ + OfsZ; + m_BoundingBox.p1.z = a_Parent.m_OriginZ + OfsZ; m_BoundingBox.p2.z = m_BoundingBox.p1.z + 10 + (rnd % 8); rnd >>= 4; m_BoundingBox.p1.y = 20; @@ -543,7 +539,7 @@ cMineShaft * cMineShaftCorridor::CreateAndFit( { cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ); BoundingBox.p2.y += 3; - int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; int NumSegments = 2 + (rnd) % (MAX_SEGMENTS - 1); // 2 .. MAX_SEGMENTS switch (a_Direction) { @@ -985,7 +981,7 @@ cMineShaft * cMineShaftCrossing::CreateAndFit( ) { cCuboid BoundingBox(a_PivotX, a_PivotY - 1, a_PivotZ); - int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; BoundingBox.p2.y += 3; if ((rnd % 4) < 2) { @@ -1127,7 +1123,7 @@ cMineShaft * cMineShaftStaircase::CreateAndFit( cNoise & a_Noise ) { - int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; + int rnd = a_Noise.IntNoise3DInt(a_PivotX, a_PivotY + (int)a_ParentSystem.m_MineShafts.size(), a_PivotZ) / 7; cCuboid Box; switch (a_Direction) { @@ -1287,6 +1283,7 @@ cStructGenMineShafts::cStructGenMineShafts( int a_Seed, int a_GridSize, int a_MaxSystemSize, int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase ) : + super(a_Seed, a_GridSize, a_GridSize, a_MaxSystemSize, a_MaxSystemSize, 100), m_Noise(a_Seed), m_GridSize(a_GridSize), m_MaxSystemSize(a_MaxSystemSize), @@ -1300,125 +1297,9 @@ cStructGenMineShafts::cStructGenMineShafts( -cStructGenMineShafts::~cStructGenMineShafts() -{ - ClearCache(); -} - - - - - -void cStructGenMineShafts::ClearCache(void) -{ - for (cMineShaftSystems::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_Cache[] - m_Cache.clear(); -} - - - - - -void cStructGenMineShafts::GetMineShaftSystemsForChunk( - int a_ChunkX, int a_ChunkZ, - cStructGenMineShafts::cMineShaftSystems & a_MineShafts -) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_GridSize; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_GridSize; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= NEIGHBORHOOD_SIZE / 2; - BaseZ -= NEIGHBORHOOD_SIZE / 2; - - // Walk the cache, move each cave system that we want into a_Caves: - int StartX = BaseX * m_GridSize; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_GridSize; - int StartZ = BaseZ * m_GridSize; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_GridSize; - for (cMineShaftSystems::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_MineShafts.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_GridSize; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_GridSize; - bool Found = false; - for (cMineShaftSystems::const_iterator itr = a_MineShafts.begin(), end = a_MineShafts.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } // for itr - a_Mineshafts - if (!Found) - { - a_MineShafts.push_back(new cMineShaftSystem(RealX, RealZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase)); - } - } // for z - } // for x - - // Copy a_MineShafts into m_Cache to the beginning: - cMineShaftSystems MineShaftsCopy(a_MineShafts); - m_Cache.splice(m_Cache.begin(), MineShaftsCopy, MineShaftsCopy.begin(), MineShaftsCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cMineShaftSystems::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cMineShaftSystems::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } -} - - - - - - -void cStructGenMineShafts::GenFinish(cChunkDesc & a_ChunkDesc) +cGridStructGen::cStructurePtr cStructGenMineShafts::CreateStructure(int a_OriginX, int a_OriginZ) { - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cMineShaftSystems MineShafts; - GetMineShaftSystemsForChunk(ChunkX, ChunkZ, MineShafts); - for (cMineShaftSystems::const_iterator itr = MineShafts.begin(); itr != MineShafts.end(); ++itr) - { - (*itr)->ProcessChunk(a_ChunkDesc); - } // for itr - MineShafts[] + return cStructurePtr(new cMineShaftSystem(a_OriginX, a_OriginZ, m_GridSize, m_MaxSystemSize, m_Noise, m_ProbLevelCorridor, m_ProbLevelCrossing, m_ProbLevelStaircase)); } diff --git a/src/Generating/MineShafts.h b/src/Generating/MineShafts.h index ba32e75ad..c29b6cdac 100644 --- a/src/Generating/MineShafts.h +++ b/src/Generating/MineShafts.h @@ -9,7 +9,7 @@ #pragma once -#include "ComposableGenerator.h" +#include "GridStructGen.h" #include "../Noise.h" @@ -17,16 +17,16 @@ class cStructGenMineShafts : - public cFinishGen + public cGridStructGen { + typedef cGridStructGen super; + public: cStructGenMineShafts( int a_Seed, int a_GridSize, int a_MaxSystemSize, int a_ChanceCorridor, int a_ChanceCrossing, int a_ChanceStaircase ); - virtual ~cStructGenMineShafts(); - protected: friend class cMineShaft; friend class cMineShaftDirtRoom; @@ -34,26 +34,16 @@ protected: friend class cMineShaftCrossing; friend class cMineShaftStaircase; class cMineShaftSystem; // fwd: MineShafts.cpp - typedef std::list<cMineShaftSystem *> cMineShaftSystems; - cNoise m_Noise; - int m_GridSize; ///< Average spacing of the systems - int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system - int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor - int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor - int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing - cMineShaftSystems m_Cache; ///< Cache of the most recently used systems. MoveToFront used. + cNoise m_Noise; + int m_GridSize; ///< Average spacing of the systems + int m_MaxSystemSize; ///< Maximum blcok size of a mineshaft system + int m_ProbLevelCorridor; ///< Probability level of a branch object being the corridor + int m_ProbLevelCrossing; ///< Probability level of a branch object being the crossing, minus Corridor + int m_ProbLevelStaircase; ///< Probability level of a branch object being the staircase, minus Crossing - /// Clears everything from the cache - void ClearCache(void); - - /** Returns all systems that *may* intersect the given chunk. - All the systems are valid until the next call to this function (which may delete some of the pointers). - */ - void GetMineShaftSystemsForChunk(int a_ChunkX, int a_ChunkZ, cMineShaftSystems & a_MineShaftSystems); - - // cFinishGen overrides: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp new file mode 100644 index 000000000..3867ec80c --- /dev/null +++ b/src/Generating/NetherFortGen.cpp @@ -0,0 +1,131 @@ + +// NetherFortGen.cpp + +// Implements the cNetherFortGen class representing the nether fortress generator + +#include "Globals.h" +#include "NetherFortGen.h" +#include "Prefabs/NetherFortPrefabs.h" + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cNetherFortGen::cNetherFort: + +class cNetherFortGen::cNetherFort : + public cGridStructGen::cStructure +{ + typedef cGridStructGen::cStructure super; + +public: + cNetherFortGen & m_ParentGen; + int m_GridSize; + int m_Seed; + cPlacedPieces m_Pieces; + + + cNetherFort(cNetherFortGen & a_ParentGen, int a_OriginX, int a_OriginZ, int a_GridSize, int a_MaxDepth, int a_Seed) : + super(a_OriginX, a_OriginZ), + m_ParentGen(a_ParentGen), + m_GridSize(a_GridSize), + m_Seed(a_Seed) + { + // TODO: Proper Y-coord placement + int BlockY = 64; + + // Generate pieces: + for (int i = 0; m_Pieces.size() < (size_t)(a_MaxDepth * a_MaxDepth / 8 + a_MaxDepth); i++) + { + cBFSPieceGenerator pg(cNetherFortGen::m_PiecePool, a_Seed + i); + pg.PlacePieces(a_OriginX, BlockY, a_OriginZ, a_MaxDepth, m_Pieces); + } + } + + + ~cNetherFort() + { + cPieceGenerator::FreePieces(m_Pieces); + } + + + /** Carves the system into the chunk data */ + virtual void DrawIntoChunk(cChunkDesc & a_Chunk) + { + for (cPlacedPieces::const_iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) + { + const cPrefab & Prefab = (const cPrefab &)((*itr)->GetPiece()); + Prefab.Draw(a_Chunk, *itr); + } // for itr - m_PlacedPieces[] + } +}; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Performance test of the NetherFort generator: + +/* +#include "OSSupport/Timer.h" +static class cNetherFortPerfTest +{ +public: + cNetherFortPerfTest(void) + { + cTimer Timer; + long long StartTime = Timer.GetNowTime(); + + const int GridSize = 512; + const int MaxDepth = 12; + const int NumIterations = 100; + for (int i = 0; i < NumIterations; i++) + { + cNetherFortGen FortGen(i, GridSize, MaxDepth); + delete new cNetherFortGen::cNetherFort(FortGen, 0, 0, GridSize, MaxDepth, i); + } + + long long EndTime = Timer.GetNowTime(); + printf("%d forts took %lld msec (%f sec) to generate\n", NumIterations, EndTime - StartTime, ((double)(EndTime - StartTime)) / 1000); + exit(0); + } + +} g_PerfTest; +//*/ + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cNetherFortGen: + +cPrefabPiecePool cNetherFortGen::m_PiecePool(g_NetherFortPrefabs, g_NetherFortPrefabsCount, g_NetherFortStartingPrefabs, g_NetherFortStartingPrefabsCount); + + + + + +cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) : + super(a_Seed, a_GridSize, a_GridSize, a_MaxDepth * 10, a_MaxDepth * 10, 200), + m_MaxDepth(a_MaxDepth) +{ + /* + // DEBUG: Try one round of placement: + cPlacedPieces Pieces; + cBFSPieceGenerator pg(m_PiecePool, a_Seed); + pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces); + //*/ +} + + + + + +cGridStructGen::cStructurePtr cNetherFortGen::CreateStructure(int a_OriginX, int a_OriginZ) +{ + return cStructurePtr(new cNetherFort(*this, a_OriginX, a_OriginZ, m_GridSizeX, m_MaxDepth, m_Seed)); +} + diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h new file mode 100644 index 000000000..f35801a3c --- /dev/null +++ b/src/Generating/NetherFortGen.h @@ -0,0 +1,45 @@ + +// NetherFortGen.h + +// Declares the cNetherFortGen class representing the nether fortress generator + + + + + +#pragma once + +#include "ComposableGenerator.h" +#include "PrefabPiecePool.h" +#include "GridStructGen.h" + + + + + +class cNetherFortGen : + public cGridStructGen +{ + typedef cGridStructGen super; + +public: + cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth); + +protected: + friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp + class cNetherFort; // fwd: NetherFortGen.cpp + + /** Maximum depth of the piece-generator tree */ + int m_MaxDepth; + + /** The pool of pieces to use for generating. Static, so that it's shared by multiple generators. */ + static cPrefabPiecePool m_PiecePool; + + + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; +} ; + + + + diff --git a/src/Generating/POCPieceGenerator.cpp b/src/Generating/POCPieceGenerator.cpp index 9ed4b565e..491f4d206 100644 --- a/src/Generating/POCPieceGenerator.cpp +++ b/src/Generating/POCPieceGenerator.cpp @@ -186,6 +186,11 @@ cPOCPieceGenerator::cPOCPieceGenerator(int a_Seed) : cPOCPieceGenerator::~cPOCPieceGenerator() { cPieceGenerator::FreePieces(m_Pieces); + for (cPieces::iterator itr = m_AvailPieces.begin(), end = m_AvailPieces.end(); itr != end; ++itr) + { + delete *itr; + } + m_AvailPieces.clear(); } diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index 8999a5ff7..5de231f75 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -286,7 +286,8 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece m_Parent(a_Parent), m_Piece(&a_Piece), m_Coords(a_Coords), - m_NumCCWRotations(a_NumCCWRotations) + m_NumCCWRotations(a_NumCCWRotations), + m_HasBeenMovedToGround(false) { m_Depth = (m_Parent == NULL) ? 0 : (m_Parent->GetDepth() + 1); m_HitBox = a_Piece.RotateMoveHitBox(a_NumCCWRotations, a_Coords.x, a_Coords.y, a_Coords.z); @@ -297,6 +298,36 @@ cPlacedPiece::cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece +cPiece::cConnector cPlacedPiece::GetRotatedConnector(size_t a_Index) const +{ + cPiece::cConnectors Connectors = m_Piece->GetConnectors(); + ASSERT(Connectors.size() >= a_Index); + return m_Piece->RotateMoveConnector(Connectors[a_Index], m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z); +} + + + + + +cPiece::cConnector cPlacedPiece::GetRotatedConnector(const cPiece::cConnector & a_Connector) const +{ + return m_Piece->RotateMoveConnector(a_Connector, m_NumCCWRotations, m_Coords.x, m_Coords.y, m_Coords.z); +} + + + + + +void cPlacedPiece::MoveToGroundBy(int a_OffsetY) +{ + m_Coords.y += a_OffsetY; + m_HasBeenMovedToGround = true; +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPieceGenerator: @@ -331,7 +362,31 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i // Choose a random one of the starting pieces: cPieces StartingPieces = m_PiecePool.GetStartingPieces(); - cPiece * StartingPiece = StartingPieces[rnd % StartingPieces.size()]; + int Total = 0; + for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr) + { + Total += m_PiecePool.GetStartingPieceWeight(**itr); + } + cPiece * StartingPiece; + if (Total > 0) + { + int Chosen = rnd % Total; + StartingPiece = StartingPieces.front(); + for (cPieces::const_iterator itr = StartingPieces.begin(), end = StartingPieces.end(); itr != end; ++itr) + { + Chosen -= m_PiecePool.GetStartingPieceWeight(**itr); + if (Chosen <= 0) + { + StartingPiece = *itr; + break; + } + } + } + else + { + // All pieces returned zero weight, but we need one to start. Choose with equal chance: + StartingPiece = StartingPieces[rnd % StartingPieces.size()]; + } rnd = rnd >> 16; // Choose a random supported rotation: @@ -339,9 +394,9 @@ cPlacedPiece * cPieceGenerator::PlaceStartingPiece(int a_BlockX, int a_BlockY, i int NumRotations = 1; for (size_t i = 1; i < ARRAYCOUNT(Rotations); i++) { - if (StartingPiece->CanRotateCCW(i)) + if (StartingPiece->CanRotateCCW((int)i)) { - Rotations[NumRotations] = i; + Rotations[NumRotations] = (int)i; NumRotations += 1; } } @@ -388,22 +443,26 @@ bool cPieceGenerator::TryPlacePieceAtConnector( // Get a list of available connections: const int * RotTable = DirectionRotationTable[a_Connector.m_Direction]; cConnections Connections; - cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(a_Connector.m_Type); + int WantedConnectorType = -a_Connector.m_Type; + cPieces AvailablePieces = m_PiecePool.GetPiecesWithConnector(WantedConnectorType); Connections.reserve(AvailablePieces.size()); Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction); - - /* - // DEBUG: - printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str()); - //*/ - + int WeightTotal = 0; for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) { + // Get the relative chance of this piece being generated in this path: + int Weight = m_PiecePool.GetPieceWeight(a_ParentPiece, a_Connector, **itrP); + if (Weight <= 0) + { + continue; + } + + // Try fitting each of the piece's connector: cPiece::cConnectors Connectors = (*itrP)->GetConnectors(); for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC) { - if (itrC->m_Type != a_Connector.m_Type) + if (itrC->m_Type != WantedConnectorType) { continue; } @@ -419,7 +478,9 @@ bool cPieceGenerator::TryPlacePieceAtConnector( // Doesn't fit in this rotation continue; } - Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations)); + // Fits, add it to list of possibile connections: + Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations, Weight)); + WeightTotal += Weight; } // for itrC - Connectors[] } // for itrP - AvailablePieces[] if (Connections.empty()) @@ -427,21 +488,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector( // No available connections, bail out return false; } + ASSERT(WeightTotal > 0); - // Choose a random connection from the list: - int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7; - cConnection & Conn = Connections[rnd % Connections.size()]; + // Choose a random connection from the list, based on the weights: + int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal; + size_t ChosenIndex = 0; + for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex) + { + rnd -= itr->m_Weight; + if (rnd <= 0) + { + // This is the piece to choose + break; + } + } + cConnection & Conn = Connections[ChosenIndex]; // Place the piece: - /* - // DEBUG - printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n", - Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z, - BlockFaceToString(Conn.m_Connector.m_Direction).c_str(), - Conn.m_NumCCWRotations - ); - //*/ - Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations); ConnPos -= NewPos; cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); @@ -449,12 +512,6 @@ bool cPieceGenerator::TryPlacePieceAtConnector( // Add the new piece's connectors to the list of free connectors: cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); - - /* - // DEBUG: - printf("Adding %u connectors to the pool\n", Connectors.size() - 1); - //*/ - for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) { if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos)) @@ -524,10 +581,11 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPieceGenerator::cConnection: -cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) : +cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight) : m_Piece(&a_Piece), m_Connector(a_Connector), - m_NumCCWRotations(a_NumCCWRotations) + m_NumCCWRotations(a_NumCCWRotations), + m_Weight(a_Weight) { } diff --git a/src/Generating/PieceGenerator.h b/src/Generating/PieceGenerator.h index bef9d3463..fd8576706 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -38,7 +38,8 @@ public: /** Position relative to the piece */ Vector3i m_Pos; - /** Type of the connector. Any arbitrary number; the generator connects only connectors of the same type. */ + /** Type of the connector. Any arbitrary number; the generator connects only connectors of opposite + (negative) types. */ int m_Type; /** Direction in which the connector is facing. @@ -85,6 +86,13 @@ typedef std::vector<cPiece *> cPieces; +// fwd: +class cPlacedPiece; + + + + + /** This class is an interface that provides pieces for the generator. It can keep track of what pieces were placed and adjust the returned piece vectors. */ class cPiecePool @@ -101,6 +109,26 @@ public: Multiple starting points are supported, one of the returned piece will be chosen. */ virtual cPieces GetStartingPieces(void) = 0; + /** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector. + a_ExistingConnector is the original connector, before any movement or rotation is applied to it. + This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used. + The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen. + */ + virtual int GetPieceWeight( + const cPlacedPiece & a_PlacedPiece, + const cPiece::cConnector & a_ExistingConnector, + const cPiece & a_NewPiece + ) { return 1; } + + /** Returns the relative weight with which the a_NewPiece is to be selected for placing as the first piece. + This allows the pool to tweak the piece's chances. + The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will not be chosen. + If all pieces return 0, a random piece is chosen, with all equal chances. + */ + virtual int GetStartingPieceWeight( + const cPiece & a_NewPiece + ) { return 1; } + /** Called after a piece is placed, to notify the pool that it has been used. The pool may adjust the pieces it will return the next time. */ virtual void PiecePlaced(const cPiece & a_Piece) = 0; @@ -120,19 +148,41 @@ class cPlacedPiece public: cPlacedPiece(const cPlacedPiece * a_Parent, const cPiece & a_Piece, const Vector3i & a_Coords, int a_NumCCWRotations); - const cPiece & GetPiece (void) const { return *m_Piece; } - const Vector3i & GetCoords (void) const { return m_Coords; } - int GetNumCCWRotations(void) const { return m_NumCCWRotations; } - const cCuboid & GetHitBox (void) const { return m_HitBox; } - int GetDepth (void) const { return m_Depth; } + const cPlacedPiece * GetParent (void) const { return m_Parent; } + const cPiece & GetPiece (void) const { return *m_Piece; } + const Vector3i & GetCoords (void) const { return m_Coords; } + int GetNumCCWRotations (void) const { return m_NumCCWRotations; } + const cCuboid & GetHitBox (void) const { return m_HitBox; } + int GetDepth (void) const { return m_Depth; } + bool HasBeenMovedToGround(void) const { return m_HasBeenMovedToGround; } + + /** Returns the coords as a modifiable object. */ + Vector3i & GetCoords(void) { return m_Coords; } + + /** Returns the connector at the specified index, rotated in the actual placement. + Undefined behavior if a_Index is out of range. */ + cPiece::cConnector GetRotatedConnector(size_t a_Index) const; + + /** Returns a copy of the specified connector, modified to account for the translation and rotation for + this placement. */ + cPiece::cConnector GetRotatedConnector(const cPiece::cConnector & a_Connector) const; + + /** Moves the placed piece Y-wise by the specified offset. + Sets m_HasBeenMovedToGround to true, too. + Used eg. by village houses. */ + void MoveToGroundBy(int a_OffsetY); protected: const cPlacedPiece * m_Parent; const cPiece * m_Piece; Vector3i m_Coords; int m_NumCCWRotations; - cCuboid m_HitBox; - int m_Depth; + cCuboid m_HitBox; // Hitbox of the placed piece, in world coords + int m_Depth; // Depth in the generated piece tree + + /** Set to true once the piece has been moved Y-wise. + Used eg. by village houses. */ + bool m_HasBeenMovedToGround; }; typedef std::vector<cPlacedPiece *> cPlacedPieces; @@ -157,8 +207,9 @@ protected: cPiece * m_Piece; // The piece being connected cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords) int m_NumCCWRotations; // Number of rotations necessary to match the two connectors + int m_Weight; // Relative chance that this connection will be chosen - cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations); + cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight); }; typedef std::vector<cConnection> cConnections; diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp index 1af1faec1..2ab1455b9 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -15,18 +15,159 @@ uses a prefabricate in a cBlockArea for drawing itself. +#ifdef SELF_TEST + +// Create one static prefab to test the parser: +static const cPrefab::sDef g_TestPrefabDef = +{ + // Size: + 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* 0 */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */, + + // Block data: + // Level 1 + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + "aaaaaaa" + + // Level 2 + "aa...aa" + "a.....a" + "......." + "......." + "......." + "a.....a" + "aa...aa" + + // Level 3 + "aa...aa" + "a.....a" + "......." + "......." + "......." + "a.....a" + "aa...aa" + + // Level 4 + "aa...aa" + "a.....a" + "......." + "......." + "......." + "a.....a" + "aa...aa" + + // Level 5 + "aabbbaa" + "a.....a" + "b.....b" + "b.....b" + "b.....b" + "a.....a" + "aabbbaa" + + // Level 6 + "aaaaaaa" + "a.....a" + "a.....a" + "a.....a" + "a.....a" + "a.....a" + "aaaaaaa", + + // Connections: + "0: 0, 3, 2: 4\n" + "0: 2, 3, 0: 2\n", + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotations */ + + // Merge strategy: + cBlockArea::msImprint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 1000, + + // MoveToGround: + false, +}; + +static cPrefab g_TestPrefab(g_TestPrefabDef); +#endif + + + + + cPrefab::cPrefab(const cPrefab::sDef & a_Def) : m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ), - m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1), + m_HitBox( + a_Def.m_HitboxMinX, a_Def.m_HitboxMinY, a_Def.m_HitboxMinZ, + a_Def.m_HitboxMaxX, a_Def.m_HitboxMaxY, a_Def.m_HitboxMaxZ + ), m_AllowedRotations(a_Def.m_AllowedRotations), - m_MergeStrategy(a_Def.m_MergeStrategy) + m_MergeStrategy(a_Def.m_MergeStrategy), + m_ShouldExtendFloor(a_Def.m_ShouldExtendFloor), + m_DefaultWeight(a_Def.m_DefaultWeight), + m_AddWeightIfSame(a_Def.m_AddWeightIfSame), + m_MoveToGround(a_Def.m_MoveToGround) { m_BlockArea[0].Create(m_Size); CharMap cm; ParseCharMap(cm, a_Def.m_CharMap); ParseBlockImage(cm, a_Def.m_Image); ParseConnectors(a_Def.m_Connectors); + ParseDepthWeight(a_Def.m_DepthWeight); + AddRotatedBlockAreas(); +} + + + + + +cPrefab::cPrefab(const cBlockArea & a_Image, int a_AllowedRotations) : + m_Size(a_Image.GetSize()), + m_AllowedRotations(a_AllowedRotations), + m_MergeStrategy(cBlockArea::msOverwrite), + m_ShouldExtendFloor(false), + m_DefaultWeight(1), + m_AddWeightIfSame(0), + m_MoveToGround(false) +{ + m_HitBox.p1.Set(0, 0, 0); + m_HitBox.p2.Set(m_Size.x - 1, m_Size.y - 1, m_Size.z - 1); + m_BlockArea[0].CopyFrom(a_Image); + AddRotatedBlockAreas(); +} + + + + + +void cPrefab::AddRotatedBlockAreas(void) +{ // 1 CCW rotation: if ((m_AllowedRotations & 0x01) != 0) { @@ -56,12 +197,64 @@ cPrefab::cPrefab(const cPrefab::sDef & a_Def) : void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const { - Vector3i Placement = a_Placement->GetCoords(); + Draw(a_Dest, a_Placement->GetCoords(), a_Placement->GetNumCCWRotations()); +} + + + + +void cPrefab::Draw(cChunkDesc & a_Dest, const Vector3i & a_Placement, int a_NumRotations) const +{ + // Draw the basic image: + Vector3i Placement(a_Placement); int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width; int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width; Placement.Move(-ChunkStartX, 0, -ChunkStartZ); - a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy); + const cBlockArea & Image = m_BlockArea[a_NumRotations]; + a_Dest.WriteBlockArea(Image, Placement.x, Placement.y, Placement.z, m_MergeStrategy); + // If requested, draw the floor (from the bottom of the prefab down to the nearest non-air) + if (m_ShouldExtendFloor) + { + int MaxX = Image.GetSizeX(); + int MaxZ = Image.GetSizeZ(); + for (int z = 0; z < MaxZ; z++) + { + int RelZ = Placement.z + z; + if ((RelZ < 0) || (RelZ >= cChunkDef::Width)) + { + // Z coord outside the chunk + continue; + } + for (int x = 0; x < MaxX; x++) + { + int RelX = Placement.x + x; + if ((RelX < 0) || (RelX >= cChunkDef::Width)) + { + // X coord outside the chunk + continue; + } + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + Image.GetRelBlockTypeMeta(x, 0, z, BlockType, BlockMeta); + if ((BlockType == E_BLOCK_AIR) || (BlockType == E_BLOCK_SPONGE)) + { + // Do not expand air nor sponge blocks + continue; + } + for (int y = Placement.y - 1; y >= 0; y--) + { + BLOCKTYPE ExistingBlock = a_Dest.GetBlockType(RelX, y, RelZ); + if (ExistingBlock != E_BLOCK_AIR) + { + // End the expansion for this column, reached the end + break; + } + a_Dest.SetBlockTypeMeta(RelX, y, RelZ, BlockType, BlockMeta); + } // for y + } // for x + } // for z + } } @@ -84,12 +277,53 @@ bool cPrefab::HasConnectorType(int a_ConnectorType) const +int cPrefab::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector) const +{ + // Use the default or per-depth weight: + cDepthWeight::const_iterator itr = m_DepthWeight.find(a_PlacedPiece.GetDepth() + 1); + int res = (itr == m_DepthWeight.end()) ? m_DefaultWeight : itr->second; + + // If the piece is the same as the parent, apply the m_AddWeightIfSame modifier: + const cPiece * ParentPiece = &a_PlacedPiece.GetPiece(); + const cPiece * ThisPiece = this; + if (ThisPiece == ParentPiece) + { + res += m_AddWeightIfSame; + } + return res; +} + + + + + +void cPrefab::SetDefaultWeight(int a_DefaultWeight) +{ + m_DefaultWeight = a_DefaultWeight; +} + + + + + +void cPrefab::AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Direction, int a_Type) +{ + m_Connectors.push_back(cConnector(a_RelX, a_RelY, a_RelZ, a_Type, a_Direction)); +} + + + + + void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) { + ASSERT(a_CharMapDef != NULL); + // Initialize the charmap to all-invalid values: for (size_t i = 0; i < ARRAYCOUNT(a_CharMapOut); i++) { - a_CharMapOut[i] = -1; + a_CharMapOut[i].m_BlockType = 0; + a_CharMapOut[i].m_BlockMeta = 16; // Mark unassigned entries with a meta that is impossible otherwise } // Process the lines in the definition: @@ -104,15 +338,15 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) continue; } unsigned char Src = (unsigned char)CharDef[0][0]; - BLOCKTYPE BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str()); + ASSERT(a_CharMapOut[Src].m_BlockMeta == 16); // This letter has not been assigned yet? + a_CharMapOut[Src].m_BlockType = (BLOCKTYPE)atoi(CharDef[1].c_str()); NIBBLETYPE BlockMeta = 0; if ((NumElements >= 3) && !CharDef[2].empty()) { BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str()); - ASSERT((BlockMeta >= 0) && (BlockMeta <= 15)); + ASSERT((BlockMeta <= 15)); } - ASSERT(a_CharMapOut[Src] == -1); // Any duplicates letter-wise? - a_CharMapOut[Src] = (BlockType << 4) | BlockMeta; + a_CharMapOut[Src].m_BlockMeta = BlockMeta; } // for itr - Lines[] } @@ -130,11 +364,9 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma const unsigned char * BlockImage = (const unsigned char *)a_BlockImage + y * m_Size.x * m_Size.z + z * m_Size.x; for (int x = 0; x < m_Size.x; x++) { - int MappedValue = a_CharMap[BlockImage[x]]; - ASSERT(MappedValue != -1); // Using a letter not defined in the CharMap? - BLOCKTYPE BlockType = MappedValue >> 4; - NIBBLETYPE BlockMeta = MappedValue & 0x0f; - m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, BlockType, BlockMeta); + const sBlockTypeDef & MappedValue = a_CharMap[BlockImage[x]]; + ASSERT(MappedValue.m_BlockMeta != 16); // Using a letter not defined in the CharMap? + m_BlockArea[0].SetRelBlockTypeMeta(x, y, z, MappedValue.m_BlockType, MappedValue.m_BlockMeta); } } } @@ -146,6 +378,8 @@ void cPrefab::ParseBlockImage(const CharMap & a_CharMap, const char * a_BlockIma void cPrefab::ParseConnectors(const char * a_ConnectorsDef) { + ASSERT(a_ConnectorsDef != NULL); + AStringVector Lines = StringSplitAndTrim(a_ConnectorsDef, "\n"); for (AStringVector::const_iterator itr = Lines.begin(), end = Lines.end(); itr != end; ++itr) { @@ -188,6 +422,54 @@ void cPrefab::ParseConnectors(const char * a_ConnectorsDef) +void cPrefab::ParseDepthWeight(const char * a_DepthWeightDef) +{ + // The member needn't be defined at all, if so, skip: + if (a_DepthWeightDef == NULL) + { + return; + } + + // Split into individual records: "Record | Record | Record" + AStringVector Defs = StringSplitAndTrim(a_DepthWeightDef, "|"); + + // Add each record's contents: + for (AStringVector::const_iterator itr = Defs.begin(), end = Defs.end(); itr != end; ++itr) + { + // Split into components: "Depth : Weight" + AStringVector Components = StringSplitAndTrim(*itr, ":"); + if (Components.size() != 2) + { + LOGWARNING("Bad prefab DepthWeight record: \"%s\", skipping.", itr->c_str()); + continue; + } + + // Parse depth: + int Depth = atoi(Components[0].c_str()); + if ((Depth == 0) && (Components[0] != "0")) + { + LOGWARNING("Bad prefab DepthWeight record, cannot parse depth \"%s\", skipping.", Components[0].c_str()); + continue; + } + + // Parse weight: + int Weight = atoi(Components[1].c_str()); + if ((Weight == 0) && (Components[1] != "0")) + { + LOGWARNING("Bad prefab DepthWeight record, cannot parse weight \"%s\", skipping.", Components[1].c_str()); + continue; + } + + // Save to map: + ASSERT(m_DepthWeight.find(Depth) == m_DepthWeight.end()); // Not a duplicate + m_DepthWeight[Depth] = Weight; + } // for itr - Defs[] +} + + + + + cPiece::cConnectors cPrefab::GetConnectors(void) const { return m_Connectors; diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h index 0b254c03b..8b4e4b4ef 100644 --- a/src/Generating/Prefab.h +++ b/src/Generating/Prefab.h @@ -37,24 +37,106 @@ public: int m_SizeX; int m_SizeY; int m_SizeZ; + + /** The hitbox used for collision-checking between prefabs. Relative to the bounds. */ + int m_HitboxMinX, m_HitboxMinY, m_HitboxMinZ; + int m_HitboxMaxX, m_HitboxMaxY, m_HitboxMaxZ; + + /** The mapping between characters in m_Image and the blocktype / blockmeta. + Format: "Char: BlockType: BlockMeta \n Char: BlockType : BlockMeta \n ..." */ const char * m_CharMap; + + /** The actual image to be used for the prefab. Organized YZX (Y changes the least often). + Each character represents a single block, the type is mapped through m_CharMap. */ const char * m_Image; + + /** List of connectors. + Format: "Type: X, Y, Z : Direction \n Type : X, Y, Z : Direction \n ...". + Type is an arbitrary number, Direction is the BlockFace constant value (0 .. 5). */ const char * m_Connectors; + + /** Bitmask specifying the allowed rotations. + N rotations CCW are allowed if bit N is set. */ int m_AllowedRotations; + + /** The merge strategy to use while drawing the prefab. */ cBlockArea::eMergeStrategy m_MergeStrategy; + + /** If set to true, the prefab will extend its lowermost blocks until a solid block is found, + thus creating a foundation for the prefab. This is used for houses to be "on the ground", as well as + nether fortresses not to float. */ + bool m_ShouldExtendFloor; + + /** Chance of this piece being used, if no other modifier is active. */ + int m_DefaultWeight; + + /** Chances of this piece being used, per depth of the generated piece tree. + The starting piece has a depth of 0, the pieces connected to it are depth 1, etc. + The specified depth stands for the depth of the new piece (not the existing already-placed piece), + so valid depths start at 1. + Format: "Depth : Weight | Depth : Weight | Depth : Weight ..." + Depths that are not specified will use the m_DefaultWeight value. */ + const char * m_DepthWeight; + + /** The weight to add to this piece's base per-depth chance if the previous piece is the same. + Can be positive or negative. + This is used e. g. to make nether bridges prefer spanning multiple segments or to penalize turrets next to each other. */ + int m_AddWeightIfSame; + + /** If true, the piece will be moved Y-wise so that its first connector is sitting on the terrain. + This is used e. g. for village houses. */ + bool m_MoveToGround; }; + + /** Creates a prefab from the provided definition. */ cPrefab(const sDef & a_Def); + /** Creates a prefab based on the given BlockArea and allowed rotations. */ + cPrefab(const cBlockArea & a_Image, int a_AllowedRotations); + /** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */ void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const; + /** Draws the prefab into the specified chunks, according to the specified placement and rotations. */ + void Draw(cChunkDesc & a_Dest, const Vector3i & a_Placement, int a_NumRotations) const; + /** Returns true if the prefab has any connector of the specified type. */ bool HasConnectorType(int a_ConnectorType) const; + + /** Returns the weight (chance) of this prefab generating as the next piece after the specified placed piece. + PiecePool implementations can use this for their GetPieceWeight() implementations. */ + int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector) const; + + /** Sets the (unmodified) DefaultWeight property for this piece. */ + void SetDefaultWeight(int a_DefaultWeight); + + /** Returns the unmodified DefaultWeight property for the piece. */ + int GetDefaultWeight(void) const { return m_DefaultWeight; } + + /** Sets the AddWeightIfSame member, that is used to modify the weight when the previous piece is the same prefab */ + void SetAddWeightIfSame(int a_AddWeightIfSame) { m_AddWeightIfSame = a_AddWeightIfSame; } + + /** Adds the specified connector to the list of connectors this piece supports. */ + void AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Direction, int a_Type); + + /** Returns whether the prefab should be moved Y-wise to ground before drawing, rather than staying + at the coords governed by the connectors. */ + bool ShouldMoveToGround(void) const { return m_MoveToGround; } protected: - /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */ - typedef int CharMap[256]; + /** Packs complete definition of a single block, for per-letter assignment. */ + struct sBlockTypeDef + { + BLOCKTYPE m_BlockType; + NIBBLETYPE m_BlockMeta; + }; + + /** Maps letters in the sDef::m_Image onto a sBlockTypeDef block type definition. */ + typedef sBlockTypeDef CharMap[256]; + + /** Maps generator tree depth to weight. */ + typedef std::map<int, int> cDepthWeight; /** The cBlockArea that contains the block definitions for the prefab. @@ -64,7 +146,7 @@ protected: /** The size of the prefab */ Vector3i m_Size; - /** The hitbox of the prefab. In first version is the same as the m_BlockArea dimensions */ + /** The hitbox used for collision-checking between prefabs. */ cCuboid m_HitBox; /** The connectors through which the piece connects to other pieces */ @@ -75,6 +157,30 @@ protected: /** The merge strategy to use when drawing the prefab into a block area */ cBlockArea::eMergeStrategy m_MergeStrategy; + + /** If set to true, the prefab will extend its lowermost blocks until a solid block is found, + thus creating a foundation for the prefab. This is used for houses to be "on the ground", as well as + nether fortresses not to float. */ + bool m_ShouldExtendFloor; + + /** Chance of this piece being used, if no other modifier is active. */ + int m_DefaultWeight; + + /** Chances of this piece being used, per depth of the generated piece tree. + The starting piece has a depth of 0, the pieces connected to it are depth 1, etc. + The specified depth stands for the depth of the new piece (not the existing already-placed piece), + so valid depths start at 1. + Depths that are not specified will use the m_DefaultWeight value. */ + cDepthWeight m_DepthWeight; + + /** The weight to add to this piece's base per-depth chance if the previous piece is the same. + Can be positive or negative. + This is used e. g. to make nether bridges prefer spanning multiple segments or to penalize turrets next to each other. */ + int m_AddWeightIfSame; + + /** If true, the piece will be moved Y-wise so that its first connector is sitting on the terrain. + This is used e. g. for village houses. */ + bool m_MoveToGround; // cPiece overrides: @@ -83,6 +189,10 @@ protected: virtual cCuboid GetHitBox(void) const override; virtual bool CanRotateCCW(int a_NumRotations) const override; + /** Based on the m_AllowedRotations, adds rotated cBlockAreas to the m_BlockArea array. + To be called only from this class's constructor! */ + void AddRotatedBlockAreas(void); + /** Parses the CharMap in the definition into a CharMap binary data used for translating the definition into BlockArea. */ void ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef); @@ -91,6 +201,9 @@ protected: /** Parses the connectors definition text into m_Connectors member. */ void ParseConnectors(const char * a_ConnectorsDef); + + /** Parses the per-depth weight into m_DepthWeight member. */ + void ParseDepthWeight(const char * a_DepthWeightDef); }; diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp new file mode 100644 index 000000000..122b9d2af --- /dev/null +++ b/src/Generating/PrefabPiecePool.cpp @@ -0,0 +1,158 @@ + +// PrefabPiecePool.cpp + +// Implements the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces + +#include "Globals.h" +#include "PrefabPiecePool.h" + + + + + +cPrefabPiecePool::cPrefabPiecePool( + const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs, + const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs +) +{ + AddPieceDefs(a_PieceDefs, a_NumPieceDefs); + if (a_StartingPieceDefs != NULL) + { + AddStartingPieceDefs(a_StartingPieceDefs, a_NumStartingPieceDefs); + } +} + + + + + +cPrefabPiecePool::~cPrefabPiecePool() +{ + Clear(); +} + + + + + +void cPrefabPiecePool::Clear(void) +{ + m_PiecesByConnector.clear(); + for (cPieces::iterator itr = m_AllPieces.begin(), end = m_AllPieces.end(); itr != end; ++itr) + { + delete *itr; + } + m_AllPieces.clear(); + for (cPieces::iterator itr = m_StartingPieces.begin(), end = m_StartingPieces.end(); itr != end; ++itr) + { + delete *itr; + } + m_StartingPieces.clear(); +} + + + + + +void cPrefabPiecePool::AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs) +{ + ASSERT(a_PieceDefs != NULL); + for (size_t i = 0; i < a_NumPieceDefs; i++) + { + cPrefab * Prefab = new cPrefab(a_PieceDefs[i]); + m_AllPieces.push_back(Prefab); + AddToPerConnectorMap(Prefab); + } +} + + + + + +void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs) +{ + ASSERT(a_StartingPieceDefs != NULL); + for (size_t i = 0; i < a_NumStartingPieceDefs; i++) + { + cPrefab * Prefab = new cPrefab(a_StartingPieceDefs[i]); + m_StartingPieces.push_back(Prefab); + } +} + + + + + +void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab) +{ + cPiece::cConnectors Connectors = ((const cPiece *)a_Prefab)->GetConnectors(); + for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr) + { + m_PiecesByConnector[itr->m_Type].push_back(a_Prefab); + } +} + + + + +cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType) +{ + return m_PiecesByConnector[a_ConnectorType]; +} + + + + + +cPieces cPrefabPiecePool::GetStartingPieces(void) +{ + if (m_StartingPieces.empty()) + { + return m_AllPieces; + } + else + { + return m_StartingPieces; + } +} + + + + + +int cPrefabPiecePool::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) +{ + return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector); +} + + + + + +int cPrefabPiecePool::GetStartingPieceWeight(const cPiece & a_NewPiece) +{ + return ((const cPrefab &)a_NewPiece).GetDefaultWeight(); +} + + + + + +void cPrefabPiecePool::PiecePlaced(const cPiece & a_Piece) +{ + // Do nothing + UNUSED(a_Piece); +} + + + + + +void cPrefabPiecePool::Reset(void) +{ + // Do nothing +} + + + + diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h new file mode 100644 index 000000000..b9c1f0483 --- /dev/null +++ b/src/Generating/PrefabPiecePool.h @@ -0,0 +1,85 @@ + +// PrefabPiecePool.h + +// Declares the cPrefabPiecePool class that represents a cPiecePool descendant that uses cPrefab instances as the pieces + + + + + +#pragma once + +#include "PieceGenerator.h" +#include "Prefab.h" + + + + + +class cPrefabPiecePool : + public cPiecePool +{ +public: + /** Creates an empty instance. Prefabs can be added by calling AddPieceDefs() and AddStartingPieceDefs(). */ + cPrefabPiecePool(void); + + /** Creates a piece pool with prefabs from the specified definitions. + If both a_PieceDefs and a_StartingPieceDefs are given, only the a_StartingPieceDefs are used as starting + pieces for the pool, and they do not participate in the generation any further. + If only a_PieceDefs is given, any such piece can be chosen as a starting piece, and all the pieces are used + for generating. + More pieces can be added to the instance afterwards by calling AddPieceDefs() and AddStartingPieceDefs(). */ + cPrefabPiecePool( + const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs, + const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs + ); + + /** Destroys the pool, freeing all pieces. */ + ~cPrefabPiecePool(); + + /** Removes and frees all pieces from this pool. */ + void Clear(void); + + /** Adds pieces from the specified definitions into m_AllPieces. Also adds the pieces into + the m_PiecesByConnector map. + May be called multiple times with different PieceDefs, will add all such pieces. */ + void AddPieceDefs(const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs); + + /** Adds pieces from the specified definitions into m_StartingPieces. Doesn't add them to + the m_PiecesByConnector map. + May be called multiple times with different PieceDefs, will add all such pieces. */ + void AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs); + +protected: + + /** The type used to map a connector type to the list of pieces with that connector */ + typedef std::map<int, cPieces> cPiecesMap; + + /** All the pieces that are allowed for building. + This is the list that's used for memory allocation and deallocation for the pieces. */ + cPieces m_AllPieces; + + /** The pieces that are used as starting pieces. + This list is not shared and the pieces need deallocation. */ + cPieces m_StartingPieces; + + /** The map that has all pieces by their connector types + The pieces are copies out of m_AllPieces and shouldn't be ever delete-d. */ + cPiecesMap m_PiecesByConnector; + + + /** Adds the prefab to the m_PiecesByConnector map for all its connectors. */ + void AddToPerConnectorMap(cPrefab * a_Prefab); + + // cPiecePool overrides: + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; + virtual cPieces GetStartingPieces(void) override; + virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override; + virtual int GetStartingPieceWeight(const cPiece & a_NewPiece) override; + virtual void PiecePlaced(const cPiece & a_Piece) override; + virtual void Reset(void) override; +} ; + + + + diff --git a/src/Generating/Prefabs/AlchemistVillagePrefabs.cpp b/src/Generating/Prefabs/AlchemistVillagePrefabs.cpp new file mode 100644 index 000000000..eb0d30fdf --- /dev/null +++ b/src/Generating/Prefabs/AlchemistVillagePrefabs.cpp @@ -0,0 +1,3184 @@ + +// AlchemistVillagePrefabs.cpp + +// Defines the prefabs in the group AlchemistVillage + +// NOTE: This file has been generated automatically by GalExport! +// Any manual changes will be overwritten by the next automatic export! + +#include "Globals.h" +#include "AlchemistVillagePrefabs.h" + + + + + +const cPrefab::sDef g_AlchemistVillagePrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BarWithBasement: + // The data has been exported from the gallery Desert, area index 82, ID 598, created by STR_Warrior + { + // Size: + 11, 12, 10, // SizeX = 11, SizeY = 12, SizeZ = 10 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 11, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A:171: 8\n" /* carpet */ + "B:101: 0\n" /* ironbars */ + "C: 64:12\n" /* wooddoorblock */ + "D:128: 2\n" /* sandstonestairs */ + "E: 24: 1\n" /* sandstone */ + "F: 44: 9\n" /* step */ + "G:126: 8\n" /* woodenslab */ + "H:128: 7\n" /* sandstonestairs */ + "I: 44: 1\n" /* step */ + "J: 64: 7\n" /* wooddoorblock */ + "K:128: 6\n" /* sandstonestairs */ + "a: 1: 0\n" /* stone */ + "b: 24: 0\n" /* sandstone */ + "c: 12: 0\n" /* sand */ + "d:134: 4\n" /* 134 */ + "e: 5: 1\n" /* wood */ + "f:134: 5\n" /* 134 */ + "g: 65: 5\n" /* ladder */ + "h: 17: 3\n" /* tree */ + "i: 69:11\n" /* lever */ + "j:134: 0\n" /* 134 */ + "k:134: 1\n" /* 134 */ + "l: 50: 4\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 5: 0\n" /* wood */ + "o: 96:12\n" /* trapdoor */ + "p: 24: 2\n" /* sandstone */ + "q:128: 5\n" /* sandstonestairs */ + "r:107: 6\n" /* fencegate */ + "s:128: 4\n" /* sandstonestairs */ + "t:134: 3\n" /* 134 */ + "u: 85: 0\n" /* fence */ + "v:134: 7\n" /* 134 */ + "w:107: 5\n" /* fencegate */ + "x: 64: 5\n" /* wooddoorblock */ + "y: 65: 3\n" /* ladder */ + "z: 50: 3\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aabbbbbbbaa" + /* 3 */ "aabbbbbbbaa" + /* 4 */ "aabbbbbbbaa" + /* 5 */ "aabbbbbbbaa" + /* 6 */ "aabbbbbbbaa" + /* 7 */ "aabbbbbbbaa" + /* 8 */ "aaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "ccccccccccc" + /* 1 */ "cbbbbbbbbbc" + /* 2 */ "cbdef.defbc" + /* 3 */ "cbdef.defbc" + /* 4 */ "cbdef.defbc" + /* 5 */ "cb.......bc" + /* 6 */ "cb.......bc" + /* 7 */ "cbg......bc" + /* 8 */ "cbbbbbbbbbc" + /* 9 */ "ccccccccccc" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "ccccccccccc" + /* 1 */ "cbbbbbbbbbc" + /* 2 */ "cbeee.eeebc" + /* 3 */ "cbeee.eeebc" + /* 4 */ "cbehe.ehebc" + /* 5 */ "cb.i...i.bc" + /* 6 */ "cb.......bc" + /* 7 */ "cbg......bc" + /* 8 */ "cbbbbbbbbbc" + /* 9 */ "ccccccccccc" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "ccccccccccc" + /* 1 */ "cbbbbbbbbbc" + /* 2 */ "cbjek.jekbc" + /* 3 */ "cbjek.jekbc" + /* 4 */ "cbjek.jekbc" + /* 5 */ "cb.......bc" + /* 6 */ "cb.......bc" + /* 7 */ "cbg..l...bc" + /* 8 */ "cbbbbbbbbbc" + /* 9 */ "ccccccccccc" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "ccccccccccc" + /* 1 */ "ccccccccccc" + /* 2 */ "ccnnnnnnncc" + /* 3 */ "cnnnnnnnnnc" + /* 4 */ "cnnnnnnnnnc" + /* 5 */ "cnnnnnnnnnc" + /* 6 */ "cnnnnnnnnnc" + /* 7 */ "cnonnnnnnnc" + /* 8 */ "cnccccccccc" + /* 9 */ "ccccccccccc" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...p...p..." + /* 1 */ "..........." + /* 2 */ "pbbbqrsbbbp" + /* 3 */ "bkt.....ttb" + /* 4 */ "bku.....ujb" + /* 5 */ "b.........b" + /* 6 */ "bfvvd.....b" + /* 7 */ "b...w..kujb" + /* 8 */ "pxbbbbbbbbp" + /* 9 */ "..y........" + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...p...p..." + /* 1 */ "..........." + /* 2 */ "pbbb...bbbp" + /* 3 */ "b..z...z..b" + /* 4 */ "b.A.....A.b" + /* 5 */ "B.........B" + /* 6 */ "b.........b" + /* 7 */ "b.......A.b" + /* 8 */ "pCbbBBBbbbp" + /* 9 */ "..y........" + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...D...D..." + /* 1 */ "...E...b..." + /* 2 */ "pbbbqFsbbbp" + /* 3 */ "bGGGGGGGGGb" + /* 4 */ "bGGGGGGGGGb" + /* 5 */ "sGGGGGGGGGq" + /* 6 */ "bGGGGGGGGGb" + /* 7 */ "bGGGGGGGGGb" + /* 8 */ "pbbbHHHbbbp" + /* 9 */ "..y........" + + // Level 8 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "bIIIIbIIIIb" + /* 3 */ "IpbbbbbbbpI" + /* 4 */ "Ib.......bI" + /* 5 */ "bb.......bb" + /* 6 */ "Ib.......bI" + /* 7 */ "IpJbbbbbbpI" + /* 8 */ "bI.IIbIIIIb" + /* 9 */ "..........." + + // Level 9 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ ".pbbBBBbbp." + /* 4 */ ".b.......b." + /* 5 */ ".B.......B." + /* 6 */ ".b.......b." + /* 7 */ ".pCbBBBbbp." + /* 8 */ "..........." + /* 9 */ "..........." + + // Level 10 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ ".pbbKKKbbp." + /* 4 */ ".bGGGGGGGb." + /* 5 */ ".sGGGGGGGq." + /* 6 */ ".bGGGGGGGb." + /* 7 */ ".pbbHHHbbp." + /* 8 */ "..........." + /* 9 */ "..........." + + // Level 11 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ ".bIIIbIIIb." + /* 4 */ ".I.......I." + /* 5 */ ".b.......b." + /* 6 */ ".I.......I." + /* 7 */ ".bIIIbIIIb." + /* 8 */ "..........." + /* 9 */ "...........", + + // Connectors: + "-1: 5, 5, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 70, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // BarWithBasement + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BarWithoutBasement: + // The data has been exported from the gallery Desert, area index 81, ID 597, created by STR_Warrior + { + // Size: + 11, 8, 10, // SizeX = 11, SizeY = 8, SizeZ = 10 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 7, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A:128: 7\n" /* sandstonestairs */ + "B: 44: 1\n" /* step */ + "C: 64: 3\n" /* wooddoorblock */ + "D: 64: 8\n" /* wooddoorblock */ + "E:128: 6\n" /* sandstonestairs */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e:128: 5\n" /* sandstonestairs */ + "f:107: 6\n" /* fencegate */ + "g:128: 4\n" /* sandstonestairs */ + "h:134: 1\n" /* 134 */ + "i:134: 3\n" /* 134 */ + "j: 85: 0\n" /* fence */ + "k:134: 0\n" /* 134 */ + "l:134: 5\n" /* 134 */ + "m: 19: 0\n" /* sponge */ + "n:134: 7\n" /* 134 */ + "o:134: 4\n" /* 134 */ + "p:107: 5\n" /* fencegate */ + "q: 64: 5\n" /* wooddoorblock */ + "r: 65: 3\n" /* ladder */ + "s: 50: 3\n" /* torch */ + "t:171: 8\n" /* carpet */ + "u:101: 0\n" /* ironbars */ + "v: 64:12\n" /* wooddoorblock */ + "w:128: 2\n" /* sandstonestairs */ + "x: 24: 1\n" /* sandstone */ + "y: 44: 9\n" /* step */ + "z:126: 8\n" /* woodenslab */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaabbbaaaa" + /* 3 */ "abbbbbbbbba" + /* 4 */ "abbbbbbbbba" + /* 5 */ "abbbbbbbbba" + /* 6 */ "abbbbbbbbba" + /* 7 */ "abbbbbbbbba" + /* 8 */ "abaaaaaaaaa" + /* 9 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...c...c..." + /* 1 */ "..........." + /* 2 */ "cdddefgdddc" + /* 3 */ "dhi.....iid" + /* 4 */ "dhj.....jkd" + /* 5 */ "d.........d" + /* 6 */ "dlnno.....d" + /* 7 */ "d...p..hjkd" + /* 8 */ "cqddddddddc" + /* 9 */ "..r........" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...c...c..." + /* 1 */ "..........." + /* 2 */ "cddd...dddc" + /* 3 */ "d..s...s..d" + /* 4 */ "d.t.....t.d" + /* 5 */ "u.........u" + /* 6 */ "d.........d" + /* 7 */ "d.......t.d" + /* 8 */ "cvdduuudddc" + /* 9 */ "..r........" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...w...w..." + /* 1 */ "...x...d..." + /* 2 */ "cdddeygdddc" + /* 3 */ "dzzzzzzzzzd" + /* 4 */ "dzzzzzzzzzd" + /* 5 */ "gzzzzzzzzze" + /* 6 */ "dzzzzzzzzzd" + /* 7 */ "dzzzzzzzzzd" + /* 8 */ "cdddAAAdddc" + /* 9 */ "..r........" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "dBBBBdBBBBd" + /* 3 */ "BcdddddddcB" + /* 4 */ "Bd.......dB" + /* 5 */ "dd.......dd" + /* 6 */ "Bd.......dB" + /* 7 */ "BcCddddddcB" + /* 8 */ "dB.BBdBBBBd" + /* 9 */ "..........." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ ".cdduuuddc." + /* 4 */ ".d.......d." + /* 5 */ ".u.......u." + /* 6 */ ".d.......d." + /* 7 */ ".cDduuuddc." + /* 8 */ "..........." + /* 9 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ ".cddEEEddc." + /* 4 */ ".dzzzzzzzd." + /* 5 */ ".gzzzzzzze." + /* 6 */ ".dzzzzzzzd." + /* 7 */ ".cddAAAddc." + /* 8 */ "..........." + /* 9 */ "..........." + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ ".dBBBdBBBd." + /* 4 */ ".B.......B." + /* 5 */ ".d.......d." + /* 6 */ ".B.......B." + /* 7 */ ".dBBBdBBBd." + /* 8 */ "..........." + /* 9 */ "...........", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 80, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // BarWithoutBasement + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BlackSmith: + // The data has been exported from the gallery Desert, area index 97, ID 642, created by STR_Warrior + { + // Size: + 11, 5, 13, // SizeX = 11, SizeY = 5, SizeZ = 13 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 4, 13, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 0\n" /* sandstone */ + "d: 24: 2\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 43: 0\n" /* doubleslab */ + "g: 53: 5\n" /* woodstairs */ + "h: 53: 4\n" /* woodstairs */ + "i: 10: 0\n" /* lava */ + "j: 54: 5\n" /* chest */ + "k: 64:12\n" /* wooddoorblock */ + "l: 50: 3\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n:101: 0\n" /* ironbars */ + "o: 50: 1\n" /* torch */ + "p: 50: 2\n" /* torch */ + "q:128: 2\n" /* sandstonestairs */ + "r: 44: 9\n" /* step */ + "s:126: 8\n" /* woodenslab */ + "t:128: 4\n" /* sandstonestairs */ + "u:128: 5\n" /* sandstonestairs */ + "v:128: 7\n" /* sandstonestairs */ + "w: 44: 1\n" /* step */ + "x: 43: 1\n" /* doubleslab */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaaaaaabaa" + /* 3 */ "acacacabbba" + /* 4 */ "acaccaabbba" + /* 5 */ "acccccabbba" + /* 6 */ "acaadddbbba" + /* 7 */ "aaacdddbbba" + /* 8 */ "aaaadddbbba" + /* 9 */ "abbbbbbbbba" + /* 10 */ "abbbbbbbbba" + /* 11 */ "abbbbbbbbba" + /* 12 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "......d...d" + /* 1 */ "..........." + /* 2 */ "......dcecd" + /* 3 */ ".d....c...c" + /* 4 */ "..f...c...c" + /* 5 */ "......c...c" + /* 6 */ "....ddc...c" + /* 7 */ ".gh.dic...c" + /* 8 */ "dcccccd...c" + /* 9 */ "cj........c" + /* 10 */ "c.........c" + /* 11 */ "c.........c" + /* 12 */ "dcccccccccd" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "......d...d" + /* 1 */ "..........." + /* 2 */ "......dckcd" + /* 3 */ ".d....c..lc" + /* 4 */ "......n...c" + /* 5 */ "......c...c" + /* 6 */ "....nnc...n" + /* 7 */ "....n.c...n" + /* 8 */ "dcccccd...n" + /* 9 */ "co........c" + /* 10 */ "n.........c" + /* 11 */ "c........pc" + /* 12 */ "dcccnnncccd" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "......q...q" + /* 1 */ "......c...c" + /* 2 */ "......dcccd" + /* 3 */ ".drrrrcsssc" + /* 4 */ ".rsssstsssc" + /* 5 */ ".rsssscsssc" + /* 6 */ ".rssddcsssu" + /* 7 */ ".rssd.csssu" + /* 8 */ "dcccccdsssu" + /* 9 */ "csssssssssc" + /* 10 */ "tsssssssssc" + /* 11 */ "csssssssssc" + /* 12 */ "dcccvvvcccd" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "......cwwwc" + /* 3 */ ".w.w.ww...w" + /* 4 */ "......w...w" + /* 5 */ ".w....w...w" + /* 6 */ "....xwx...w" + /* 7 */ ".w..w.w...c" + /* 8 */ "cwwwxwc...w" + /* 9 */ "w.........w" + /* 10 */ "w.........w" + /* 11 */ "w.........w" + /* 12 */ "cwwwwcwwwwc", + + // Connectors: + "-1: 8, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 50, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BlackSmith + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LargeHouse1: + // The data has been exported from the gallery Desert, area index 77, ID 577, created by STR_Warrior + { + // Size: + 15, 13, 11, // SizeX = 15, SizeY = 13, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, -1, // MinX, MinY, MinZ + 14, 12, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A:128: 4\n" /* sandstonestairs */ + "B:128: 5\n" /* sandstonestairs */ + "C:128: 7\n" /* sandstonestairs */ + "D: 44: 1\n" /* step */ + "E:128: 2\n" /* sandstonestairs */ + "F:128: 0\n" /* sandstonestairs */ + "G: 87: 0\n" /* netherstone */ + "H:128: 3\n" /* sandstonestairs */ + "I: 51: 0\n" /* fire */ + "J: 44: 9\n" /* step */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 85: 0\n" /* fence */ + "f: 5: 1\n" /* wood */ + "g: 64: 6\n" /* wooddoorblock */ + "h: 64: 0\n" /* wooddoorblock */ + "i: 61: 2\n" /* furnace */ + "j:118: 0\n" /* cauldronblock */ + "k:134: 4\n" /* 134 */ + "l: 65: 2\n" /* ladder */ + "m: 19: 0\n" /* sponge */ + "n:101: 0\n" /* ironbars */ + "o: 50: 1\n" /* torch */ + "p:140: 0\n" /* flowerpotblock */ + "q: 64:12\n" /* wooddoorblock */ + "r: 50: 3\n" /* torch */ + "s: 64: 8\n" /* wooddoorblock */ + "t: 69:12\n" /* lever */ + "u: 50: 4\n" /* torch */ + "v:128: 6\n" /* sandstonestairs */ + "w: 44:10\n" /* step */ + "x:128: 1\n" /* sandstonestairs */ + "y: 47: 0\n" /* bookshelf */ + "z: 96:10\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaabbbbbbbaaa" + /* 2 */ "aaaabbbbbbbbaaa" + /* 3 */ "aaaaabbbbbbbbaa" + /* 4 */ "aaaaabbbbbbbaaa" + /* 5 */ "aaaaabbbbbbbaaa" + /* 6 */ "aaaaabbbbbbbaaa" + /* 7 */ "aaaaabbbbbbbaaa" + /* 8 */ "aaaaabbbbbbbaaa" + /* 9 */ "aaaaabbbbbbbaaa" + /* 10 */ "aaaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "....cdddddddc.." + /* 1 */ "eeeed......fd.c" + /* 2 */ "e...g.......d.." + /* 3 */ "e...d.......h.." + /* 4 */ "e...dijk..l.d.." + /* 5 */ "e...dddd.dddd.c" + /* 6 */ "eeeed.......d.." + /* 7 */ "mmmmd.......d.." + /* 8 */ "mmmmd.......d.." + /* 9 */ "mmmmd.......d.." + /* 10 */ "mmmmcdddddddc.." + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "....cddnnnddc.." + /* 1 */ "....do.....pd.c" + /* 2 */ "....q.......d.r" + /* 3 */ "....d.......s.." + /* 4 */ "....d.t...l.d.u" + /* 5 */ "....dddd.dddd.c" + /* 6 */ "....n..r.r..n.." + /* 7 */ "mmmmn.......n.." + /* 8 */ "mmmmn.......n.." + /* 9 */ "mmmmd.......d.." + /* 10 */ "mmmmcddnnnddc.." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "....cddvvvddc.." + /* 1 */ "....dwwwwwwwddx" + /* 2 */ "....dwwwwwwwd.." + /* 3 */ "....dwwwwwwwd.." + /* 4 */ "....dyyywwzwd.." + /* 5 */ "....ddddddddddx" + /* 6 */ "....AwwwwwwwB.." + /* 7 */ "mmmmAwwwwwwwB.." + /* 8 */ "mmmmAwwwwwwwB.." + /* 9 */ "mmmmdwwwwwwwd.." + /* 10 */ "mmmmcddCCCddc.." + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "....dDDDdDDDd.." + /* 1 */ "....DcdddddcD.." + /* 2 */ "....Dd.....dD.." + /* 3 */ "....Dd.....dD.." + /* 4 */ "....Dd.....dD.." + /* 5 */ "....dcdd.ddcd.." + /* 6 */ "....D.......D.." + /* 7 */ "mmmmD.......D.." + /* 8 */ "mmmmD.......D.." + /* 9 */ "mmmmD.......D.." + /* 10 */ "mmmmdDDDdDDDd.." + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".....cddnddc..." + /* 2 */ ".....n.....n..." + /* 3 */ ".....n.....n..." + /* 4 */ ".....n.....n..." + /* 5 */ ".....cdd.ddc..." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".....cddvddc..." + /* 2 */ ".....AwwwwwB..." + /* 3 */ ".....AwwwwwB..." + /* 4 */ ".....AwwwwwB..." + /* 5 */ ".....cdddddc..." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".....dDDdDDd..." + /* 2 */ ".....D.ddd.D..." + /* 3 */ ".....d.ddd.d..." + /* 4 */ ".....D.ddd.D..." + /* 5 */ ".....dDDdDDd..." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 8 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ ".......cEc....." + /* 3 */ ".......FGx....." + /* 4 */ ".......cHc....." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 9 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ ".......c.c....." + /* 3 */ "........I......" + /* 4 */ ".......c.c....." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 10 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ ".......cvc....." + /* 3 */ ".......A.B....." + /* 4 */ ".......cCc....." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 11 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ ".......ddd....." + /* 3 */ ".......dJd....." + /* 4 */ ".......ddd....." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + + // Level 12 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ ".......D.D....." + /* 3 */ "..............." + /* 4 */ ".......D.D....." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "...............", + + // Connectors: + "-1: 14, 1, 3: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 60, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LargeHouse1 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LargeTower: + // The data has been exported from the gallery Desert, area index 80, ID 596, created by STR_Warrior + { + // Size: + 7, 11, 7, // SizeX = 7, SizeY = 11, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 7, 10, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c:128: 2\n" /* sandstonestairs */ + "d:128: 0\n" /* sandstonestairs */ + "e: 24: 2\n" /* sandstone */ + "f: 24: 0\n" /* sandstone */ + "g: 71: 3\n" /* irondoorblock */ + "h:128: 1\n" /* sandstonestairs */ + "i:128: 3\n" /* sandstonestairs */ + "j: 77: 4\n" /* stonebutton */ + "k: 71: 8\n" /* irondoorblock */ + "l:128: 6\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 4\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p: 50: 4\n" /* torch */ + "q:128: 7\n" /* sandstonestairs */ + "r: 85: 0\n" /* fence */ + "s: 24: 1\n" /* sandstone */ + "t: 44: 1\n" /* step */ + "u: 89: 0\n" /* lightstone */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaabaaa" + /* 2 */ "aabbbaa" + /* 3 */ "aabbbaa" + /* 4 */ "aabbbaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "mc...cm" + /* 1 */ "defgfeh" + /* 2 */ ".f...f." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ "defffeh" + /* 6 */ "mi...im" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "m.j...m" + /* 1 */ ".efkfe." + /* 2 */ ".f...f." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ ".efffe." + /* 6 */ "m.....m" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..lfl.." + /* 2 */ ".n...o." + /* 3 */ ".f...f." + /* 4 */ ".n.p.o." + /* 5 */ "..qfq.." + /* 6 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..frf.." + /* 2 */ ".f...f." + /* 3 */ ".r...r." + /* 4 */ ".f...f." + /* 5 */ "..frf.." + /* 6 */ "......." + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..frf.." + /* 2 */ ".f...f." + /* 3 */ ".r...r." + /* 4 */ ".f...f." + /* 5 */ "..frf.." + /* 6 */ "......." + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..frf.." + /* 2 */ ".f...f." + /* 3 */ ".r...r." + /* 4 */ ".f...f." + /* 5 */ "..frf.." + /* 6 */ "......." + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..cfc.." + /* 2 */ ".d...h." + /* 3 */ ".f...f." + /* 4 */ ".d...h." + /* 5 */ "..ifi.." + /* 6 */ "......." + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ffsff." + /* 2 */ ".f...f." + /* 3 */ ".s...s." + /* 4 */ ".f...f." + /* 5 */ ".ffsff." + /* 6 */ "......." + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "...l..." + /* 1 */ ".efffe." + /* 2 */ ".ftttf." + /* 3 */ "nftftfo" + /* 4 */ ".ftttf." + /* 5 */ ".efffe." + /* 6 */ "...q..." + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "...t..." + /* 1 */ ".t...t." + /* 2 */ "......." + /* 3 */ "t..u..t" + /* 4 */ "......." + /* 5 */ ".t...t." + /* 6 */ "...t...", + + // Connectors: + "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LargeTower + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse: + // The data has been exported from the gallery Desert, area index 65, ID 551, created by STR_Warrior + { + // Size: + 5, 5, 7, // SizeX = 5, SizeY = 5, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 5, 4, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 3\n" /* wooddoorblock */ + "f: 61: 2\n" /* furnace */ + "g: 65: 2\n" /* ladder */ + "h: 64: 8\n" /* wooddoorblock */ + "i:101: 0\n" /* ironbars */ + "j: 50: 4\n" /* torch */ + "k:128: 2\n" /* sandstonestairs */ + "l:126: 8\n" /* woodenslab */ + "m: 19: 0\n" /* sponge */ + "n:128: 4\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p:128: 7\n" /* sandstonestairs */ + "q: 44: 1\n" /* step */ + "r: 96: 6\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aabaa" + /* 3 */ "abbba" + /* 4 */ "abbba" + /* 5 */ "abbba" + /* 6 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "c...c" + /* 1 */ "....." + /* 2 */ "cdedc" + /* 3 */ "d...d" + /* 4 */ "d...d" + /* 5 */ "df.gd" + /* 6 */ "cdddc" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "c...c" + /* 1 */ "....." + /* 2 */ "cdhdc" + /* 3 */ "d...d" + /* 4 */ "i...i" + /* 5 */ "dj.gd" + /* 6 */ "cdidc" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "k...k" + /* 1 */ "d...d" + /* 2 */ "cdddc" + /* 3 */ "dllld" + /* 4 */ "nlllo" + /* 5 */ "dllgd" + /* 6 */ "cdpdc" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "dqdqd" + /* 3 */ "q...q" + /* 4 */ "d...d" + /* 5 */ "q..rq" + /* 6 */ "dqdqd", + + // Connectors: + "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse2: + // The data has been exported from the gallery Desert, area index 72, ID 562, created by STR_Warrior + { + // Size: + 7, 5, 11, // SizeX = 7, SizeY = 5, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 7, 4, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 3\n" /* wooddoorblock */ + "f: 65: 5\n" /* ladder */ + "g: 85: 0\n" /* fence */ + "h:101: 0\n" /* ironbars */ + "i: 64: 8\n" /* wooddoorblock */ + "j: 50: 3\n" /* torch */ + "k:128: 2\n" /* sandstonestairs */ + "l:128: 6\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:126: 8\n" /* woodenslab */ + "o:128: 4\n" /* sandstonestairs */ + "p:128: 5\n" /* sandstonestairs */ + "q:128: 7\n" /* sandstonestairs */ + "r: 44: 1\n" /* step */ + "s: 96: 0\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaabaa" + /* 3 */ "abbbbba" + /* 4 */ "abbbbba" + /* 5 */ "abbbbba" + /* 6 */ "aabaaaa" + /* 7 */ "aaaaaaa" + /* 8 */ "aaaaaaa" + /* 9 */ "aaaaaaa" + /* 10 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ ".c...c." + /* 1 */ "......." + /* 2 */ "cdddedc" + /* 3 */ "d.....d" + /* 4 */ "d.....d" + /* 5 */ "df....d" + /* 6 */ "cd.dddc" + /* 7 */ "g.....g" + /* 8 */ "g.....g" + /* 9 */ "g.....g" + /* 10 */ "ggggggg" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ ".c...c." + /* 1 */ "......." + /* 2 */ "cdhdidc" + /* 3 */ "d..j..d" + /* 4 */ "h.....h" + /* 5 */ "df....d" + /* 6 */ "cd.dhdc" + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ ".k...k." + /* 1 */ ".d...d." + /* 2 */ "cdldddc" + /* 3 */ "dnnnnnd" + /* 4 */ "onnnnnp" + /* 5 */ "dfnnnnd" + /* 6 */ "cdddqdc" + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "drrdrrd" + /* 3 */ "r.....r" + /* 4 */ "d.....d" + /* 5 */ "rs....r" + /* 6 */ "drrdrrd" + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ ".......", + + // Connectors: + "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse2 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse3: + // The data has been exported from the gallery Desert, area index 66, ID 553, created by STR_Warrior + { + // Size: + 9, 5, 7, // SizeX = 9, SizeY = 5, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 9, 4, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 65: 2\n" /* ladder */ + "g: 64:12\n" /* wooddoorblock */ + "h:101: 0\n" /* ironbars */ + "i: 50: 4\n" /* torch */ + "j:128: 2\n" /* sandstonestairs */ + "k:126: 8\n" /* woodenslab */ + "l:128: 4\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 5\n" /* sandstonestairs */ + "o:128: 7\n" /* sandstonestairs */ + "p: 44: 1\n" /* step */ + "q: 96: 2\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaaaaaa" + /* 2 */ "aaaabaaaa" + /* 3 */ "abbbbbbba" + /* 4 */ "abbbbbbba" + /* 5 */ "abbbbbbba" + /* 6 */ "aaaaaaaaa" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "..c...c.." + /* 1 */ "........." + /* 2 */ "cdddedddc" + /* 3 */ "d.......d" + /* 4 */ "d.......d" + /* 5 */ "d......fd" + /* 6 */ "cdddddddc" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "..c...c.." + /* 1 */ "........." + /* 2 */ "cdddgdddc" + /* 3 */ "d.......d" + /* 4 */ "h.......h" + /* 5 */ "d.i....fd" + /* 6 */ "cddhhhddc" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "..j...j.." + /* 1 */ "..d...d.." + /* 2 */ "cdddddddc" + /* 3 */ "dkkkkkkkd" + /* 4 */ "lkkkkkkkn" + /* 5 */ "dkkkkkkfd" + /* 6 */ "cddoooddc" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "dpppdpppd" + /* 3 */ "p.......p" + /* 4 */ "d.......d" + /* 5 */ "p......qp" + /* 6 */ "dpppdpppd", + + // Connectors: + "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse3 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse4: + // The data has been exported from the gallery Desert, area index 70, ID 560, created by STR_Warrior + { + // Size: + 5, 5, 11, // SizeX = 5, SizeY = 5, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 5, 4, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 65: 5\n" /* ladder */ + "g:134: 3\n" /* 134 */ + "h: 85: 0\n" /* fence */ + "i:134: 2\n" /* 134 */ + "j: 61: 2\n" /* furnace */ + "k:134: 6\n" /* 134 */ + "l:134: 4\n" /* 134 */ + "m: 19: 0\n" /* sponge */ + "n: 64:12\n" /* wooddoorblock */ + "o: 50: 2\n" /* torch */ + "p:101: 0\n" /* ironbars */ + "q:171: 8\n" /* carpet */ + "r:128: 2\n" /* sandstonestairs */ + "s:126: 8\n" /* woodenslab */ + "t:128: 4\n" /* sandstonestairs */ + "u:128: 5\n" /* sandstonestairs */ + "v:128: 7\n" /* sandstonestairs */ + "w: 44: 1\n" /* step */ + "x: 96: 1\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aabaa" + /* 3 */ "abbba" + /* 4 */ "abbba" + /* 5 */ "abbba" + /* 6 */ "abbba" + /* 7 */ "abbba" + /* 8 */ "abbba" + /* 9 */ "abbba" + /* 10 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "c...c" + /* 1 */ "....." + /* 2 */ "cdedc" + /* 3 */ "df..d" + /* 4 */ "d...d" + /* 5 */ "d..gd" + /* 6 */ "d..hd" + /* 7 */ "d..id" + /* 8 */ "d...d" + /* 9 */ "djkld" + /* 10 */ "cdddc" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "c...c" + /* 1 */ "....." + /* 2 */ "cdndc" + /* 3 */ "df..d" + /* 4 */ "d..od" + /* 5 */ "p...p" + /* 6 */ "p..qp" + /* 7 */ "p...p" + /* 8 */ "d...d" + /* 9 */ "d...d" + /* 10 */ "cdpdc" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "r...r" + /* 1 */ "d...d" + /* 2 */ "cdddc" + /* 3 */ "dfssd" + /* 4 */ "dsssd" + /* 5 */ "tsssu" + /* 6 */ "tsssu" + /* 7 */ "tsssu" + /* 8 */ "dsssd" + /* 9 */ "dsssd" + /* 10 */ "cdvdc" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "dwdwd" + /* 3 */ "wx..w" + /* 4 */ "w...w" + /* 5 */ "w...w" + /* 6 */ "d...d" + /* 7 */ "w...w" + /* 8 */ "w...w" + /* 9 */ "w...w" + /* 10 */ "dwdwd", + + // Connectors: + "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse4 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse5: + // The data has been exported from the gallery Desert, area index 68, ID 558, created by STR_Warrior + { + // Size: + 9, 5, 9, // SizeX = 9, SizeY = 5, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 9, 4, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 65: 2\n" /* ladder */ + "g: 64:12\n" /* wooddoorblock */ + "h:101: 0\n" /* ironbars */ + "i: 50: 1\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 2\n" /* sandstonestairs */ + "l:126: 8\n" /* woodenslab */ + "m: 19: 0\n" /* sponge */ + "n:128: 6\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p:128: 4\n" /* sandstonestairs */ + "q:128: 7\n" /* sandstonestairs */ + "r: 44: 1\n" /* step */ + "s: 96: 6\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaaaaaa" + /* 2 */ "aaaaaabaa" + /* 3 */ "aaaaabbba" + /* 4 */ "aaaaabbba" + /* 5 */ "abbbbbbba" + /* 6 */ "abbbbbbba" + /* 7 */ "abbbbbbba" + /* 8 */ "aaaaaaaaa" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "mmmmc...c" + /* 1 */ "mmmm....." + /* 2 */ "mmmmcdedc" + /* 3 */ "mmmmd...d" + /* 4 */ "cdddd...d" + /* 5 */ "d.......d" + /* 6 */ "d.......d" + /* 7 */ "d......fd" + /* 8 */ "cdddddddc" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "mmmmc...c" + /* 1 */ "mmmm....." + /* 2 */ "mmmmcdgdc" + /* 3 */ "mmmmd...d" + /* 4 */ "cdhdd...h" + /* 5 */ "d.......h" + /* 6 */ "h.......d" + /* 7 */ "di....jfd" + /* 8 */ "cddhhhddc" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "mmmmk...k" + /* 1 */ "mmmmd...d" + /* 2 */ "mmmmcdddc" + /* 3 */ "mmmmdllld" + /* 4 */ "cdnddlllo" + /* 5 */ "dlllllllo" + /* 6 */ "pllllllld" + /* 7 */ "dllllllfd" + /* 8 */ "cddqqqddc" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "mmmm....." + /* 1 */ "mmmm....." + /* 2 */ "mmmmcrdrd" + /* 3 */ "mmmmr...r" + /* 4 */ "drrrd...d" + /* 5 */ "r.......r" + /* 6 */ "r.......r" + /* 7 */ "r......sr" + /* 8 */ "drrrdrrrd", + + // Connectors: + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse6: + // The data has been exported from the gallery Desert, area index 69, ID 559, created by STR_Warrior + { + // Size: + 9, 5, 9, // SizeX = 9, SizeY = 5, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 9, 4, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 2: 0\n" /* grass */ + "c: 5: 0\n" /* wood */ + "d: 85: 0\n" /* fence */ + "e: 24: 2\n" /* sandstone */ + "f: 24: 0\n" /* sandstone */ + "g: 64: 7\n" /* wooddoorblock */ + "h: 38: 1\n" /* rose */ + "i: 38: 2\n" /* rose */ + "j: 38: 5\n" /* rose */ + "k: 65: 2\n" /* ladder */ + "l: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */ + "n:101: 0\n" /* ironbars */ + "o: 50: 1\n" /* torch */ + "p: 50: 4\n" /* torch */ + "q:128: 2\n" /* sandstonestairs */ + "r:126: 8\n" /* woodenslab */ + "s:128: 6\n" /* sandstonestairs */ + "t:128: 5\n" /* sandstonestairs */ + "u:128: 4\n" /* sandstonestairs */ + "v:128: 7\n" /* sandstonestairs */ + "w: 44: 1\n" /* step */ + "x: 96: 6\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "abbbaaaaa" + /* 2 */ "abbbaacaa" + /* 3 */ "abbbaccca" + /* 4 */ "aaaaaccca" + /* 5 */ "accccccca" + /* 6 */ "accccccca" + /* 7 */ "accccccca" + /* 8 */ "aaaaaaaaa" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "dddde...e" + /* 1 */ "d........" + /* 2 */ "d...efgfe" + /* 3 */ "dhijf...f" + /* 4 */ "effff...f" + /* 5 */ "f.......f" + /* 6 */ "f.......f" + /* 7 */ "f......kf" + /* 8 */ "efffffffe" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "....e...e" + /* 1 */ "........." + /* 2 */ "....eflfe" + /* 3 */ "....f...f" + /* 4 */ "efnff...n" + /* 5 */ "f.......n" + /* 6 */ "n.......f" + /* 7 */ "fo....pkf" + /* 8 */ "effnnnffe" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "....q...q" + /* 1 */ "....f...f" + /* 2 */ "....efffe" + /* 3 */ "....frrrf" + /* 4 */ "efsffrrrt" + /* 5 */ "frrrrrrrt" + /* 6 */ "urrrrrrrf" + /* 7 */ "frrrrrrkf" + /* 8 */ "effvvvffe" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "....ewfwf" + /* 3 */ "....w...w" + /* 4 */ "fwwwf...f" + /* 5 */ "w.......w" + /* 6 */ "w.......w" + /* 7 */ "w......xw" + /* 8 */ "fwwwfwwwf", + + // Connectors: + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse6 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleHouse7: + // The data has been exported from the gallery Desert, area index 73, ID 563, created by xoft + { + // Size: + 9, 5, 11, // SizeX = 9, SizeY = 5, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 9, 4, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 65: 2\n" /* ladder */ + "g:101: 0\n" /* ironbars */ + "h: 64:12\n" /* wooddoorblock */ + "i: 50: 1\n" /* torch */ + "j: 50: 2\n" /* torch */ + "k:128: 2\n" /* sandstonestairs */ + "l:128: 6\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:126: 8\n" /* woodenslab */ + "o:128: 4\n" /* sandstonestairs */ + "p:128: 5\n" /* sandstonestairs */ + "q:128: 7\n" /* sandstonestairs */ + "r: 44: 1\n" /* step */ + "s: 96: 6\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaaaaaa" + /* 2 */ "aaaaaabaa" + /* 3 */ "abbbbbbba" + /* 4 */ "abbbbbbba" + /* 5 */ "abbbbbbba" + /* 6 */ "aaaaabbba" + /* 7 */ "aaaaabbba" + /* 8 */ "aaaaabbba" + /* 9 */ "aaaaabbba" + /* 10 */ "aaaaaaaaa" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "....c...c" + /* 1 */ "........." + /* 2 */ "cdddddedc" + /* 3 */ "d.......d" + /* 4 */ "d.......d" + /* 5 */ "d.......d" + /* 6 */ "cdddd...d" + /* 7 */ "mmmmd...d" + /* 8 */ "mmmmd...d" + /* 9 */ "mmmmd..fd" + /* 10 */ "mmmmddddc" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "....c...c" + /* 1 */ "........." + /* 2 */ "cdgdddhdc" + /* 3 */ "d.......d" + /* 4 */ "g.......d" + /* 5 */ "di......g" + /* 6 */ "cdgdd...g" + /* 7 */ "mmmmd...g" + /* 8 */ "mmmmg..jd" + /* 9 */ "mmmmd..fd" + /* 10 */ "mmmmddgdc" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "....k...k" + /* 1 */ "....d...d" + /* 2 */ "cdldddddc" + /* 3 */ "dnnnnnnnd" + /* 4 */ "onnnnnnnd" + /* 5 */ "dnnnnnnnp" + /* 6 */ "cdqddnnnp" + /* 7 */ "mmmmdnnnp" + /* 8 */ "mmmmonnnd" + /* 9 */ "mmmmdnnfd" + /* 10 */ "mmmmddqdc" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "drrrdrdrd" + /* 3 */ "r.......r" + /* 4 */ "r.......r" + /* 5 */ "r.......r" + /* 6 */ "drrrd...d" + /* 7 */ "mmmmr...r" + /* 8 */ "mmmmr...r" + /* 9 */ "mmmmr..sr" + /* 10 */ "mmmmdrrrd", + + // Connectors: + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleHouse7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LittleTower: + // The data has been exported from the gallery Desert, area index 79, ID 595, created by STR_Warrior + { + // Size: + 5, 8, 7, // SizeX = 5, SizeY = 8, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 5, 7, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 65: 5\n" /* ladder */ + "g: 64:12\n" /* wooddoorblock */ + "h:101: 0\n" /* ironbars */ + "i: 50: 4\n" /* torch */ + "j:128: 2\n" /* sandstonestairs */ + "k:126: 8\n" /* woodenslab */ + "l:128: 4\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 5\n" /* sandstonestairs */ + "o:128: 7\n" /* sandstonestairs */ + "p:128: 6\n" /* sandstonestairs */ + "q: 44: 1\n" /* step */ + "r: 96: 5\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aabaa" + /* 3 */ "abbba" + /* 4 */ "abbba" + /* 5 */ "abbba" + /* 6 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "c...c" + /* 1 */ "....." + /* 2 */ "cdedc" + /* 3 */ "df..d" + /* 4 */ "d...d" + /* 5 */ "d...d" + /* 6 */ "cdddc" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "c...c" + /* 1 */ "....." + /* 2 */ "cdgdc" + /* 3 */ "df..d" + /* 4 */ "h...h" + /* 5 */ "d..id" + /* 6 */ "cdhdc" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "j...j" + /* 1 */ "d...d" + /* 2 */ "cdddc" + /* 3 */ "dfkkd" + /* 4 */ "lkkkn" + /* 5 */ "dkkkd" + /* 6 */ "cdodc" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "cdddc" + /* 3 */ "df..d" + /* 4 */ "d...d" + /* 5 */ "d...d" + /* 6 */ "cdddc" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "cdhdc" + /* 3 */ "df..d" + /* 4 */ "h...h" + /* 5 */ "d..id" + /* 6 */ "cdhdc" + + // Level 6 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "cdpdc" + /* 3 */ "dfkkd" + /* 4 */ "lkkkn" + /* 5 */ "dkkkd" + /* 6 */ "cdodc" + + // Level 7 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "dqdqd" + /* 3 */ "qr..q" + /* 4 */ "d...d" + /* 5 */ "q...q" + /* 6 */ "dqdqd", + + // Connectors: + "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LittleTower + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MediumHouse1: + // The data has been exported from the gallery Desert, area index 71, ID 561, created by STR_Warrior + { + // Size: + 15, 8, 9, // SizeX = 15, SizeY = 8, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 15, 7, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 3\n" /* wooddoorblock */ + "f: 85: 0\n" /* fence */ + "g: 64: 0\n" /* wooddoorblock */ + "h: 65: 5\n" /* ladder */ + "i: 64: 8\n" /* wooddoorblock */ + "j:101: 0\n" /* ironbars */ + "k: 50: 4\n" /* torch */ + "l:128: 2\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:126: 8\n" /* woodenslab */ + "o:128: 4\n" /* sandstonestairs */ + "p:128: 7\n" /* sandstonestairs */ + "q: 44: 1\n" /* step */ + "r: 50: 3\n" /* torch */ + "s:128: 6\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaabaaaaaaaaa" + /* 3 */ "abbbbbbbbbaaaaa" + /* 4 */ "abbbbbbbbbaaaaa" + /* 5 */ "abbbbbbbbbbaaaa" + /* 6 */ "abbbbbbbbbaaaaa" + /* 7 */ "abbbbbbbbbaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "...c...c......." + /* 1 */ "..............." + /* 2 */ "cddddeddddcffff" + /* 3 */ "d.........d...f" + /* 4 */ "d.........d...f" + /* 5 */ "d.........g...f" + /* 6 */ "d.........d...f" + /* 7 */ "d.........dh..f" + /* 8 */ "cdddddddddcffff" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "...c...c......." + /* 1 */ "..............." + /* 2 */ "cddddiddddc...." + /* 3 */ "d.........d...." + /* 4 */ "j.........d...." + /* 5 */ "j.........i...." + /* 6 */ "j.........d...." + /* 7 */ "d..k...k..dh..." + /* 8 */ "cdddjjjdddc...." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "...l...l......." + /* 1 */ "...d...d......." + /* 2 */ "cdddddddddc...." + /* 3 */ "dnnnnnnnnnd...." + /* 4 */ "onnnnnnnnnd...." + /* 5 */ "onnnnnnnnnd...." + /* 6 */ "onnnnnnnnnd...." + /* 7 */ "dnnnnnnnnndh..." + /* 8 */ "cdddpppdddc...." + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "dqqqqdqqqqd...." + /* 3 */ "q..cdddc..q...." + /* 4 */ "q..d...d..q...." + /* 5 */ "d.........d...." + /* 6 */ "q..d...d..q...." + /* 7 */ "q..cdddc..q...." + /* 8 */ "dqqqqdqqqqd...." + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "...cdjdc......." + /* 4 */ "...dr..d......." + /* 5 */ "..............." + /* 6 */ "...d...d......." + /* 7 */ "...cdjdc......." + /* 8 */ "..............." + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "...cdsdc......." + /* 4 */ "...dnnnd......." + /* 5 */ "...dnnnd......." + /* 6 */ "...dnnnd......." + /* 7 */ "...cdpdc......." + /* 8 */ "..............." + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "...dqdqd......." + /* 4 */ "...q...q......." + /* 5 */ "...d...d......." + /* 6 */ "...q...q......." + /* 7 */ "...dqdqd......." + /* 8 */ "...............", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 80, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // MediumHouse1 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MediumHouse2: + // The data has been exported from the gallery Desert, area index 74, ID 573, created by STR_Warrior + { + // Size: + 11, 9, 9, // SizeX = 11, SizeY = 9, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 8, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A: 96: 3\n" /* trapdoor */ + "B: 96: 6\n" /* trapdoor */ + "C:128: 2\n" /* sandstonestairs */ + "D:128: 0\n" /* sandstonestairs */ + "E: 87: 0\n" /* netherstone */ + "F:128: 1\n" /* sandstonestairs */ + "G:128: 3\n" /* sandstonestairs */ + "H: 51: 0\n" /* fire */ + "I: 44: 9\n" /* step */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 65: 3\n" /* ladder */ + "f: 85: 0\n" /* fence */ + "g: 64: 7\n" /* wooddoorblock */ + "h:134: 1\n" /* 134 */ + "i:134: 2\n" /* 134 */ + "j: 61: 2\n" /* furnace */ + "k:134: 6\n" /* 134 */ + "l:134: 4\n" /* 134 */ + "m: 19: 0\n" /* sponge */ + "n: 65: 2\n" /* ladder */ + "o:101: 0\n" /* ironbars */ + "p: 50: 2\n" /* torch */ + "q: 47: 0\n" /* bookshelf */ + "r: 64:12\n" /* wooddoorblock */ + "s: 50: 3\n" /* torch */ + "t:171: 8\n" /* carpet */ + "u:128: 6\n" /* sandstonestairs */ + "v:126: 8\n" /* woodenslab */ + "w:128: 5\n" /* sandstonestairs */ + "x:128: 4\n" /* sandstonestairs */ + "y:128: 7\n" /* sandstonestairs */ + "z: 44: 1\n" /* step */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "abbbaaaaaaa" + /* 2 */ "abbbaaaaaaa" + /* 3 */ "abbbaaaaaaa" + /* 4 */ "abbbaaaabaa" + /* 5 */ "abbbbbbbbba" + /* 6 */ "abbbbbbbbba" + /* 7 */ "abbbbbbbbba" + /* 8 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "cdddc......" + /* 1 */ "de..dfff.f." + /* 2 */ "d...d....f." + /* 3 */ "d...d....f." + /* 4 */ "d...ddddgdc" + /* 5 */ "d.........d" + /* 6 */ "dhf.......d" + /* 7 */ "dhi.jkl..nd" + /* 8 */ "cdddddddddc" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "cdodc......" + /* 1 */ "de..o......" + /* 2 */ "d...o......" + /* 3 */ "o..pd......" + /* 4 */ "o...qdodrdc" + /* 5 */ "o......s..d" + /* 6 */ "d.t.......o" + /* 7 */ "d........nd" + /* 8 */ "cdddooodddc" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "cdudc......" + /* 1 */ "devvw......" + /* 2 */ "dvvvw......" + /* 3 */ "xvvvd......" + /* 4 */ "xvvvddudddc" + /* 5 */ "xvvvvvvvvvd" + /* 6 */ "dvvvvvvvvvw" + /* 7 */ "dvvvqqqvvnd" + /* 8 */ "cdddyyydddc" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "dzzzd......" + /* 1 */ "zA..z......" + /* 2 */ "z...z......" + /* 3 */ "z...z......" + /* 4 */ "d...dzzzzzd" + /* 5 */ "zddd......z" + /* 6 */ "zddd......z" + /* 7 */ "zddd.....Bz" + /* 8 */ "dzzzzdzzzzd" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "..........." + /* 5 */ ".cCc......." + /* 6 */ ".DEF......." + /* 7 */ ".cGc......." + /* 8 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "..........." + /* 5 */ ".c.c......." + /* 6 */ "..H........" + /* 7 */ ".c.c......." + /* 8 */ "..........." + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "..........." + /* 5 */ ".ddd......." + /* 6 */ ".dId......." + /* 7 */ ".ddd......." + /* 8 */ "..........." + + // Level 8 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "..........." + /* 5 */ ".z.z......." + /* 6 */ "..........." + /* 7 */ ".z.z......." + /* 8 */ "...........", + + // Connectors: + "-1: 8, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 80, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // MediumHouse2 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MediumHouse3: + // The data has been exported from the gallery Desert, area index 76, ID 575, created by STR_Warrior + { + // Size: + 12, 10, 11, // SizeX = 12, SizeY = 10, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 12, 9, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 3: 0\n" /* dirt */ + "c: 2: 0\n" /* grass */ + "d: 5: 0\n" /* wood */ + "e: 24: 0\n" /* sandstone */ + "f: 24: 2\n" /* sandstone */ + "g: 85: 0\n" /* fence */ + "h: 64: 3\n" /* wooddoorblock */ + "i: 64: 6\n" /* wooddoorblock */ + "j: 65: 4\n" /* ladder */ + "k: 65: 2\n" /* ladder */ + "l: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 50: 2\n" /* torch */ + "o:101: 0\n" /* ironbars */ + "p: 64: 8\n" /* wooddoorblock */ + "q: 64:12\n" /* wooddoorblock */ + "r:128: 2\n" /* sandstonestairs */ + "s:128: 6\n" /* sandstonestairs */ + "t:126: 8\n" /* woodenslab */ + "u:128: 5\n" /* sandstonestairs */ + "v:128: 7\n" /* sandstonestairs */ + "w: 44: 1\n" /* step */ + "x: 96: 4\n" /* trapdoor */ + "y:126: 0\n" /* woodenslab */ + "z:128: 4\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "bbbbbaaaaaaa" + /* 3 */ "bbbbbaaaaaaa" + /* 4 */ "bbbbbaaaaaaa" + /* 5 */ "bbbbbaaaaaaa" + /* 6 */ "bbbaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaa" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "cccccaaaadaa" + /* 3 */ "cccccaddddda" + /* 4 */ "cccccdddddda" + /* 5 */ "cccccaddddda" + /* 6 */ "cccaadddddda" + /* 7 */ "aaaaddddddda" + /* 8 */ "aaaadddaaaaa" + /* 9 */ "aaaadddaaaaa" + /* 10 */ "aaaaaaaaaaaa" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ ".....e.....f" + /* 1 */ "............" + /* 2 */ "gggggfeeehef" + /* 3 */ "g....e.....e" + /* 4 */ "g....i.....e" + /* 5 */ "g....e.....e" + /* 6 */ "gggfe......e" + /* 7 */ "mmme......je" + /* 8 */ "mmme...eeeef" + /* 9 */ "mmme..kemmmm" + /* 10 */ "mmmfeeefmmmm" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ ".....el...nf" + /* 1 */ "............" + /* 2 */ ".....fooepef" + /* 3 */ ".....e.....e" + /* 4 */ ".....q.....e" + /* 5 */ ".....e.....o" + /* 6 */ "...ge......e" + /* 7 */ "mmme......je" + /* 8 */ "mmme...eeoof" + /* 9 */ "mmme..kemmmm" + /* 10 */ "mmmgeeegmmmm" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ ".....r.....r" + /* 1 */ ".....e.....e" + /* 2 */ ".....fsseeef" + /* 3 */ ".....ettttte" + /* 4 */ ".....ettttte" + /* 5 */ ".....etttttu" + /* 6 */ "...getttttte" + /* 7 */ "mmmettttttje" + /* 8 */ "mmmettteevvf" + /* 9 */ "mmmettkemmmm" + /* 10 */ "mmmgeeegmmmm" + + // Level 5 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ ".....ewwewwe" + /* 3 */ ".....w.....w" + /* 4 */ ".....w.....w" + /* 5 */ ".....w.....e" + /* 6 */ "...geeeg...w" + /* 7 */ "mmme...e..xw" + /* 8 */ "mmme...ewwwe" + /* 9 */ "mmme..kemmmm" + /* 10 */ "mmmgeeegmmmm" + + // Level 6 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "............" + /* 4 */ "............" + /* 5 */ "............" + /* 6 */ "...ge.eg...." + /* 7 */ "mmme...e...." + /* 8 */ "mmmo........" + /* 9 */ "mmme..kemmmm" + /* 10 */ "mmmgeoegmmmm" + + // Level 7 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "............" + /* 4 */ "............" + /* 5 */ "............" + /* 6 */ "...ge.eg...." + /* 7 */ "mmme...e...." + /* 8 */ "mmmo........" + /* 9 */ "mmmel.kemmmm" + /* 10 */ "mmmgeoegmmmm" + + // Level 8 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "............" + /* 4 */ "............" + /* 5 */ "............" + /* 6 */ "...fesef...." + /* 7 */ "mmmeyyye...." + /* 8 */ "mmmzyyyu...." + /* 9 */ "mmmeyykemmmm" + /* 10 */ "mmmfevefmmmm" + + // Level 9 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "............" + /* 4 */ "............" + /* 5 */ "............" + /* 6 */ "...w.w.w...." + /* 7 */ "mmm........." + /* 8 */ "mmmw...w...." + /* 9 */ "mmm.....mmmm" + /* 10 */ "mmmw.w.wmmmm", + + // Connectors: + "-1: 9, 2, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 80, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // MediumHouse3 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SmallHouse9: + // The data has been exported from the gallery Desert, area index 67, ID 556, created by STR_Warrior + { + // Size: + 9, 5, 11, // SizeX = 9, SizeY = 5, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 9, 4, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 65: 2\n" /* ladder */ + "g: 64:12\n" /* wooddoorblock */ + "h:101: 0\n" /* ironbars */ + "i: 50: 2\n" /* torch */ + "j: 50: 1\n" /* torch */ + "k:128: 2\n" /* sandstonestairs */ + "l:126: 8\n" /* woodenslab */ + "m: 19: 0\n" /* sponge */ + "n:128: 5\n" /* sandstonestairs */ + "o:128: 6\n" /* sandstonestairs */ + "p:128: 4\n" /* sandstonestairs */ + "q:128: 7\n" /* sandstonestairs */ + "r: 44: 1\n" /* step */ + "s: 96: 6\n" /* trapdoor */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaaaaaa" + /* 2 */ "aaaaaabaa" + /* 3 */ "aaaaabbba" + /* 4 */ "aaaaabbba" + /* 5 */ "aaaaabbba" + /* 6 */ "aaaaabbba" + /* 7 */ "abbbbbbba" + /* 8 */ "abbbbbbba" + /* 9 */ "abbbbbbba" + /* 10 */ "aaaaaaaaa" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "mmmmc...c" + /* 1 */ "mmmm....." + /* 2 */ "mmmmcdedc" + /* 3 */ "mmmmd...d" + /* 4 */ "mmmmd...d" + /* 5 */ "mmmmd...d" + /* 6 */ "cdddd...d" + /* 7 */ "d.......d" + /* 8 */ "d.......d" + /* 9 */ "d......fd" + /* 10 */ "cdddddddc" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "mmmmc...c" + /* 1 */ "mmmm....." + /* 2 */ "mmmmcdgdc" + /* 3 */ "mmmmd...d" + /* 4 */ "mmmmd...d" + /* 5 */ "mmmmd...h" + /* 6 */ "cdhdd...h" + /* 7 */ "d.......h" + /* 8 */ "h......id" + /* 9 */ "dj.....fd" + /* 10 */ "cddhhhddc" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "mmmmk...k" + /* 1 */ "mmmmd...d" + /* 2 */ "mmmmcdddc" + /* 3 */ "mmmmdllld" + /* 4 */ "mmmmdllld" + /* 5 */ "mmmmdllln" + /* 6 */ "cdoddllln" + /* 7 */ "dllllllln" + /* 8 */ "pllllllld" + /* 9 */ "dllllllfd" + /* 10 */ "cddqqqddc" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "mmmm....." + /* 1 */ "mmmm....." + /* 2 */ "mmmmdrdrd" + /* 3 */ "mmmmr...r" + /* 4 */ "mmmmr...r" + /* 5 */ "mmmmr...r" + /* 6 */ "drrrd...d" + /* 7 */ "r.......r" + /* 8 */ "r.......r" + /* 9 */ "r......sr" + /* 10 */ "drrrdrrrd", + + // Connectors: + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // SmallHouse9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Temple: + // The data has been exported from the gallery Desert, area index 83, ID 599, created by STR_Warrior + { + // Size: + 13, 9, 9, // SizeX = 13, SizeY = 9, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 13, 8, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A: 44: 9\n" /* step */ + "a: 12: 0\n" /* sand */ + "b: 5: 0\n" /* wood */ + "c: 24: 2\n" /* sandstone */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 17: 0\n" /* tree */ + "g:128: 5\n" /* sandstonestairs */ + "h:128: 4\n" /* sandstonestairs */ + "i:128: 7\n" /* sandstonestairs */ + "j:128: 6\n" /* sandstonestairs */ + "k:118: 3\n" /* cauldronblock */ + "l:155: 1\n" /* quartzblock */ + "m: 19: 0\n" /* sponge */ + "n: 64:12\n" /* wooddoorblock */ + "o: 50: 3\n" /* torch */ + "p:101: 0\n" /* ironbars */ + "q:140: 0\n" /* flowerpotblock */ + "r: 24: 1\n" /* sandstone */ + "s:128: 2\n" /* sandstonestairs */ + "t:126: 8\n" /* woodenslab */ + "u: 44: 1\n" /* step */ + "v:128: 0\n" /* sandstonestairs */ + "w: 87: 0\n" /* netherstone */ + "x:128: 1\n" /* sandstonestairs */ + "y:128: 3\n" /* sandstonestairs */ + "z: 51: 0\n" /* fire */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaabbababbaaa" + /* 3 */ "abbbbbbbbbbba" + /* 4 */ "abbbbbbbbbbba" + /* 5 */ "abbbbbbbbbbba" + /* 6 */ "abbbbbbbbbbba" + /* 7 */ "abbbbbbbbbbba" + /* 8 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "....c...c...." + /* 1 */ "............." + /* 2 */ "cdddddedddddc" + /* 3 */ "dfg.......hfd" + /* 4 */ "di.........id" + /* 5 */ "d...........d" + /* 6 */ "dj.........jd" + /* 7 */ "dfg.khlgk.hfd" + /* 8 */ "cdddddddddddc" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "....c...c...." + /* 1 */ "............." + /* 2 */ "cdddddndddddc" + /* 3 */ "df...o.o...fd" + /* 4 */ "d...........d" + /* 5 */ "p...........p" + /* 6 */ "d...........d" + /* 7 */ "df...qrq...fd" + /* 8 */ "cdpppdddpppdc" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "....s...s...." + /* 1 */ "....r...d...." + /* 2 */ "cdddddddddddc" + /* 3 */ "dftttttttttfd" + /* 4 */ "dtttttttttttd" + /* 5 */ "htttttttttttg" + /* 6 */ "dtttttttttttd" + /* 7 */ "dftttttttttfd" + /* 8 */ "cdiiidddiiidc" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "duuuuuduuuuud" + /* 3 */ "u...........u" + /* 4 */ "u.ddd...ddd.u" + /* 5 */ "d.ddd...ddd.d" + /* 6 */ "u.ddd...ddd.u" + /* 7 */ "u...........u" + /* 8 */ "duuuuuduuuuud" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "..csc...csc.." + /* 5 */ "..vwx...vwx.." + /* 6 */ "..cyc...cyc.." + /* 7 */ "............." + /* 8 */ "............." + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "..c.c...c.c.." + /* 5 */ "...z.....z..." + /* 6 */ "..c.c...c.c.." + /* 7 */ "............." + /* 8 */ "............." + + // Level 7 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "..ddd...ddd.." + /* 5 */ "..dAd...dAd.." + /* 6 */ "..ddd...ddd.." + /* 7 */ "............." + /* 8 */ "............." + + // Level 8 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "..u.u...u.u.." + /* 5 */ "............." + /* 6 */ "..u.u...u.u.." + /* 7 */ "............." + /* 8 */ ".............", + + // Connectors: + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 50, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Temple +}; // g_AlchemistVillagePrefabs + + + + + + +const cPrefab::sDef g_AlchemistVillageStartingPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Well: + // The data has been exported from the gallery Desert, area index 90, ID 631, created by STR_Warrior + { + // Size: + 5, 21, 5, // SizeX = 5, SizeY = 21, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 20, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 24: 0\n" /* sandstone */ + "c: 8: 0\n" /* water */ + "d: 24: 2\n" /* sandstone */ + "e:128: 1\n" /* sandstonestairs */ + "f: 44: 1\n" /* step */ + "g:128: 0\n" /* sandstonestairs */ + "h:128: 3\n" /* sandstonestairs */ + "i:128: 2\n" /* sandstonestairs */ + "j: 44: 9\n" /* step */ + "k:126: 0\n" /* woodenslab */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 6 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 7 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 8 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 9 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 10 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 11 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 12 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 13 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 14 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 15 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 16 + /* z\x* 01234 */ + /* 0 */ "defgd" + /* 1 */ "h...h" + /* 2 */ "f...f" + /* 3 */ "i...i" + /* 4 */ "defgd" + + // Level 17 + /* z\x* 01234 */ + /* 0 */ "d...d" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "d...d" + + // Level 18 + /* z\x* 01234 */ + /* 0 */ "djjjd" + /* 1 */ "j...j" + /* 2 */ "j...j" + /* 3 */ "j...j" + /* 4 */ "djjjd" + + // Level 19 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bkkkb" + /* 2 */ "bkkkb" + /* 3 */ "bkkkb" + /* 4 */ "bbbbb" + + // Level 20 + /* z\x* 01234 */ + /* 0 */ "f.f.f" + /* 1 */ "....." + /* 2 */ "f...f" + /* 3 */ "....." + /* 4 */ "f.f.f", + + // Connectors: + "2: 2, 16, 4: 3\n" /* Type 2, direction Z+ */ + "2: 0, 16, 2: 4\n" /* Type 2, direction X- */ + "2: 2, 16, 0: 2\n" /* Type 2, direction Z- */ + "2: 4, 16, 2: 5\n" /* Type 2, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Well +}; + + + + + +// The prefab counts: + +const size_t g_AlchemistVillagePrefabsCount = ARRAYCOUNT(g_AlchemistVillagePrefabs); + +const size_t g_AlchemistVillageStartingPrefabsCount = ARRAYCOUNT(g_AlchemistVillageStartingPrefabs); + diff --git a/src/Generating/Prefabs/AlchemistVillagePrefabs.h b/src/Generating/Prefabs/AlchemistVillagePrefabs.h new file mode 100644 index 000000000..dddc5530a --- /dev/null +++ b/src/Generating/Prefabs/AlchemistVillagePrefabs.h @@ -0,0 +1,15 @@ + +// AlchemistVillagePrefabs.h + +// Declares the prefabs in the group AlchemistVillage + +#include "../Prefab.h" + + + + + +extern const cPrefab::sDef g_AlchemistVillagePrefabs[]; +extern const cPrefab::sDef g_AlchemistVillageStartingPrefabs[]; +extern const size_t g_AlchemistVillagePrefabsCount; +extern const size_t g_AlchemistVillageStartingPrefabsCount; diff --git a/src/Generating/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt new file mode 100644 index 000000000..a1f09112d --- /dev/null +++ b/src/Generating/Prefabs/CMakeLists.txt @@ -0,0 +1,14 @@ + +cmake_minimum_required (VERSION 2.6) +project (MCServer) + +include_directories ("${PROJECT_SOURCE_DIR}/../../") + +file(GLOB SOURCE + "*.cpp" + "*.h" +) + +add_library(Generating_Prefabs ${SOURCE}) + +target_link_libraries(Generating_Prefabs OSSupport iniFile Blocks) diff --git a/src/Generating/Prefabs/JapaneseVillagePrefabs.cpp b/src/Generating/Prefabs/JapaneseVillagePrefabs.cpp new file mode 100644 index 000000000..5ec222f84 --- /dev/null +++ b/src/Generating/Prefabs/JapaneseVillagePrefabs.cpp @@ -0,0 +1,3200 @@ + +// JapaneseVillagePrefabs.cpp + +// Defines the prefabs in the group JapaneseVillage + +// NOTE: This file has been generated automatically by GalExport! +// Any manual changes will be overwritten by the next automatic export! + +#include "Globals.h" +#include "JapaneseVillagePrefabs.h" + + + + + +const cPrefab::sDef g_JapaneseVillagePrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Arch: + // The data has been exported from the gallery Plains, area index 144, ID 488, created by Aloe_vera + { + // Size: + 11, 7, 5, // SizeX = 11, SizeY = 7, SizeZ = 5 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 6, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 2: 0\n" /* grass */ + "b: 13: 0\n" /* gravel */ + "c:113: 0\n" /* netherbrickfence */ + "d: 50: 5\n" /* torch */ + "e: 44: 8\n" /* step */ + "f: 44: 0\n" /* step */ + "g: 43: 0\n" /* doubleslab */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaabbbaaaa" + /* 1 */ "aaaabbbaaaa" + /* 2 */ "aaaabbbaaaa" + /* 3 */ "aaaabbbaaaa" + /* 4 */ "aaaabbbaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..c.....c.." + /* 1 */ "..c.....c.." + /* 2 */ "..c.....c.." + /* 3 */ "..c.....c.." + /* 4 */ "..c.....c.." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..c.....c.." + /* 1 */ "..........." + /* 2 */ "..c.....c.." + /* 3 */ "..........." + /* 4 */ "..c.....c.." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..d.....d.." + /* 1 */ "..........." + /* 2 */ "..c.....c.." + /* 3 */ "..........." + /* 4 */ "..d.....d.." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...eeeee..." + /* 1 */ "..........." + /* 2 */ "..c.....c.." + /* 3 */ "..........." + /* 4 */ "...eeeee..." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..f.....f.." + /* 1 */ ".egfffffge." + /* 2 */ ".egeeeeege." + /* 3 */ ".egfffffge." + /* 4 */ "..f.....f.." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "gf.......fg" + /* 3 */ "..........." + /* 4 */ "...........", + + // Connectors: + "2: 5, 1, 4: 3\n" /* Type 2, direction Z+ */ + "2: 5, 1, 0: 2\n" /* Type 2, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Arch + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Forge: + // The data has been exported from the gallery Plains, area index 79, ID 145, created by Aloe_vera + { + // Size: + 16, 11, 14, // SizeX = 16, SizeY = 11, SizeZ = 14 + + // Hitbox (relative to bounding box): + 0, 0, -1, // MinX, MinY, MinZ + 16, 10, 14, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 17: 1\n" /* tree */ + "c: 67: 0\n" /* stairs */ + "d: 5: 2\n" /* wood */ + "e: 67: 2\n" /* stairs */ + "f:113: 0\n" /* netherbrickfence */ + "g:118: 2\n" /* cauldronblock */ + "h: 67: 6\n" /* stairs */ + "i: 67: 4\n" /* stairs */ + "j: 87: 0\n" /* netherstone */ + "k: 67: 7\n" /* stairs */ + "l: 54: 5\n" /* chest */ + "m: 19: 0\n" /* sponge */ + "n: 61: 2\n" /* furnace */ + "o:101: 0\n" /* ironbars */ + "p: 51: 0\n" /* fire */ + "q: 50: 4\n" /* torch */ + "r: 50: 2\n" /* torch */ + "s: 35: 0\n" /* wool */ + "t: 67: 3\n" /* stairs */ + "u: 50: 3\n" /* torch */ + "v: 44: 8\n" /* step */ + "w: 43: 0\n" /* doubleslab */ + "x: 44: 0\n" /* step */ + "y: 17: 5\n" /* tree */ + "z: 17: 9\n" /* tree */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmmmmmmm" + /* 2 */ "mmaaaaaaaaaaaamm" + /* 3 */ "mmaaaaaaaaaaaamm" + /* 4 */ "mmaaaaaaaaaaaamm" + /* 5 */ "mmaaaaaaaaaaaamm" + /* 6 */ "mmaaaaaaaaaaaamm" + /* 7 */ "mmaaaaaaaaaaaamm" + /* 8 */ "mmaaaaaaaaaaaamm" + /* 9 */ "mmaaaaaaaaaaaamm" + /* 10 */ "mmaaaaaaaaaaaamm" + /* 11 */ "mmaaaaaaaaaaaamm" + /* 12 */ "mmmmmmmmmmmmmmmm" + /* 13 */ "mmmmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ ".....bbbbbbbbb.." + /* 3 */ ".....cdddddddb.." + /* 4 */ ".....cddaaaadb.." + /* 5 */ "..beeedaaaaadb.." + /* 6 */ "..bddddaaaaadb.." + /* 7 */ "..bddddaaaaadb.." + /* 8 */ "..bddddaaaaadb.." + /* 9 */ "..bddddaaaaadb.." + /* 10 */ "..bddddddddddb.." + /* 11 */ "..bbbbbbbbbbbb.." + /* 12 */ "................" + /* 13 */ "................" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ ".....bfffbfffb.." + /* 3 */ ".............a.." + /* 4 */ ".............a.." + /* 5 */ "..b.....ghh..a.." + /* 6 */ "..f.....haa..b.." + /* 7 */ "..f.....ija..b.." + /* 8 */ "..f.....kaa..a.." + /* 9 */ "..f..........a.." + /* 10 */ "..fl.........a.." + /* 11 */ "..bffffbbffffb.." + /* 12 */ "................" + /* 13 */ "................" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ ".....bfffbfffb.." + /* 3 */ ".............a.." + /* 4 */ ".............a.." + /* 5 */ "..b......nn..a.." + /* 6 */ "..f.....oaa..b.." + /* 7 */ "..f.....opa..b.." + /* 8 */ "..f.....oaa..a.." + /* 9 */ "..f..........a.." + /* 10 */ "..f..........a.." + /* 11 */ "..bffffbbffffb.." + /* 12 */ "................" + /* 13 */ "................" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".........q...q.." + /* 2 */ "....rbsssbsssb.." + /* 3 */ ".............a.." + /* 4 */ "..q..........a.." + /* 5 */ "..b......ce..a.." + /* 6 */ "..s......ea..b.." + /* 7 */ "..s......aa..b.." + /* 8 */ "..s......ta..a.." + /* 9 */ "..s..........a.." + /* 10 */ "..s..........a.." + /* 11 */ ".rbssssbbssssb.." + /* 12 */ "..u....uu....u.." + /* 13 */ "................" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ ".vwxxxxxxxxxxwv." + /* 1 */ "vvvvvvvvvvvvvvvv" + /* 2 */ "wvbyybyyybbyybvw" + /* 3 */ "xvz..........zvx" + /* 4 */ "xvz..........zvx" + /* 5 */ "xvb..........zvx" + /* 6 */ "xvz.......a..bvx" + /* 7 */ "xvz......ca..bvx" + /* 8 */ "xvz.......a..zvx" + /* 9 */ "xvz..........zvx" + /* 10 */ "xvz..........zvx" + /* 11 */ "wvbyyyyyyyyyybvw" + /* 12 */ "vvvvvvvvvvvvvvvv" + /* 13 */ ".vwxxxxxxxxxxwv." + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "wx............xw" + /* 1 */ "x..............x" + /* 2 */ "..xxxxxxxxxxxx.." + /* 3 */ "..xwwwwwwwwwwx.." + /* 4 */ "..xwvvvvvvvvvx.." + /* 5 */ "..xwv.......vx.." + /* 6 */ "..xwv.....a.vx.." + /* 7 */ "..xwv.....a.vx.." + /* 8 */ "..xwv.....a.vx.." + /* 9 */ "..xwvvvvvvvvvx.." + /* 10 */ "..xwwwwwwwwwwx.." + /* 11 */ "..xxxxxxxxxxxx.." + /* 12 */ "x..............x" + /* 13 */ "wx............xw" + + // Level 7 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "....xxxxxxxx...." + /* 5 */ "....xxxxxxxx...." + /* 6 */ "....xwwwwwax...." + /* 7 */ "....xwvvvvax...." + /* 8 */ "....xwwwwwax...." + /* 9 */ "....xxxxxxxx...." + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ "................" + + // Level 8 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "................" + /* 5 */ "................" + /* 6 */ "..........a....." + /* 7 */ ".......xx.a....." + /* 8 */ "..........a....." + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ "................" + + // Level 9 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "................" + /* 5 */ "................" + /* 6 */ "..........a....." + /* 7 */ "..........a....." + /* 8 */ "..........a....." + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ "................" + + // Level 10 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "................" + /* 5 */ "................" + /* 6 */ "..........a....." + /* 7 */ "..........a....." + /* 8 */ "..........a....." + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ "................", + + // Connectors: + "-1: 0, 1, 3: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Forge + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Garden2: + // The data has been exported from the gallery Plains, area index 147, ID 491, created by Aloe_vera + { + // Size: + 16, 5, 16, // SizeX = 16, SizeY = 5, SizeZ = 16 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 15, 4, 15, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 8: 0\n" /* water */ + "c: 2: 0\n" /* grass */ + "d: 17: 1\n" /* tree */ + "e: 13: 0\n" /* gravel */ + "f: 31: 2\n" /* tallgrass */ + "g: 18: 5\n" /* leaves */ + "h: 38: 7\n" /* rose */ + "i: 17: 9\n" /* tree */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaaa" + /* 15 */ "aaaaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaaa" + /* 6 */ "aaaabbaaaaaaaaaa" + /* 7 */ "aaabbbaaaaaaaaaa" + /* 8 */ "aaabbaaaaaaaaaaa" + /* 9 */ "aaaabaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaaa" + /* 15 */ "aaaaaaaaaaaaaaaa" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "cccccccccccccccc" + /* 1 */ "ccdccccccccdcccc" + /* 2 */ "cccccceecccccdcc" + /* 3 */ "ccccccceeccccccc" + /* 4 */ "cccccccceccccccc" + /* 5 */ "cccbbbbceccccccc" + /* 6 */ "cccbbbbceecccccc" + /* 7 */ "ccbbbbbcceeeeccc" + /* 8 */ "ccbbbbbccccceecc" + /* 9 */ "ccbbbbcccccccecc" + /* 10 */ "ccccbcccccccceec" + /* 11 */ "ccccccccccccccec" + /* 12 */ "ccccccccaaacccec" + /* 13 */ "cccccccccaccccec" + /* 14 */ "ccccccccccccceec" + /* 15 */ "cccccccccccceecc" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "......f...gg.g.." + /* 1 */ "..gg.....gggggg." + /* 2 */ "ffgg......ghgggg" + /* 3 */ ".............gg." + /* 4 */ "...........f...." + /* 5 */ "...........h.ff." + /* 6 */ ".............fh." + /* 7 */ "...............f" + /* 8 */ "................" + /* 9 */ ".......ff.f....." + /* 10 */ ".f.....ffggf...." + /* 11 */ ".......gggg.f..." + /* 12 */ ".f......iddg...." + /* 13 */ ".....f..gdgg...." + /* 14 */ "....ff...gg....." + /* 15 */ "................" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "...........g.g.." + /* 2 */ ".............gg." + /* 3 */ "................" + /* 4 */ "................" + /* 5 */ "................" + /* 6 */ "................" + /* 7 */ "................" + /* 8 */ "................" + /* 9 */ "................" + /* 10 */ ".........g......" + /* 11 */ "........ggg....." + /* 12 */ "........ggg....." + /* 13 */ ".........g......" + /* 14 */ "................" + /* 15 */ "................", + + // Connectors: + "-1: 12, 3, 15: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Garden2 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseMid: + // The data has been exported from the gallery Plains, area index 62, ID 119, created by Aloe_vera + { + // Size: + 10, 9, 9, // SizeX = 10, SizeY = 9, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, -1, // MinX, MinY, MinZ + 10, 8, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b:135: 2\n" /* 135 */ + "c:135: 0\n" /* 135 */ + "d: 17: 9\n" /* tree */ + "e:135: 3\n" /* 135 */ + "f: 85: 0\n" /* fence */ + "g: 17: 1\n" /* tree */ + "h:171: 0\n" /* carpet */ + "i: 50: 5\n" /* torch */ + "j: 35: 0\n" /* wool */ + "k: 17: 5\n" /* tree */ + "l:124: 0\n" /* redstonelampon */ + "m: 19: 0\n" /* sponge */ + "n: 69: 9\n" /* lever */ + "o: 44: 8\n" /* step */ + "p: 43: 0\n" /* doubleslab */ + "q: 44: 0\n" /* step */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "maaaaaaaaa" + /* 1 */ "maaaaaaaaa" + /* 2 */ "aaaaaaaaaa" + /* 3 */ "aaaaaaaaaa" + /* 4 */ "aaaaaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "aaaaaaaaaa" + /* 7 */ "maaaaaaaaa" + /* 8 */ "maaaaaaaaa" + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".aaaaaaaaa" + /* 1 */ ".aaaaaaaaa" + /* 2 */ "baaaaaaaaa" + /* 3 */ "caaaaaaaaa" + /* 4 */ "caadaaaaaa" + /* 5 */ "caaaaaaaaa" + /* 6 */ "eaaaaaaaaa" + /* 7 */ ".aaaaaaaaa" + /* 8 */ ".aaaaaaaaa" + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".fffffffff" + /* 1 */ ".f.......f" + /* 2 */ ".f.ggggg.f" + /* 3 */ "...ghhhg.f" + /* 4 */ "....hhhg.f" + /* 5 */ "...ghhhg.f" + /* 6 */ ".f.ggggg.f" + /* 7 */ ".f.......f" + /* 8 */ ".fffffffff" + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".....i...i" + /* 1 */ ".........." + /* 2 */ ".i.jjgjj.." + /* 3 */ "...g...j.." + /* 4 */ ".......g.i" + /* 5 */ "...g...j.." + /* 6 */ ".i.jjgjj.." + /* 7 */ ".........." + /* 8 */ ".....i...i" + + // Level 4 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".........." + /* 2 */ "...jjgjj.." + /* 3 */ "...g...j.." + /* 4 */ "...j...g.." + /* 5 */ "...g...j.." + /* 6 */ "...jjgjj.." + /* 7 */ ".........." + /* 8 */ ".........." + + // Level 5 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ "...f...f.." + /* 2 */ "..fgkgkgf." + /* 3 */ "..fd...d.." + /* 4 */ "...d.lng.." + /* 5 */ "..fd...d.." + /* 6 */ "..fgkgkgf." + /* 7 */ "...f...f.." + /* 8 */ ".........." + + // Level 6 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "...ooooo.." + /* 1 */ "..opppppo." + /* 2 */ ".opgjjjgpo" + /* 3 */ ".opjgggjpo" + /* 4 */ ".opjgggjpo" + /* 5 */ ".opjgggjpo" + /* 6 */ ".opgjjjgpo" + /* 7 */ "..opppppo." + /* 8 */ "...ooooo.." + + // Level 7 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".opq...qpo" + /* 1 */ ".pq.....qp" + /* 2 */ ".q.qqqqq.q" + /* 3 */ "...qpppq.." + /* 4 */ "...qpppq.." + /* 5 */ "...qpppq.." + /* 6 */ ".q.qqqqq.q" + /* 7 */ ".pq.....qp" + /* 8 */ ".opq...qpo" + + // Level 8 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".q.......q" + /* 1 */ ".........." + /* 2 */ ".........." + /* 3 */ ".........." + /* 4 */ ".....q...." + /* 5 */ ".........." + /* 6 */ ".........." + /* 7 */ ".........." + /* 8 */ ".q.......q", + + // Connectors: + "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseMid + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseSmall: + // The data has been exported from the gallery Plains, area index 68, ID 131, created by Aloe_vera + { + // Size: + 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 7, 5, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b: 17: 1\n" /* tree */ + "c: 35: 0\n" /* wool */ + "d: 50: 4\n" /* torch */ + "e: 85: 0\n" /* fence */ + "f: 44: 8\n" /* step */ + "g: 43: 0\n" /* doubleslab */ + "h: 44: 0\n" /* step */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "maaaaam" + /* 2 */ "maaaaam" + /* 3 */ "maaaaam" + /* 4 */ "maaaaam" + /* 5 */ "maaaaam" + /* 6 */ "mmmmmmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".bcc.b." + /* 2 */ ".c...c." + /* 3 */ ".c...c." + /* 4 */ ".c...c." + /* 5 */ ".bcccb." + /* 6 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ ".....d." + /* 1 */ ".bee.b." + /* 2 */ ".c...c." + /* 3 */ ".e...e." + /* 4 */ ".c...c." + /* 5 */ ".beeeb." + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ ".fffff." + /* 1 */ "fbcccbf" + /* 2 */ "fc...cf" + /* 3 */ "fc...cf" + /* 4 */ "fc...cf" + /* 5 */ "fbcccbf" + /* 6 */ ".fffff." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "gh...hg" + /* 1 */ "hhhhhhh" + /* 2 */ ".hgggh." + /* 3 */ ".hgggh." + /* 4 */ ".hgggh." + /* 5 */ "hhhhhhh" + /* 6 */ "gh...hg" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "...h..." + /* 4 */ "......." + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseSmall + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseSmallDblWithDoor: + // The data has been exported from the gallery Plains, area index 113, ID 265, created by Aloe_vera + { + // Size: + 11, 6, 7, // SizeX = 11, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 5, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b: 17: 9\n" /* tree */ + "c: 17: 1\n" /* tree */ + "d: 35: 0\n" /* wool */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171:12\n" /* carpet */ + "g:135: 1\n" /* 135 */ + "h:126: 2\n" /* woodenslab */ + "i:135: 2\n" /* 135 */ + "j: 50: 4\n" /* torch */ + "k: 64:12\n" /* wooddoorblock */ + "l: 85: 0\n" /* fence */ + "m: 19: 0\n" /* sponge */ + "n: 44: 8\n" /* step */ + "o: 43: 0\n" /* doubleslab */ + "p: 44: 0\n" /* step */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaabaaaam" + /* 3 */ "maaaabaaaam" + /* 4 */ "maaaabaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".cdedcdddc." + /* 2 */ ".dfff.fffd." + /* 3 */ ".dgffdfhfd." + /* 4 */ ".diifdfffd." + /* 5 */ ".cdddcdddc." + /* 6 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ ".j...j...j." + /* 1 */ ".cdkdclllc." + /* 2 */ ".d.......l." + /* 3 */ ".l...l...l." + /* 4 */ ".d...l...l." + /* 5 */ ".clllclllc." + /* 6 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ ".nnnnnnnnn." + /* 1 */ "ncdddcdddcn" + /* 2 */ "nd...d...dn" + /* 3 */ "nd...d...dn" + /* 4 */ "nd...d...dn" + /* 5 */ "ncdddcdddcn" + /* 6 */ ".nnnnnnnnn." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "op.......po" + /* 1 */ "ppppppppppp" + /* 2 */ ".pooooooop." + /* 3 */ ".ponndnnop." + /* 4 */ ".pooooooop." + /* 5 */ "ppppppppppp" + /* 6 */ "op.......po" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "...ppppp..." + /* 4 */ "..........." + /* 5 */ "..........." + /* 6 */ "...........", + + // Connectors: + "-1: 3, 1, -1: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseSmallDblWithDoor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseSmallDouble: + // The data has been exported from the gallery Plains, area index 72, ID 135, created by Aloe_vera + { + // Size: + 11, 6, 7, // SizeX = 11, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 5, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b: 17: 1\n" /* tree */ + "c: 35: 0\n" /* wool */ + "d:171:12\n" /* carpet */ + "e:135: 1\n" /* 135 */ + "f:126: 2\n" /* woodenslab */ + "g:135: 2\n" /* 135 */ + "h: 50: 4\n" /* torch */ + "i: 85: 0\n" /* fence */ + "j: 44: 8\n" /* step */ + "k: 43: 0\n" /* doubleslab */ + "l: 44: 0\n" /* step */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".bcc.bcccb." + /* 2 */ ".cddd.dddc." + /* 3 */ ".ceddcdfdc." + /* 4 */ ".cggdcdddc." + /* 5 */ ".bcccbcccb." + /* 6 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ ".h...h...h." + /* 1 */ ".bii.biiib." + /* 2 */ ".c.......c." + /* 3 */ ".i...i...i." + /* 4 */ ".c...i...c." + /* 5 */ ".biiibiiib." + /* 6 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ ".jjjjjjjjj." + /* 1 */ "jbiiibiiibj" + /* 2 */ "jc.......cj" + /* 3 */ "jc...c...cj" + /* 4 */ "jc...c...cj" + /* 5 */ "jbcccbcccbj" + /* 6 */ ".jjjjjjjjj." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "kl...l...lk" + /* 1 */ "lllllllllll" + /* 2 */ ".lkkklkkkl." + /* 3 */ ".lkjklkkkl." + /* 4 */ ".lkkklkkkl." + /* 5 */ "lllllllllll" + /* 6 */ "kl...l...lk" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "...l...l..." + /* 4 */ "..........." + /* 5 */ "..........." + /* 6 */ "...........", + + // Connectors: + "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseSmallDouble + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseSmallWithDoor: + // The data has been exported from the gallery Plains, area index 112, ID 264, created by Aloe_vera + { + // Size: + 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 7, 5, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b: 17: 1\n" /* tree */ + "c: 35: 0\n" /* wool */ + "d: 64: 7\n" /* wooddoorblock */ + "e: 50: 4\n" /* torch */ + "f: 64:12\n" /* wooddoorblock */ + "g: 85: 0\n" /* fence */ + "h: 44: 8\n" /* step */ + "i: 43: 0\n" /* doubleslab */ + "j: 44: 0\n" /* step */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "maaaaam" + /* 2 */ "maaaaam" + /* 3 */ "maaaaam" + /* 4 */ "maaaaam" + /* 5 */ "maaaaam" + /* 6 */ "mmmmmmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".bcdcb." + /* 2 */ ".c...c." + /* 3 */ ".c...c." + /* 4 */ ".c...c." + /* 5 */ ".bcccb." + /* 6 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ ".....e." + /* 1 */ ".bcfcb." + /* 2 */ ".g...g." + /* 3 */ ".g...g." + /* 4 */ ".g...g." + /* 5 */ ".bgggb." + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ ".hhhhh." + /* 1 */ "hbcccbh" + /* 2 */ "hc...ch" + /* 3 */ "hc...ch" + /* 4 */ "hc...ch" + /* 5 */ "hbcccbh" + /* 6 */ ".hhhhh." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "ij...ji" + /* 1 */ "jjjjjjj" + /* 2 */ ".jiiij." + /* 3 */ ".jiiij." + /* 4 */ ".jiiij." + /* 5 */ "jjjjjjj" + /* 6 */ "ij...ji" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "...j..." + /* 4 */ "......." + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseSmallWithDoor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseWide: + // The data has been exported from the gallery Plains, area index 64, ID 121, created by STR_Warrior + { + // Size: + 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, 0, -1, // MinX, MinY, MinZ + 11, 5, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b: 17: 1\n" /* tree */ + "c: 35: 0\n" /* wool */ + "d:171: 0\n" /* carpet */ + "e:126: 1\n" /* woodenslab */ + "f: 64: 5\n" /* wooddoorblock */ + "g: 85: 0\n" /* fence */ + "h: 50: 1\n" /* torch */ + "i: 50: 2\n" /* torch */ + "j: 64:12\n" /* wooddoorblock */ + "k:126:11\n" /* woodenslab */ + "l: 17: 5\n" /* tree */ + "m: 19: 0\n" /* sponge */ + "n:126: 3\n" /* woodenslab */ + "o:125: 3\n" /* woodendoubleslab */ + "p: 5: 3\n" /* wood */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmaaaaaaamm" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "maaaaaaaaam" + /* 7 */ "maaaaaaaaam" + /* 8 */ "maaaaaaaaam" + /* 9 */ "mmaaaaaaamm" + /* 10 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..bcbcbcb.." + /* 2 */ ".b.d.....b." + /* 3 */ ".cded....c." + /* 4 */ ".bded....b." + /* 5 */ ".c.d.....c." + /* 6 */ ".b.......b." + /* 7 */ ".c.......c." + /* 8 */ ".b.......b." + /* 9 */ "..bcbfbcb.." + /* 10 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..bgbgbgb.." + /* 2 */ ".b.......b." + /* 3 */ ".g.......g." + /* 4 */ ".bh.....ib." + /* 5 */ ".g.......g." + /* 6 */ ".b.......b." + /* 7 */ ".g.......g." + /* 8 */ ".b.......b." + /* 9 */ "..bgbjbgb.." + /* 10 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...kkkkk..." + /* 1 */ "..bcbcbcb.." + /* 2 */ ".b.......b." + /* 3 */ "kc.......ck" + /* 4 */ "kb.......bk" + /* 5 */ "kc.......ck" + /* 6 */ "kb.......bk" + /* 7 */ "kc.......ck" + /* 8 */ ".b.......b." + /* 9 */ "..bcblbcb.." + /* 10 */ "...kkkkk..." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ ".kn.....nk." + /* 1 */ "konnnnnnnok" + /* 2 */ "nnnnnnnnnnn" + /* 3 */ ".nnpppppnn." + /* 4 */ ".nnpkkkpnn." + /* 5 */ ".nnpkkkpnn." + /* 6 */ ".nnpkkkpnn." + /* 7 */ ".nnpppppnn." + /* 8 */ "nnnnnnnnnnn" + /* 9 */ "kknnnnnnnok" + /* 10 */ ".kn.....nk." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "n.........n" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "....nnn...." + /* 5 */ "....non...." + /* 6 */ "....nnn...." + /* 7 */ "..........." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "n.........n", + + // Connectors: + "-1: 5, 1, 10: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseWide + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseWithGarden: + // The data has been exported from the gallery Plains, area index 67, ID 130, created by Aloe_vera + { + // Size: + 16, 9, 16, // SizeX = 16, SizeY = 9, SizeZ = 16 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 16, 8, 16, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 5: 2\n" /* wood */ + "c: 2: 0\n" /* grass */ + "d:113: 0\n" /* netherbrickfence */ + "e: 17: 1\n" /* tree */ + "f: 35: 0\n" /* wool */ + "g:126: 2\n" /* woodenslab */ + "h: 31: 2\n" /* tallgrass */ + "i:125: 2\n" /* woodendoubleslab */ + "j: 38: 3\n" /* rose */ + "k: 38: 2\n" /* rose */ + "l: 38: 1\n" /* rose */ + "m: 19: 0\n" /* sponge */ + "n: 17: 2\n" /* tree */ + "o: 50: 4\n" /* torch */ + "p: 85: 0\n" /* fence */ + "q:140: 0\n" /* flowerpotblock */ + "r: 50: 3\n" /* torch */ + "s: 44: 8\n" /* step */ + "t: 50: 1\n" /* torch */ + "u: 50: 2\n" /* torch */ + "v: 43: 0\n" /* doubleslab */ + "w: 44: 0\n" /* step */ + "x: 18:10\n" /* leaves */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmaammmmm" + /* 1 */ "aabbbbbbbbbbaaam" + /* 2 */ "aabbbbbbbbbbaaam" + /* 3 */ "aabbbbbbbbbbaaam" + /* 4 */ "aabbbbbbbbbbaaam" + /* 5 */ "aabbbbbbbbbbaaam" + /* 6 */ "aabbbbbbbbbbaaam" + /* 7 */ "aabbbbbbbbbbaaam" + /* 8 */ "aabbbbbbbbbbaaam" + /* 9 */ "aabbbbbbbbbbaaam" + /* 10 */ "aaaaaaaaaaaaaaam" + /* 11 */ "aaaaaaaaaaaaaaam" + /* 12 */ "aaaaaaaaaaaaaaam" + /* 13 */ "aaaaaaaaaaaaaaam" + /* 14 */ "aaaaaaaaaaaaaaam" + /* 15 */ "mmmmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmccmmmmm" + /* 1 */ "ccbbbbbbbbbbcccm" + /* 2 */ "ccbbbbbbbbbbcccm" + /* 3 */ "ccbbbbbbbbbbcccm" + /* 4 */ "ccbbbbbbbbbbcccm" + /* 5 */ "ccbbbbbbbbbbcccm" + /* 6 */ "ccbbbbbbbbbbcccm" + /* 7 */ "ccbbbbbbbbbbcccm" + /* 8 */ "ccbbbbbbbbbbcccm" + /* 9 */ "ccbbbbbbbbbbcccm" + /* 10 */ "cccccccccccccccm" + /* 11 */ "cccccccccccccccm" + /* 12 */ "cccccccccccccccm" + /* 13 */ "cccccccccccccacm" + /* 14 */ "cccccccccccccccm" + /* 15 */ "mmmmmmmmmmmmmmmm" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "ddeffeffe..eddd." + /* 2 */ "d.fbbgggg..f..d." + /* 3 */ "d.fbgggggggf.hd." + /* 4 */ "d.fbgggggggf..d." + /* 5 */ "d.eggggggggehhd." + /* 6 */ "d.fgiiggiigf.hd." + /* 7 */ "d.fgiiggiigf..d." + /* 8 */ "d.fggggggggf..d." + /* 9 */ "d.efffeefffe.hd." + /* 10 */ "d.............d." + /* 11 */ "djhhk.jhh..hh.d." + /* 12 */ "d.jlk.hj.h....d." + /* 13 */ "d..jh.hh..h..nd." + /* 14 */ "ddddddddddddddd." + /* 15 */ "................" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "........o..o...." + /* 1 */ "..eppeffe..e...." + /* 2 */ "..pqq......p...." + /* 3 */ "..pq.......p...." + /* 4 */ "..pq.......p...." + /* 5 */ "..e........e...." + /* 6 */ "..p........p...." + /* 7 */ "..p........p...." + /* 8 */ "..p........p...." + /* 9 */ "..epppeepppe...." + /* 10 */ "......rr........" + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ ".............n.." + /* 14 */ "................" + /* 15 */ "................" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "..ssssssssss...." + /* 1 */ ".seffeffeffes..." + /* 2 */ ".sf..r.....fs..." + /* 3 */ ".sf........fs..." + /* 4 */ ".sf........fs..." + /* 5 */ ".set......ues..." + /* 6 */ ".sf........fs..." + /* 7 */ ".sf........fs..." + /* 8 */ ".sf........fs..." + /* 9 */ ".sefffeefffes..." + /* 10 */ "..ssssssssss...." + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ ".............n.." + /* 14 */ "................" + /* 15 */ "................" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ ".vw........wv..." + /* 1 */ ".wwwwwwwwwwww..." + /* 2 */ "..wvvvvvvvvw...." + /* 3 */ "..wvvvvvvvvw...." + /* 4 */ "..wvvvvvvvvw...." + /* 5 */ "..wvvvvvvvvw...." + /* 6 */ "..wvvvvvvvvw...." + /* 7 */ "..wvvvvvvvvw...." + /* 8 */ "..wvvvvvvvvw...." + /* 9 */ ".wwwwwwwwwwww..." + /* 10 */ ".vw........wv..." + /* 11 */ "............xxx." + /* 12 */ "...........xxxxx" + /* 13 */ "...........xxnxx" + /* 14 */ "...........xxxxx" + /* 15 */ "............xxx." + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "....wwwwww......" + /* 4 */ "....wvvvvw......" + /* 5 */ "....wvvvvw......" + /* 6 */ "....wvvvvw......" + /* 7 */ "....wwwwww......" + /* 8 */ "................" + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "............xxx." + /* 12 */ "...........xxxxx" + /* 13 */ "...........xxnxx" + /* 14 */ "...........xxxxx" + /* 15 */ "............xxx." + + // Level 7 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "................" + /* 5 */ "......ww........" + /* 6 */ "................" + /* 7 */ "................" + /* 8 */ "................" + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ "............xxx." + /* 13 */ "............xnx." + /* 14 */ "............xx.." + /* 15 */ "................" + + // Level 8 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "................" + /* 5 */ "................" + /* 6 */ "................" + /* 7 */ "................" + /* 8 */ "................" + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ ".............x.." + /* 13 */ "............xxx." + /* 14 */ ".............x.." + /* 15 */ "................", + + // Connectors: + "-1: 9, 2, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseWithGarden + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseWithSakura1: + // The data has been exported from the gallery Plains, area index 75, ID 141, created by Aloe_vera + { + // Size: + 13, 7, 15, // SizeX = 13, SizeY = 7, SizeZ = 15 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 13, 6, 15, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 2: 0\n" /* grass */ + "c: 17: 5\n" /* tree */ + "d: 5: 2\n" /* wood */ + "e: 17: 9\n" /* tree */ + "f:113: 0\n" /* netherbrickfence */ + "g: 17: 1\n" /* tree */ + "h: 35: 0\n" /* wool */ + "i: 31: 2\n" /* tallgrass */ + "j: 54: 2\n" /* chest */ + "k: 38: 6\n" /* rose */ + "l: 38: 2\n" /* rose */ + "m: 19: 0\n" /* sponge */ + "n: 50: 4\n" /* torch */ + "o: 85: 0\n" /* fence */ + "p: 44: 8\n" /* step */ + "q: 35: 6\n" /* wool */ + "r: 43: 0\n" /* doubleslab */ + "s: 44: 0\n" /* step */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "bbbbbbbbbbbbb" + /* 1 */ "bbbbbbbbbbbbb" + /* 2 */ "bbbaccdabbbbb" + /* 3 */ "bbbedddebbbbb" + /* 4 */ "bbbedddebbbbb" + /* 5 */ "bbbedddebbbbb" + /* 6 */ "bbbacccabbbbb" + /* 7 */ "bbbbbbbbbbbbb" + /* 8 */ "bbbbbbbbbbbbb" + /* 9 */ "bbbbbbbbbbbbb" + /* 10 */ "bbbbbbbbbbabb" + /* 11 */ "bbbbbbbbbbbbb" + /* 12 */ "bbbbbbbbbbbbb" + /* 13 */ "bbbbbbbbbbbbb" + /* 14 */ "bbbbbbbbbbbbb" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ffff...ffffff" + /* 1 */ "f...........f" + /* 2 */ "f..ghh.g..i.f" + /* 3 */ "f..h...h..i.f" + /* 4 */ "f..h...h....f" + /* 5 */ "fi.h..jh..i.f" + /* 6 */ "f..ghhhg....f" + /* 7 */ "f.........i.f" + /* 8 */ "fii.........f" + /* 9 */ "f.k..k.i....f" + /* 10 */ "fl.i..i...g.f" + /* 11 */ "f.i..i.k....f" + /* 12 */ "f.l.k.......f" + /* 13 */ "f.....l.....f" + /* 14 */ "fffffffffffff" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".......n....." + /* 2 */ "...goo.g....." + /* 3 */ "...h...h....." + /* 4 */ "...o...o....." + /* 5 */ "...h...h....." + /* 6 */ "...gooog....." + /* 7 */ "............." + /* 8 */ "............." + /* 9 */ "............." + /* 10 */ "..........g.." + /* 11 */ "............." + /* 12 */ "............." + /* 13 */ "............." + /* 14 */ "............." + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "...ppppp....." + /* 2 */ "..pghhhgp...." + /* 3 */ "..ph...hp...." + /* 4 */ "..ph...hp...." + /* 5 */ "..ph...hp...." + /* 6 */ "..pghhhgp...." + /* 7 */ "...ppppp....." + /* 8 */ "............." + /* 9 */ "..........q.." + /* 10 */ ".........qgq." + /* 11 */ "..........q.." + /* 12 */ "............." + /* 13 */ "............." + /* 14 */ "............." + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "..rs...sr...." + /* 2 */ "..sssssss...." + /* 3 */ "...srrrs....." + /* 4 */ "...srrrs....." + /* 5 */ "...srrrs....." + /* 6 */ "..sssssss...." + /* 7 */ "..rs...sr...." + /* 8 */ "............." + /* 9 */ ".........qqq." + /* 10 */ ".........qqq." + /* 11 */ ".........qqq." + /* 12 */ "............." + /* 13 */ "............." + /* 14 */ "............." + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ ".....s......." + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "............." + /* 9 */ "............." + /* 10 */ "..........q.." + /* 11 */ "............." + /* 12 */ "............." + /* 13 */ "............." + /* 14 */ ".............", + + // Connectors: + "-1: 5, 2, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseWithSakura1 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseWithSpa: + // The data has been exported from the gallery Plains, area index 73, ID 139, created by Aloe_vera + { + // Size: + 16, 8, 14, // SizeX = 16, SizeY = 8, SizeZ = 14 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 15, 7, 13, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b: 3: 0\n" /* dirt */ + "c: 2: 0\n" /* grass */ + "d: 8: 0\n" /* water */ + "e:135: 3\n" /* 135 */ + "f:135: 1\n" /* 135 */ + "g:113: 0\n" /* netherbrickfence */ + "h: 17: 1\n" /* tree */ + "i: 35: 0\n" /* wool */ + "j:171:12\n" /* carpet */ + "k: 64: 6\n" /* wooddoorblock */ + "l:126: 2\n" /* woodenslab */ + "m: 19: 0\n" /* sponge */ + "n:135: 2\n" /* 135 */ + "o: 64: 7\n" /* wooddoorblock */ + "p: 50: 4\n" /* torch */ + "q: 85: 0\n" /* fence */ + "r: 64:12\n" /* wooddoorblock */ + "s: 50: 3\n" /* torch */ + "t: 44: 8\n" /* step */ + "u: 43: 0\n" /* doubleslab */ + "v: 44: 0\n" /* step */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".aaaaaaaaaaaaaa." + /* 2 */ ".aaaaaaaaaaaaaa." + /* 3 */ ".aaaaaaaaaaaaaa." + /* 4 */ ".aaaaaaaaaaaaaa." + /* 5 */ ".aaaaaaaaaaaaaa." + /* 6 */ ".aaaaaaaaaaaaaa." + /* 7 */ ".aaaaaabbbbbbbbb" + /* 8 */ ".aaaaaabbbbbbbbb" + /* 9 */ ".aaaaaabbbbbbbbb" + /* 10 */ ".aaaaaabbbbbbbbb" + /* 11 */ ".aaaaaabbbbbbbbb" + /* 12 */ ".aaaaaabbbbbbbbb" + /* 13 */ ".......bbbbbbbbb" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmmmmm" + /* 1 */ "maaaaaaaaaaaaaam" + /* 2 */ "maaaaaaaaaaaaaam" + /* 3 */ "maaaaaaaaaaaaaam" + /* 4 */ "maaaaaaaaaaaaaam" + /* 5 */ "maaaaaaaaaaaaaam" + /* 6 */ "maaaaaaaaaaaaaam" + /* 7 */ "maaaaaaaaaaccccc" + /* 8 */ "maaaaaaacccccccc" + /* 9 */ "maaaaaaacccccccc" + /* 10 */ "maaaaaaacccccccc" + /* 11 */ "maaaaaaccccccccc" + /* 12 */ "maaaaaaccccccccc" + /* 13 */ "mmmmmmmccccccccc" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".aaaaaaaaaaaaaa." + /* 2 */ ".aaaaaaaaaaaaaa." + /* 3 */ ".aaaaaaaaaaaaaa." + /* 4 */ ".aaaaaaaaaaaaaa." + /* 5 */ ".aaaaaaaaaaaaaa." + /* 6 */ ".aaddaaaaaaaaaa." + /* 7 */ ".aaddaaeeef....." + /* 8 */ ".aaddaaf........" + /* 9 */ ".aaddaaf........" + /* 10 */ ".aaddaae........" + /* 11 */ ".aaddaa........." + /* 12 */ ".aaaaaa........." + /* 13 */ "................" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".ggggghiiihiiih." + /* 2 */ ".geee.ijjjjjjji." + /* 3 */ ".gf...kjjjijlji." + /* 4 */ ".gf...innjijjji." + /* 5 */ ".g....hiiohiiih." + /* 6 */ ".g....g........." + /* 7 */ ".g.............." + /* 8 */ ".g.............." + /* 9 */ ".g.............." + /* 10 */ ".g....g........." + /* 11 */ ".g....g........." + /* 12 */ ".gggggg........." + /* 13 */ "................" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "......p...p...p." + /* 1 */ ".g....hqqqhqqqh." + /* 2 */ "......i.......i." + /* 3 */ "......r...q...q." + /* 4 */ "......i...q...i." + /* 5 */ "......hqqrhqqqh." + /* 6 */ "......g...s....." + /* 7 */ "................" + /* 8 */ "................" + /* 9 */ "................" + /* 10 */ "................" + /* 11 */ "................" + /* 12 */ ".g....g........." + /* 13 */ "................" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ ".tttttttttttttt." + /* 1 */ "tggggghqqqhqqqht" + /* 2 */ "tg....i.......it" + /* 3 */ "tg....i...i...it" + /* 4 */ "tg....i...i...it" + /* 5 */ "tg....hiiihiiiht" + /* 6 */ "tg....gtttttttt." + /* 7 */ "tg....gt........" + /* 8 */ "tg....gt........" + /* 9 */ "tg....gt........" + /* 10 */ "tg....gt........" + /* 11 */ "tg....gt........" + /* 12 */ "tggggggt........" + /* 13 */ ".tttttt........." + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "uv............vu" + /* 1 */ "vvvvvvvvvvvvvvvv" + /* 2 */ ".vuuuuuuuuuuuuv." + /* 3 */ ".vuuuuuutuuuuuv." + /* 4 */ ".vuuuuuuuuuuuuv." + /* 5 */ ".vuuuuvvvvvvvvvv" + /* 6 */ ".vuuuuv.......vu" + /* 7 */ ".vuuuuv........." + /* 8 */ ".vuuuuv........." + /* 9 */ ".vuuuuv........." + /* 10 */ ".vuuuuv........." + /* 11 */ ".vuuuuv........." + /* 12 */ "vvvvvvvv........" + /* 13 */ "uv....vu........" + + // Level 7 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "...vvvvvvvvvv..." + /* 4 */ "...vv..........." + /* 5 */ "...vv..........." + /* 6 */ "...vv..........." + /* 7 */ "...vv..........." + /* 8 */ "...vv..........." + /* 9 */ "...vv..........." + /* 10 */ "...vv..........." + /* 11 */ "................" + /* 12 */ "................" + /* 13 */ "................", + + // Connectors: + "", + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseWithSpa + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MediumSakuraTree: + // The data has been exported from the gallery Plains, area index 146, ID 490, created by STR_Warrior + { + // Size: + 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 9, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 2: 0\n" /* grass */ + "c: 31: 1\n" /* tallgrass */ + "d: 38: 7\n" /* rose */ + "e: 17: 1\n" /* tree */ + "f: 38: 0\n" /* rose */ + "g: 38: 8\n" /* rose */ + "h: 38: 5\n" /* rose */ + "i: 35: 6\n" /* wool */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "bbbbbbb" + /* 1 */ "bbbbbbb" + /* 2 */ "bbbbbbb" + /* 3 */ "bbbabbb" + /* 4 */ "bbbbbbb" + /* 5 */ "bbbbbbb" + /* 6 */ "bbbbbbb" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..c.c.." + /* 2 */ ".dccdc." + /* 3 */ "..cefc." + /* 4 */ ".ccfgh." + /* 5 */ "..ccc.." + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "...e..." + /* 4 */ "......." + /* 5 */ "......." + /* 6 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..i...." + /* 2 */ "......." + /* 3 */ "...e.i." + /* 4 */ ".i....." + /* 5 */ "......." + /* 6 */ "......." + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..i...." + /* 2 */ "...i..." + /* 3 */ "..ieii." + /* 4 */ ".i.ii.." + /* 5 */ "...i..." + /* 6 */ "......." + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..ii..." + /* 2 */ "..iii.." + /* 3 */ ".iieii." + /* 4 */ ".iiii.." + /* 5 */ "..iii.." + /* 6 */ "......." + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "..iii.." + /* 2 */ ".iiiii." + /* 3 */ ".iieii." + /* 4 */ ".iiiii." + /* 5 */ "..iii.." + /* 6 */ "......." + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "...i..." + /* 2 */ "..iiii." + /* 3 */ ".iiiii." + /* 4 */ "..iii.." + /* 5 */ "...i..." + /* 6 */ "......." + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "...i..." + /* 3 */ "..iii.." + /* 4 */ "...i..." + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "-1: 3, 2, 0: 2\n" /* Type -1, direction Z- */ + "3: 6, 2, 3: 5\n" /* Type 3, direction X+ */ + "-3: 0, 2, 3: 4\n" /* Type -3, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // MediumSakuraTree + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Restaurant: + // The data has been exported from the gallery Plains, area index 61, ID 117, created by Aloe_vera + { + // Size: + 15, 10, 15, // SizeX = 15, SizeY = 10, SizeZ = 15 + + // Hitbox (relative to bounding box): + -1, 0, -1, // MinX, MinY, MinZ + 14, 9, 15, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b:135: 0\n" /* 135 */ + "c:135: 2\n" /* 135 */ + "d:135: 1\n" /* 135 */ + "e: 17: 9\n" /* tree */ + "f:135: 3\n" /* 135 */ + "g: 85: 0\n" /* fence */ + "h: 17: 1\n" /* tree */ + "i:171: 0\n" /* carpet */ + "j:171:12\n" /* carpet */ + "k:126: 1\n" /* woodenslab */ + "l: 50: 5\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 35: 0\n" /* wool */ + "o: 50: 3\n" /* torch */ + "p: 50: 1\n" /* torch */ + "q: 50: 4\n" /* torch */ + "r: 35:14\n" /* wool */ + "s: 44: 8\n" /* step */ + "t: 43: 0\n" /* doubleslab */ + "u: 44: 0\n" /* step */ + "v: 17: 5\n" /* tree */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmaaaaaaammmm" + /* 1 */ "maaaaaaaaaaaaam" + /* 2 */ "maaaaaaaaaaaaam" + /* 3 */ "maaaaaaaaaaaaam" + /* 4 */ "aaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaa" + /* 11 */ "maaaaaaaaaaaaam" + /* 12 */ "maaaaaaaaaaaaam" + /* 13 */ "maaaaaaaaaaaaam" + /* 14 */ "mmmmaaaaaaammmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "....bcccccd...." + /* 1 */ ".aaaaaaaaaaaaa." + /* 2 */ ".aaaaaaaaaaaaa." + /* 3 */ ".aaaaaaaaaaaaa." + /* 4 */ "caaaaaaaaaaaaac" + /* 5 */ "baaaaaaaaaaaaad" + /* 6 */ "baaaaaaaaaaaaad" + /* 7 */ "baaaaaaaaaaeaad" + /* 8 */ "baaaaaaaaaaaaad" + /* 9 */ "baaaaaaaaaaaaad" + /* 10 */ "faaaaaaaaaaaaaf" + /* 11 */ ".aaaaaaaaaaaaa." + /* 12 */ ".aaaaaaaaaaaaa." + /* 13 */ ".aaaaaaaaaaaaa." + /* 14 */ "....bfffffd...." + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".gggg.....gggg." + /* 2 */ ".g...........g." + /* 3 */ ".g.hhhhhhhhh.g." + /* 4 */ ".g.hiiijiiih.g." + /* 5 */ "...hikijikih..." + /* 6 */ "...hiiijiiihg.." + /* 7 */ "...hjjjjjjj...." + /* 8 */ "...hiiijiiihg.." + /* 9 */ "...hikijikih..." + /* 10 */ ".g.hiiijiiih.g." + /* 11 */ ".g.hhhhhhhhh.g." + /* 12 */ ".g...........g." + /* 13 */ ".gggg.....gggg." + /* 14 */ "..............." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".l..g.....g..l." + /* 2 */ "..............." + /* 3 */ "...hnnnhnnnh..." + /* 4 */ ".g.n.......n.g." + /* 5 */ "...n.......n..." + /* 6 */ "...n.......hl.." + /* 7 */ "...h..........." + /* 8 */ "...n.......hl.." + /* 9 */ "...n.......n..." + /* 10 */ ".g.n.......n.g." + /* 11 */ "...hnnnhnnnh..." + /* 12 */ "..............." + /* 13 */ ".l..g.....g..l." + /* 14 */ "..............." + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "....g.....g...." + /* 2 */ "..............." + /* 3 */ "...hn.nhn.nh..." + /* 4 */ ".g.n...o...n.g." + /* 5 */ "...n.......n..." + /* 6 */ "...n.......h..." + /* 7 */ "...hp......e..." + /* 8 */ "...n.......h..." + /* 9 */ "...n.......n..." + /* 10 */ ".g.n...q...n.g." + /* 11 */ "...hn.nhn.nh..." + /* 12 */ "..............." + /* 13 */ "....g.....g...." + /* 14 */ "..............." + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "....g.....g...." + /* 2 */ "....ggggggg...." + /* 3 */ "...hnnnhnnnh..." + /* 4 */ ".ggn.......ngg." + /* 5 */ "..gn.......ng.." + /* 6 */ "..gn.......hg.." + /* 7 */ "..gh..r.r..ng.." + /* 8 */ "..gn.......hg.." + /* 9 */ "..gn.......ng.." + /* 10 */ ".ggn.......ngg." + /* 11 */ "...hnnnhnnnh..." + /* 12 */ "....ggggggg...." + /* 13 */ "....g.....g...." + /* 14 */ "..............." + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "...stuuuuuts..." + /* 2 */ "..sttttttttts.." + /* 3 */ ".sthvvvhvvvhts." + /* 4 */ ".tte.......ett." + /* 5 */ ".ute.......etu." + /* 6 */ ".ute.......htu." + /* 7 */ ".uth..g.g..etu." + /* 8 */ ".ute.......htu." + /* 9 */ ".ute.......etu." + /* 10 */ ".tte.......ett." + /* 11 */ ".sthvvvhvvvhts." + /* 12 */ "..sttttttttts.." + /* 13 */ "...stuuuuuts..." + /* 14 */ "..............." + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".stu.......uts." + /* 2 */ ".tu.........ut." + /* 3 */ ".u.uuuuuuuuu.u." + /* 4 */ "...utttttttu..." + /* 5 */ "...utttttttu..." + /* 6 */ "...utttttttu..." + /* 7 */ "...utttttttu..." + /* 8 */ "...utttttttu..." + /* 9 */ "...utttttttu..." + /* 10 */ "...utttttttu..." + /* 11 */ ".u.uuuuuuuuu.u." + /* 12 */ ".tu.........ut." + /* 13 */ ".stu.......uts." + /* 14 */ "..............." + + // Level 8 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".u...........u." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ ".....uuuuu....." + /* 6 */ ".....utttu....." + /* 7 */ ".....utttu....." + /* 8 */ ".....utttu....." + /* 9 */ ".....uuuuu....." + /* 10 */ "..............." + /* 11 */ "..............." + /* 12 */ "..............." + /* 13 */ ".u...........u." + /* 14 */ "..............." + + // Level 9 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ ".......u......." + /* 8 */ "..............." + /* 9 */ "..............." + /* 10 */ "..............." + /* 11 */ "..............." + /* 12 */ "..............." + /* 13 */ "..............." + /* 14 */ "...............", + + // Connectors: + "-1: 14, 1, 7: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Restaurant + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SakuraDouble: + // The data has been exported from the gallery Plains, area index 76, ID 142, created by Aloe_vera + { + // Size: + 12, 8, 6, // SizeX = 12, SizeY = 8, SizeZ = 6 + + // Hitbox (relative to bounding box): + -1, 0, -1, // MinX, MinY, MinZ + 12, 7, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 2: 0\n" /* grass */ + "c: 17: 1\n" /* tree */ + "d: 35: 6\n" /* wool */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaa" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "bbbbbbbbbbbb" + /* 1 */ "bbbbbbbbbbbb" + /* 2 */ "bbabbbbbbbbb" + /* 3 */ "bbbbbbbbbabb" + /* 4 */ "bbbbbbbbbbbb" + /* 5 */ "bbbbbbbbbbbb" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "..c........." + /* 3 */ ".........c.." + /* 4 */ "............" + /* 5 */ "............" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "..c........." + /* 3 */ ".........c.." + /* 4 */ "............" + /* 5 */ "............" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "..d........." + /* 1 */ "ddddd......." + /* 2 */ "ddcdd...ddd." + /* 3 */ "ddddd...dcd." + /* 4 */ "..d.....ddd." + /* 5 */ "............" + + // Level 5 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ ".ddd........" + /* 1 */ ".ddd....ddd." + /* 2 */ "ddddd..ddddd" + /* 3 */ ".ddd...ddcdd" + /* 4 */ ".ddd...ddddd" + /* 5 */ "........ddd." + + // Level 6 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "..d......d.." + /* 2 */ ".ddd....ddd." + /* 3 */ "..d....ddddd" + /* 4 */ "........ddd." + /* 5 */ ".........d.." + + // Level 7 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ ".........d.." + /* 4 */ "............" + /* 5 */ "............", + + // Connectors: + "-1: -1, 2, 2: 4\n" /* Type -1, direction X- */ + "3: 5, 2, 6: 3\n" /* Type 3, direction Z+ */ + "-3: 6, 2, -1: 2\n" /* Type -3, direction Z- */ + "-3: 12, 2, 2: 5\n" /* Type -3, direction X+ */ + "3: 12, 2, 2: 5\n" /* Type 3, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // SakuraDouble + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SakuraSmall: + // The data has been exported from the gallery Plains, area index 145, ID 489, created by Aloe_vera + { + // Size: + 5, 7, 5, // SizeX = 5, SizeY = 7, SizeZ = 5 + + // Hitbox (relative to bounding box): + -1, 0, -1, // MinX, MinY, MinZ + 5, 6, 5, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 2: 0\n" /* grass */ + "c: 17: 1\n" /* tree */ + "d: 35: 6\n" /* wool */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bbbbb" + /* 2 */ "bbabb" + /* 3 */ "bbbbb" + /* 4 */ "bbbbb" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "..c.." + /* 3 */ "....." + /* 4 */ "....." + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "..c.." + /* 3 */ "....." + /* 4 */ "....." + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "..d.." + /* 1 */ "ddddd" + /* 2 */ "ddcdd" + /* 3 */ "ddddd" + /* 4 */ "..d.." + + // Level 5 + /* z\x* 01234 */ + /* 0 */ ".ddd." + /* 1 */ ".ddd." + /* 2 */ "ddddd" + /* 3 */ ".ddd." + /* 4 */ ".ddd." + + // Level 6 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "..d.." + /* 2 */ ".ddd." + /* 3 */ "..d.." + /* 4 */ ".....", + + // Connectors: + "-1: 2, 2, -1: 2\n" /* Type -1, direction Z- */ + "3: 5, 2, 2: 5\n" /* Type 3, direction X+ */ + "-3: -1, 2, 2: 4\n" /* Type -3, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // SakuraSmall +}; // g_JapaneseVillagePrefabs + + + + + + +const cPrefab::sDef g_JapaneseVillageStartingPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HighTemple: + // The data has been exported from the gallery Plains, area index 70, ID 133, created by Aloe_vera + { + // Size: + 11, 19, 11, // SizeX = 11, SizeY = 19, SizeZ = 11 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 18, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 2\n" /* wood */ + "b:135: 0\n" /* 135 */ + "c:135: 2\n" /* 135 */ + "d:135: 1\n" /* 135 */ + "e: 17: 9\n" /* tree */ + "f:135: 3\n" /* 135 */ + "g: 85: 0\n" /* fence */ + "h: 17: 1\n" /* tree */ + "i:171: 0\n" /* carpet */ + "j: 50: 5\n" /* torch */ + "k: 35: 0\n" /* wool */ + "l: 17: 5\n" /* tree */ + "m: 19: 0\n" /* sponge */ + "n:124: 0\n" /* redstonelampon */ + "o: 69: 9\n" /* lever */ + "p: 44: 8\n" /* step */ + "q: 43: 0\n" /* doubleslab */ + "r: 44: 0\n" /* step */ + "s: 50: 4\n" /* torch */ + "t: 50: 1\n" /* torch */ + "u: 50: 3\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmaaaaammm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "aaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaa" + /* 8 */ "maaaaaaaaam" + /* 9 */ "maaaaaaaaam" + /* 10 */ "mmmaaaaammm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "...bcccd..." + /* 1 */ ".aaaaaaaaa." + /* 2 */ ".aaaaaaaaa." + /* 3 */ "caaaaaaaaac" + /* 4 */ "baaaaaaaaad" + /* 5 */ "baaeaaaaaad" + /* 6 */ "baaaaaaaaad" + /* 7 */ "faaaaaaaaaf" + /* 8 */ ".aaaaaaaaa." + /* 9 */ ".aaaaaaaaa." + /* 10 */ "...bfffd..." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ggg...ggg." + /* 2 */ ".g.......g." + /* 3 */ ".g.hhhhh.g." + /* 4 */ "...hiiih..." + /* 5 */ "....iiih..." + /* 6 */ "...hiiih..." + /* 7 */ ".g.hhhhh.g." + /* 8 */ ".g.......g." + /* 9 */ ".ggg...ggg." + /* 10 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".j.g...g.j." + /* 2 */ "..........." + /* 3 */ ".g.kkhkk.g." + /* 4 */ "...h...k..." + /* 5 */ ".......h..." + /* 6 */ "...h...k..." + /* 7 */ ".g.kkhkk.g." + /* 8 */ "..........." + /* 9 */ ".j.g...g.j." + /* 10 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "...g...g..." + /* 2 */ "..........." + /* 3 */ ".g.kkhkk.g." + /* 4 */ "...h...k..." + /* 5 */ "...k...h..." + /* 6 */ "...h...k..." + /* 7 */ ".g.kkhkk.g." + /* 8 */ "..........." + /* 9 */ "...g...g..." + /* 10 */ "..........." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "...g...g..." + /* 2 */ "...ggggg..." + /* 3 */ ".gghlhlhgg." + /* 4 */ "..ge...eg.." + /* 5 */ "..ge.nohg.." + /* 6 */ "..ge...eg.." + /* 7 */ ".gghlhlhgg." + /* 8 */ "...ggggg..." + /* 9 */ "...g...g..." + /* 10 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..pqrrrqp.." + /* 2 */ ".pqqqqqqqp." + /* 3 */ ".qqhkkkhqq." + /* 4 */ ".rqkhhhkqr." + /* 5 */ ".rqkhhhkqr." + /* 6 */ ".rqkhhhkqr." + /* 7 */ ".qqhkkkhqq." + /* 8 */ ".pqqqqqqqp." + /* 9 */ "..pqrrrqp.." + /* 10 */ "..........." + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".qr.....rq." + /* 2 */ ".........r." + /* 3 */ "...hhhhh..." + /* 4 */ "...hiiih..." + /* 5 */ "....iiih..." + /* 6 */ "...hiiih..." + /* 7 */ "...hhhhh..." + /* 8 */ ".r.......r." + /* 9 */ ".qr.....rq." + /* 10 */ "..........." + + // Level 8 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "...kkhkk..." + /* 4 */ "...h...k..." + /* 5 */ ".......h..." + /* 6 */ "...h...k..." + /* 7 */ "...kkhkk..." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "..........." + + // Level 9 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ ".....s....." + /* 3 */ "...kkhkk..." + /* 4 */ "...h...k..." + /* 5 */ "...k...ht.." + /* 6 */ "...h...k..." + /* 7 */ "...kkhkk..." + /* 8 */ ".....u....." + /* 9 */ "..........." + /* 10 */ "..........." + + // Level 10 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "...ggggg..." + /* 3 */ "..ghlhlhg.." + /* 4 */ "..ge...eg.." + /* 5 */ "..ge.nohg.." + /* 6 */ "..ge...eg.." + /* 7 */ "..ghlhlhg.." + /* 8 */ "...ggggg..." + /* 9 */ "..........." + /* 10 */ "..........." + + // Level 11 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..prrrrrp.." + /* 2 */ ".pqqqqqqqp." + /* 3 */ ".qqhkkkhqq." + /* 4 */ ".rqkhhhkqr." + /* 5 */ ".rqkhhhkqr." + /* 6 */ ".rqkhhhkqr." + /* 7 */ ".qqhkkkhqr." + /* 8 */ ".pqqqqqqqp." + /* 9 */ "..pqrrrqp.." + /* 10 */ "..........." + + // Level 12 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".qr.....rq." + /* 2 */ ".r.......r." + /* 3 */ "...hhhhh..." + /* 4 */ "...hiiih..." + /* 5 */ "....iiih..." + /* 6 */ "...hiiih..." + /* 7 */ "...hhhhh..." + /* 8 */ ".r.......r." + /* 9 */ ".qr.....rq." + /* 10 */ "..........." + + // Level 13 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "...kkhkk..." + /* 4 */ "...h...k..." + /* 5 */ ".......h..." + /* 6 */ "...h...k..." + /* 7 */ "...kkhkk..." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "..........." + + // Level 14 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ ".....s....." + /* 3 */ "...kkhkk..." + /* 4 */ "...h...k..." + /* 5 */ "...k...ht.." + /* 6 */ "...h...k..." + /* 7 */ "...kkhkk..." + /* 8 */ ".....u....." + /* 9 */ "..........." + /* 10 */ "..........." + + // Level 15 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "...ggggg..." + /* 3 */ "..ghlhlhg.." + /* 4 */ "..ge...eg.." + /* 5 */ "..ge.nohg.." + /* 6 */ "..ge...eg.." + /* 7 */ "..ghlhlhg.." + /* 8 */ "...ggggg..." + /* 9 */ "..........." + /* 10 */ "..........." + + // Level 16 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..pqrrrqp.." + /* 2 */ ".pqqqqqqqp." + /* 3 */ ".qqrrrrrqq." + /* 4 */ ".rqrrrrrqr." + /* 5 */ ".rqrrrrrqr." + /* 6 */ ".rqrrrrrqr." + /* 7 */ ".qqrrrrrqq." + /* 8 */ ".pqqqqqqqp." + /* 9 */ "..pqrrrqp.." + /* 10 */ "..........." + + // Level 17 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".qr.....rq." + /* 2 */ ".rr.....rr." + /* 3 */ "...rrrrr..." + /* 4 */ "...rqqqr..." + /* 5 */ "...rqqqr..." + /* 6 */ "...rqqqr..." + /* 7 */ "...rrrrr..." + /* 8 */ ".rr.....rr." + /* 9 */ ".qr.....rq." + /* 10 */ "..........." + + // Level 18 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "..........." + /* 5 */ ".....r....." + /* 6 */ "..........." + /* 7 */ "..........." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "...........", + + // Connectors: + "2: 0, 1, 5: 4\n" /* Type 2, direction X- */ + "2: 5, 1, 0: 2\n" /* Type 2, direction Z- */ + "2: 10, 1, 5: 5\n" /* Type 2, direction X+ */ + "2: 5, 1, 10: 3\n" /* Type 2, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HighTemple + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Well: + // The data has been exported from the gallery Plains, area index 143, ID 487, created by STR_Warrior + { + // Size: + 7, 14, 7, // SizeX = 7, SizeY = 14, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 13, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 4: 0\n" /* cobblestone */ + "c: 8: 0\n" /* water */ + "d: 3: 0\n" /* dirt */ + "e: 2: 0\n" /* grass */ + "f: 13: 0\n" /* gravel */ + "g: 67: 1\n" /* stairs */ + "h: 67: 2\n" /* stairs */ + "i: 67: 0\n" /* stairs */ + "j: 67: 3\n" /* stairs */ + "k: 85: 0\n" /* fence */ + "l: 44: 8\n" /* step */ + "m: 19: 0\n" /* sponge */ + "n: 44: 0\n" /* step */ + "o: 43: 0\n" /* doubleslab */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcc.ba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "eefffee" + /* 1 */ "ebbbbbe" + /* 2 */ "fbcccbf" + /* 3 */ "fbcccbf" + /* 4 */ "fbcccbf" + /* 5 */ "ebbbbbe" + /* 6 */ "eefffee" + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".bghib." + /* 2 */ ".j...j." + /* 3 */ ".i...g." + /* 4 */ ".h...h." + /* 5 */ ".bgjib." + /* 6 */ "......." + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".k...k." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ ".k...k." + /* 6 */ "......." + + // Level 11 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".k...k." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ ".k...k." + /* 6 */ "......." + + // Level 12 + /* z\x* 0123456 */ + /* 0 */ ".lnnnl." + /* 1 */ "loooool" + /* 2 */ "nooooon" + /* 3 */ "nooooon" + /* 4 */ "nooooon" + /* 5 */ "loooool" + /* 6 */ ".lnnnl." + + // Level 13 + /* z\x* 0123456 */ + /* 0 */ "n.....n" + /* 1 */ "......." + /* 2 */ "..nnn.." + /* 3 */ "..non.." + /* 4 */ "..nnn.." + /* 5 */ "......." + /* 6 */ "n.....n", + + // Connectors: + "2: 0, 9, 3: 4\n" /* Type 2, direction X- */ + "2: 3, 9, 0: 2\n" /* Type 2, direction Z- */ + "2: 6, 9, 3: 5\n" /* Type 2, direction X+ */ + "2: 3, 9, 6: 3\n" /* Type 2, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Well +}; + + + + + +// The prefab counts: + +const size_t g_JapaneseVillagePrefabsCount = ARRAYCOUNT(g_JapaneseVillagePrefabs); + +const size_t g_JapaneseVillageStartingPrefabsCount = ARRAYCOUNT(g_JapaneseVillageStartingPrefabs); + diff --git a/src/Generating/Prefabs/JapaneseVillagePrefabs.h b/src/Generating/Prefabs/JapaneseVillagePrefabs.h new file mode 100644 index 000000000..501b6c1cd --- /dev/null +++ b/src/Generating/Prefabs/JapaneseVillagePrefabs.h @@ -0,0 +1,15 @@ + +// JapaneseVillagePrefabs.h + +// Declares the prefabs in the group JapaneseVillage + +#include "../Prefab.h" + + + + + +extern const cPrefab::sDef g_JapaneseVillagePrefabs[]; +extern const cPrefab::sDef g_JapaneseVillageStartingPrefabs[]; +extern const size_t g_JapaneseVillagePrefabsCount; +extern const size_t g_JapaneseVillageStartingPrefabsCount; diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp new file mode 100644 index 000000000..2c97f28ea --- /dev/null +++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp @@ -0,0 +1,5495 @@ + +// NetherFortPrefabs.cpp + +// Defines the prefabs in the group NetherFort + +// NOTE: This file has been generated automatically by GalExport! +// Any manual changes will be overwritten by the next automatic export! + +#include "Globals.h" +#include "NetherFortPrefabs.h" + + + + + +const cPrefab::sDef g_NetherFortPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BalconyCorridor: + // The data has been exported from the gallery Nether, area index 37, ID 288, created by Aloe_vera + { + // Size: + 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 6, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 4\n" /* netherbrickstairs */ + "c:114: 7\n" /* netherbrickstairs */ + "d:114: 5\n" /* netherbrickstairs */ + "e: 44: 6\n" /* step */ + "f:113: 0\n" /* netherbrickfence */ + "g:114: 2\n" /* netherbrickstairs */ + "h:114: 3\n" /* netherbrickstairs */ + "i:114: 0\n" /* netherbrickstairs */ + "j:114: 1\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "mmmmaaaaammmm" + /* 6 */ "mmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmm" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaa.aaa.aaaa" + /* 5 */ "mmbcaaaaacdmm" + /* 6 */ "mmmbcccccdmmm" + /* 7 */ "mmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmm" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "aaaa.eee.aaaa" + /* 5 */ "mmaaaaaaaaamm" + /* 6 */ "mmaaaaaaaaamm" + /* 7 */ "mmaaaaaaaaamm" + /* 8 */ "mmaaaaaaaaamm" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "afafafafafafa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "afaa.....aafa" + /* 5 */ "mmaaa...aaamm" + /* 6 */ "mmf.......fmm" + /* 7 */ "mmf.......fmm" + /* 8 */ "mmfffffffffmm" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "afafafafafafa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "afaa.....aafa" + /* 5 */ "mmaaa...aaamm" + /* 6 */ "mm.........mm" + /* 7 */ "mm.........mm" + /* 8 */ "mm.........mm" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "afafafafafafa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "afaa.....aafa" + /* 5 */ "mmaaa...aaamm" + /* 6 */ "mm.........mm" + /* 7 */ "mm.........mm" + /* 8 */ "mm.........mm" + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ggggggggggggg" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "hhiaaaaaaahhh" + /* 5 */ "mmihhhhhhhjmm" + /* 6 */ "mmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmm", + + // Connectors: + "1: 12, 2, 2: 5\n" /* Type 1, direction X+ */ + "1: 0, 2, 2: 4\n" /* Type 1, direction X- */ + "-1: 12, 2, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 2, 2: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BalconyCorridor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BalconyTee2: + // The data has been exported from the gallery Nether, area index 38, ID 289, created by Aloe_vera + { + // Size: + 13, 7, 11, // SizeX = 13, SizeY = 7, SizeZ = 11 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 6, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 4\n" /* netherbrickstairs */ + "c:114: 7\n" /* netherbrickstairs */ + "d:114: 5\n" /* netherbrickstairs */ + "e: 44: 6\n" /* step */ + "f:113: 0\n" /* netherbrickfence */ + "g:114: 0\n" /* netherbrickstairs */ + "h:114: 1\n" /* netherbrickstairs */ + "i:114: 2\n" /* netherbrickstairs */ + "j:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmaaaaammmm" + /* 1 */ "mmmmaaaaammmm" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "mmmmaaaaammmm" + /* 8 */ "mmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmm" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmaaaaammmm" + /* 1 */ "mmmmaaaaammmm" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaa.aaa.aaaa" + /* 7 */ "mmbcaaaaacdmm" + /* 8 */ "mmmbcccccdmmm" + /* 9 */ "mmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmm" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmma...ammmm" + /* 2 */ "aaaaa...aaaaa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "aaaa.eee.aaaa" + /* 7 */ "mmaaaaaaaaamm" + /* 8 */ "mmaaaaaaaaamm" + /* 9 */ "mmaaaaaaaaamm" + /* 10 */ "mmaaaaaaaaamm" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmf...fmmmm" + /* 2 */ "afafa...afafa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "afaa.....aafa" + /* 7 */ "mmaaa...aaamm" + /* 8 */ "mmf.......fmm" + /* 9 */ "mmf.......fmm" + /* 10 */ "mmfffffffffmm" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmf...fmmmm" + /* 2 */ "afafa...afafa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "afaa.....aafa" + /* 7 */ "mmaaa...aaamm" + /* 8 */ "mm.........mm" + /* 9 */ "mm.........mm" + /* 10 */ "mm.........mm" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmf...fmmmm" + /* 2 */ "afafa...afafa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "afaa.....aafa" + /* 7 */ "mmaaa...aaamm" + /* 8 */ "mm.........mm" + /* 9 */ "mm.........mm" + /* 10 */ "mm.........mm" + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmgaaahmmmm" + /* 1 */ "mmmmgaaahmmmm" + /* 2 */ "iiiiiaaaiiiii" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "jjgaaaaaaajjj" + /* 7 */ "mmgjjjjjjjhmm" + /* 8 */ "mmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmm", + + // Connectors: + "1: 12, 2, 4: 5\n" /* Type 1, direction X+ */ + "1: 6, 2, 0: 2\n" /* Type 1, direction Z- */ + "1: 0, 2, 4: 4\n" /* Type 1, direction X- */ + "-1: 12, 2, 4: 5\n" /* Type -1, direction X+ */ + "-1: 6, 2, 0: 2\n" /* Type -1, direction Z- */ + "-1: 0, 2, 4: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BalconyTee2 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BlazePlatform: + // The data has been exported from the gallery Nether, area index 26, ID 276, created by tonibm1999 + { + // Size: + 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 9, 6, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b: 52: 0\n" /* mobspawner */ + "c:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmmmmmmm" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "aaaaaaaaaa" + /* 3 */ "aaaaaaaaaa" + /* 4 */ "aaaaaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "mmmmmmmmmm" + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmmmmmmm" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "..aaaaaaaa" + /* 3 */ "..aaaaaaaa" + /* 4 */ "..aaaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "mmmmmmmmmm" + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmaaaaaa" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "...aaaaaaa" + /* 3 */ "...aaaaaaa" + /* 4 */ "...aaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "mmmmaaaaaa" + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmaaaaaa" + /* 1 */ "mmaaa....a" + /* 2 */ ".........a" + /* 3 */ "......b..a" + /* 4 */ ".........a" + /* 5 */ "mmaaa....a" + /* 6 */ "mmmmaaaaaa" + + // Level 4 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmcccccc" + /* 1 */ "mmmcc....c" + /* 2 */ ".........c" + /* 3 */ ".........c" + /* 4 */ ".........c" + /* 5 */ "mmmcc....c" + /* 6 */ "mmmmcccccc" + + // Level 5 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmmmmmmm" + /* 1 */ "mmmmm....c" + /* 2 */ "m........c" + /* 3 */ "m........c" + /* 4 */ "m........c" + /* 5 */ "mmmmm....c" + /* 6 */ "mmmmmmmmmm" + + // Level 6 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmmmmmmm" + /* 1 */ "mmmmm....m" + /* 2 */ "mm.......c" + /* 3 */ "mm.......c" + /* 4 */ "mm.......c" + /* 5 */ "mmmmm....m" + /* 6 */ "mmmmmmmmmm", + + // Connectors: + "0: 0, 1, 3: 4\n" /* Type 0, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BlazePlatform + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BlazePlatformOverhang: + // The data has been exported from the gallery Nether, area index 20, ID 162, created by STR_Warrior + { + // Size: + 14, 11, 7, // SizeX = 14, SizeY = 11, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 13, 20, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 5\n" /* netherbrickstairs */ + "c: 44:14\n" /* step */ + "d:114: 6\n" /* netherbrickstairs */ + "e:114: 7\n" /* netherbrickstairs */ + "f:114: 0\n" /* netherbrickstairs */ + "g:114: 4\n" /* netherbrickstairs */ + "h:113: 0\n" /* netherbrickfence */ + "i: 52: 0\n" /* mobspawner */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmmmmm" + /* 2 */ "aammmmmmmmmmmm" + /* 3 */ "aammmmmmmmmmmm" + /* 4 */ "aammmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmmmmm" + /* 2 */ "aabcmmmmmmmmmm" + /* 3 */ "aabcmmmmmmmmmm" + /* 4 */ "aabcmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" + + // Level 2 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmmmmm" + /* 2 */ "aaaaabmmmmmmmm" + /* 3 */ "aaaaabmmmmmmmm" + /* 4 */ "aaaaabmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" + + // Level 3 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "dddddddmmmmmmm" + /* 2 */ "aaaaaabmmmmmmm" + /* 3 */ "aaaaaabmmmmmmm" + /* 4 */ "aaaaaabmmmmmmm" + /* 5 */ "eeeeeeemmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" + + // Level 4 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "aaaaaaadmmmmmm" + /* 2 */ "aaaaaaabmmmmmm" + /* 3 */ "aaaaaaabmmmmmm" + /* 4 */ "aaaaaaabmmmmmm" + /* 5 */ "aaaaaaaemmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" + + // Level 5 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "aaaaaaaabddddm" + /* 2 */ "......faaaaabm" + /* 3 */ "......faaaaabm" + /* 4 */ "......faaaaabm" + /* 5 */ "aaaaaaaaabeebm" + /* 6 */ "mmmmmmmmmmmmmm" + + // Level 6 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmgdddbm" + /* 1 */ "mmmmmmaaaaaaad" + /* 2 */ ".......faaaaab" + /* 3 */ ".......faaaaab" + /* 4 */ ".......faaaaab" + /* 5 */ "mmmmmmaaaaaaae" + /* 6 */ "mmmmmmmmgeeebm" + + // Level 7 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmaaaaam" + /* 1 */ "mmmmmmhaa...aa" + /* 2 */ ".............a" + /* 3 */ "..........i..a" + /* 4 */ ".............a" + /* 5 */ "mmmmmmhaa...aa" + /* 6 */ "mmmmmmmmaaaaam" + + // Level 8 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmhhhhhm" + /* 1 */ "mmmmmmhhh...hh" + /* 2 */ "mm...........h" + /* 3 */ "mm...........h" + /* 4 */ "mm...........h" + /* 5 */ "mmmmmmhhh...hh" + /* 6 */ "mmmmmmmmhhhhhm" + + // Level 9 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmm.....m" + /* 1 */ "mmmmmm........" + /* 2 */ "mmmm.........." + /* 3 */ "mmmm.........." + /* 4 */ "mmmm.........." + /* 5 */ "mmmmmm........" + /* 6 */ "mmmmmmmm.....m" + + // Level 10 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmm.....m" + /* 1 */ "mmmmmm........" + /* 2 */ "mmmmmm........" + /* 3 */ "mmmmmm........" + /* 4 */ "mmmmmm........" + /* 5 */ "mmmmmm........" + /* 6 */ "mmmmmmmm.....m", + + // Connectors: + "0: 0, 5, 3: 4\n" /* Type 0, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BlazePlatformOverhang + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeCircleCrossing: + // The data has been exported from the gallery Nether, area index 49, ID 308, created by Aloe_vera + { + // Size: + 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 17, 14, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 7\n" /* netherbrickstairs */ + "c:114: 5\n" /* netherbrickstairs */ + "d:114: 4\n" /* netherbrickstairs */ + "e:114: 6\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "mmmmmmaaammmmmm" + /* 2 */ "mmmmmmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "aammmmmmmmmmmaa" + /* 7 */ "aammmmmmmmmmmaa" + /* 8 */ "aammmmmmmmmmmaa" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + /* 12 */ "mmmmmmmmmmmmmmm" + /* 13 */ "mmmmmmaaammmmmm" + /* 14 */ "mmmmmmaaammmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "mmmmmmaaammmmmm" + /* 2 */ "mmmmmmbbbmmmmmm" + /* 3 */ "mmmmmmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "aacmmmmmmmmmdaa" + /* 7 */ "aacmmmmmmmmmdaa" + /* 8 */ "aacmmmmmmmmmdaa" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + /* 12 */ "mmmmmmeeemmmmmm" + /* 13 */ "mmmmmmaaammmmmm" + /* 14 */ "mmmmmmaaammmmmm" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "mmmmmeaaammmmmm" + /* 2 */ "mmmmmdaaammmmmm" + /* 3 */ "mmmmmdbbbmmmmmm" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mdeemmmmmmmeecm" + /* 6 */ "aaacmmmmmmmdaaa" + /* 7 */ "aaacmmmmmmmdaaa" + /* 8 */ "aaacmmmmmmmdaaa" + /* 9 */ "mdbcmmmmmmmbbcm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmdeeecmmmmm" + /* 12 */ "mmmmmdaaacmmmmm" + /* 13 */ "mmmmmbaaabmmmmm" + /* 14 */ "mmmmmmaaammmmmm" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "deeeedaaaceeeec" + /* 1 */ "daaaaaaaaaaaaac" + /* 2 */ "daaaaaaaaaaaaac" + /* 3 */ "daaaaaaaaaaaaac" + /* 4 */ "daaacbbaabdaaac" + /* 5 */ "eaaacmmmmmdaaae" + /* 6 */ "aaaacmmmmmdaaaa" + /* 7 */ "aaaacmmmmmdaaaa" + /* 8 */ "aaaacmmmmmdaaaa" + /* 9 */ "baaacmmmmmdaaab" + /* 10 */ "daaaceeeeedaaac" + /* 11 */ "daaaaaaaaaaaaac" + /* 12 */ "daaaaaaaaaaaaac" + /* 13 */ "daaaaaaaaaaaaac" + /* 14 */ "dbbbbdaaacbbbbb" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaa" + /* 5 */ "aaaaammmmmaaaaa" + /* 6 */ "aaaaammmmmaaaaa" + /* 7 */ "aaaaammmmmaaaaa" + /* 8 */ "aaaaammmmmaaaaa" + /* 9 */ "aaaaammmmmaaaaa" + /* 10 */ "aaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaa" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaa...aaaaaa" + /* 1 */ "a.............a" + /* 2 */ "a.............a" + /* 3 */ "a.............a" + /* 4 */ "a...aaaaaaa...a" + /* 5 */ "a...ammmmma...a" + /* 6 */ "....ammmmma...." + /* 7 */ "....ammmmma...." + /* 8 */ "....ammmmma...." + /* 9 */ "a...ammmmma...a" + /* 10 */ "a...aaaaaaa...a" + /* 11 */ "a.............a" + /* 12 */ "a.............a" + /* 13 */ "a.............a" + /* 14 */ "aaaaaa...aaaaaa" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmm...mmmmmm" + /* 1 */ "m.............m" + /* 2 */ "m.............m" + /* 3 */ "m.............m" + /* 4 */ "m.............m" + /* 5 */ "m....mmmmm....m" + /* 6 */ ".....mmmmm....." + /* 7 */ ".....mmmmm....." + /* 8 */ ".....mmmmm....." + /* 9 */ "m....mmmmm....m" + /* 10 */ "m.............m" + /* 11 */ "m.............m" + /* 12 */ "m.............m" + /* 13 */ "m.............m" + /* 14 */ "mmmmmm...mmmmmm" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmm...mmmmmm" + /* 1 */ "m.............m" + /* 2 */ "m.............m" + /* 3 */ "m.............m" + /* 4 */ "m.............m" + /* 5 */ "m....mmmmm....m" + /* 6 */ ".....mmmmm....." + /* 7 */ ".....mmmmm....." + /* 8 */ ".....mmmmm....." + /* 9 */ "m....mmmmm....m" + /* 10 */ "m.............m" + /* 11 */ "m.............m" + /* 12 */ "m.............m" + /* 13 */ "m.............m" + /* 14 */ "mmmmmm...mmmmmm", + + // Connectors: + "0: 0, 5, 7: 4\n" /* Type 0, direction X- */ + "0: 7, 5, 0: 2\n" /* Type 0, direction Z- */ + "0: 14, 5, 7: 5\n" /* Type 0, direction X+ */ + "0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 5, + + // DepthWeight: + "", + + // AddWeightIfSame: + -1000, + + // MoveToGround: + false, + }, // BridgeCircleCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeCrossing: + // The data has been exported from the gallery Nether, area index 17, ID 159, created by Aloe_vera + { + // Size: + 15, 8, 15, // SizeX = 15, SizeY = 8, SizeZ = 15 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 17, 14, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 7\n" /* netherbrickstairs */ + "c:114: 5\n" /* netherbrickstairs */ + "d:114: 4\n" /* netherbrickstairs */ + "e:114: 6\n" /* netherbrickstairs */ + "f: 44:14\n" /* step */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "mmmmmmaaammmmmm" + /* 2 */ "mmmmmmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "aammmmmmmmmmmaa" + /* 7 */ "aammmmmmmmmmmaa" + /* 8 */ "aammmmmmmmmmmaa" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + /* 12 */ "mmmmmmmmmmmmmmm" + /* 13 */ "mmmmmmaaammmmmm" + /* 14 */ "mmmmmmaaammmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "mmmmmmaaammmmmm" + /* 2 */ "mmmmmmbbbmmmmmm" + /* 3 */ "mmmmmmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "aacmmmmmmmmmdaa" + /* 7 */ "aacmmmmmmmmmdaa" + /* 8 */ "aacmmmmmmmmmdaa" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + /* 12 */ "mmmmmmeeemmmmmm" + /* 13 */ "mmmmmmaaammmmmm" + /* 14 */ "mmmmmmaaammmmmm" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "mmmmmmaaammmmmm" + /* 2 */ "mmmmmmaaammmmmm" + /* 3 */ "mmmmmmbbbmmmmmm" + /* 4 */ "mmmmmmfffmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "aaacfmmmmmfdaaa" + /* 7 */ "aaacfmmmmmfdaaa" + /* 8 */ "aaacfmmmmmfdaaa" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmfffmmmmmm" + /* 11 */ "mmmmmmeeemmmmmm" + /* 12 */ "mmmmmmaaammmmmm" + /* 13 */ "mmmmmmaaammmmmm" + /* 14 */ "mmmmmmaaammmmmm" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmdaaacmmmmm" + /* 1 */ "mmmmmdaaacmmmmm" + /* 2 */ "mmmmmdaaacmmmmm" + /* 3 */ "mmmmmdaaacmmmmm" + /* 4 */ "mmmmmdaaacmmmmm" + /* 5 */ "eeeeeeaaaeeeeee" + /* 6 */ "aaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + /* 9 */ "bbbbbdaaacbbbbb" + /* 10 */ "mmmmmdaaacmmmmm" + /* 11 */ "mmmmmdaaacmmmmm" + /* 12 */ "mmmmmdaaacmmmmm" + /* 13 */ "mmmmmdaaacmmmmm" + /* 14 */ "mmmmmdaaacmmmmm" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmaaaaammmmm" + /* 1 */ "mmmmmaaaaammmmm" + /* 2 */ "mmmmmaaaaammmmm" + /* 3 */ "mmmmmaaaaammmmm" + /* 4 */ "mmmmmaaaaammmmm" + /* 5 */ "aaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaa" + /* 10 */ "mmmmmaaaaammmmm" + /* 11 */ "mmmmmaaaaammmmm" + /* 12 */ "mmmmmaaaaammmmm" + /* 13 */ "mmmmmaaaaammmmm" + /* 14 */ "mmmmmaaaaammmmm" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmma...ammmmm" + /* 1 */ "mmmmma...ammmmm" + /* 2 */ "mmmmma...ammmmm" + /* 3 */ "mmmmma...ammmmm" + /* 4 */ "mmmmma...ammmmm" + /* 5 */ "aaaaaa...aaaaaa" + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "aaaaaa...aaaaaa" + /* 10 */ "mmmmma...ammmmm" + /* 11 */ "mmmmma...ammmmm" + /* 12 */ "mmmmma...ammmmm" + /* 13 */ "mmmmma...ammmmm" + /* 14 */ "mmmmma...ammmmm" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmm...mmmmmm" + /* 1 */ "mmmmmm...mmmmmm" + /* 2 */ "mmmmmm...mmmmmm" + /* 3 */ "mmmmmm...mmmmmm" + /* 4 */ "mmmmmm...mmmmmm" + /* 5 */ "mmmmmm...mmmmmm" + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "mmmmmm...mmmmmm" + /* 10 */ "mmmmmm...mmmmmm" + /* 11 */ "mmmmmm...mmmmmm" + /* 12 */ "mmmmmm...mmmmmm" + /* 13 */ "mmmmmm...mmmmmm" + /* 14 */ "mmmmmm...mmmmmm" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmm...mmmmmm" + /* 1 */ "mmmmmm...mmmmmm" + /* 2 */ "mmmmmm...mmmmmm" + /* 3 */ "mmmmmm...mmmmmm" + /* 4 */ "mmmmmm...mmmmmm" + /* 5 */ "mmmmmm...mmmmmm" + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + /* 9 */ "mmmmmm...mmmmmm" + /* 10 */ "mmmmmm...mmmmmm" + /* 11 */ "mmmmmm...mmmmmm" + /* 12 */ "mmmmmm...mmmmmm" + /* 13 */ "mmmmmm...mmmmmm" + /* 14 */ "mmmmmm...mmmmmm", + + // Connectors: + "0: 0, 5, 7: 4\n" /* Type 0, direction X- */ + "0: 7, 5, 0: 2\n" /* Type 0, direction Z- */ + "0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */ + "0: 14, 5, 7: 5\n" /* Type 0, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "1:1000", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BridgeCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeCrumble1: + // The data has been exported from the gallery Nether, area index 19, ID 161, created by Aloe_vera + { + // Size: + 9, 6, 5, // SizeX = 9, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 8, 15, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 5\n" /* netherbrickstairs */ + "c: 44:14\n" /* step */ + "d:114: 6\n" /* netherbrickstairs */ + "e:114: 7\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "mmmmmmmmm" + /* 1 */ "aammmmmmm" + /* 2 */ "aammmmmmm" + /* 3 */ "aammmmmmm" + /* 4 */ "mmmmmmmmm" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "mmmmmmmmm" + /* 1 */ "aabmmmmmm" + /* 2 */ "aabmmmmmm" + /* 3 */ "aabmmmmmm" + /* 4 */ "mmmmmmmmm" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "mmmmmmmmm" + /* 1 */ "aaabcmmmm" + /* 2 */ "aaabcmmmm" + /* 3 */ "aaabcmmmm" + /* 4 */ "mmmmmmmmm" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "dddddddmm" + /* 1 */ "aaaaaaaam" + /* 2 */ "aaaaaaaaa" + /* 3 */ "aaaaaaamm" + /* 4 */ "eeeeemmmm" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaammmm" + /* 2 */ "aaaaaammm" + /* 3 */ "aaaaaammm" + /* 4 */ "aaaaaaaam" + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "aaaaaammm" + /* 1 */ "mmmmmmmmm" + /* 2 */ "mmmmmmmmm" + /* 3 */ "mmmmmmmmm" + /* 4 */ "aaaaaaamm", + + // Connectors: + "1: 0, 5, 2: 4\n" /* Type 1, direction X- */ + "0: 0, 5, 2: 4\n" /* Type 0, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BridgeCrumble1 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeCrumble2: + // The data has been exported from the gallery Nether, area index 18, ID 160, created by Aloe_vera + { + // Size: + 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 15, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 5\n" /* netherbrickstairs */ + "c: 44:14\n" /* step */ + "d:114: 6\n" /* netherbrickstairs */ + "e:114: 7\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmm" + /* 2 */ "aammmmmmmmmmm" + /* 3 */ "aammmmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmm" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmmmmmmmmmm" + /* 1 */ "aabmmmmmmmmmm" + /* 2 */ "aabmmmmmmmmmm" + /* 3 */ "aabmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmm" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmmmmmmmmmm" + /* 1 */ "aaabcmmmmmmmm" + /* 2 */ "aaabcmmmmmmmm" + /* 3 */ "aaabcmmmmmmmm" + /* 4 */ "mmmmmmmmmmmmm" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "dddddddddmmmm" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaammmm" + /* 3 */ "aaaaaaaaaaaam" + /* 4 */ "eeeeeeeeemmmm" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaam" + /* 1 */ "aaaaaaaaaammm" + /* 2 */ "aaaaaaaaaaamm" + /* 3 */ "aaaaaaaaammmm" + /* 4 */ "aaaaaaaaaaaaa" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaammmm" + /* 1 */ "mmmmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmmmm" + /* 4 */ "aaaaaaaaaammm", + + // Connectors: + "0: 0, 5, 2: 4\n" /* Type 0, direction X- */ + "1: 0, 5, 2: 4\n" /* Type 1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BridgeCrumble2 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeDoubleCrumble: + // The data has been exported from the gallery Nether, area index 46, ID 305, created by STR_Warrior + { + // Size: + 5, 7, 16, // SizeX = 5, SizeY = 7, SizeZ = 16 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 16, 15, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 7\n" /* netherbrickstairs */ + "c:114: 6\n" /* netherbrickstairs */ + "d:114: 4\n" /* netherbrickstairs */ + "e:114: 5\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "maaam" + /* 1 */ "maaam" + /* 2 */ "mmmmm" + /* 3 */ "mmmmm" + /* 4 */ "mmmmm" + /* 5 */ "mmmmm" + /* 6 */ "mmmmm" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmmm" + /* 11 */ "mmmmm" + /* 12 */ "mmmmm" + /* 13 */ "mmmmm" + /* 14 */ "maaam" + /* 15 */ "maaam" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "maaam" + /* 1 */ "maaam" + /* 2 */ "mbbbm" + /* 3 */ "mmmmm" + /* 4 */ "mmmmm" + /* 5 */ "mmmmm" + /* 6 */ "mmmmm" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmmm" + /* 11 */ "mmmmm" + /* 12 */ "mmmmm" + /* 13 */ "mcccm" + /* 14 */ "maaam" + /* 15 */ "maaam" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "daaae" + /* 1 */ "daaae" + /* 2 */ "daaae" + /* 3 */ "daaae" + /* 4 */ "daaae" + /* 5 */ "mamae" + /* 6 */ "mmmam" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmae" + /* 11 */ "dmaae" + /* 12 */ "daaae" + /* 13 */ "daaae" + /* 14 */ "daaae" + /* 15 */ "daaae" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaama" + /* 4 */ "mamaa" + /* 5 */ "mmmmm" + /* 6 */ "mmmmm" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmma" + /* 11 */ "mmmaa" + /* 12 */ "amaaa" + /* 13 */ "aaaaa" + /* 14 */ "aaaaa" + /* 15 */ "aaaaa" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "ammma" + /* 1 */ "ammma" + /* 2 */ "ammma" + /* 3 */ "mmmma" + /* 4 */ "mmmmm" + /* 5 */ "mmmmm" + /* 6 */ "mmmmm" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmmm" + /* 11 */ "mmmma" + /* 12 */ "mmmmm" + /* 13 */ "ammma" + /* 14 */ "ammma" + /* 15 */ "ammma" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "mmmmm" + /* 1 */ "mmmmm" + /* 2 */ "mmmmm" + /* 3 */ "mmmmm" + /* 4 */ "mmmmm" + /* 5 */ "mmmmm" + /* 6 */ "mmmmm" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmmm" + /* 11 */ "mmmmm" + /* 12 */ "mmmmm" + /* 13 */ "mmmmm" + /* 14 */ "mmmmm" + /* 15 */ "mmmmm" + + // Level 6 + /* z\x* 01234 */ + /* 0 */ "mmmmm" + /* 1 */ "mmmmm" + /* 2 */ "mmmmm" + /* 3 */ "mmmmm" + /* 4 */ "mmmmm" + /* 5 */ "mmmmm" + /* 6 */ "mmmmm" + /* 7 */ "mmmmm" + /* 8 */ "mmmmm" + /* 9 */ "mmmmm" + /* 10 */ "mmmmm" + /* 11 */ "mmmmm" + /* 12 */ "mmmmm" + /* 13 */ "mmmmm" + /* 14 */ "mmmmm" + /* 15 */ "mmmmm", + + // Connectors: + "0: 2, 4, 0: 2\n" /* Type 0, direction Z- */ + "0: 2, 4, 15: 3\n" /* Type 0, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 1000, + + // MoveToGround: + false, + }, // BridgeDoubleCrumble + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeFunnelDown: + // The data has been exported from the gallery Nether, area index 0, ID 2, created by Aloe_vera + { + // Size: + 15, 12, 12, // SizeX = 15, SizeY = 12, SizeZ = 12 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 21, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 6\n" /* netherbrickstairs */ + "c:114: 4\n" /* netherbrickstairs */ + "d:114: 5\n" /* netherbrickstairs */ + "e: 44:14\n" /* step */ + "f:114: 7\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmaaammmmmm" + /* 10 */ "mmmmmmaaammmmmm" + /* 11 */ "mmmmmmaaammmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmbbbmmmmmm" + /* 9 */ "mmmmmmaaammmmmm" + /* 10 */ "mmmmmmaaammmmmm" + /* 11 */ "mmmmmmaaammmmmm" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmcbbbdmmmmm" + /* 8 */ "mmmmmcaaadmmmmm" + /* 9 */ "mmmmmcaaadmmmmm" + /* 10 */ "mmmmmcaaadmmmmm" + /* 11 */ "mmmmmcaaadmmmmm" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmaaaaammmmm" + /* 8 */ "mmmmmaaaaammmmm" + /* 9 */ "mmmmmaaaaammmmm" + /* 10 */ "mmmmmaaaaammmmm" + /* 11 */ "mmmmmaaaaammmmm" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmcbbbbbdmmmm" + /* 7 */ "mmmmaaaaaaammmm" + /* 8 */ "mmmma.....ammmm" + /* 9 */ "mmmmaa...aammmm" + /* 10 */ "mmmmma...ammmmm" + /* 11 */ "mmmmma...ammmmm" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aadmmmmmmmmmcaa" + /* 2 */ "aadmmmmmmmmmcaa" + /* 3 */ "aadmmmmmmmmmcaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmcbbbbbbbdmmm" + /* 6 */ "mmmaaaaaaaaaamm" + /* 7 */ "mmma.......ammm" + /* 8 */ "mmmaa.....aammm" + /* 9 */ "mmmmam...mammmm" + /* 10 */ "mmmmmm...mmmmmm" + /* 11 */ "mmmmmm...mmmmmm" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aaademmmmmecaaa" + /* 2 */ "aaademmmmmecaaa" + /* 3 */ "aaademmmmmecaaa" + /* 4 */ "mmaaabbbbbaaaam" + /* 5 */ "mmaaaaaaaaaaaam" + /* 6 */ "mma.........amm" + /* 7 */ "mmaa.......aamm" + /* 8 */ "mmmam.....mammm" + /* 9 */ "mmmmmm...mmmmmm" + /* 10 */ "mmmmmm...mmmmmm" + /* 11 */ "mmmmmm...mmmmmm" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "bbbbbbbbbbbbbbb" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "faaaaaaaaaaaaaa" + /* 5 */ "ma...........am" + /* 6 */ "maa.........aam" + /* 7 */ "mmam.......mamm" + /* 8 */ "mmmmm.....mmmmm" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + + // Level 8 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "a.............a" + /* 5 */ "aa...........aa" + /* 6 */ "mam.........mam" + /* 7 */ "mmmm.......mmmm" + /* 8 */ "mmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + + // Level 9 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "a.............a" + /* 5 */ "am............a" + /* 6 */ "mmm.........mmm" + /* 7 */ "mmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + + // Level 10 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "m.............m" + /* 5 */ "mm............m" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm" + + // Level 11 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "m.............m" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmm", + + // Connectors: + "0: 7, 4, 11: 3\n" /* Type 0, direction Z+ */ + "0: 0, 9, 2: 4\n" /* Type 0, direction X- */ + "0: 14, 9, 2: 5\n" /* Type 0, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 5, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BridgeFunnelDown + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeLevelCrossing: + // The data has been exported from the gallery Nether, area index 61, ID 321, created by Aloe_vera + { + // Size: + 16, 14, 16, // SizeX = 16, SizeY = 14, SizeZ = 16 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 15, 23, 15, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 5\n" /* netherbrickstairs */ + "c:114: 4\n" /* netherbrickstairs */ + "d: 44:14\n" /* step */ + "e:114: 6\n" /* netherbrickstairs */ + "f:114: 7\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmmm" + /* 12 */ "maaammmmmmmmmmmm" + /* 13 */ "maaammmmmmmmmmmm" + /* 14 */ "maaammmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmmmmm" + /* 1 */ "aabmmmmmmmmmmcaa" + /* 2 */ "aabmmmmmmmmmmcaa" + /* 3 */ "aabmmmmmmmmmmcaa" + /* 4 */ "mmmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmmm" + /* 12 */ "maaammmmmmmmmmmm" + /* 13 */ "maaammmmmmmmmmmm" + /* 14 */ "maaammmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmmmmm" + /* 1 */ "aaabdmmmmmmdcaaa" + /* 2 */ "aaabdmmmmmmdcaaa" + /* 3 */ "aaabdmmmmmmdcaaa" + /* 4 */ "mmmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmmm" + /* 12 */ "maaammmmmmmmmmmm" + /* 13 */ "maaammmmmmmmmmmm" + /* 14 */ "maaammmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "eeeeeeeeeeeeeeee" + /* 1 */ "aaaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaaa" + /* 4 */ "ffffffffffffffff" + /* 5 */ "mmmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmmm" + /* 12 */ "maaammmmmmmmmmmm" + /* 13 */ "maaammmmmmmmmmmm" + /* 14 */ "maaammmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaaa" + /* 5 */ "faaabmmmmmmmmmmm" + /* 6 */ "caaabmmmmmmmmmmm" + /* 7 */ "caaabmmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmmm" + /* 12 */ "maaammmmmmmmmmmm" + /* 13 */ "maaammmmmmmmmmmm" + /* 14 */ "maaammmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "a...aaaaaaaaaaaa" + /* 5 */ "a...ammmmmmmmmmm" + /* 6 */ "aaaaammmmmmmmmmm" + /* 7 */ "aaaaammmmmmmmmmm" + /* 8 */ "caaabmmmmmmmmmmm" + /* 9 */ "caaabmmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmmmmmmm" + /* 12 */ "maaammmmmmmmmmmm" + /* 13 */ "maaammmmmmmmmmmm" + /* 14 */ "maaammmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmaaam" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "m...mmmmmmmmaaam" + /* 5 */ "a...ammmmmmmmmmm" + /* 6 */ "a...ammmmmmmmmmm" + /* 7 */ "a...ammmmmmmmmmm" + /* 8 */ "aaaaammmmmmmmmmm" + /* 9 */ "aaaaammmmmmmmmmm" + /* 10 */ "caaabmmmmmmmmmmm" + /* 11 */ "caaabmmmmmmmmmmm" + /* 12 */ "maaabmmmmmmmmmmm" + /* 13 */ "maaabmmmmmmmmmmm" + /* 14 */ "maaafmmmmmmmaaam" + /* 15 */ "mmmmmmmmmmmmaaam" + + // Level 7 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmaaam" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "................" + /* 4 */ "m...mmmmmmmmaaam" + /* 5 */ "m...mmmmmmmmmmmm" + /* 6 */ "m...mmmmmmmmmmmm" + /* 7 */ "a...ammmmmmmmmmm" + /* 8 */ "a...ammmmmmmmmmm" + /* 9 */ "a...ammmmmmmmmmm" + /* 10 */ "aaaaammmmmmmmmmm" + /* 11 */ "aaaaaeemmmmmmmmm" + /* 12 */ "caaaaaammmmmmmmm" + /* 13 */ "caaaaaammmmmmmmm" + /* 14 */ "caaaaaammmmmaaam" + /* 15 */ "fffffffmmmmmaaam" + + // Level 8 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmmaaam" + /* 1 */ "mmmmmmmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmmmmmmm" + /* 4 */ "m...mmmmmmmmaaam" + /* 5 */ "m...mmmmmmmmmmmm" + /* 6 */ "m...mmmmmmmmmmmm" + /* 7 */ "m...mmmmmmmmmmmm" + /* 8 */ "m...mmmmmmmmmmmm" + /* 9 */ "a...ammmmmmmmmmm" + /* 10 */ "a...ammmmmmmmmmm" + /* 11 */ "a...aaaeemmmmmmm" + /* 12 */ "a.....aaammmmmmm" + /* 13 */ "a.....aaammmmmmm" + /* 14 */ "a.....aaammmaaam" + /* 15 */ "aaaaaaaffmmmaaam" + + // Level 9 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmcaaab" + /* 1 */ "mmmmmmmmmmmcaaab" + /* 2 */ "mmmmmmmmmmmcaaab" + /* 3 */ "mmmmmmmmmmmcaaab" + /* 4 */ "mmmmmmmmmmmcaaab" + /* 5 */ "mmmmmmmmmmmcaaab" + /* 6 */ "m...mmmmmmmcaaab" + /* 7 */ "m...mmmmmmmcaaab" + /* 8 */ "m...mmmmmmmcaaab" + /* 9 */ "m...mmmmmmmcaaab" + /* 10 */ "m...mmmmmmmcaaab" + /* 11 */ "m...maaaaeecaaab" + /* 12 */ "m.......aaaaaaab" + /* 13 */ "m.......aaaaaaab" + /* 14 */ "m.......aaaaaaab" + /* 15 */ "mmmmmaaaafffaaab" + + // Level 10 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmaaaaa" + /* 1 */ "mmmmmmmmmmmaaaaa" + /* 2 */ "mmmmmmmmmmmaaaaa" + /* 3 */ "mmmmmmmmmmmaaaaa" + /* 4 */ "mmmmmmmmmmmaaaaa" + /* 5 */ "mmmmmmmmmmmaaaaa" + /* 6 */ "mmmmmmmmmmmaaaaa" + /* 7 */ "mmmmmmmmmmmaaaaa" + /* 8 */ "m...mmmmmmmaaaaa" + /* 9 */ "m...mmmmmmmaaaaa" + /* 10 */ "m...mmmmmmmaaaaa" + /* 11 */ "m...mmmaaaaaaaaa" + /* 12 */ "m.........aaaaaa" + /* 13 */ "m.........aaaaaa" + /* 14 */ "m.........aaaaaa" + /* 15 */ "mmmmmmmaaaaaaaaa" + + // Level 11 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmma...a" + /* 1 */ "mmmmmmmmmmma...a" + /* 2 */ "mmmmmmmmmmma...a" + /* 3 */ "mmmmmmmmmmma...a" + /* 4 */ "mmmmmmmmmmma...a" + /* 5 */ "mmmmmmmmmmma...a" + /* 6 */ "mmmmmmmmmmma...a" + /* 7 */ "mmmmmmmmmmma...a" + /* 8 */ "mmmmmmmmmmma...a" + /* 9 */ "mmmmmmmmmmma...a" + /* 10 */ "mmmmmmmmmmma...a" + /* 11 */ "mmmmmmmmmaaa...a" + /* 12 */ "mmmm...........a" + /* 13 */ "mmmm...........a" + /* 14 */ "mmmm...........a" + /* 15 */ "mmmmmmmmmaaa...a" + + // Level 12 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmm...m" + /* 1 */ "mmmmmmmmmmmm...m" + /* 2 */ "mmmmmmmmmmmm...m" + /* 3 */ "mmmmmmmmmmmm...m" + /* 4 */ "mmmmmmmmmmmm...m" + /* 5 */ "mmmmmmmmmmmm...m" + /* 6 */ "mmmmmmmmmmmm...m" + /* 7 */ "mmmmmmmmmmmm...m" + /* 8 */ "mmmmmmmmmmmm...m" + /* 9 */ "mmmmmmmmmmmm...m" + /* 10 */ "mmmmmmmmmmmm...m" + /* 11 */ "mmmmmmmmmmmm...m" + /* 12 */ "mmmmmm.........m" + /* 13 */ "mmmmmm.........m" + /* 14 */ "mmmmmm.........m" + /* 15 */ "mmmmmmmmmmmm...m" + + // Level 13 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmmmmm...m" + /* 1 */ "mmmmmmmmmmmm...m" + /* 2 */ "mmmmmmmmmmmm...m" + /* 3 */ "mmmmmmmmmmmm...m" + /* 4 */ "mmmmmmmmmmmm...m" + /* 5 */ "mmmmmmmmmmmm...m" + /* 6 */ "mmmmmmmmmmmm...m" + /* 7 */ "mmmmmmmmmmmm...m" + /* 8 */ "mmmmmmmmmmmm...m" + /* 9 */ "mmmmmmmmmmmm...m" + /* 10 */ "mmmmmmmmmmmm...m" + /* 11 */ "mmmmmmmmmmmm...m" + /* 12 */ "mmmmmmmm.......m" + /* 13 */ "mmmmmmmm.......m" + /* 14 */ "mmmmmmmm.......m" + /* 15 */ "mmmmmmmmmmmm...m", + + // Connectors: + "0: 0, 5, 2: 4\n" /* Type 0, direction X- */ + "0: 15, 5, 2: 5\n" /* Type 0, direction X+ */ + "0: 13, 11, 0: 2\n" /* Type 0, direction Z- */ + "0: 13, 11, 15: 3\n" /* Type 0, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BridgeLevelCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeSegment: + // The data has been exported from the gallery Nether, area index 16, ID 158, created by Aloe_vera + { + // Size: + 15, 8, 5, // SizeX = 15, SizeY = 8, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 17, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 5\n" /* netherbrickstairs */ + "c:114: 4\n" /* netherbrickstairs */ + "d: 44:14\n" /* step */ + "e:114: 6\n" /* netherbrickstairs */ + "f:114: 7\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aabmmmmmmmmmcaa" + /* 2 */ "aabmmmmmmmmmcaa" + /* 3 */ "aabmmmmmmmmmcaa" + /* 4 */ "mmmmmmmmmmmmmmm" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aaabdmmmmmdcaaa" + /* 2 */ "aaabdmmmmmdcaaa" + /* 3 */ "aaabdmmmmmdcaaa" + /* 4 */ "mmmmmmmmmmmmmmm" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "eeeeeeeeeeeeeee" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "fffffffffffffff" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaa" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "aaaaaaaaaaaaaaa" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "mmmmmmmmmmmmmmm" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "mmmmmmmmmmmmmmm", + + // Connectors: + "0: 0, 5, 2: 4\n" /* Type 0, direction X- */ + "0: 14, 5, 2: 5\n" /* Type 0, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 500, + + // DepthWeight: + "4:-3000|8:-3000|12:-3000|16:-3000|20:-3000", + + // AddWeightIfSame: + 1000, + + // MoveToGround: + false, + }, // BridgeSegment + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BridgeTee: + // The data has been exported from the gallery Nether, area index 39, ID 290, created by STR_Warrior + { + // Size: + 15, 8, 10, // SizeX = 15, SizeY = 8, SizeZ = 10 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 17, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 5\n" /* netherbrickstairs */ + "c:114: 4\n" /* netherbrickstairs */ + "d:114: 6\n" /* netherbrickstairs */ + "e: 44:14\n" /* step */ + "f:114: 7\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aammmmmmmmmmmaa" + /* 2 */ "aammmmmmmmmmmaa" + /* 3 */ "aammmmmmmmmmmaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmmmmmm" + /* 8 */ "mmmmmmaaammmmmm" + /* 9 */ "mmmmmmaaammmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aabmmmmmmmmmcaa" + /* 2 */ "aabmmmmmmmmmcaa" + /* 3 */ "aabmmmmmmmmmcaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmmm" + /* 7 */ "mmmmmmdddmmmmmm" + /* 8 */ "mmmmmmaaammmmmm" + /* 9 */ "mmmmmmaaammmmmm" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "aaabemmmmmecaaa" + /* 2 */ "aaabemmmmmecaaa" + /* 3 */ "aaabemmmmmecaaa" + /* 4 */ "mmmmmmmmmmmmmmm" + /* 5 */ "mmmmmmeeemmmmmm" + /* 6 */ "mmmmmmdddmmmmmm" + /* 7 */ "mmmmmmaaammmmmm" + /* 8 */ "mmmmmmaaammmmmm" + /* 9 */ "mmmmmmaaammmmmm" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "ddddddddddddddd" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "fffffcaaabfffff" + /* 5 */ "mmmmmcaaabmmmmm" + /* 6 */ "mmmmmcaaabmmmmm" + /* 7 */ "mmmmmcaaabmmmmm" + /* 8 */ "mmmmmcaaabmmmmm" + /* 9 */ "mmmmmcaaabmmmmm" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaa" + /* 5 */ "mmmmmaaaaammmmm" + /* 6 */ "mmmmmaaaaammmmm" + /* 7 */ "mmmmmaaaaammmmm" + /* 8 */ "mmmmmaaaaammmmm" + /* 9 */ "mmmmmaaaaammmmm" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "aaaaaa...aaaaaa" + /* 5 */ "mmmmma...ammmmm" + /* 6 */ "mmmmma...ammmmm" + /* 7 */ "mmmmma...ammmmm" + /* 8 */ "mmmmma...ammmmm" + /* 9 */ "mmmmma...ammmmm" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "mmmmmm...mmmmmm" + /* 5 */ "mmmmmm...mmmmmm" + /* 6 */ "mmmmmm...mmmmmm" + /* 7 */ "mmmmmm...mmmmmm" + /* 8 */ "mmmmmm...mmmmmm" + /* 9 */ "mmmmmm...mmmmmm" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmmmmmmmmmm" + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "mmmmmm...mmmmmm" + /* 5 */ "mmmmmm...mmmmmm" + /* 6 */ "mmmmmm...mmmmmm" + /* 7 */ "mmmmmm...mmmmmm" + /* 8 */ "mmmmmm...mmmmmm" + /* 9 */ "mmmmmm...mmmmmm", + + // Connectors: + "0: 0, 5, 2: 4\n" /* Type 0, direction X- */ + "0: 7, 5, 9: 3\n" /* Type 0, direction Z+ */ + "0: 14, 5, 2: 5\n" /* Type 0, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "1:500", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // BridgeTee + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Corridor11: + // The data has been exported from the gallery Nether, area index 36, ID 287, created by Aloe_vera + { + // Size: + 11, 6, 5, // SizeX = 11, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 2\n" /* netherbrickstairs */ + "d:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "aaaaaaaaaaa" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "abababababa" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "abababababa" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "abababababa" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "ccccccccccc" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaa" + /* 4 */ "ddddddddddd", + + // Connectors: + "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */ + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 300, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // Corridor11 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Corridor13: + // The data has been exported from the gallery Nether, area index 35, ID 286, created by Aloe_vera + { + // Size: + 13, 6, 5, // SizeX = 13, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 2\n" /* netherbrickstairs */ + "d:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "aaaaaaaaaaaaa" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ababababababa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "ababababababa" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ababababababa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "ababababababa" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ababababababa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "ababababababa" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ccccccccccccc" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "ddddddddddddd", + + // Connectors: + "1: 12, 1, 2: 5\n" /* Type 1, direction X+ */ + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 12, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 300, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // Corridor13 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Corridor5: + // The data has been exported from the gallery Nether, area index 65, ID 330, created by xoft + { + // Size: + 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 2\n" /* netherbrickstairs */ + "d:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "aaaaa" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "ababa" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "ababa" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "ababa" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "ababa" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "ababa" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "ababa" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "ccccc" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "ddddd", + + // Connectors: + "1: 4, 1, 2: 5\n" /* Type 1, direction X+ */ + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 4, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 500, + + // DepthWeight: + "6:0|12:0|18:0", + + // AddWeightIfSame: + 500, + + // MoveToGround: + false, + }, // Corridor5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CorridorCorner5: + // The data has been exported from the gallery Nether, area index 10, ID 40, created by xoft + { + // Size: + 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 5, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 2\n" /* netherbrickstairs */ + "d:114: 0\n" /* netherbrickstairs */ + "e:114: 3\n" /* netherbrickstairs */ + "f:114: 1\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaa" + /* 5 */ "aaaaa......" + /* 6 */ "aaaaa......" + /* 7 */ "aaaaa......" + /* 8 */ "aaaaa......" + /* 9 */ "aaaaa......" + /* 10 */ "aaaaa......" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "a.........." + /* 2 */ "a.........." + /* 3 */ "a.........." + /* 4 */ "a...aaaaaaa" + /* 5 */ "a...a......" + /* 6 */ "a...a......" + /* 7 */ "a...a......" + /* 8 */ "a...a......" + /* 9 */ "a...a......" + /* 10 */ "a...a......" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "b.........." + /* 2 */ "a.........." + /* 3 */ "b.........." + /* 4 */ "a...abababa" + /* 5 */ "b...b......" + /* 6 */ "a...a......" + /* 7 */ "b...b......" + /* 8 */ "a...a......" + /* 9 */ "b...b......" + /* 10 */ "a...a......" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "b.........." + /* 2 */ "a.........." + /* 3 */ "b.........." + /* 4 */ "a...abababa" + /* 5 */ "b...b......" + /* 6 */ "a...a......" + /* 7 */ "b...b......" + /* 8 */ "a...a......" + /* 9 */ "b...b......" + /* 10 */ "a...a......" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "b.........." + /* 2 */ "a.........." + /* 3 */ "b.........." + /* 4 */ "a...abababa" + /* 5 */ "b...b......" + /* 6 */ "a...a......" + /* 7 */ "b...b......" + /* 8 */ "a...a......" + /* 9 */ "b...b......" + /* 10 */ "a...a......" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "ccccccccccc" + /* 1 */ "daaaaaaaaaa" + /* 2 */ "daaaaaaaaaa" + /* 3 */ "daaaaaaaaaa" + /* 4 */ "daaaeeeeeee" + /* 5 */ "daaaf......" + /* 6 */ "daaaf......" + /* 7 */ "daaaf......" + /* 8 */ "daaaf......" + /* 9 */ "daaaf......" + /* 10 */ "daaaf......", + + // Connectors: + "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */ + "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */ + "-1: 2, 1, 10: 3\n" /* Type -1, direction Z+ */ + "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // CorridorCorner5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CorridorCornerChest5: + // The data has been exported from the gallery Nether, area index 42, ID 293, created by STR_Warrior + { + // Size: + 11, 6, 11, // SizeX = 11, SizeY = 6, SizeZ = 11 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 5, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b: 54: 5\n" /* chest */ + "c:113: 0\n" /* netherbrickfence */ + "d:114: 0\n" /* netherbrickstairs */ + "e:114: 2\n" /* netherbrickstairs */ + "f:114: 1\n" /* netherbrickstairs */ + "g:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaa" + /* 5 */ "aaaaammmmmm" + /* 6 */ "aaaaammmmmm" + /* 7 */ "aaaaammmmmm" + /* 8 */ "aaaaammmmmm" + /* 9 */ "aaaaammmmmm" + /* 10 */ "aaaaammmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "ab........." + /* 2 */ "a.........." + /* 3 */ "a.........." + /* 4 */ "a...aaaaaaa" + /* 5 */ "a...ammmmmm" + /* 6 */ "a...ammmmmm" + /* 7 */ "a...ammmmmm" + /* 8 */ "a...ammmmmm" + /* 9 */ "a...ammmmmm" + /* 10 */ "a...ammmmmm" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "acacacacaca" + /* 1 */ "c.........." + /* 2 */ "a.........." + /* 3 */ "c.........." + /* 4 */ "a...acacaca" + /* 5 */ "c...cmmmmmm" + /* 6 */ "a...ammmmmm" + /* 7 */ "c...cmmmmmm" + /* 8 */ "a...ammmmmm" + /* 9 */ "c...cmmmmmm" + /* 10 */ "a...ammmmmm" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "acacacacaca" + /* 1 */ "c.........." + /* 2 */ "a.........." + /* 3 */ "c.........." + /* 4 */ "a...acacaca" + /* 5 */ "c...cmmmmmm" + /* 6 */ "a...ammmmmm" + /* 7 */ "c...cmmmmmm" + /* 8 */ "a...ammmmmm" + /* 9 */ "c...cmmmmmm" + /* 10 */ "a...ammmmmm" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "acacacacaca" + /* 1 */ "c.........." + /* 2 */ "a.........." + /* 3 */ "c.........." + /* 4 */ "a...acacaca" + /* 5 */ "c...cmmmmmm" + /* 6 */ "a...ammmmmm" + /* 7 */ "c...cmmmmmm" + /* 8 */ "a...ammmmmm" + /* 9 */ "c...cmmmmmm" + /* 10 */ "a...ammmmmm" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "deeeeeeeeee" + /* 1 */ "daaaaaaaaaa" + /* 2 */ "daaaaaaaaaa" + /* 3 */ "daaaaaaaaaa" + /* 4 */ "daaafgggggg" + /* 5 */ "daaafmmmmmm" + /* 6 */ "daaafmmmmmm" + /* 7 */ "daaafmmmmmm" + /* 8 */ "daaafmmmmmm" + /* 9 */ "daaafmmmmmm" + /* 10 */ "daaafmmmmmm", + + // Connectors: + "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */ + "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */ + "-1: 2, 1, 10: 3\n" /* Type -1, direction Z+ */ + "-1: 10, 1, 2: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // CorridorCornerChest5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CorridorCrossing: + // The data has been exported from the gallery Nether, area index 63, ID 328, created by xoft + { + // Size: + 9, 6, 9, // SizeX = 9, SizeY = 6, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 8, 5, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 0\n" /* netherbrickstairs */ + "d:114: 1\n" /* netherbrickstairs */ + "e:114: 2\n" /* netherbrickstairs */ + "f:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "mmaaaaamm" + /* 1 */ "mmaaaaamm" + /* 2 */ "aaaaaaaaa" + /* 3 */ "aaaaaaaaa" + /* 4 */ "aaaaaaaaa" + /* 5 */ "aaaaaaaaa" + /* 6 */ "aaaaaaaaa" + /* 7 */ "mmaaaaamm" + /* 8 */ "mmaaaaamm" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "mma...amm" + /* 1 */ "mma...amm" + /* 2 */ "aaa...aaa" + /* 3 */ "........." + /* 4 */ "........." + /* 5 */ "........." + /* 6 */ "aaa...aaa" + /* 7 */ "mma...amm" + /* 8 */ "mma...amm" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "mma...amm" + /* 1 */ "mmb...bmm" + /* 2 */ "aba...aba" + /* 3 */ "........." + /* 4 */ "........." + /* 5 */ "........." + /* 6 */ "aba...aba" + /* 7 */ "mmb...bmm" + /* 8 */ "mma...amm" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "mma...amm" + /* 1 */ "mmb...bmm" + /* 2 */ "aba...aba" + /* 3 */ "........." + /* 4 */ "........." + /* 5 */ "........." + /* 6 */ "aba...aba" + /* 7 */ "mmb...bmm" + /* 8 */ "mma...amm" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "mma...amm" + /* 1 */ "mmb...bmm" + /* 2 */ "aba...aba" + /* 3 */ "........." + /* 4 */ "........." + /* 5 */ "........." + /* 6 */ "aba...aba" + /* 7 */ "mmb...bmm" + /* 8 */ "mma...amm" + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "mmcaaadmm" + /* 1 */ "mmcaaadmm" + /* 2 */ "eeeaaaeee" + /* 3 */ "aaaaaaaaa" + /* 4 */ "aaaaaaaaa" + /* 5 */ "aaaaaaaaa" + /* 6 */ "ffcaaadff" + /* 7 */ "mmcaaadmm" + /* 8 */ "mmcaaadmm", + + // Connectors: + "1: 8, 1, 4: 5\n" /* Type 1, direction X+ */ + "1: 4, 1, 0: 2\n" /* Type 1, direction Z- */ + "1: 4, 1, 8: 3\n" /* Type 1, direction Z+ */ + "1: 0, 1, 4: 4\n" /* Type 1, direction X- */ + "-1: 8, 1, 4: 5\n" /* Type -1, direction X+ */ + "-1: 4, 1, 8: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */ + "-1: 4, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -50, + + // MoveToGround: + false, + }, // CorridorCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CorridorStairs: + // The data has been exported from the gallery Nether, area index 12, ID 42, created by xoft + { + // Size: + 9, 13, 5, // SizeX = 9, SizeY = 13, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 8, 12, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 0\n" /* netherbrickstairs */ + "c:113: 0\n" /* netherbrickfence */ + "d:114: 2\n" /* netherbrickstairs */ + "e:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaaaaaa" + /* 2 */ "aaaaaaaaa" + /* 3 */ "aaaaaaaaa" + /* 4 */ "aaaaaaaaa" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ ".baaaaaaa" + /* 2 */ ".baaaaaaa" + /* 3 */ ".baaaaaaa" + /* 4 */ "aaaaaaaaa" + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "acaaaaaaa" + /* 1 */ "..baaaaaa" + /* 2 */ "..baaaaaa" + /* 3 */ "..baaaaaa" + /* 4 */ "acaaaaaaa" + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "acaaaaaaa" + /* 1 */ "...baaaaa" + /* 2 */ "...baaaaa" + /* 3 */ "...baaaaa" + /* 4 */ "acaaaaaaa" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "acacaaaaa" + /* 1 */ "....baaaa" + /* 2 */ "....baaaa" + /* 3 */ "....baaaa" + /* 4 */ "acacaaaaa" + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "aaacaaaaa" + /* 1 */ ".....baaa" + /* 2 */ ".....baaa" + /* 3 */ ".....baaa" + /* 4 */ "aaacaaaaa" + + // Level 6 + /* z\x* 012345678 */ + /* 0 */ "daacacaaa" + /* 1 */ "a.....baa" + /* 2 */ "a.....baa" + /* 3 */ "a.....baa" + /* 4 */ "eaacacaaa" + + // Level 7 + /* z\x* 012345678 */ + /* 0 */ "mdaaacaaa" + /* 1 */ "ma.....ba" + /* 2 */ "ma.....ba" + /* 3 */ "ma.....ba" + /* 4 */ "meaaacaaa" + + // Level 8 + /* z\x* 012345678 */ + /* 0 */ "mmdaacaca" + /* 1 */ "mma......" + /* 2 */ "mma......" + /* 3 */ "mma......" + /* 4 */ "mmeaacaca" + + // Level 9 + /* z\x* 012345678 */ + /* 0 */ "mmmdaaaca" + /* 1 */ "mmma....." + /* 2 */ "mmma....." + /* 3 */ "mmma....." + /* 4 */ "mmmeaaaca" + + // Level 10 + /* z\x* 012345678 */ + /* 0 */ "mmmmdaaca" + /* 1 */ "mmmma...." + /* 2 */ "mmmma...." + /* 3 */ "mmmma...." + /* 4 */ "mmmmeaaca" + + // Level 11 + /* z\x* 012345678 */ + /* 0 */ "mmmmmdaaa" + /* 1 */ "mmmmma..." + /* 2 */ "mmmmma..." + /* 3 */ "mmmmma..." + /* 4 */ "mmmmmeaaa" + + // Level 12 + /* z\x* 012345678 */ + /* 0 */ "mmmmmmddd" + /* 1 */ "mmmmmmaaa" + /* 2 */ "mmmmmmaaa" + /* 3 */ "mmmmmmaaa" + /* 4 */ "mmmmmmeee", + + // Connectors: + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "1: 8, 8, 2: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */ + "-1: 8, 8, 2: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 1000, + + // DepthWeight: + "0:0|2:0|4:0|6:0|8:0|10:0|12:0|14:0|16:0|18:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // CorridorStairs + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // DarkCorridor: + // The data has been exported from the gallery Nether, area index 3, ID 30, created by STR_Warrior + { + // Size: + 14, 6, 5, // SizeX = 14, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 13, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 2\n" /* netherbrickstairs */ + "d:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "aaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "aaaaaaaaaaaaaa" + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ ".............." + /* 4 */ "aaaaaaaaaaaaaa" + + // Level 2 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "aabaaaaaaaabaa" + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ ".............." + /* 4 */ "aabaaaaaaaabaa" + + // Level 3 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "aabaaaaaaaabaa" + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ ".............." + /* 4 */ "aabaaaaaaaabaa" + + // Level 4 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "aabaaaaaaaabaa" + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ ".............." + /* 4 */ "aabaaaaaaaabaa" + + // Level 5 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "cccccccccccccc" + /* 1 */ "aaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaa" + /* 4 */ "dddddddddddddd", + + // Connectors: + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "1: 13, 1, 2: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */ + "-1: 13, 1, 2: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // DarkCorridor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LavaStaircase: + // The data has been exported from the gallery Nether, area index 28, ID 278, created by Aloe_vera + { + // Size: + 15, 11, 15, // SizeX = 15, SizeY = 11, SizeZ = 15 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 10, 14, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c: 10: 0\n" /* lava */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaa...aaaa" + /* 1 */ "aaaaa.........a" + /* 2 */ "aaaaa.........a" + /* 3 */ "aaaaab........a" + /* 4 */ "accca...aaaa..a" + /* 5 */ "accca...acca..a" + /* 6 */ "acccaaaaacca..a" + /* 7 */ "acccccccccca..a" + /* 8 */ "acccaaaaacca..a" + /* 9 */ "accca...acca..a" + /* 10 */ "accca...aaaa..a" + /* 11 */ "aaaaab........a" + /* 12 */ "aaaaa.........a" + /* 13 */ "aaaaa.........a" + /* 14 */ "aaaaaaaa...aaaa" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaa...aaaa" + /* 1 */ "aaaa..........a" + /* 2 */ "aaaa..........a" + /* 3 */ "aaaabb........a" + /* 4 */ "aaaa..........a" + /* 5 */ "a.............a" + /* 6 */ "a.............a" + /* 7 */ "a.............a" + /* 8 */ "a.............a" + /* 9 */ "a.............a" + /* 10 */ "aaaa..........a" + /* 11 */ "aaaabb........a" + /* 12 */ "aaaa..........a" + /* 13 */ "aaaa..........a" + /* 14 */ "aaaaaaaa...aaaa" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaa...aaaa" + /* 1 */ "a.............a" + /* 2 */ "a.............a" + /* 3 */ "a..bb.........a" + /* 4 */ "aaaa..........a" + /* 5 */ "aaaa..........a" + /* 6 */ "a.............a" + /* 7 */ "a.............a" + /* 8 */ "a.............a" + /* 9 */ "aaaa..........a" + /* 10 */ "aaaa..........a" + /* 11 */ "a..bb.........a" + /* 12 */ "a.............a" + /* 13 */ "a.............a" + /* 14 */ "aaaaaaaa...aaaa" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaa...aaaa" + /* 1 */ "a.............a" + /* 2 */ "a.............a" + /* 3 */ "a..b..........a" + /* 4 */ "a..b..........a" + /* 5 */ "aaaa..........a" + /* 6 */ "aaaa..........a" + /* 7 */ "a.............a" + /* 8 */ "aaaa..........a" + /* 9 */ "aaaa..........a" + /* 10 */ "a..b..........a" + /* 11 */ "a..b..........a" + /* 12 */ "a.............a" + /* 13 */ "a.............a" + /* 14 */ "aaaaaaaa...aaaa" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "a.............a" + /* 2 */ "a.............a" + /* 3 */ "a.............a" + /* 4 */ "a..b..........a" + /* 5 */ "a..b..........a" + /* 6 */ "aaaa..........a" + /* 7 */ "aaaa..........a" + /* 8 */ "aaaa..........a" + /* 9 */ "a..b..........a" + /* 10 */ "a..b..........a" + /* 11 */ "a.............a" + /* 12 */ "a.............a" + /* 13 */ "a.............a" + /* 14 */ "aaaaaaaaaaaaaaa" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "a.............a" + /* 2 */ "a.............a" + /* 3 */ "a.............a" + /* 4 */ "a.............a" + /* 5 */ "a..b..........a" + /* 6 */ "...b..........a" + /* 7 */ "...b..........a" + /* 8 */ "...b..........a" + /* 9 */ "a..b..........a" + /* 10 */ "a.............a" + /* 11 */ "a.............a" + /* 12 */ "a.............a" + /* 13 */ "a.............a" + /* 14 */ "aaaaaaaaaaaaaaa" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aababababababaa" + /* 1 */ "a.............a" + /* 2 */ "b.............b" + /* 3 */ "a.............a" + /* 4 */ "b.............b" + /* 5 */ "a.............a" + /* 6 */ "..............b" + /* 7 */ "..............a" + /* 8 */ "..............b" + /* 9 */ "a.............a" + /* 10 */ "b.............b" + /* 11 */ "a.............a" + /* 12 */ "b.............b" + /* 13 */ "a.............a" + /* 14 */ "aababababababaa" + + // Level 8 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aababababababaa" + /* 1 */ "a.............a" + /* 2 */ "b.............b" + /* 3 */ "a.............a" + /* 4 */ "b.............b" + /* 5 */ "a.............a" + /* 6 */ "..............b" + /* 7 */ "..............a" + /* 8 */ "..............b" + /* 9 */ "a.............a" + /* 10 */ "b.............b" + /* 11 */ "a.............a" + /* 12 */ "b.............b" + /* 13 */ "a.............a" + /* 14 */ "aababababababaa" + + // Level 9 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aababababababaa" + /* 1 */ "a.............a" + /* 2 */ "b.............b" + /* 3 */ "a.............a" + /* 4 */ "b.............b" + /* 5 */ "a.............a" + /* 6 */ "..............b" + /* 7 */ "..............a" + /* 8 */ "..............b" + /* 9 */ "a.............a" + /* 10 */ "b.............b" + /* 11 */ "a.............a" + /* 12 */ "b.............b" + /* 13 */ "a.............a" + /* 14 */ "aababababababaa" + + // Level 10 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaa", + + // Connectors: + "1: 0, 6, 7: 4\n" /* Type 1, direction X- */ + "1: 9, 1, 14: 3\n" /* Type 1, direction Z+ */ + "1: 9, 1, 0: 2\n" /* Type 1, direction Z- */ + "-1: 0, 6, 7: 4\n" /* Type -1, direction X- */ + "-1: 9, 1, 14: 3\n" /* Type -1, direction Z+ */ + "-1: 9, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // LavaStaircase + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LavaStaircaseBig: + // The data has been exported from the gallery Nether, area index 31, ID 282, created by STR_Warrior + { + // Size: + 12, 15, 15, // SizeX = 12, SizeY = 15, SizeZ = 15 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 11, 14, 14, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b: 10: 0\n" /* lava */ + "c:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaa" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaa" + /* 4 */ "abbbbbaaaaaa" + /* 5 */ "abbbbbbaaaaa" + /* 6 */ "abbbbbba...." + /* 7 */ "abbbbbba...." + /* 8 */ "abbbbbba...." + /* 9 */ "abbbbbbaaaaa" + /* 10 */ "abbbbb.aaaaa" + /* 11 */ "aaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaa" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaa" + /* 4 */ "abbbbbaaaaaa" + /* 5 */ "abbbbbba...a" + /* 6 */ "abbbbbba...." + /* 7 */ "abbbbbba...." + /* 8 */ "abbbbbba...." + /* 9 */ "abbbbbba...a" + /* 10 */ "abbbbb.aaaaa" + /* 11 */ "aaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaa" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaa" + /* 4 */ "abbbbbaa...a" + /* 5 */ "abbbbbba...a" + /* 6 */ "abbbbbba...." + /* 7 */ "abbbbbba...." + /* 8 */ "abbbbbba...." + /* 9 */ "abbbbbba...a" + /* 10 */ "abbbbbaa...a" + /* 11 */ "aaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaa" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaa......a" + /* 2 */ "aaaaa......a" + /* 3 */ "aaaaacc....a" + /* 4 */ "a.....cc...a" + /* 5 */ "a......c...a" + /* 6 */ "a......c...a" + /* 7 */ "a......c...a" + /* 8 */ "a......c...a" + /* 9 */ "a......c...a" + /* 10 */ "a.....cc...a" + /* 11 */ "aaaaacc....a" + /* 12 */ "aaaaa......a" + /* 13 */ "aaaaa......a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 5 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaa.......a" + /* 2 */ "aaaa.......a" + /* 3 */ "aaaacc.....a" + /* 4 */ "aaaa.......a" + /* 5 */ "a..........a" + /* 6 */ "a..........a" + /* 7 */ "a..........a" + /* 8 */ "a..........a" + /* 9 */ "a..........a" + /* 10 */ "aaaa.......a" + /* 11 */ "aaaacc.....a" + /* 12 */ "aaaa.......a" + /* 13 */ "aaaa.......a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 6 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..cc......a" + /* 4 */ "aaaa.......a" + /* 5 */ "aaaa.......a" + /* 6 */ "a..........a" + /* 7 */ "a..........a" + /* 8 */ "a..........a" + /* 9 */ "aaaa.......a" + /* 10 */ "aaaa.......a" + /* 11 */ "a..cc......a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 7 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..c.......a" + /* 4 */ "a..c.......a" + /* 5 */ "aaaa.......a" + /* 6 */ "aaaa.......a" + /* 7 */ "a..........a" + /* 8 */ "aaaa.......a" + /* 9 */ "aaaa.......a" + /* 10 */ "a..c.......a" + /* 11 */ "a..c.......a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 8 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..........a" + /* 4 */ "a..c.......a" + /* 5 */ "a..c.......a" + /* 6 */ "aaaa.......a" + /* 7 */ "aaaa.......a" + /* 8 */ "aaaa.......a" + /* 9 */ "a..c.......a" + /* 10 */ "a..c.......a" + /* 11 */ "a..........a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 9 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..........a" + /* 4 */ "a..........a" + /* 5 */ "a..c.......a" + /* 6 */ "...c.......a" + /* 7 */ "...c.......a" + /* 8 */ "...c.......a" + /* 9 */ "a..c.......a" + /* 10 */ "a..........a" + /* 11 */ "a..........a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 10 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..........a" + /* 4 */ "a..........a" + /* 5 */ "a..........a" + /* 6 */ "...........a" + /* 7 */ "...........a" + /* 8 */ "...........a" + /* 9 */ "a..........a" + /* 10 */ "a..........a" + /* 11 */ "a..........a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 11 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..........a" + /* 4 */ "a..........a" + /* 5 */ "a..........a" + /* 6 */ "...........a" + /* 7 */ "...........a" + /* 8 */ "...........a" + /* 9 */ "a..........a" + /* 10 */ "a..........a" + /* 11 */ "a..........a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 12 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "a..........a" + /* 2 */ "a..........a" + /* 3 */ "a..........a" + /* 4 */ "a..........a" + /* 5 */ "a..........a" + /* 6 */ "a..........a" + /* 7 */ "a..........a" + /* 8 */ "a..........a" + /* 9 */ "a..........a" + /* 10 */ "a..........a" + /* 11 */ "a..........a" + /* 12 */ "a..........a" + /* 13 */ "a..........a" + /* 14 */ "aaaaaaaaaaaa" + + // Level 13 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaa" + + // Level 14 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaaaaaaaa" + /* 1 */ "abbbbbbbbbba" + /* 2 */ "abbbbbbbbbba" + /* 3 */ "abbbbbbbbbba" + /* 4 */ "abbbbbbbbbba" + /* 5 */ "abbbbbbbbbba" + /* 6 */ "abbbbbbbbbba" + /* 7 */ "abbbbbbbbbba" + /* 8 */ "abbbbbbbbbba" + /* 9 */ "abbbbbbbbbba" + /* 10 */ "abbbbbbbbbba" + /* 11 */ "abbbbbbbbbba" + /* 12 */ "abbbbbbbbbba" + /* 13 */ "abbbbbbbbbba" + /* 14 */ "aaaaaaaaaaaa", + + // Connectors: + "1: 11, 1, 7: 5\n" /* Type 1, direction X+ */ + "1: 0, 9, 7: 4\n" /* Type 1, direction X- */ + "-1: 11, 1, 7: 5\n" /* Type -1, direction X+ */ + "-1: 0, 9, 7: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + -1000, + + // MoveToGround: + false, + }, // LavaStaircaseBig + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LavaStairsBridge: + // The data has been exported from the gallery Nether, area index 30, ID 281, created by STR_Warrior + { + // Size: + 16, 12, 15, // SizeX = 16, SizeY = 12, SizeZ = 15 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 15, 11, 14, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c: 10: 0\n" /* lava */ + "d:114: 2\n" /* netherbrickstairs */ + "e:114: 3\n" /* netherbrickstairs */ + "f:114: 7\n" /* netherbrickstairs */ + "g: 44:14\n" /* step */ + "h:114: 6\n" /* netherbrickstairs */ + "i: 44: 6\n" /* step */ + "j:114: 0\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaa...aaaaa" + /* 1 */ "aaaaa..........a" + /* 2 */ "aaaaa..........a" + /* 3 */ "aaaaab.........a" + /* 4 */ "accca...ddd.aaaa" + /* 5 */ "accca...aaa.acca" + /* 6 */ "acccaaaaaaaaacca" + /* 7 */ "acccccccccccccca" + /* 8 */ "acccaaaaaaaaacca" + /* 9 */ "accca...aaa.acca" + /* 10 */ "accca...eee.aaaa" + /* 11 */ "aaaaab.........a" + /* 12 */ "aaaaa..........a" + /* 13 */ "aaaaa..........a" + /* 14 */ "aaaaaaaa...aaaaa" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaa...aaaaa" + /* 1 */ "aaaa...........a" + /* 2 */ "aaaa...........a" + /* 3 */ "aaaabb.........a" + /* 4 */ "aaaa........b..a" + /* 5 */ "a.......ddd....a" + /* 6 */ "a.......fff....a" + /* 7 */ "a.......ggg....a" + /* 8 */ "a.......hhh....a" + /* 9 */ "a.......eee....a" + /* 10 */ "aaaa........b..a" + /* 11 */ "aaaabb.........a" + /* 12 */ "aaaa...........a" + /* 13 */ "aaaa...........a" + /* 14 */ "aaaaaaaa...aaaaa" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaa...aaaaa" + /* 1 */ "a..............a" + /* 2 */ "a..............a" + /* 3 */ "a..bb..........a" + /* 4 */ "aaaa........b..a" + /* 5 */ "aaaa...........a" + /* 6 */ "a..............a" + /* 7 */ "a..............a" + /* 8 */ "a..............a" + /* 9 */ "aaaa...........a" + /* 10 */ "aaaa........b..a" + /* 11 */ "a..bb..........a" + /* 12 */ "a..............a" + /* 13 */ "a..............a" + /* 14 */ "aaaaaaaa...aaaaa" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaabbbaaaaa" + /* 1 */ "a..............a" + /* 2 */ "a..............a" + /* 3 */ "a..b...........a" + /* 4 */ "a..b........b..a" + /* 5 */ "aaaa...........a" + /* 6 */ "aaaa...........a" + /* 7 */ "a..............a" + /* 8 */ "aaaa...........a" + /* 9 */ "aaaa...........a" + /* 10 */ "a..b........b..a" + /* 11 */ "a..b...........a" + /* 12 */ "a..............a" + /* 13 */ "a..............a" + /* 14 */ "aaaaaaaabbbaaaaa" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "a..............a" + /* 2 */ "a..............a" + /* 3 */ "a...........ggga" + /* 4 */ "a..b........iija" + /* 5 */ "a..b........iija" + /* 6 */ "aaaa........iija" + /* 7 */ "aaaa........iija" + /* 8 */ "aaaa........iija" + /* 9 */ "a..b........iija" + /* 10 */ "a..b........iija" + /* 11 */ "a...........ggga" + /* 12 */ "a..............a" + /* 13 */ "a..............a" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "a.............ga" + /* 2 */ "a............iia" + /* 3 */ "a..............a" + /* 4 */ "a..............a" + /* 5 */ "a..b...........a" + /* 6 */ "...b...........a" + /* 7 */ "...b...........a" + /* 8 */ "...b...........a" + /* 9 */ "a..b...........a" + /* 10 */ "a..............a" + /* 11 */ "a..............a" + /* 12 */ "a............iia" + /* 13 */ "a.............ga" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 7 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "a..............a" + /* 2 */ "a..............a" + /* 3 */ "a..............a" + /* 4 */ "a..............a" + /* 5 */ "a..............a" + /* 6 */ "...............a" + /* 7 */ "...............a" + /* 8 */ "...............a" + /* 9 */ "a..............a" + /* 10 */ "a..............a" + /* 11 */ "a..............a" + /* 12 */ "a..............a" + /* 13 */ "a..............a" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 8 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "a..............a" + /* 2 */ "a..............a" + /* 3 */ "a..............a" + /* 4 */ "a..............a" + /* 5 */ "a..............a" + /* 6 */ "...............a" + /* 7 */ "...............a" + /* 8 */ "...............a" + /* 9 */ "a..............a" + /* 10 */ "a..............a" + /* 11 */ "a..............a" + /* 12 */ "a..............a" + /* 13 */ "a..............a" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 9 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "a..............a" + /* 2 */ "a..............a" + /* 3 */ "a..............a" + /* 4 */ "a..............a" + /* 5 */ "a..............a" + /* 6 */ "a..............a" + /* 7 */ "a..............a" + /* 8 */ "a..............a" + /* 9 */ "a..............a" + /* 10 */ "a..............a" + /* 11 */ "a..............a" + /* 12 */ "a..............a" + /* 13 */ "a..............a" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 10 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "aaaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaaaaa" + /* 13 */ "aaaaaaaaaaaaaaaa" + /* 14 */ "aaaaaaaaaaaaaaaa" + + // Level 11 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "abbaabbaabbaabba" + /* 1 */ "b..............b" + /* 2 */ "a..............a" + /* 3 */ "b..............b" + /* 4 */ "a..............a" + /* 5 */ "b..............b" + /* 6 */ "a..............a" + /* 7 */ "b..............b" + /* 8 */ "a..............a" + /* 9 */ "b..............b" + /* 10 */ "a..............a" + /* 11 */ "b..............b" + /* 12 */ "a..............a" + /* 13 */ "b..............b" + /* 14 */ "abbaabbaabbaabba", + + // Connectors: + "", + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // LavaStairsBridge + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MidStaircase: + // The data has been exported from the gallery Nether, area index 23, ID 165, created by Aloe_vera + { + // Size: + 13, 8, 13, // SizeX = 13, SizeY = 8, SizeZ = 13 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 7, 12, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b: 88: 0\n" /* soulsand */ + "c:115: 7\n" /* netherwartblock */ + "d:114: 3\n" /* netherbrickstairs */ + "e:114: 0\n" /* netherbrickstairs */ + "f:114: 1\n" /* netherbrickstairs */ + "g:114: 2\n" /* netherbrickstairs */ + "h: 10: 0\n" /* lava */ + "i:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaabbbbbaaaa" + /* 4 */ "aaaabbbbbaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaabbbbbaaaa" + /* 9 */ "aaaabbbbbaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaacccccaaaa" + /* 4 */ "addecccccfdda" + /* 5 */ "...eaaaaad..." + /* 6 */ "...eaaaaa...." + /* 7 */ "...eaaaaag..." + /* 8 */ "agggcccccfgga" + /* 9 */ "aaaacccccaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aha.......aha" + /* 2 */ "aaa.......aaa" + /* 3 */ "a...........a" + /* 4 */ "a...........a" + /* 5 */ "....eaaaa...." + /* 6 */ "....eaaaa...." + /* 7 */ "....eaaaa...." + /* 8 */ "a...........a" + /* 9 */ "a...........a" + /* 10 */ "aaa.......aaa" + /* 11 */ "aha.......aha" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaiiaaaiiaaa" + /* 1 */ "a...........a" + /* 2 */ "a...........a" + /* 3 */ "a...........a" + /* 4 */ "a...........a" + /* 5 */ ".....eaaa...." + /* 6 */ ".....eaaa...." + /* 7 */ ".....eaaa...." + /* 8 */ "a...........a" + /* 9 */ "a...........a" + /* 10 */ "a...........a" + /* 11 */ "a...........a" + /* 12 */ "aaaiiaaaiiaaa" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaiiaaaiiaaa" + /* 1 */ "a...........a" + /* 2 */ "a...........a" + /* 3 */ "a...........a" + /* 4 */ "a...........a" + /* 5 */ "......eaa...." + /* 6 */ "......eaa...." + /* 7 */ "......eaa...." + /* 8 */ "a...........a" + /* 9 */ "a...........a" + /* 10 */ "a...........a" + /* 11 */ "a...........a" + /* 12 */ "aaaiiaaaiiaaa" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "a...........a" + /* 2 */ "a...........a" + /* 3 */ "a...........a" + /* 4 */ "a...........a" + /* 5 */ "a......ea...a" + /* 6 */ "a......ea...a" + /* 7 */ "a......ea...a" + /* 8 */ "a...........a" + /* 9 */ "a...........a" + /* 10 */ "a...........a" + /* 11 */ "a...........a" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaa....eaaaa" + /* 6 */ "aaaa....eaaaa" + /* 7 */ "aaaa....eaaaa" + /* 8 */ "aaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 7 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "iaiaiaiaiaiai" + /* 1 */ "a...........a" + /* 2 */ "i...........i" + /* 3 */ "a...........a" + /* 4 */ "i...........i" + /* 5 */ "a...........a" + /* 6 */ "i...........i" + /* 7 */ "a...........a" + /* 8 */ "i...........i" + /* 9 */ "a...........a" + /* 10 */ "i...........i" + /* 11 */ "a...........a" + /* 12 */ "iaiaiaiaiaiai", + + // Connectors: + "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */ + "1: 0, 1, 6: 4\n" /* Type 1, direction X- */ + "-1: 12, 1, 6: 5\n" /* Type -1, direction X+ */ + "-1: 0, 1, 6: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -1000, + + // MoveToGround: + false, + }, // MidStaircase + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // StairsToOpen1: + // The data has been exported from the gallery Nether, area index 27, ID 277, created by Aloe_vera + { + // Size: + 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 19, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a.aaaaa" + /* 6 */ "aabaaba" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a..aaaa" + /* 6 */ "aabaaba" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "aabbbaa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a...aaa" + /* 6 */ "aabaaba" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "a....aa" + /* 6 */ "aaaaaaa" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a......" + /* 3 */ "a......" + /* 4 */ "a......" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "m.....m" + /* 2 */ "m......" + /* 3 */ "m......" + /* 4 */ "m......" + /* 5 */ "m.....m" + /* 6 */ "mmmmmmm" + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "m.....m" + /* 2 */ "m......" + /* 3 */ "m......" + /* 4 */ "m......" + /* 5 */ "m.....m" + /* 6 */ "mmmmmmm", + + // Connectors: + "0: 6, 7, 3: 5\n" /* Type 0, direction X+ */ + "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|3:0|5:0|7:0|9:0|11:0|13:0|15:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // StairsToOpen1 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // StairsToOpen2: + // The data has been exported from the gallery Nether, area index 8, ID 35, created by xoft + { + // Size: + 7, 10, 7, // SizeX = 7, SizeY = 10, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 19, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a.aaaaa" + /* 6 */ "aabaaba" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a..aaaa" + /* 6 */ "aabaaba" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "aabbbaa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a...aaa" + /* 6 */ "aabaaba" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "a....aa" + /* 6 */ "aaaaaaa" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "......a" + /* 3 */ "......a" + /* 4 */ "......a" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "m.....m" + /* 2 */ "......m" + /* 3 */ "......m" + /* 4 */ "......m" + /* 5 */ "m.....m" + /* 6 */ "mmmmmmm" + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "m.....m" + /* 2 */ "......m" + /* 3 */ "......m" + /* 4 */ "......m" + /* 5 */ "m.....m" + /* 6 */ "mmmmmmm", + + // Connectors: + "0: 0, 7, 3: 4\n" /* Type 0, direction X- */ + "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|3:0|5:0|7:0|9:0|11:0|13:0|15:0", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // StairsToOpen2 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Tee2x4: + // The data has been exported from the gallery Nether, area index 40, ID 291, created by Aloe_vera + { + // Size: + 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 0\n" /* netherbrickstairs */ + "d:114: 1\n" /* netherbrickstairs */ + "e:114: 2\n" /* netherbrickstairs */ + "f:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmaaaaammmm" + /* 1 */ "mmmmaaaaammmm" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmma...ammmm" + /* 2 */ "aaaaa...aaaaa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "aaaaaaaaaaaaa" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "ababa...ababa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "ababababababa" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "ababa...ababa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "ababababababa" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "ababa...ababa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "ababababababa" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmcaaadmmmm" + /* 1 */ "mmmmcaaadmmmm" + /* 2 */ "eeeecaaadeeee" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "fffffffffffff", + + // Connectors: + "1: 0, 1, 4: 4\n" /* Type 1, direction X- */ + "1: 6, 1, 0: 2\n" /* Type 1, direction Z- */ + "1: 12, 1, 4: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 4: 4\n" /* Type -1, direction X- */ + "-1: 12, 1, 4: 5\n" /* Type -1, direction X+ */ + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // Tee2x4 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Tee4x4: + // The data has been exported from the gallery Nether, area index 41, ID 292, created by Aloe_vera + { + // Size: + 13, 6, 9, // SizeX = 13, SizeY = 6, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 5, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 0\n" /* netherbrickstairs */ + "d:114: 1\n" /* netherbrickstairs */ + "e:114: 2\n" /* netherbrickstairs */ + "f:114: 3\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmaaaaammmm" + /* 1 */ "mmmmaaaaammmm" + /* 2 */ "mmmmaaaaammmm" + /* 3 */ "mmmmaaaaammmm" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmma...ammmm" + /* 2 */ "mmmma...ammmm" + /* 3 */ "mmmma...ammmm" + /* 4 */ "aaaaa...aaaaa" + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "aaaaaaaaaaaaa" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "mmmma...ammmm" + /* 3 */ "mmmmb...bmmmm" + /* 4 */ "ababa...ababa" + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "ababababababa" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "mmmma...ammmm" + /* 3 */ "mmmmb...bmmmm" + /* 4 */ "ababa...ababa" + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "ababababababa" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "mmmma...ammmm" + /* 3 */ "mmmmb...bmmmm" + /* 4 */ "ababa...ababa" + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "ababababababa" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmmcaaadmmmm" + /* 1 */ "mmmmcaaadmmmm" + /* 2 */ "mmmmcaaadmmmm" + /* 3 */ "mmmmcaaadmmmm" + /* 4 */ "eeeecaaadeeee" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "fffffffffffff", + + // Connectors: + "1: 0, 1, 6: 4\n" /* Type 1, direction X- */ + "1: 6, 1, 0: 2\n" /* Type 1, direction Z- */ + "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */ + "-1: 0, 1, 6: 4\n" /* Type -1, direction X- */ + "-1: 6, 1, 0: 2\n" /* Type -1, direction Z- */ + "-1: 12, 1, 6: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // Tee4x4 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // TinyCorridorCorner: + // The data has been exported from the gallery Nether, area index 66, ID 331, created by xoft + { + // Size: + 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "c:114: 2\n" /* netherbrickstairs */ + "d:114: 1\n" /* netherbrickstairs */ + "e:114: 0\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "....a" + /* 2 */ "....a" + /* 3 */ "....a" + /* 4 */ "a...a" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "ababa" + /* 1 */ "....b" + /* 2 */ "....a" + /* 3 */ "....b" + /* 4 */ "a...a" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "ababa" + /* 1 */ "....b" + /* 2 */ "....a" + /* 3 */ "....b" + /* 4 */ "a...a" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "ababa" + /* 1 */ "....b" + /* 2 */ "....a" + /* 3 */ "....b" + /* 4 */ "a...a" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "ccccc" + /* 1 */ "aaaad" + /* 2 */ "aaaad" + /* 3 */ "aaaad" + /* 4 */ "eaaad", + + // Connectors: + "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */ + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -50, + + // MoveToGround: + false, + }, // TinyCorridorCorner + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // TinyCorridorCornerChest: + // The data has been exported from the gallery Nether, area index 67, ID 332, created by Aloe_vera + { + // Size: + 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b: 54: 4\n" /* chest */ + "c:113: 0\n" /* netherbrickfence */ + "d:114: 2\n" /* netherbrickstairs */ + "e:114: 1\n" /* netherbrickstairs */ + "f:114: 0\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "....a" + /* 2 */ "...ba" + /* 3 */ "....a" + /* 4 */ "a...a" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "acaca" + /* 1 */ "....c" + /* 2 */ "....a" + /* 3 */ "....c" + /* 4 */ "a...a" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "acaca" + /* 1 */ "....c" + /* 2 */ "....a" + /* 3 */ "....c" + /* 4 */ "a...a" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "acaca" + /* 1 */ "....c" + /* 2 */ "....a" + /* 3 */ "....c" + /* 4 */ "a...a" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "ddddd" + /* 1 */ "aaaae" + /* 2 */ "aaaae" + /* 3 */ "aaaae" + /* 4 */ "faaae", + + // Connectors: + "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */ + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // TinyCorridorCornerChest + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // TinyCorridorCrossing: + // The data has been exported from the gallery Nether, area index 64, ID 329, created by xoft + { + // Size: + 5, 6, 5, // SizeX = 5, SizeY = 6, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 5, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:114: 2\n" /* netherbrickstairs */ + "c:114: 0\n" /* netherbrickstairs */ + "d:114: 1\n" /* netherbrickstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "a...a" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "a...a" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "a...a" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "a...a" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "a...a" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "a...a" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "a...a" + /* 1 */ "....." + /* 2 */ "....." + /* 3 */ "....." + /* 4 */ "a...a" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "baaab" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "caaad", + + // Connectors: + "1: 4, 1, 2: 5\n" /* Type 1, direction X+ */ + "1: 2, 1, 4: 3\n" /* Type 1, direction Z+ */ + "1: 0, 1, 2: 4\n" /* Type 1, direction X- */ + "1: 2, 1, 0: 2\n" /* Type 1, direction Z- */ + "-1: 4, 1, 2: 5\n" /* Type -1, direction X+ */ + "-1: 2, 1, 4: 3\n" /* Type -1, direction Z+ */ + "-1: 0, 1, 2: 4\n" /* Type -1, direction X- */ + "-1: 2, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:200|2:400|3:0|4:500", + + // AddWeightIfSame: + -50, + + // MoveToGround: + false, + }, // TinyCorridorCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Turret: + // The data has been exported from the gallery Nether, area index 7, ID 34, created by xoft + { + // Size: + 7, 7, 7, // SizeX = 7, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 16, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "a.....a" + /* 6 */ "aa...aa" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "a.....a" + /* 6 */ "aa...aa" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "a.....a" + /* 6 */ "aa...aa" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "aabbbaa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "b.....b" + /* 4 */ "b.....b" + /* 5 */ "a.....a" + /* 6 */ "aabbbaa" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "0: 0, 1, 3: 4\n" /* Type 0, direction X- */ + "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */ + "0: 6, 1, 3: 5\n" /* Type 0, direction X+ */ + "0: 3, 1, 6: 3\n" /* Type 0, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -99, + + // MoveToGround: + false, + }, // Turret +}; // g_NetherFortPrefabs + + + + + + +const cPrefab::sDef g_NetherFortStartingPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CentralRoom: + // The data has been exported from the gallery Nether, area index 22, ID 164, created by Aloe_vera + { + // Size: + 13, 9, 13, // SizeX = 13, SizeY = 9, SizeZ = 13 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 8, 12, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:112: 0\n" /* netherbrick */ + "b: 10: 0\n" /* lava */ + "c:113: 0\n" /* netherbrickfence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaa...aaaaa" + /* 1 */ "aaaaa...aaaaa" + /* 2 */ "aa.........aa" + /* 3 */ "aa.........aa" + /* 4 */ "aa.........aa" + /* 5 */ "aa...aaa...aa" + /* 6 */ "aa...aba...aa" + /* 7 */ "aa...aaa...aa" + /* 8 */ "aa.........aa" + /* 9 */ "aa.........aa" + /* 10 */ "aa.........aa" + /* 11 */ "aaaaa...aaaaa" + /* 12 */ "aaaaa...aaaaa" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaa...aaaaa" + /* 1 */ "aaaca...acaaa" + /* 2 */ "aa.........aa" + /* 3 */ "ac.........ca" + /* 4 */ "aa.........aa" + /* 5 */ "ac.........ca" + /* 6 */ "aa.........aa" + /* 7 */ "ac.........ca" + /* 8 */ "aa.........aa" + /* 9 */ "ac.........ca" + /* 10 */ "aa.........aa" + /* 11 */ "aaaca...acaaa" + /* 12 */ "aaaaa...aaaaa" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaa...aaaaa" + /* 1 */ "aaaca...acaaa" + /* 2 */ "aa.........aa" + /* 3 */ "ac.........ca" + /* 4 */ "aa.........aa" + /* 5 */ "ac.........ca" + /* 6 */ "aa.........aa" + /* 7 */ "ac.........ca" + /* 8 */ "aa.........aa" + /* 9 */ "ac.........ca" + /* 10 */ "aa.........aa" + /* 11 */ "aaaca...acaaa" + /* 12 */ "aaaaa...aaaaa" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "acacacccacaca" + /* 1 */ "caaaa...aaaac" + /* 2 */ "aa.........aa" + /* 3 */ "ca.........ac" + /* 4 */ "aa.........aa" + /* 5 */ "ca.........ac" + /* 6 */ "aa.........aa" + /* 7 */ "ca.........ac" + /* 8 */ "aa.........aa" + /* 9 */ "ca.........ac" + /* 10 */ "aa.........aa" + /* 11 */ "caaaa...aaaac" + /* 12 */ "acaca...acaca" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "acacaaaaacaca" + /* 1 */ "caaaaaaaaaaac" + /* 2 */ "aa.........aa" + /* 3 */ "ca.........ac" + /* 4 */ "aa.........aa" + /* 5 */ "ca.........ac" + /* 6 */ "aa.........aa" + /* 7 */ "ca.........ac" + /* 8 */ "aa.........aa" + /* 9 */ "ca.........ac" + /* 10 */ "aa.........aa" + /* 11 */ "caaaaaaaaaaac" + /* 12 */ "acacaaaaacaca" + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 7 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + /* 12 */ "aaaaaaaaaaaaa" + + // Level 8 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "cacacacacacac" + /* 1 */ "a...........a" + /* 2 */ "c...........c" + /* 3 */ "a...........a" + /* 4 */ "c...........c" + /* 5 */ "a...........a" + /* 6 */ "c...........c" + /* 7 */ "a...........a" + /* 8 */ "c...........c" + /* 9 */ "a...........a" + /* 10 */ "c...........c" + /* 11 */ "a...........a" + /* 12 */ "cacacacacacac", + + // Connectors: + "0: 6, 1, 0: 2\n" /* Type 0, direction Z- */ + "1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */ + "-1: 6, 1, 12: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // CentralRoom +}; + + + + + +// The prefab counts: + +const size_t g_NetherFortPrefabsCount = ARRAYCOUNT(g_NetherFortPrefabs); + +const size_t g_NetherFortStartingPrefabsCount = ARRAYCOUNT(g_NetherFortStartingPrefabs); + diff --git a/src/Generating/Prefabs/NetherFortPrefabs.h b/src/Generating/Prefabs/NetherFortPrefabs.h new file mode 100644 index 000000000..04edc2953 --- /dev/null +++ b/src/Generating/Prefabs/NetherFortPrefabs.h @@ -0,0 +1,15 @@ + +// NetherFortPrefabs.h + +// Declares the prefabs in the group NetherFort + +#include "../Prefab.h" + + + + + +extern const cPrefab::sDef g_NetherFortPrefabs[]; +extern const cPrefab::sDef g_NetherFortStartingPrefabs[]; +extern const size_t g_NetherFortPrefabsCount; +extern const size_t g_NetherFortStartingPrefabsCount; diff --git a/src/Generating/Prefabs/PlainsVillagePrefabs.cpp b/src/Generating/Prefabs/PlainsVillagePrefabs.cpp new file mode 100644 index 000000000..f5c5b7a20 --- /dev/null +++ b/src/Generating/Prefabs/PlainsVillagePrefabs.cpp @@ -0,0 +1,6114 @@ + +// PlainsVillagePrefabs.cpp + +// Defines the prefabs in the group PlainsVillage + +// NOTE: This file has been generated automatically by GalExport! +// Any manual changes will be overwritten by the next automatic export! + +#include "Globals.h" +#include "PlainsVillagePrefabs.h" + + + + + +const cPrefab::sDef g_PlainsVillagePrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // BigPlantBed: + // The data has been exported from the gallery Plains, area index 26, ID 70, created by Taugrammaton + { + // Size: + 13, 8, 12, // SizeX = 13, SizeY = 8, SizeZ = 12 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 7, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 5: 0\n" /* wood */ + "c: 13: 0\n" /* gravel */ + "d: 17: 0\n" /* tree */ + "e: 60: 7\n" /* tilleddirt */ + "f: 8: 0\n" /* water */ + "g: 85: 0\n" /* fence */ + "h: 59: 7\n" /* crops */ + "i: 50: 5\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaa" + /* 9 */ "aaaaaaaaaaaaa" + /* 10 */ "aaaaaaaaaaaaa" + /* 11 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "bbbbbbbbbbbbb" + /* 1 */ "bcccccccccccb" + /* 2 */ "bcccccccccccb" + /* 3 */ "bcccccccccccb" + /* 4 */ "bcccccccccccb" + /* 5 */ "bcccccccccccb" + /* 6 */ "bcccccccccccb" + /* 7 */ "bcccccccccccb" + /* 8 */ "bcccccccccccb" + /* 9 */ "bcccccccccccb" + /* 10 */ "bcccccccccccb" + /* 11 */ "bbbbbbbbbbbbb" + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ddddddddddddd" + /* 1 */ "deefeefeefeed" + /* 2 */ "deefeefeefeed" + /* 3 */ "deefeefeefeed" + /* 4 */ "deefeefeefeed" + /* 5 */ "deefeefeefeed" + /* 6 */ "deefeefeefeed" + /* 7 */ "deefeefeefeed" + /* 8 */ "deefeefeefeed" + /* 9 */ "deefeefeefeed" + /* 10 */ "deefeefeefeed" + /* 11 */ "ddddddddddddd" + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "g..g..g..g..g" + /* 1 */ "ghh.h..hh.hhg" + /* 2 */ "ghh..h.hh.hhg" + /* 3 */ "ghh.h..h..hhg" + /* 4 */ "ghh.hh.h..hhg" + /* 5 */ "ghh.h..hh.hhg" + /* 6 */ "ghh.hh.hh.hhg" + /* 7 */ "ghh....h..hhg" + /* 8 */ "ghh..h....hhg" + /* 9 */ "ghh.....h.hhg" + /* 10 */ "ghh.hh.h..hhg" + /* 11 */ "g..g..g..g..g" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "i..i..i..i..i" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "............." + /* 9 */ "............." + /* 10 */ "............." + /* 11 */ "i..i..i..i..i" + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "............." + /* 9 */ "............." + /* 10 */ "............." + /* 11 */ "............." + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "............." + /* 9 */ "............." + /* 10 */ "............." + /* 11 */ "............." + + // Level 7 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ "............." + /* 9 */ "............." + /* 10 */ "............." + /* 11 */ ".............", + + // Connectors: + "-1: 7, 1, 11: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // BigPlantBed + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CobbleHouse10x5Library: + // The data has been exported from the gallery Plains, area index 23, ID 66, created by xoft + { + // Size: + 12, 7, 7, // SizeX = 12, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 12, 6, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 64: 7\n" /* wooddoorblock */ + "f: 53: 3\n" /* woodstairs */ + "g: 53: 1\n" /* woodstairs */ + "h: 85: 0\n" /* fence */ + "i: 53: 0\n" /* woodstairs */ + "j: 53: 2\n" /* woodstairs */ + "k:102: 0\n" /* glasspane */ + "l: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */ + "n: 50: 3\n" /* torch */ + "o: 72: 0\n" /* woodplate */ + "p: 50: 4\n" /* torch */ + "q: 53: 7\n" /* woodstairs */ + "r: 47: 0\n" /* bookshelf */ + "s: 50: 1\n" /* torch */ + "t: 50: 2\n" /* torch */ + "u: 53: 6\n" /* woodstairs */ + "v: 5: 0\n" /* wood */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "mmmmmmmaaamm" + /* 1 */ "maaaaaaaaaam" + /* 2 */ "maaaaaaaaaam" + /* 3 */ "maaaaaaaaaam" + /* 4 */ "maaaaaaaaaam" + /* 5 */ "maaaaaaaaaam" + /* 6 */ "mmmmmmmmmmmm" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ ".......bcd.." + /* 1 */ ".aaaaaaaaaa." + /* 2 */ ".aaaaaaaaaa." + /* 3 */ ".aaaaaaaaaa." + /* 4 */ ".aaaaaaaaaa." + /* 5 */ ".aaaaaaaaaa." + /* 6 */ "............" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".aaaaaaaeaa." + /* 2 */ ".af.ghi...a." + /* 3 */ ".ah.......a." + /* 4 */ ".aj.ghighia." + /* 5 */ ".aaaaaaaaaa." + /* 6 */ "............" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".akkakkalaa." + /* 2 */ ".k..no.n.nk." + /* 3 */ ".ko.......k." + /* 4 */ ".k..po.po.k." + /* 5 */ ".akkakkakka." + /* 6 */ "............" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "jjjjjjjjjjjj" + /* 1 */ "qaaaaaaaaaaq" + /* 2 */ ".arrrrrrrra." + /* 3 */ ".as......ta." + /* 4 */ ".arrrrrrrra." + /* 5 */ "uaaaaaaaaaau" + /* 6 */ "ffffffffffff" + + // Level 5 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "jjjjjjjjjjjj" + /* 2 */ "qvvvvvvvvvvq" + /* 3 */ ".vvvvvvvvvv." + /* 4 */ "uvvvvvvvvvvu" + /* 5 */ "ffffffffffff" + /* 6 */ "............" + + // Level 6 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "jjjjjjjjjjjj" + /* 3 */ "vvvvvvvvvvvv" + /* 4 */ "ffffffffffff" + /* 5 */ "............" + /* 6 */ "............", + + // Connectors: + "-1: 8, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // CobbleHouse10x5Library + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // DoublePlantBed: + // The data has been exported from the gallery Plains, area index 5, ID 20, created by tonibm1999 + { + // Size: + 15, 8, 9, // SizeX = 15, SizeY = 8, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 7, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 2: 0\n" /* grass */ + "c: 17: 0\n" /* tree */ + "d: 60: 7\n" /* tilleddirt */ + "e: 8: 0\n" /* water */ + "f: 50: 5\n" /* torch */ + "g: 59: 7\n" /* crops */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaaaaaa" + /* 3 */ "aaaaaaaaaaaaaaa" + /* 4 */ "aaaaaaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaaaaaa" + /* 8 */ "aaaaaaaaaaaaaaa" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "aaaaaaabaaaaaaa" + /* 1 */ "aaaaaaabaaaaaaa" + /* 2 */ "aaaaaaabaaaaaaa" + /* 3 */ "aaaaaaabaaaaaaa" + /* 4 */ "aaaaaaabaaaaaaa" + /* 5 */ "aaaaaaabaaaaaaa" + /* 6 */ "aaaaaaabaaaaaaa" + /* 7 */ "aaaaaaabaaaaaaa" + /* 8 */ "aaaaaaabaaaaaaa" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "ccccccc.ccccccc" + /* 1 */ "cddeddc.cddeddc" + /* 2 */ "cddeddc.cddeddc" + /* 3 */ "cddeddc.cddeddc" + /* 4 */ "cddeddc.cddeddc" + /* 5 */ "cddeddc.cddeddc" + /* 6 */ "cddeddc.cddeddc" + /* 7 */ "cddeddc.cddeddc" + /* 8 */ "ccccccc.ccccccc" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "f.....f.f.....f" + /* 1 */ ".gg.gg...gg.gg." + /* 2 */ ".g...g...gg.gg." + /* 3 */ ".g.......gg.gg." + /* 4 */ ".gg..g...gg.gg." + /* 5 */ ".gg..g...gg.gg." + /* 6 */ "..g..g...gg.gg." + /* 7 */ "..g.g....gg.gg." + /* 8 */ "f.....f.f.....f" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "..............." + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "...............", + + // Connectors: + "-1: 7, 2, 8: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // DoublePlantBed + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Forge: + // The data has been exported from the gallery Plains, area index 51, ID 102, created by Aloe_vera + { + // Size: + 12, 9, 11, // SizeX = 12, SizeY = 9, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 12, 8, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 6\n" /* wooddoorblock */ + "h: 10: 0\n" /* lava */ + "i: 54: 2\n" /* chest */ + "j: 61: 2\n" /* furnace */ + "k:102: 0\n" /* glasspane */ + "l: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */ + "n:139: 0\n" /* cobblestonewall */ + "o:101: 0\n" /* ironbars */ + "p: 53: 2\n" /* woodstairs */ + "q: 53: 7\n" /* woodstairs */ + "r: 50: 2\n" /* torch */ + "s: 50: 1\n" /* torch */ + "t: 53: 6\n" /* woodstairs */ + "u: 53: 3\n" /* woodstairs */ + "v: 43: 0\n" /* doubleslab */ + "w: 44: 0\n" /* step */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "mmmmmaaaaamm" + /* 1 */ "maaaaaaaaamm" + /* 2 */ "maaaaaaaaamm" + /* 3 */ "maaaaaaaaaaa" + /* 4 */ "maaaaaaaaaaa" + /* 5 */ "maaaaaaaaaaa" + /* 6 */ "maaaaaaaaaaa" + /* 7 */ "maaaaaaaaaaa" + /* 8 */ "maaaaammmmmm" + /* 9 */ "maaaaammmmmm" + /* 10 */ "mmmmmmmmmmmm" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ ".....bcccd.." + /* 1 */ ".aaaaaaaad.." + /* 2 */ ".aaaaaaaad.." + /* 3 */ ".aaaaaaaaaaa" + /* 4 */ ".aaaaaaaaaaa" + /* 5 */ ".aaaaaaaaaaa" + /* 6 */ ".aaaaaaaaaaa" + /* 7 */ ".aaaaaaaaaaa" + /* 8 */ ".aaaaa......" + /* 9 */ ".aaaaa......" + /* 10 */ "............" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".efffe......" + /* 2 */ ".f...g......" + /* 3 */ ".f...ea..aaa" + /* 4 */ ".f...f...aha" + /* 5 */ ".f...f...aha" + /* 6 */ ".f...fijjaha" + /* 7 */ ".f...eaaaaaa" + /* 8 */ ".f...f......" + /* 9 */ ".efffe......" + /* 10 */ "............" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".ekkke......" + /* 2 */ ".k...l......" + /* 3 */ ".k...en..n.a" + /* 4 */ ".k...k.....o" + /* 5 */ ".f...k.....o" + /* 6 */ ".k...k.....o" + /* 7 */ ".k...eaooooa" + /* 8 */ ".k...f......" + /* 9 */ ".ekkke......" + /* 10 */ "............" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "ppppppp....." + /* 1 */ "qfffffq....." + /* 2 */ ".f...f......" + /* 3 */ ".f..rfa..aoa" + /* 4 */ ".f...f...o.a" + /* 5 */ ".f...f...o.a" + /* 6 */ ".fs..f...o.a" + /* 7 */ ".f...faaaaaa" + /* 8 */ ".f...f......" + /* 9 */ "tffffft....." + /* 10 */ "uuuuuuu....." + + // Level 5 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "ppppppp....." + /* 2 */ "qfffffq....." + /* 3 */ ".f...fvvvvvv" + /* 4 */ ".f...fvwwwwv" + /* 5 */ ".f...fvwwwwv" + /* 6 */ ".f...fvwwwwv" + /* 7 */ ".f...fvvvvvv" + /* 8 */ "tffffft....." + /* 9 */ "uuuuuuu....." + /* 10 */ "............" + + // Level 6 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "ppppppp....." + /* 3 */ "qfffffq....." + /* 4 */ ".f...f......" + /* 5 */ ".f...f......" + /* 6 */ ".f...f......" + /* 7 */ "tffffft....." + /* 8 */ "uuuuuuu....." + /* 9 */ "............" + /* 10 */ "............" + + // Level 7 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "ppppppp....." + /* 4 */ "qfffffq....." + /* 5 */ ".f...f......" + /* 6 */ "tffffft....." + /* 7 */ "uuuuuuu....." + /* 8 */ "............" + /* 9 */ "............" + /* 10 */ "............" + + // Level 8 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "............" + /* 4 */ "ppppppp....." + /* 5 */ "fffffff....." + /* 6 */ "uuuuuuu....." + /* 7 */ "............" + /* 8 */ "............" + /* 9 */ "............" + /* 10 */ "............", + + // Connectors: + "-1: 7, 1, -1: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Forge + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // LampPost: + // The data has been exported from the gallery Plains, area index 28, ID 73, created by STR_Warrior + { + // Size: + 3, 7, 3, // SizeX = 3, SizeY = 7, SizeZ = 3 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 2, 6, 2, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 43: 0\n" /* doubleslab */ + "c:139: 0\n" /* cobblestonewall */ + "d: 50: 4\n" /* torch */ + "e: 50: 2\n" /* torch */ + "f: 50: 1\n" /* torch */ + "g: 50: 3\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 012 */ + /* 0 */ "mmm" + /* 1 */ "mam" + /* 2 */ "mmm" + + // Level 1 + /* z\x* 012 */ + /* 0 */ "..." + /* 1 */ ".b." + /* 2 */ "..." + + // Level 2 + /* z\x* 012 */ + /* 0 */ "..." + /* 1 */ ".c." + /* 2 */ "..." + + // Level 3 + /* z\x* 012 */ + /* 0 */ "..." + /* 1 */ ".c." + /* 2 */ "..." + + // Level 4 + /* z\x* 012 */ + /* 0 */ ".d." + /* 1 */ "ebf" + /* 2 */ ".g." + + // Level 5 + /* z\x* 012 */ + /* 0 */ "..." + /* 1 */ "..." + /* 2 */ "..." + + // Level 6 + /* z\x* 012 */ + /* 0 */ "..." + /* 1 */ "..." + /* 2 */ "...", + + // Connectors: + "-1: 1, 1, 2: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // LampPost + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftCorridor: + // The data has been exported from the gallery Plains, area index 139, ID 447, created by STR_Warrior + { + // Size: + 10, 4, 3, // SizeX = 10, SizeY = 4, SizeZ = 3 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 9, 3, 2, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 85: 0\n" /* fence */ + "c: 66: 1\n" /* tracks */ + "d: 50: 2\n" /* torch */ + "e: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "aaaaaaaaaa" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "aaaaaaaaaa" + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "..b....b.." + /* 1 */ "cccccccccc" + /* 2 */ "..b....b.." + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "..b....b.." + /* 1 */ ".........." + /* 2 */ "..b....b.." + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "..a....a.." + /* 1 */ ".dae..dae." + /* 2 */ "..a....a..", + + // Connectors: + "-3: 0, 1, 1: 4\n" /* Type -3, direction X- */ + "3: 9, 1, 1: 5\n" /* Type 3, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 200, + + // MoveToGround: + false, + }, // MineshaftCorridor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftCrossing: + // The data has been exported from the gallery Plains, area index 171, ID 578, created by Aloe_vera + { + // Size: + 5, 4, 5, // SizeX = 5, SizeY = 4, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 3, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 66: 0\n" /* tracks */ + "c: 66: 1\n" /* tracks */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "m.b.m" + /* 1 */ ".aba." + /* 2 */ "ccccc" + /* 3 */ ".aba." + /* 4 */ "m.b.m" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m", + + // Connectors: + "3: 4, 1, 2: 5\n" /* Type 3, direction X+ */ + "-3: 4, 1, 2: 5\n" /* Type -3, direction X+ */ + "-3: 2, 1, 4: 3\n" /* Type -3, direction Z+ */ + "3: 2, 1, 4: 3\n" /* Type 3, direction Z+ */ + "3: 0, 1, 2: 4\n" /* Type 3, direction X- */ + "-3: 0, 1, 2: 4\n" /* Type -3, direction X- */ + "3: 2, 1, 0: 2\n" /* Type 3, direction Z- */ + "-3: 2, 1, 0: 2\n" /* Type -3, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 1, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftCrossing: + // The data has been exported from the gallery Plains, area index 193, ID 657, created by Aloe_vera + { + // Size: + 11, 4, 11, // SizeX = 11, SizeY = 4, SizeZ = 11 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 3, 10, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 66: 0\n" /* tracks */ + "c: 85: 0\n" /* fence */ + "d: 66: 1\n" /* tracks */ + "e: 50: 4\n" /* torch */ + "f: 50: 3\n" /* torch */ + "g: 50: 2\n" /* torch */ + "h: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "mmmmaaammmm" + /* 2 */ "mmmmaaammmm" + /* 3 */ "mmmmaaammmm" + /* 4 */ "aaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaa" + /* 7 */ "mmmmaaammmm" + /* 8 */ "mmmmaaammmm" + /* 9 */ "mmmmaaammmm" + /* 10 */ "mmmmaaammmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm.b.mmmm" + /* 1 */ "mmmm.b.mmmm" + /* 2 */ "mmmmcbcmmmm" + /* 3 */ "mmmm.b.mmmm" + /* 4 */ "..c..b..c.." + /* 5 */ "ddddddddddd" + /* 6 */ "..c..b..c.." + /* 7 */ "mmmm.b.mmmm" + /* 8 */ "mmmmcbcmmmm" + /* 9 */ "mmmm.b.mmmm" + /* 10 */ "mmmm.b.mmmm" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm...mmmm" + /* 1 */ "mmmm...mmmm" + /* 2 */ "mmmmc.cmmmm" + /* 3 */ "mmmm...mmmm" + /* 4 */ "..c.....c.." + /* 5 */ "..........." + /* 6 */ "..c.....c.." + /* 7 */ "mmmm...mmmm" + /* 8 */ "mmmmc.cmmmm" + /* 9 */ "mmmm...mmmm" + /* 10 */ "mmmm...mmmm" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm...mmmm" + /* 1 */ "mmmm.e.mmmm" + /* 2 */ "mmmmaaammmm" + /* 3 */ "mmmm.f.mmmm" + /* 4 */ "..a.....a.." + /* 5 */ ".gah...gah." + /* 6 */ "..a.....a.." + /* 7 */ "mmmm.e.mmmm" + /* 8 */ "mmmmaaammmm" + /* 9 */ "mmmm.f.mmmm" + /* 10 */ "mmmm...mmmm", + + // Connectors: + "3: 5, 1, 0: 2\n" /* Type 3, direction Z- */ + "-3: 5, 1, 0: 2\n" /* Type -3, direction Z- */ + "3: 0, 1, 5: 4\n" /* Type 3, direction X- */ + "-3: 0, 1, 5: 4\n" /* Type -3, direction X- */ + "3: 5, 1, 10: 3\n" /* Type 3, direction Z+ */ + "-3: 5, 1, 10: 3\n" /* Type -3, direction Z+ */ + "3: 10, 1, 5: 5\n" /* Type 3, direction X+ */ + "-3: 10, 1, 5: 5\n" /* Type -3, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftDoubleCrossing: + // The data has been exported from the gallery Plains, area index 172, ID 579, created by Aloe_vera + { + // Size: + 5, 8, 5, // SizeX = 5, SizeY = 8, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 7, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 66: 0\n" /* tracks */ + "c: 66: 1\n" /* tracks */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "m.b.m" + /* 1 */ ".aba." + /* 2 */ "ccccc" + /* 3 */ ".aba." + /* 4 */ "m.b.m" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aa.aa" + /* 2 */ "a...a" + /* 3 */ "aa.aa" + /* 4 */ "aaaaa" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m" + + // Level 6 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m" + + // Level 7 + /* z\x* 01234 */ + /* 0 */ "m...m" + /* 1 */ ".a.a." + /* 2 */ "....." + /* 3 */ ".a.a." + /* 4 */ "m...m", + + // Connectors: + "-3: 4, 5, 2: 5\n" /* Type -3, direction X+ */ + "3: 4, 5, 2: 5\n" /* Type 3, direction X+ */ + "-3: 2, 1, 4: 3\n" /* Type -3, direction Z+ */ + "3: 2, 1, 4: 3\n" /* Type 3, direction Z+ */ + "-3: 0, 1, 2: 4\n" /* Type -3, direction X- */ + "3: 0, 1, 2: 4\n" /* Type 3, direction X- */ + "-3: 2, 1, 0: 2\n" /* Type -3, direction Z- */ + "3: 2, 1, 0: 2\n" /* Type 3, direction Z- */ + "-3: 4, 1, 2: 5\n" /* Type -3, direction X+ */ + "3: 4, 1, 2: 5\n" /* Type 3, direction X+ */ + "-3: 2, 5, 4: 3\n" /* Type -3, direction Z+ */ + "3: 2, 5, 4: 3\n" /* Type 3, direction Z+ */ + "-3: 0, 5, 2: 4\n" /* Type -3, direction X- */ + "3: 0, 5, 2: 4\n" /* Type 3, direction X- */ + "-3: 2, 5, 0: 2\n" /* Type -3, direction Z- */ + "3: 2, 5, 0: 2\n" /* Type 3, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 1, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftDoubleCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftSpiral: + // The data has been exported from the gallery Plains, area index 198, ID 662, created by Aloe_vera + { + // Size: + 7, 12, 7, // SizeX = 7, SizeY = 12, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 11, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 85: 0\n" /* fence */ + "c: 66: 4\n" /* tracks */ + "d: 66: 0\n" /* tracks */ + "e: 66: 6\n" /* tracks */ + "f: 66: 2\n" /* tracks */ + "g: 50: 1\n" /* torch */ + "h: 50: 3\n" /* torch */ + "i: 66: 1\n" /* tracks */ + "j: 66: 7\n" /* tracks */ + "k: 66: 5\n" /* tracks */ + "l: 50: 2\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 66: 3\n" /* tracks */ + "o: 66: 8\n" /* tracks */ + "p: 50: 4\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmmmmm" + /* 2 */ "mmmmmmm" + /* 3 */ "aaabmmm" + /* 4 */ "aaammmm" + /* 5 */ "aaammmm" + /* 6 */ "aaammmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmmmmm" + /* 2 */ "aaammmm" + /* 3 */ "aaabmmm" + /* 4 */ ".c.mmmm" + /* 5 */ ".d.mmmm" + /* 6 */ ".d.mmmm" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aaaammm" + /* 1 */ "aaaammm" + /* 2 */ "aaaammm" + /* 3 */ ".c.bmmm" + /* 4 */ "...mmmm" + /* 5 */ "...mmmm" + /* 6 */ "...mmmm" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "b..aamm" + /* 1 */ ".efaamm" + /* 2 */ ".d.aamm" + /* 3 */ "...bmmm" + /* 4 */ "...mmmm" + /* 5 */ "...mmmm" + /* 6 */ "...mmmm" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "b...aaa" + /* 1 */ "...faaa" + /* 2 */ "....aaa" + /* 3 */ "...baaa" + /* 4 */ "...mmmm" + /* 5 */ "mmmmmmm" + /* 6 */ "mmmmmmm" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "ag....b" + /* 1 */ "h...ij." + /* 2 */ ".....k." + /* 3 */ "...baaa" + /* 4 */ "mmmmaaa" + /* 5 */ "mmmmmmm" + /* 6 */ "mmmmmmm" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "mm....b" + /* 1 */ "mm....." + /* 2 */ "mm....." + /* 3 */ "mmmb.k." + /* 4 */ "mmmaaaa" + /* 5 */ "mmmaaaa" + /* 6 */ "mmmaaaa" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "mmm..la" + /* 1 */ "mmm...h" + /* 2 */ "mmm...." + /* 3 */ "mmmb..." + /* 4 */ "mmaa.d." + /* 5 */ "mmaano." + /* 6 */ "mmaa..b" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmmmmm" + /* 2 */ "mmmm..." + /* 3 */ "mmmb..." + /* 4 */ "aaa...." + /* 5 */ "aaan..." + /* 6 */ "aaa...b" + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmmmmm" + /* 2 */ "mmmmmmm" + /* 3 */ "mmmb..." + /* 4 */ "......." + /* 5 */ "iii...p" + /* 6 */ ".....la" + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmmmmm" + /* 2 */ "mmmmmmm" + /* 3 */ "mmmbmmm" + /* 4 */ ".....mm" + /* 5 */ ".....mm" + /* 6 */ ".....mm" + + // Level 11 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmmmmm" + /* 2 */ "mmmmmmm" + /* 3 */ "mmmbmmm" + /* 4 */ "....mmm" + /* 5 */ "....mmm" + /* 6 */ "....mmm", + + // Connectors: + "3: 1, 1, 6: 3\n" /* Type 3, direction Z+ */ + "-3: 1, 1, 6: 3\n" /* Type -3, direction Z+ */ + "3: 0, 9, 5: 4\n" /* Type 3, direction X- */ + "-3: 0, 9, 5: 4\n" /* Type -3, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftSpiral + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftStairs: + // The data has been exported from the gallery Plains, area index 195, ID 659, created by Aloe_vera + { + // Size: + 7, 8, 3, // SizeX = 7, SizeY = 8, SizeZ = 3 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 7, 2, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 66: 1\n" /* tracks */ + "c: 66: 2\n" /* tracks */ + "d: 85: 0\n" /* fence */ + "e: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaammmm" + /* 1 */ "aaammmm" + /* 2 */ "aaammmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "..aammm" + /* 1 */ "bcaammm" + /* 2 */ "..aammm" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "...aamm" + /* 1 */ "..caamm" + /* 2 */ "...aamm" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "...daam" + /* 1 */ "...caam" + /* 2 */ "...daam" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "m..d.aa" + /* 1 */ "m...caa" + /* 2 */ "m..d.aa" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "mm.d..." + /* 1 */ "mm...bb" + /* 2 */ "mm.d..." + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "mmmd..." + /* 1 */ "mmm...." + /* 2 */ "mmmd..." + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "mmma..." + /* 1 */ "mmmae.." + /* 2 */ "mmma...", + + // Connectors: + "3: 0, 1, 1: 4\n" /* Type 3, direction X- */ + "-3: 0, 1, 1: 4\n" /* Type -3, direction X- */ + "3: 6, 5, 1: 5\n" /* Type 3, direction X+ */ + "-3: 6, 5, 1: 5\n" /* Type -3, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftStairs + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftStairsCrossing: + // The data has been exported from the gallery Plains, area index 199, ID 663, created by Aloe_vera + { + // Size: + 11, 12, 12, // SizeX = 11, SizeY = 12, SizeZ = 12 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 11, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 66: 0\n" /* tracks */ + "c: 66: 5\n" /* tracks */ + "d: 85: 0\n" /* fence */ + "e: 66: 1\n" /* tracks */ + "f: 50: 3\n" /* torch */ + "g: 50: 2\n" /* torch */ + "h: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "mmmmaaammmm" + /* 2 */ "mmmmaaammmm" + /* 3 */ "mmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm.b.mmmm" + /* 1 */ "mmmm.c.mmmm" + /* 2 */ "mmmmaaammmm" + /* 3 */ "mmmmaaammmm" + /* 4 */ "mmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm...mmmm" + /* 1 */ "mmmm...mmmm" + /* 2 */ "mmmm.c.mmmm" + /* 3 */ "mmmmaaammmm" + /* 4 */ "mmmmaaammmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm...mmmm" + /* 1 */ "mmmm...mmmm" + /* 2 */ "mmmm...mmmm" + /* 3 */ "mmmmdcdmmmm" + /* 4 */ "mmmmaaammmm" + /* 5 */ "mmmmaaammmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmm" + /* 9 */ "mmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmm...mmmm" + /* 2 */ "mmmm...mmmm" + /* 3 */ "mmmmd.dmmmm" + /* 4 */ "mmmm.c.mmmm" + /* 5 */ "aaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaa" + /* 7 */ "aaaaaaaaaaa" + /* 8 */ "mmmmaaammmm" + /* 9 */ "mmmmmmmmmmm" + /* 10 */ "mmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmm...mmmm" + /* 3 */ "mmmmd.dmmmm" + /* 4 */ "mmmm...mmmm" + /* 5 */ "..d..b..d.." + /* 6 */ "eeeeeeeeeee" + /* 7 */ "..d..c..d.." + /* 8 */ "mmmmaaammmm" + /* 9 */ "mmmmaaammmm" + /* 10 */ "mmmmmmmmmmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmm" + /* 3 */ "mmmmd.dmmmm" + /* 4 */ "mmmm...mmmm" + /* 5 */ "..d.....d.." + /* 6 */ "..........." + /* 7 */ "..d.....d.." + /* 8 */ "mmmm.c.mmmm" + /* 9 */ "mmmmaaammmm" + /* 10 */ "mmmmaaammmm" + /* 11 */ "mmmmmmmmmmm" + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmm" + /* 3 */ "mmmmaaammmm" + /* 4 */ "mmmm.f.mmmm" + /* 5 */ "..a.....a.." + /* 6 */ ".gah...gah." + /* 7 */ "..a.....a.." + /* 8 */ "mmmm...mmmm" + /* 9 */ "mmmmdcdmmmm" + /* 10 */ "mmmmaaammmm" + /* 11 */ "mmmmaaammmm" + + // Level 8 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmm...mmmm" + /* 8 */ "mmmm...mmmm" + /* 9 */ "mmmmd.dmmmm" + /* 10 */ "mmmm.c.mmmm" + /* 11 */ "mmmmaaammmm" + + // Level 9 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmm...mmmm" + /* 9 */ "mmmmd.dmmmm" + /* 10 */ "mmmm...mmmm" + /* 11 */ "mmmm.b.mmmm" + + // Level 10 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmm" + /* 9 */ "mmmmd.dmmmm" + /* 10 */ "mmmm...mmmm" + /* 11 */ "mmmm...mmmm" + + // Level 11 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmm" + /* 2 */ "mmmmmmmmmmm" + /* 3 */ "mmmmmmmmmmm" + /* 4 */ "mmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmm" + /* 7 */ "mmmmmmmmmmm" + /* 8 */ "mmmmmmmmmmm" + /* 9 */ "mmmmaaammmm" + /* 10 */ "mmmm.f.mmmm" + /* 11 */ "mmmm...mmmm", + + // Connectors: + "3: 0, 5, 6: 4\n" /* Type 3, direction X- */ + "-3: 0, 5, 6: 4\n" /* Type -3, direction X- */ + "3: 10, 5, 6: 5\n" /* Type 3, direction X+ */ + "-3: 10, 5, 6: 5\n" /* Type -3, direction X+ */ + "3: 5, 9, 11: 3\n" /* Type 3, direction Z+ */ + "-3: 5, 9, 11: 3\n" /* Type -3, direction Z+ */ + "3: 5, 1, 1: 2\n" /* Type 3, direction Z- */ + "-3: 5, 1, 1: 2\n" /* Type -3, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 30, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftStairsCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftTee: + // The data has been exported from the gallery Plains, area index 194, ID 658, created by Aloe_vera + { + // Size: + 11, 4, 7, // SizeX = 11, SizeY = 4, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 3, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 66: 0\n" /* tracks */ + "c: 85: 0\n" /* fence */ + "d: 66: 1\n" /* tracks */ + "e: 50: 4\n" /* torch */ + "f: 50: 3\n" /* torch */ + "g: 50: 2\n" /* torch */ + "h: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "mmmmaaammmm" + /* 2 */ "mmmmaaammmm" + /* 3 */ "mmmmaaammmm" + /* 4 */ "aaaaaaaaaaa" + /* 5 */ "aaaaaaaaaaa" + /* 6 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm.b.mmmm" + /* 1 */ "mmmm.b.mmmm" + /* 2 */ "mmmmcbcmmmm" + /* 3 */ "mmmm.b.mmmm" + /* 4 */ "..c..b..c.." + /* 5 */ "ddddddddddd" + /* 6 */ "..c.....c.." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm...mmmm" + /* 1 */ "mmmm...mmmm" + /* 2 */ "mmmmc.cmmmm" + /* 3 */ "mmmm...mmmm" + /* 4 */ "..c.....c.." + /* 5 */ "..........." + /* 6 */ "..c.....c.." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmm...mmmm" + /* 1 */ "mmmm.e.mmmm" + /* 2 */ "mmmmaaammmm" + /* 3 */ "mmmm.f.mmmm" + /* 4 */ "..a.....a.." + /* 5 */ ".gah...gah." + /* 6 */ "..a.....a..", + + // Connectors: + "3: 0, 1, 5: 4\n" /* Type 3, direction X- */ + "-3: 0, 1, 5: 4\n" /* Type -3, direction X- */ + "3: 5, 1, 0: 2\n" /* Type 3, direction Z- */ + "-3: 5, 1, 0: 2\n" /* Type -3, direction Z- */ + "3: 10, 1, 5: 5\n" /* Type 3, direction X+ */ + "-3: 10, 1, 5: 5\n" /* Type -3, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftTee + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineshaftsCorridor5: + // The data has been exported from the gallery Plains, area index 200, ID 664, created by Aloe_vera + { + // Size: + 11, 4, 3, // SizeX = 11, SizeY = 4, SizeZ = 3 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 3, 2, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 85: 0\n" /* fence */ + "c: 66: 1\n" /* tracks */ + "d: 50: 2\n" /* torch */ + "e: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "aaaaaaaaaaa" + /* 2 */ "aaaaaaaaaaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..b.....b.." + /* 1 */ "ccccccccccc" + /* 2 */ "..b.....b.." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..b.....b.." + /* 1 */ "..........." + /* 2 */ "..b.....b.." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..a.....a.." + /* 1 */ ".dae...dae." + /* 2 */ "..a.....a..", + + // Connectors: + "3: 10, 1, 1: 5\n" /* Type 3, direction X+ */ + "-3: 10, 1, 1: 5\n" /* Type -3, direction X+ */ + "-3: 0, 1, 1: 4\n" /* Type -3, direction X- */ + "3: 0, 1, 1: 4\n" /* Type 3, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + false, + }, // MineshaftsCorridor5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Scarecrow: + // The data has been exported from the gallery Plains, area index 150, ID 494, created by STR_Warrior + { + // Size: + 1, 6, 3, // SizeX = 1, SizeY = 6, SizeZ = 3 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 0, 5, 2, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:139: 0\n" /* cobblestonewall */ + "b: 85: 0\n" /* fence */ + "c:126: 4\n" /* woodenslab */ + "d: 86: 1\n" /* pumpkin */ + "e:139: 1\n" /* cobblestonewall */ + "f:163: 4\n" /* acaciawoodenstairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0 */ + /* 0 */ "." + /* 1 */ "a" + /* 2 */ "." + + // Level 1 + /* z\x* 0 */ + /* 0 */ "." + /* 1 */ "b" + /* 2 */ "." + + // Level 2 + /* z\x* 0 */ + /* 0 */ "c" + /* 1 */ "d" + /* 2 */ "c" + + // Level 3 + /* z\x* 0 */ + /* 0 */ "." + /* 1 */ "e" + /* 2 */ "." + + // Level 4 + /* z\x* 0 */ + /* 0 */ "f" + /* 1 */ "d" + /* 2 */ "f" + + // Level 5 + /* z\x* 0 */ + /* 0 */ "." + /* 1 */ "f" + /* 2 */ ".", + + // Connectors: + "-1: -1, 0, 1: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Scarecrow + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SinglePlantBed: + // The data has been exported from the gallery Plains, area index 17, ID 60, created by Aloe_vera + { + // Size: + 10, 7, 7, // SizeX = 10, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 9, 6, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 3: 0\n" /* dirt */ + "b: 17: 0\n" /* tree */ + "c: 60: 7\n" /* tilleddirt */ + "d: 8: 0\n" /* water */ + "e: 59: 7\n" /* crops */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "aaaaaaaaaa" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "aaaaaaaaaa" + /* 3 */ "aaaaaaaaaa" + /* 4 */ "aaaaaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "aaaaaaaaaa" + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "bbbbbbbbbb" + /* 1 */ "bccccccccb" + /* 2 */ "bccccccccb" + /* 3 */ "bddddddddb" + /* 4 */ "bccccccccb" + /* 5 */ "bccccccccb" + /* 6 */ "bbbbbbbbbb" + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".eeeeeeee." + /* 2 */ ".eeeeeeee." + /* 3 */ ".........." + /* 4 */ ".eeeeeeee." + /* 5 */ ".eeeeeeee." + /* 6 */ ".........." + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".........." + /* 2 */ ".........." + /* 3 */ ".........." + /* 4 */ ".........." + /* 5 */ ".........." + /* 6 */ ".........." + + // Level 4 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".........." + /* 2 */ ".........." + /* 3 */ ".........." + /* 4 */ ".........." + /* 5 */ ".........." + /* 6 */ ".........." + + // Level 5 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".........." + /* 2 */ ".........." + /* 3 */ ".........." + /* 4 */ ".........." + /* 5 */ ".........." + /* 6 */ ".........." + + // Level 6 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".........." + /* 2 */ ".........." + /* 3 */ ".........." + /* 4 */ ".........." + /* 5 */ ".........." + /* 6 */ "..........", + + // Connectors: + "-1: 9, 1, 3: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // SinglePlantBed + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenChurchMid: + // The data has been exported from the gallery Plains, area index 58, ID 109, created by Aloe_vera + { + // Size: + 7, 15, 13, // SizeX = 7, SizeY = 15, SizeZ = 13 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 7, 14, 13, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A: 85: 0\n" /* fence */ + "B:126: 8\n" /* woodenslab */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h: 65: 3\n" /* ladder */ + "i: 53: 3\n" /* woodstairs */ + "j: 53: 7\n" /* woodstairs */ + "k: 64:12\n" /* wooddoorblock */ + "l:102: 0\n" /* glasspane */ + "m: 19: 0\n" /* sponge */ + "n: 50: 1\n" /* torch */ + "o: 50: 2\n" /* torch */ + "p:171:14\n" /* carpet */ + "q: 50: 3\n" /* torch */ + "r: 53: 2\n" /* woodstairs */ + "s: 53: 0\n" /* woodstairs */ + "t: 53: 1\n" /* woodstairs */ + "u: 53: 5\n" /* woodstairs */ + "v: 53: 4\n" /* woodstairs */ + "w: 17: 4\n" /* tree */ + "x: 17: 8\n" /* tree */ + "y: 54: 2\n" /* chest */ + "z: 50: 4\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "mmaaamm" + /* 1 */ "maaaaam" + /* 2 */ "maaaaam" + /* 3 */ "maaaaam" + /* 4 */ "maaaaam" + /* 5 */ "maaaaam" + /* 6 */ "maaaaam" + /* 7 */ "maaaaam" + /* 8 */ "maaaaam" + /* 9 */ "maaaaam" + /* 10 */ "maaaaam" + /* 11 */ "maaaaam" + /* 12 */ "mmmmmmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "..bcd.." + /* 1 */ ".aaaaa." + /* 2 */ ".aaaaa." + /* 3 */ ".aaaaa." + /* 4 */ ".aaaaa." + /* 5 */ ".aaaaa." + /* 6 */ ".aaaaa." + /* 7 */ ".aaaaa." + /* 8 */ ".aaaaa." + /* 9 */ ".aaaaa." + /* 10 */ ".aaaaa." + /* 11 */ ".aaaaa." + /* 12 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".efgfe." + /* 2 */ ".f..hf." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ ".ei.ie." + /* 6 */ ".f...f." + /* 7 */ ".fi.if." + /* 8 */ ".f...f." + /* 9 */ ".f.j.f." + /* 10 */ ".f...f." + /* 11 */ ".efffe." + /* 12 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".efkfe." + /* 2 */ ".l..hl." + /* 3 */ ".l...l." + /* 4 */ ".l...l." + /* 5 */ ".e...e." + /* 6 */ ".l...l." + /* 7 */ ".l...l." + /* 8 */ ".fn.of." + /* 9 */ ".l.p.l." + /* 10 */ ".l...l." + /* 11 */ ".ellle." + /* 12 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".efffe." + /* 2 */ ".f.qhf." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ "re...er" + /* 6 */ "sf...ft" + /* 7 */ "sf...ft" + /* 8 */ "sf...ft" + /* 9 */ "sf...ft" + /* 10 */ "sf...ft" + /* 11 */ "sefffet" + /* 12 */ "su...vt" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ewwwe." + /* 2 */ ".xffhx." + /* 3 */ ".xfffx." + /* 4 */ ".xfffx." + /* 5 */ ".ewwwe." + /* 6 */ ".sf.ft." + /* 7 */ ".sf.ft." + /* 8 */ ".sf.ft." + /* 9 */ ".sf.ft." + /* 10 */ ".sf.ft." + /* 11 */ ".sffft." + /* 12 */ ".su.vt." + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".eflfe." + /* 2 */ ".f..hf." + /* 3 */ ".f...f." + /* 4 */ ".f.y.f." + /* 5 */ ".efffe." + /* 6 */ "..sft.." + /* 7 */ "..sft.." + /* 8 */ "..sft.." + /* 9 */ "..sft.." + /* 10 */ "..sft.." + /* 11 */ "..sft.." + /* 12 */ "..sft.." + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".eflfe." + /* 2 */ ".f..hf." + /* 3 */ ".l...l." + /* 4 */ ".f...f." + /* 5 */ ".efffe." + /* 6 */ "......." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".eflfe." + /* 2 */ ".f..hf." + /* 3 */ ".f...f." + /* 4 */ ".f.z.f." + /* 5 */ ".efffe." + /* 6 */ "......." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ewwwe." + /* 2 */ ".xffhx." + /* 3 */ ".xfffx." + /* 4 */ ".xfffx." + /* 5 */ ".ewwwe." + /* 6 */ "......." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".eAAAe." + /* 2 */ ".A...A." + /* 3 */ ".A...A." + /* 4 */ ".A...A." + /* 5 */ ".eAAAe." + /* 6 */ "......." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 11 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".e...e." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ ".e...e." + /* 6 */ "......." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 12 + /* z\x* 0123456 */ + /* 0 */ "su...vt" + /* 1 */ "sefffet" + /* 2 */ "sfBBBft" + /* 3 */ "sfBBBft" + /* 4 */ "sfBBBft" + /* 5 */ "sefffet" + /* 6 */ "su...vt" + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 13 + /* z\x* 0123456 */ + /* 0 */ ".su.vt." + /* 1 */ ".sffft." + /* 2 */ ".sffft." + /* 3 */ ".sffft." + /* 4 */ ".sffft." + /* 5 */ ".sffft." + /* 6 */ ".su.vt." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ "......." + + // Level 14 + /* z\x* 0123456 */ + /* 0 */ "..sft.." + /* 1 */ "..sft.." + /* 2 */ "..sft.." + /* 3 */ "..sft.." + /* 4 */ "..sft.." + /* 5 */ "..sft.." + /* 6 */ "..sft.." + /* 7 */ "......." + /* 8 */ "......." + /* 9 */ "......." + /* 10 */ "......." + /* 11 */ "......." + /* 12 */ ".......", + + // Connectors: + "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenChurchMid + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenGranary: + // The data has been exported from the gallery Plains, area index 54, ID 105, created by Aloe_vera + { + // Size: + 7, 7, 9, // SizeX = 7, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 7, 6, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b:170: 0\n" /* haybale */ + "c: 67: 0\n" /* stairs */ + "d: 67: 2\n" /* stairs */ + "e: 67: 1\n" /* stairs */ + "f: 17: 0\n" /* tree */ + "g: 5: 0\n" /* wood */ + "h:170: 4\n" /* haybale */ + "i:170: 8\n" /* haybale */ + "j: 54: 2\n" /* chest */ + "k: 50: 4\n" /* torch */ + "l: 53: 0\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 53: 5\n" /* woodstairs */ + "o: 53: 4\n" /* woodstairs */ + "p: 53: 1\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "maaaaam" + /* 1 */ "maaaaam" + /* 2 */ "maaaaam" + /* 3 */ "maaaaam" + /* 4 */ "maaaaam" + /* 5 */ "maaaaam" + /* 6 */ "maaaaam" + /* 7 */ "maaaaam" + /* 8 */ "mmmmmmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "bcddde." + /* 1 */ ".aaaaa." + /* 2 */ ".aaaaa." + /* 3 */ ".aaaaa." + /* 4 */ ".aaaaa." + /* 5 */ ".aaaaa." + /* 6 */ ".aaaaa." + /* 7 */ ".aaaaa." + /* 8 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".f..bf." + /* 2 */ ".g...g." + /* 3 */ ".gb.hg." + /* 4 */ ".fihif." + /* 5 */ ".gbbbg." + /* 6 */ ".gijbg." + /* 7 */ ".fgfgf." + /* 8 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ ".k...k." + /* 1 */ ".f...f." + /* 2 */ ".g...g." + /* 3 */ ".g...g." + /* 4 */ ".fh..f." + /* 5 */ ".ghibg." + /* 6 */ ".ghiig." + /* 7 */ ".fgfgf." + /* 8 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "ln...op" + /* 1 */ "lgggggp" + /* 2 */ "lg...gp" + /* 3 */ "lg...gp" + /* 4 */ "lg...gp" + /* 5 */ "lgbb.gp" + /* 6 */ "lgibigp" + /* 7 */ "lgggggp" + /* 8 */ "ln...op" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ ".ln.op." + /* 1 */ ".lgggp." + /* 2 */ ".lg.gp." + /* 3 */ ".lg.gp." + /* 4 */ ".lg.gp." + /* 5 */ ".lg.gp." + /* 6 */ ".lg.gp." + /* 7 */ ".lgggp." + /* 8 */ ".ln.op." + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "..lgp.." + /* 1 */ "..lgp.." + /* 2 */ "..lgp.." + /* 3 */ "..lgp.." + /* 4 */ "..lgp.." + /* 5 */ "..lgp.." + /* 6 */ "..lgp.." + /* 7 */ "..lgp.." + /* 8 */ "..lgp..", + + // Connectors: + "-1: 3, 1, -1: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenGranary + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse10x7Library: + // The data has been exported from the gallery Plains, area index 47, ID 98, created by Aloe_vera + { + // Size: + 12, 8, 9, // SizeX = 12, SizeY = 8, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 12, 7, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h: 64: 5\n" /* wooddoorblock */ + "i: 53: 3\n" /* woodstairs */ + "j: 85: 0\n" /* fence */ + "k: 53: 2\n" /* woodstairs */ + "l: 53: 1\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 53: 0\n" /* woodstairs */ + "o:102: 0\n" /* glasspane */ + "p: 64:12\n" /* wooddoorblock */ + "q: 50: 3\n" /* torch */ + "r: 72: 0\n" /* woodplate */ + "s: 53: 7\n" /* woodstairs */ + "t: 47: 0\n" /* bookshelf */ + "u: 50: 1\n" /* torch */ + "v: 50: 2\n" /* torch */ + "w: 53: 6\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "mmmmaaaammmm" + /* 1 */ "maaaaaaaaaam" + /* 2 */ "maaaaaaaaaam" + /* 3 */ "maaaaaaaaaam" + /* 4 */ "maaaaaaaaaam" + /* 5 */ "maaaaaaaaaam" + /* 6 */ "maaaaaaaaaam" + /* 7 */ "maaaaaaaaaam" + /* 8 */ "mmmmmmmmmmmm" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "....bccd...." + /* 1 */ ".aaaaaaaaaa." + /* 2 */ ".aaaaaaaaaa." + /* 3 */ ".aaaaaaaaaa." + /* 4 */ ".aaaaaaaaaa." + /* 5 */ ".aaaaaaaaaa." + /* 6 */ ".aaaaaaaaaa." + /* 7 */ ".aaaaaaaaaa." + /* 8 */ "............" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".efffghfffe." + /* 2 */ ".f........f." + /* 3 */ ".fi......if." + /* 4 */ ".fj......jf." + /* 5 */ ".fk......kf." + /* 6 */ ".f.ljnljn.f." + /* 7 */ ".effffffffe." + /* 8 */ "............" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".eoofppfooe." + /* 2 */ ".o..q..q..o." + /* 3 */ ".o........o." + /* 4 */ ".fr......rf." + /* 5 */ ".o........o." + /* 6 */ ".o..r..r..o." + /* 7 */ ".eoofoofooe." + /* 8 */ "............" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "kkkkkkkkkkkk" + /* 1 */ "sffffffffffs" + /* 2 */ ".fttttttttf." + /* 3 */ ".f........f." + /* 4 */ ".fu......vf." + /* 5 */ ".f........f." + /* 6 */ ".fttttttttf." + /* 7 */ "wffffffffffw" + /* 8 */ "iiiiiiiiiiii" + + // Level 5 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "kkkkkkkkkkkk" + /* 2 */ "sffffffffffs" + /* 3 */ ".fttttttttf." + /* 4 */ ".f........f." + /* 5 */ ".fttttttttf." + /* 6 */ "wffffffffffw" + /* 7 */ "iiiiiiiiiiii" + /* 8 */ "............" + + // Level 6 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "kkkkkkkkkkkk" + /* 3 */ "sffffffffffs" + /* 4 */ ".f........f." + /* 5 */ "wffffffffffw" + /* 6 */ "iiiiiiiiiiii" + /* 7 */ "............" + /* 8 */ "............" + + // Level 7 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ "............" + /* 2 */ "............" + /* 3 */ "kkkkkkkkkkkk" + /* 4 */ "ffffffffffff" + /* 5 */ "iiiiiiiiiiii" + /* 6 */ "............" + /* 7 */ "............" + /* 8 */ "............", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse10x7Library + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse5x5: + // The data has been exported from the gallery Plains, area index 49, ID 100, created by Aloe_vera + { + // Size: + 7, 7, 7, // SizeX = 7, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 7, 6, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h: 64:12\n" /* wooddoorblock */ + "i:102: 0\n" /* glasspane */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 7\n" /* woodstairs */ + "l: 50: 3\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 53: 6\n" /* woodstairs */ + "o: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "mmaaamm" + /* 1 */ "maaaaam" + /* 2 */ "maaaaam" + /* 3 */ "maaaaam" + /* 4 */ "maaaaam" + /* 5 */ "maaaaam" + /* 6 */ "mmmmmmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "..bcd.." + /* 1 */ ".aaaaa." + /* 2 */ ".aaaaa." + /* 3 */ ".aaaaa." + /* 4 */ ".aaaaa." + /* 5 */ ".aaaaa." + /* 6 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".efgfe." + /* 2 */ ".f...f." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ ".efffe." + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".efhfe." + /* 2 */ ".i...i." + /* 3 */ ".i...i." + /* 4 */ ".i...i." + /* 5 */ ".eiiie." + /* 6 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "jjjjjjj" + /* 1 */ "kfffffk" + /* 2 */ ".fl.lf." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ "nfffffn" + /* 6 */ "ooooooo" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "jjjjjjj" + /* 2 */ "kfffffk" + /* 3 */ ".f...f." + /* 4 */ "nfffffn" + /* 5 */ "ooooooo" + /* 6 */ "......." + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "jjjjjjj" + /* 3 */ "fffffff" + /* 4 */ "ooooooo" + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "-1: 3, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse5x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse7x5: + // The data has been exported from the gallery Plains, area index 40, ID 91, created by xoft + { + // Size: + 9, 7, 7, // SizeX = 9, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 9, 6, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h:102: 0\n" /* glasspane */ + "i: 64:12\n" /* wooddoorblock */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 7\n" /* woodstairs */ + "l: 50: 3\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 53: 6\n" /* woodstairs */ + "o: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "mmmaaammm" + /* 1 */ "maaaaaaam" + /* 2 */ "maaaaaaam" + /* 3 */ "maaaaaaam" + /* 4 */ "maaaaaaam" + /* 5 */ "maaaaaaam" + /* 6 */ "mmmmmmmmm" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "...bcd..." + /* 1 */ ".aaaaaaa." + /* 2 */ ".aaaaaaa." + /* 3 */ ".aaaaaaa." + /* 4 */ ".aaaaaaa." + /* 5 */ ".aaaaaaa." + /* 6 */ "........." + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".effgffe." + /* 2 */ ".f.....f." + /* 3 */ ".f.....f." + /* 4 */ ".f.....f." + /* 5 */ ".efffffe." + /* 6 */ "........." + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".ehfifhe." + /* 2 */ ".h.....h." + /* 3 */ ".h.....h." + /* 4 */ ".h.....h." + /* 5 */ ".ehhfhhe." + /* 6 */ "........." + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "jjjjjjjjj" + /* 1 */ "kefffffek" + /* 2 */ ".f.l.l.f." + /* 3 */ ".f.....f." + /* 4 */ ".f.....f." + /* 5 */ "nefffffen" + /* 6 */ "ooooooooo" + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "jjjjjjjjj" + /* 2 */ "kfffffffk" + /* 3 */ ".f.....f." + /* 4 */ "nfffffffn" + /* 5 */ "ooooooooo" + /* 6 */ "........." + + // Level 6 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "jjjjjjjjj" + /* 3 */ "fffffffff" + /* 4 */ "ooooooooo" + /* 5 */ "........." + /* 6 */ ".........", + + // Connectors: + "-1: 4, 1, -1: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse7x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse9x5: + // The data has been exported from the gallery Plains, area index 41, ID 92, created by xoft + { + // Size: + 11, 7, 7, // SizeX = 11, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 11, 6, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h:102: 0\n" /* glasspane */ + "i: 64:12\n" /* wooddoorblock */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 7\n" /* woodstairs */ + "l: 50: 3\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 53: 6\n" /* woodstairs */ + "o: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....bcd...." + /* 1 */ ".aaaaaaaaa." + /* 2 */ ".aaaaaaaaa." + /* 3 */ ".aaaaaaaaa." + /* 4 */ ".aaaaaaaaa." + /* 5 */ ".aaaaaaaaa." + /* 6 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".efffgfffe." + /* 2 */ ".f.......f." + /* 3 */ ".f.......f." + /* 4 */ ".f.......f." + /* 5 */ ".efffffffe." + /* 6 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ehhfifhhe." + /* 2 */ ".h.......h." + /* 3 */ ".h.......h." + /* 4 */ ".h.......h." + /* 5 */ ".ehhhfhhhe." + /* 6 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "jjjjjjjjjjj" + /* 1 */ "kfffffffffk" + /* 2 */ ".f..l.l.ff." + /* 3 */ ".f......ff." + /* 4 */ ".f......ff." + /* 5 */ "nfffffffffn" + /* 6 */ "ooooooooooo" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "jjjjjjjjjjj" + /* 2 */ "kfffffffffk" + /* 3 */ ".fffffffff." + /* 4 */ "nfffffffffn" + /* 5 */ "ooooooooooo" + /* 6 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "jjjjjjjjjjj" + /* 3 */ "fffffffffff" + /* 4 */ "ooooooooooo" + /* 5 */ "..........." + /* 6 */ "...........", + + // Connectors: + "-1: 5, 1, -1: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse9x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse9x5Fence: + // The data has been exported from the gallery Plains, area index 9, ID 26, created by Aloe_vera + { + // Size: + 10, 7, 11, // SizeX = 10, SizeY = 7, SizeZ = 11 + + // Hitbox (relative to bounding box): + 0, -1, -1, // MinX, MinY, MinZ + 10, 6, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 3: 0\n" /* dirt */ + "c: 5: 0\n" /* wood */ + "d: 2: 0\n" /* grass */ + "e: 67: 2\n" /* stairs */ + "f: 43: 0\n" /* doubleslab */ + "g: 67: 0\n" /* stairs */ + "h: 67: 3\n" /* stairs */ + "i: 17: 0\n" /* tree */ + "j: 53: 1\n" /* woodstairs */ + "k: 85: 0\n" /* fence */ + "l: 53: 0\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 64: 6\n" /* wooddoorblock */ + "o: 64: 4\n" /* wooddoorblock */ + "p:102: 0\n" /* glasspane */ + "q: 72: 0\n" /* woodplate */ + "r: 64:12\n" /* wooddoorblock */ + "s: 53: 5\n" /* woodstairs */ + "t: 53: 4\n" /* woodstairs */ + "u: 50: 1\n" /* torch */ + "v: 50: 2\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".aaaaa...." + /* 2 */ ".aaaaa...." + /* 3 */ ".aaaaabbbb" + /* 4 */ "aaaaaabbbb" + /* 5 */ "aaaaaabbbb" + /* 6 */ "aaaaaabbbb" + /* 7 */ ".aaaaabbbb" + /* 8 */ ".aaaaabbbb" + /* 9 */ ".aaaaa...." + /* 10 */ ".........." + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "......mmmm" + /* 1 */ ".aaaaammmm" + /* 2 */ ".acccammmm" + /* 3 */ ".acccadddd" + /* 4 */ "eafffadddd" + /* 5 */ "gaffffdddd" + /* 6 */ "hafffadddd" + /* 7 */ ".afffadddd" + /* 8 */ ".afffadddd" + /* 9 */ ".aaaaammmm" + /* 10 */ "......mmmm" + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "......mmmm" + /* 1 */ ".icccimmmm" + /* 2 */ ".cjklcmmmm" + /* 3 */ ".c...ckkkk" + /* 4 */ ".c...c...k" + /* 5 */ ".n...o...k" + /* 6 */ ".c...c...k" + /* 7 */ ".cff.c...k" + /* 8 */ ".c...ckkkk" + /* 9 */ ".icccimmmm" + /* 10 */ "......mmmm" + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "......mmmm" + /* 1 */ ".ipppimmmm" + /* 2 */ ".p.q.pmmmm" + /* 3 */ ".p...p...." + /* 4 */ ".c...c...." + /* 5 */ ".r...r...." + /* 6 */ ".c...c...." + /* 7 */ ".p...p...." + /* 8 */ ".p...p...." + /* 9 */ ".ipppimmmm" + /* 10 */ "......mmmm" + + // Level 4 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "ls...tjmmm" + /* 1 */ "licccijmmm" + /* 2 */ "lc...cjmmm" + /* 3 */ "lc...cj..." + /* 4 */ "lcu.vcj..." + /* 5 */ "lc...cj..." + /* 6 */ "lcu.vcj..." + /* 7 */ "lc...cj..." + /* 8 */ "lc...cj..." + /* 9 */ "licccijmmm" + /* 10 */ "ls...tjmmm" + + // Level 5 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mls.tjmmmm" + /* 1 */ "mlcccjmmmm" + /* 2 */ "mlc.cjmmmm" + /* 3 */ "mlc.cjm..." + /* 4 */ "mlc.cjm..." + /* 5 */ "mlc.cjm..." + /* 6 */ "mlc.cjm..." + /* 7 */ "mlc.cjm..." + /* 8 */ "mlc.cjm..." + /* 9 */ "mlcccjmmmm" + /* 10 */ "mls.tjmmmm" + + // Level 6 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmlcjmmmmm" + /* 1 */ "mmlcjmmmmm" + /* 2 */ "mmlcjmmmmm" + /* 3 */ "mmlcjmm..." + /* 4 */ "mmlcjmm..." + /* 5 */ "mmlcjmm..." + /* 6 */ "mmlcjmm..." + /* 7 */ "mmlcjmm..." + /* 8 */ "mmlcjmm..." + /* 9 */ "mmlcjmmmmm" + /* 10 */ "mmlcjmmmmm", + + // Connectors: + "-1: 0, 1, 5: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse9x5Fence + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse9x5Library: + // The data has been exported from the gallery Plains, area index 46, ID 97, created by Aloe_vera + { + // Size: + 11, 7, 7, // SizeX = 11, SizeY = 7, SizeZ = 7 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 11, 6, 7, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h: 53: 3\n" /* woodstairs */ + "i: 85: 0\n" /* fence */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 1\n" /* woodstairs */ + "l: 53: 0\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n:102: 0\n" /* glasspane */ + "o: 64:12\n" /* wooddoorblock */ + "p: 50: 3\n" /* torch */ + "q: 72: 0\n" /* woodplate */ + "r: 53: 7\n" /* woodstairs */ + "s: 47: 0\n" /* bookshelf */ + "t: 50: 1\n" /* torch */ + "u: 50: 2\n" /* torch */ + "v: 53: 6\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....bcd...." + /* 1 */ ".aaaaaaaaa." + /* 2 */ ".aaaaaaaaa." + /* 3 */ ".aaaaaaaaa." + /* 4 */ ".aaaaaaaaa." + /* 5 */ ".aaaaaaaaa." + /* 6 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".efffgfffe." + /* 2 */ ".fh.....hf." + /* 3 */ ".fi.....if." + /* 4 */ ".fj.kil.jf." + /* 5 */ ".efffffffe." + /* 6 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ennfofnne." + /* 2 */ ".n..p.p..n." + /* 3 */ ".nq.....qn." + /* 4 */ ".n...q...n." + /* 5 */ ".ennnfnnne." + /* 6 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "jjjjjjjjjjj" + /* 1 */ "rfffffffffr" + /* 2 */ ".fsssssssf." + /* 3 */ ".ft.....uf." + /* 4 */ ".fsssssssf." + /* 5 */ "vfffffffffv" + /* 6 */ "hhhhhhhhhhh" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "jjjjjjjjjjj" + /* 2 */ "rfffffffffr" + /* 3 */ ".f.......f." + /* 4 */ "vfffffffffv" + /* 5 */ "hhhhhhhhhhh" + /* 6 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "jjjjjjjjjjj" + /* 3 */ "fffffffffff" + /* 4 */ "hhhhhhhhhhh" + /* 5 */ "..........." + /* 6 */ "...........", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse9x5Library + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse9x7: + // The data has been exported from the gallery Plains, area index 52, ID 103, created by Aloe_vera + { + // Size: + 11, 8, 9, // SizeX = 11, SizeY = 8, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 11, 7, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h:102: 0\n" /* glasspane */ + "i: 64:12\n" /* wooddoorblock */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 7\n" /* woodstairs */ + "l: 50: 3\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 50: 4\n" /* torch */ + "o: 53: 6\n" /* woodstairs */ + "p: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "maaaaaaaaam" + /* 7 */ "maaaaaaaaam" + /* 8 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....bcd...." + /* 1 */ ".aaaaaaaaa." + /* 2 */ ".aaaaaaaaa." + /* 3 */ ".aaaaaaaaa." + /* 4 */ ".aaaaaaaaa." + /* 5 */ ".aaaaaaaaa." + /* 6 */ ".aaaaaaaaa." + /* 7 */ ".aaaaaaaaa." + /* 8 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".efffgfffe." + /* 2 */ ".f.......f." + /* 3 */ ".f.......f." + /* 4 */ ".f.......f." + /* 5 */ ".f.......f." + /* 6 */ ".f.......f." + /* 7 */ ".efffffffe." + /* 8 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ehhfifhhe." + /* 2 */ ".h.......h." + /* 3 */ ".h.......h." + /* 4 */ ".f.......f." + /* 5 */ ".h.......h." + /* 6 */ ".h.......h." + /* 7 */ ".ehhhfhhhe." + /* 8 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "jjjjjjjjjjj" + /* 1 */ "kfffffffffk" + /* 2 */ ".f..l.l..f." + /* 3 */ ".f.......f." + /* 4 */ ".f.......f." + /* 5 */ ".f.......f." + /* 6 */ ".f...n...f." + /* 7 */ "offfffffffo" + /* 8 */ "ppppppppppp" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "jjjjjjjjjjj" + /* 2 */ "kfffffffffk" + /* 3 */ ".f.......f." + /* 4 */ ".f.......f." + /* 5 */ ".f.......f." + /* 6 */ "offfffffffo" + /* 7 */ "ppppppppppp" + /* 8 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "jjjjjjjjjjj" + /* 3 */ "kfffffffffk" + /* 4 */ ".f.......f." + /* 5 */ "offfffffffo" + /* 6 */ "ppppppppppp" + /* 7 */ "..........." + /* 8 */ "..........." + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "jjjjjjjjjjj" + /* 4 */ "fffffffffff" + /* 5 */ "ppppppppppp" + /* 6 */ "..........." + /* 7 */ "..........." + /* 8 */ "...........", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse9x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse9x7Butcher: + // The data has been exported from the gallery Plains, area index 48, ID 99, created by Aloe_vera + { + // Size: + 11, 9, 13, // SizeX = 11, SizeY = 9, SizeZ = 13 + + // Hitbox (relative to bounding box): + -1, 0, 0, // MinX, MinY, MinZ + 11, 8, 13, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 2: 0\n" /* grass */ + "b: 3: 0\n" /* dirt */ + "c: 4: 0\n" /* cobblestone */ + "d: 67: 0\n" /* stairs */ + "e: 67: 2\n" /* stairs */ + "f: 67: 1\n" /* stairs */ + "g: 43: 0\n" /* doubleslab */ + "h: 17: 0\n" /* tree */ + "i: 5: 0\n" /* wood */ + "j: 64: 7\n" /* wooddoorblock */ + "k: 53: 3\n" /* woodstairs */ + "l: 85: 0\n" /* fence */ + "m: 19: 0\n" /* sponge */ + "n: 53: 2\n" /* woodstairs */ + "o:102: 0\n" /* glasspane */ + "p: 64:12\n" /* wooddoorblock */ + "q: 72: 0\n" /* woodplate */ + "r: 53: 7\n" /* woodstairs */ + "s: 50: 1\n" /* torch */ + "t: 50: 2\n" /* torch */ + "u: 53: 6\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaabbbbaaaa" + /* 1 */ "abbbbbbbbba" + /* 2 */ "abbbbbbbbba" + /* 3 */ "abbbbbbbbba" + /* 4 */ "abbbbbbbbba" + /* 5 */ "abbbbbbbbba" + /* 6 */ "abbbbbbbbba" + /* 7 */ "abbbbbbbbba" + /* 8 */ "aabbbbbbbaa" + /* 9 */ "aabbbbbbbaa" + /* 10 */ "aabbbbbbbaa" + /* 11 */ "aabbbbbbbaa" + /* 12 */ "aabbbbbbbaa" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmcccmmmm" + /* 1 */ "mcccccccccm" + /* 2 */ "mcccccccccm" + /* 3 */ "mcccccccccm" + /* 4 */ "mcccccccccm" + /* 5 */ "mcccccccccm" + /* 6 */ "mcccccccccm" + /* 7 */ "mcccccccccm" + /* 8 */ "mmbbbbbbbmm" + /* 9 */ "mmbbbbbbbmm" + /* 10 */ "mmbbbbbbbmm" + /* 11 */ "mmbbbbbbbmm" + /* 12 */ "mmbbbbbbbmm" + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....def...." + /* 1 */ ".ccccccccc." + /* 2 */ ".cggggcccc." + /* 3 */ ".cggggcccc." + /* 4 */ ".cggggcccc." + /* 5 */ ".cggggcccc." + /* 6 */ ".cggggcccc." + /* 7 */ ".ccccccccc." + /* 8 */ "..aaaaaaa.." + /* 9 */ "..aaaaaaa.." + /* 10 */ "..aaaaaaa.." + /* 11 */ "..aaaaaaa.." + /* 12 */ "..aaaaaaa.." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".hiiijiiih." + /* 2 */ ".i.g....ki." + /* 3 */ ".i.g....li." + /* 4 */ ".i.g....ni." + /* 5 */ ".i.......i." + /* 6 */ ".i.......i." + /* 7 */ ".hiiijiiih." + /* 8 */ "..l.....l.." + /* 9 */ "..l.....l.." + /* 10 */ "..l.....l.." + /* 11 */ "..l.....l.." + /* 12 */ "..lllllll.." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".hooipiooh." + /* 2 */ ".o.......o." + /* 3 */ ".o......qo." + /* 4 */ ".i.......i." + /* 5 */ ".o.......o." + /* 6 */ ".o.......o." + /* 7 */ ".hooipiooh." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "..........." + /* 11 */ "..........." + /* 12 */ "..........." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "nnnnnnnnnnn" + /* 1 */ "riiiiiiiiir" + /* 2 */ ".i.......i." + /* 3 */ ".i.......i." + /* 4 */ ".is.....ti." + /* 5 */ ".i.......i." + /* 6 */ ".i.......i." + /* 7 */ "uiiiiiiiiiu" + /* 8 */ "kkkkkkkkkkk" + /* 9 */ "..........." + /* 10 */ "..........." + /* 11 */ "..........." + /* 12 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "nnnnnnnnnnn" + /* 2 */ "riiiiiiiiir" + /* 3 */ ".i.......i." + /* 4 */ ".i.......i." + /* 5 */ ".i.......i." + /* 6 */ "uiiiiiiiiiu" + /* 7 */ "kkkkkkkkkkk" + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "..........." + /* 11 */ "..........." + /* 12 */ "..........." + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "nnnnnnnnnnn" + /* 3 */ "riiiiiiiiir" + /* 4 */ ".i.......i." + /* 5 */ "uiiiiiiiiiu" + /* 6 */ "kkkkkkkkkkk" + /* 7 */ "..........." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "..........." + /* 11 */ "..........." + /* 12 */ "..........." + + // Level 8 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "nnnnnnnnnnn" + /* 4 */ "iiiiiiiiiii" + /* 5 */ "kkkkkkkkkkk" + /* 6 */ "..........." + /* 7 */ "..........." + /* 8 */ "..........." + /* 9 */ "..........." + /* 10 */ "..........." + /* 11 */ "..........." + /* 12 */ "...........", + + // Connectors: + "-1: 5, 2, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse9x7Butcher + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouse9x7DoubleDoor: + // The data has been exported from the gallery Plains, area index 38, ID 87, created by Aloe_vera + { + // Size: + 11, 8, 9, // SizeX = 11, SizeY = 8, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 11, 7, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 67: 3\n" /* stairs */ + "f: 17: 0\n" /* tree */ + "g: 5: 0\n" /* wood */ + "h: 64: 7\n" /* wooddoorblock */ + "i:102: 0\n" /* glasspane */ + "j: 64:12\n" /* wooddoorblock */ + "k: 53: 2\n" /* woodstairs */ + "l: 53: 7\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 17: 4\n" /* tree */ + "o: 17: 8\n" /* tree */ + "p: 50: 3\n" /* torch */ + "q: 50: 4\n" /* torch */ + "r: 53: 6\n" /* woodstairs */ + "s: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "maaaaaaaaam" + /* 7 */ "maaaaaaaaam" + /* 8 */ "mmmmaaammmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....bcd...." + /* 1 */ ".aaaaaaaaa." + /* 2 */ ".aaaaaaaaa." + /* 3 */ ".aaaaaaaaa." + /* 4 */ ".aaaaaaaaa." + /* 5 */ ".aaaaaaaaa." + /* 6 */ ".aaaaaaaaa." + /* 7 */ ".aaaaaaaaa." + /* 8 */ "....bed...." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".fggfhfggf." + /* 2 */ ".g.......g." + /* 3 */ ".g.......g." + /* 4 */ ".f.......f." + /* 5 */ ".g.......g." + /* 6 */ ".g.......g." + /* 7 */ ".fggfhfggf." + /* 8 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".fiifjfiif." + /* 2 */ ".i.......i." + /* 3 */ ".i.......i." + /* 4 */ ".f.......f." + /* 5 */ ".i.......i." + /* 6 */ ".i.......i." + /* 7 */ ".fiifjfiif." + /* 8 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "kkkkkkkkkkk" + /* 1 */ "lfnnnnnnnfl" + /* 2 */ ".o..p.p..o." + /* 3 */ ".o.......o." + /* 4 */ ".o.......o." + /* 5 */ ".o.......o." + /* 6 */ ".o..q.q..o." + /* 7 */ "rfnnnnnnnfr" + /* 8 */ "sssssssssss" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "kkkkkkkkkkk" + /* 2 */ "lgggggggggl" + /* 3 */ ".g.......g." + /* 4 */ ".g.......g." + /* 5 */ ".g.......g." + /* 6 */ "rgggggggggr" + /* 7 */ "sssssssssss" + /* 8 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "kkkkkkkkkkk" + /* 3 */ "lgggggggggl" + /* 4 */ ".g.......g." + /* 5 */ "rgggggggggr" + /* 6 */ "sssssssssss" + /* 7 */ "..........." + /* 8 */ "..........." + + // Level 7 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "kkkkkkkkkkk" + /* 4 */ "ggggggggggg" + /* 5 */ "sssssssssss" + /* 6 */ "..........." + /* 7 */ "..........." + /* 8 */ "...........", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouse9x7DoubleDoor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouseL13x14: + // The data has been exported from the gallery Plains, area index 39, ID 90, created by STR_Warrior + { + // Size: + 15, 9, 16, // SizeX = 15, SizeY = 9, SizeZ = 16 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 15, 8, 16, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "A: 53: 7\n" /* woodstairs */ + "B: 53: 4\n" /* woodstairs */ + "C: 53: 5\n" /* woodstairs */ + "D: 53: 6\n" /* woodstairs */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 43: 0\n" /* doubleslab */ + "f: 17: 0\n" /* tree */ + "g: 5: 0\n" /* wood */ + "h: 64: 7\n" /* wooddoorblock */ + "i: 96: 8\n" /* trapdoor */ + "j: 61: 2\n" /* furnace */ + "k: 53: 3\n" /* woodstairs */ + "l: 85: 0\n" /* fence */ + "m: 19: 0\n" /* sponge */ + "n: 53: 2\n" /* woodstairs */ + "o: 53: 1\n" /* woodstairs */ + "p: 53: 0\n" /* woodstairs */ + "q: 47: 0\n" /* bookshelf */ + "r:102: 0\n" /* glasspane */ + "s: 64:12\n" /* wooddoorblock */ + "t: 72: 0\n" /* woodplate */ + "u: 17: 4\n" /* tree */ + "v: 17: 8\n" /* tree */ + "w: 50: 3\n" /* torch */ + "x: 50: 1\n" /* torch */ + "y: 50: 4\n" /* torch */ + "z: 50: 2\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "maaaaaaaaaaaaam" + /* 2 */ "maaaaaaaaaaaaam" + /* 3 */ "maaaaaaaaaaaaam" + /* 4 */ "maaaaaaaaaaaaam" + /* 5 */ "maaaaaaaaaaaaam" + /* 6 */ "maaaaaaaaaaaaam" + /* 7 */ "maaaaaaaaaaaaam" + /* 8 */ "mmmmmmmmaaaaaam" + /* 9 */ "mmmmmmmmaaaaaam" + /* 10 */ "mmmmmmmmaaaaaam" + /* 11 */ "mmmmmmmmaaaaaam" + /* 12 */ "mmmmmmmmaaaaaam" + /* 13 */ "mmmmmmmmaaaaaam" + /* 14 */ "mmmmmmmmaaaaaam" + /* 15 */ "mmmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "......bcd......" + /* 1 */ ".aaaaaaaaaaaaa." + /* 2 */ ".aeeeeaaaaaaaa." + /* 3 */ ".aeeeeaaaaaaaa." + /* 4 */ ".aaaaaaaaaaaaa." + /* 5 */ ".aaaaaaaaaaaaa." + /* 6 */ ".aaaaaaaaaaaaa." + /* 7 */ ".aaaaaaaaaaaaa." + /* 8 */ "........aaaaaa." + /* 9 */ "mmmmmmm.aaaaaa." + /* 10 */ "mmmmmmm.aaaaaa." + /* 11 */ "mmmmmmm.aaaaaa." + /* 12 */ "mmmmmmm.aaaaaa." + /* 13 */ "mmmmmmm.aaaaaa." + /* 14 */ "mmmmmmm.aaaaaa." + /* 15 */ "mmmmmmm........" + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".fggggfhfggggf." + /* 2 */ ".g...i.......g." + /* 3 */ ".gjeee......kg." + /* 4 */ ".f..........lg." + /* 5 */ ".g..........ng." + /* 6 */ ".g.olp..ol...g." + /* 7 */ ".fggggggfn...f." + /* 8 */ "........g....g." + /* 9 */ "mmmmmmm.gk...g." + /* 10 */ "mmmmmmm.gl..kg." + /* 11 */ "mmmmmmm.gn..lg." + /* 12 */ "mmmmmmm.g...ng." + /* 13 */ "mmmmmmm.gq..qg." + /* 14 */ "mmmmmmm.fggggf." + /* 15 */ "mmmmmmm........" + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".fgrrgfsfgrrgf." + /* 2 */ ".g...........g." + /* 3 */ ".g...........r." + /* 4 */ ".f..........tr." + /* 5 */ ".g...........r." + /* 6 */ ".g..t....t...g." + /* 7 */ ".fgrrrrgf....f." + /* 8 */ "........g....g." + /* 9 */ "mmmmmmm.r....r." + /* 10 */ "mmmmmmm.rt...r." + /* 11 */ "mmmmmmm.r...tr." + /* 12 */ "mmmmmmm.r....r." + /* 13 */ "mmmmmmm.gq..qg." + /* 14 */ "mmmmmmm.fgrrgf." + /* 15 */ "mmmmmmm........" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".fuuuuuuuuuuuf." + /* 2 */ ".v....w.w....v." + /* 3 */ ".v...........v." + /* 4 */ ".vx..........v." + /* 5 */ ".v...........v." + /* 6 */ ".v......y....v." + /* 7 */ ".fuuuuuufx..zv." + /* 8 */ "........v....v." + /* 9 */ "mmmmmmm.v....v." + /* 10 */ "mmmmmmm.v....v." + /* 11 */ "mmmmmmm.v....v." + /* 12 */ "mmmmmmm.v....v." + /* 13 */ "mmmmmmm.v.yy.v." + /* 14 */ "mmmmmmm.fuuuuf." + /* 15 */ "mmmmmmm........" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "nnnnnnnnnnnnnno" + /* 1 */ "pgggggggggggggo" + /* 2 */ "pgAAAAAAAAAABgo" + /* 3 */ "pgC.........Bgo" + /* 4 */ "pgC.........Bgo" + /* 5 */ "pgC.........Bgo" + /* 6 */ "pgCDDDDDDD..Bgo" + /* 7 */ "pggggggggC..Bgo" + /* 8 */ "pkkkkkkpgC..Bgo" + /* 9 */ "mmmmmmmpgC..Bgo" + /* 10 */ "mmmmmmmpgC..Bgo" + /* 11 */ "mmmmmmmpgC..Bgo" + /* 12 */ "mmmmmmmpgC..Bgo" + /* 13 */ "mmmmmmmpgCDDBgo" + /* 14 */ "mmmmmmmpggggggo" + /* 15 */ "mmmmmmmpkkkkkkk" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".pnnnnnnnnnnno." + /* 2 */ ".pgggggggggggo." + /* 3 */ ".pgggggggggggo." + /* 4 */ ".pgggggggggggo." + /* 5 */ ".pgggggggggggo." + /* 6 */ ".pgggggggggggo." + /* 7 */ ".pkkkkkkkggggo." + /* 8 */ "........pggggo." + /* 9 */ "mmmmmmm.pggggo." + /* 10 */ "mmmmmmm.pggggo." + /* 11 */ "mmmmmmm.pggggo." + /* 12 */ "mmmmmmm.pggggo." + /* 13 */ "mmmmmmm.pggggo." + /* 14 */ "mmmmmmm.kkkkko." + /* 15 */ "mmmmmmm........" + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..nnnnnnnnnnn.." + /* 3 */ "..pgggggggggo.." + /* 4 */ "..pgggggggggo.." + /* 5 */ "..pgggggggggo.." + /* 6 */ "..kkkkkkkkggo.." + /* 7 */ ".........pggo.." + /* 8 */ ".........pggo.." + /* 9 */ "mmmmmmm..pggo.." + /* 10 */ "mmmmmmm..pggo.." + /* 11 */ "mmmmmmm..pggo.." + /* 12 */ "mmmmmmm..pggo.." + /* 13 */ "mmmmmmm..kkko.." + /* 14 */ "mmmmmmm........" + /* 15 */ "mmmmmmm........" + + // Level 8 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "...pnnnnnnno..." + /* 4 */ "...pgggggggo..." + /* 5 */ "...pkkkkkkpo..." + /* 6 */ "..........po..." + /* 7 */ "..........po..." + /* 8 */ "..........po..." + /* 9 */ "mmmmmmm...po..." + /* 10 */ "mmmmmmm...po..." + /* 11 */ "mmmmmmm...po..." + /* 12 */ "mmmmmmm...pk..." + /* 13 */ "mmmmmmm........" + /* 14 */ "mmmmmmm........" + /* 15 */ "mmmmmmm........", + + // Connectors: + "-1: 7, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouseL13x14 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouseL14x14: + // The data has been exported from the gallery Plains, area index 0, ID 4, created by Aloe_vera + { + // Size: + 16, 8, 16, // SizeX = 16, SizeY = 8, SizeZ = 16 + + // Hitbox (relative to bounding box): + -1, 1, 0, // MinX, MinY, MinZ + 16, 7, 16, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 2: 0\n" /* grass */ + "c: 67: 0\n" /* stairs */ + "d: 67: 2\n" /* stairs */ + "e: 67: 1\n" /* stairs */ + "f: 5: 0\n" /* wood */ + "g: 67: 3\n" /* stairs */ + "h: 17: 0\n" /* tree */ + "i: 64: 7\n" /* wooddoorblock */ + "j: 64: 5\n" /* wooddoorblock */ + "k:102: 0\n" /* glasspane */ + "l: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */ + "n: 53: 2\n" /* woodstairs */ + "o: 53: 1\n" /* woodstairs */ + "p: 53: 7\n" /* woodstairs */ + "q: 53: 6\n" /* woodstairs */ + "r: 53: 3\n" /* woodstairs */ + "s: 53: 0\n" /* woodstairs */ + "t: 53: 5\n" /* woodstairs */ + "u: 53: 4\n" /* woodstairs */ + "v: 50: 3\n" /* torch */ + "w: 50: 2\n" /* torch */ + "x: 50: 4\n" /* torch */ + "y: 50: 1\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "mmmmmmmmaaammmmm" + /* 1 */ "maaaaaaaaaaaaaam" + /* 2 */ "maaaaaaaaaaaaaam" + /* 3 */ "maaaaaaaaaaaaaam" + /* 4 */ "maaaaaaaaaaaaaam" + /* 5 */ "maaaaaaaaaaaaaam" + /* 6 */ "maaaaaaaaaaaaaam" + /* 7 */ "maaaaaaaaaaaaaam" + /* 8 */ "bbbbbaaaaaaaaaam" + /* 9 */ "bbbbbbbbaaaaaaam" + /* 10 */ "bbbbbbbbaaaaaaam" + /* 11 */ "bbbbbbbbaaaaaaam" + /* 12 */ "bbbbbbbbaaaaaaam" + /* 13 */ "bbbbbbbbaaaaaaam" + /* 14 */ "bbbbbbbbaaaaaaam" + /* 15 */ "bbbbbbbbmmmmmmmm" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "........cde....." + /* 1 */ ".aaaaaaaaaaaaaa." + /* 2 */ ".affffffffffffa." + /* 3 */ ".affffffffffffa." + /* 4 */ ".affffffffffffa." + /* 5 */ ".affffffffffffa." + /* 6 */ ".affffffffffffa." + /* 7 */ ".aaaaaaaafffffa." + /* 8 */ ".....cgeafffffa." + /* 9 */ "........afffffa." + /* 10 */ "........afffffa." + /* 11 */ "........afffffa." + /* 12 */ "........afffffa." + /* 13 */ "........afffffa." + /* 14 */ "........aaaaaaa." + /* 15 */ "................" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".hffffffhihfffh." + /* 2 */ ".f............f." + /* 3 */ ".f............f." + /* 4 */ ".f............f." + /* 5 */ ".f............f." + /* 6 */ ".f............f." + /* 7 */ ".hffffjfh.....f." + /* 8 */ "........f.....f." + /* 9 */ "........f.....f." + /* 10 */ "........f.....f." + /* 11 */ "........f.....f." + /* 12 */ "........f.....f." + /* 13 */ "........f.....f." + /* 14 */ "........hfffffh." + /* 15 */ "................" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".hfkkfkkhlhkkfh." + /* 2 */ ".k............f." + /* 3 */ ".k............k." + /* 4 */ ".k............k." + /* 5 */ ".k............f." + /* 6 */ ".k............k." + /* 7 */ ".hfkkflfh.....k." + /* 8 */ "........f.....f." + /* 9 */ "........k.....k." + /* 10 */ "........k.....k." + /* 11 */ "........f.....f." + /* 12 */ "........k.....k." + /* 13 */ "........k.....k." + /* 14 */ "........hkkkkkh." + /* 15 */ "................" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "nnnnnnnnnnnnnnno" + /* 1 */ "phffffffhfhfffho" + /* 2 */ ".f............fo" + /* 3 */ ".f............fo" + /* 4 */ ".f............fo" + /* 5 */ ".f............fo" + /* 6 */ ".f............fo" + /* 7 */ "qhffffffh.....fo" + /* 8 */ "rrrrrrrsf.....fo" + /* 9 */ ".......sf.....fo" + /* 10 */ ".......sf.....fo" + /* 11 */ ".......sf.....fo" + /* 12 */ ".......sf.....fo" + /* 13 */ ".......sf.....fo" + /* 14 */ ".......shfffffho" + /* 15 */ ".......st.....uo" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "nnnnnnnnnnnnnnn." + /* 2 */ "pfffffffffffffo." + /* 3 */ ".f.........v.fo." + /* 4 */ ".f..........wfo." + /* 5 */ ".f......x....fo." + /* 6 */ "qfffffffff...fo." + /* 7 */ "rrrrrrrrsfy..fo." + /* 8 */ "........sf...fo." + /* 9 */ "........sf...fo." + /* 10 */ "........sf...fo." + /* 11 */ "........sf...fo." + /* 12 */ "........sf...fo." + /* 13 */ "........sf...fo." + /* 14 */ "........sfffffo." + /* 15 */ "........st...uo." + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "nnnnnnnnnnnnno.." + /* 3 */ "pffffffffffffo.." + /* 4 */ ".fy.........fo.." + /* 5 */ "qffffffffff.fo.." + /* 6 */ "rrrrrrrrrsf.fo.." + /* 7 */ ".........sf.fo.." + /* 8 */ ".........sf.fo.." + /* 9 */ ".........sf.fo.." + /* 10 */ ".........sf.fo.." + /* 11 */ ".........sf.fo.." + /* 12 */ ".........sf.fo.." + /* 13 */ ".........sfxfo.." + /* 14 */ ".........sfffo.." + /* 15 */ ".........st.uo.." + + // Level 7 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "nnnnnnnnnnnnn..." + /* 4 */ "ffffffffffffo..." + /* 5 */ "rrrrrrrrrrsfo..." + /* 6 */ "..........sfo..." + /* 7 */ "..........sfo..." + /* 8 */ "..........sfo..." + /* 9 */ "..........sfo..." + /* 10 */ "..........sfo..." + /* 11 */ "..........sfo..." + /* 12 */ "..........sfo..." + /* 13 */ "..........sfo..." + /* 14 */ "..........sfo..." + /* 15 */ "..........sfo...", + + // Connectors: + "-1: 9, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouseL14x14 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouseL9x9: + // The data has been exported from the gallery Plains, area index 42, ID 93, created by xoft + { + // Size: + 11, 7, 11, // SizeX = 11, SizeY = 7, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 11, 6, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h:102: 0\n" /* glasspane */ + "i: 64:12\n" /* wooddoorblock */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 7\n" /* woodstairs */ + "l: 53: 1\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 50: 3\n" /* torch */ + "o: 50: 4\n" /* torch */ + "p: 53: 6\n" /* woodstairs */ + "q: 50: 1\n" /* torch */ + "r: 50: 2\n" /* torch */ + "s: 53: 3\n" /* woodstairs */ + "t: 53: 0\n" /* woodstairs */ + "u: 53: 5\n" /* woodstairs */ + "v: 53: 4\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "mmmmaaammmm" + /* 1 */ "maaaaaaaaam" + /* 2 */ "maaaaaaaaam" + /* 3 */ "maaaaaaaaam" + /* 4 */ "maaaaaaaaam" + /* 5 */ "maaaaaaaaam" + /* 6 */ "mmmmmaaaaam" + /* 7 */ "mmmmmaaaaam" + /* 8 */ "mmmmmaaaaam" + /* 9 */ "mmmmmaaaaam" + /* 10 */ "mmmmmmmmmmm" + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....bcd...." + /* 1 */ ".aaaaaaaaa." + /* 2 */ ".aaaaaaaaa." + /* 3 */ ".aaaaaaaaa." + /* 4 */ ".aaaaaaaaa." + /* 5 */ ".aaaaaaaaa." + /* 6 */ ".....aaaaa." + /* 7 */ ".....aaaaa." + /* 8 */ ".....aaaaa." + /* 9 */ ".....aaaaa." + /* 10 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".efffgfffe." + /* 2 */ ".f.......f." + /* 3 */ ".f.......f." + /* 4 */ ".f.......f." + /* 5 */ ".efffe...f." + /* 6 */ ".....f...f." + /* 7 */ ".....f...f." + /* 8 */ ".....f...f." + /* 9 */ ".....efffe." + /* 10 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ehhfifhhe." + /* 2 */ ".h.......h." + /* 3 */ ".h.......h." + /* 4 */ ".h.......h." + /* 5 */ ".ehhhe...f." + /* 6 */ ".....h...h." + /* 7 */ ".....h...h." + /* 8 */ ".....h...h." + /* 9 */ ".....ehhhe." + /* 10 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "jjjjjjjjjjj" + /* 1 */ "kfffffffffl" + /* 2 */ ".f..n.n..fl" + /* 3 */ ".f.......fl" + /* 4 */ ".f...o...fl" + /* 5 */ "pfffffq.rfl" + /* 6 */ "sssssf...fl" + /* 7 */ "....tf...fl" + /* 8 */ "....tf...fl" + /* 9 */ "....tfffffl" + /* 10 */ "....tu...vl" + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "jjjjjjjjjl." + /* 2 */ "kffffffffl." + /* 3 */ ".f......fl." + /* 4 */ "pffffff.fl." + /* 5 */ "ssssssf.fl." + /* 6 */ ".....tf.fl." + /* 7 */ ".....tf.fl." + /* 8 */ ".....tf.fl." + /* 9 */ ".....tfffl." + /* 10 */ ".....tu.vl." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "jjjjjjjjj.." + /* 3 */ "ffffffffl.." + /* 4 */ "sssssstfl.." + /* 5 */ "......tfl.." + /* 6 */ "......tfl.." + /* 7 */ "......tfl.." + /* 8 */ "......tfl.." + /* 9 */ "......tfl.." + /* 10 */ "......tfl..", + + // Connectors: + "-1: 5, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouseL9x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenHouseU13x9: + // The data has been exported from the gallery Plains, area index 43, ID 94, created by xoft + { + // Size: + 15, 7, 11, // SizeX = 15, SizeY = 7, SizeZ = 11 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 15, 6, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 64: 7\n" /* wooddoorblock */ + "h:102: 0\n" /* glasspane */ + "i: 64:12\n" /* wooddoorblock */ + "j: 53: 2\n" /* woodstairs */ + "k: 53: 0\n" /* woodstairs */ + "l: 53: 1\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 50: 3\n" /* torch */ + "o: 50: 4\n" /* torch */ + "p: 50: 2\n" /* torch */ + "q: 50: 1\n" /* torch */ + "r: 53: 3\n" /* woodstairs */ + "s: 53: 5\n" /* woodstairs */ + "t: 53: 4\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "mmmmmmaaammmmmm" + /* 1 */ "maaaaaaaaaaaaam" + /* 2 */ "maaaaaaaaaaaaam" + /* 3 */ "maaaaaaaaaaaaam" + /* 4 */ "maaaaaaaaaaaaam" + /* 5 */ "maaaaaaaaaaaaam" + /* 6 */ "maaaaammmaaaaam" + /* 7 */ "maaaaammmaaaaam" + /* 8 */ "maaaaammmaaaaam" + /* 9 */ "maaaaammmaaaaam" + /* 10 */ "mmmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "......bcd......" + /* 1 */ ".aaaaaaaaaaaaa." + /* 2 */ ".aaaaaaaaaaaaa." + /* 3 */ ".aaaaaaaaaaaaa." + /* 4 */ ".aaaaaaaaaaaaa." + /* 5 */ ".aaaaaaaaaaaaa." + /* 6 */ ".aaaaa...aaaaa." + /* 7 */ ".aaaaa...aaaaa." + /* 8 */ ".aaaaa...aaaaa." + /* 9 */ ".aaaaa...aaaaa." + /* 10 */ "..............." + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".efffffgfffffe." + /* 2 */ ".f...........f." + /* 3 */ ".f...........f." + /* 4 */ ".f...........f." + /* 5 */ ".f...efffe...f." + /* 6 */ ".f...f...f...f." + /* 7 */ ".f...f...f...f." + /* 8 */ ".f...f...f...f." + /* 9 */ ".efffe...efffe." + /* 10 */ "..............." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".ehhhhfifhhhhe." + /* 2 */ ".h...........h." + /* 3 */ ".h...........h." + /* 4 */ ".h...........h." + /* 5 */ ".f...ehhhe...f." + /* 6 */ ".h...h...h...h." + /* 7 */ ".h...h...h...h." + /* 8 */ ".h...h...h...h." + /* 9 */ ".ehhhe...ehhhe." + /* 10 */ "..............." + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "jjjjjjjjjjjjjjj" + /* 1 */ "kfffffffffffffl" + /* 2 */ "kf....n.n....fl" + /* 3 */ "kf...........fl" + /* 4 */ "kf...o...o...fl" + /* 5 */ "kf..pfffffq..fl" + /* 6 */ "kf...frrrf...fl" + /* 7 */ "kf...fl.kf...fl" + /* 8 */ "kf...fl.kf...fl" + /* 9 */ "kfffffl.kfffffl" + /* 10 */ "ks...tl.ks...tl" + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".jjjjjjjjjjjjl." + /* 2 */ ".kfffffffffffl." + /* 3 */ ".kfffffffffffl." + /* 4 */ ".kfffffffffffl." + /* 5 */ ".kffflrrrrfffl." + /* 6 */ ".kfffl...kfffl." + /* 7 */ ".kfffl...kfffl." + /* 8 */ ".kfffl...kfffl." + /* 9 */ ".kfffl...kfffl." + /* 10 */ ".ks.tl...ks.tl." + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..kjjjjjjjjjj.." + /* 3 */ "..kfffffffffl.." + /* 4 */ "..kflrrrrrkfl.." + /* 5 */ "..kfl.....kfl.." + /* 6 */ "..kfl.....kfl.." + /* 7 */ "..kfl.....kfl.." + /* 8 */ "..kfl.....kfl.." + /* 9 */ "..kfl.....kfl.." + /* 10 */ "..kfl.....kfl..", + + // Connectors: + "-1: 7, 1, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenHouseU13x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenMill5x5: + // The data has been exported from the gallery Plains, area index 60, ID 111, created by Aloe_vera + { + // Size: + 9, 17, 13, // SizeX = 9, SizeY = 17, SizeZ = 13 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 8, 16, 12, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 2\n" /* stairs */ + "c: 67: 1\n" /* stairs */ + "d: 67: 3\n" /* stairs */ + "e: 17: 0\n" /* tree */ + "f: 5: 0\n" /* wood */ + "g: 54: 4\n" /* chest */ + "h:154: 4\n" /* hopper */ + "i: 64: 4\n" /* wooddoorblock */ + "j:102: 0\n" /* glasspane */ + "k: 85: 0\n" /* fence */ + "l: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */ + "n: 50: 2\n" /* torch */ + "o: 35: 0\n" /* wool */ + "p: 17: 4\n" /* tree */ + "q: 17: 8\n" /* tree */ + "r: 53: 2\n" /* woodstairs */ + "s: 53: 7\n" /* woodstairs */ + "t: 53: 6\n" /* woodstairs */ + "u: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "mmmmmmmmm" + /* 1 */ "mmmmmmmmm" + /* 2 */ "mmmmmmmmm" + /* 3 */ "mmmmmmmmm" + /* 4 */ "maaaaammm" + /* 5 */ "maaaaaamm" + /* 6 */ "maaaaaamm" + /* 7 */ "maaaaaamm" + /* 8 */ "maaaaammm" + /* 9 */ "mmmmmmmmm" + /* 10 */ "mmmmmmmmm" + /* 11 */ "mmmmmmmmm" + /* 12 */ "mmmmmmmmm" + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".aaaaa..." + /* 5 */ ".aaaaab.." + /* 6 */ ".aaaaac.." + /* 7 */ ".aaaaad.." + /* 8 */ ".aaaaa..." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".efffe..." + /* 5 */ ".f...f..." + /* 6 */ ".fgh.i..." + /* 7 */ ".f...f..." + /* 8 */ ".efffe..." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".ejjje..." + /* 5 */ ".j...f..." + /* 6 */ ".j.k.l..." + /* 7 */ ".j...f..." + /* 8 */ ".ejjje..." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".efffe..." + /* 5 */ ".f..nf..." + /* 6 */ ".f.k.f..." + /* 7 */ ".f..nf..k" + /* 8 */ ".efffe..o" + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".epppe..." + /* 5 */ ".q...q..." + /* 6 */ ".q.k.q..." + /* 7 */ ".q...q..k" + /* 8 */ ".epppe..o" + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 6 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".efffe..." + /* 5 */ ".f...f..." + /* 6 */ ".f.k.f..k" + /* 7 */ ".f...f..o" + /* 8 */ ".efffe..o" + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 7 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ ".ejjje..." + /* 5 */ ".j...j..." + /* 6 */ ".j.k.j..k" + /* 7 */ ".j...j..o" + /* 8 */ ".ejjje..." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 8 + /* z\x* 012345678 */ + /* 0 */ "........o" + /* 1 */ "........o" + /* 2 */ "........o" + /* 3 */ "........." + /* 4 */ ".efffe..." + /* 5 */ ".f...f..k" + /* 6 */ ".f.k.f..o" + /* 7 */ ".f...f..o" + /* 8 */ ".efffe..." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 9 + /* z\x* 012345678 */ + /* 0 */ "........k" + /* 1 */ "........k" + /* 2 */ "........o" + /* 3 */ "........o" + /* 4 */ ".epppe..o" + /* 5 */ ".q...q..k" + /* 6 */ ".q.k.q..o" + /* 7 */ ".q...q..k" + /* 8 */ ".epppe..k" + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 10 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........k" + /* 3 */ "rrrrrrr.k" + /* 4 */ "sfffffs.o" + /* 5 */ ".f...f..o" + /* 6 */ ".f.kppppp" + /* 7 */ ".f...f..o" + /* 8 */ "tffffft.o" + /* 9 */ "uuuuuuu.k" + /* 10 */ "........k" + /* 11 */ "........." + /* 12 */ "........." + + // Level 11 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ "rrrrrrr.k" + /* 5 */ "sfffffs.k" + /* 6 */ ".f...f..o" + /* 7 */ "tffffft.k" + /* 8 */ "uuuuuuu.o" + /* 9 */ "........o" + /* 10 */ "........o" + /* 11 */ "........k" + /* 12 */ "........k" + + // Level 12 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ "........." + /* 5 */ "rrrrrrr.o" + /* 6 */ "fffffff.o" + /* 7 */ "uuuuuuu.k" + /* 8 */ "........." + /* 9 */ "........." + /* 10 */ "........o" + /* 11 */ "........o" + /* 12 */ "........o" + + // Level 13 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ "........." + /* 5 */ "........o" + /* 6 */ "........k" + /* 7 */ "........." + /* 8 */ "........." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 14 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ "........o" + /* 5 */ "........o" + /* 6 */ "........k" + /* 7 */ "........." + /* 8 */ "........." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 15 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ "........o" + /* 5 */ "........k" + /* 6 */ "........." + /* 7 */ "........." + /* 8 */ "........." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ "........." + + // Level 16 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "........." + /* 4 */ "........o" + /* 5 */ "........k" + /* 6 */ "........." + /* 7 */ "........." + /* 8 */ "........." + /* 9 */ "........." + /* 10 */ "........." + /* 11 */ "........." + /* 12 */ ".........", + + // Connectors: + "-1: 8, 1, 6: 5\n" /* Type -1, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenMill5x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // WoodenStables: + // The data has been exported from the gallery Plains, area index 55, ID 106, created by Aloe_vera + { + // Size: + 15, 9, 9, // SizeX = 15, SizeY = 9, SizeZ = 9 + + // Hitbox (relative to bounding box): + -1, -1, 0, // MinX, MinY, MinZ + 15, 8, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 4: 0\n" /* cobblestone */ + "b: 67: 0\n" /* stairs */ + "c: 67: 2\n" /* stairs */ + "d: 67: 1\n" /* stairs */ + "e: 3: 0\n" /* dirt */ + "f: 17: 0\n" /* tree */ + "g:107: 0\n" /* fencegate */ + "h:107: 4\n" /* fencegate */ + "i: 5: 0\n" /* wood */ + "j:107: 6\n" /* fencegate */ + "k: 85: 0\n" /* fence */ + "l:170: 0\n" /* haybale */ + "m: 19: 0\n" /* sponge */ + "n:170: 4\n" /* haybale */ + "o:170: 8\n" /* haybale */ + "p: 50: 1\n" /* torch */ + "q: 50: 2\n" /* torch */ + "r: 53: 2\n" /* woodstairs */ + "s: 53: 7\n" /* woodstairs */ + "t: 53: 6\n" /* woodstairs */ + "u: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "maaaaaaaaaaaaam" + /* 1 */ "maaaaaaaaaaaaam" + /* 2 */ "maaaaaaaaaaaaam" + /* 3 */ "maaaaaaaaaaaaam" + /* 4 */ "maaaaaaaaaaaaam" + /* 5 */ "maaaaaaaaaaaaam" + /* 6 */ "maaaaaaaaaaaaam" + /* 7 */ "maaaaaaaaaaaaam" + /* 8 */ "mmmmmmmmmmmmmmm" + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ ".bcccccccccccd." + /* 1 */ ".aaaaaaaaaaaaa." + /* 2 */ ".aeeeeeeeeeeea." + /* 3 */ ".aeeeeeeeeeeea." + /* 4 */ ".aeeeeeeeeeeea." + /* 5 */ ".aeeeeeeeeeeea." + /* 6 */ ".aeeeeeeeeeeea." + /* 7 */ ".aaaaaaaaaaaaa." + /* 8 */ "..............." + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".fghgighgigjgf." + /* 2 */ ".k...k...k...k." + /* 3 */ ".k...k...k...k." + /* 4 */ ".k...k...k...k." + /* 5 */ ".k...k...k...k." + /* 6 */ ".kl..k..nko..k." + /* 7 */ ".fkkkikkkikkkf." + /* 8 */ "..............." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".f...i...i...f." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ ".f...i...i...f." + /* 8 */ "..............." + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".fp.qip.qip.qf." + /* 2 */ "..............." + /* 3 */ "..............." + /* 4 */ "..............." + /* 5 */ "..............." + /* 6 */ "..............." + /* 7 */ ".f...i...i...f." + /* 8 */ "..............." + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "rrrrrrrrrrrrrrr" + /* 1 */ "siiiiiiiiiiiiis" + /* 2 */ ".i...........i." + /* 3 */ ".i...........i." + /* 4 */ ".i...........i." + /* 5 */ ".i...........i." + /* 6 */ ".i...........i." + /* 7 */ "tiiiiiiiiiiiiit" + /* 8 */ "uuuuuuuuuuuuuuu" + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "rrrrrrrrrrrrrrr" + /* 2 */ "siiiiiiiiiiiiis" + /* 3 */ ".i...........i." + /* 4 */ ".i...........i." + /* 5 */ ".i...........i." + /* 6 */ "tiiiiiiiiiiiiit" + /* 7 */ "uuuuuuuuuuuuuuu" + /* 8 */ "..............." + + // Level 7 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "rrrrrrrrrrrrrrr" + /* 3 */ "siiiiiiiiiiiiis" + /* 4 */ ".i...........i." + /* 5 */ "tiiiiiiiiiiiiit" + /* 6 */ "uuuuuuuuuuuuuuu" + /* 7 */ "..............." + /* 8 */ "..............." + + // Level 8 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "rrrrrrrrrrrrrrr" + /* 4 */ "iiiiiiiiiiiiiii" + /* 5 */ "uuuuuuuuuuuuuuu" + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "...............", + + // Connectors: + "-1: 7, 1, -1: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // WoodenStables +}; // g_PlainsVillagePrefabs + + + + + + +const cPrefab::sDef g_PlainsVillageStartingPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // CobbleWell4x4: + // The data has been exported from the gallery Plains, area index 1, ID 5, created by Aloe_vera + { + // Size: + 4, 13, 4, // SizeX = 4, SizeY = 13, SizeZ = 4 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 3, 12, 3, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 4: 0\n" /* cobblestone */ + "c: 8: 0\n" /* water */ + "d: 85: 0\n" /* fence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123 */ + /* 0 */ "aaaa" + /* 1 */ "aaaa" + /* 2 */ "aaaa" + /* 3 */ "aaaa" + + // Level 1 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 2 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 3 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 4 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 5 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 6 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 7 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 8 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 9 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "b..b" + /* 2 */ "b..b" + /* 3 */ "bbbb" + + // Level 10 + /* z\x* 0123 */ + /* 0 */ "d..d" + /* 1 */ "...." + /* 2 */ "...." + /* 3 */ "d..d" + + // Level 11 + /* z\x* 0123 */ + /* 0 */ "d..d" + /* 1 */ "...." + /* 2 */ "...." + /* 3 */ "d..d" + + // Level 12 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bbbb" + /* 2 */ "bbbb" + /* 3 */ "bbbb", + + // Connectors: + "2: 1, 9, 3: 3\n" /* Type 2, direction Z+ */ + "2: 2, 9, 0: 2\n" /* Type 2, direction Z- */ + "2: 0, 9, 1: 4\n" /* Type 2, direction X- */ + "2: 3, 9, 2: 5\n" /* Type 2, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // CobbleWell4x4 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MineEntrance: + // The data has been exported from the gallery Plains, area index 138, ID 446, created by STR_Warrior + { + // Size: + 7, 38, 7, // SizeX = 7, SizeY = 38, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 37, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 5: 0\n" /* wood */ + "b: 77: 2\n" /* stonebutton */ + "c: 66: 6\n" /* tracks */ + "d: 27: 1\n" /* poweredrail */ + "e: 66: 5\n" /* tracks */ + "f: 66: 9\n" /* tracks */ + "g: 66: 2\n" /* tracks */ + "h: 50: 4\n" /* torch */ + "i: 66: 4\n" /* tracks */ + "j: 66: 8\n" /* tracks */ + "k: 66: 3\n" /* tracks */ + "l: 66: 7\n" /* tracks */ + "m: 19: 0\n" /* sponge */ + "n: 50: 2\n" /* torch */ + "o: 2: 0\n" /* grass */ + "p: 53: 2\n" /* woodstairs */ + "q: 77: 1\n" /* stonebutton */ + "r: 27: 0\n" /* poweredrail */ + "s: 53: 7\n" /* woodstairs */ + "t: 53: 6\n" /* woodstairs */ + "u: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "maaaaam" + /* 1 */ "maaaaam" + /* 2 */ "maaaaam" + /* 3 */ "maaaaam" + /* 4 */ "maaaaam" + /* 5 */ "maaaaam" + /* 6 */ "mmmmmmm" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "mm...mm" + /* 1 */ "mm.abam" + /* 2 */ "mmcddam" + /* 3 */ "mae..am" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "mm...mm" + /* 1 */ "mm.a.mm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "mm.h.mm" + /* 1 */ "mm.a.mm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 11 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 12 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 13 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 14 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 15 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 16 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 17 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 18 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 19 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 20 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 21 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 22 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 23 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 24 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 25 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 26 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 27 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm.aamm" + /* 3 */ "ma..iam" + /* 4 */ "mm..jmm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 28 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmaklmm" + /* 3 */ "maa..am" + /* 4 */ "mm...mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 29 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mmc..mm" + /* 3 */ "mae.nam" + /* 4 */ "mmaa.mm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 30 + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "mmmammm" + /* 2 */ "mm...mm" + /* 3 */ "ma..aam" + /* 4 */ "mmfgamm" + /* 5 */ "mmmammm" + /* 6 */ "mmmmmmm" + + // Level 31 + /* z\x* 0123456 */ + /* 0 */ "ooomooo" + /* 1 */ "oaaaaao" + /* 2 */ "oa.aaao" + /* 3 */ "oa..iao" + /* 4 */ "oa..jao" + /* 5 */ "oaaaaao" + /* 6 */ "ooooooo" + + // Level 32 + /* z\x* 0123456 */ + /* 0 */ "...p..." + /* 1 */ ".aqrba." + /* 2 */ "...fl.." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ ".a...a." + /* 6 */ "......." + + // Level 33 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".a...a." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ ".a...a." + /* 6 */ "......." + + // Level 34 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".a...a." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ ".a...a." + /* 6 */ "......." + + // Level 35 + /* z\x* 0123456 */ + /* 0 */ "ppppppp" + /* 1 */ "saaaaas" + /* 2 */ ".a...a." + /* 3 */ ".a...a." + /* 4 */ ".a...a." + /* 5 */ "taaaaat" + /* 6 */ "uuuuuuu" + + // Level 36 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "ppppppp" + /* 2 */ "saaaaas" + /* 3 */ ".aaaaa." + /* 4 */ "taaaaat" + /* 5 */ "uuuuuuu" + /* 6 */ "......." + + // Level 37 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "ppppppp" + /* 3 */ "aaaaaaa" + /* 4 */ "uuuuuuu" + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "2: 6, 32, 3: 5\n" /* Type 2, direction X+ */ + "2: 3, 32, 6: 3\n" /* Type 2, direction Z+ */ + "2: 0, 32, 3: 4\n" /* Type 2, direction X- */ + "2: 3, 32, 0: 2\n" /* Type 2, direction Z- */ + "3: 3, 1, 0: 2\n" /* Type 3, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // MineEntrance + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // RoofedWell: + // The data has been exported from the gallery Plains, area index 119, ID 271, created by STR_Warrior + { + // Size: + 7, 15, 7, // SizeX = 7, SizeY = 15, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 14, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 4: 0\n" /* cobblestone */ + "c: 8: 0\n" /* water */ + "d: 3: 0\n" /* dirt */ + "e: 2: 0\n" /* grass */ + "f: 13: 0\n" /* gravel */ + "g:118: 3\n" /* cauldronblock */ + "h: 85: 0\n" /* fence */ + "i: 53: 2\n" /* woodstairs */ + "j: 53: 7\n" /* woodstairs */ + "k: 5: 0\n" /* wood */ + "l: 53: 4\n" /* woodstairs */ + "m: 19: 0\n" /* sponge */ + "n: 53: 5\n" /* woodstairs */ + "o: 53: 6\n" /* woodstairs */ + "p: 53: 3\n" /* woodstairs */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "eefffee" + /* 1 */ "ebbbbbe" + /* 2 */ "fbcccbf" + /* 3 */ "fbcccbf" + /* 4 */ "fbcccbf" + /* 5 */ "ebbbbbe" + /* 6 */ "eefffee" + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".bbbbb." + /* 2 */ ".b...b." + /* 3 */ ".b.g.b." + /* 4 */ ".b...b." + /* 5 */ ".bbbbb." + /* 6 */ "......." + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".h...h." + /* 2 */ "......." + /* 3 */ "...h..." + /* 4 */ "......." + /* 5 */ ".h...h." + /* 6 */ "......." + + // Level 11 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".h...h." + /* 2 */ "......." + /* 3 */ "...h..." + /* 4 */ "......." + /* 5 */ ".h...h." + /* 6 */ "......." + + // Level 12 + /* z\x* 0123456 */ + /* 0 */ "iiiiiii" + /* 1 */ "jkjjjkj" + /* 2 */ ".l...n." + /* 3 */ ".l.h.n." + /* 4 */ ".l...n." + /* 5 */ "okoooko" + /* 6 */ "ppppppp" + + // Level 13 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "iiiiiii" + /* 2 */ "jkjjjkj" + /* 3 */ ".k.h.k." + /* 4 */ "okoooko" + /* 5 */ "ppppppp" + /* 6 */ "......." + + // Level 14 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "iiiiiii" + /* 3 */ "kkkkkkk" + /* 4 */ "ppppppp" + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "2: 0, 9, 3: 4\n" /* Type 2, direction X- */ + "2: 3, 9, 6: 3\n" /* Type 2, direction Z+ */ + "2: 6, 9, 3: 5\n" /* Type 2, direction X+ */ + "2: 3, 9, 0: 2\n" /* Type 2, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // RoofedWell +}; + + + + + +// The prefab counts: + +const size_t g_PlainsVillagePrefabsCount = ARRAYCOUNT(g_PlainsVillagePrefabs); + +const size_t g_PlainsVillageStartingPrefabsCount = ARRAYCOUNT(g_PlainsVillageStartingPrefabs); + diff --git a/src/Generating/Prefabs/PlainsVillagePrefabs.h b/src/Generating/Prefabs/PlainsVillagePrefabs.h new file mode 100644 index 000000000..087783b1e --- /dev/null +++ b/src/Generating/Prefabs/PlainsVillagePrefabs.h @@ -0,0 +1,15 @@ + +// PlainsVillagePrefabs.h + +// Declares the prefabs in the group PlainsVillage + +#include "../Prefab.h" + + + + + +extern const cPrefab::sDef g_PlainsVillagePrefabs[]; +extern const cPrefab::sDef g_PlainsVillageStartingPrefabs[]; +extern const size_t g_PlainsVillagePrefabsCount; +extern const size_t g_PlainsVillageStartingPrefabsCount; diff --git a/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp new file mode 100644 index 000000000..4f0efdcc6 --- /dev/null +++ b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.cpp @@ -0,0 +1,1558 @@ + +// SandFlatRoofVillagePrefabs.cpp + +// Defines the prefabs in the group SandFlatRoofVillage + +// NOTE: This file has been generated automatically by GalExport! +// Any manual changes will be overwritten by the next automatic export! + +#include "Globals.h" +#include "SandFlatRoofVillagePrefabs.h" + + + + + +const cPrefab::sDef g_SandFlatRoofVillagePrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Forge: + // The data has been exported from the gallery Desert, area index 32, ID 173, created by Aloe_vera + { + // Size: + 12, 5, 10, // SizeX = 12, SizeY = 5, SizeZ = 10 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 11, 4, 9, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 2\n" /* sandstonestairs */ + "b:128: 1\n" /* sandstonestairs */ + "c:128: 0\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e:128: 3\n" /* sandstonestairs */ + "f:171:15\n" /* carpet */ + "g: 64: 6\n" /* wooddoorblock */ + "h:171: 0\n" /* carpet */ + "i:171:14\n" /* carpet */ + "j: 61: 2\n" /* furnace */ + "k: 10: 0\n" /* lava */ + "l: 54: 2\n" /* chest */ + "m: 19: 0\n" /* sponge */ + "n: 24: 2\n" /* sandstone */ + "o: 64:12\n" /* wooddoorblock */ + "p: 50: 1\n" /* torch */ + "q:101: 0\n" /* ironbars */ + "r:128: 4\n" /* sandstonestairs */ + "s:128: 6\n" /* sandstonestairs */ + "t:128: 5\n" /* sandstonestairs */ + "u:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "aaaaaab....." + /* 1 */ "cdddddddddd." + /* 2 */ "cdddddddddd." + /* 3 */ "cdddddddddd." + /* 4 */ "cdddddddddd." + /* 5 */ "edddddddddd." + /* 6 */ ".dddddddddd." + /* 7 */ ".dddddddddd." + /* 8 */ ".dddddddddd." + /* 9 */ "............" + + // Level 1 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".d....ddddd." + /* 2 */ "......dfffd." + /* 3 */ "......ghfhd." + /* 4 */ "......diiid." + /* 5 */ ".d....dhfhd." + /* 6 */ ".djddjdfffd." + /* 7 */ ".ddkkddl..d." + /* 8 */ ".dddddddddd." + /* 9 */ "............" + + // Level 2 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".n....nn.nn." + /* 2 */ "......n...n." + /* 3 */ "......o...n." + /* 4 */ "......n....." + /* 5 */ ".n....n...n." + /* 6 */ ".n....n...n." + /* 7 */ ".n....n...n." + /* 8 */ ".nnn.nnn.nn." + /* 9 */ "............" + + // Level 3 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "............" + /* 1 */ ".d....ddddd." + /* 2 */ "......d...d." + /* 3 */ "......d...d." + /* 4 */ "......dp..d." + /* 5 */ ".d....d...d." + /* 6 */ ".dqqqqd...d." + /* 7 */ ".d....d...d." + /* 8 */ ".dddddddddd." + /* 9 */ "............" + + // Level 4 + /* z\x* 11 */ + /* * 012345678901 */ + /* 0 */ "rsssssssssss" + /* 1 */ "rddddddddddt" + /* 2 */ "rddddddddddt" + /* 3 */ "rddddddddddt" + /* 4 */ "rddddddddddt" + /* 5 */ "rddddddddddt" + /* 6 */ "rddddddddddt" + /* 7 */ "rddddddddddt" + /* 8 */ "rddddddddddt" + /* 9 */ "uuuuuuuuuuut", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Forge + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House11x7: + // The data has been exported from the gallery Desert, area index 31, ID 172, created by Aloe_vera + { + // Size: + 13, 5, 9, // SizeX = 13, SizeY = 5, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 4, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171: 0\n" /* carpet */ + "g:171:15\n" /* carpet */ + "h:171:14\n" /* carpet */ + "i: 24: 2\n" /* sandstone */ + "j: 64:12\n" /* wooddoorblock */ + "k: 50: 3\n" /* torch */ + "l: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 50: 2\n" /* torch */ + "o: 50: 4\n" /* torch */ + "p:128: 4\n" /* sandstonestairs */ + "q:128: 6\n" /* sandstonestairs */ + "r:128: 5\n" /* sandstonestairs */ + "s:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "..abc........" + /* 1 */ ".ddddddddddd." + /* 2 */ ".ddddddddddd." + /* 3 */ ".ddddddddddd." + /* 4 */ ".ddddddddddd." + /* 5 */ ".ddddddddddd." + /* 6 */ ".ddddddddddd." + /* 7 */ ".ddddddddddd." + /* 8 */ "............." + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".ddedddddddd." + /* 2 */ ".dffgggggffd." + /* 3 */ ".dfghhhhhgfd." + /* 4 */ ".dfghfffhgfd." + /* 5 */ ".dfghhhhhgfd." + /* 6 */ ".dffgggggffd." + /* 7 */ ".ddddddddddd." + /* 8 */ "............." + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".iiji.iii.ii." + /* 2 */ ".i.........i." + /* 3 */ ".i.........i." + /* 4 */ "............." + /* 5 */ ".i.........i." + /* 6 */ ".i.........i." + /* 7 */ ".ii.ii.ii.ii." + /* 8 */ "............." + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".ddddddddddd." + /* 2 */ ".d..k..k...d." + /* 3 */ ".d.........d." + /* 4 */ ".dl.......nd." + /* 5 */ ".d.........d." + /* 6 */ ".d....o....d." + /* 7 */ ".ddddddddddd." + /* 8 */ "............." + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "pqqqqqqqqqqqq" + /* 1 */ "pdddddddddddr" + /* 2 */ "pdddddddddddr" + /* 3 */ "pdddddddddddr" + /* 4 */ "pdddddddddddr" + /* 5 */ "pdddddddddddr" + /* 6 */ "pdddddddddddr" + /* 7 */ "pdddddddddddr" + /* 8 */ "ssssssssssssr", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House11x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House5x4: + // The data has been exported from the gallery Desert, area index 25, ID 166, created by Aloe_vera + { + // Size: + 7, 5, 6, // SizeX = 7, SizeY = 5, SizeZ = 6 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 4, 5, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171: 0\n" /* carpet */ + "g:171:14\n" /* carpet */ + "h: 24: 2\n" /* sandstone */ + "i: 64:12\n" /* wooddoorblock */ + "j: 50: 3\n" /* torch */ + "k:128: 4\n" /* sandstonestairs */ + "l:128: 6\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 5\n" /* sandstonestairs */ + "o:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "..abc.." + /* 1 */ ".ddddd." + /* 2 */ ".ddddd." + /* 3 */ ".ddddd." + /* 4 */ ".ddddd." + /* 5 */ "......." + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ddedd." + /* 2 */ ".dfgfd." + /* 3 */ ".dfgfd." + /* 4 */ ".ddddd." + /* 5 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".hhihh." + /* 2 */ ".h...h." + /* 3 */ ".h...h." + /* 4 */ ".hh.hh." + /* 5 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ddddd." + /* 2 */ ".dj.jd." + /* 3 */ ".d...d." + /* 4 */ ".ddddd." + /* 5 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "kllllln" + /* 1 */ "kdddddn" + /* 2 */ "kdddddn" + /* 3 */ "kdddddn" + /* 4 */ "kdddddn" + /* 5 */ "oooooon", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House5x4 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House5x5: + // The data has been exported from the gallery Desert, area index 26, ID 167, created by Aloe_vera + { + // Size: + 7, 5, 7, // SizeX = 7, SizeY = 5, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 4, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171: 0\n" /* carpet */ + "g:171:15\n" /* carpet */ + "h:171:14\n" /* carpet */ + "i: 24: 2\n" /* sandstone */ + "j: 64:12\n" /* wooddoorblock */ + "k: 50: 3\n" /* torch */ + "l:128: 4\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 6\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "..abc.." + /* 1 */ ".ddddd." + /* 2 */ ".ddddd." + /* 3 */ ".ddddd." + /* 4 */ ".ddddd." + /* 5 */ ".ddddd." + /* 6 */ "......." + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ddedd." + /* 2 */ ".dfffd." + /* 3 */ ".dghgd." + /* 4 */ ".dfffd." + /* 5 */ ".ddddd." + /* 6 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".iijii." + /* 2 */ ".i...i." + /* 3 */ "......." + /* 4 */ ".i...i." + /* 5 */ ".ii.ii." + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ddddd." + /* 2 */ ".dk.kd." + /* 3 */ ".d...d." + /* 4 */ ".d...d." + /* 5 */ ".ddddd." + /* 6 */ "......." + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "lnnnnno" + /* 1 */ "ldddddo" + /* 2 */ "ldddddo" + /* 3 */ "ldddddo" + /* 4 */ "ldddddo" + /* 5 */ "ldddddo" + /* 6 */ "ppppppo", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House5x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House7x5: + // The data has been exported from the gallery Desert, area index 27, ID 168, created by Aloe_vera + { + // Size: + 9, 5, 7, // SizeX = 9, SizeY = 5, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 8, 4, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171:14\n" /* carpet */ + "g:171: 0\n" /* carpet */ + "h:171:15\n" /* carpet */ + "i: 24: 2\n" /* sandstone */ + "j: 64:12\n" /* wooddoorblock */ + "k: 50: 3\n" /* torch */ + "l:128: 4\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 6\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "..abc...." + /* 1 */ ".ddddddd." + /* 2 */ ".ddddddd." + /* 3 */ ".ddddddd." + /* 4 */ ".ddddddd." + /* 5 */ ".ddddddd." + /* 6 */ "........." + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".ddedddd." + /* 2 */ ".dfffffd." + /* 3 */ ".dghhhgd." + /* 4 */ ".dfffffd." + /* 5 */ ".ddddddd." + /* 6 */ "........." + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".iiji.ii." + /* 2 */ ".i.....i." + /* 3 */ "........." + /* 4 */ ".i.....i." + /* 5 */ ".iii.iii." + /* 6 */ "........." + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".ddddddd." + /* 2 */ ".dk.k..d." + /* 3 */ ".d.....d." + /* 4 */ ".d.....d." + /* 5 */ ".ddddddd." + /* 6 */ "........." + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "lnnnnnnnn" + /* 1 */ "ldddddddo" + /* 2 */ "ldddddddo" + /* 3 */ "ldddddddo" + /* 4 */ "ldddddddo" + /* 5 */ "ldddddddo" + /* 6 */ "ppppppppo", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House7x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House8x5: + // The data has been exported from the gallery Desert, area index 28, ID 169, created by Aloe_vera + { + // Size: + 10, 5, 7, // SizeX = 10, SizeY = 5, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 9, 4, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171: 0\n" /* carpet */ + "g:171:14\n" /* carpet */ + "h:171:15\n" /* carpet */ + "i: 24: 2\n" /* sandstone */ + "j: 64:12\n" /* wooddoorblock */ + "k: 50: 3\n" /* torch */ + "l:128: 4\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n:128: 6\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "..abc....." + /* 1 */ ".dddddddd." + /* 2 */ ".dddddddd." + /* 3 */ ".dddddddd." + /* 4 */ ".dddddddd." + /* 5 */ ".dddddddd." + /* 6 */ ".........." + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".ddeddddd." + /* 2 */ ".dfghhgfd." + /* 3 */ ".dfhffhfd." + /* 4 */ ".dfghhgfd." + /* 5 */ ".dddddddd." + /* 6 */ ".........." + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".iijii.ii." + /* 2 */ ".i......i." + /* 3 */ ".........." + /* 4 */ ".i......i." + /* 5 */ ".ii.ii.ii." + /* 6 */ ".........." + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".dddddddd." + /* 2 */ ".dk.k...d." + /* 3 */ ".d......d." + /* 4 */ ".d......d." + /* 5 */ ".dddddddd." + /* 6 */ ".........." + + // Level 4 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "lnnnnnnnnn" + /* 1 */ "lddddddddo" + /* 2 */ "lddddddddo" + /* 3 */ "lddddddddo" + /* 4 */ "lddddddddo" + /* 5 */ "lddddddddo" + /* 6 */ "pppppppppo", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House8x5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House8x7: + // The data has been exported from the gallery Desert, area index 29, ID 170, created by Aloe_vera + { + // Size: + 10, 5, 9, // SizeX = 10, SizeY = 5, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 9, 4, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171: 0\n" /* carpet */ + "g:171:14\n" /* carpet */ + "h:171:15\n" /* carpet */ + "i: 24: 2\n" /* sandstone */ + "j: 64:12\n" /* wooddoorblock */ + "k: 50: 3\n" /* torch */ + "l: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 50: 2\n" /* torch */ + "o:128: 4\n" /* sandstonestairs */ + "p:128: 6\n" /* sandstonestairs */ + "q:128: 5\n" /* sandstonestairs */ + "r:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "..abc....." + /* 1 */ ".dddddddd." + /* 2 */ ".dddddddd." + /* 3 */ ".dddddddd." + /* 4 */ ".dddddddd." + /* 5 */ ".dddddddd." + /* 6 */ ".dddddddd." + /* 7 */ ".dddddddd." + /* 8 */ ".........." + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".ddeddddd." + /* 2 */ ".dfghhgfd." + /* 3 */ ".dfhffhfd." + /* 4 */ ".dfhgghfd." + /* 5 */ ".dfhffhfd." + /* 6 */ ".dfghhgfd." + /* 7 */ ".dddddddd." + /* 8 */ ".........." + + // Level 2 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".iijii.ii." + /* 2 */ ".i......i." + /* 3 */ ".i......i." + /* 4 */ ".........." + /* 5 */ ".i......i." + /* 6 */ ".i......i." + /* 7 */ ".ii.ii.ii." + /* 8 */ ".........." + + // Level 3 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ ".........." + /* 1 */ ".dddddddd." + /* 2 */ ".d..k...d." + /* 3 */ ".d......d." + /* 4 */ ".dl....nd." + /* 5 */ ".d......d." + /* 6 */ ".d......d." + /* 7 */ ".dddddddd." + /* 8 */ ".........." + + // Level 4 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "oppppppppp" + /* 1 */ "oddddddddq" + /* 2 */ "oddddddddq" + /* 3 */ "oddddddddq" + /* 4 */ "oddddddddq" + /* 5 */ "oddddddddq" + /* 6 */ "oddddddddq" + /* 7 */ "oddddddddq" + /* 8 */ "rrrrrrrrrq", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House8x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House9x7: + // The data has been exported from the gallery Desert, area index 30, ID 171, created by Aloe_vera + { + // Size: + 11, 5, 9, // SizeX = 11, SizeY = 5, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 4, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:171: 0\n" /* carpet */ + "g:171:15\n" /* carpet */ + "h:171:14\n" /* carpet */ + "i: 24: 2\n" /* sandstone */ + "j: 64:12\n" /* wooddoorblock */ + "k: 50: 3\n" /* torch */ + "l: 50: 1\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n: 50: 2\n" /* torch */ + "o: 50: 4\n" /* torch */ + "p:128: 4\n" /* sandstonestairs */ + "q:128: 6\n" /* sandstonestairs */ + "r:128: 5\n" /* sandstonestairs */ + "s:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..abc......" + /* 1 */ ".ddddddddd." + /* 2 */ ".ddddddddd." + /* 3 */ ".ddddddddd." + /* 4 */ ".ddddddddd." + /* 5 */ ".ddddddddd." + /* 6 */ ".ddddddddd." + /* 7 */ ".ddddddddd." + /* 8 */ "..........." + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ddedddddd." + /* 2 */ ".dffgggffd." + /* 3 */ ".dfghhhgfd." + /* 4 */ ".dfghfhgfd." + /* 5 */ ".dfghhhgfd." + /* 6 */ ".dffgggffd." + /* 7 */ ".ddddddddd." + /* 8 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".iijii.iii." + /* 2 */ ".i.......i." + /* 3 */ ".i.......i." + /* 4 */ "..........." + /* 5 */ ".i.......i." + /* 6 */ ".i.......i." + /* 7 */ ".ii.iii.ii." + /* 8 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ddddddddd." + /* 2 */ ".d..k....d." + /* 3 */ ".d.......d." + /* 4 */ ".dl.....nd." + /* 5 */ ".d.......d." + /* 6 */ ".d...o...d." + /* 7 */ ".ddddddddd." + /* 8 */ "..........." + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "pqqqqqqqqqq" + /* 1 */ "pdddddddddr" + /* 2 */ "pdddddddddr" + /* 3 */ "pdddddddddr" + /* 4 */ "pdddddddddr" + /* 5 */ "pdddddddddr" + /* 6 */ "pdddddddddr" + /* 7 */ "pdddddddddr" + /* 8 */ "ssssssssssr", + + // Connectors: + "-1: 3, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House9x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseL13x12: + // The data has been exported from the gallery Desert, area index 53, ID 345, created by jakibaki + { + // Size: + 15, 5, 14, // SizeX = 15, SizeY = 5, SizeZ = 14 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 4, 13, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 43: 1\n" /* doubleslab */ + "f: 64: 7\n" /* wooddoorblock */ + "g:171: 0\n" /* carpet */ + "h:171:15\n" /* carpet */ + "i:171:14\n" /* carpet */ + "j: 58: 0\n" /* workbench */ + "k: 24: 2\n" /* sandstone */ + "l: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */ + "n: 50: 3\n" /* torch */ + "o: 50: 1\n" /* torch */ + "p: 50: 2\n" /* torch */ + "q: 50: 4\n" /* torch */ + "r:128: 6\n" /* sandstonestairs */ + "s:128: 5\n" /* sandstonestairs */ + "t:128: 4\n" /* sandstonestairs */ + "u:128: 7\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "...abc........." + /* 1 */ ".ddddddddddddd." + /* 2 */ ".ddddddddddddd." + /* 3 */ ".ddddddddddddd." + /* 4 */ ".ddddddddddddd." + /* 5 */ ".ddddddddddded." + /* 6 */ ".ddddddddddddd." + /* 7 */ ".ddddddddddddd." + /* 8 */ ".......deddddd." + /* 9 */ "mmmmmm.ddddddd." + /* 10 */ "mmmmmm.ddddddd." + /* 11 */ "mmmmmm.ddddddd." + /* 12 */ "mmmmmm.ddddddd." + /* 13 */ "..............." + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".dddfddddddddd." + /* 2 */ ".dgghhhhhhhhgd." + /* 3 */ ".dghiiiiiiiihd." + /* 4 */ ".dghiggggggihd." + /* 5 */ ".dghiiiiiigihd." + /* 6 */ ".dgghhhhhigihd." + /* 7 */ ".dddddddhigihd." + /* 8 */ ".......dhigihd." + /* 9 */ "mmmmmm.dhiiihd." + /* 10 */ "mmmmmm.dghhhgd." + /* 11 */ "mmmmmm.dggggjd." + /* 12 */ "mmmmmm.ddddddd." + /* 13 */ "..............." + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".kkklkkkk.kkkk." + /* 2 */ ".k...........k." + /* 3 */ ".k...........k." + /* 4 */ "..............." + /* 5 */ ".k...........k." + /* 6 */ ".k...........k." + /* 7 */ ".kkk.kkk.....k." + /* 8 */ ".......k.....k." + /* 9 */ "mmmmmm.k......." + /* 10 */ "mmmmmm.......k." + /* 11 */ "mmmmmm.k.....k." + /* 12 */ "mmmmmm.kkk.kkk." + /* 13 */ "..............." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".ddddddddddddd." + /* 2 */ ".d......n....d." + /* 3 */ ".d...........d." + /* 4 */ ".do..........d." + /* 5 */ ".d...........d." + /* 6 */ ".d..........pd." + /* 7 */ ".ddddddd.....d." + /* 8 */ ".......d.....d." + /* 9 */ "mmmmmm.d.....d." + /* 10 */ "mmmmmm.d.....d." + /* 11 */ "mmmmmm.d..q..d." + /* 12 */ "mmmmmm.ddddddd." + /* 13 */ "..............." + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "rrrrrrrrrrrrrrs" + /* 1 */ "tddddddddddddds" + /* 2 */ "tddddddddddddds" + /* 3 */ "tddddddddddddds" + /* 4 */ "tddddddddddddds" + /* 5 */ "tddddddddddddds" + /* 6 */ "tddddddddddddds" + /* 7 */ "tddddddddddddds" + /* 8 */ "tuuuuutddddddds" + /* 9 */ "mmmmmmtddddddds" + /* 10 */ "mmmmmmtddddddds" + /* 11 */ "mmmmmmtddddddds" + /* 12 */ "mmmmmmtddddddds" + /* 13 */ "......tuuuuuuuu", + + // Connectors: + "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseL13x12 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // MarketStall: + // The data has been exported from the gallery Desert, area index 34, ID 175, created by Aloe_vera + { + // Size: + 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 12: 0\n" /* sand */ + "b: 85: 0\n" /* fence */ + "c:171:14\n" /* carpet */ + "d:171:15\n" /* carpet */ + "e:171: 0\n" /* carpet */ + "f: 35:14\n" /* wool */ + "g: 35: 0\n" /* wool */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "b.....b" + /* 1 */ "cddeddc" + /* 2 */ "cdeeedc" + /* 3 */ "cdeeedc" + /* 4 */ "cddeddc" + /* 5 */ "b.....b" + /* 6 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "b.....b" + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "b.....b" + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "b.....b" + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "b.....b" + /* 6 */ "fgfgfgf" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "fgfgfgf" + /* 1 */ "......." + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "fgfgfgf" + /* 6 */ "......." + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "fgfgfgf" + /* 2 */ "fgfgfgf" + /* 3 */ "fgfgfgf" + /* 4 */ "fgfgfgf" + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "-1: 2, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 5, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // MarketStall + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Marketplace: + // The data has been exported from the gallery Desert, area index 38, ID 261, created by Aloe_vera + { + // Size: + 14, 4, 16, // SizeX = 14, SizeY = 4, SizeZ = 16 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 13, 3, 15, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 24: 0\n" /* sandstone */ + "b: 12: 0\n" /* sand */ + "c: 24: 2\n" /* sandstone */ + "d: 12: 2\n" /* sand */ + "e: 85: 0\n" /* fence */ + "f: 5: 0\n" /* wood */ + "g:128: 2\n" /* sandstonestairs */ + "h:128: 0\n" /* sandstonestairs */ + "i: 8: 0\n" /* water */ + "j:128: 1\n" /* sandstonestairs */ + "k:128: 3\n" /* sandstonestairs */ + "l: 35: 0\n" /* wool */ + "m: 19: 0\n" /* sponge */ + "n: 35:14\n" /* wool */, + + // Block data: + // Level 0 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "aaaabbbaaabbbb" + /* 1 */ "aaaabbaabbabbb" + /* 2 */ "aababbabcabbbb" + /* 3 */ "aaaaabaaaaabbb" + /* 4 */ "bbbbbbbbbbbbbb" + /* 5 */ "bbbbbbbbbbaabb" + /* 6 */ "bbbbccccbbabab" + /* 7 */ "ccbbccccbbaaab" + /* 8 */ "ccbbccccbbabbb" + /* 9 */ "dcbbccccbbabaa" + /* 10 */ "ccbbbbbbbbaaba" + /* 11 */ "ccbbbbbbbbabaa" + /* 12 */ "bbbbbbbbbbabaa" + /* 13 */ "bbbaababbbaaba" + /* 14 */ "bbbcaaaabbabbb" + /* 15 */ "bbbcccabbbabbb" + + // Level 1 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "e...e.e...e..." + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ "fffff.fffff..." + /* 4 */ ".............." + /* 5 */ "..........f..e" + /* 6 */ "....gggg..f..." + /* 7 */ ".f..hiij..f..." + /* 8 */ ".f..hiij..f..." + /* 9 */ ".f..kkkk..f..e" + /* 10 */ ".f............" + /* 11 */ ".f........f..e" + /* 12 */ "...fffff..f..." + /* 13 */ "..........f..." + /* 14 */ "..........f..." + /* 15 */ "...e...e..f..e" + + // Level 2 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "lnlnl.lnlnl..." + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ "e...e.e...e..." + /* 4 */ ".............." + /* 5 */ "..........e..l" + /* 6 */ ".............n" + /* 7 */ ".e...........l" + /* 8 */ ".............n" + /* 9 */ "..........e..l" + /* 10 */ ".............." + /* 11 */ ".e........e..l" + /* 12 */ "...e...e.....n" + /* 13 */ ".............l" + /* 14 */ ".............n" + /* 15 */ "...lnlnl..e..l" + + // Level 3 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ "lnlnl.lnlnl..." + /* 2 */ "lnlnl.lnlnl..." + /* 3 */ "lnlnl.lnlnl..." + /* 4 */ ".............." + /* 5 */ "..........lll." + /* 6 */ "..........nnn." + /* 7 */ "ll........lll." + /* 8 */ "nn........nnn." + /* 9 */ "ll........lll." + /* 10 */ "nn............" + /* 11 */ "ll........lll." + /* 12 */ "...lnlnl..nnn." + /* 13 */ "...lnlnl..lll." + /* 14 */ "...lnlnl..nnn." + /* 15 */ "..........lll.", + + // Connectors: + "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Marketplace +}; // g_SandFlatRoofVillagePrefabs + + + + + + +const cPrefab::sDef g_SandFlatRoofVillageStartingPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Well: + // The data has been exported from the gallery Desert, area index 44, ID 275, created by Aloe_vera + { + // Size: + 5, 16, 5, // SizeX = 5, SizeY = 16, SizeZ = 5 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 15, 4, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 24: 0\n" /* sandstone */ + "c: 8: 0\n" /* water */ + "d:128: 2\n" /* sandstonestairs */ + "e:128: 0\n" /* sandstonestairs */ + "f:128: 1\n" /* sandstonestairs */ + "g:128: 3\n" /* sandstonestairs */ + "h:128: 6\n" /* sandstonestairs */ + "i:128: 4\n" /* sandstonestairs */ + "j:128: 5\n" /* sandstonestairs */ + "k:128: 7\n" /* sandstonestairs */ + "l: 44: 1\n" /* step */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "abbba" + /* 2 */ "abbba" + /* 3 */ "abbba" + /* 4 */ "aaaaa" + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 4 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 5 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 6 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 7 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcccb" + /* 2 */ "bcccb" + /* 3 */ "bcccb" + /* 4 */ "bbbbb" + + // Level 8 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcbcb" + /* 2 */ "bbcbb" + /* 3 */ "bcbcb" + /* 4 */ "bbbbb" + + // Level 9 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcbcb" + /* 2 */ "bbbbb" + /* 3 */ "bcbcb" + /* 4 */ "bbbbb" + + // Level 10 + /* z\x* 01234 */ + /* 0 */ "bbbbb" + /* 1 */ "bcbcb" + /* 2 */ "bbbbb" + /* 3 */ "bcbcb" + /* 4 */ "bbbbb" + + // Level 11 + /* z\x* 01234 */ + /* 0 */ "ddddd" + /* 1 */ "ecccf" + /* 2 */ "ecbcf" + /* 3 */ "ecccf" + /* 4 */ "ggggf" + + // Level 12 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "..b.." + /* 3 */ "....." + /* 4 */ "....." + + // Level 13 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ "....." + /* 2 */ "..b.." + /* 3 */ "....." + /* 4 */ "....." + + // Level 14 + /* z\x* 01234 */ + /* 0 */ "....." + /* 1 */ ".hhh." + /* 2 */ ".ibj." + /* 3 */ ".kkj." + /* 4 */ "....." + + // Level 15 + /* z\x* 01234 */ + /* 0 */ "lllll" + /* 1 */ "lllll" + /* 2 */ "lllll" + /* 3 */ "lllll" + /* 4 */ "lllll", + + // Connectors: + "2: 4, 11, 2: 5\n" /* Type 2, direction X+ */ + "2: 2, 11, 4: 3\n" /* Type 2, direction Z+ */ + "2: 0, 11, 2: 4\n" /* Type 2, direction X- */ + "2: 2, 11, 0: 2\n" /* Type 2, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Well +}; + + + + + +// The prefab counts: + +const size_t g_SandFlatRoofVillagePrefabsCount = ARRAYCOUNT(g_SandFlatRoofVillagePrefabs); + +const size_t g_SandFlatRoofVillageStartingPrefabsCount = ARRAYCOUNT(g_SandFlatRoofVillageStartingPrefabs); + diff --git a/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h new file mode 100644 index 000000000..ea06de5b5 --- /dev/null +++ b/src/Generating/Prefabs/SandFlatRoofVillagePrefabs.h @@ -0,0 +1,15 @@ + +// SandFlatRoofVillagePrefabs.h + +// Declares the prefabs in the group SandFlatRoofVillage + +#include "../Prefab.h" + + + + + +extern const cPrefab::sDef g_SandFlatRoofVillagePrefabs[]; +extern const cPrefab::sDef g_SandFlatRoofVillageStartingPrefabs[]; +extern const size_t g_SandFlatRoofVillagePrefabsCount; +extern const size_t g_SandFlatRoofVillageStartingPrefabsCount; diff --git a/src/Generating/Prefabs/SandVillagePrefabs.cpp b/src/Generating/Prefabs/SandVillagePrefabs.cpp new file mode 100644 index 000000000..a062f8cd4 --- /dev/null +++ b/src/Generating/Prefabs/SandVillagePrefabs.cpp @@ -0,0 +1,2133 @@ + +// SandVillagePrefabs.cpp + +// Defines the prefabs in the group SandVillage + +// NOTE: This file has been generated automatically by GalExport! +// Any manual changes will be overwritten by the next automatic export! + +#include "Globals.h" +#include "SandVillagePrefabs.h" + + + + + +const cPrefab::sDef g_SandVillagePrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // DoubleField: + // The data has been exported from the gallery Desert, area index 5, ID 75, created by tonibm1999 + { + // Size: + 13, 2, 9, // SizeX = 13, SizeY = 2, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 1, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 24: 0\n" /* sandstone */ + "b: 60: 7\n" /* tilleddirt */ + "c: 8: 0\n" /* water */ + "d: 50: 5\n" /* torch */ + "e: 59: 7\n" /* crops */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "abbcbbabbcbba" + /* 2 */ "abbcbbabbcbba" + /* 3 */ "abbcbbabbcbba" + /* 4 */ "abbcbbabbcbba" + /* 5 */ "abbcbbabbcbba" + /* 6 */ "abbcbbabbcbba" + /* 7 */ "abbcbbabbcbba" + /* 8 */ "aaaaaaaaaaaaa" + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "d.....d.....d" + /* 1 */ ".......ee.ee." + /* 2 */ ".......ee.ee." + /* 3 */ ".......ee.ee." + /* 4 */ ".......ee.ee." + /* 5 */ ".......ee.ee." + /* 6 */ ".......ee.ee." + /* 7 */ ".......ee.ee." + /* 8 */ "d.....d.....d", + + // Connectors: + "-1: 6, 0, 8: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // DoubleField + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House11x7: + // The data has been exported from the gallery Desert, area index 6, ID 81, created by Aloe_vera + { + // Size: + 11, 6, 7, // SizeX = 11, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */ + "n: 50: 1\n" /* torch */ + "o: 50: 2\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....abc...." + /* 1 */ ".ddddddddd." + /* 2 */ ".ddddddddd." + /* 3 */ ".ddddddddd." + /* 4 */ ".ddddddddd." + /* 5 */ ".ddddddddd." + /* 6 */ "..........." + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ddddedddd." + /* 2 */ ".d.......d." + /* 3 */ ".d.......d." + /* 4 */ ".d.......d." + /* 5 */ ".ddddddddd." + /* 6 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".dffdgdffd." + /* 2 */ ".f.......f." + /* 3 */ ".f.......f." + /* 4 */ ".f.......f." + /* 5 */ ".dffdfdffd." + /* 6 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "bbbbbbbbbbb" + /* 1 */ "hdddddddddh" + /* 2 */ ".d..i.i..d." + /* 3 */ ".d.......d." + /* 4 */ ".d..j.j..d." + /* 5 */ "kdddddddddk" + /* 6 */ "lllllllllll" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "bbbbbbbbbbb" + /* 2 */ "hdddddddddh" + /* 3 */ ".dn.....od." + /* 4 */ "kdddddddddk" + /* 5 */ "lllllllllll" + /* 6 */ "..........." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "bbbbbbbbbbb" + /* 3 */ "ddddddddddd" + /* 4 */ "lllllllllll" + /* 5 */ "..........." + /* 6 */ "...........", + + // Connectors: + "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House11x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House11x9: + // The data has been exported from the gallery Desert, area index 11, ID 115, created by xoft + { + // Size: + 11, 7, 9, // SizeX = 11, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 10, 6, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "....abc...." + /* 1 */ ".ddddddddd." + /* 2 */ ".ddddddddd." + /* 3 */ ".ddddddddd." + /* 4 */ ".ddddddddd." + /* 5 */ ".ddddddddd." + /* 6 */ ".ddddddddd." + /* 7 */ ".ddddddddd." + /* 8 */ "..........." + + // Level 1 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".ddddedddd." + /* 2 */ ".d.......d." + /* 3 */ ".d.......d." + /* 4 */ ".d.......d." + /* 5 */ ".d.......d." + /* 6 */ ".d.......d." + /* 7 */ ".ddddddddd." + /* 8 */ "..........." + + // Level 2 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ ".dffdgdffd." + /* 2 */ ".f.......f." + /* 3 */ ".f.......f." + /* 4 */ ".d.......d." + /* 5 */ ".f.......f." + /* 6 */ ".f.......f." + /* 7 */ ".dfffdfffd." + /* 8 */ "..........." + + // Level 3 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "bbbbbbbbbbb" + /* 1 */ "hdddddddddh" + /* 2 */ ".d..i.i..d." + /* 3 */ ".d.......d." + /* 4 */ ".d.......d." + /* 5 */ ".d.......d." + /* 6 */ ".d...j...d." + /* 7 */ "kdddddddddk" + /* 8 */ "lllllllllll" + + // Level 4 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "bbbbbbbbbbb" + /* 2 */ "hdddddddddh" + /* 3 */ ".d.......d." + /* 4 */ ".d.......d." + /* 5 */ ".d.......d." + /* 6 */ "kdddddddddk" + /* 7 */ "lllllllllll" + /* 8 */ "..........." + + // Level 5 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "bbbbbbbbbbb" + /* 3 */ "hdddddddddh" + /* 4 */ ".d.......d." + /* 5 */ "kdddddddddk" + /* 6 */ "lllllllllll" + /* 7 */ "..........." + /* 8 */ "..........." + + // Level 6 + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "..........." + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "bbbbbbbbbbb" + /* 4 */ "ddddddddddd" + /* 5 */ "lllllllllll" + /* 6 */ "..........." + /* 7 */ "..........." + /* 8 */ "...........", + + // Connectors: + "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House11x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House13x7: + // The data has been exported from the gallery Desert, area index 15, ID 125, created by Aloe_vera + { + // Size: + 13, 6, 7, // SizeX = 13, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ ".....abc....." + /* 1 */ ".ddddddddddd." + /* 2 */ ".ddddddddddd." + /* 3 */ ".ddddddddddd." + /* 4 */ ".ddddddddddd." + /* 5 */ ".ddddddddddd." + /* 6 */ "............." + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".dddddeddddd." + /* 2 */ ".d.........d." + /* 3 */ ".d.........d." + /* 4 */ ".d.........d." + /* 5 */ ".ddddddddddd." + /* 6 */ "............." + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".dfffdgdfffd." + /* 2 */ ".f.........f." + /* 3 */ ".f.........f." + /* 4 */ ".f.........f." + /* 5 */ ".dffdfffdffd." + /* 6 */ "............." + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "bbbbbbbbbbbbb" + /* 1 */ "hdddddddddddh" + /* 2 */ ".d...i.i...d." + /* 3 */ ".d.........d." + /* 4 */ ".d..j...j..d." + /* 5 */ "kdddddddddddk" + /* 6 */ "lllllllllllll" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "bbbbbbbbbbbbb" + /* 2 */ "hdddddddddddh" + /* 3 */ ".d.........d." + /* 4 */ "kdddddddddddk" + /* 5 */ "lllllllllllll" + /* 6 */ "............." + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "bbbbbbbbbbbbb" + /* 3 */ "ddddddddddddd" + /* 4 */ "lllllllllllll" + /* 5 */ "............." + /* 6 */ ".............", + + // Connectors: + "-1: 6, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House13x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House13x9: + // The data has been exported from the gallery Desert, area index 12, ID 116, created by xoft + { + // Size: + 13, 7, 9, // SizeX = 13, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 12, 6, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ ".....abc....." + /* 1 */ ".ddddddddddd." + /* 2 */ ".ddddddddddd." + /* 3 */ ".ddddddddddd." + /* 4 */ ".ddddddddddd." + /* 5 */ ".ddddddddddd." + /* 6 */ ".ddddddddddd." + /* 7 */ ".ddddddddddd." + /* 8 */ "............." + + // Level 1 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".dddddeddddd." + /* 2 */ ".d.........d." + /* 3 */ ".d.........d." + /* 4 */ ".d.........d." + /* 5 */ ".d.........d." + /* 6 */ ".d.........d." + /* 7 */ ".ddddddddddd." + /* 8 */ "............." + + // Level 2 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ ".dfffdgdfffd." + /* 2 */ ".f.........f." + /* 3 */ ".f.........f." + /* 4 */ ".d.........d." + /* 5 */ ".f.........f." + /* 6 */ ".f.........f." + /* 7 */ ".dffdffdfffd." + /* 8 */ "............." + + // Level 3 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "bbbbbbbbbbbbb" + /* 1 */ "hdddddddddddh" + /* 2 */ ".d...i.i...d." + /* 3 */ ".d.........d." + /* 4 */ ".d.........d." + /* 5 */ ".d.........d." + /* 6 */ ".d..j..j...d." + /* 7 */ "kdddddddddddk" + /* 8 */ "lllllllllllll" + + // Level 4 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "bbbbbbbbbbbbb" + /* 2 */ "hdddddddddddh" + /* 3 */ ".d.........d." + /* 4 */ ".d.........d." + /* 5 */ ".d.........d." + /* 6 */ "kdddddddddddk" + /* 7 */ "lllllllllllll" + /* 8 */ "............." + + // Level 5 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "bbbbbbbbbbbbb" + /* 3 */ "hdddddddddddh" + /* 4 */ ".d.........d." + /* 5 */ "kdddddddddddk" + /* 6 */ "lllllllllllll" + /* 7 */ "............." + /* 8 */ "............." + + // Level 6 + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "............." + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "bbbbbbbbbbbbb" + /* 4 */ "ddddddddddddd" + /* 5 */ "lllllllllllll" + /* 6 */ "............." + /* 7 */ "............." + /* 8 */ ".............", + + // Connectors: + "-1: 6, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House13x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House15x9: + // The data has been exported from the gallery Desert, area index 13, ID 118, created by xoft + { + // Size: + 15, 7, 9, // SizeX = 15, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 14, 6, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ ".....abc......." + /* 1 */ ".ddddddddddddd." + /* 2 */ ".ddddddddddddd." + /* 3 */ ".ddddddddddddd." + /* 4 */ ".ddddddddddddd." + /* 5 */ ".ddddddddddddd." + /* 6 */ ".ddddddddddddd." + /* 7 */ ".ddddddddddddd." + /* 8 */ "..............." + + // Level 1 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".dddddeddddddd." + /* 2 */ ".d...........d." + /* 3 */ ".d...........d." + /* 4 */ ".d...........d." + /* 5 */ ".d...........d." + /* 6 */ ".d...........d." + /* 7 */ ".ddddddddddddd." + /* 8 */ "..............." + + // Level 2 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ ".dfffdgdffdffd." + /* 2 */ ".f...........f." + /* 3 */ ".f...........f." + /* 4 */ ".d...........d." + /* 5 */ ".f...........f." + /* 6 */ ".f...........f." + /* 7 */ ".dffdffdffdffd." + /* 8 */ "..............." + + // Level 3 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "bbbbbbbbbbbbbbb" + /* 1 */ "hdddddddddddddh" + /* 2 */ ".d...i.i..i..d." + /* 3 */ ".d...........d." + /* 4 */ ".d...........d." + /* 5 */ ".d...........d." + /* 6 */ ".d..j..j..j..d." + /* 7 */ "kdddddddddddddk" + /* 8 */ "lllllllllllllll" + + // Level 4 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "bbbbbbbbbbbbbbb" + /* 2 */ "hdddddddddddddh" + /* 3 */ ".d...........d." + /* 4 */ ".d...........d." + /* 5 */ ".d...........d." + /* 6 */ "kdddddddddddddk" + /* 7 */ "lllllllllllllll" + /* 8 */ "..............." + + // Level 5 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "bbbbbbbbbbbbbbb" + /* 3 */ "hdddddddddddddh" + /* 4 */ ".d...........d." + /* 5 */ "kdddddddddddddk" + /* 6 */ "lllllllllllllll" + /* 7 */ "..............." + /* 8 */ "..............." + + // Level 6 + /* z\x* 11111 */ + /* * 012345678901234 */ + /* 0 */ "..............." + /* 1 */ "..............." + /* 2 */ "..............." + /* 3 */ "bbbbbbbbbbbbbbb" + /* 4 */ "ddddddddddddddd" + /* 5 */ "lllllllllllllll" + /* 6 */ "..............." + /* 7 */ "..............." + /* 8 */ "...............", + + // Connectors: + "-1: 6, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House15x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House16x9: + // The data has been exported from the gallery Desert, area index 16, ID 126, created by Aloe_vera + { + // Size: + 16, 7, 9, // SizeX = 16, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 15, 6, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "........abc....." + /* 1 */ ".dddddddddddddd." + /* 2 */ ".dddddddddddddd." + /* 3 */ ".dddddddddddddd." + /* 4 */ ".dddddddddddddd." + /* 5 */ ".dddddddddddddd." + /* 6 */ ".dddddddddddddd." + /* 7 */ ".dddddddddddddd." + /* 8 */ "................" + + // Level 1 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".ddddddddeddddd." + /* 2 */ ".d............d." + /* 3 */ ".d............d." + /* 4 */ ".d............d." + /* 5 */ ".d............d." + /* 6 */ ".d............d." + /* 7 */ ".dddddddddddddd." + /* 8 */ "................" + + // Level 2 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ ".dffdfffdgdfffd." + /* 2 */ ".f............f." + /* 3 */ ".f............f." + /* 4 */ ".d............d." + /* 5 */ ".f............f." + /* 6 */ ".f............f." + /* 7 */ ".dffdffdfffdffd." + /* 8 */ "................" + + // Level 3 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "bbbbbbbbbbbbbbbb" + /* 1 */ "hddddddddddddddh" + /* 2 */ ".d..i...i.i...d." + /* 3 */ ".d............d." + /* 4 */ ".d............d." + /* 5 */ ".d............d." + /* 6 */ ".d..j..j...j..d." + /* 7 */ "kddddddddddddddk" + /* 8 */ "llllllllllllllll" + + // Level 4 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "bbbbbbbbbbbbbbbb" + /* 2 */ "hddddddddddddddh" + /* 3 */ ".d............d." + /* 4 */ ".d............d." + /* 5 */ ".d............d." + /* 6 */ "kddddddddddddddk" + /* 7 */ "llllllllllllllll" + /* 8 */ "................" + + // Level 5 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "bbbbbbbbbbbbbbbb" + /* 3 */ "hddddddddddddddh" + /* 4 */ ".d............d." + /* 5 */ "kddddddddddddddk" + /* 6 */ "llllllllllllllll" + /* 7 */ "................" + /* 8 */ "................" + + // Level 6 + /* z\x* 111111 */ + /* * 0123456789012345 */ + /* 0 */ "................" + /* 1 */ "................" + /* 2 */ "................" + /* 3 */ "bbbbbbbbbbbbbbbb" + /* 4 */ "dddddddddddddddd" + /* 5 */ "llllllllllllllll" + /* 6 */ "................" + /* 7 */ "................" + /* 8 */ "................", + + // Connectors: + "-1: 9, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House16x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House7x7: + // The data has been exported from the gallery Desert, area index 8, ID 112, created by Aloe_vera + { + // Size: + 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j:128: 6\n" /* sandstonestairs */ + "k:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "...abc." + /* 1 */ ".ddddd." + /* 2 */ ".ddddd." + /* 3 */ ".ddddd." + /* 4 */ ".ddddd." + /* 5 */ ".ddddd." + /* 6 */ "......." + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".ddded." + /* 2 */ ".d...d." + /* 3 */ ".d...d." + /* 4 */ ".d...d." + /* 5 */ ".ddddd." + /* 6 */ "......." + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".dfdgd." + /* 2 */ ".f...f." + /* 3 */ ".f...f." + /* 4 */ ".f...f." + /* 5 */ ".dfffd." + /* 6 */ "......." + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "bbbbbbb" + /* 1 */ "hdddddh" + /* 2 */ ".d.i.d." + /* 3 */ ".d...d." + /* 4 */ ".d...d." + /* 5 */ "jdddddj" + /* 6 */ "kkkkkkk" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "bbbbbbb" + /* 2 */ "hdddddh" + /* 3 */ ".d...d." + /* 4 */ "jdddddj" + /* 5 */ "kkkkkkk" + /* 6 */ "......." + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "bbbbbbb" + /* 3 */ "ddddddd" + /* 4 */ "kkkkkkk" + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House7x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House9x7: + // The data has been exported from the gallery Desert, area index 9, ID 113, created by xoft + { + // Size: + 9, 6, 7, // SizeX = 9, SizeY = 6, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 8, 5, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "...abc..." + /* 1 */ ".ddddddd." + /* 2 */ ".ddddddd." + /* 3 */ ".ddddddd." + /* 4 */ ".ddddddd." + /* 5 */ ".ddddddd." + /* 6 */ "........." + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".dddeddd." + /* 2 */ ".d.....d." + /* 3 */ ".d.....d." + /* 4 */ ".d.....d." + /* 5 */ ".ddddddd." + /* 6 */ "........." + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".dfdgdfd." + /* 2 */ ".f.....f." + /* 3 */ ".f.....f." + /* 4 */ ".f.....f." + /* 5 */ ".dffdffd." + /* 6 */ "........." + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "bbbbbbbbb" + /* 1 */ "hdddddddh" + /* 2 */ ".d.i.i.d." + /* 3 */ ".d.....d." + /* 4 */ ".d..j..d." + /* 5 */ "kdddddddk" + /* 6 */ "lllllllll" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "bbbbbbbbb" + /* 2 */ "hdddddddh" + /* 3 */ ".d.....d." + /* 4 */ "kdddddddk" + /* 5 */ "lllllllll" + /* 6 */ "........." + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "bbbbbbbbb" + /* 3 */ "ddddddddd" + /* 4 */ "lllllllll" + /* 5 */ "........." + /* 6 */ ".........", + + // Connectors: + "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House9x7 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // House9x9: + // The data has been exported from the gallery Desert, area index 10, ID 114, created by xoft + { + // Size: + 9, 7, 9, // SizeX = 9, SizeY = 7, SizeZ = 9 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 8, 6, 8, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e: 64: 7\n" /* wooddoorblock */ + "f:102: 0\n" /* glasspane */ + "g: 64:12\n" /* wooddoorblock */ + "h:128: 7\n" /* sandstonestairs */ + "i: 50: 3\n" /* torch */ + "j: 50: 4\n" /* torch */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "...abc..." + /* 1 */ ".ddddddd." + /* 2 */ ".ddddddd." + /* 3 */ ".ddddddd." + /* 4 */ ".ddddddd." + /* 5 */ ".ddddddd." + /* 6 */ ".ddddddd." + /* 7 */ ".ddddddd." + /* 8 */ "........." + + // Level 1 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".dddeddd." + /* 2 */ ".d.....d." + /* 3 */ ".d.....d." + /* 4 */ ".d.....d." + /* 5 */ ".d.....d." + /* 6 */ ".d.....d." + /* 7 */ ".ddddddd." + /* 8 */ "........." + + // Level 2 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ ".dfdgdfd." + /* 2 */ ".f.....f." + /* 3 */ ".f.....f." + /* 4 */ ".d.....d." + /* 5 */ ".f.....f." + /* 6 */ ".f.....f." + /* 7 */ ".dffdffd." + /* 8 */ "........." + + // Level 3 + /* z\x* 012345678 */ + /* 0 */ "bbbbbbbbb" + /* 1 */ "hdddddddh" + /* 2 */ ".d.i.i.d." + /* 3 */ ".d.....d." + /* 4 */ ".d.....d." + /* 5 */ ".d.....d." + /* 6 */ ".d..j..d." + /* 7 */ "kdddddddk" + /* 8 */ "lllllllll" + + // Level 4 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "bbbbbbbbb" + /* 2 */ "hdddddddh" + /* 3 */ ".d.....d." + /* 4 */ ".d.....d." + /* 5 */ ".d.....d." + /* 6 */ "kdddddddk" + /* 7 */ "lllllllll" + /* 8 */ "........." + + // Level 5 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "bbbbbbbbb" + /* 3 */ "hdddddddh" + /* 4 */ ".d.....d." + /* 5 */ "kdddddddk" + /* 6 */ "lllllllll" + /* 7 */ "........." + /* 8 */ "........." + + // Level 6 + /* z\x* 012345678 */ + /* 0 */ "........." + /* 1 */ "........." + /* 2 */ "........." + /* 3 */ "bbbbbbbbb" + /* 4 */ "ddddddddd" + /* 5 */ "lllllllll" + /* 6 */ "........." + /* 7 */ "........." + /* 8 */ ".........", + + // Connectors: + "-1: 4, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // House9x9 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseL14x12: + // The data has been exported from the gallery Desert, area index 14, ID 124, created by Aloe_vera + { + // Size: + 14, 7, 12, // SizeX = 14, SizeY = 7, SizeZ = 12 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 13, 6, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e:128: 3\n" /* sandstonestairs */ + "f: 64: 7\n" /* wooddoorblock */ + "g:102: 0\n" /* glasspane */ + "h: 64:12\n" /* wooddoorblock */ + "i:128: 7\n" /* sandstonestairs */ + "j: 50: 3\n" /* torch */ + "k: 50: 2\n" /* torch */ + "l: 50: 4\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n:128: 6\n" /* sandstonestairs */ + "o: 50: 1\n" /* torch */ + "p:128: 5\n" /* sandstonestairs */ + "q:128: 4\n" /* sandstonestairs */, + + // Block data: + // Level 0 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "....abc......." + /* 1 */ ".dddddddddddd." + /* 2 */ ".dddddddddddd." + /* 3 */ ".dddddddddddd." + /* 4 */ ".dddddddddddd." + /* 5 */ ".dddddddddddd." + /* 6 */ ".dddddddddddd." + /* 7 */ ".dddddddddddd." + /* 8 */ "....aeddddddd." + /* 9 */ "mmmmm.ddddddd." + /* 10 */ "mmmmm.ddddddd." + /* 11 */ "mmmmm........." + + // Level 1 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".ddddfddddddd." + /* 2 */ ".d..........d." + /* 3 */ ".d..........d." + /* 4 */ ".d..........d." + /* 5 */ ".d..........d." + /* 6 */ ".d..........d." + /* 7 */ ".ddddfd.....d." + /* 8 */ "......d.....d." + /* 9 */ "mmmmm.d.....d." + /* 10 */ "mmmmm.ddddddd." + /* 11 */ "mmmmm........." + + // Level 2 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".dggdhdggdggd." + /* 2 */ ".g..........g." + /* 3 */ ".g..........g." + /* 4 */ ".d..........d." + /* 5 */ ".g..........g." + /* 6 */ ".g..........g." + /* 7 */ ".dggdhd.....d." + /* 8 */ "......g.....g." + /* 9 */ "mmmmm.g.....g." + /* 10 */ "mmmmm.dggdggd." + /* 11 */ "mmmmm........." + + // Level 3 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "bbbbbbbbbbbbbb" + /* 1 */ "iddddddddddddc" + /* 2 */ ".d..j.j.....dc" + /* 3 */ ".d..........dc" + /* 4 */ ".d.........kdc" + /* 5 */ ".d..........dc" + /* 6 */ ".d..l.l.....dc" + /* 7 */ "nddddddo...kdc" + /* 8 */ "eeeeead.....dc" + /* 9 */ "mmmmmad.....dc" + /* 10 */ "mmmmmadddddddc" + /* 11 */ "mmmmmap.....qc" + + // Level 4 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ "bbbbbbbbbbbbc." + /* 2 */ "idddddddddddc." + /* 3 */ ".d.........dc." + /* 4 */ ".d.........dc." + /* 5 */ ".d.........dc." + /* 6 */ "nddddddd...dc." + /* 7 */ "eeeeeead...dc." + /* 8 */ "......ad...dc." + /* 9 */ "mmmmm.ad...dc." + /* 10 */ "mmmmm.adddddc." + /* 11 */ "mmmmm.ap...qc." + + // Level 5 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".............." + /* 2 */ "bbbbbbbbbbbb.." + /* 3 */ "iddddddddddc.." + /* 4 */ ".d........dc.." + /* 5 */ "ndddddddd.dc.." + /* 6 */ "eeeeeeeed.dc.." + /* 7 */ ".......ad.dc.." + /* 8 */ ".......ad.dc.." + /* 9 */ "mmmmm..ad.dc.." + /* 10 */ "mmmmm..adddc.." + /* 11 */ "mmmmm..ap.qc.." + + // Level 6 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".............." + /* 2 */ ".............." + /* 3 */ "bbbbbbbbbbb..." + /* 4 */ "ddddddddddc..." + /* 5 */ "eeeeeeeeadc..." + /* 6 */ "........adc..." + /* 7 */ "........adc..." + /* 8 */ "........adc..." + /* 9 */ "mmmmm...adc..." + /* 10 */ "mmmmm...adc..." + /* 11 */ "mmmmm...adc...", + + // Connectors: + "-1: 5, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseL14x12 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // HouseL14x12: + // The data has been exported from the gallery Desert, area index 7, ID 82, created by Aloe_vera + { + // Size: + 14, 6, 12, // SizeX = 14, SizeY = 6, SizeZ = 12 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 13, 5, 11, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a:128: 0\n" /* sandstonestairs */ + "b:128: 2\n" /* sandstonestairs */ + "c:128: 1\n" /* sandstonestairs */ + "d: 24: 0\n" /* sandstone */ + "e:128: 3\n" /* sandstonestairs */ + "f: 64: 7\n" /* wooddoorblock */ + "g: 64: 5\n" /* wooddoorblock */ + "h:102: 0\n" /* glasspane */ + "i: 64:12\n" /* wooddoorblock */ + "j:128: 7\n" /* sandstonestairs */ + "k: 50: 3\n" /* torch */ + "l: 50: 4\n" /* torch */ + "m: 19: 0\n" /* sponge */ + "n:128: 6\n" /* sandstonestairs */ + "o:128: 5\n" /* sandstonestairs */ + "p:128: 4\n" /* sandstonestairs */ + "q: 50: 1\n" /* torch */, + + // Block data: + // Level 0 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".......abc...." + /* 1 */ ".dddddddddddd." + /* 2 */ ".dddddddddddd." + /* 3 */ ".dddddddddddd." + /* 4 */ ".dddddddddddd." + /* 5 */ ".dddddddddddd." + /* 6 */ "....aec.ddddd." + /* 7 */ "mmmmmmm.ddddd." + /* 8 */ "mmmmmmm.ddddd." + /* 9 */ "mmmmmmm.ddddd." + /* 10 */ "mmmmmmm.ddddd." + /* 11 */ "mmmmmmm......." + + // Level 1 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".dddddddfdddd." + /* 2 */ ".d..........d." + /* 3 */ ".d..........d." + /* 4 */ ".d..........d." + /* 5 */ ".ddddgddd...d." + /* 6 */ "........d...d." + /* 7 */ "mmmmmmm.d...d." + /* 8 */ "mmmmmmm.d...d." + /* 9 */ "mmmmmmm.d...d." + /* 10 */ "mmmmmmm.ddddd." + /* 11 */ "mmmmmmm......." + + // Level 2 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".dhhdhhdidhhd." + /* 2 */ ".h..........h." + /* 3 */ ".h..........h." + /* 4 */ ".h..........d." + /* 5 */ ".dhhdidhh...h." + /* 6 */ "........h...h." + /* 7 */ "mmmmmmm.d...d." + /* 8 */ "mmmmmmm.h...h." + /* 9 */ "mmmmmmm.h...h." + /* 10 */ "mmmmmmm.dhhhd." + /* 11 */ "mmmmmmm......." + + // Level 3 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "bbbbbbbbbbbbbb" + /* 1 */ "jddddddddddddc" + /* 2 */ ".d.....k.k..dc" + /* 3 */ ".d..........dc" + /* 4 */ ".d..l.l.....dc" + /* 5 */ "ndddddddd...dc" + /* 6 */ "eeeeeeead...dc" + /* 7 */ "mmmmmmmad...dc" + /* 8 */ "mmmmmmmad...dc" + /* 9 */ "mmmmmmmad...dc" + /* 10 */ "mmmmmmmadddddc" + /* 11 */ "mmmmmmmao...pc" + + // Level 4 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ "bbbbbbbbbbbbb." + /* 2 */ "jdddddddddddc." + /* 3 */ ".dq........dc." + /* 4 */ "nddddddddd.dc." + /* 5 */ "eeeeeeeead.dc." + /* 6 */ "........ad.dc." + /* 7 */ "mmmmmmm.ad.dc." + /* 8 */ "mmmmmmm.ad.dc." + /* 9 */ "mmmmmmm.adldc." + /* 10 */ "mmmmmmm.adddc." + /* 11 */ "mmmmmmm.ao.pc." + + // Level 5 + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ ".............." + /* 1 */ ".............." + /* 2 */ "bbbbbbbbbbbb.." + /* 3 */ "dddddddddddc.." + /* 4 */ "eeeeeeeeeadc.." + /* 5 */ ".........adc.." + /* 6 */ ".........adc.." + /* 7 */ "mmmmmmm..adc.." + /* 8 */ "mmmmmmm..adc.." + /* 9 */ "mmmmmmm..adc.." + /* 10 */ "mmmmmmm..adc.." + /* 11 */ "mmmmmmm..adc..", + + // Connectors: + "-1: 8, 0, 0: 2\n" /* Type -1, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // HouseL14x12 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SingleField: + // The data has been exported from the gallery Desert, area index 17, ID 127, created by Aloe_vera + { + // Size: + 10, 2, 7, // SizeX = 10, SizeY = 2, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 9, 1, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 24: 0\n" /* sandstone */ + "b: 60: 7\n" /* tilleddirt */ + "c: 8: 0\n" /* water */ + "d: 50: 5\n" /* torch */ + "e: 59: 7\n" /* crops */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "aaaaaaaaaa" + /* 1 */ "abbbbbbbba" + /* 2 */ "abbbbbbbba" + /* 3 */ "acccccccca" + /* 4 */ "abbbbbbbba" + /* 5 */ "abbbbbbbba" + /* 6 */ "aaaaaaaaaa" + + // Level 1 + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "d........d" + /* 1 */ ".eeeeeeee." + /* 2 */ ".eeeeeeee." + /* 3 */ ".........." + /* 4 */ ".eeeeeeee." + /* 5 */ ".eeeeeeee." + /* 6 */ "d........d", + + // Connectors: + "-1: 0, 0, 3: 4\n" /* Type -1, direction X- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // SingleField + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // SmallHut: + // The data has been exported from the gallery Desert, area index 4, ID 68, created by tonibm1999 + { + // Size: + 5, 5, 6, // SizeX = 5, SizeY = 5, SizeZ = 6 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 4, 4, 5, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 24: 0\n" /* sandstone */ + "b:128: 3\n" /* sandstonestairs */ + "c: 24: 2\n" /* sandstone */ + "d: 50: 5\n" /* torch */ + "e: 26:10\n" /* bedblock */ + "f: 26: 2\n" /* bedblock */ + "g: 64: 5\n" /* wooddoorblock */ + "h: 64:12\n" /* wooddoorblock */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 01234 */ + /* 0 */ "aaaaa" + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ "aaaaa" + /* 5 */ "..b.." + + // Level 1 + /* z\x* 01234 */ + /* 0 */ "accca" + /* 1 */ "cdedc" + /* 2 */ "c.f.c" + /* 3 */ "c...c" + /* 4 */ "acgca" + /* 5 */ "....." + + // Level 2 + /* z\x* 01234 */ + /* 0 */ "ac.ca" + /* 1 */ "c...c" + /* 2 */ "....." + /* 3 */ "c...c" + /* 4 */ "achca" + /* 5 */ "....." + + // Level 3 + /* z\x* 01234 */ + /* 0 */ "accca" + /* 1 */ "c...c" + /* 2 */ "c...c" + /* 3 */ "c...c" + /* 4 */ "accca" + /* 5 */ "....." + + // Level 4 + /* z\x* 01234 */ + /* 0 */ ".aaa." + /* 1 */ "aaaaa" + /* 2 */ "aaaaa" + /* 3 */ "aaaaa" + /* 4 */ ".aaa." + /* 5 */ ".....", + + // Connectors: + "-1: 2, 0, 5: 3\n" /* Type -1, direction Z+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // SmallHut +}; // g_SandVillagePrefabs + + + + + + +const cPrefab::sDef g_SandVillageStartingPrefabs[] = +{ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // RoofedWell: + // The data has been exported from the gallery Desert, area index 43, ID 274, created by Aloe_vera + { + // Size: + 7, 14, 7, // SizeX = 7, SizeY = 14, SizeZ = 7 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 6, 13, 6, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 24: 0\n" /* sandstone */ + "c: 8: 0\n" /* water */ + "d: 12: 0\n" /* sand */ + "e:118: 3\n" /* cauldronblock */ + "f: 85: 0\n" /* fence */ + "g:128: 2\n" /* sandstonestairs */ + "h:128: 7\n" /* sandstonestairs */ + "i:128: 4\n" /* sandstonestairs */ + "j:128: 5\n" /* sandstonestairs */ + "k:128: 6\n" /* sandstonestairs */ + "l:128: 3\n" /* sandstonestairs */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" + + // Level 1 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 2 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 3 + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "abbbbba" + /* 2 */ "abcccba" + /* 3 */ "abcccba" + /* 4 */ "abcccba" + /* 5 */ "abbbbba" + /* 6 */ "aaaaaaa" + + // Level 4 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 5 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 6 + /* z\x* 0123456 */ + /* 0 */ "ddddddd" + /* 1 */ "dbbbbbd" + /* 2 */ "dbcccbd" + /* 3 */ "dbcccbd" + /* 4 */ "dbcccbd" + /* 5 */ "dbbbbbd" + /* 6 */ "ddddddd" + + // Level 7 + /* z\x* 0123456 */ + /* 0 */ "ddbbbdd" + /* 1 */ "dbbbbbd" + /* 2 */ "bbcccbb" + /* 3 */ "bbcccbb" + /* 4 */ "bbcccbb" + /* 5 */ "dbbbbbd" + /* 6 */ "ddbbbdd" + + // Level 8 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".bbbbb." + /* 2 */ ".b...b." + /* 3 */ ".b.e.b." + /* 4 */ ".b...b." + /* 5 */ ".bbbbb." + /* 6 */ "......." + + // Level 9 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".f...f." + /* 2 */ "......." + /* 3 */ "...f..." + /* 4 */ "......." + /* 5 */ ".f...f." + /* 6 */ "......." + + // Level 10 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ ".f...f." + /* 2 */ "......." + /* 3 */ "...f..." + /* 4 */ "......." + /* 5 */ ".f...f." + /* 6 */ "......." + + // Level 11 + /* z\x* 0123456 */ + /* 0 */ "ggggggg" + /* 1 */ "hbhhhbh" + /* 2 */ ".i...j." + /* 3 */ ".i.f.j." + /* 4 */ ".i...j." + /* 5 */ "kbkkkbk" + /* 6 */ "lllllll" + + // Level 12 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "ggggggg" + /* 2 */ "hb...bh" + /* 3 */ ".b.f.b." + /* 4 */ "kb...bk" + /* 5 */ "lllllll" + /* 6 */ "......." + + // Level 13 + /* z\x* 0123456 */ + /* 0 */ "......." + /* 1 */ "......." + /* 2 */ "ggggggg" + /* 3 */ "bbbbbbb" + /* 4 */ "lllllll" + /* 5 */ "......." + /* 6 */ ".......", + + // Connectors: + "2: 6, 8, 3: 5\n" /* Type 2, direction X+ */ + "2: 3, 8, 6: 3\n" /* Type 2, direction Z+ */ + "2: 0, 8, 3: 4\n" /* Type 2, direction X- */ + "2: 3, 8, 0: 2\n" /* Type 2, direction Z- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // RoofedWell + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Well: + // The data has been exported from the gallery Desert, area index 0, ID 1, created by Aloe_vera + { + // Size: + 4, 13, 4, // SizeX = 4, SizeY = 13, SizeZ = 4 + + // Hitbox (relative to bounding box): + 0, 0, 0, // MinX, MinY, MinZ + 3, 12, 3, // MaxX, MaxY, MaxZ + + // Block definitions: + ".: 0: 0\n" /* air */ + "a: 1: 0\n" /* stone */ + "b: 24: 0\n" /* sandstone */ + "c: 8: 0\n" /* water */ + "d: 85: 0\n" /* fence */ + "m: 19: 0\n" /* sponge */, + + // Block data: + // Level 0 + /* z\x* 0123 */ + /* 0 */ "aaaa" + /* 1 */ "aaaa" + /* 2 */ "aaaa" + /* 3 */ "aaaa" + + // Level 1 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 2 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 3 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 4 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 5 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 6 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 7 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bccb" + /* 2 */ "bccb" + /* 3 */ "bbbb" + + // Level 8 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "b..b" + /* 2 */ "b..b" + /* 3 */ "bbbb" + + // Level 9 + /* z\x* 0123 */ + /* 0 */ "d..d" + /* 1 */ "...." + /* 2 */ "...." + /* 3 */ "d..d" + + // Level 10 + /* z\x* 0123 */ + /* 0 */ "d..d" + /* 1 */ "...." + /* 2 */ "...." + /* 3 */ "d..d" + + // Level 11 + /* z\x* 0123 */ + /* 0 */ "d..d" + /* 1 */ "...." + /* 2 */ "...." + /* 3 */ "d..d" + + // Level 12 + /* z\x* 0123 */ + /* 0 */ "bbbb" + /* 1 */ "bbbb" + /* 2 */ "bbbb" + /* 3 */ "bbbb", + + // Connectors: + "2: 2, 8, 0: 2\n" /* Type 2, direction Z- */ + "2: 0, 8, 1: 4\n" /* Type 2, direction X- */ + "2: 1, 8, 3: 3\n" /* Type 2, direction Z+ */ + "2: 3, 8, 2: 5\n" /* Type 2, direction X+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + true, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + + // MoveToGround: + true, + }, // Well +}; + + + + + +// The prefab counts: + +const size_t g_SandVillagePrefabsCount = ARRAYCOUNT(g_SandVillagePrefabs); + +const size_t g_SandVillageStartingPrefabsCount = ARRAYCOUNT(g_SandVillageStartingPrefabs); + diff --git a/src/Generating/Prefabs/SandVillagePrefabs.h b/src/Generating/Prefabs/SandVillagePrefabs.h new file mode 100644 index 000000000..7b00db56f --- /dev/null +++ b/src/Generating/Prefabs/SandVillagePrefabs.h @@ -0,0 +1,15 @@ + +// SandVillagePrefabs.h + +// Declares the prefabs in the group SandVillage + +#include "../Prefab.h" + + + + + +extern const cPrefab::sDef g_SandVillagePrefabs[]; +extern const cPrefab::sDef g_SandVillageStartingPrefabs[]; +extern const size_t g_SandVillagePrefabsCount; +extern const size_t g_SandVillageStartingPrefabsCount; diff --git a/src/Generating/Ravines.cpp b/src/Generating/Ravines.cpp index e64f55214..2722e4ca3 100644 --- a/src/Generating/Ravines.cpp +++ b/src/Generating/Ravines.cpp @@ -9,9 +9,6 @@ -/// How many ravines in each direction are generated for a given chunk. Must be an even number -static const int NEIGHBORHOOD_SIZE = 8; - static const int NUM_RAVINE_POINTS = 4; @@ -42,40 +39,38 @@ typedef std::vector<cRavDefPoint> cRavDefPoints; -class cStructGenRavines::cRavine +class cStructGenRavines::cRavine : + public cGridStructGen::cStructure { + typedef cGridStructGen::cStructure super; + cRavDefPoints m_Points; + - /// Generates the shaping defpoints for the ravine, based on the ravine block coords and noise + /** Generates the shaping defpoints for the ravine, based on the ravine block coords and noise */ void GenerateBaseDefPoints(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise); - /// Refines (adds and smooths) defpoints from a_Src into a_Dst + /** Refines (adds and smooths) defpoints from a_Src into a_Dst */ void RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst); - /// Does one round of smoothing, two passes of RefineDefPoints() + /** Does one round of smoothing, two passes of RefineDefPoints() */ void Smooth(void); - /// Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block + /** Linearly interpolates the points so that the maximum distance between two neighbors is max 1 block */ void FinishLinear(void); public: - // Coords for which the ravine was generated (not necessarily the center) - int m_BlockX; - int m_BlockZ; cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise); - /// Carves the ravine into the chunk specified - void ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap - ); - #ifdef _DEBUG /// Exports itself as a SVG line definition AString ExportAsSVG(int a_Color, int a_OffsetX = 0, int a_OffsetZ = 0) const; #endif // _DEBUG + +protected: + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_ChunkDesc) override; } ; @@ -86,6 +81,7 @@ public: // cStructGenRavines: cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) : + super(a_Seed, a_Size, a_Size, a_Size * 2, a_Size * 2, 100), m_Noise(a_Seed), m_Size(a_Size) { @@ -95,139 +91,9 @@ cStructGenRavines::cStructGenRavines(int a_Seed, int a_Size) : -cStructGenRavines::~cStructGenRavines() -{ - ClearCache(); -} - - - - - -void cStructGenRavines::ClearCache(void) +cGridStructGen::cStructurePtr cStructGenRavines::CreateStructure(int a_OriginX, int a_OriginZ) { - for (cRavines::const_iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } // for itr - m_Cache[] - m_Cache.clear(); -} - - - - - -void cStructGenRavines::GenFinish(cChunkDesc & a_ChunkDesc) -{ - int ChunkX = a_ChunkDesc.GetChunkX(); - int ChunkZ = a_ChunkDesc.GetChunkZ(); - cRavines Ravines; - GetRavinesForChunk(ChunkX, ChunkZ, Ravines); - for (cRavines::const_iterator itr = Ravines.begin(), end = Ravines.end(); itr != end; ++itr) - { - (*itr)->ProcessChunk(ChunkX, ChunkZ, a_ChunkDesc.GetBlockTypes(), a_ChunkDesc.GetHeightMap()); - } // for itr - Ravines[] -} - - - - - -void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGenRavines::cRavines & a_Ravines) -{ - int BaseX = a_ChunkX * cChunkDef::Width / m_Size; - int BaseZ = a_ChunkZ * cChunkDef::Width / m_Size; - if (BaseX < 0) - { - --BaseX; - } - if (BaseZ < 0) - { - --BaseZ; - } - BaseX -= 4; - BaseZ -= 4; - - // Walk the cache, move each ravine that we want into a_Ravines: - int StartX = BaseX * m_Size; - int EndX = (BaseX + NEIGHBORHOOD_SIZE + 1) * m_Size; - int StartZ = BaseZ * m_Size; - int EndZ = (BaseZ + NEIGHBORHOOD_SIZE + 1) * m_Size; - for (cRavines::iterator itr = m_Cache.begin(), end = m_Cache.end(); itr != end;) - { - if ( - ((*itr)->m_BlockX >= StartX) && ((*itr)->m_BlockX < EndX) && - ((*itr)->m_BlockZ >= StartZ) && ((*itr)->m_BlockZ < EndZ) - ) - { - // want - a_Ravines.push_back(*itr); - itr = m_Cache.erase(itr); - } - else - { - // don't want - ++itr; - } - } // for itr - m_Cache[] - - for (int x = 0; x < NEIGHBORHOOD_SIZE; x++) - { - int RealX = (BaseX + x) * m_Size; - for (int z = 0; z < NEIGHBORHOOD_SIZE; z++) - { - int RealZ = (BaseZ + z) * m_Size; - bool Found = false; - for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr) - { - if (((*itr)->m_BlockX == RealX) && ((*itr)->m_BlockZ == RealZ)) - { - Found = true; - break; - } - } - if (!Found) - { - a_Ravines.push_back(new cRavine(RealX, RealZ, m_Size, m_Noise)); - } - } - } - - // Copy a_Ravines into m_Cache to the beginning: - cRavines RavinesCopy(a_Ravines); - m_Cache.splice(m_Cache.begin(), RavinesCopy, RavinesCopy.begin(), RavinesCopy.end()); - - // Trim the cache if it's too long: - if (m_Cache.size() > 100) - { - cRavines::iterator itr = m_Cache.begin(); - std::advance(itr, 100); - for (cRavines::iterator end = m_Cache.end(); itr != end; ++itr) - { - delete *itr; - } - itr = m_Cache.begin(); - std::advance(itr, 100); - m_Cache.erase(itr, m_Cache.end()); - } - - /* - #ifdef _DEBUG - // DEBUG: Export as SVG into a file specific for the chunk, for visual verification: - AString SVG; - SVG.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1024\" height = \"1024\">\n"); - for (cRavines::const_iterator itr = a_Ravines.begin(), end = a_Ravines.end(); itr != end; ++itr) - { - SVG.append((*itr)->ExportAsSVG(0, 512, 512)); - } - SVG.append("</svg>\n"); - - AString fnam; - Printf(fnam, "ravines\\%03d_%03d.svg", a_ChunkX, a_ChunkZ); - cFile File(fnam, cFile::fmWrite); - File.Write(SVG.c_str(), SVG.size()); - #endif // _DEBUG - //*/ + return cStructurePtr(new cRavine(a_OriginX, a_OriginZ, m_Size, m_Noise)); } @@ -238,14 +104,13 @@ void cStructGenRavines::GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cStructGe /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cStructGenRavines::cRavine -cStructGenRavines::cRavine::cRavine(int a_BlockX, int a_BlockZ, int a_Size, cNoise & a_Noise) : - m_BlockX(a_BlockX), - m_BlockZ(a_BlockZ) +cStructGenRavines::cRavine::cRavine(int a_OriginX, int a_OriginZ, int a_Size, cNoise & a_Noise) : + super(a_OriginX, a_OriginZ) { // Calculate the ravine shape-defining points: - GenerateBaseDefPoints(a_BlockX, a_BlockZ, a_Size, a_Noise); + GenerateBaseDefPoints(a_OriginX, a_OriginZ, a_Size, a_Noise); - // Smooth the ravine. A two passes are needed: + // Smooth the ravine. Two passes are needed: Smooth(); Smooth(); @@ -263,13 +128,13 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block a_Size = (512 + ((a_Noise.IntNoise3DInt(19 * a_BlockX, 11 * a_BlockZ, a_BlockX + a_BlockZ) / 17) % 512)) * a_Size / 1024; // The complete offset of the ravine from its cellpoint, up to 2 * a_Size in each direction - int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2; - int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * m_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2; + int OffsetX = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 0) / 9) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 1000) / 7) % (2 * a_Size)) - 2 * a_Size) / 2; + int OffsetZ = (((a_Noise.IntNoise3DInt(50 * a_BlockX, 30 * a_BlockZ, 2000) / 7) % (2 * a_Size)) + ((a_Noise.IntNoise3DInt(30 * a_BlockX, 50 * a_BlockZ, 3000) / 9) % (2 * a_Size)) - 2 * a_Size) / 2; int CenterX = a_BlockX + OffsetX; int CenterZ = a_BlockZ + OffsetZ; // Get the base angle in which the ravine "axis" goes: - float Angle = (float)(((float)((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * 3.141592653); + float Angle = (float)(((float)((a_Noise.IntNoise3DInt(20 * a_BlockX, 70 * a_BlockZ, 6000) / 9) % 16384)) / 16384.0 * M_PI); float xc = sin(Angle); float zc = cos(Angle); @@ -306,18 +171,25 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block void cStructGenRavines::cRavine::RefineDefPoints(const cRavDefPoints & a_Src, cRavDefPoints & a_Dst) { + if (a_Src.size() < 2) + { + // No midpoints, nothing to refine + return; + } + // Smoothing: for each line segment, add points on its 1/4 lengths - int Num = a_Src.size() - 2; // this many intermediary points + size_t Num = a_Src.size() - 2; // this many intermediary points a_Dst.clear(); a_Dst.reserve(Num * 2 + 2); cRavDefPoints::const_iterator itr = a_Src.begin() + 1; - a_Dst.push_back(a_Src.front()); - int PrevX = a_Src.front().m_BlockX; - int PrevZ = a_Src.front().m_BlockZ; - int PrevR = a_Src.front().m_Radius; - int PrevT = a_Src.front().m_Top; - int PrevB = a_Src.front().m_Bottom; - for (int i = 0; i <= Num; ++i, ++itr) + const cRavDefPoint & Source = a_Src.front(); + a_Dst.push_back(Source); + int PrevX = Source.m_BlockX; + int PrevZ = Source.m_BlockZ; + int PrevR = Source.m_Radius; + int PrevT = Source.m_Top; + int PrevB = Source.m_Bottom; + for (size_t i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; int dz = itr->m_BlockZ - PrevZ; @@ -422,15 +294,15 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int // Base point highlight: AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX - 5, a_OffsetZ + m_BlockZ, a_OffsetX + m_BlockX + 5, a_OffsetZ + m_BlockZ + a_OffsetX + m_OriginX - 5, a_OffsetZ + m_OriginZ, a_OffsetX + m_OriginX + 5, a_OffsetZ + m_OriginZ ); AppendPrintf(SVG, "<path style=\"fill:none;stroke:#ff0000;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ - 5, a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ + 5 + a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ - 5, a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ + 5 ); // A gray line from the base point to the first point of the ravine, for identification: AppendPrintf(SVG, "<path style=\"fill:none;stroke:#cfcfcf;stroke-width:1px;\"\nd=\"M %d,%d L %d,%d\"/>\n", - a_OffsetX + m_BlockX, a_OffsetZ + m_BlockZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ + a_OffsetX + m_OriginX, a_OffsetZ + m_OriginZ, a_OffsetX + m_Points.front().m_BlockX, a_OffsetZ + m_Points.front().m_BlockZ ); // Offset guides: @@ -454,14 +326,10 @@ AString cStructGenRavines::cRavine::ExportAsSVG(int a_Color, int a_OffsetX, int -void cStructGenRavines::cRavine::ProcessChunk( - int a_ChunkX, int a_ChunkZ, - cChunkDef::BlockTypes & a_BlockTypes, - cChunkDef::HeightMap & a_HeightMap -) +void cStructGenRavines::cRavine::DrawIntoChunk(cChunkDesc & a_ChunkDesc) { - int BlockStartX = a_ChunkX * cChunkDef::Width; - int BlockStartZ = a_ChunkZ * cChunkDef::Width; + int BlockStartX = a_ChunkDesc.GetChunkX() * cChunkDef::Width; + int BlockStartZ = a_ChunkDesc.GetChunkZ() * cChunkDef::Width; int BlockEndX = BlockStartX + cChunkDef::Width; int BlockEndZ = BlockStartZ + cChunkDef::Width; for (cRavDefPoints::const_iterator itr = m_Points.begin(), end = m_Points.end(); itr != end; ++itr) @@ -487,7 +355,7 @@ void cStructGenRavines::cRavine::ProcessChunk( // DEBUG: Make the ravine shapepoints visible on a single layer (so that we can see with Minutor what's going on) if ((DifX + x == 0) && (DifZ + z == 0)) { - cChunkDef::SetBlock(a_BlockTypes, x, 4, z, E_BLOCK_LAPIS_ORE); + a_ChunkDesc.SetBlockType(x, 4, z, E_BLOCK_LAPIS_ORE); } #endif // _DEBUG @@ -497,7 +365,7 @@ void cStructGenRavines::cRavine::ProcessChunk( int Top = std::min(itr->m_Top, (int)(cChunkDef::Height)); // Stupid gcc needs int cast for (int y = std::max(itr->m_Bottom, 1); y <= Top; y++) { - switch (cChunkDef::GetBlock(a_BlockTypes, x, y, z)) + switch (a_ChunkDesc.GetBlockType(x, y, z)) { // Only carve out these specific block types case E_BLOCK_DIRT: @@ -515,7 +383,7 @@ void cStructGenRavines::cRavine::ProcessChunk( case E_BLOCK_REDSTONE_ORE: case E_BLOCK_REDSTONE_ORE_GLOWING: { - cChunkDef::SetBlock(a_BlockTypes, x, y, z, E_BLOCK_AIR); + a_ChunkDesc.SetBlockType(x, y, z, E_BLOCK_AIR); break; } default: break; diff --git a/src/Generating/Ravines.h b/src/Generating/Ravines.h index c76b9f19f..30b47e9ec 100644 --- a/src/Generating/Ravines.h +++ b/src/Generating/Ravines.h @@ -9,7 +9,7 @@ #pragma once -#include "ComposableGenerator.h" +#include "GridStructGen.h" #include "../Noise.h" @@ -17,28 +17,22 @@ class cStructGenRavines : - public cFinishGen + public cGridStructGen { + typedef cGridStructGen super; + public: cStructGenRavines(int a_Seed, int a_Size); - ~cStructGenRavines(); protected: class cRavine; // fwd: Ravines.cpp - typedef std::list<cRavine *> cRavines; - - cNoise m_Noise; - int m_Size; // Max size, in blocks, of the ravines generated - cRavines m_Cache; - /// Clears everything from the cache - void ClearCache(void); + cNoise m_Noise; + int m_Size; // Max size, in blocks, of the ravines generated - /// Returns all ravines that *may* intersect the given chunk. All the ravines are valid until the next call to this function. - void GetRavinesForChunk(int a_ChunkX, int a_ChunkZ, cRavines & a_Ravines); - - // cFinishGen override: - virtual void GenFinish(cChunkDesc & a_ChunkDesc) override; + + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; } ; diff --git a/src/Generating/StructGen.cpp b/src/Generating/StructGen.cpp index db9d5578c..636364e17 100644 --- a/src/Generating/StructGen.cpp +++ b/src/Generating/StructGen.cpp @@ -596,24 +596,22 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc) // Interpolate between FloorLo and FloorHi: for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++) { - switch (a_ChunkDesc.GetBiome(x, z)) + EMCSBiome biome = a_ChunkDesc.GetBiome(x, z); + + if ((biome == biExtremeHills) || (biome == biExtremeHillsEdge)) { - case biExtremeHills: - case biExtremeHillsEdge: + int Lo = FloorLo[x + 17 * z] / 256; + int Hi = FloorHi[x + 17 * z] / 256; + for (int y = 0; y < SEGMENT_HEIGHT; y++) { - int Lo = FloorLo[x + 17 * z] / 256; - int Hi = FloorHi[x + 17 * z] / 256; - for (int y = 0; y < SEGMENT_HEIGHT; y++) + int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT; + if (Val < 0) { - int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT; - if (Val < 0) - { - a_ChunkDesc.SetBlockType(x, y + Segment, z, E_BLOCK_AIR); - } - } // for y - break; - } - } // switch (biome) + a_ChunkDesc.SetBlockType(x, y + Segment, z, E_BLOCK_AIR); + } + } // for y + break; + } // if (biome) } // for z, x // Swap the floors: diff --git a/src/Generating/Trees.cpp b/src/Generating/Trees.cpp index 4909587b1..522f45148 100644 --- a/src/Generating/Trees.cpp +++ b/src/Generating/Trees.cpp @@ -136,7 +136,7 @@ inline void PushSomeColumns(int a_BlockX, int a_Height, int a_BlockZ, int a_Colu { 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) + if (a_Noise.IntNoise3DInt(x + 64 * a_Seq, a_Height + (int)i, z + 64 * a_Seq) <= a_Chance) { for (int j = 0; j < a_ColumnHeight; j++) { @@ -174,7 +174,7 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No { GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); } - break; + return; } case biTaiga: @@ -184,14 +184,14 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No { // Conifers GetConiferTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); - break; + return; } case biSwampland: { // Swamp trees: GetSwampTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); - break; + return; } case biJungle: @@ -207,21 +207,21 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No { GetJungleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); } - break; + return; } case biBirchForest: case biBirchForestHills: { GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); - break; + return; } case biBirchForestM: case biBirchForestHillsM: { GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); - break; + return; } case biRoofedForest: @@ -257,9 +257,29 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No { // TODO: These need their special trees GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks); - break; + return; + } + + case biDesert: + case biDesertHills: + case biRiver: + case biBeach: + case biHell: + case biSky: + case biOcean: + case biFrozenOcean: + case biFrozenRiver: + case biVariant: + case biNumBiomes: + case biNumVariantBiomes: + case biInvalidBiome: + { + // These biomes have no trees, or are non-biome members of the enum. + return; } } + + ASSERT(!"Invalid biome type!"); } diff --git a/src/Generating/VillageGen.cpp b/src/Generating/VillageGen.cpp new file mode 100644 index 000000000..b9cb056ad --- /dev/null +++ b/src/Generating/VillageGen.cpp @@ -0,0 +1,430 @@ + +// VillageGen.cpp + +// Implements the cVillageGen class representing the village generator + +#include "Globals.h" +#include "VillageGen.h" +#include "Prefabs/AlchemistVillagePrefabs.h" +#include "Prefabs/JapaneseVillagePrefabs.h" +#include "Prefabs/PlainsVillagePrefabs.h" +#include "Prefabs/SandVillagePrefabs.h" +#include "Prefabs/SandFlatRoofVillagePrefabs.h" +#include "PieceGenerator.h" + + + + + +/* +How village generating works: +By descending from a cGridStructGen, a semi-random grid is generated. A village may be generated for each of +the grid's cells. Each cell checks the biomes in an entire chunk around it, only generating a village if all +biomes are village-friendly. If yes, the entire village structure is built for that cell. If not, the cell +is left village-less. + +A village is generated using the regular BFS piece generator. The well piece is used as the starting piece, +the roads and houses are then used as the following pieces. Only the houses are read from the prefabs, +though, the roads are generated by code and their content is ignored. A special subclass of the cPiecePool +class is used, so that the roads connect to each other and to the well only in predefined manners. + +The well has connectors of type "2". The houses have connectors of type "-1". The roads have connectors of +both types' opposites, type "-2" at the far ends and type "1" on the long edges. Additionally, there are +type "2" connectors along the long edges of the roads as well, so that the roads create T junctions. + +When the village is about to be drawn into a chunk, it queries the heights for each piece intersecting the +chunk. The pieces are shifted so that their pivot points lie on the surface, and the roads are drawn +directly by turning the surface blocks into gravel / sandstone. + +The village prefabs are stored in global piecepools (one pool per village type). In order to support +per-village density setting, the cVillage class itself implements the cPiecePool interface, relaying the +calls to the underlying cVillagePiecePool, after processing the density check. +*/ + +class cVillagePiecePool : + public cPrefabPiecePool +{ + typedef cPrefabPiecePool super; +public: + cVillagePiecePool( + const cPrefab::sDef * a_PieceDefs, size_t a_NumPieceDefs, + const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs + ) : + super(a_PieceDefs, a_NumPieceDefs, a_StartingPieceDefs, a_NumStartingPieceDefs) + { + // Add the road pieces: + for (int len = 27; len < 60; len += 12) + { + cBlockArea BA; + BA.Create(len, 1, 3, cBlockArea::baTypes | cBlockArea::baMetas); + BA.Fill(cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_GRAVEL, 0); + cPrefab * RoadPiece = new cPrefab(BA, 1); + RoadPiece->AddConnector(0, 0, 1, BLOCK_FACE_XM, -2); + RoadPiece->AddConnector(len - 1, 0, 1, BLOCK_FACE_XP, -2); + RoadPiece->SetDefaultWeight(100); + + // Add the road connectors: + for (int x = 1; x < len; x += 12) + { + RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 2); + RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 2); + } + + // Add the buildings connectors: + for (int x = 7; x < len; x += 12) + { + RoadPiece->AddConnector(x, 0, 0, BLOCK_FACE_ZM, 1); + RoadPiece->AddConnector(x, 0, 2, BLOCK_FACE_ZP, 1); + } + m_AllPieces.push_back(RoadPiece); + m_PiecesByConnector[-2].push_back(RoadPiece); + m_PiecesByConnector[1].push_back(RoadPiece); + m_PiecesByConnector[2].push_back(RoadPiece); + } // for len - roads of varying length + } + + + // cPrefabPiecePool overrides: + virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override + { + // Roads cannot branch T-wise (appending -2 connector to a +2 connector on a 1-high piece): + if ((a_ExistingConnector.m_Type == 2) && (a_PlacedPiece.GetDepth() > 0) && (a_PlacedPiece.GetPiece().GetSize().y == 1)) + { + return 0; + } + + return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector); + } +} ; + + + + + +class cVillageGen::cVillage : + public cGridStructGen::cStructure, + protected cPiecePool +{ + typedef cGridStructGen::cStructure super; + +public: + cVillage( + int a_Seed, + int a_OriginX, int a_OriginZ, + int a_MaxRoadDepth, + int a_MaxSize, + int a_Density, + cPiecePool & a_Prefabs, + cTerrainHeightGen & a_HeightGen, + BLOCKTYPE a_RoadBlock + ) : + super(a_OriginX, a_OriginZ), + m_Seed(a_Seed), + m_Noise(a_Seed), + m_MaxSize(a_MaxSize), + m_Density(a_Density), + m_Borders(a_OriginX - a_MaxSize, 0, a_OriginZ - a_MaxSize, a_OriginX + a_MaxSize, 255, a_OriginZ + a_MaxSize), + m_Prefabs(a_Prefabs), + m_HeightGen(a_HeightGen), + m_RoadBlock(a_RoadBlock) + { + // Generate the pieces for this village; don't care about the Y coord: + cBFSPieceGenerator pg(*this, a_Seed); + pg.PlacePieces(a_OriginX, 0, a_OriginZ, a_MaxRoadDepth + 1, m_Pieces); + if (m_Pieces.empty()) + { + return; + } + + // If the central piece should be moved to ground, move it, and + // check all of its dependents and move those that are strictly connector-driven based on its new Y coord: + if (((cPrefab &)m_Pieces[0]->GetPiece()).ShouldMoveToGround()) + { + int OrigPosY = m_Pieces[0]->GetCoords().y; + PlacePieceOnGround(*m_Pieces[0]); + int NewPosY = m_Pieces[0]->GetCoords().y; + MoveAllDescendants(m_Pieces, 0, NewPosY - OrigPosY); + } + } + + ~cVillage() + { + cPieceGenerator::FreePieces(m_Pieces); + } + +protected: + /** Seed for the random functions */ + int m_Seed; + + /** The noise used as a pseudo-random generator */ + cNoise m_Noise; + + /** Maximum size, in X/Z blocks, of the village (radius from the origin) */ + int m_MaxSize; + + /** The density for this village. Used to refrain from populating all house connectors. Range [0, 100] */ + int m_Density; + + /** Borders of the vilalge - no item may reach out of this cuboid. */ + cCuboid m_Borders; + + /** Prefabs to use for buildings */ + cPiecePool & m_Prefabs; + + /** The underlying height generator, used for placing the structures on top of the terrain. */ + cTerrainHeightGen & m_HeightGen; + + /** The village pieces, placed by the generator. */ + cPlacedPieces m_Pieces; + + /** The block to use for the roads. */ + BLOCKTYPE m_RoadBlock; + + + // cGridStructGen::cStructure overrides: + virtual void DrawIntoChunk(cChunkDesc & a_Chunk) override + { + // Iterate over all items + // Each intersecting prefab is placed on ground, then drawn + // Each intersecting road is drawn by replacing top soil blocks with gravel / sandstone blocks + cChunkDef::HeightMap HeightMap; // Heightmap for this chunk, used by roads + m_HeightGen.GenHeightMap(a_Chunk.GetChunkX(), a_Chunk.GetChunkZ(), HeightMap); + for (cPlacedPieces::iterator itr = m_Pieces.begin(), end = m_Pieces.end(); itr != end; ++itr) + { + cPrefab & Prefab = (cPrefab &)((*itr)->GetPiece()); + if ((*itr)->GetPiece().GetSize().y == 1) + { + // It's a road, special handling (change top terrain blocks to m_RoadBlock) + DrawRoad(a_Chunk, **itr, HeightMap); + continue; + } + if (Prefab.ShouldMoveToGround() && !(*itr)->HasBeenMovedToGround()) + { + PlacePieceOnGround(**itr); + } + Prefab.Draw(a_Chunk, *itr); + } // for itr - m_PlacedPieces[] + } + + + /** Adjusts the Y coord of the given piece so that the piece is on the ground. + Ground level is assumed to be represented by the first connector in the piece. */ + void PlacePieceOnGround(cPlacedPiece & a_Piece) + { + cPiece::cConnector FirstConnector = a_Piece.GetRotatedConnector(0); + int ChunkX, ChunkZ; + int BlockX = FirstConnector.m_Pos.x; + int BlockZ = FirstConnector.m_Pos.z; + int BlockY; + cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); + cChunkDef::HeightMap HeightMap; + m_HeightGen.GenHeightMap(ChunkX, ChunkZ, HeightMap); + int TerrainHeight = cChunkDef::GetHeight(HeightMap, BlockX, BlockZ); + a_Piece.MoveToGroundBy(TerrainHeight - FirstConnector.m_Pos.y + 1); + } + + + /** Draws the road into the chunk. + The heightmap is not queried from the heightgen, but is given via parameter, so that it may be queried just + once for all roads in a chunk. */ + void DrawRoad(cChunkDesc & a_Chunk, cPlacedPiece & a_Road, cChunkDef::HeightMap & a_HeightMap) + { + cCuboid RoadCoords = a_Road.GetHitBox(); + RoadCoords.Sort(); + int MinX = std::max(RoadCoords.p1.x - a_Chunk.GetChunkX() * cChunkDef::Width, 0); + int MaxX = std::min(RoadCoords.p2.x - a_Chunk.GetChunkX() * cChunkDef::Width, cChunkDef::Width - 1); + int MinZ = std::max(RoadCoords.p1.z - a_Chunk.GetChunkZ() * cChunkDef::Width, 0); + int MaxZ = std::min(RoadCoords.p2.z - a_Chunk.GetChunkZ() * cChunkDef::Width, cChunkDef::Width - 1); + for (int z = MinZ; z <= MaxZ; z++) + { + for (int x = MinX; x <= MaxX; x++) + { + a_Chunk.SetBlockType(x, cChunkDef::GetHeight(a_HeightMap, x, z), z, m_RoadBlock); + } + } + } + + + // cPiecePool overrides: + virtual cPieces GetPiecesWithConnector(int a_ConnectorType) + { + return m_Prefabs.GetPiecesWithConnector(a_ConnectorType); + } + + + virtual cPieces GetStartingPieces(void) + { + return m_Prefabs.GetStartingPieces(); + } + + + virtual int GetPieceWeight( + const cPlacedPiece & a_PlacedPiece, + const cPiece::cConnector & a_ExistingConnector, + const cPiece & a_NewPiece + ) override + { + // Check against the density: + if (a_ExistingConnector.m_Type == 1) + { + const Vector3i & Coords = a_PlacedPiece.GetRotatedConnector(a_ExistingConnector).m_Pos; + int rnd = (m_Noise.IntNoise3DInt(Coords.x, Coords.y, Coords.z) / 7) % 100; + if (rnd > m_Density) + { + return 0; + } + } + + // Density check passed, relay to m_Prefabs: + return m_Prefabs.GetPieceWeight(a_PlacedPiece, a_ExistingConnector, a_NewPiece); + } + + + virtual int GetStartingPieceWeight(const cPiece & a_NewPiece) override + { + return m_Prefabs.GetStartingPieceWeight(a_NewPiece); + } + + + virtual void PiecePlaced(const cPiece & a_Piece) override + { + m_Prefabs.PiecePlaced(a_Piece); + } + + + virtual void Reset(void) override + { + m_Prefabs.Reset(); + } + + + void MoveAllDescendants(cPlacedPieces & a_PlacedPieces, size_t a_Pivot, int a_HeightDifference) + { + size_t num = a_PlacedPieces.size(); + cPlacedPiece * Pivot = a_PlacedPieces[a_Pivot]; + for (size_t i = a_Pivot + 1; i < num; i++) + { + if ( + (a_PlacedPieces[i]->GetParent() == Pivot) && // It is a direct dependant of the pivot + !((const cPrefab &)a_PlacedPieces[i]->GetPiece()).ShouldMoveToGround() // It attaches strictly by connectors + ) + { + a_PlacedPieces[i]->MoveToGroundBy(a_HeightDifference); + MoveAllDescendants(a_PlacedPieces, i, a_HeightDifference); + } + } // for i - a_PlacedPieces[] + } +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cVillageGen: + +static cVillagePiecePool g_SandVillage(g_SandVillagePrefabs, g_SandVillagePrefabsCount, g_SandVillageStartingPrefabs, g_SandVillageStartingPrefabsCount); +static cVillagePiecePool g_SandFlatRoofVillage(g_SandFlatRoofVillagePrefabs, g_SandFlatRoofVillagePrefabsCount, g_SandFlatRoofVillageStartingPrefabs, g_SandFlatRoofVillageStartingPrefabsCount); +static cVillagePiecePool g_AlchemistVillage(g_AlchemistVillagePrefabs, g_AlchemistVillagePrefabsCount, g_AlchemistVillageStartingPrefabs, g_AlchemistVillageStartingPrefabsCount); +static cVillagePiecePool g_PlainsVillage(g_PlainsVillagePrefabs, g_PlainsVillagePrefabsCount, g_PlainsVillageStartingPrefabs, g_PlainsVillageStartingPrefabsCount); +static cVillagePiecePool g_JapaneseVillage(g_JapaneseVillagePrefabs, g_JapaneseVillagePrefabsCount, g_JapaneseVillageStartingPrefabs, g_JapaneseVillageStartingPrefabsCount); + +static cVillagePiecePool * g_DesertVillagePools[] = +{ + &g_SandVillage, + &g_SandFlatRoofVillage, + &g_AlchemistVillage, +} ; + +static cVillagePiecePool * g_PlainsVillagePools[] = +{ + &g_PlainsVillage, + &g_JapaneseVillage, +} ; + + + + + +cVillageGen::cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen) : + super(a_Seed, a_GridSize, a_GridSize, a_MaxSize, a_MaxSize, 100), + m_Noise(a_Seed + 1000), + m_MaxDepth(a_MaxDepth), + m_MaxSize(a_MaxSize), + m_MinDensity(a_MinDensity), + m_MaxDensity(a_MaxDensity), + m_BiomeGen(a_BiomeGen), + m_HeightGen(a_HeightGen) +{ +} + + + + + +cGridStructGen::cStructurePtr cVillageGen::CreateStructure(int a_OriginX, int a_OriginZ) +{ + // Generate the biomes for the chunk surrounding the origin: + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(a_OriginX, a_OriginZ, ChunkX, ChunkZ); + cChunkDef::BiomeMap Biomes; + m_BiomeGen.GenBiomes(ChunkX, ChunkZ, Biomes); + + // Check if all the biomes are village-friendly: + // If just one is not, no village is created, because it's likely that an unfriendly biome is too close + cVillagePiecePool * VillagePrefabs = NULL; + BLOCKTYPE RoadBlock = E_BLOCK_GRAVEL; + int rnd = m_Noise.IntNoise2DInt(a_OriginX, a_OriginZ) / 11; + cVillagePiecePool * PlainsVillage = g_PlainsVillagePools[rnd % ARRAYCOUNT(g_PlainsVillagePools)]; + cVillagePiecePool * DesertVillage = g_DesertVillagePools[rnd % ARRAYCOUNT(g_DesertVillagePools)]; + for (size_t i = 0; i < ARRAYCOUNT(Biomes); i++) + { + switch (Biomes[i]) + { + case biDesert: + case biDesertM: + { + // These biomes allow sand villages + VillagePrefabs = DesertVillage; + // RoadBlock = E_BLOCK_SANDSTONE; + break; + } + case biPlains: + case biSavanna: + case biSavannaM: + case biSunflowerPlains: + { + // These biomes allow plains-style villages + VillagePrefabs = PlainsVillage; + break; + } + default: + { + // Village-unfriendly biome, bail out with zero structure: + return cStructurePtr(); + } + } // switch (Biomes[i]) + } // for i - Biomes[] + + // Choose density for the village, random between m_MinDensity and m_MaxDensity: + int Density; + if (m_MaxDensity > m_MinDensity) + { + Density = m_MinDensity + rnd % (m_MaxDensity - m_MinDensity); + } + else + { + Density = m_MinDensity; + } + + // Create a village based on the chosen prefabs: + if (VillagePrefabs == NULL) + { + return cStructurePtr(); + } + return cStructurePtr(new cVillage(m_Seed, a_OriginX, a_OriginZ, m_MaxDepth, m_MaxSize, Density, *VillagePrefabs, m_HeightGen, RoadBlock)); +} + + + + diff --git a/src/Generating/VillageGen.h b/src/Generating/VillageGen.h new file mode 100644 index 000000000..5faaae8a6 --- /dev/null +++ b/src/Generating/VillageGen.h @@ -0,0 +1,57 @@ + +// VillageGen.h + +// Declares the cVillageGen class representing the village generator + + + + + +#pragma once + +#include "GridStructGen.h" +#include "PrefabPiecePool.h" + + + + + +class cVillageGen : + public cGridStructGen +{ + typedef cGridStructGen super; +public: + cVillageGen(int a_Seed, int a_GridSize, int a_MaxDepth, int a_MaxSize, int a_MinDensity, int a_MaxDensity, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen); + +protected: + class cVillage; // fwd: VillageGen.cpp + + /** The noise used for generating random numbers */ + cNoise m_Noise; + + /** Maximum depth of the generator tree*/ + int m_MaxDepth; + + /** Maximum size, in X/Z blocks, of the village (radius from the origin) */ + int m_MaxSize; + + /** Minimum density - percentage of allowed house connections. Range [0, 100] */ + int m_MinDensity; + + /** Maximum density - percentage of allowed house connections. Range [0, 100] */ + int m_MaxDensity; + + /** The underlying biome generator that defines whether the village is created or not */ + cBiomeGen & m_BiomeGen; + + /** The underlying height generator, used to position the prefabs crossing chunk borders */ + cTerrainHeightGen & m_HeightGen; + + + // cGridStructGen overrides: + virtual cStructurePtr CreateStructure(int a_OriginX, int a_OriginZ) override; +} ; + + + + diff --git a/src/Globals.h b/src/Globals.h index a1cee5c2f..c5768facf 100644 --- a/src/Globals.h +++ b/src/Globals.h @@ -29,6 +29,9 @@ // Disabling this warning, because we know what we're doing when we're doing this: #pragma warning(disable: 4355) // 'this' used in initializer list + + // Disabled because it's useless: + #pragma warning(disable: 4512) // 'class': assignment operator could not be generated - reported for each class that has a reference-type member // 2014_01_06 xoft: Disabled this warning because MSVC is stupid and reports it in obviously wrong places // #pragma warning(3 : 4244) // Conversion from 'type1' to 'type2', possible loss of data @@ -222,16 +225,28 @@ template class SizeChecker<UInt16, 2>; +#ifndef TEST_GLOBALS + // Common headers (part 1, without macros): + #include "StringUtils.h" + #include "OSSupport/Sleep.h" + #include "OSSupport/CriticalSection.h" + #include "OSSupport/Semaphore.h" + #include "OSSupport/Event.h" + #include "OSSupport/Thread.h" + #include "OSSupport/File.h" + #include "MCLogger.h" +#else + // Logging functions +void inline LOGERROR(const char* a_Format, ...) FORMATSTRING(1,2); -// Common headers (part 1, without macros): -#include "StringUtils.h" -#include "OSSupport/Sleep.h" -#include "OSSupport/CriticalSection.h" -#include "OSSupport/Semaphore.h" -#include "OSSupport/Event.h" -#include "OSSupport/Thread.h" -#include "OSSupport/File.h" -#include "MCLogger.h" +void inline LOGERROR(const char* a_Format, ...) +{ + va_list argList; + va_start(argList, a_Format); + vprintf(a_Format, argList); + va_end(argList); +} +#endif @@ -250,10 +265,44 @@ template class SizeChecker<UInt16, 2>; #define FAST_FLOOR_DIV( x, div ) (((x) - (((x) < 0) ? ((div) - 1) : 0)) / (div)) // Own version of assert() that writes failed assertions to the log for review -#ifdef _DEBUG - #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) ) +#ifdef TEST_GLOBALS + + class cAssertFailure + { + }; + + #ifdef _WIN32 + #if (defined(_MSC_VER) && defined(_DEBUG)) + #define DBG_BREAK _CrtDbgBreak() + #else + #define DBG_BREAK + #endif + #define REPORT_ERROR(FMT, ...) \ + { \ + AString msg = Printf(FMT, __VA_ARGS__); \ + puts(msg.c_str()); \ + fflush(stdout); \ + OutputDebugStringA(msg.c_str()); \ + DBG_BREAK; \ + } + #else + #define REPORT_ERROR(FMT, ...) \ + { \ + AString msg = Printf(FMT, __VA_ARGS__); \ + puts(msg.c_str()); \ + fflush(stdout); \ + } + #endif + #define ASSERT(x) do { if (!(x)) { throw cAssertFailure();} } while (0) + #define testassert(x) do { if(!(x)) { REPORT_ERROR("Test failure: %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } } while (0) + #define CheckAsserts(x) do { try {x} catch (cAssertFailure) { break; } REPORT_ERROR("Test failure: assert didn't fire for %s, file %s, line %d\n", #x, __FILE__, __LINE__); exit(1); } while (0) + #else - #define ASSERT(x) ((void)(x)) + #ifdef _DEBUG + #define ASSERT( x ) ( !!(x) || ( LOGERROR("Assertion failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), assert(0), 0 ) ) + #else + #define ASSERT(x) ((void)(x)) + #endif #endif // Pretty much the same as ASSERT() but stays in Release builds @@ -261,7 +310,21 @@ template class SizeChecker<UInt16, 2>; // Same as assert but in all Self test builds #ifdef SELF_TEST -#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0)) + #define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0)) +#endif + +// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr: +// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed. +#if (defined(_MSC_VER) && (_MSC_VER < 1600)) + // MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier + #define SharedPtr std::tr1::shared_ptr +#elif (defined(_MSC_VER) || (__cplusplus >= 201103L)) + // C++11 has std::shared_ptr in <memory>, included earlier + #define SharedPtr std::shared_ptr +#else + // C++03 has std::tr1::shared_ptr in <tr1/memory> + #include <tr1/memory> + #define SharedPtr std::tr1::shared_ptr #endif @@ -293,7 +356,7 @@ T Clamp(T a_Value, T a_Min, T a_Max) #ifndef TOLUA_TEMPLATE_BIND -#define TOLUA_TEMPLATE_BIND(x) + #define TOLUA_TEMPLATE_BIND(x) #endif diff --git a/src/Group.cpp b/src/Group.cpp index 5f1f25782..725740905 100644 --- a/src/Group.cpp +++ b/src/Group.cpp @@ -7,7 +7,7 @@ -void cGroup::AddCommand( AString a_Command ) +void cGroup::AddCommand( const AString & a_Command ) { m_Commands[ a_Command ] = true; } @@ -16,7 +16,7 @@ void cGroup::AddCommand( AString a_Command ) -void cGroup::AddPermission( AString a_Permission ) +void cGroup::AddPermission( const AString & a_Permission ) { m_Permissions[ a_Permission ] = true; } @@ -38,4 +38,4 @@ void cGroup::InheritFrom( cGroup* a_Group ) void cGroup::ClearPermission() { m_Permissions.clear(); -}
\ No newline at end of file +} diff --git a/src/Group.h b/src/Group.h index 8bee6f7ed..47088d50d 100644 --- a/src/Group.h +++ b/src/Group.h @@ -11,11 +11,11 @@ public: // tolua_export cGroup() {} ~cGroup() {} - void SetName( AString a_Name ) { m_Name = a_Name; } // tolua_export + void SetName( const AString & a_Name ) { m_Name = a_Name; } // tolua_export const AString & GetName() const { return m_Name; } // tolua_export - void SetColor( AString a_Color ) { m_Color = a_Color; } // tolua_export - void AddCommand( AString a_Command ); // tolua_export - void AddPermission( AString a_Permission ); // tolua_export + void SetColor( const AString & a_Color ) { m_Color = a_Color; } // tolua_export + void AddCommand( const AString & a_Command ); // tolua_export + void AddPermission( const AString & a_Permission ); // tolua_export void InheritFrom( cGroup* a_Group ); // tolua_export typedef std::map< AString, bool > PermissionMap; diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index 33b601e82..523697b07 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -45,8 +45,14 @@ cGroupManager::cGroupManager() { LOGD("-- Loading Groups --"); - LoadGroups(); - CheckUsers(); + if (!LoadGroups()) + { + LOGWARNING("ERROR: Groups could not load!"); + } + if (!CheckUsers()) + { + LOGWARNING("ERROR: User file could not be found!"); + } LOGD("-- Groups Successfully Loaded --"); } @@ -70,39 +76,42 @@ void cGroupManager::GenerateDefaultUsersIni(cIniFile & a_IniFile) -void cGroupManager::CheckUsers(void) +bool cGroupManager::CheckUsers() { cIniFile IniFile; if (!IniFile.ReadFile("users.ini")) { GenerateDefaultUsersIni(IniFile); - return; + return true; } - unsigned int NumKeys = IniFile.GetNumKeys(); - for (size_t i = 0; i < NumKeys; i++) + int NumKeys = IniFile.GetNumKeys(); + for (int i = 0; i < NumKeys; i++) { - AString Player = IniFile.GetKeyName( i ); + AString Player = IniFile.GetKeyName(i); AString Groups = IniFile.GetValue(Player, "Groups", ""); - if (!Groups.empty()) + if (Groups.empty()) { - AStringVector Split = StringSplit( Groups, "," ); - for( unsigned int i = 0; i < Split.size(); i++ ) + continue; + } + AStringVector Split = StringSplitAndTrim(Groups, ","); + for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr) + { + if (!ExistsGroup(*itr)) { - if (!ExistsGroup(Split[i])) - { - LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str()); - } + LOGWARNING("The group %s for player %s was not found!", Split[i].c_str(), Player.c_str()); } - } - } + } // for itr - Split[] + } // for i - ini file keys + // Always return true for now, just but we can handle writefile fails later. + return true; } -void cGroupManager::LoadGroups() +bool cGroupManager::LoadGroups() { cIniFile IniFile; if (!IniFile.ReadFile("groups.ini")) @@ -128,15 +137,15 @@ void cGroupManager::LoadGroups() IniFile.WriteFile("groups.ini"); } - unsigned int NumKeys = IniFile.GetNumKeys(); - for (size_t i = 0; i < NumKeys; i++) + int NumKeys = IniFile.GetNumKeys(); + for (int i = 0; i < NumKeys; i++) { - AString KeyName = IniFile.GetKeyName( i ); - cGroup* Group = GetGroup( KeyName.c_str() ); + AString KeyName = IniFile.GetKeyName(i); + cGroup * Group = GetGroup(KeyName.c_str()); Group->ClearPermission(); // Needed in case the groups are reloaded. - LOGD("Loading group: %s", KeyName.c_str() ); + LOGD("Loading group %s", KeyName.c_str()); Group->SetName(KeyName); AString Color = IniFile.GetValue(KeyName, "Color", "-"); @@ -179,6 +188,8 @@ void cGroupManager::LoadGroups() } } } + // Always return true, we can handle writefile fails later. + return true; } diff --git a/src/GroupManager.h b/src/GroupManager.h index 9e1689a76..d42b55c4a 100644 --- a/src/GroupManager.h +++ b/src/GroupManager.h @@ -16,8 +16,8 @@ class cGroupManager public: bool ExistsGroup(const AString & a_Name); cGroup * GetGroup(const AString & a_Name); - void LoadGroups(void); - void CheckUsers(void); + bool LoadGroups(); + bool CheckUsers(); /** Writes the default header to the specified ini file, and saves it as "users.ini". */ static void GenerateDefaultUsersIni(cIniFile & a_IniFile); diff --git a/src/HTTPServer/CMakeLists.txt b/src/HTTPServer/CMakeLists.txt index 3badc669f..dc894368d 100644 --- a/src/HTTPServer/CMakeLists.txt +++ b/src/HTTPServer/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(HTTPServer ${SOURCE}) diff --git a/src/HTTPServer/EnvelopeParser.cpp b/src/HTTPServer/EnvelopeParser.cpp index 8dbe05f14..fd4f3836d 100644 --- a/src/HTTPServer/EnvelopeParser.cpp +++ b/src/HTTPServer/EnvelopeParser.cpp @@ -20,7 +20,7 @@ cEnvelopeParser::cEnvelopeParser(cCallbacks & a_Callbacks) : -int cEnvelopeParser::Parse(const char * a_Data, int a_Size) +size_t cEnvelopeParser::Parse(const char * a_Data, size_t a_Size) { if (!m_IsInHeaders) { @@ -55,7 +55,7 @@ int cEnvelopeParser::Parse(const char * a_Data, int a_Size) { // An error has occurred m_IsInHeaders = false; - return -1; + return AString::npos; } Last = idxCRLF + 2; idxCRLF = m_IncomingData.find("\r\n", idxCRLF + 2); diff --git a/src/HTTPServer/EnvelopeParser.h b/src/HTTPServer/EnvelopeParser.h index 6430fbebf..e96d80abe 100644 --- a/src/HTTPServer/EnvelopeParser.h +++ b/src/HTTPServer/EnvelopeParser.h @@ -19,7 +19,10 @@ public: class cCallbacks { public: - /// Called when a full header line is parsed + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + + /** Called when a full header line is parsed */ virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) = 0; } ; @@ -27,40 +30,41 @@ public: cEnvelopeParser(cCallbacks & a_Callbacks); /** Parses the incoming data. - Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header + Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header. + Returns AString::npos on error */ - int Parse(const char * a_Data, int a_Size); + size_t Parse(const char * a_Data, size_t a_Size); - /// Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream + /** Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream */ void Reset(void); - /// Returns true if more input is expected for the envelope header + /** Returns true if more input is expected for the envelope header */ bool IsInHeaders(void) const { return m_IsInHeaders; } - /// Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions + /** Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions */ void SetIsInHeaders(bool a_IsInHeaders) { m_IsInHeaders = a_IsInHeaders; } public: - /// Callbacks to call for the various events + /** Callbacks to call for the various events */ cCallbacks & m_Callbacks; - /// Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data. + /** Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data. */ bool m_IsInHeaders; - /// Buffer for the incoming data until it is parsed + /** Buffer for the incoming data until it is parsed */ AString m_IncomingData; - /// Holds the last parsed key; used for line-wrapped values + /** Holds the last parsed key; used for line-wrapped values */ AString m_LastKey; - /// Holds the last parsed value; used for line-wrapped values + /** Holds the last parsed value; used for line-wrapped values */ AString m_LastValue; - /// Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them + /** Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them */ void NotifyLast(void); - /// Parses one line of header data. Returns true if successful + /** Parses one line of header data. Returns true if successful */ bool ParseLine(const char * a_Data, size_t a_Size); } ; diff --git a/src/HTTPServer/HTTPConnection.cpp b/src/HTTPServer/HTTPConnection.cpp index 78b7ce4d9..b127e7091 100644 --- a/src/HTTPServer/HTTPConnection.cpp +++ b/src/HTTPServer/HTTPConnection.cpp @@ -26,6 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : cHTTPConnection::~cHTTPConnection() { + // LOGD("HTTP: Connection deleting: %p", this); delete m_CurrentRequest; } @@ -67,10 +68,10 @@ void cHTTPConnection::Send(const cHTTPResponse & a_Response) -void cHTTPConnection::Send(const void * a_Data, int a_Size) +void cHTTPConnection::Send(const void * a_Data, size_t a_Size) { ASSERT(m_State == wcsSendingResp); - AppendPrintf(m_OutgoingData, "%x\r\n", a_Size); + AppendPrintf(m_OutgoingData, SIZE_T_FMT_HEX "\r\n", a_Size); m_OutgoingData.append((const char *)a_Data, a_Size); m_OutgoingData.append("\r\n"); m_HTTPServer.NotifyConnectionWrite(*this); @@ -144,7 +145,7 @@ void cHTTPConnection::Terminate(void) -void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) +bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) { switch (m_State) { @@ -155,26 +156,26 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) m_CurrentRequest = new cHTTPRequest; } - int BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size); - if (BytesConsumed < 0) + size_t BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size); + if (BytesConsumed == AString::npos) { delete m_CurrentRequest; m_CurrentRequest = NULL; m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); - return; + return true; } if (m_CurrentRequest->IsInHeaders()) { // The request headers are not yet complete - return; + return false; } // The request has finished parsing its headers successfully, notify of it: m_State = wcsRecvBody; m_HTTPServer.NewRequest(*this, *m_CurrentRequest); m_CurrentRequestBodyRemaining = m_CurrentRequest->GetContentLength(); - if (m_CurrentRequestBodyRemaining < 0) + if (m_CurrentRequestBodyRemaining == AString::npos) { // The body length was not specified in the request, assume zero m_CurrentRequestBodyRemaining = 0; @@ -183,13 +184,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) // Process the rest of the incoming data into the request body: if (a_Size > BytesConsumed) { - DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); + return cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed); } else { - DataReceived("", 0); // If the request has zero body length, let it be processed right-away + return cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away } - break; } case wcsRecvBody: @@ -197,7 +197,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) ASSERT(m_CurrentRequest != NULL); if (m_CurrentRequestBodyRemaining > 0) { - int BytesToConsume = std::min(m_CurrentRequestBodyRemaining, a_Size); + size_t BytesToConsume = std::min(m_CurrentRequestBodyRemaining, (size_t)a_Size); m_HTTPServer.RequestBody(*this, *m_CurrentRequest, a_Data, BytesToConsume); m_CurrentRequestBodyRemaining -= BytesToConsume; } @@ -209,7 +209,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) { m_State = wcsInvalid; m_HTTPServer.CloseConnection(*this); - return; + return true; } delete m_CurrentRequest; m_CurrentRequest = NULL; @@ -223,6 +223,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) break; } } + return false; } diff --git a/src/HTTPServer/HTTPConnection.h b/src/HTTPServer/HTTPConnection.h index 5b8103554..6ea8a1ae8 100644 --- a/src/HTTPServer/HTTPConnection.h +++ b/src/HTTPServer/HTTPConnection.h @@ -51,7 +51,7 @@ public: void Send(const cHTTPResponse & a_Response); /** Sends the data as the response (may be called multiple times) */ - void Send(const void * a_Data, int a_Size); + void Send(const void * a_Data, size_t a_Size); /** Sends the data as the response (may be called multiple times) */ void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); } @@ -87,13 +87,19 @@ protected: /** Number of bytes that remain to read for the complete body of the message to be received. Valid only in wcsRecvBody */ - int m_CurrentRequestBodyRemaining; + size_t m_CurrentRequestBodyRemaining; // cSocketThreads::cCallback overrides: - virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client - virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client - virtual void SocketClosed (void) override; // The socket has been closed for any reason + /** Data is received from the client. + Returns true if the connection has been closed as the result of parsing the data. */ + virtual bool DataReceived(const char * a_Data, size_t a_Size) override; + + /** Data can be sent to client */ + virtual void GetOutgoingData(AString & a_Data) override; + + /** The socket has been closed for any reason */ + virtual void SocketClosed(void) override; } ; typedef std::vector<cHTTPConnection *> cHTTPConnections; diff --git a/src/HTTPServer/HTTPFormParser.cpp b/src/HTTPServer/HTTPFormParser.cpp index e661ea6f9..9ddfb82f1 100644 --- a/src/HTTPServer/HTTPFormParser.cpp +++ b/src/HTTPServer/HTTPFormParser.cpp @@ -52,7 +52,7 @@ cHTTPFormParser::cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callba -cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks) : +cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks) : m_Callbacks(a_Callbacks), m_Kind(a_Kind), m_IsValid(true) @@ -64,7 +64,7 @@ cHTTPFormParser::cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, -void cHTTPFormParser::Parse(const char * a_Data, int a_Size) +void cHTTPFormParser::Parse(const char * a_Data, size_t a_Size) { if (!m_IsValid) { @@ -243,7 +243,7 @@ void cHTTPFormParser::OnPartHeader(const AString & a_Key, const AString & a_Valu -void cHTTPFormParser::OnPartData(const char * a_Data, int a_Size) +void cHTTPFormParser::OnPartData(const char * a_Data, size_t a_Size) { if (m_CurrentPartName.empty()) { diff --git a/src/HTTPServer/HTTPFormParser.h b/src/HTTPServer/HTTPFormParser.h index a554ca5a4..edc6d2471 100644 --- a/src/HTTPServer/HTTPFormParser.h +++ b/src/HTTPServer/HTTPFormParser.h @@ -36,11 +36,14 @@ public: class cCallbacks { public: + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + /// Called when a new file part is encountered in the form data virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) = 0; /// Called when more file data has come for the current file in the form data - virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) = 0; + virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) = 0; /// Called when the current file part has ended in the form data virtual void OnFileEnd(cHTTPFormParser & a_Parser) = 0; @@ -51,10 +54,10 @@ public: cHTTPFormParser(cHTTPRequest & a_Request, cCallbacks & a_Callbacks); /// Creates a parser with the specified content type that reads data from a string - cHTTPFormParser(eKind a_Kind, const char * a_Data, int a_Size, cCallbacks & a_Callbacks); + cHTTPFormParser(eKind a_Kind, const char * a_Data, size_t a_Size, cCallbacks & a_Callbacks); /// Adds more data into the parser, as the request body is received - void Parse(const char * a_Data, int a_Size); + void Parse(const char * a_Data, size_t a_Size); /** Notifies that there's no more data incoming and the parser should finish its parsing. Returns true if parsing successful @@ -103,7 +106,7 @@ protected: // cMultipartParser::cCallbacks overrides: virtual void OnPartStart (void) override; virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) override; - virtual void OnPartData (const char * a_Data, int a_Size) override; + virtual void OnPartData (const char * a_Data, size_t a_Size) override; virtual void OnPartEnd (void) override; } ; diff --git a/src/HTTPServer/HTTPMessage.cpp b/src/HTTPServer/HTTPMessage.cpp index 98627eb8e..44feda469 100644 --- a/src/HTTPServer/HTTPMessage.cpp +++ b/src/HTTPServer/HTTPMessage.cpp @@ -25,7 +25,7 @@ cHTTPMessage::cHTTPMessage(eKind a_Kind) : m_Kind(a_Kind), - m_ContentLength(-1) + m_ContentLength(AString::npos) { } @@ -81,23 +81,23 @@ cHTTPRequest::cHTTPRequest(void) : -int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size) +size_t cHTTPRequest::ParseHeaders(const char * a_Data, size_t a_Size) { if (!m_IsValid) { - return -1; + return AString::npos; } if (m_Method.empty()) { // The first line hasn't been processed yet - int res = ParseRequestLine(a_Data, a_Size); - if ((res < 0) || (res == a_Size)) + size_t res = ParseRequestLine(a_Data, a_Size); + if ((res == AString::npos) || (res == a_Size)) { return res; } - int res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res); - if (res2 < 0) + size_t res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res); + if (res2 == AString::npos) { m_IsValid = false; return res2; @@ -107,8 +107,8 @@ int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size) if (m_EnvelopeParser.IsInHeaders()) { - int res = m_EnvelopeParser.Parse(a_Data, a_Size); - if (res < 0) + size_t res = m_EnvelopeParser.Parse(a_Data, a_Size); + if (res == AString::npos) { m_IsValid = false; } @@ -138,7 +138,7 @@ AString cHTTPRequest::GetBareURL(void) const -int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size) +size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size) { m_IncomingHeaderData.append(a_Data, a_Size); size_t IdxEnd = m_IncomingHeaderData.size(); @@ -158,7 +158,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size) if (LineStart >= IdxEnd) { m_IsValid = false; - return -1; + return AString::npos; } int NumSpaces = 0; @@ -186,7 +186,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size) { // Too many spaces in the request m_IsValid = false; - return -1; + return AString::npos; } } NumSpaces += 1; @@ -198,13 +198,13 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size) { // LF too early, without a CR, without two preceeding spaces or too soon after the second space m_IsValid = false; - return -1; + return AString::npos; } // Check that there's HTTP/version at the end - if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0) + if (strncmp(m_IncomingHeaderData.c_str() + URLEnd + 1, "HTTP/1.", 7) != 0) { m_IsValid = false; - return -1; + return AString::npos; } m_Method = m_IncomingHeaderData.substr(LineStart, MethodEnd - LineStart); m_URL = m_IncomingHeaderData.substr(MethodEnd + 1, URLEnd - MethodEnd - 1); diff --git a/src/HTTPServer/HTTPMessage.h b/src/HTTPServer/HTTPMessage.h index ab3338db7..dab942136 100644 --- a/src/HTTPServer/HTTPMessage.h +++ b/src/HTTPServer/HTTPMessage.h @@ -39,10 +39,10 @@ public: void AddHeader(const AString & a_Key, const AString & a_Value); void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; } - void SetContentLength(int a_ContentLength) { m_ContentLength = a_ContentLength; } + void SetContentLength(size_t a_ContentLength) { m_ContentLength = a_ContentLength; } const AString & GetContentType (void) const { return m_ContentType; } - int GetContentLength(void) const { return m_ContentLength; } + size_t GetContentLength(void) const { return m_ContentLength; } protected: typedef std::map<AString, AString> cNameValueMap; @@ -54,8 +54,10 @@ protected: /** Type of the content; parsed by AddHeader(), set directly by SetContentLength() */ AString m_ContentType; - /** Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() */ - int m_ContentLength; + /** Length of the content that is to be received. + AString::npos when the object is created. + Parsed by AddHeader() or set directly by SetContentLength() */ + size_t m_ContentLength; } ; @@ -72,12 +74,12 @@ public: cHTTPRequest(void); /** Parses the request line and then headers from the received data. - Returns the number of bytes consumed or a negative number for error + Returns the number of bytes consumed or AString::npos number for error */ - int ParseHeaders(const char * a_Data, int a_Size); + size_t ParseHeaders(const char * a_Data, size_t a_Size); /** Returns true if the request did contain a Content-Length header */ - bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } + bool HasReceivedContentLength(void) const { return (m_ContentLength != AString::npos); } /** Returns the method used in the request */ const AString & GetMethod(void) const { return m_Method; } @@ -145,7 +147,7 @@ protected: /** Parses the incoming data for the first line (RequestLine) Returns the number of bytes consumed, or -1 for an error */ - int ParseRequestLine(const char * a_Data, int a_Size); + size_t ParseRequestLine(const char * a_Data, size_t a_Size); // cEnvelopeParser::cCallbacks overrides: virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override; diff --git a/src/HTTPServer/HTTPServer.cpp b/src/HTTPServer/HTTPServer.cpp index 4e9195a00..d288c83c9 100644 --- a/src/HTTPServer/HTTPServer.cpp +++ b/src/HTTPServer/HTTPServer.cpp @@ -8,6 +8,7 @@ #include "HTTPMessage.h" #include "HTTPConnection.h" #include "HTTPFormParser.h" +#include "SslHTTPConnection.h" @@ -38,7 +39,7 @@ class cDebugCallbacks : } - virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override + virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override { UNUSED(a_Connection); @@ -100,7 +101,7 @@ class cDebugCallbacks : } - virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override + virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) override { // TODO } @@ -142,6 +143,41 @@ cHTTPServer::~cHTTPServer() bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6) { + // Read the HTTPS cert + key: + AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt"); + AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem"); + if (!CertFile.empty() && !KeyFile.empty()) + { + m_Cert.reset(new cX509Cert); + int res = m_Cert->Parse(CertFile.data(), CertFile.size()); + if (res == 0) + { + m_CertPrivKey.reset(new cCryptoKey); + int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), ""); + if (res2 != 0) + { + // Reading the private key failed, reset the cert: + LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2); + m_Cert.reset(); + } + } + else + { + LOGWARNING("WebServer: Cannot read HTTPS certificate: -0x%x", -res); + } + } + + // Notify the admin about the HTTPS / HTTP status + if (m_Cert.get() == NULL) + { + LOGWARNING("WebServer: The server is running in unsecure HTTP mode."); + } + else + { + LOGINFO("WebServer: The server is running in secure HTTPS mode."); + } + + // Open up requested ports: bool HasAnyPort; HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4); HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort; @@ -195,7 +231,15 @@ void cHTTPServer::Stop(void) void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket) { - cHTTPConnection * Connection = new cHTTPConnection(*this); + cHTTPConnection * Connection; + if (m_Cert.get() != NULL) + { + Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey); + } + else + { + Connection = new cHTTPConnection(*this); + } m_SocketThreads.AddClient(a_Socket, Connection); cCSLock Lock(m_CSConnections); m_Connections.push_back(Connection); @@ -242,7 +286,7 @@ void cHTTPServer::NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Re -void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) +void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) { m_Callbacks->OnRequestBody(a_Connection, a_Request, a_Data, a_Size); } diff --git a/src/HTTPServer/HTTPServer.h b/src/HTTPServer/HTTPServer.h index 383abb4b6..522b7da62 100644 --- a/src/HTTPServer/HTTPServer.h +++ b/src/HTTPServer/HTTPServer.h @@ -12,6 +12,9 @@ #include "../OSSupport/ListenThread.h" #include "../OSSupport/SocketThreads.h" #include "inifile/iniFile.h" +#include "PolarSSL++/RsaPrivateKey.h" +#include "PolarSSL++/CryptoKey.h" +#include "PolarSSL++/X509Cert.h" @@ -44,8 +47,9 @@ public: */ virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0; - /// Called when another part of request body has arrived. - virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) = 0; + /** Called when another part of request body has arrived. + May be called multiple times for a single request. */ + virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) = 0; /// Called when the request body has been fully received in previous calls to OnRequestBody() virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0; @@ -65,6 +69,7 @@ public: protected: friend class cHTTPConnection; + friend class cSslHTTPConnection; cListenThread m_ListenThreadIPv4; cListenThread m_ListenThreadIPv6; @@ -77,6 +82,12 @@ protected: /// The callbacks to call for various events cCallbacks * m_Callbacks; + /** The server certificate to use for the SSL connections */ + cX509CertPtr m_Cert; + + /** The private key for m_Cert. */ + cCryptoKeyPtr m_CertPrivKey; + // cListenThread::cCallback overrides: virtual void OnConnectionAccepted(cSocket & a_Socket) override; @@ -90,8 +101,9 @@ protected: /// Called by cHTTPConnection when it finishes parsing the request header void NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request); - /// Called by cHTTPConenction when it receives more data for the request body - void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size); + /** Called by cHTTPConenction when it receives more data for the request body. + May be called multiple times for a single request. */ + void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size); /// Called by cHTTPConnection when it detects that the request has finished (all of its body has been received) void RequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request); diff --git a/src/HTTPServer/MultipartParser.cpp b/src/HTTPServer/MultipartParser.cpp index 14c2c00fa..309495dd7 100644 --- a/src/HTTPServer/MultipartParser.cpp +++ b/src/HTTPServer/MultipartParser.cpp @@ -97,8 +97,6 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a m_EnvelopeParser(*this), m_HasHadData(false) { - static AString s_Multipart = "multipart/"; - // Check that the content type is multipart: AString ContentType(a_ContentType); if (strncmp(ContentType.c_str(), "multipart/", 10) != 0) @@ -146,7 +144,7 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a -void cMultipartParser::Parse(const char * a_Data, int a_Size) +void cMultipartParser::Parse(const char * a_Data, size_t a_Size) { // Skip parsing if invalid if (!m_IsValid) @@ -160,8 +158,8 @@ void cMultipartParser::Parse(const char * a_Data, int a_Size) { if (m_EnvelopeParser.IsInHeaders()) { - int BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size()); - if (BytesConsumed < 0) + size_t BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size()); + if (BytesConsumed == AString::npos) { m_IsValid = false; return; diff --git a/src/HTTPServer/MultipartParser.h b/src/HTTPServer/MultipartParser.h index d853929ed..ad76ad650 100644 --- a/src/HTTPServer/MultipartParser.h +++ b/src/HTTPServer/MultipartParser.h @@ -22,50 +22,53 @@ public: class cCallbacks { public: - /// Called when a new part starts + // Force a virtual destructor in descendants: + virtual ~cCallbacks() {} + + /** Called when a new part starts */ virtual void OnPartStart(void) = 0; - /// Called when a complete header line is received for a part + /** Called when a complete header line is received for a part */ virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) = 0; - /// Called when body for a part is received - virtual void OnPartData(const char * a_Data, int a_Size) = 0; + /** Called when body for a part is received */ + virtual void OnPartData(const char * a_Data, size_t a_Size) = 0; - /// Called when the current part ends + /** Called when the current part ends */ virtual void OnPartEnd(void) = 0; } ; - /// Creates the parser, expects to find the boundary in a_ContentType + /** Creates the parser, expects to find the boundary in a_ContentType */ cMultipartParser(const AString & a_ContentType, cCallbacks & a_Callbacks); - /// Parses more incoming data - void Parse(const char * a_Data, int a_Size); + /** Parses more incoming data */ + void Parse(const char * a_Data, size_t a_Size); protected: - /// The callbacks to call for various parsing events + /** The callbacks to call for various parsing events */ cCallbacks & m_Callbacks; - /// True if the data parsed so far is valid; if false, further parsing is skipped + /** True if the data parsed so far is valid; if false, further parsing is skipped */ bool m_IsValid; - /// Parser for each part's envelope + /** Parser for each part's envelope */ cEnvelopeParser m_EnvelopeParser; - /// Buffer for the incoming data until it is parsed + /** Buffer for the incoming data until it is parsed */ AString m_IncomingData; - /// The boundary, excluding both the initial "--" and the terminating CRLF + /** The boundary, excluding both the initial "--" and the terminating CRLF */ AString m_Boundary; - /// Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting. + /** Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting. */ bool m_HasHadData; - /// Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size - void ParseLine(const char * a_Data, int a_Size); + /** Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size */ + void ParseLine(const char * a_Data, size_t a_Size); - /// Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size - void ParseHeaderLine(const char * a_Data, int a_Size); + /** Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size */ + void ParseHeaderLine(const char * a_Data, size_t a_Size); // cEnvelopeParser overrides: virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override; diff --git a/src/HTTPServer/NameValueParser.cpp b/src/HTTPServer/NameValueParser.cpp index 9ea8594ae..f16ea1915 100644 --- a/src/HTTPServer/NameValueParser.cpp +++ b/src/HTTPServer/NameValueParser.cpp @@ -24,7 +24,7 @@ public: // Now try parsing char-by-char, to debug transitions across datachunk boundaries: cNameValueParser Parser2; - for (int i = 0; i < sizeof(Data) - 1; i++) + for (size_t i = 0; i < sizeof(Data) - 1; i++) { Parser2.Parse(Data + i, 1); } @@ -82,7 +82,7 @@ cNameValueParser::cNameValueParser(bool a_AllowsKeyOnly) : -cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly) : +cNameValueParser::cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly) : m_State(psKeySpace), m_AllowsKeyOnly(a_AllowsKeyOnly) { @@ -93,12 +93,12 @@ cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_Allow -void cNameValueParser::Parse(const char * a_Data, int a_Size) +void cNameValueParser::Parse(const char * a_Data, size_t a_Size) { ASSERT(m_State != psFinished); // Calling Parse() after Finish() is wrong! - int Last = 0; - for (int i = 0; i < a_Size;) + size_t Last = 0; + for (size_t i = 0; i < a_Size;) { switch (m_State) { diff --git a/src/HTTPServer/NameValueParser.h b/src/HTTPServer/NameValueParser.h index 07dc0b942..9794614fa 100644 --- a/src/HTTPServer/NameValueParser.h +++ b/src/HTTPServer/NameValueParser.h @@ -21,10 +21,10 @@ public: cNameValueParser(bool a_AllowsKeyOnly = true); /// Creates an empty parser, then parses the data given. Doesn't call Finish(), so more data can be parsed later - cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly = true); + cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly = true); /// Parses the data given - void Parse(const char * a_Data, int a_Size); + void Parse(const char * a_Data, size_t a_Size); /// Notifies the parser that no more data will be coming. Returns true if the parser state is valid bool Finish(void); diff --git a/src/HTTPServer/SslHTTPConnection.cpp b/src/HTTPServer/SslHTTPConnection.cpp new file mode 100644 index 000000000..d237089d9 --- /dev/null +++ b/src/HTTPServer/SslHTTPConnection.cpp @@ -0,0 +1,107 @@ + +// SslHTTPConnection.cpp + +// Implements the cSslHTTPConnection class representing a HTTP connection made over a SSL link + +#include "Globals.h" +#include "SslHTTPConnection.h" +#include "HTTPServer.h" + + + + + +cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) : + super(a_HTTPServer), + m_Ssl(64000), + m_Cert(a_Cert), + m_PrivateKey(a_PrivateKey) +{ + m_Ssl.Initialize(false); + m_Ssl.SetOwnCert(a_Cert, a_PrivateKey); +} + + + + + +bool cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size) +{ + // If there is outgoing data in the queue, notify the server that it should write it out: + if (!m_OutgoingData.empty()) + { + m_HTTPServer.NotifyConnectionWrite(*this); + } + + // Process the received data: + const char * Data = a_Data; + size_t Size = a_Size; + for (;;) + { + // Try to write as many bytes into Ssl's "incoming" buffer as possible: + size_t BytesWritten = 0; + if (Size > 0) + { + BytesWritten = m_Ssl.WriteIncoming(Data, Size); + Data += BytesWritten; + Size -= BytesWritten; + } + + // Try to read as many bytes from SSL's decryption as possible: + char Buffer[32000]; + int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer)); + if (NumRead > 0) + { + if (super::DataReceived(Buffer, (size_t)NumRead)) + { + // The socket has been closed, and the object is already deleted. Bail out. + return true; + } + } + + // If both failed, bail out: + if ((BytesWritten == 0) && (NumRead <= 0)) + { + return false; + } + } +} + + + + + +void cSslHTTPConnection::GetOutgoingData(AString & a_Data) +{ + for (;;) + { + // Write as many bytes from our buffer to SSL's encryption as possible: + int NumWritten = 0; + if (!m_OutgoingData.empty()) + { + NumWritten = m_Ssl.WritePlain(m_OutgoingData.data(), m_OutgoingData.size()); + if (NumWritten > 0) + { + m_OutgoingData.erase(0, (size_t)NumWritten); + } + } + + // Read as many bytes from SSL's "outgoing" buffer as possible: + char Buffer[32000]; + size_t NumBytes = m_Ssl.ReadOutgoing(Buffer, sizeof(Buffer)); + if (NumBytes > 0) + { + a_Data.append(Buffer, NumBytes); + } + + // If both failed, bail out: + if ((NumWritten <= 0) && (NumBytes == 0)) + { + return; + } + } +} + + + + diff --git a/src/HTTPServer/SslHTTPConnection.h b/src/HTTPServer/SslHTTPConnection.h new file mode 100644 index 000000000..c2c1585cd --- /dev/null +++ b/src/HTTPServer/SslHTTPConnection.h @@ -0,0 +1,45 @@ + +// SslHTTPConnection.h + +// Declared the cSslHTTPConnection class representing a HTTP connection made over a SSL link + + + + + +#pragma once + +#include "HTTPConnection.h" +#include "PolarSSL++/BufferedSslContext.h" + + + + + +class cSslHTTPConnection : + public cHTTPConnection +{ + typedef cHTTPConnection super; + +public: + /** Creates a new connection on the specified server. + Sends the specified cert as the server certificate, uses the private key for decryption. */ + cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey); + +protected: + cBufferedSslContext m_Ssl; + + /** The certificate to send to the client */ + cX509CertPtr m_Cert; + + /** The private key used for the certificate */ + cCryptoKeyPtr m_PrivateKey; + + // cHTTPConnection overrides: + virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client + virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client +} ; + + + + diff --git a/src/Inventory.cpp b/src/Inventory.cpp index c7c089d5f..bce882c88 100644 --- a/src/Inventory.cpp +++ b/src/Inventory.cpp @@ -243,6 +243,16 @@ void cInventory::SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item) +void cInventory::SendEquippedSlot() +{ + int EquippedSlotNum = cInventory::invArmorCount + cInventory::invInventoryCount + GetEquippedSlotNum(); + SendSlot(EquippedSlotNum); +} + + + + + const cItem & cInventory::GetSlot(int a_SlotNum) const { if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots)) @@ -376,6 +386,7 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount) if (!Grid->DamageItem(GridSlotNum, a_Amount)) { // The item has been damaged, but did not break yet + SendSlot(a_SlotNum); return false; } diff --git a/src/Inventory.h b/src/Inventory.h index 1ad7c4776..39aef1538 100644 --- a/src/Inventory.h +++ b/src/Inventory.h @@ -56,13 +56,13 @@ public: // tolua_begin - /// Removes all items from the entire inventory + /** Removes all items from the entire inventory */ void Clear(void); - /// Returns number of items out of a_ItemStack that can fit in the storage + /** Returns number of items out of a_ItemStack that can fit in the storage */ int HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlots); - /// Returns how many items of the specified type would fit into the slot range specified + /** Returns how many items of the specified type would fit into the slot range specified */ int HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots); /** Adds as many items out of a_ItemStack as can fit. @@ -86,33 +86,36 @@ public: */ int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst); - /// Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed + /** Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed */ bool RemoveOneEquippedItem(void); - /// Returns the number of items of type a_Item that are stored + /** Returns the number of items of type a_Item that are stored */ int HowManyItems(const cItem & a_Item); - /// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack + /** Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack */ bool HasItems(const cItem & a_ItemStack); + + /** Sends the equipped item slot to the client */ + void SendEquippedSlot(); - /// Returns the cItemGrid object representing the armor slots + /** Returns the cItemGrid object representing the armor slots */ cItemGrid & GetArmorGrid(void) { return m_ArmorSlots; } - /// Returns the cItemGrid object representing the main inventory slots + /** Returns the cItemGrid object representing the main inventory slots */ cItemGrid & GetInventoryGrid(void) { return m_InventorySlots; } - /// Returns the cItemGrid object representing the hotbar slots + /** Returns the cItemGrid object representing the hotbar slots */ cItemGrid & GetHotbarGrid(void) { return m_HotbarSlots; } - /// Returns the player associated with this inventory + /** Returns the player associated with this inventory */ cPlayer & GetOwner(void) { return m_Owner; } - /// Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents + /** Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents */ void CopyToItems(cItems & a_Items); // tolua_end - /// Returns the player associated with this inventory (const version) + /** Returns the player associated with this inventory (const version) */ const cPlayer & GetOwner(void) const { return m_Owner; } // tolua_begin @@ -136,10 +139,10 @@ public: */ int ChangeSlotCount(int a_SlotNum, int a_AddToCount); - /// Adds the specified damage to the specified item; deletes the item and returns true if the item broke. + /** Adds the specified damage to the specified item; deletes the item and returns true if the item broke. */ bool DamageItem(int a_SlotNum, short a_Amount); - /// Adds the specified damage to the currently held item; deletes the item and returns true if the item broke. + /** Adds the specified damage to the currently held item; deletes the item and returns true if the item broke. */ bool DamageEquippedItem(short a_Amount = 1); const cItem & GetEquippedHelmet (void) const { return m_ArmorSlots.GetSlot(0); } @@ -149,13 +152,13 @@ public: // tolua_end - /// Sends the slot contents to the owner + /** Sends the slot contents to the owner */ void SendSlot(int a_SlotNum); - /// Update items (e.g. Maps) + /** Update items (e.g. Maps) */ void UpdateItems(void); - /// Converts an armor slot number into the ID for the EntityEquipment packet + /** Converts an armor slot number into the ID for the EntityEquipment packet */ static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum); void SaveToJson(Json::Value & a_Value); @@ -172,10 +175,10 @@ protected: cPlayer & m_Owner; - /// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum + /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */ const cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const; - /// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum + /** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */ cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum); // cItemGrid::cListener override: diff --git a/src/Item.cpp b/src/Item.cpp index 856b68be6..d6e8b224a 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -5,6 +5,8 @@ #include "json/json.h" #include "Items/ItemHandler.h" +#include "FastRandom.h" + @@ -149,6 +151,8 @@ void cItem::GetJson(Json::Value & a_OutValue) const a_OutValue["Colours"] = m_FireworkItem.ColoursToString(m_FireworkItem); a_OutValue["FadeColours"] = m_FireworkItem.FadeColoursToString(m_FireworkItem); } + + a_OutValue["RepairCost"] = m_RepairCost; } } @@ -177,6 +181,8 @@ void cItem::FromJson(const Json::Value & a_Value) m_FireworkItem.ColoursFromString(a_Value.get("Colours", "").asString(), m_FireworkItem); m_FireworkItem.FadeColoursFromString(a_Value.get("FadeColours", "").asString(), m_FireworkItem); } + + m_RepairCost = a_Value.get("RepairCost", 0).asInt(); } } @@ -196,9 +202,6 @@ bool cItem::IsEnchantable(short item) return true; if ((item >= 298) && (item <= 317)) return true; - if ((item >= 290) && (item <= 294)) - return true; - if ((item == 346) || (item == 359) || (item == 261)) return true; @@ -209,6 +212,157 @@ bool cItem::IsEnchantable(short item) +int cItem::GetEnchantability() +{ + int Enchantability = 0; + + switch (m_ItemType) + { + case E_ITEM_WOODEN_SWORD: Enchantability = 15; break; + case E_ITEM_WOODEN_PICKAXE: Enchantability = 15; break; + case E_ITEM_WOODEN_SHOVEL: Enchantability = 15; break; + case E_ITEM_WOODEN_AXE: Enchantability = 15; break; + case E_ITEM_WOODEN_HOE: Enchantability = 15; break; + + case E_ITEM_LEATHER_CAP: Enchantability = 15; break; + case E_ITEM_LEATHER_TUNIC: Enchantability = 15; break; + case E_ITEM_LEATHER_PANTS: Enchantability = 15; break; + case E_ITEM_LEATHER_BOOTS: Enchantability = 15; break; + + case E_ITEM_STONE_SWORD: Enchantability = 5; break; + case E_ITEM_STONE_PICKAXE: Enchantability = 5; break; + case E_ITEM_STONE_SHOVEL: Enchantability = 5; break; + case E_ITEM_STONE_AXE: Enchantability = 5; break; + case E_ITEM_STONE_HOE: Enchantability = 5; break; + + case E_ITEM_IRON_HELMET: Enchantability = 9; break; + case E_ITEM_IRON_CHESTPLATE: Enchantability = 9; break; + case E_ITEM_IRON_LEGGINGS: Enchantability = 9; break; + case E_ITEM_IRON_BOOTS: Enchantability = 9; break; + + case E_ITEM_IRON_SWORD: Enchantability = 14; break; + case E_ITEM_IRON_PICKAXE: Enchantability = 14; break; + case E_ITEM_IRON_SHOVEL: Enchantability = 14; break; + case E_ITEM_IRON_AXE: Enchantability = 14; break; + case E_ITEM_IRON_HOE: Enchantability = 14; break; + + case E_ITEM_CHAIN_HELMET: Enchantability = 12; break; + case E_ITEM_CHAIN_CHESTPLATE: Enchantability = 12; break; + case E_ITEM_CHAIN_LEGGINGS: Enchantability = 12; break; + case E_ITEM_CHAIN_BOOTS: Enchantability = 12; break; + + case E_ITEM_DIAMOND_HELMET: Enchantability = 10; break; + case E_ITEM_DIAMOND_CHESTPLATE: Enchantability = 10; break; + case E_ITEM_DIAMOND_LEGGINGS: Enchantability = 10; break; + case E_ITEM_DIAMOND_BOOTS: Enchantability = 10; break; + + case E_ITEM_DIAMOND_SWORD: Enchantability = 10; break; + case E_ITEM_DIAMOND_PICKAXE: Enchantability = 10; break; + case E_ITEM_DIAMOND_SHOVEL: Enchantability = 10; break; + case E_ITEM_DIAMOND_AXE: Enchantability = 10; break; + case E_ITEM_DIAMOND_HOE: Enchantability = 10; break; + + case E_ITEM_GOLD_HELMET: Enchantability = 25; break; + case E_ITEM_GOLD_CHESTPLATE: Enchantability = 25; break; + case E_ITEM_GOLD_LEGGINGS: Enchantability = 25; break; + case E_ITEM_GOLD_BOOTS: Enchantability = 25; break; + + case E_ITEM_GOLD_SWORD: Enchantability = 22; break; + case E_ITEM_GOLD_PICKAXE: Enchantability = 22; break; + case E_ITEM_GOLD_SHOVEL: Enchantability = 22; break; + case E_ITEM_GOLD_AXE: Enchantability = 22; break; + case E_ITEM_GOLD_HOE: Enchantability = 22; break; + + case E_ITEM_FISHING_ROD: Enchantability = 1; break; + case E_ITEM_BOW: Enchantability = 1; break; + case E_ITEM_BOOK: Enchantability = 1; break; + } + + return Enchantability; +} + + + + + +bool cItem::EnchantByXPLevels(int a_NumXPLevels) +{ + if (!cItem::IsEnchantable(m_ItemType) && (m_ItemType != E_ITEM_BOOK)) + { + return false; + } + + int Enchantability = GetEnchantability(); + + cFastRandom Random; + int ModifiedEnchantmentLevel = a_NumXPLevels + (int)Random.NextFloat((float)Enchantability / 4) + (int)Random.NextFloat((float)Enchantability / 4) + 1; + float RandomBonus = 1.0F + (Random.NextFloat(1) + Random.NextFloat(1) - 1.0F) * 0.15F; + int FinalEnchantmentLevel = (int)(ModifiedEnchantmentLevel * RandomBonus + 0.5F); + + cWeightedEnchantments enchantments; + cEnchantments::AddItemEnchantmentWeights(enchantments, m_ItemType, FinalEnchantmentLevel); + + if (m_ItemType == E_ITEM_BOOK) + { + m_ItemType = E_ITEM_ENCHANTED_BOOK; + } + + cEnchantments Enchantment1 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + m_Enchantments.AddFromString(Enchantment1.ToString()); + cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment1); + + // Checking for conflicting enchantments + cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment1); + + float NewEnchantmentLevel = (float)a_NumXPLevels; + + // Next Enchantment (Second) + NewEnchantmentLevel = NewEnchantmentLevel / 2; + float SecondEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; + if (enchantments.empty() || (Random.NextFloat(100) > SecondEnchantmentChance)) + { + return true; + } + + cEnchantments Enchantment2 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + m_Enchantments.AddFromString(Enchantment2.ToString()); + cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment2); + + // Checking for conflicting enchantments + cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment2); + + // Next Enchantment (Third) + NewEnchantmentLevel = NewEnchantmentLevel / 2; + float ThirdEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; + if (enchantments.empty() || (Random.NextFloat(100) > ThirdEnchantmentChance)) + { + return true; + } + + cEnchantments Enchantment3 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + m_Enchantments.AddFromString(Enchantment3.ToString()); + cEnchantments::RemoveEnchantmentWeightFromVector(enchantments, Enchantment3); + + // Checking for conflicting enchantments + cEnchantments::CheckEnchantmentConflictsFromVector(enchantments, Enchantment3); + + // Next Enchantment (Fourth) + NewEnchantmentLevel = NewEnchantmentLevel / 2; + float FourthEnchantmentChance = (NewEnchantmentLevel + 1) / 50 * 100; + if (enchantments.empty() || (Random.NextFloat(100) > FourthEnchantmentChance)) + { + return true; + } + cEnchantments Enchantment4 = cEnchantments::GetRandomEnchantmentFromVector(enchantments); + m_Enchantments.AddFromString(Enchantment4.ToString()); + + return true; +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cItems: diff --git a/src/Item.h b/src/Item.h index 4bdfb12dd..acbc880dc 100644 --- a/src/Item.h +++ b/src/Item.h @@ -40,6 +40,7 @@ public: m_ItemDamage(0), m_CustomName(""), m_Lore(""), + m_RepairCost(0), m_FireworkItem() { } @@ -60,11 +61,12 @@ public: m_Enchantments(a_Enchantments), m_CustomName (a_CustomName), m_Lore (a_Lore), + m_RepairCost (0), m_FireworkItem() { if (!IsValidItem(m_ItemType)) { - if (m_ItemType != E_BLOCK_AIR) + if ((m_ItemType != E_BLOCK_AIR) && (m_ItemType != E_ITEM_EMPTY)) { LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType); } @@ -73,6 +75,10 @@ public: } + // The constructor is disabled in code, because the compiler generates it anyway, + // but it needs to stay because ToLua needs to generate the binding for it + #if 0 + /** Creates an exact copy of the item */ cItem(const cItem & a_CopyFrom) : m_ItemType (a_CopyFrom.m_ItemType), @@ -81,10 +87,13 @@ public: m_Enchantments(a_CopyFrom.m_Enchantments), m_CustomName (a_CopyFrom.m_CustomName), m_Lore (a_CopyFrom.m_Lore), + m_RepairCost (a_CopyFrom.m_RepairCost), m_FireworkItem(a_CopyFrom.m_FireworkItem) { } + #endif + void Empty(void) { @@ -94,6 +103,7 @@ public: m_Enchantments.Clear(); m_CustomName = ""; m_Lore = ""; + m_RepairCost = 0; m_FireworkItem.EmptyData(); } @@ -103,6 +113,7 @@ public: m_ItemType = E_ITEM_EMPTY; m_ItemCount = 0; m_ItemDamage = 0; + m_RepairCost = 0; } @@ -175,16 +186,24 @@ public: /** Returns true if the specified item type is enchantable (as per 1.2.5 protocol requirements) */ static bool IsEnchantable(short a_ItemType); // tolua_export + /** Returns the enchantability of the item. When the item hasn't a enchantability, it will returns 0 */ + int GetEnchantability(); // tolua_export + + /** Enchants the item using the specified number of XP levels. + Returns true if item enchanted, false if not. */ + bool EnchantByXPLevels(int a_NumXPLevels); // tolua_export + // tolua_begin - short m_ItemType; - char m_ItemCount; - short m_ItemDamage; - cEnchantments m_Enchantments; - AString m_CustomName; - AString m_Lore; - - cFireworkItem m_FireworkItem; + short m_ItemType; + char m_ItemCount; + short m_ItemDamage; + cEnchantments m_Enchantments; + AString m_CustomName; + AString m_Lore; + + int m_RepairCost; + cFireworkItem m_FireworkItem; }; // tolua_end @@ -209,7 +228,7 @@ public: void Add (const cItem & a_Item) {push_back(a_Item); } void Delete(int a_Idx); void Clear (void) {clear(); } - int Size (void) {return size(); } + size_t Size (void) const { return size(); } void Set (int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage); void Add (short a_ItemType, char a_ItemCount, short a_ItemDamage) diff --git a/src/Items/CMakeLists.txt b/src/Items/CMakeLists.txt index 44a9f594f..a6fe6ea70 100644 --- a/src/Items/CMakeLists.txt +++ b/src/Items/CMakeLists.txt @@ -4,4 +4,9 @@ project (MCServer) include_directories ("${PROJECT_SOURCE_DIR}/../") -add_library(Items ItemHandler) +file(GLOB SOURCE + "*.cpp" + "*.h" +) + +add_library(Items ${SOURCE}) diff --git a/src/Items/ItemArmor.h b/src/Items/ItemArmor.h new file mode 100644 index 000000000..2436df5bd --- /dev/null +++ b/src/Items/ItemArmor.h @@ -0,0 +1,110 @@ + +#pragma once + +#include "ItemHandler.h" +#include "../World.h" + + + + + +class cItemArmorHandler : + public cItemHandler +{ +public: + cItemArmorHandler(int a_ItemType) : + cItemHandler(a_ItemType) + { + } + + /** Move the armor to the armor slot of the player's inventory */ + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override + { + int SlotNum; + if (ItemCategory::IsHelmet(a_Item.m_ItemType)) + { + SlotNum = 0; + } + else if (ItemCategory::IsChestPlate(a_Item.m_ItemType)) + { + SlotNum = 1; + } + else if (ItemCategory::IsLeggings(a_Item.m_ItemType)) + { + SlotNum = 2; + } + else if (ItemCategory::IsBoots(a_Item.m_ItemType)) + { + SlotNum = 3; + } + else + { + LOGWARNING("Used unknown armor: %i", a_Item.m_ItemType); + return false; + } + + if (!a_Player->GetInventory().GetArmorSlot(SlotNum).IsEmpty()) + { + return false; + } + + a_Player->GetInventory().SetArmorSlot(SlotNum, a_Item.CopyOne()); + + cItem Item(a_Item); + Item.m_ItemCount--; + if (Item.m_ItemCount <= 0) + { + Item.Empty(); + } + a_Player->GetInventory().SetHotbarSlot(a_Player->GetInventory().GetEquippedSlotNum(), Item); + return true; + } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_CHAIN_BOOTS: + case E_ITEM_CHAIN_CHESTPLATE: + case E_ITEM_CHAIN_HELMET: + case E_ITEM_CHAIN_LEGGINGS: + { + return (a_ItemType == E_ITEM_IRON); + } + case E_ITEM_DIAMOND_BOOTS: + case E_ITEM_DIAMOND_CHESTPLATE: + case E_ITEM_DIAMOND_HELMET: + case E_ITEM_DIAMOND_LEGGINGS: + { + return (a_ItemType == E_ITEM_DIAMOND); + } + case E_ITEM_IRON_BOOTS: + case E_ITEM_IRON_CHESTPLATE: + case E_ITEM_IRON_HELMET: + case E_ITEM_IRON_LEGGINGS: + { + return (a_ItemType == E_ITEM_IRON); + } + case E_ITEM_GOLD_BOOTS: + case E_ITEM_GOLD_CHESTPLATE: + case E_ITEM_GOLD_HELMET: + case E_ITEM_GOLD_LEGGINGS: + { + return (a_ItemType == E_ITEM_GOLD); + } + case E_ITEM_LEATHER_BOOTS: + case E_ITEM_LEATHER_CAP: + case E_ITEM_LEATHER_PANTS: + case E_ITEM_LEATHER_TUNIC: + { + return (a_ItemType == E_ITEM_LEATHER); + } + } + return false; + } + +} ; + + + + diff --git a/src/Items/ItemBoat.h b/src/Items/ItemBoat.h index a28ec8e22..42f4ffc8f 100644 --- a/src/Items/ItemBoat.h +++ b/src/Items/ItemBoat.h @@ -39,12 +39,20 @@ public: public cBlockTracer::cCallbacks { public: - Vector3d Pos; - virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override + Vector3d m_Pos; + bool m_HasFound; + + cCallbacks(void) : + m_HasFound(false) { - if (a_BlockType != E_BLOCK_AIR) + } + + virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override + { + if (a_CBBlockType != E_BLOCK_AIR) { - Pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ); + m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); + m_HasFound = true; return true; } return false; @@ -57,15 +65,15 @@ public: Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); - double x = Callbacks.Pos.x; - double y = Callbacks.Pos.y; - double z = Callbacks.Pos.z; - - if ((x == 0) && (y == 0) && (z == 0)) + if (!Callbacks.m_HasFound) { return false; } + double x = Callbacks.m_Pos.x; + double y = Callbacks.m_Pos.y; + double z = Callbacks.m_Pos.z; + cBoat * Boat = new cBoat(x + 0.5, y + 1, z + 0.5); Boat->Initialize(a_World); diff --git a/src/Items/ItemBow.h b/src/Items/ItemBow.h index 410c5f512..8c0b3a0a3 100644 --- a/src/Items/ItemBow.h +++ b/src/Items/ItemBow.h @@ -9,7 +9,7 @@ #pragma once -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" diff --git a/src/Items/ItemBucket.h b/src/Items/ItemBucket.h index 72cb8fa0a..68c89dd85 100644 --- a/src/Items/ItemBucket.h +++ b/src/Items/ItemBucket.h @@ -172,12 +172,12 @@ public: virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override { - if (a_BlockMeta != 0) // Even if it was a water block it would not be a source. - { - return false; - } if (IsBlockWater(a_BlockType) || IsBlockLava(a_BlockType)) { + if (a_BlockMeta != 0) // GetBlockFromTrace is called for scooping up fluids; the hit block should be a source + { + return false; + } m_HasHitFluid = true; m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); return true; diff --git a/src/Items/ItemEmptyMap.h b/src/Items/ItemEmptyMap.h index f0b1e1424..953673382 100644 --- a/src/Items/ItemEmptyMap.h +++ b/src/Items/ItemEmptyMap.h @@ -55,7 +55,7 @@ public: return true; } - a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, NewMap->GetID()), true, true); + a_Player->GetInventory().AddItem(cItem(E_ITEM_MAP, 1, (short)(NewMap->GetID() & 0x7fff)), true, true); return true; } diff --git a/src/Items/ItemFishingRod.h b/src/Items/ItemFishingRod.h index 15acbd9fe..32c151db5 100644 --- a/src/Items/ItemFishingRod.h +++ b/src/Items/ItemFishingRod.h @@ -123,7 +123,7 @@ public: } case 2: { - Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, a_World->GetTickRandomNumber(50))); // Fishing rod with durability. TODO: Enchantments on it + Drops.Add(cItem(E_ITEM_FISHING_ROD, 1, (short)a_World->GetTickRandomNumber(50))); // Fishing rod with durability. TODO: Enchantments on it break; } case 3: @@ -142,6 +142,8 @@ public: break; } } + + a_Player->GetStatManager().AddValue(statTreasureFished, 1); } else if (ItemCategory <= 14) // Junk 10% { @@ -152,7 +154,7 @@ public: } else if (Junk <= 4) { - Drops.Add(cItem(E_ITEM_BOW, 1, a_World->GetTickRandomNumber(64))); + Drops.Add(cItem(E_ITEM_BOW, 1, (short)a_World->GetTickRandomNumber(64))); } else if (Junk <= 9) { @@ -190,6 +192,8 @@ public: { Drops.Add(cItem(E_BLOCK_TRIPWIRE_HOOK)); } + + a_Player->GetStatManager().AddValue(statJunkFished, 1); } else // Fish { @@ -210,6 +214,8 @@ public: { Drops.Add(cItem(E_ITEM_RAW_FISH, 1, E_META_RAW_FISH_FISH)); } + + a_Player->GetStatManager().AddValue(statFishCaught, 1); } if (cRoot::Get()->GetPluginManager()->CallHookPlayerFishing(*a_Player, Drops)) diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 454fabdd7..d97f986ba 100644 --- a/src/Items/ItemHandler.cpp +++ b/src/Items/ItemHandler.cpp @@ -8,6 +8,7 @@ #include "../BlockInServerPluginInterface.h" // Handlers: +#include "ItemArmor.h" #include "ItemBed.h" #include "ItemBoat.h" #include "ItemBow.h" @@ -27,6 +28,7 @@ #include "ItemHoe.h" #include "ItemLeaves.h" #include "ItemLighter.h" +#include "ItemLilypad.h" #include "ItemMap.h" #include "ItemMinecart.h" #include "ItemNetherWart.h" @@ -115,6 +117,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); + case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType); case E_ITEM_MAP: return new cItemMapHandler(); case E_ITEM_ITEM_FRAME: return new cItemItemFrameHandler(a_ItemType); case E_ITEM_NETHER_WART: return new cItemNetherWartHandler(a_ItemType); @@ -220,6 +223,31 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) { return new cItemFoodHandler(a_ItemType); } + + // Armor: + case E_ITEM_LEATHER_CAP: + case E_ITEM_GOLD_HELMET: + case E_ITEM_CHAIN_HELMET: + case E_ITEM_IRON_HELMET: + case E_ITEM_DIAMOND_HELMET: + case E_ITEM_LEATHER_TUNIC: + case E_ITEM_GOLD_CHESTPLATE: + case E_ITEM_CHAIN_CHESTPLATE: + case E_ITEM_IRON_CHESTPLATE: + case E_ITEM_DIAMOND_CHESTPLATE: + case E_ITEM_LEATHER_PANTS: + case E_ITEM_GOLD_LEGGINGS: + case E_ITEM_CHAIN_LEGGINGS: + case E_ITEM_IRON_LEGGINGS: + case E_ITEM_DIAMOND_LEGGINGS: + case E_ITEM_LEATHER_BOOTS: + case E_ITEM_GOLD_BOOTS: + case E_ITEM_CHAIN_BOOTS: + case E_ITEM_IRON_BOOTS: + case E_ITEM_DIAMOND_BOOTS: + { + return new cItemArmorHandler(a_ItemType); + } } } @@ -429,7 +457,6 @@ bool cItemHandler::IsTool() || (m_ItemType >= 267 && m_ItemType <= 279) || (m_ItemType >= 283 && m_ItemType <= 286) || (m_ItemType >= 290 && m_ItemType <= 294) - || (m_ItemType >= 256 && m_ItemType <= 259) || (m_ItemType == 325) || (m_ItemType == 346); } @@ -484,6 +511,16 @@ bool cItemHandler::IsPlaceable(void) + +bool cItemHandler::CanRepairWithRawMaterial(short a_ItemType) +{ + return false; +} + + + + + bool cItemHandler::CanHarvestBlock(BLOCKTYPE a_BlockType) { UNUSED(a_BlockType); @@ -504,13 +541,13 @@ bool cItemHandler::GetPlacementBlockTypeMeta( { ASSERT(m_ItemType < 256); // Items with IDs above 255 should all be handled by specific handlers - if (m_ItemType > 256) + if (m_ItemType >= 256) { - LOGERROR("%s: Item %d has no valid block!", __FUNCTION__, m_ItemType); + LOGERROR("%s: Item %d is not eligible for direct block placement!", __FUNCTION__, m_ItemType); return false; } - cBlockHandler * BlockH = BlockHandler(m_ItemType); + cBlockHandler * BlockH = BlockHandler((BLOCKTYPE)m_ItemType); cChunkInterface ChunkInterface(a_World->GetChunkMap()); return BlockH->GetPlacementBlockTypeMeta( ChunkInterface, a_Player, diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 5b6c239cc..e13198cd7 100644 --- a/src/Items/ItemHandler.h +++ b/src/Items/ItemHandler.h @@ -21,13 +21,13 @@ class cItemHandler public: cItemHandler(int a_ItemType); - // Force virtual destructor + /** Force virtual destructor */ virtual ~cItemHandler() {} - /// Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False + /** Called when the player tries to use the item (right mouse button). Return false to make the item unusable. DEFAULT: False */ virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir); - /// Called when the client sends the SHOOT status in the lclk packet + /** Called when the client sends the SHOOT status in the lclk packet */ virtual void OnItemShoot(cPlayer *, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) { UNUSED(a_BlockX); @@ -36,7 +36,7 @@ public: UNUSED(a_BlockFace); } - /// Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items + /** Called every tick while the item is on the player's inventory (Used by maps) - For now, called only for equipped items */ virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item) { UNUSED(a_World); @@ -44,48 +44,51 @@ public: UNUSED(a_Item); } - /// Called while the player diggs a block using this item + /** Called while the player diggs a block using this item */ virtual bool OnDiggingBlock(cWorld * a_World, cPlayer * a_Player, const cItem & a_HeldItem, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace); - /// Called when the player destroys a block using this item. This also calls the drop function for the destroyed block + /** Called when the player destroys a block using this item. This also calls the drop function for the destroyed block */ virtual void OnBlockDestroyed(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_X, int a_Y, int a_Z); - /// Called after the player has eaten this item. + /** Called after the player has eaten this item. */ virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item); - /// Returns the maximum stack size for a given item + /** Returns the maximum stack size for a given item */ virtual char GetMaxStackSize(void); struct FoodInfo { - int FoodLevel; double Saturation; + int FoodLevel; int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) : - FoodLevel(a_FoodLevel), Saturation(a_Saturation), + FoodLevel(a_FoodLevel), PoisonChance(a_PoisonChance) { } } ; - /// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) + /** Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) */ virtual FoodInfo GetFoodInfo(); - /// Lets the player eat a selected item. Returns true if the player ate the item + /** Lets the player eat a selected item. Returns true if the player ate the item */ virtual bool EatItem(cPlayer *a_Player, cItem *a_Item); - /// Indicates if this item is a tool + /** Indicates if this item is a tool */ virtual bool IsTool(void); - /// Indicates if this item is food + /** Indicates if this item is food */ virtual bool IsFood(void); - /// Blocks simply get placed + /** Blocks simply get placed */ virtual bool IsPlaceable(void); - /** Called before a block is placed into a world. + /** Can the anvil repair this item, when a_Item is the second input? */ + virtual bool CanRepairWithRawMaterial(short a_ItemType); + + /** Called before a block is placed into a world. The handler should return true to allow placement, false to refuse. Also, the handler should set a_BlockType and a_BlockMeta to correct values for the newly placed block. */ @@ -96,7 +99,7 @@ public: BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta ); - /// Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can´t) DEFAULT: False + /** Returns whether this tool/item can harvest a specific block (e.g. wooden pickaxe can harvest stone, but wood can�t) DEFAULT: False */ virtual bool CanHarvestBlock(BLOCKTYPE a_BlockType); static cItemHandler * GetItemHandler(int a_ItemType); diff --git a/src/Items/ItemLilypad.h b/src/Items/ItemLilypad.h new file mode 100644 index 000000000..bc650cdbd --- /dev/null +++ b/src/Items/ItemLilypad.h @@ -0,0 +1,108 @@ +#pragma once + +#include "ItemHandler.h" +#include "../Entities/Player.h" +#include "Vector3.h" +#include "../LineBlockTracer.h" +#include "BlockInfo.h" + + + + + +class cItemLilypadHandler : + public cItemHandler +{ + typedef cItemHandler super; + +public: + cItemLilypadHandler(int a_ItemType): + super(a_ItemType) + { + + } + + + virtual bool IsPlaceable(void) override + { + return false; // Set as not placeable so OnItemUse is called + } + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override + { + if (a_BlockFace > BLOCK_FACE_NONE) + { + // Clicked on the side of a submerged block; vanilla allows placement, so should we + AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace); + a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LILY_PAD, 0); + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + return true; + } + + class cCallbacks : + public cBlockTracer::cCallbacks + { + public: + + cCallbacks(void) : + m_HasHitFluid(false) + { + } + + virtual bool OnNextBlock(int a_CBBlockX, int a_CBBlockY, int a_CBBlockZ, BLOCKTYPE a_CBBlockType, NIBBLETYPE a_CBBlockMeta, char a_CBEntryFace) override + { + if (IsBlockWater(a_CBBlockType)) + { + if ((a_CBBlockMeta != 0) || (a_CBEntryFace == BLOCK_FACE_NONE)) // The hit block should be a source. The FACE_NONE check is clicking whilst submerged + { + return false; + } + AddFaceDirection(a_CBBlockX, a_CBBlockY, a_CBBlockZ, BLOCK_FACE_YP); // Always place pad at top of water block + if ( + !IsBlockWater(a_CBBlockType) && + cBlockInfo::FullyOccupiesVoxel(a_CBBlockType) + ) + { + // Can't place lilypad on air/in another block! + return true; + } + m_HasHitFluid = true; + m_Pos.Set(a_CBBlockX, a_CBBlockY, a_CBBlockZ); + return true; + } + return false; + } + + Vector3i m_Pos; + bool m_HasHitFluid; + + }; + + cCallbacks Callbacks; + cLineBlockTracer Tracer(*a_Player->GetWorld(), Callbacks); + Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector()); + Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5); + + Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z); + + if (Callbacks.m_HasHitFluid) + { + a_World->SetBlock(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z, E_BLOCK_LILY_PAD, 0); + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } + return true; + } + + return false; + } +}; + + + + diff --git a/src/Items/ItemMap.h b/src/Items/ItemMap.h index e8ff9da88..056fe0fe7 100644 --- a/src/Items/ItemMap.h +++ b/src/Items/ItemMap.h @@ -29,7 +29,7 @@ public: virtual void OnUpdate(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item) { - cMap * Map = a_World->GetMapManager().GetMapData(a_Item.m_ItemDamage); + cMap * Map = a_World->GetMapManager().GetMapData((unsigned)a_Item.m_ItemDamage); if (Map == NULL) { diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h index bcaa5635a..4e7d8fcff 100644 --- a/src/Items/ItemMinecart.h +++ b/src/Items/ItemMinecart.h @@ -1,4 +1,3 @@ - // ItemMinecart.h // Declares the various minecart ItemHandlers @@ -72,9 +71,14 @@ public: } } // switch (m_ItemType) Minecart->Initialize(a_World); + + if (!a_Player->IsGameModeCreative()) + { + a_Player->GetInventory().RemoveOneEquippedItem(); + } return true; } - + } ; diff --git a/src/Items/ItemPickaxe.h b/src/Items/ItemPickaxe.h index 2a8e40daa..82bec52d4 100644 --- a/src/Items/ItemPickaxe.h +++ b/src/Items/ItemPickaxe.h @@ -76,6 +76,7 @@ public: case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_BRICK: case E_BLOCK_COBBLESTONE_STAIRS: + case E_BLOCK_COBBLESTONE_WALL: case E_BLOCK_STONE_BRICK_STAIRS: case E_BLOCK_NETHER_BRICK_STAIRS: case E_BLOCK_CAULDRON: @@ -85,6 +86,19 @@ public: } return false; } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_PICKAXE: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_PICKAXE: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_PICKAXE: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_PICKAXE: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_PICKAXE: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } } ; diff --git a/src/Items/ItemShovel.h b/src/Items/ItemShovel.h index 873d5ae25..333ba46e8 100644 --- a/src/Items/ItemShovel.h +++ b/src/Items/ItemShovel.h @@ -41,4 +41,18 @@ public: { return (a_BlockType == E_BLOCK_SNOW); } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_SHOVEL: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_SHOVEL: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_SHOVEL: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_SHOVEL: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_SHOVEL: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } + }; diff --git a/src/Items/ItemSpawnEgg.h b/src/Items/ItemSpawnEgg.h index 0d6019398..bba97afa1 100644 --- a/src/Items/ItemSpawnEgg.h +++ b/src/Items/ItemSpawnEgg.h @@ -33,7 +33,10 @@ public: a_BlockY--; } - if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0) + cMonster::eType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage); + if ( + (MonsterType != cMonster::mtInvalidType) && // Valid monster type + (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded { if (!a_Player->IsGameModeCreative()) { @@ -45,6 +48,41 @@ public: return false; } + + + /** Converts the Spawn egg item damage to the monster type to spawn. + Returns mtInvalidType for invalid damage values. */ + static cMonster::eType ItemDamageToMonsterType(short a_ItemDamage) + { + switch (a_ItemDamage) + { + case E_META_SPAWN_EGG_BAT: return cMonster::mtBat; + case E_META_SPAWN_EGG_BLAZE: return cMonster::mtBlaze; + case E_META_SPAWN_EGG_CAVE_SPIDER: return cMonster::mtCaveSpider; + case E_META_SPAWN_EGG_CHICKEN: return cMonster::mtChicken; + case E_META_SPAWN_EGG_COW: return cMonster::mtCow; + case E_META_SPAWN_EGG_CREEPER: return cMonster::mtCreeper; + case E_META_SPAWN_EGG_ENDERMAN: return cMonster::mtEnderman; + case E_META_SPAWN_EGG_GHAST: return cMonster::mtGhast; + case E_META_SPAWN_EGG_HORSE: return cMonster::mtHorse; + case E_META_SPAWN_EGG_MAGMA_CUBE: return cMonster::mtMagmaCube; + case E_META_SPAWN_EGG_MOOSHROOM: return cMonster::mtMooshroom; + case E_META_SPAWN_EGG_OCELOT: return cMonster::mtOcelot; + case E_META_SPAWN_EGG_PIG: return cMonster::mtPig; + case E_META_SPAWN_EGG_SHEEP: return cMonster::mtSheep; + case E_META_SPAWN_EGG_SILVERFISH: return cMonster::mtSilverfish; + case E_META_SPAWN_EGG_SKELETON: return cMonster::mtSkeleton; + case E_META_SPAWN_EGG_SLIME: return cMonster::mtSlime; + case E_META_SPAWN_EGG_SPIDER: return cMonster::mtSpider; + case E_META_SPAWN_EGG_SQUID: return cMonster::mtSquid; + case E_META_SPAWN_EGG_VILLAGER: return cMonster::mtVillager; + case E_META_SPAWN_EGG_WITCH: return cMonster::mtWitch; + case E_META_SPAWN_EGG_WOLF: return cMonster::mtWolf; + case E_META_SPAWN_EGG_ZOMBIE: return cMonster::mtZombie; + case E_META_SPAWN_EGG_ZOMBIE_PIGMAN: return cMonster::mtZombiePigman; + } + return cMonster::mtInvalidType; + } } ; diff --git a/src/Items/ItemSword.h b/src/Items/ItemSword.h index a7c1d2432..44feb2d83 100644 --- a/src/Items/ItemSword.h +++ b/src/Items/ItemSword.h @@ -23,6 +23,19 @@ public: { return (a_BlockType == E_BLOCK_COBWEB); } + + virtual bool CanRepairWithRawMaterial(short a_ItemType) override + { + switch (m_ItemType) + { + case E_ITEM_WOODEN_SWORD: return (a_ItemType == E_BLOCK_PLANKS); + case E_ITEM_STONE_SWORD: return (a_ItemType == E_BLOCK_COBBLESTONE); + case E_ITEM_IRON_SWORD: return (a_ItemType == E_ITEM_IRON); + case E_ITEM_GOLD_SWORD: return (a_ItemType == E_ITEM_GOLD); + case E_ITEM_DIAMOND_SWORD: return (a_ItemType == E_ITEM_DIAMOND); + } + return false; + } } ; diff --git a/src/Items/ItemThrowable.h b/src/Items/ItemThrowable.h index c6a4e714e..35c2b8731 100644 --- a/src/Items/ItemThrowable.h +++ b/src/Items/ItemThrowable.h @@ -28,15 +28,19 @@ public: virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_Dir) override { + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; + + if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0) + { + return false; + } + if (!a_Player->IsGameModeCreative()) { a_Player->GetInventory().RemoveOneEquippedItem(); } - Vector3d Pos = a_Player->GetThrowStartPos(); - Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; - a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed); - return true; } @@ -127,7 +131,10 @@ public: return false; } - a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()); + if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()) < 0) + { + return false; + } if (!a_Player->IsGameModeCreative()) { diff --git a/src/LightingThread.cpp b/src/LightingThread.cpp index 302473d71..dc19bf500 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -18,20 +18,17 @@ class cReader : public cChunkDataCallback { - virtual void BlockTypes(const BLOCKTYPE * a_Type) override + virtual void ChunkData(const cChunkData & a_ChunkBuffer) 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; + BLOCKTYPE * OutputRows = 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++]; + a_ChunkBuffer.CopyBlockTypes(OutputRows + OutputIdx * 16, InputIdx * 16, 16); + InputIdx++; OutputIdx += 3; } // for z // Skip into the next y-level in the 3x3 chunk blob; each level has cChunkDef::Width * 9 rows @@ -106,11 +103,13 @@ void cLightingThread::Stop(void) cCSLock Lock(m_CS); for (cChunkStays::iterator itr = m_PendingQueue.begin(), end = m_PendingQueue.end(); itr != end; ++itr) { + (*itr)->Disable(); delete *itr; } m_PendingQueue.clear(); for (cChunkStays::iterator itr = m_Queue.begin(), end = m_Queue.end(); itr != end; ++itr) { + (*itr)->Disable(); delete *itr; } m_Queue.clear(); @@ -286,6 +285,7 @@ void cLightingThread::LightChunk(cLightingChunkStay & a_Item) { a_Item.m_CallbackAfter->Call(a_Item.m_ChunkX, a_Item.m_ChunkZ); } + a_Item.Disable(); delete &a_Item; } diff --git a/src/LightingThread.h b/src/LightingThread.h index 198f27248..770ae809f 100644 --- a/src/LightingThread.h +++ b/src/LightingThread.h @@ -160,14 +160,12 @@ protected: inline void PropagateLight( NIBBLETYPE * a_Light, - int a_SrcIdx, int a_DstIdx, + unsigned int a_SrcIdx, unsigned int a_DstIdx, int & a_NumSeedsOut, unsigned char * a_IsSeedOut, unsigned int * a_SeedIdxOut ) { - ASSERT(a_SrcIdx >= 0); - ASSERT(a_SrcIdx < (int)ARRAYCOUNT(m_SkyLight)); - ASSERT(a_DstIdx >= 0); - ASSERT(a_DstIdx < (int)ARRAYCOUNT(m_BlockTypes)); + ASSERT(a_SrcIdx < ARRAYCOUNT(m_SkyLight)); + ASSERT(a_DstIdx < ARRAYCOUNT(m_BlockTypes)); if (a_Light[a_SrcIdx] <= a_Light[a_DstIdx] + cBlockInfo::GetSpreadLightFalloff(m_BlockTypes[a_DstIdx])) { diff --git a/src/LineBlockTracer.cpp b/src/LineBlockTracer.cpp index f4f29e833..b03652bab 100644 --- a/src/LineBlockTracer.cpp +++ b/src/LineBlockTracer.cpp @@ -171,7 +171,6 @@ bool cLineBlockTracer::MoveToNextBlock(void) double CoeffZ = (DestZ - m_StartZ) / m_DiffZ; if (CoeffZ < Coeff) { - Coeff = CoeffZ; Direction = dirZ; } } diff --git a/src/MCLogger.cpp b/src/MCLogger.cpp index 4f3e5dc0f..583438d65 100644 --- a/src/MCLogger.cpp +++ b/src/MCLogger.cpp @@ -9,7 +9,6 @@ cMCLogger * cMCLogger::s_MCLogger = NULL; -bool g_ShouldColorOutput = false; #ifdef _WIN32 #include <io.h> // Needed for _isatty(), not available on Linux @@ -33,7 +32,8 @@ cMCLogger * cMCLogger::GetInstance(void) -cMCLogger::cMCLogger(void) +cMCLogger::cMCLogger(void): + m_ShouldColorOutput(false) { AString FileName; Printf(FileName, "LOG_%d.txt", (int)time(NULL)); @@ -76,15 +76,15 @@ void cMCLogger::InitLog(const AString & a_FileName) #ifdef _WIN32 // See whether we are writing to a console the default console attrib: - g_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); - if (g_ShouldColorOutput) + m_ShouldColorOutput = (_isatty(_fileno(stdin)) != 0); + if (m_ShouldColorOutput) { CONSOLE_SCREEN_BUFFER_INFO sbi; GetConsoleScreenBufferInfo(g_Console, &sbi); g_DefaultConsoleAttrib = sbi.wAttributes; } #elif defined (__linux) && !defined(ANDROID_NDK) - g_ShouldColorOutput = isatty(fileno(stdout)); + m_ShouldColorOutput = isatty(fileno(stdout)); // TODO: Check if the terminal supports colors, somehow? #endif } @@ -93,25 +93,30 @@ void cMCLogger::InitLog(const AString & a_FileName) -void cMCLogger::LogSimple(const char* a_Text, int a_LogType /* = 0 */ ) +void cMCLogger::LogSimple(const char * a_Text, eLogLevel a_LogLevel) { - switch( a_LogType ) + switch (a_LogLevel) { - case 0: + case llRegular: + { LOG("%s", a_Text); break; - case 1: + } + case llInfo: + { LOGINFO("%s", a_Text); break; - case 2: + } + case llWarning: + { LOGWARN("%s", a_Text); break; - case 3: + } + case llError: + { LOGERROR("%s", a_Text); break; - default: - LOG("(#%d#: %s", a_LogType, a_Text); - break; + } } } @@ -173,7 +178,7 @@ void cMCLogger::Error(const char * a_Format, va_list a_ArgList) void cMCLogger::SetColor(eColorScheme a_Scheme) { - if (!g_ShouldColorOutput) + if (!m_ShouldColorOutput) { return; } @@ -206,7 +211,7 @@ void cMCLogger::SetColor(eColorScheme a_Scheme) void cMCLogger::ResetColor(void) { - if (!g_ShouldColorOutput) + if (!m_ShouldColorOutput) { return; } diff --git a/src/MCLogger.h b/src/MCLogger.h index 996e60329..114210f63 100644 --- a/src/MCLogger.h +++ b/src/MCLogger.h @@ -10,25 +10,36 @@ class cLog; -class cMCLogger // tolua_export -{ // tolua_export -public: // tolua_export - /// Creates a logger with the default filename, "logs/LOG_<timestamp>.log" +// tolua_begin +class cMCLogger +{ +public: + enum eLogLevel + { + llRegular, + llInfo, + llWarning, + llError, + }; + // tolua_end + + /** Creates a logger with the default filename, "logs/LOG_<timestamp>.log" */ cMCLogger(void); - /// Creates a logger with the specified filename inside "logs" folder + /** Creates a logger with the specified filename inside "logs" folder */ cMCLogger(const AString & a_FileName); // tolua_export ~cMCLogger(); // tolua_export - void Log(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Info(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Warn(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void Error(const char* a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Log (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Info (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Warn (const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); + void Error(const char * a_Format, va_list a_ArgList) FORMATSTRING(2, 0); - void LogSimple(const char* a_Text, int a_LogType = 0 ); // tolua_export + /** Logs the simple text message at the specified log level. */ + void LogSimple(const char * a_Text, eLogLevel a_LogLevel = llRegular); // tolua_export - static cMCLogger* GetInstance(); + static cMCLogger * GetInstance(); private: enum eColorScheme { @@ -41,6 +52,7 @@ private: cCriticalSection m_CriticalSection; cLog * m_Log; static cMCLogger * s_MCLogger; + bool m_ShouldColorOutput; /// Sets the specified color scheme in the terminal (TODO: if coloring available) diff --git a/src/Map.cpp b/src/Map.cpp index 79370b097..7721baa70 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -614,7 +614,7 @@ unsigned int cMap::GetNumPixels(void) const -unsigned int cMap::GetNumDecorators(void) const +size_t cMap::GetNumDecorators(void) const { return m_Decorators.size(); } @@ -181,7 +181,7 @@ public: // tolua_end - unsigned int GetNumDecorators(void) const; + size_t GetNumDecorators(void) const; const cColorList & GetData(void) const { return m_Data; } diff --git a/src/MapManager.cpp b/src/MapManager.cpp index 9d02eafb4..e7df75118 100644 --- a/src/MapManager.cpp +++ b/src/MapManager.cpp @@ -86,7 +86,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale) return NULL; } - cMap Map(m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale); + cMap Map((unsigned)m_MapData.size(), a_CenterX, a_CenterY, m_World, a_Scale); m_MapData.push_back(Map); @@ -97,7 +97,7 @@ cMap * cMapManager::CreateMap(int a_CenterX, int a_CenterY, int a_Scale) -unsigned int cMapManager::GetNumMaps(void) const +size_t cMapManager::GetNumMaps(void) const { return m_MapData.size(); } @@ -151,7 +151,7 @@ void cMapManager::SaveMapData(void) cIDCountSerializer IDSerializer(m_World->GetName()); - IDSerializer.SetMapCount(m_MapData.size()); + IDSerializer.SetMapCount((unsigned)m_MapData.size()); if (!IDSerializer.Save()) { diff --git a/src/MapManager.h b/src/MapManager.h index 80e6d16d1..ceab8f126 100644 --- a/src/MapManager.h +++ b/src/MapManager.h @@ -53,7 +53,7 @@ public: */ bool ForEachMap(cMapCallback & a_Callback); - unsigned int GetNumMaps(void) const; // tolua_export + size_t GetNumMaps(void) const; // tolua_export /** Loads the map data from the disk */ void LoadMapData(void); diff --git a/src/MobCensus.cpp b/src/MobCensus.cpp index 9c32bf695..23f74b59e 100644 --- a/src/MobCensus.cpp +++ b/src/MobCensus.cpp @@ -64,7 +64,7 @@ void cMobCensus::CollectSpawnableChunk(cChunk & a_Chunk) int cMobCensus::GetNumChunks(void) { - return m_EligibleForSpawnChunks.size(); + return (int)m_EligibleForSpawnChunks.size(); } diff --git a/src/MobFamilyCollecter.cpp b/src/MobFamilyCollecter.cpp index e9c69e078..6da330c83 100644 --- a/src/MobFamilyCollecter.cpp +++ b/src/MobFamilyCollecter.cpp @@ -18,7 +18,7 @@ void cMobFamilyCollecter::CollectMob(cMonster & a_Monster) int cMobFamilyCollecter::GetNumberOfCollectedMobs(cMonster::eFamily a_Family) { - return m_Mobs[a_Family].size(); + return (int)m_Mobs[a_Family].size(); } diff --git a/src/MobProximityCounter.cpp b/src/MobProximityCounter.cpp index 6c44ea458..ce20bf56b 100644 --- a/src/MobProximityCounter.cpp +++ b/src/MobProximityCounter.cpp @@ -24,7 +24,7 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl if (a_Distance < it->second.m_Distance) { it->second.m_Distance = a_Distance; - it->second.m_Chunk = a_Chunk; + it->second.m_Chunk = &a_Chunk; } } @@ -34,9 +34,9 @@ void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, doubl void cMobProximityCounter::convertMaps() { - for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); itr++) + for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); ++itr) { - m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk))); + m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,*itr->second.m_Chunk))); } } @@ -55,7 +55,7 @@ cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDist convertMaps(); } - for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); itr++) + for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); ++itr) { if (toReturn.m_Begin == m_DistanceToMonster.end()) { diff --git a/src/MobProximityCounter.h b/src/MobProximityCounter.h index 8a67139aa..79429eb60 100644 --- a/src/MobProximityCounter.h +++ b/src/MobProximityCounter.h @@ -16,9 +16,9 @@ protected : // structs used for later maps (see m_MonsterToDistance and m_DistanceToMonster) struct sDistanceAndChunk { - sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(a_Chunk) {} + sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(&a_Chunk) {} double m_Distance; - cChunk& m_Chunk; + cChunk* m_Chunk; }; struct sMonsterAndChunk { diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp index a0d0f5c54..de8e01b8a 100644 --- a/src/MobSpawner.cpp +++ b/src/MobSpawner.cpp @@ -13,7 +13,7 @@ cMobSpawner::cMobSpawner(cMonster::eFamily a_MonsterFamily,const std::set<cMonst m_NewPack(true), m_MobType(cMonster::mtInvalidType) { - for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); itr++) + for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); ++itr) { if (cMonster::FamilyFromType(*itr) == a_MonsterFamily) { @@ -104,15 +104,15 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) } } - int allowedMobsSize = allowedMobs.size(); + size_t allowedMobsSize = allowedMobs.size(); if (allowedMobsSize > 0) { std::set<cMonster::eType>::iterator itr = allowedMobs.begin(); - int iRandom = m_Random.NextInt(allowedMobsSize,a_Biome); + int iRandom = m_Random.NextInt((int)allowedMobsSize, a_Biome); - for(int i = 0; i < iRandom; i++) + for (int i = 0; i < iRandom; i++) { - itr++; + ++itr; } return *itr; @@ -129,6 +129,11 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R BLOCKTYPE TargetBlock = E_BLOCK_AIR; if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock)) { + if ((a_RelY + 1 > cChunkDef::Height) || (a_RelY - 1 < 0)) + { + return false; + } + NIBBLETYPE BlockLight = a_Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ); NIBBLETYPE SkyLight = a_Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ); BLOCKTYPE BlockAbove = a_Chunk->GetBlock(a_RelX, a_RelY + 1, a_RelZ); @@ -200,7 +205,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R case cMonster::mtSpider: { bool CanSpawn = true; - bool HaveFloor = false; + bool HasFloor = false; for (int x = 0; x < 2; ++x) { for(int z = 0; z < 2; ++z) @@ -211,8 +216,8 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R { return false; } - HaveFloor = ( - HaveFloor || + HasFloor = ( + HasFloor || ( a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock) && !cBlockInfo::IsTransparent(TargetBlock) @@ -220,7 +225,7 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_R ); } } - return CanSpawn && HaveFloor && (SkyLight <= 7) && (BlockLight <= 7); + return CanSpawn && HasFloor && (SkyLight <= 7) && (BlockLight <= 7); } case cMonster::mtCreeper: diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index 0901f85a9..85b122034 100644 --- a/src/Mobs/AggressiveMonster.cpp +++ b/src/Mobs/AggressiveMonster.cpp @@ -37,7 +37,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt) } } - if (((float)m_FinalDestination.x != (float)m_Target->GetPosX()) || ((float)m_FinalDestination.z != (float)m_Target->GetPosZ())) + if (!IsMovingToTargetPosition()) { MoveToPosition(m_Target->GetPosition()); } @@ -106,3 +106,17 @@ void cAggressiveMonster::Attack(float a_Dt) +bool cAggressiveMonster::IsMovingToTargetPosition() +{ + // Difference between destination x and target x is negligible (to 10^-12 precision) + if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon()) + { + return false; + } + // Difference between destination z and target z is negligible (to 10^-12 precision) + else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon()) + { + return false; + } + return true; +} diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h index 152260f95..d70ff04a3 100644 --- a/src/Mobs/AggressiveMonster.h +++ b/src/Mobs/AggressiveMonster.h @@ -22,6 +22,10 @@ public: virtual void EventSeePlayer(cEntity *) override; virtual void Attack(float a_Dt); +protected: + /** Whether this mob's destination is the same as its target's position. */ + bool IsMovingToTargetPosition(); + } ; diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp index ac42cf40b..326b42f07 100644 --- a/src/Mobs/Blaze.cpp +++ b/src/Mobs/Blaze.cpp @@ -3,6 +3,7 @@ #include "Blaze.h" #include "../World.h" +#include "../Entities/FireChargeEntity.h" @@ -53,4 +54,4 @@ void cBlaze::Attack(float a_Dt) m_AttackInterval = 0.0; // ToDo: Shoot 3 fireballs instead of 1. } -}
\ No newline at end of file +} diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h index cdb3a1306..5970451c7 100644 --- a/src/Mobs/Blaze.h +++ b/src/Mobs/Blaze.h @@ -20,7 +20,3 @@ public: virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; virtual void Attack(float a_Dt) override; } ; - - - - diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt index 87fbfd2fc..53c265803 100644 --- a/src/Mobs/CMakeLists.txt +++ b/src/Mobs/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Mobs ${SOURCE}) diff --git a/src/Mobs/Cavespider.cpp b/src/Mobs/CaveSpider.cpp index 94e93283d..56ecd2d28 100644 --- a/src/Mobs/Cavespider.cpp +++ b/src/Mobs/CaveSpider.cpp @@ -1,15 +1,14 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Cavespider.h" +#include "CaveSpider.h" #include "../World.h" -cCavespider::cCavespider(void) : - super("Cavespider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5) +cCaveSpider::cCaveSpider(void) : + super("CaveSpider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5) { } @@ -17,7 +16,7 @@ cCavespider::cCavespider(void) : -void cCavespider::Tick(float a_Dt, cChunk & a_Chunk) +void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); @@ -29,7 +28,7 @@ void cCavespider::Tick(float a_Dt, cChunk & a_Chunk) -void cCavespider::GetDrops(cItems & a_Drops, cEntity * a_Killer) +void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer) { int LootingLevel = 0; if (a_Killer != NULL) diff --git a/src/Mobs/Cavespider.h b/src/Mobs/CaveSpider.h index 10ea03f7b..be9f174f9 100644 --- a/src/Mobs/Cavespider.h +++ b/src/Mobs/CaveSpider.h @@ -1,4 +1,3 @@ - #pragma once #include "AggressiveMonster.h" @@ -7,13 +6,13 @@ -class cCavespider : +class cCaveSpider : public cAggressiveMonster { typedef cAggressiveMonster super; public: - cCavespider(void); + cCaveSpider(void); CLASS_PROTODEF(cCaveSpider); diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp index 3471b4cf1..9cf539427 100644 --- a/src/Mobs/Creeper.cpp +++ b/src/Mobs/Creeper.cpp @@ -75,9 +75,12 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer) -void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if (a_TDI.DamageType == dtLightning) { @@ -85,6 +88,7 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI) } m_World->BroadcastEntityMetadata(*this); + return true; } diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h index 9abca369b..fc7db6716 100644 --- a/src/Mobs/Creeper.h +++ b/src/Mobs/Creeper.h @@ -18,7 +18,7 @@ public: CLASS_PROTODEF(cCreeper); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Attack(float a_Dt) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void OnRightClicked(cPlayer & a_Player) override; diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp index fe18f5e76..d8a7663f8 100644 --- a/src/Mobs/Ghast.cpp +++ b/src/Mobs/Ghast.cpp @@ -3,6 +3,7 @@ #include "Ghast.h" #include "../World.h" +#include "../Entities/GhastFireballEntity.h" diff --git a/src/Mobs/IncludeAllMonsters.h b/src/Mobs/IncludeAllMonsters.h index 1b436a11f..3460db993 100644 --- a/src/Mobs/IncludeAllMonsters.h +++ b/src/Mobs/IncludeAllMonsters.h @@ -1,6 +1,6 @@ #include "Bat.h" #include "Blaze.h" -#include "Cavespider.h" +#include "CaveSpider.h" #include "Chicken.h" #include "Cow.h" #include "Creeper.h" @@ -10,7 +10,7 @@ #include "Giant.h" #include "Horse.h" #include "IronGolem.h" -#include "Magmacube.h" +#include "MagmaCube.h" #include "Mooshroom.h" #include "Ocelot.h" #include "Pig.h" @@ -26,4 +26,4 @@ #include "Wither.h" #include "Wolf.h" #include "Zombie.h" -#include "Zombiepigman.h" +#include "ZombiePigman.h" diff --git a/src/Mobs/Magmacube.cpp b/src/Mobs/MagmaCube.cpp index 05405f082..3e9abc108 100644 --- a/src/Mobs/Magmacube.cpp +++ b/src/Mobs/MagmaCube.cpp @@ -1,7 +1,6 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Magmacube.h" +#include "MagmaCube.h" diff --git a/src/Mobs/Magmacube.h b/src/Mobs/MagmaCube.h index 130952970..43065cae5 100644 --- a/src/Mobs/Magmacube.h +++ b/src/Mobs/MagmaCube.h @@ -1,4 +1,3 @@ - #pragma once #include "AggressiveMonster.h" diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index d3e0f1c26..a9ca7a2fa 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -111,9 +111,9 @@ void cMonster::SpawnOn(cClientHandle & a_Client) void cMonster::TickPathFinding() { - int PosX = (int)floor(GetPosX()); - int PosY = (int)floor(GetPosY()); - int PosZ = (int)floor(GetPosZ()); + const int PosX = POSX_TOINT; + const int PosY = POSY_TOINT; + const int PosZ = POSZ_TOINT; m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z); @@ -130,14 +130,16 @@ void cMonster::TickPathFinding() { 0, 1}, { 0,-1}, } ; + + if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */) + { + // Too low/high, can't really do anything + FinishPathFinding(); + return; + } for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - if ((gCrossCoords[i].x + PosX == PosX) && (gCrossCoords[i].z + PosZ == PosZ)) - { - continue; - } - if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ))) { continue; @@ -146,13 +148,27 @@ void cMonster::TickPathFinding() BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ); BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ); - BLOCKTYPE BlockAtYM = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY - 1, gCrossCoords[i].z + PosZ); - - if ((!cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE)) + int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ); + BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ); + + if ( + (!cBlockInfo::IsSolid(BlockAtY)) && + (!cBlockInfo::IsSolid(BlockAtYP)) && + (!IsBlockLava(BlockAtLowestY)) && + (BlockAtLowestY != E_BLOCK_CACTUS) && + (PosY - LowestY < FALL_DAMAGE_HEIGHT) + ) { m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ)); } - else if ((cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!cBlockInfo::IsSolid(BlockAtYPP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE)) + else if ( + (cBlockInfo::IsSolid(BlockAtY)) && + (BlockAtY != E_BLOCK_CACTUS) && + (!cBlockInfo::IsSolid(BlockAtYP)) && + (!cBlockInfo::IsSolid(BlockAtYPP)) && + (BlockAtY != E_BLOCK_FENCE) && + (BlockAtY != E_BLOCK_FENCE_GATE) + ) { m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ)); } @@ -339,6 +355,8 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk) InStateEscaping(a_Dt); break; } + + case ATTACKING: break; } // switch (m_EMState) BroadcastMovementUpdate(); @@ -400,7 +418,7 @@ void cMonster::HandleFalling() GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */); } - m_LastGroundHeight = (int)floor(GetPosY()); + m_LastGroundHeight = POSY_TOINT; } } @@ -409,7 +427,7 @@ void cMonster::HandleFalling() int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ) { - int PosY = (int)floor(GetPosY()); + int PosY = POSY_TOINT; if (PosY < 0) PosY = 0; @@ -441,17 +459,23 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ) -void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } - if((m_SoundHurt != "") && (m_Health > 0)) + if (!m_SoundHurt.empty() && (m_Health > 0)) + { m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f); + } if (a_TDI.Attacker != NULL) { m_Target = a_TDI.Attacker; } + return true; } @@ -524,7 +548,10 @@ void cMonster::KilledBy(cEntity * a_Killer) break; } } - m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward); + if ((a_Killer != NULL) && (!IsBaby())) + { + m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward); + } m_DestroyTimer = 0; } @@ -742,8 +769,10 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type) case mtChicken: return mfPassive; case mtCow: return mfPassive; case mtCreeper: return mfHostile; + case mtEnderDragon: return mfNoSpawn; case mtEnderman: return mfHostile; case mtGhast: return mfHostile; + case mtGiant: return mfNoSpawn; case mtHorse: return mfPassive; case mtIronGolem: return mfPassive; case mtMagmaCube: return mfHostile; @@ -754,17 +783,20 @@ cMonster::eFamily cMonster::FamilyFromType(eType a_Type) case mtSilverfish: return mfHostile; case mtSkeleton: return mfHostile; case mtSlime: return mfHostile; + case mtSnowGolem: return mfNoSpawn; case mtSpider: return mfHostile; case mtSquid: return mfWater; case mtVillager: return mfPassive; case mtWitch: return mfHostile; - case mtWither: return mfHostile; + case mtWither: return mfNoSpawn; case mtWolf: return mfHostile; case mtZombie: return mfHostile; case mtZombiePigman: return mfHostile; - } ; + + case mtInvalidType: break; + } ASSERT(!"Unhandled mob type"); - return mfMaxplusone; + return mfUnhandled; } @@ -775,10 +807,12 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily) { switch (a_MobFamily) { - case mfHostile: return 40; - case mfPassive: return 40; - case mfAmbient: return 40; - case mfWater: return 400; + case mfHostile: return 40; + case mfPassive: return 40; + case mfAmbient: return 40; + case mfWater: return 400; + case mfNoSpawn: return -1; + case mfUnhandled: break; } ASSERT(!"Unhandled mob family"); return -1; @@ -797,6 +831,10 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) switch (a_MobType) { case mtMagmaCube: + { + toReturn = new cMagmaCube(Random.NextInt(2) + 1); + break; + } case mtSlime: { toReturn = new cSlime(Random.NextInt(2) + 1); @@ -840,13 +878,14 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType) case mtBat: toReturn = new cBat(); break; case mtBlaze: toReturn = new cBlaze(); break; - case mtCaveSpider: toReturn = new cCavespider(); break; + case mtCaveSpider: toReturn = new cCaveSpider(); break; case mtChicken: toReturn = new cChicken(); break; case mtCow: toReturn = new cCow(); break; case mtCreeper: toReturn = new cCreeper(); break; case mtEnderDragon: toReturn = new cEnderDragon(); break; case mtEnderman: toReturn = new cEnderman(); break; case mtGhast: toReturn = new cGhast(); break; + case mtGiant: toReturn = new cGiant(); break; case mtIronGolem: toReturn = new cIronGolem(); break; case mtMooshroom: toReturn = new cMooshroom(); break; case mtOcelot: toReturn = new cOcelot(); break; @@ -964,15 +1003,15 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) return; } - int RelY = (int)floor(GetPosY()); + int RelY = POSY_TOINT; if ((RelY < 0) || (RelY >= cChunkDef::Height)) { // Outside the world return; } - int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width; - int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width; + int RelX = POSX_TOINT - GetChunkX() * cChunkDef::Width; + int RelZ = POSZ_TOINT - GetChunkZ() * cChunkDef::Width; if (!a_Chunk.IsLightValid()) { @@ -984,7 +1023,8 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime - !IsOnFire() // Not already burning + !IsOnFire() && // Not already burning + (GetWorld()->GetWeather() != eWeather_Rain) // Not raining ) { // Burn for 100 ticks, then decide again diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h index 776426a0d..7d7e90eb2 100644 --- a/src/Mobs/Monster.h +++ b/src/Mobs/Monster.h @@ -66,7 +66,8 @@ public: mfAmbient = 2, // Bats mfWater = 3, // Squid - mfMaxplusone, // Nothing. Be sure this is the last and the others are in order + mfNoSpawn, + mfUnhandled, // Nothing. Be sure this is the last and the others are in order } ; // tolua_end @@ -87,7 +88,7 @@ public: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void KilledBy(cEntity * a_Killer) override; @@ -185,14 +186,14 @@ protected: inline bool IsNextYPosReachable(int a_PosY) { return ( - (a_PosY <= (int)floor(GetPosY())) || + (a_PosY <= POSY_TOINT) || DoesPosYRequireJump(a_PosY) ); } /** Returns if a monster can reach a given height by jumping */ inline bool DoesPosYRequireJump(int a_PosY) { - return ((a_PosY > (int)floor(GetPosY())) && (a_PosY == (int)floor(GetPosY()) + 1)); + return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1)); } /** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */ diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp index 4b45f9a2a..24501b1ba 100644 --- a/src/Mobs/PassiveAggressiveMonster.cpp +++ b/src/Mobs/PassiveAggressiveMonster.cpp @@ -19,9 +19,12 @@ cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigNam -void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if ((m_Target != NULL) && (m_Target->IsPlayer())) { @@ -30,6 +33,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) m_EMState = CHASING; } } + return true; } diff --git a/src/Mobs/PassiveAggressiveMonster.h b/src/Mobs/PassiveAggressiveMonster.h index 2c5ef30b1..a0da50e8e 100644 --- a/src/Mobs/PassiveAggressiveMonster.h +++ b/src/Mobs/PassiveAggressiveMonster.h @@ -15,7 +15,7 @@ class cPassiveAggressiveMonster : public: cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; } ; diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp index 904cd63cc..2861d7314 100644 --- a/src/Mobs/PassiveMonster.cpp +++ b/src/Mobs/PassiveMonster.cpp @@ -18,13 +18,17 @@ cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType, -void cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL)) { m_EMState = ESCAPING; } + return true; } diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h index 0b3c155da..70574585a 100644 --- a/src/Mobs/PassiveMonster.h +++ b/src/Mobs/PassiveMonster.h @@ -18,7 +18,7 @@ public: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /// When hit by someone, run away - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; /** Returns the item that the animal of this class follows when a player holds it in hand Return an empty item not to follow (default). */ virtual const cItem GetFollowedItem(void) const { return cItem(); } diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp index c64360153..5a6b760af 100644 --- a/src/Mobs/Sheep.cpp +++ b/src/Mobs/Sheep.cpp @@ -36,7 +36,8 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer) void cSheep::OnRightClicked(cPlayer & a_Player) { - if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared)) + const cItem & EquippedItem = a_Player.GetEquippedItem(); + if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared)) { m_IsSheared = true; m_World->BroadcastEntityMetadata(*this); @@ -51,9 +52,9 @@ void cSheep::OnRightClicked(cPlayer & a_Player) Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor)); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); } - if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - a_Player.GetEquippedItem().m_ItemDamage)) + else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage)) { - m_WoolColor = 15 - a_Player.GetEquippedItem().m_ItemDamage; + m_WoolColor = 15 - EquippedItem.m_ItemDamage; if (!a_Player.IsGameModeCreative()) { a_Player.GetInventory().RemoveOneEquippedItem(); @@ -101,7 +102,7 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk) { if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) { - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING); + m_World->BroadcastEntityStatus(*this, esSheepEating); m_TimeToStopEating = 40; } } diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp index 47fcdbb26..1e62d7987 100644 --- a/src/Mobs/Skeleton.cpp +++ b/src/Mobs/Skeleton.cpp @@ -3,6 +3,7 @@ #include "Skeleton.h" #include "../World.h" +#include "../Entities/ArrowEntity.h" @@ -88,4 +89,4 @@ void cSkeleton::Attack(float a_Dt) m_World->BroadcastSpawnEntity(*Arrow); m_AttackInterval = 0.0; } -}
\ No newline at end of file +} diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp index bbd8d6aaa..41283acf4 100644 --- a/src/Mobs/Villager.cpp +++ b/src/Mobs/Villager.cpp @@ -23,16 +23,21 @@ cVillager::cVillager(eVillagerType VillagerType) : -void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (!super::DoTakeDamage(a_TDI)) + { + return false; + } + if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer()) { if (m_World->GetTickRandomNumber(5) == 3) { - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY); + m_World->BroadcastEntityStatus(*this, esVillagerAngry); } } + return true; } diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h index 5bba4d4ba..abde48407 100644 --- a/src/Mobs/Villager.h +++ b/src/Mobs/Villager.h @@ -30,7 +30,7 @@ public: CLASS_PROTODEF(cVillager); // cEntity overrides - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick (float a_Dt, cChunk & a_Chunk) override; // cVillager functions diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp index 0e42194ac..170f4fdc0 100644 --- a/src/Mobs/Wither.cpp +++ b/src/Mobs/Wither.cpp @@ -2,7 +2,9 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Wither.h" + #include "../World.h" +#include "../Entities/Player.h" @@ -10,30 +12,54 @@ cWither::cWither(void) : super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0), - m_InvulnerableTicks(220) + m_WitherInvulnerableTicks(220) { SetMaxHealth(300); +} + + + + + +bool cWither::IsArmored(void) const +{ + return GetHealth() <= (GetMaxHealth() / 2); +} + + + + +bool cWither::Initialize(cWorld * a_World) +{ + // Set health before BroadcastSpawnEntity() SetHealth(GetMaxHealth() / 3); + + return super::Initialize(a_World); } -void cWither::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI) { if (a_TDI.DamageType == dtDrowning) { - return; + return false; + } + + if (m_WitherInvulnerableTicks > 0) + { + return false; } - if (m_InvulnerableTicks > 0) + if (IsArmored() && (a_TDI.DamageType == dtRangedAttack)) { - return; + return false; } - super::DoTakeDamage(a_TDI); + return super::DoTakeDamage(a_TDI); } @@ -44,22 +70,24 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk) { super::Tick(a_Dt, a_Chunk); - if (m_InvulnerableTicks > 0) + if (m_WitherInvulnerableTicks > 0) { - unsigned int NewTicks = m_InvulnerableTicks - 1; + unsigned int NewTicks = m_WitherInvulnerableTicks - 1; if (NewTicks == 0) { m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this); } - m_InvulnerableTicks = NewTicks; + m_WitherInvulnerableTicks = NewTicks; if ((NewTicks % 10) == 0) { Heal(10); } } + + m_World->BroadcastEntityMetadata(*this); } @@ -74,3 +102,35 @@ void cWither::GetDrops(cItems & a_Drops, cEntity * a_Killer) + +void cWither::KilledBy(cEntity * a_Killer) +{ + super::KilledBy(a_Killer); + + class cPlayerCallback : public cPlayerListCallback + { + Vector3f m_Pos; + + virtual bool Item(cPlayer * a_Player) + { + // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one + double Dist = (a_Player->GetPosition() - m_Pos).Length(); + if (Dist < 50.0) + { + // If player is close, award achievement + a_Player->AwardAchievement(achKillWither); + } + return false; + } + + public: + cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {} + + } PlayerCallback(GetPosition()); + + m_World->ForEachPlayer(PlayerCallback); +} + + + + diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h index d09e3607a..93b4f8bfc 100644 --- a/src/Mobs/Wither.h +++ b/src/Mobs/Wither.h @@ -17,19 +17,24 @@ public: CLASS_PROTODEF(cWither); - unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; } + unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; } - void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; } + void SetWitherInvulnerableTicks(unsigned int a_Ticks) { m_WitherInvulnerableTicks = a_Ticks; } + + /** Returns whether the wither is invulnerable to arrows. */ + bool IsArmored(void) const; // cEntity overrides + virtual bool Initialize(cWorld * a_World) override; virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; + virtual void KilledBy(cEntity * a_Killer) override; private: /** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */ - unsigned int m_InvulnerableTicks; + unsigned int m_WitherInvulnerableTicks; } ; diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index 0d3619166..e6268abc7 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -25,14 +25,19 @@ cWolf::cWolf(void) : -void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) +bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI) { - super::DoTakeDamage(a_TDI); + if (super::DoTakeDamage(a_TDI)) + { + return false; + } + if (!m_IsTame) { m_IsAngry = true; } m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face + return true; } @@ -75,12 +80,12 @@ void cWolf::OnRightClicked(cPlayer & a_Player) SetMaxHealth(20); SetIsTame(true); SetOwner(a_Player.GetName()); - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED); + m_World->BroadcastEntityStatus(*this, esWolfTamed); m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); } else { - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMING); + m_World->BroadcastEntityStatus(*this, esWolfTaming); m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5); } } diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h index 9e5ad03c7..fb8a7c995 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -18,7 +18,7 @@ public: CLASS_PROTODEF(cWolf); - virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override; virtual void OnRightClicked(cPlayer & a_Player) override; virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void TickFollowPlayer(); @@ -37,7 +37,7 @@ public: void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; } void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; } void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; } - void SetOwner (AString a_NewOwner) { m_OwnerName = a_NewOwner; } + void SetOwner (const AString & a_NewOwner) { m_OwnerName = a_NewOwner; } void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; } protected: diff --git a/src/Mobs/Zombiepigman.cpp b/src/Mobs/ZombiePigman.cpp index a0142b566..c9d94face 100644 --- a/src/Mobs/Zombiepigman.cpp +++ b/src/Mobs/ZombiePigman.cpp @@ -1,7 +1,6 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Zombiepigman.h" +#include "ZombiePigman.h" #include "../World.h" diff --git a/src/Mobs/Zombiepigman.h b/src/Mobs/ZombiePigman.h index 67991d56a..ab3cebf6d 100644 --- a/src/Mobs/Zombiepigman.h +++ b/src/Mobs/ZombiePigman.h @@ -1,4 +1,3 @@ - #pragma once #include "PassiveAggressiveMonster.h" diff --git a/src/MonsterConfig.cpp b/src/MonsterConfig.cpp index c06bd6b6f..72a3a3245 100644 --- a/src/MonsterConfig.cpp +++ b/src/MonsterConfig.cpp @@ -17,6 +17,7 @@ struct cMonsterConfig::sAttributesStruct int m_AttackRange; double m_AttackRate; int m_MaxHealth; + bool m_IsFireproof; }; @@ -72,6 +73,7 @@ void cMonsterConfig::Initialize() Attributes.m_SightDistance = MonstersIniFile.GetValueI(Name, "SightDistance", 0); Attributes.m_AttackRate = MonstersIniFile.GetValueF(Name, "AttackRate", 0); Attributes.m_MaxHealth = MonstersIniFile.GetValueI(Name, "MaxHealth", 1); + Attributes.m_IsFireproof = MonstersIniFile.GetValueB(Name, "IsFireproof", false); m_pState->AttributesList.push_front(Attributes); } // for i - SplitList[] } @@ -92,6 +94,7 @@ void cMonsterConfig::AssignAttributes(cMonster * a_Monster, const AString & a_Na a_Monster->SetSightDistance(itr->m_SightDistance); a_Monster->SetAttackRate ((float)itr->m_AttackRate); a_Monster->SetMaxHealth (itr->m_MaxHealth); + a_Monster->SetIsFireproof (itr->m_IsFireproof); return; } } // for itr - m_pState->AttributesList[] diff --git a/src/Noise.cpp b/src/Noise.cpp index a97ea70c6..89115d992 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -425,7 +425,7 @@ void cCubicCell3D::Move(int a_NewFloorX, int a_NewFloorY, int a_NewFloorZ) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cNoise: -cNoise::cNoise(unsigned int a_Seed) : +cNoise::cNoise(int a_Seed) : m_Seed(a_Seed) { } @@ -608,6 +608,8 @@ void cCubicNoise::Generate2D( NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction ) const { + ASSERT(a_SizeX > 0); + ASSERT(a_SizeY > 0); ASSERT(a_SizeX < MAX_SIZE); ASSERT(a_SizeY < MAX_SIZE); ASSERT(a_StartX < a_EndX); @@ -744,6 +746,8 @@ void cCubicNoise::CalcFloorFrac( int * a_Same, int & a_NumSame ) const { + ASSERT(a_Size > 0); + NOISE_DATATYPE val = a_Start; NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1); for (int i = 0; i < a_Size; i++) @@ -810,7 +814,7 @@ void cPerlinNoise::SetSeed(int a_Seed) void cPerlinNoise::AddOctave(float a_Frequency, float a_Amplitude) { - m_Octaves.push_back(cOctave(m_Seed * (m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude)); + m_Octaves.push_back(cOctave(m_Seed * ((int)m_Octaves.size() + 4) * 4 + 1024, a_Frequency, a_Amplitude)); } @@ -840,12 +844,14 @@ void cPerlinNoise::Generate2D( } // Generate the first octave directly into array: - m_Octaves.front().m_Noise.Generate2D( + const cOctave & FirstOctave = m_Octaves.front(); + + FirstOctave.m_Noise.Generate2D( a_Workspace, a_SizeX, a_SizeY, - a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency, - a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency + a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency, + a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency ); - NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude; + NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude; for (int i = 0; i < ArrayCount; i++) { a_Array[i] *= Amplitude; @@ -902,13 +908,15 @@ void cPerlinNoise::Generate3D( } // Generate the first octave directly into array: - m_Octaves.front().m_Noise.Generate3D( + const cOctave & FirstOctave = m_Octaves.front(); + + FirstOctave.m_Noise.Generate3D( a_Workspace, a_SizeX, a_SizeY, a_SizeZ, - a_StartX * m_Octaves.front().m_Frequency, a_EndX * m_Octaves.front().m_Frequency, - a_StartY * m_Octaves.front().m_Frequency, a_EndY * m_Octaves.front().m_Frequency, - a_StartZ * m_Octaves.front().m_Frequency, a_EndZ * m_Octaves.front().m_Frequency + a_StartX * FirstOctave.m_Frequency, a_EndX * FirstOctave.m_Frequency, + a_StartY * FirstOctave.m_Frequency, a_EndY * FirstOctave.m_Frequency, + a_StartZ * FirstOctave.m_Frequency, a_EndZ * FirstOctave.m_Frequency ); - NOISE_DATATYPE Amplitude = m_Octaves.front().m_Amplitude; + NOISE_DATATYPE Amplitude = FirstOctave.m_Amplitude; for (int i = 0; i < ArrayCount; i++) { a_Array[i] = a_Workspace[i] * Amplitude; diff --git a/src/Noise.h b/src/Noise.h index ea72c64e9..e605051b5 100644 --- a/src/Noise.h +++ b/src/Noise.h @@ -25,7 +25,7 @@ class cNoise { public: - cNoise(unsigned int a_Seed); + cNoise(int a_Seed); cNoise(const cNoise & a_Noise); // The following functions, if not marked INLINE, are about 20 % slower @@ -47,14 +47,14 @@ public: NOISE_DATATYPE CubicNoise3D (NOISE_DATATYPE a_X, NOISE_DATATYPE a_Y, NOISE_DATATYPE a_Z) const; - void SetSeed(unsigned int a_Seed) { m_Seed = a_Seed; } + void SetSeed(int a_Seed) { m_Seed = a_Seed; } INLINE static NOISE_DATATYPE CubicInterpolate (NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_C, NOISE_DATATYPE a_D, NOISE_DATATYPE a_Pct); INLINE static NOISE_DATATYPE CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct); INLINE static NOISE_DATATYPE LinearInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct); private: - unsigned int m_Seed; + int m_Seed; } ; @@ -280,7 +280,7 @@ NOISE_DATATYPE cNoise::CubicInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE cNoise::CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct) { const NOISE_DATATYPE ft = a_Pct * (NOISE_DATATYPE)3.1415927; - const NOISE_DATATYPE f = (1 - cos(ft)) * (NOISE_DATATYPE)0.5; + const NOISE_DATATYPE f = (NOISE_DATATYPE)((NOISE_DATATYPE)(1 - cos(ft)) * (NOISE_DATATYPE)0.5); return a_A * (1 - f) + a_B * f; } diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp deleted file mode 100644 index 07f48b955..000000000 --- a/src/OSSupport/BlockingTCPLink.cpp +++ /dev/null @@ -1,142 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "BlockingTCPLink.h" -#include "Errors.h" - - - - -cBlockingTCPLink::cBlockingTCPLink(void) -{ -} - - - - - -cBlockingTCPLink::~cBlockingTCPLink() -{ - CloseSocket(); -} - - - - - -void cBlockingTCPLink::CloseSocket() -{ - if (!m_Socket.IsValid()) - { - m_Socket.CloseSocket(); - } -} - - - - - -bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort) -{ - ASSERT(!m_Socket.IsValid()); - if (m_Socket.IsValid()) - { - LOGWARN("WARNING: cTCPLink Connect() called while still connected."); - m_Socket.CloseSocket(); - } - - struct hostent *hp; - unsigned int addr; - struct sockaddr_in server; - - m_Socket = socket(AF_INET, SOCK_STREAM, 0); - if (!m_Socket.IsValid()) - { - LOGERROR("cTCPLink: Cannot create a socket"); - return false; - } - - addr = inet_addr(iAddress); - hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); - if (hp == NULL) - { - //LOGWARN("cTCPLink: gethostbyaddr returned NULL"); - hp = gethostbyname(iAddress); - if (hp == NULL) - { - LOGWARN("cTCPLink: Could not resolve %s", iAddress); - CloseSocket(); - return false; - } - } - - memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length); - server.sin_family = AF_INET; - server.sin_port = htons( (unsigned short)iPort); - if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server))) - { - LOGWARN("cTCPLink: Connection to \"%s:%d\" failed (%s)", iAddress, iPort,GetOSErrorString( cSocket::GetLastError() ).c_str() ); - CloseSocket(); - return false; - } - - return true; -} - - - - - -int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ ) -{ - UNUSED(a_Flags); - - ASSERT(m_Socket.IsValid()); - if (!m_Socket.IsValid()) - { - LOGERROR("cBlockingTCPLink: Trying to send data without a valid connection!"); - return -1; - } - return m_Socket.Send(a_Data, a_Size); -} - - - - - -int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ ) -{ - UNUSED(a_Flags); - - ASSERT(m_Socket.IsValid()); - if (!m_Socket.IsValid()) - { - LOGWARN("cBlockingTCPLink: Trying to send message without a valid connection!"); - return -1; - } - return m_Socket.Send(a_Message, strlen(a_Message)); -} - - - - - -void cBlockingTCPLink::ReceiveData(AString & oData) -{ - ASSERT(m_Socket.IsValid()); - if (!m_Socket.IsValid()) - { - return; - } - - int Received = 0; - char Buffer[256]; - while ((Received = recv(m_Socket, Buffer, sizeof(Buffer), 0)) > 0) - { - oData.append(Buffer, Received); - } -} - - - - diff --git a/src/OSSupport/BlockingTCPLink.h b/src/OSSupport/BlockingTCPLink.h deleted file mode 100644 index cb5f9e3f4..000000000 --- a/src/OSSupport/BlockingTCPLink.h +++ /dev/null @@ -1,28 +0,0 @@ - -#pragma once - -#include "Socket.h" - - - - - -class cBlockingTCPLink // tolua_export -{ // tolua_export -public: // tolua_export - cBlockingTCPLink(void); // tolua_export - ~cBlockingTCPLink(); // tolua_export - - bool Connect( const char* a_Address, unsigned int a_Port ); // tolua_export - int Send( char* a_Data, unsigned int a_Size, int a_Flags = 0 ); // tolua_export - int SendMessage( const char* a_Message, int a_Flags = 0 ); // tolua_export - void CloseSocket(); // tolua_export - void ReceiveData(AString & oData); // tolua_export -protected: - - cSocket m_Socket; -}; // tolua_export - - - - diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt index 497cd0ba3..dee60b450 100644 --- a/src/OSSupport/CMakeLists.txt +++ b/src/OSSupport/CMakeLists.txt @@ -5,6 +5,7 @@ project (MCServer) include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(OSSupport ${SOURCE}) diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp index 2e05f1df1..6072b6ac6 100644 --- a/src/OSSupport/Errors.cpp +++ b/src/OSSupport/Errors.cpp @@ -22,7 +22,7 @@ AString GetOSErrorString( int a_ErrNo ) // According to http://linux.die.net/man/3/strerror_r there are two versions of strerror_r(): - #if ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r() + #if !defined(__APPLE__) && ( _GNU_SOURCE ) && !defined(ANDROID_NDK) // GNU version of strerror_r() char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer) ); if( res != NULL ) diff --git a/src/OSSupport/File.cpp b/src/OSSupport/File.cpp index 17070030f..8c24fa541 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -67,15 +67,15 @@ bool cFile::Open(const AString & iFileName, eMode iMode) case fmRead: Mode = "rb"; break; case fmWrite: Mode = "wb"; break; case fmReadWrite: Mode = "rb+"; break; - default: - { - ASSERT(!"Unhandled file mode"); - return false; - } + } + if (Mode == NULL) + { + ASSERT(!"Unhandled file mode"); + return false; } #ifdef _WIN32 - fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), Mode); + m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR); #else m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode); #endif // _WIN32 @@ -88,7 +88,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode) // Simply re-open for read-writing, erasing existing contents: #ifdef _WIN32 - fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), "wb+"); + m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+", _SH_DENYWR); #else m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+"); #endif // _WIN32 @@ -143,7 +143,7 @@ bool cFile::IsEOF(void) const -int cFile::Read (void * iBuffer, int iNumBytes) +int cFile::Read (void * iBuffer, size_t iNumBytes) { ASSERT(IsOpen()); @@ -152,14 +152,14 @@ int cFile::Read (void * iBuffer, int iNumBytes) return -1; } - return fread(iBuffer, 1, iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count + return (int)fread(iBuffer, 1, (size_t)iNumBytes, m_File); // fread() returns the portion of Count parameter actually read, so we need to send iNumBytes as Count } -int cFile::Write(const void * iBuffer, int iNumBytes) +int cFile::Write(const void * iBuffer, size_t iNumBytes) { ASSERT(IsOpen()); @@ -168,7 +168,7 @@ int cFile::Write(const void * iBuffer, int iNumBytes) return -1; } - int res = fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count + int res = (int)fwrite(iBuffer, 1, (size_t)iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count return res; } @@ -189,7 +189,7 @@ int cFile::Seek (int iPosition) { return -1; } - return ftell(m_File); + return (int)ftell(m_File); } @@ -206,7 +206,7 @@ int cFile::Tell (void) const return -1; } - return ftell(m_File); + return (int)ftell(m_File); } @@ -222,7 +222,7 @@ int cFile::GetSize(void) const return -1; } - int CurPos = ftell(m_File); + int CurPos = Tell(); if (CurPos < 0) { return -1; @@ -231,8 +231,8 @@ int cFile::GetSize(void) const { return -1; } - int res = ftell(m_File); - if (fseek(m_File, CurPos, SEEK_SET) != 0) + int res = Tell(); + if (fseek(m_File, (long)CurPos, SEEK_SET) != 0) { return -1; } @@ -255,7 +255,7 @@ int cFile::ReadRestOfFile(AString & a_Contents) int DataSize = GetSize() - Tell(); // HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly - a_Contents.assign(DataSize, '\0'); + a_Contents.assign((size_t)DataSize, '\0'); return Read((void *)a_Contents.data(), DataSize); } @@ -350,7 +350,7 @@ int cFile::GetSize(const AString & a_FileName) struct stat st; if (stat(a_FileName.c_str(), &st) == 0) { - return st.st_size; + return (int)st.st_size; } return -1; } @@ -456,7 +456,7 @@ int cFile::Printf(const char * a_Fmt, ...) va_start(args, a_Fmt); AppendVPrintf(buf, a_Fmt, args); va_end(args); - return Write(buf.c_str(), buf.length()); + return Write(buf.c_str(), (int)buf.length()); } diff --git a/src/OSSupport/File.h b/src/OSSupport/File.h index b394c5cb9..2a7ecf0ed 100644 --- a/src/OSSupport/File.h +++ b/src/OSSupport/File.h @@ -80,10 +80,10 @@ public: bool IsEOF(void) const; /** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */ - int Read (void * iBuffer, int iNumBytes); + int Read (void * iBuffer, size_t iNumBytes); /** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */ - int Write(const void * iBuffer, int iNumBytes); + int Write(const void * iBuffer, size_t iNumBytes); /** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */ int Seek (int iPosition); diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp index b13e519e0..22d887783 100644 --- a/src/OSSupport/GZipFile.cpp +++ b/src/OSSupport/GZipFile.cpp @@ -11,7 +11,7 @@ cGZipFile::cGZipFile(void) : - m_File(NULL) + m_File(NULL), m_Mode(fmRead) { } @@ -78,7 +78,7 @@ int cGZipFile::ReadRestOfFile(AString & a_Contents) while ((NumBytesRead = gzread(m_File, Buffer, sizeof(Buffer))) > 0) { TotalBytes += NumBytesRead; - a_Contents.append(Buffer, NumBytesRead); + a_Contents.append(Buffer, (size_t)NumBytesRead); } // NumBytesRead is < 0 on error return (NumBytesRead >= 0) ? TotalBytes : NumBytesRead; @@ -102,7 +102,7 @@ bool cGZipFile::Write(const char * a_Contents, int a_Size) return false; } - return (gzwrite(m_File, a_Contents, a_Size) != 0); + return (gzwrite(m_File, a_Contents, (unsigned int)a_Size) != 0); } diff --git a/src/OSSupport/IsThread.cpp b/src/OSSupport/IsThread.cpp index 36205bcf1..04fc818e4 100644 --- a/src/OSSupport/IsThread.cpp +++ b/src/OSSupport/IsThread.cpp @@ -18,26 +18,33 @@ // Usage: SetThreadName (-1, "MainThread"); // -static void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName) +// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + +const DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) +typedef struct tagTHREADNAME_INFO { - struct - { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero - } info; - + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1 = caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +static void SetThreadName(DWORD dwThreadID, const char * threadName) +{ + THREADNAME_INFO info; info.dwType = 0x1000; - info.szName = szThreadName; + info.szName = threadName; info.dwThreadID = dwThreadID; info.dwFlags = 0; __try { - RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (DWORD *)&info); + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); } - __except(EXCEPTION_CONTINUE_EXECUTION) + __except (EXCEPTION_EXECUTE_HANDLER) { } } diff --git a/src/OSSupport/IsThread.h b/src/OSSupport/IsThread.h index 42b8bfdda..57651a490 100644 --- a/src/OSSupport/IsThread.h +++ b/src/OSSupport/IsThread.h @@ -62,7 +62,7 @@ protected: HANDLE m_Handle; - static DWORD_PTR __stdcall thrExecute(LPVOID a_Param) + static DWORD __stdcall thrExecute(LPVOID a_Param) { // Create a window so that the thread can be identified by 3rd party tools: HWND IdentificationWnd = CreateWindow("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL); diff --git a/src/OSSupport/ListenThread.cpp b/src/OSSupport/ListenThread.cpp index ba3198764..02e98acfc 100644 --- a/src/OSSupport/ListenThread.cpp +++ b/src/OSSupport/ListenThread.cpp @@ -214,7 +214,7 @@ void cListenThread::Execute(void) timeval tv; // On Linux select() doesn't seem to wake up when socket is closed, so let's kinda busy-wait: tv.tv_sec = 1; tv.tv_usec = 0; - if (select(Highest + 1, &fdRead, NULL, NULL, &tv) == -1) + if (select((int)Highest + 1, &fdRead, NULL, NULL, &tv) == -1) { LOG("select(R) call failed in cListenThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; diff --git a/src/OSSupport/Sleep.h b/src/OSSupport/Sleep.h index 5298c15da..0ec0adf9d 100644 --- a/src/OSSupport/Sleep.h +++ b/src/OSSupport/Sleep.h @@ -4,4 +4,4 @@ class cSleep { public: static void MilliSleep( unsigned int a_MilliSeconds ); -};
\ No newline at end of file +}; diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp index c29e495c3..56835b518 100644 --- a/src/OSSupport/Socket.cpp +++ b/src/OSSupport/Socket.cpp @@ -295,7 +295,7 @@ bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port) bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port) { - // First try IP Address string to hostent conversion, because it's faster + // First try IP Address string to hostent conversion, because it's faster and local: unsigned long addr = inet_addr(a_HostNameOrAddr.c_str()); if (addr == INADDR_NONE) { @@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por CloseSocket(); return false; } - // Should be optimised to a single word copy memcpy(&addr, hp->h_addr, hp->h_length); } + // If the socket is not created yet, create one: + if (!IsValid()) + { + m_Socket = socket((int)IPv4, SOCK_STREAM, 0); + } + + // Connect the socket: sockaddr_in server; server.sin_addr.s_addr = addr; server.sin_family = AF_INET; @@ -322,18 +328,18 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por -int cSocket::Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags) +int cSocket::Receive(char * a_Buffer, size_t a_Length, unsigned int a_Flags) { - return recv(m_Socket, a_Buffer, a_Length, a_Flags); + return recv(m_Socket, a_Buffer, (int)a_Length, a_Flags); } -int cSocket::Send(const char * a_Buffer, unsigned int a_Length) +int cSocket::Send(const char * a_Buffer, size_t a_Length) { - return send(m_Socket, a_Buffer, a_Length, MSG_NOSIGNAL); + return send(m_Socket, a_Buffer, (int)a_Length, MSG_NOSIGNAL); } diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h index bdc2babf5..35ecadfa0 100644 --- a/src/OSSupport/Socket.h +++ b/src/OSSupport/Socket.h @@ -110,8 +110,8 @@ public: /// Connects to the specified host or string IP address and port, using IPv4. Returns true if successful. bool ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port); - int Receive(char * a_Buffer, unsigned int a_Length, unsigned int a_Flags); - int Send (const char * a_Buffer, unsigned int a_Length); + int Receive(char * a_Buffer, size_t a_Length, unsigned int a_Flags); + int Send (const char * a_Buffer, size_t a_Length); unsigned short GetPort(void) const; // Returns 0 on failure diff --git a/src/OSSupport/SocketThreads.cpp b/src/OSSupport/SocketThreads.cpp index 0bc1d6b55..0ab5b6298 100644 --- a/src/OSSupport/SocketThreads.cpp +++ b/src/OSSupport/SocketThreads.cpp @@ -406,7 +406,7 @@ void cSocketThreads::cSocketThread::Execute(void) timeval Timeout; Timeout.tv_sec = 5; Timeout.tv_usec = 0; - if (select(Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1) + if (select((int)Highest + 1, &fdRead, &fdWrite, NULL, &Timeout) == -1) { LOG("select() call failed in cSocketThread: \"%s\"", cSocket::GetLastErrorString().c_str()); continue; diff --git a/src/OSSupport/SocketThreads.h b/src/OSSupport/SocketThreads.h index b2eb5950f..944f5f3bc 100644 --- a/src/OSSupport/SocketThreads.h +++ b/src/OSSupport/SocketThreads.h @@ -63,8 +63,10 @@ public: // Force a virtual destructor in all subclasses: virtual ~cCallback() {} - /** Called when data is received from the remote party */ - virtual void DataReceived(const char * a_Data, int a_Size) = 0; + /** Called when data is received from the remote party. + SocketThreads does not care about the return value, others can use it for their specific purpose - + for example HTTPServer uses it to signal if the connection was terminated as a result of the data received. */ + virtual bool DataReceived(const char * a_Data, size_t a_Size) = 0; /** Called when data can be sent to remote party The function is supposed to *set* outgoing data to a_Data (overwrite) */ diff --git a/src/OSSupport/Thread.cpp b/src/OSSupport/Thread.cpp index 3df75f0e7..7a10ef8d2 100644 --- a/src/OSSupport/Thread.cpp +++ b/src/OSSupport/Thread.cpp @@ -10,27 +10,34 @@ // // Usage: SetThreadName (-1, "MainThread"); // + +// Code adapted from MSDN: http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + +const DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) typedef struct tagTHREADNAME_INFO { - DWORD dwType; // must be 0x1000 - LPCSTR szName; // pointer to name (in user addr space) - DWORD dwThreadID; // thread ID (-1=caller thread) - DWORD dwFlags; // reserved for future use, must be zero + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1 = caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. } THREADNAME_INFO; +#pragma pack(pop) -void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName) +static void SetThreadName(DWORD dwThreadID, const char * threadName) { THREADNAME_INFO info; info.dwType = 0x1000; - info.szName = szThreadName; + info.szName = threadName; info.dwThreadID = dwThreadID; info.dwFlags = 0; __try { - RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info ); + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR *)&info); } - __except(EXCEPTION_CONTINUE_EXECUTION) + __except (EXCEPTION_EXECUTE_HANDLER) { } } diff --git a/src/OSSupport/Thread.h b/src/OSSupport/Thread.h index 3c9316424..4153b2427 100644 --- a/src/OSSupport/Thread.h +++ b/src/OSSupport/Thread.h @@ -23,4 +23,4 @@ private: cEvent* m_StopEvent; AString m_ThreadName; -};
\ No newline at end of file +}; diff --git a/src/PolarSSL++/AesCfb128Decryptor.cpp b/src/PolarSSL++/AesCfb128Decryptor.cpp new file mode 100644 index 000000000..af0d5106e --- /dev/null +++ b/src/PolarSSL++/AesCfb128Decryptor.cpp @@ -0,0 +1,67 @@ + +// AesCfb128Decryptor.cpp + +// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128 + +#include "Globals.h" +#include "AesCfb128Decryptor.h" + + + + + +cAesCfb128Decryptor::cAesCfb128Decryptor(void) : + m_IVOffset(0), + m_IsValid(false) +{ +} + + + + + +cAesCfb128Decryptor::~cAesCfb128Decryptor() +{ + // Clear the leftover in-memory data, so that they can't be accessed by a backdoor + memset(&m_Aes, 0, sizeof(m_Aes)); +} + + + + + +void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) +{ + ASSERT(!IsValid()); // Cannot Init twice + + memcpy(m_IV, a_IV, 16); + aes_setkey_enc(&m_Aes, a_Key, 128); + m_IsValid = true; +} + + + + + +void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length) +{ + ASSERT(IsValid()); // Must Init() first + + // PolarSSL doesn't support AES-CFB8, need to implement it manually: + for (size_t i = 0; i < a_Length; i++) + { + Byte Buffer[sizeof(m_IV)]; + aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer); + for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++) + { + m_IV[idx] = m_IV[idx + 1]; + } + m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i]; + a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0]; + } +} + + + + + diff --git a/src/PolarSSL++/AesCfb128Decryptor.h b/src/PolarSSL++/AesCfb128Decryptor.h new file mode 100644 index 000000000..68c203d70 --- /dev/null +++ b/src/PolarSSL++/AesCfb128Decryptor.h @@ -0,0 +1,52 @@ + +// AesCfb128Decryptor.h + +// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128 + + + + + +#pragma once + +#include "polarssl/aes.h" + + + + + +/** Decrypts data using the AES / CFB 128 algorithm */ +class cAesCfb128Decryptor +{ +public: + Byte test; + + cAesCfb128Decryptor(void); + ~cAesCfb128Decryptor(); + + /** Initializes the decryptor with the specified Key / IV */ + void Init(const Byte a_Key[16], const Byte a_IV[16]); + + /** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */ + void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length); + + /** Returns true if the object has been initialized with the Key / IV */ + bool IsValid(void) const { return m_IsValid; } + +protected: + aes_context m_Aes; + + /** The InitialVector, used by the CFB mode decryption */ + Byte m_IV[16]; + + /** Current offset in the m_IV, used by the CFB mode decryption */ + size_t m_IVOffset; + + /** Indicates whether the object has been initialized with the Key / IV */ + bool m_IsValid; +} ; + + + + + diff --git a/src/PolarSSL++/AesCfb128Encryptor.cpp b/src/PolarSSL++/AesCfb128Encryptor.cpp new file mode 100644 index 000000000..a641ad48e --- /dev/null +++ b/src/PolarSSL++/AesCfb128Encryptor.cpp @@ -0,0 +1,68 @@ + +// AesCfb128Encryptor.cpp + +// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128 + +#include "Globals.h" +#include "AesCfb128Encryptor.h" + + + + + +cAesCfb128Encryptor::cAesCfb128Encryptor(void) : + m_IVOffset(0), + m_IsValid(false) +{ +} + + + + + +cAesCfb128Encryptor::~cAesCfb128Encryptor() +{ + // Clear the leftover in-memory data, so that they can't be accessed by a backdoor + memset(&m_Aes, 0, sizeof(m_Aes)); +} + + + + + +void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16]) +{ + ASSERT(!IsValid()); // Cannot Init twice + ASSERT(m_IVOffset == 0); + + memcpy(m_IV, a_IV, 16); + aes_setkey_enc(&m_Aes, a_Key, 128); + m_IsValid = true; +} + + + + + +void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length) +{ + ASSERT(IsValid()); // Must Init() first + + // PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves: + for (size_t i = 0; i < a_Length; i++) + { + Byte Buffer[sizeof(m_IV)]; + aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer); + for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++) + { + m_IV[idx] = m_IV[idx + 1]; + } + a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0]; + m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i]; + } +} + + + + + diff --git a/src/PolarSSL++/AesCfb128Encryptor.h b/src/PolarSSL++/AesCfb128Encryptor.h new file mode 100644 index 000000000..9dbb5d2c3 --- /dev/null +++ b/src/PolarSSL++/AesCfb128Encryptor.h @@ -0,0 +1,50 @@ + +// AesCfb128Encryptor.h + +// Declares the cAesCfb128Encryptor class encrypting data using AES CFB-128 + + + + + +#pragma once + +#include "polarssl/aes.h" + + + + + +/** Encrypts data using the AES / CFB (128) algorithm */ +class cAesCfb128Encryptor +{ +public: + cAesCfb128Encryptor(void); + ~cAesCfb128Encryptor(); + + /** Initializes the decryptor with the specified Key / IV */ + void Init(const Byte a_Key[16], const Byte a_IV[16]); + + /** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */ + void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length); + + /** Returns true if the object has been initialized with the Key / IV */ + bool IsValid(void) const { return m_IsValid; } + +protected: + aes_context m_Aes; + + /** The InitialVector, used by the CFB mode encryption */ + Byte m_IV[16]; + + /** Current offset in the m_IV, used by the CFB mode encryption */ + size_t m_IVOffset; + + /** Indicates whether the object has been initialized with the Key / IV */ + bool m_IsValid; +} ; + + + + + diff --git a/src/PolarSSL++/BlockingSslClientSocket.cpp b/src/PolarSSL++/BlockingSslClientSocket.cpp new file mode 100644 index 000000000..699bc57ee --- /dev/null +++ b/src/PolarSSL++/BlockingSslClientSocket.cpp @@ -0,0 +1,195 @@ + +// BlockingSslClientSocket.cpp + +// Implements the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it + +#include "Globals.h" +#include "BlockingSslClientSocket.h" + + + + + +cBlockingSslClientSocket::cBlockingSslClientSocket(void) : + m_Ssl(*this), + m_IsConnected(false) +{ + // Nothing needed yet +} + + + + + +bool cBlockingSslClientSocket::Connect(const AString & a_ServerName, UInt16 a_Port) +{ + // If already connected, report an error: + if (m_IsConnected) + { + // TODO: Handle this better - if connected to the same server and port, and the socket is alive, return success + m_LastErrorText = "Already connected"; + return false; + } + + // Connect the underlying socket: + m_Socket.CreateSocket(cSocket::IPv4); + if (!m_Socket.ConnectIPv4(a_ServerName.c_str(), a_Port)) + { + Printf(m_LastErrorText, "Socket connect failed: %s", m_Socket.GetLastErrorString().c_str()); + return false; + } + + // Initialize the SSL: + int ret = m_Ssl.Initialize(true); + if (ret != 0) + { + Printf(m_LastErrorText, "SSL initialization failed: -0x%x", -ret); + return false; + } + + // If we have been assigned a trusted CA root cert store, push it into the SSL context: + if (m_CACerts.get() != NULL) + { + m_Ssl.SetCACerts(m_CACerts, m_ExpectedPeerName); + } + + ret = m_Ssl.Handshake(); + if (ret != 0) + { + Printf(m_LastErrorText, "SSL handshake failed: -0x%x", -ret); + return false; + } + + m_IsConnected = true; + return true; +} + + + + + + +bool cBlockingSslClientSocket::SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName) +{ + // Warn if used multiple times, but don't signal an error: + if (m_CACerts.get() != NULL) + { + LOGWARNING( + "SSL: Trying to set multiple trusted CA root cert stores, only the last one will be used. Name: %s", + a_ExpectedPeerName.c_str() + ); + } + + // Parse the cert: + m_CACerts.reset(new cX509Cert); + int ret = m_CACerts->Parse(a_CACerts.data(), a_CACerts.size()); + if (ret < 0) + { + Printf(m_LastErrorText, "CA cert parsing failed: -0x%x", -ret); + return false; + } + m_ExpectedPeerName = a_ExpectedPeerName; + + return true; +} + + + + + +bool cBlockingSslClientSocket::Send(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(m_IsConnected); + + // Keep sending the data until all of it is sent: + const char * Data = (const char *)a_Data; + size_t NumBytes = a_NumBytes; + for (;;) + { + int res = m_Ssl.WritePlain(a_Data, a_NumBytes); + if (res < 0) + { + ASSERT(res != POLARSSL_ERR_NET_WANT_READ); // This should never happen with callback-based SSL + ASSERT(res != POLARSSL_ERR_NET_WANT_WRITE); // This should never happen with callback-based SSL + Printf(m_LastErrorText, "Data cannot be written to SSL context: -0x%x", -res); + return false; + } + else + { + Data += res; + NumBytes -= res; + if (NumBytes == 0) + { + return true; + } + } + } +} + + + + + + +int cBlockingSslClientSocket::Receive(void * a_Data, size_t a_MaxBytes) +{ + ASSERT(m_IsConnected); + + int res = m_Ssl.ReadPlain(a_Data, a_MaxBytes); + if (res < 0) + { + Printf(m_LastErrorText, "Data cannot be read form SSL context: -0x%x", -res); + } + return res; +} + + + + + +void cBlockingSslClientSocket::Disconnect(void) +{ + // Ignore if not connected + if (!m_IsConnected) + { + return; + } + + m_Ssl.NotifyClose(); + m_Socket.CloseSocket(); + m_IsConnected = false; +} + + + + + +int cBlockingSslClientSocket::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) +{ + int res = m_Socket.Receive((char *)a_Buffer, a_NumBytes, 0); + if (res < 0) + { + // PolarSSL's net routines distinguish between connection reset and general failure, we don't need to + return POLARSSL_ERR_NET_RECV_FAILED; + } + return res; +} + + + + + +int cBlockingSslClientSocket::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) +{ + int res = m_Socket.Send((const char *)a_Buffer, a_NumBytes); + if (res < 0) + { + // PolarSSL's net routines distinguish between connection reset and general failure, we don't need to + return POLARSSL_ERR_NET_SEND_FAILED; + } + return res; +} + + + + diff --git a/src/PolarSSL++/BlockingSslClientSocket.h b/src/PolarSSL++/BlockingSslClientSocket.h new file mode 100644 index 000000000..7af897582 --- /dev/null +++ b/src/PolarSSL++/BlockingSslClientSocket.h @@ -0,0 +1,80 @@ + +// BlockingSslClientSocket.h + +// Declares the cBlockingSslClientSocket class representing a blocking TCP socket with client SSL encryption over it + + + + + +#pragma once + +#include "CallbackSslContext.h" +#include "../OSSupport/Socket.h" + + + + + +class cBlockingSslClientSocket : + protected cCallbackSslContext::cDataCallbacks +{ +public: + cBlockingSslClientSocket(void); + + /** Connects to the specified server and performs SSL handshake. + Returns true if successful, false on failure. Sets internal error text on failure. */ + bool Connect(const AString & a_ServerName, UInt16 a_Port); + + /** Sends the specified data over the connection. + Returns true if successful, false on failure. Sets the internal error text on failure. */ + bool Send(const void * a_Data, size_t a_NumBytes); + + /** Receives data from the connection. + Blocks until there is any data available, then returns as much as possible. + Returns the number of bytes actually received, negative number on failure. + Sets the internal error text on failure. */ + int Receive(void * a_Data, size_t a_MaxBytes); + + /** Disconnects the connection gracefully, if possible. + Note that this also frees the internal SSL context, so all the certificates etc. are lost. */ + void Disconnect(void); + + /** Sets the root certificates that are to be trusted. Forces the connection to use strict cert + verification. Needs to be used before calling Connect(). + a_ExpectedPeerName is the name that we expect to receive in the SSL peer's cert; verification will fail if + the presented name is different (possible MITM). + Returns true on success, false on failure. Sets internal error text on failure. */ + bool SetTrustedRootCertsFromString(const AString & a_CACerts, const AString & a_ExpectedPeerName); + + /** Returns the text of the last error that has occurred in this instance. */ + const AString & GetLastErrorText(void) const { return m_LastErrorText; } + +protected: + /** The SSL context used for the socket */ + cCallbackSslContext m_Ssl; + + /** The underlying socket to the SSL server */ + cSocket m_Socket; + + /** The trusted CA root cert store, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */ + cX509CertPtr m_CACerts; + + /** The expected SSL peer's name, if we are to verify the cert strictly. Set by SetTrustedRootCertsFromString(). */ + AString m_ExpectedPeerName; + + /** Text of the last error that has occurred. */ + AString m_LastErrorText; + + /** Set to true if the connection established successfully. */ + bool m_IsConnected; + + + // cCallbackSslContext::cDataCallbacks overrides: + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; +} ; + + + + diff --git a/src/PolarSSL++/BufferedSslContext.cpp b/src/PolarSSL++/BufferedSslContext.cpp new file mode 100644 index 000000000..9f7caeb8a --- /dev/null +++ b/src/PolarSSL++/BufferedSslContext.cpp @@ -0,0 +1,93 @@ + +// BufferedSslContext.cpp + +// Implements the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer + +#include "Globals.h" +#include "BufferedSslContext.h" + + + + + +cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize): + m_OutgoingData(a_BufferSize), + m_IncomingData(a_BufferSize) +{ +} + + + + + +size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes) +{ + size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes); + if (NumBytes > 0) + { + m_IncomingData.Write(a_Data, NumBytes); + return NumBytes; + } + return 0; +} + + + + + +size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize) +{ + size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize); + if (NumBytes > 0) + { + m_OutgoingData.ReadBuf(a_Data, NumBytes); + m_OutgoingData.CommitRead(); + return NumBytes; + } + return 0; +} + + + + + +int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) +{ + // Called when PolarSSL wants to read encrypted data from the SSL peer + // Read the data from the buffer inside this object, where the owner has stored them using WriteIncoming(): + size_t NumBytes = std::min(a_NumBytes, m_IncomingData.GetReadableSpace()); + if (NumBytes == 0) + { + return POLARSSL_ERR_NET_WANT_READ; + } + if (!m_IncomingData.ReadBuf(a_Buffer, NumBytes)) + { + m_IncomingData.ResetRead(); + return POLARSSL_ERR_NET_RECV_FAILED; + } + m_IncomingData.CommitRead(); + return (int)NumBytes; +} + + + + + +int cBufferedSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) +{ + // Called when PolarSSL wants to write encrypted data to the SSL peer + // Write the data into the buffer inside this object, where the owner can later read them using ReadOutgoing(): + if (!m_OutgoingData.CanWriteBytes(a_NumBytes)) + { + return POLARSSL_ERR_NET_WANT_WRITE; + } + if (!m_OutgoingData.Write((const char *)a_Buffer, a_NumBytes)) + { + return POLARSSL_ERR_NET_SEND_FAILED; + } + return (int)a_NumBytes; +} + + + + diff --git a/src/PolarSSL++/BufferedSslContext.h b/src/PolarSSL++/BufferedSslContext.h new file mode 100644 index 000000000..1b7e1af46 --- /dev/null +++ b/src/PolarSSL++/BufferedSslContext.h @@ -0,0 +1,52 @@ + +// BufferedSslContext.h + +// Declares the cBufferedSslContext class representing a SSL context with the SSL peer data backed by a cByteBuffer + + + + + +#pragma once + +#include "SslContext.h" + + + + + +class cBufferedSslContext : + public cSslContext +{ + typedef cSslContext super; + +public: + /** Creates a new context with the buffers of specified size for the encrypted / decrypted data. */ + cBufferedSslContext(size_t a_BufferSize = 64000); + + /** Stores the specified data in the "incoming" buffer, to be process by the SSL decryptor. + This is the data received from the SSL peer. + Returns the number of bytes actually stored. If 0 is returned, owner should check the error state. */ + size_t WriteIncoming(const void * a_Data, size_t a_NumBytes); + + /** Retrieves data from the "outgoing" buffer, after being processed by the SSL encryptor. + This is the data to be sent to the SSL peer. + Returns the number of bytes actually retrieved. */ + size_t ReadOutgoing(void * a_Data, size_t a_DataMaxSize); + +protected: + /** Buffer for the data that has been encrypted into the SSL stream and should be sent out. */ + cByteBuffer m_OutgoingData; + + /** Buffer for the data that has come in and needs to be decrypted from the SSL stream. */ + cByteBuffer m_IncomingData; + + + // cSslContext overrides: + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; +} ; + + + + diff --git a/src/PolarSSL++/CMakeLists.txt b/src/PolarSSL++/CMakeLists.txt new file mode 100644 index 000000000..9a59cdb2c --- /dev/null +++ b/src/PolarSSL++/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required (VERSION 2.6) +project (MCServer) + +include_directories ("${PROJECT_SOURCE_DIR}/../") + +set(SOURCES + AesCfb128Decryptor.cpp + AesCfb128Encryptor.cpp + BlockingSslClientSocket.cpp + BufferedSslContext.cpp + CallbackSslContext.cpp + CtrDrbgContext.cpp + CryptoKey.cpp + EntropyContext.cpp + RsaPrivateKey.cpp + Sha1Checksum.cpp + SslContext.cpp + X509Cert.cpp +) + +set(HEADERS + AesCfb128Decryptor.h + AesCfb128Encryptor.h + BlockingSslClientSocket.h + BufferedSslContext.h + CallbackSslContext.h + CtrDrbgContext.h + CryptoKey.h + EntropyContext.h + RsaPrivateKey.h + SslContext.h + Sha1Checksum.h + X509Cert.h +) + +add_library(PolarSSL++ ${SOURCES} ${HEADERS}) + +if (UNIX) + target_link_libraries(PolarSSL++ polarssl) +endif() diff --git a/src/PolarSSL++/CallbackSslContext.cpp b/src/PolarSSL++/CallbackSslContext.cpp new file mode 100644 index 000000000..0cc88a14a --- /dev/null +++ b/src/PolarSSL++/CallbackSslContext.cpp @@ -0,0 +1,59 @@ + +// CallbackSslContext.cpp + +// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data + +#include "Globals.h" +#include "CallbackSslContext.h" + + + + + + +cCallbackSslContext::cCallbackSslContext(void) +{ + // Nothing needed, but the constructor needs to exist so +} + + + + + +cCallbackSslContext::cCallbackSslContext(cCallbackSslContext::cDataCallbacks & a_Callbacks) : + m_Callbacks(&a_Callbacks) +{ +} + + + + + +int cCallbackSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) +{ + if (m_Callbacks == NULL) + { + LOGWARNING("SSL: Trying to receive data with no callbacks, aborting."); + return POLARSSL_ERR_NET_RECV_FAILED; + } + return m_Callbacks->ReceiveEncrypted(a_Buffer, a_NumBytes); +} + + + + + +int cCallbackSslContext::SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) +{ + if (m_Callbacks == NULL) + { + LOGWARNING("SSL: Trying to send data with no callbacks, aborting."); + return POLARSSL_ERR_NET_SEND_FAILED; + } + return m_Callbacks->SendEncrypted(a_Buffer, a_NumBytes); +} + + + + + diff --git a/src/PolarSSL++/CallbackSslContext.h b/src/PolarSSL++/CallbackSslContext.h new file mode 100644 index 000000000..3e6edc5f4 --- /dev/null +++ b/src/PolarSSL++/CallbackSslContext.h @@ -0,0 +1,64 @@ + +// CallbackSslContext.h + +// Declares the cCallbackSslContext class representing a SSL context wrapper that uses callbacks to read and write SSL peer data + + + + + +#pragma once + +#include "SslContext.h" + + + + + +class cCallbackSslContext : + public cSslContext +{ +public: + /** Interface used as a data sink for the SSL peer data. */ + class cDataCallbacks + { + public: + // Force a virtual destructor in descendants: + virtual ~cDataCallbacks() {} + + /** Called when PolarSSL wants to read encrypted data from the SSL peer. + The returned value is the number of bytes received, or a PolarSSL error on failure. + The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate + that there's currently no more data and that there might be more data in the future. In such cases the + SSL operation that invoked this call will terminate with the same return value, so that the owner is + notified of this condition and can potentially restart the operation later on. */ + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0; + + /** Called when PolarSSL wants to write encrypted data to the SSL peer. + The returned value is the number of bytes sent, or a PolarSSL error on failure. + The implementation can return POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE to indicate + that there's currently no more data and that there might be more data in the future. In such cases the + SSL operation that invoked this call will terminate with the same return value, so that the owner is + notified of this condition and can potentially restart the operation later on. */ + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0; + } ; + + + /** Creates a new SSL context with no callbacks assigned */ + cCallbackSslContext(void); + + /** Creates a new SSL context with the specified callbacks */ + cCallbackSslContext(cDataCallbacks & a_Callbacks); + +protected: + /** The callbacks to use to send and receive SSL peer data */ + cDataCallbacks * m_Callbacks; + + // cSslContext overrides: + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) override; + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) override; +}; + + + + diff --git a/src/PolarSSL++/CryptoKey.cpp b/src/PolarSSL++/CryptoKey.cpp new file mode 100644 index 000000000..0763c387b --- /dev/null +++ b/src/PolarSSL++/CryptoKey.cpp @@ -0,0 +1,149 @@ + +// CryptoKey.cpp + +// Implements the cCryptoKey class representing a RSA public key in PolarSSL + +#include "Globals.h" +#include "CryptoKey.h" + + + + + +cCryptoKey::cCryptoKey(void) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); +} + + + + + +cCryptoKey::cCryptoKey(const AString & a_PublicKeyData) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); + int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); + if (res != 0) + { + LOGWARNING("Failed to parse public key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_privkey", 11); + int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); + if (res != 0) + { + LOGWARNING("Failed to parse private key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cCryptoKey::~cCryptoKey() +{ + pk_free(&m_Pk); +} + + + + + +int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) +{ + ASSERT(IsValid()); + + size_t DecryptedLen = a_DecryptedMaxLength; + int res = pk_decrypt(&m_Pk, + a_EncryptedData, a_EncryptedLength, + a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength, + ctr_drbg_random, m_CtrDrbg.GetInternal() + ); + if (res != 0) + { + return res; + } + return (int)DecryptedLen; +} + + + + + +int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) +{ + ASSERT(IsValid()); + + size_t EncryptedLength = a_EncryptedMaxLength; + int res = pk_encrypt(&m_Pk, + a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, + ctr_drbg_random, m_CtrDrbg.GetInternal() + ); + if (res != 0) + { + return res; + } + return (int)EncryptedLength; +} + + + + + + +int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes); +} + + + + + + +int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + if (a_Password.empty()) + { + return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0); + } + else + { + return pk_parse_key( + &m_Pk, + (const unsigned char *)a_Data, a_NumBytes, + (const unsigned char *)a_Password.c_str(), a_Password.size() + ); + } +} + + + + + +bool cCryptoKey::IsValid(void) const +{ + return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE); +} + + + + diff --git a/src/PolarSSL++/CryptoKey.h b/src/PolarSSL++/CryptoKey.h new file mode 100644 index 000000000..9c298e501 --- /dev/null +++ b/src/PolarSSL++/CryptoKey.h @@ -0,0 +1,76 @@ + +// CryptoKey.h + +// Declares the cCryptoKey class representing a RSA public key in PolarSSL + + + + + +#pragma once + +#include "CtrDrbgContext.h" +#include "polarssl/pk.h" + + + + + +class cCryptoKey +{ + friend class cSslContext; + +public: + /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ + cCryptoKey(void); + + /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ + cCryptoKey(const AString & a_PublicKeyData); + + /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. + If a_Password is empty, no password is assumed. */ + cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password); + + ~cCryptoKey(); + + /** Decrypts the data using the stored public key + Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); + + /** Encrypts the data using the stored public key + Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + + /** Parses the specified data into a public key representation. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePublic(const void * a_Data, size_t a_NumBytes); + + /** Parses the specified data into a private key representation. + If a_Password is empty, no password is assumed. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); + + /** Returns true if the contained key is valid. */ + bool IsValid(void) const; + +protected: + /** The PolarSSL representation of the key data */ + pk_context m_Pk; + + /** The random generator used in encryption and decryption */ + cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + pk_context * GetInternal(void) { return &m_Pk; } +} ; + +typedef SharedPtr<cCryptoKey> cCryptoKeyPtr; + + + + diff --git a/src/PolarSSL++/CtrDrbgContext.cpp b/src/PolarSSL++/CtrDrbgContext.cpp new file mode 100644 index 000000000..86e6d1ca5 --- /dev/null +++ b/src/PolarSSL++/CtrDrbgContext.cpp @@ -0,0 +1,49 @@ + +// CtrDrbgContext.cpp + +// Implements the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL + +#include "Globals.h" +#include "CtrDrbgContext.h" +#include "EntropyContext.h" + + + + + +cCtrDrbgContext::cCtrDrbgContext(void) : + m_EntropyContext(new cEntropyContext), + m_IsValid(false) +{ +} + + + + + +cCtrDrbgContext::cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext) : + m_EntropyContext(a_EntropyContext), + m_IsValid(false) +{ +} + + + + + +int cCtrDrbgContext::Initialize(const void * a_Custom, size_t a_CustomSize) +{ + if (m_IsValid) + { + // Already initialized + return 0; + } + + int res = ctr_drbg_init(&m_CtrDrbg, entropy_func, &(m_EntropyContext->m_Entropy), (const unsigned char *)a_Custom, a_CustomSize); + m_IsValid = (res == 0); + return res; +} + + + + diff --git a/src/PolarSSL++/CtrDrbgContext.h b/src/PolarSSL++/CtrDrbgContext.h new file mode 100644 index 000000000..230db8753 --- /dev/null +++ b/src/PolarSSL++/CtrDrbgContext.h @@ -0,0 +1,63 @@ + +// CtrDrbgContext.h + +// Declares the cCtrDrbgContext class representing a wrapper over CTR-DRBG implementation in PolarSSL + + + + + +#pragma once + +#include "polarssl/ctr_drbg.h" + + + + + +// fwd: EntropyContext.h +class cEntropyContext; + + + + + +class cCtrDrbgContext +{ + friend class cSslContext; + friend class cRsaPrivateKey; + friend class cCryptoKey; + +public: + /** Constructs the context with a new entropy context. */ + cCtrDrbgContext(void); + + /** Constructs the context with the specified entropy context. */ + cCtrDrbgContext(const SharedPtr<cEntropyContext> & a_EntropyContext); + + /** Initializes the context. + a_Custom is optional additional data to use for entropy, nullptr is accepted. + Returns 0 if successful, PolarSSL error code on failure. */ + int Initialize(const void * a_Custom, size_t a_CustomSize); + + /** Returns true if the object is valid (has been initialized properly) */ + bool IsValid(void) const { return m_IsValid; } + +protected: + /** The entropy source used for generating the random */ + SharedPtr<cEntropyContext> m_EntropyContext; + + /** The random generator context */ + ctr_drbg_context m_CtrDrbg; + + /** Set to true if the object is valid (has been initialized properly) */ + bool m_IsValid; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + ctr_drbg_context * GetInternal(void) { return &m_CtrDrbg; } +} ; + + + + diff --git a/src/PolarSSL++/EntropyContext.cpp b/src/PolarSSL++/EntropyContext.cpp new file mode 100644 index 000000000..9c59b3f11 --- /dev/null +++ b/src/PolarSSL++/EntropyContext.cpp @@ -0,0 +1,29 @@ + +// EntropyContext.cpp + +// Implements the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL + +#include "Globals.h" +#include "EntropyContext.h" + + + + + +cEntropyContext::cEntropyContext(void) +{ + entropy_init(&m_Entropy); +} + + + + + +cEntropyContext::~cEntropyContext() +{ + entropy_free(&m_Entropy); +} + + + + diff --git a/src/PolarSSL++/EntropyContext.h b/src/PolarSSL++/EntropyContext.h new file mode 100644 index 000000000..bc7fff066 --- /dev/null +++ b/src/PolarSSL++/EntropyContext.h @@ -0,0 +1,31 @@ + +// EntropyContext.h + +// Declares the cEntropyContext class representing a wrapper over entropy contexts in PolarSSL + + + + + +#pragma once + +#include "polarssl/entropy.h" + + + + + +class cEntropyContext +{ + friend class cCtrDrbgContext; +public: + cEntropyContext(void); + ~cEntropyContext(); + +protected: + entropy_context m_Entropy; +} ; + + + + diff --git a/src/PolarSSL++/RsaPrivateKey.cpp b/src/PolarSSL++/RsaPrivateKey.cpp new file mode 100644 index 000000000..2d5a2a4b1 --- /dev/null +++ b/src/PolarSSL++/RsaPrivateKey.cpp @@ -0,0 +1,176 @@ + +// RsaPrivateKey.cpp + +#include "Globals.h" +#include "RsaPrivateKey.h" +#include "CtrDrbgContext.h" +#include "polarssl/pk.h" + + + + + + +cRsaPrivateKey::cRsaPrivateKey(void) +{ + rsa_init(&m_Rsa, RSA_PKCS_V15, 0); + m_CtrDrbg.Initialize("RSA", 3); +} + + + + + +cRsaPrivateKey::cRsaPrivateKey(const cRsaPrivateKey & a_Other) +{ + rsa_init(&m_Rsa, RSA_PKCS_V15, 0); + rsa_copy(&m_Rsa, &a_Other.m_Rsa); + m_CtrDrbg.Initialize("RSA", 3); +} + + + + + +cRsaPrivateKey::~cRsaPrivateKey() +{ + rsa_free(&m_Rsa); +} + + + + + +bool cRsaPrivateKey::Generate(unsigned a_KeySizeBits) +{ + int res = rsa_gen_key(&m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), a_KeySizeBits, 65537); + if (res != 0) + { + LOG("RSA key generation failed: -0x%x", -res); + return false; + } + + return true; +} + + + + + +AString cRsaPrivateKey::GetPubKeyDER(void) +{ + class cPubKey + { + public: + cPubKey(rsa_context * a_Rsa) : + m_IsValid(false) + { + pk_init(&m_Key); + if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0) + { + ASSERT(!"Cannot init PrivKey context"); + return; + } + if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0) + { + ASSERT(!"Cannot copy PrivKey to PK context"); + return; + } + m_IsValid = true; + } + + ~cPubKey() + { + if (m_IsValid) + { + pk_free(&m_Key); + } + } + + operator pk_context * (void) { return &m_Key; } + + protected: + bool m_IsValid; + pk_context m_Key; + } PkCtx(&m_Rsa); + + unsigned char buf[3000]; + int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf)); + if (res < 0) + { + return AString(); + } + return AString((const char *)(buf + sizeof(buf) - res), (size_t)res); +} + + + + + +int cRsaPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) +{ + if (a_EncryptedLength < m_Rsa.len) + { + LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u", + __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len) + ); + ASSERT(!"Invalid a_DecryptedMaxLength!"); + return -1; + } + if (a_DecryptedMaxLength < m_Rsa.len) + { + LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u", + __FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len) + ); + ASSERT(!"Invalid a_DecryptedMaxLength!"); + return -1; + } + size_t DecryptedLength; + int res = rsa_pkcs1_decrypt( + &m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, &DecryptedLength, + a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength + ); + if (res != 0) + { + return -1; + } + return (int)DecryptedLength; +} + + + + + +int cRsaPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) +{ + if (a_EncryptedMaxLength < m_Rsa.len) + { + LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u", + __FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len) + ); + ASSERT(!"Invalid a_DecryptedMaxLength!"); + return -1; + } + if (a_PlainLength < m_Rsa.len) + { + LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u", + __FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len) + ); + ASSERT(!"Invalid a_PlainLength!"); + return -1; + } + int res = rsa_pkcs1_encrypt( + &m_Rsa, ctr_drbg_random, m_CtrDrbg.GetInternal(), RSA_PRIVATE, + a_PlainLength, a_PlainData, a_EncryptedData + ); + if (res != 0) + { + return -1; + } + return (int)m_Rsa.len; +} + + + + + diff --git a/src/PolarSSL++/RsaPrivateKey.h b/src/PolarSSL++/RsaPrivateKey.h new file mode 100644 index 000000000..4d03f27df --- /dev/null +++ b/src/PolarSSL++/RsaPrivateKey.h @@ -0,0 +1,67 @@ + +// RsaPrivateKey.h + +// Declares the cRsaPrivateKey class representing a private key for RSA operations. + + + + + +#pragma once + +#include "CtrDrbgContext.h" +#include "polarssl/rsa.h" + + + + + +/** Encapsulates an RSA private key used in PKI cryptography */ +class cRsaPrivateKey +{ + friend class cSslContext; + +public: + /** Creates a new empty object, the key is not assigned */ + cRsaPrivateKey(void); + + /** Deep-copies the key from a_Other */ + cRsaPrivateKey(const cRsaPrivateKey & a_Other); + + ~cRsaPrivateKey(); + + /** Generates a new key within this object, with the specified size in bits. + Returns true on success, false on failure. */ + bool Generate(unsigned a_KeySizeBits = 1024); + + /** Returns the public key part encoded in ASN1 DER encoding */ + AString GetPubKeyDER(void); + + /** Decrypts the data using RSAES-PKCS#1 algorithm. + Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength); + + /** Encrypts the data using RSAES-PKCS#1 algorithm. + Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large. + Returns the number of bytes decrypted, or negative number for error. */ + int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + +protected: + /** The PolarSSL key context */ + rsa_context m_Rsa; + + /** The random generator used for generating the key and encryption / decryption */ + cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + rsa_context * GetInternal(void) { return &m_Rsa; } +} ; + +typedef SharedPtr<cRsaPrivateKey> cRsaPrivateKeyPtr; + + + + + diff --git a/src/PolarSSL++/Sha1Checksum.cpp b/src/PolarSSL++/Sha1Checksum.cpp new file mode 100644 index 000000000..a1ee9d7b9 --- /dev/null +++ b/src/PolarSSL++/Sha1Checksum.cpp @@ -0,0 +1,138 @@ + +// Sha1Checksum.cpp + +// Declares the cSha1Checksum class representing the SHA-1 checksum calculator + +#include "Globals.h" +#include "Sha1Checksum.h" + + + + + +/* +// Self-test the hash formatting for known values: +// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48 +// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1 +// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6 + +static class Test +{ +public: + Test(void) + { + AString DigestNotch, DigestJeb, DigestSimon; + Byte Digest[20]; + cSha1Checksum Checksum; + Checksum.Update((const Byte *)"Notch", 5); + Checksum.Finalize(Digest); + cSha1Checksum::DigestToJava(Digest, DigestNotch); + Checksum.Restart(); + Checksum.Update((const Byte *)"jeb_", 4); + Checksum.Finalize(Digest); + cSha1Checksum::DigestToJava(Digest, DigestJeb); + Checksum.Restart(); + Checksum.Update((const Byte *)"simon", 5); + Checksum.Finalize(Digest); + cSha1Checksum::DigestToJava(Digest, DigestSimon); + printf("Notch: \"%s\"\n", DigestNotch.c_str()); + printf("jeb_: \"%s\"\n", DigestJeb.c_str()); + printf("simon: \"%s\"\n", DigestSimon.c_str()); + assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48"); + assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1"); + assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6"); + } +} test; +*/ + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSha1Checksum: + +cSha1Checksum::cSha1Checksum(void) : + m_DoesAcceptInput(true) +{ + sha1_starts(&m_Sha1); +} + + + + + +void cSha1Checksum::Update(const Byte * a_Data, size_t a_Length) +{ + ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed + + sha1_update(&m_Sha1, a_Data, a_Length); +} + + + + + +void cSha1Checksum::Finalize(cSha1Checksum::Checksum & a_Output) +{ + ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed + + sha1_finish(&m_Sha1, a_Output); + m_DoesAcceptInput = false; +} + + + + + +void cSha1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out) +{ + Checksum Digest; + memcpy(Digest, a_Digest, sizeof(Digest)); + + bool IsNegative = (Digest[0] >= 0x80); + if (IsNegative) + { + // Two's complement: + bool carry = true; // Add one to the whole number + for (int i = 19; i >= 0; i--) + { + Digest[i] = ~Digest[i]; + if (carry) + { + carry = (Digest[i] == 0xff); + Digest[i]++; + } + } + } + a_Out.clear(); + a_Out.reserve(40); + for (int i = 0; i < 20; i++) + { + AppendPrintf(a_Out, "%02x", Digest[i]); + } + while ((a_Out.length() > 0) && (a_Out[0] == '0')) + { + a_Out.erase(0, 1); + } + if (IsNegative) + { + a_Out.insert(0, "-"); + } +} + + + + + + +void cSha1Checksum::Restart(void) +{ + sha1_starts(&m_Sha1); + m_DoesAcceptInput = true; +} + + + + diff --git a/src/PolarSSL++/Sha1Checksum.h b/src/PolarSSL++/Sha1Checksum.h new file mode 100644 index 000000000..68fdbcf1b --- /dev/null +++ b/src/PolarSSL++/Sha1Checksum.h @@ -0,0 +1,52 @@ + +// Sha1Checksum.h + +// Declares the cSha1Checksum class representing the SHA-1 checksum calculator + + + + + +#pragma once + +#include "polarssl/sha1.h" + + + + + +/** Calculates a SHA1 checksum for data stream */ +class cSha1Checksum +{ +public: + typedef Byte Checksum[20]; // The type used for storing the checksum + + cSha1Checksum(void); + + /** Adds the specified data to the checksum */ + void Update(const Byte * a_Data, size_t a_Length); + + /** Calculates and returns the final checksum */ + void Finalize(Checksum & a_Output); + + /** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ + bool DoesAcceptInput(void) const { return m_DoesAcceptInput; } + + /** Converts a raw 160-bit SHA1 digest into a Java Hex representation + According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802 + */ + static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut); + + /** Clears the current context and start a new checksum calculation */ + void Restart(void); + +protected: + /** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */ + bool m_DoesAcceptInput; + + sha1_context m_Sha1; +} ; + + + + diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp new file mode 100644 index 000000000..c3074f197 --- /dev/null +++ b/src/PolarSSL++/SslContext.cpp @@ -0,0 +1,303 @@ + +// SslContext.cpp + +// Implements the cSslContext class that holds everything a single SSL context needs to function + +#include "Globals.h" +#include "SslContext.h" +#include "EntropyContext.h" +#include "CtrDrbgContext.h" + + + + + +cSslContext::cSslContext(void) : + m_IsValid(false), + m_HasHandshaken(false) +{ +} + + + + + +cSslContext::~cSslContext() +{ + if (m_IsValid) + { + ssl_free(&m_Ssl); + } +} + + + + + +int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg) +{ + // Check double-initialization: + if (m_IsValid) + { + LOGWARNING("SSL: Double initialization is not supported."); + return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one. + } + + // Set the CtrDrbg context, create a new one if needed: + m_CtrDrbg = a_CtrDrbg; + if (m_CtrDrbg.get() == NULL) + { + m_CtrDrbg.reset(new cCtrDrbgContext); + m_CtrDrbg->Initialize("MCServer", 8); + } + + // Initialize PolarSSL's structures: + memset(&m_Ssl, 0, sizeof(m_Ssl)); + int res = ssl_init(&m_Ssl); + if (res != 0) + { + return res; + } + ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER); + ssl_set_authmode(&m_Ssl, a_IsClient ? SSL_VERIFY_OPTIONAL : SSL_VERIFY_NONE); // Clients ask for server's cert but don't verify strictly; servers don't ask clients for certs by default + ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg); + ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this); + + #ifdef _DEBUG + /* + // These functions allow us to debug SSL and certificate problems, but produce way too much output, + // so they're disabled until someone needs them + ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this); + ssl_set_verify(&m_Ssl, &SSLVerifyCert, this); + */ + + /* + // Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded: + static const int CipherSuites[] = + { + TLS_RSA_WITH_RC4_128_MD5, + TLS_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_AES_128_CBC_SHA, + 0, // Must be 0-terminated! + }; + ssl_set_ciphersuites(&m_Ssl, CipherSuites); + */ + #endif + + m_IsValid = true; + return 0; +} + + + + + +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Check that both the cert and the key is valid: + if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + { + LOGWARNING("SSL: Own certificate is not valid, skipping the set."); + return; + } + + // Make sure we have the cert stored for later, PolarSSL only uses the cert later on + m_OwnCert = a_OwnCert; + m_OwnCertPrivKey = a_OwnCertPrivKey; + + // Set into the context: + ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal()); +} + + + + + +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Check that both the cert and the key is valid: + if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + { + LOGWARNING("SSL: Own certificate is not valid, skipping the set."); + return; + } + + // Make sure we have the cert stored for later, PolarSSL only uses the cert later on + m_OwnCert = a_OwnCert; + m_OwnCertPrivKey2 = a_OwnCertPrivKey; + + // Set into the context: + ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal()); +} + + + + + +void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Store the data in our internal buffers, to avoid losing the pointers later on + // PolarSSL will need these after this call returns, and the caller may move / delete the data before that: + m_ExpectedPeerName = a_ExpectedPeerName; + m_CACerts = a_CACert; + + // Set the trusted CA root cert store: + ssl_set_authmode(&m_Ssl, SSL_VERIFY_REQUIRED); + ssl_set_ca_chain(&m_Ssl, m_CACerts->GetInternal(), NULL, m_ExpectedPeerName.empty() ? NULL : m_ExpectedPeerName.c_str()); +} + + + + + +int cSslContext::WritePlain(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(m_IsValid); // Need to call Initialize() first + if (!m_HasHandshaken) + { + int res = Handshake(); + if (res != 0) + { + return res; + } + } + + return ssl_write(&m_Ssl, (const unsigned char *)a_Data, a_NumBytes); +} + + + + + +int cSslContext::ReadPlain(void * a_Data, size_t a_MaxBytes) +{ + ASSERT(m_IsValid); // Need to call Initialize() first + if (!m_HasHandshaken) + { + int res = Handshake(); + if (res != 0) + { + return res; + } + } + + return ssl_read(&m_Ssl, (unsigned char *)a_Data, a_MaxBytes); +} + + + + + +int cSslContext::Handshake(void) +{ + ASSERT(m_IsValid); // Need to call Initialize() first + ASSERT(!m_HasHandshaken); // Must not call twice + + int res = ssl_handshake(&m_Ssl); + if (res == 0) + { + m_HasHandshaken = true; + } + return res; +} + + + + + +int cSslContext::NotifyClose(void) +{ + return ssl_close_notify(&m_Ssl); +} + + + + + +#ifdef _DEBUG + void cSslContext::SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text) + { + if (a_Level > 3) + { + // Don't want the trace messages + return; + } + + // Remove the terminating LF: + size_t len = strlen(a_Text) - 1; + while ((len > 0) && (a_Text[len] <= 32)) + { + len--; + } + AString Text(a_Text, len + 1); + + LOGD("SSL (%d): %s", a_Level, Text.c_str()); + } + + + + + + int cSslContext::SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags) + { + char buf[1024]; + UNUSED(a_This); + + LOG("Verify requested for (Depth %d):", a_Depth); + x509_crt_info(buf, sizeof(buf) - 1, "", a_Crt); + LOG("%s", buf); + + int Flags = *a_Flags; + if ((Flags & BADCERT_EXPIRED) != 0) + { + LOG(" ! server certificate has expired"); + } + + if ((Flags & BADCERT_REVOKED) != 0) + { + LOG(" ! server certificate has been revoked"); + } + + if ((Flags & BADCERT_CN_MISMATCH) != 0) + { + LOG(" ! CN mismatch"); + } + + if ((Flags & BADCERT_NOT_TRUSTED) != 0) + { + LOG(" ! self-signed or not signed by a trusted CA"); + } + + if ((Flags & BADCRL_NOT_TRUSTED) != 0) + { + LOG(" ! CRL not trusted"); + } + + if ((Flags & BADCRL_EXPIRED) != 0) + { + LOG(" ! CRL expired"); + } + + if ((Flags & BADCERT_OTHER) != 0) + { + LOG(" ! other (unknown) flag"); + } + + if (Flags == 0) + { + LOG(" This certificate has no flags"); + } + + return 0; + } +#endif // _DEBUG + + + + diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h new file mode 100644 index 000000000..6b4f2c1e7 --- /dev/null +++ b/src/PolarSSL++/SslContext.h @@ -0,0 +1,156 @@ + +// SslContext.h + +// Declares the cSslContext class that holds everything a single SSL context needs to function + + + + + +#pragma once + +#include "polarssl/ssl.h" +#include "../ByteBuffer.h" +#include "CryptoKey.h" +#include "RsaPrivateKey.h" +#include "X509Cert.h" + + + + + +// fwd: +class cCtrDrbgContext; + + + + + +/** +Acts as a generic SSL encryptor / decryptor between the two endpoints. The "owner" of this class is expected +to create it, initialize it and then provide the means of reading and writing data through the SSL link. +This is an abstract base class, there are descendants that handle the specific aspects of how the SSL peer +data comes into the system: + - cBufferedSslContext uses a cByteBuffer to read and write the data + - cCallbackSslContext uses callbacks to provide the data +*/ +class cSslContext abstract +{ +public: + /** Creates a new uninitialized context */ + cSslContext(void); + + virtual ~cSslContext(); + + /** Initializes the context for use as a server or client. + Returns 0 on success, PolarSSL error on failure. */ + int Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> & a_CtrDrbg = SharedPtr<cCtrDrbgContext>()); + + /** Returns true if the object has been initialized properly. */ + bool IsValid(void) const { return m_IsValid; } + + /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. + Must be called after Initialize(). */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey); + + /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. + Must be called after Initialize(). */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey); + + /** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize(). + Calling this will switch the context into strict cert verification mode. + a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert, + if it is different, the verification will fail. An empty string will disable the CN check. */ + void SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName); + + /** Writes data to be encrypted and sent to the SSL peer. Will perform SSL handshake, if needed. + Returns the number of bytes actually written, or PolarSSL error code. + If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any + cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call + this function again with the same parameters. Note that this may repeat a few times before the data is + actually written, mainly due to initial handshake. */ + int WritePlain(const void * a_Data, size_t a_NumBytes); + + /** Reads data decrypted from the SSL stream. Will perform SSL handshake, if needed. + Returns the number of bytes actually read, or PolarSSL error code. + If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any + cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call + this function again with the same parameters. Note that this may repeat a few times before the data is + actually read, mainly due to initial handshake. */ + int ReadPlain(void * a_Data, size_t a_MaxBytes); + + /** Performs the SSL handshake. + Returns zero on success, PoladSSL error code on failure. + If the return value is POLARSSL_ERR_NET_WANT_READ or POLARSSL_ERR_NET_WANT_WRITE, the owner should send any + cached outgoing data to the SSL peer and write any incoming data received from the SSL peer and then call + this function again. Note that this may repeat a few times before the handshake is completed. */ + int Handshake(void); + + /** Returns true if the SSL handshake has been completed. */ + bool HasHandshaken(void) const { return m_HasHandshaken; } + + /** Notifies the SSL peer that the connection is being closed. + Returns 0 on success, PolarSSL error code on failure. */ + int NotifyClose(void); + +protected: + /** True if the object has been initialized properly. */ + bool m_IsValid; + + /** The random generator to use */ + SharedPtr<cCtrDrbgContext> m_CtrDrbg; + + /** The SSL context that PolarSSL uses. */ + ssl_context m_Ssl; + + /** The certificate that we present to the peer. */ + cX509CertPtr m_OwnCert; + + /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey. */ + cRsaPrivateKeyPtr m_OwnCertPrivKey; + + /** Private key for m_OwnCert, if initialized from a cCryptoKey. */ + cCryptoKeyPtr m_OwnCertPrivKey2; + + /** True if the SSL handshake has been completed. */ + bool m_HasHandshaken; + + /** A copy of the trusted CA root cert store that is passed to us in SetCACerts(), so that the pointer + stays valid even after the call, when PolarSSL finally uses it. */ + cX509CertPtr m_CACerts; + + /** Buffer for the expected peer name. We need to buffer it because the caller may free the string they + give us before PolarSSL consumes the raw pointer it gets to the CN. */ + AString m_ExpectedPeerName; + + + /** The callback used by PolarSSL when it wants to read encrypted data. */ + static int ReceiveEncrypted(void * a_This, unsigned char * a_Buffer, size_t a_NumBytes) + { + return ((cSslContext *)a_This)->ReceiveEncrypted(a_Buffer, a_NumBytes); + } + + /** The callback used by PolarSSL when it wants to write encrypted data. */ + static int SendEncrypted(void * a_This, const unsigned char * a_Buffer, size_t a_NumBytes) + { + return ((cSslContext *)a_This)->SendEncrypted(a_Buffer, a_NumBytes); + } + + #ifdef _DEBUG + /** The callback used by PolarSSL to output debug messages */ + static void SSLDebugMessage(void * a_UserParam, int a_Level, const char * a_Text); + + /** The callback used by PolarSSL to log information on the cert chain */ + static int SSLVerifyCert(void * a_This, x509_crt * a_Crt, int a_Depth, int * a_Flags); + #endif // _DEBUG + + /** Called when PolarSSL wants to read encrypted data. */ + virtual int ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes) = 0; + + /** Called when PolarSSL wants to write encrypted data. */ + virtual int SendEncrypted(const unsigned char * a_Buffer, size_t a_NumBytes) = 0; +} ; + + + + diff --git a/src/PolarSSL++/X509Cert.cpp b/src/PolarSSL++/X509Cert.cpp new file mode 100644 index 000000000..ecf664855 --- /dev/null +++ b/src/PolarSSL++/X509Cert.cpp @@ -0,0 +1,38 @@ + +// X509Cert.cpp + +// Implements the cX509Cert class representing a wrapper over X509 certs in PolarSSL + +#include "Globals.h" +#include "X509Cert.h" + + + + + +cX509Cert::cX509Cert(void) +{ + x509_crt_init(&m_Cert); +} + + + + + +cX509Cert::~cX509Cert() +{ + x509_crt_free(&m_Cert); +} + + + + + +int cX509Cert::Parse(const void * a_CertContents, size_t a_Size) +{ + return x509_crt_parse(&m_Cert, (const unsigned char *)a_CertContents, a_Size); +} + + + + diff --git a/src/PolarSSL++/X509Cert.h b/src/PolarSSL++/X509Cert.h new file mode 100644 index 000000000..991617d24 --- /dev/null +++ b/src/PolarSSL++/X509Cert.h @@ -0,0 +1,41 @@ + +// X509Cert.h + +// Declares the cX509Cert class representing a wrapper over X509 certs in PolarSSL + + + + + +#pragma once + +#include "polarssl/x509_crt.h" + + + + + +class cX509Cert +{ + friend class cSslContext; + +public: + cX509Cert(void); + ~cX509Cert(void); + + /** Parses the certificate chain data into the context. + Returns 0 on succes, or PolarSSL error code on failure. */ + int Parse(const void * a_CertContents, size_t a_Size); + +protected: + x509_crt m_Cert; + + /** Returns the internal cert ptr. Only use in PolarSSL API calls. */ + x509_crt * GetInternal(void) { return &m_Cert; } +} ; + +typedef SharedPtr<cX509Cert> cX509CertPtr; + + + + diff --git a/src/ProbabDistrib.cpp b/src/ProbabDistrib.cpp index 5fa17c276..7a5869dcc 100644 --- a/src/ProbabDistrib.cpp +++ b/src/ProbabDistrib.cpp @@ -118,7 +118,7 @@ int cProbabDistrib::MapValue(int a_OrigValue) const size_t Hi = m_Cumulative.size() - 1; while (Hi - Lo > 1) { - int Mid = (Lo + Hi) / 2; + size_t Mid = (Lo + Hi) / 2; int MidProbab = m_Cumulative[Mid].m_Probability; if (MidProbab < a_OrigValue) { diff --git a/src/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp new file mode 100644 index 000000000..2050393c2 --- /dev/null +++ b/src/Protocol/Authenticator.cpp @@ -0,0 +1,309 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Authenticator.h" +#include "../Root.h" +#include "../Server.h" +#include "../ClientHandle.h" + +#include "inifile/iniFile.h" +#include "json/json.h" + +#include "PolarSSL++/BlockingSslClientSocket.h" + +#include <sstream> +#include <iomanip> + + + + + +#define DEFAULT_AUTH_SERVER "sessionserver.mojang.com" +#define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%" + + + + + +cAuthenticator::cAuthenticator(void) : + super("cAuthenticator"), + m_Server(DEFAULT_AUTH_SERVER), + m_Address(DEFAULT_AUTH_ADDRESS), + m_ShouldAuthenticate(true) +{ +} + + + + + +cAuthenticator::~cAuthenticator() +{ + Stop(); +} + + + + + +void cAuthenticator::ReadINI(cIniFile & IniFile) +{ + m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER); + m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS); + m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true); +} + + + + + +void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash) +{ + if (!m_ShouldAuthenticate) + { + cRoot::Get()->AuthenticateUser(a_ClientID, a_UserName, cClientHandle::GenerateOfflineUUID(a_UserName)); + return; + } + + cCSLock LOCK(m_CS); + m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash)); + m_QueueNonempty.Set(); +} + + + + + +void cAuthenticator::Start(cIniFile & IniFile) +{ + ReadINI(IniFile); + m_ShouldTerminate = false; + super::Start(); +} + + + + + +void cAuthenticator::Stop(void) +{ + m_ShouldTerminate = true; + m_QueueNonempty.Set(); + Wait(); +} + + + + + +void cAuthenticator::Execute(void) +{ + for (;;) + { + cCSLock Lock(m_CS); + while (!m_ShouldTerminate && (m_Queue.size() == 0)) + { + cCSUnlock Unlock(Lock); + m_QueueNonempty.Wait(); + } + if (m_ShouldTerminate) + { + return; + } + ASSERT(!m_Queue.empty()); + + cAuthenticator::cUser & User = m_Queue.front(); + int ClientID = User.m_ClientID; + AString UserName = User.m_Name; + AString ServerID = User.m_ServerID; + m_Queue.pop_front(); + Lock.Unlock(); + + AString NewUserName = UserName; + AString UUID; + if (AuthWithYggdrasil(NewUserName, ServerID, UUID)) + { + LOGINFO("User %s authenticated with UUID '%s'", NewUserName.c_str(), UUID.c_str()); + cRoot::Get()->AuthenticateUser(ClientID, NewUserName, UUID); + } + else + { + cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!"); + } + } // for (-ever) +} + + + + + +bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID) +{ + LOGD("Trying to auth user %s", a_UserName.c_str()); + + int ret; + unsigned char buf[1024]; + + /* Initialize certificates */ + // This is the data of the root certs for Starfield Technologies, the CA that signed sessionserver.mojang.com's cert: + // Downloaded from http://certs.starfieldtech.com/repository/ + static const AString StarfieldCACert( + // G2 cert + "-----BEGIN CERTIFICATE-----\n" + "MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx\n" + "EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT\n" + "HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs\n" + "ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw\n" + "MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6\n" + "b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj\n" + "aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp\n" + "Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC\n" + "ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg\n" + "nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1\n" + "HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N\n" + "Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN\n" + "dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0\n" + "HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO\n" + "BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G\n" + "CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU\n" + "sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3\n" + "4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg\n" + "8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K\n" + "pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1\n" + "mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0\n" + "-----END CERTIFICATE-----\n\n" + // Original (G1) cert: + "-----BEGIN CERTIFICATE-----\n" + "MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl\n" + "MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp\n" + "U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw\n" + "NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE\n" + "ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp\n" + "ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3\n" + "DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf\n" + "8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN\n" + "+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0\n" + "X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa\n" + "K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA\n" + "1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G\n" + "A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR\n" + "zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0\n" + "YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD\n" + "bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w\n" + "DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3\n" + "L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D\n" + "eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl\n" + "xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp\n" + "VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY\n" + "WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=\n" + "-----END CERTIFICATE-----\n" + ); + + // Connect the socket: + cBlockingSslClientSocket Socket; + Socket.SetTrustedRootCertsFromString(StarfieldCACert, m_Server); + if (!Socket.Connect(m_Server, 443)) + { + LOGWARNING("cAuthenticator: Can't connect to %s: %s", m_Server.c_str(), Socket.GetLastErrorText().c_str()); + return false; + } + + // Create the GET request: + AString ActualAddress = m_Address; + ReplaceString(ActualAddress, "%USERNAME%", a_UserName); + ReplaceString(ActualAddress, "%SERVERID%", a_ServerId); + + AString Request; + Request += "GET " + ActualAddress + " HTTP/1.0\r\n"; + Request += "Host: " + m_Server + "\r\n"; + Request += "User-Agent: MCServer\r\n"; + Request += "Connection: close\r\n"; + Request += "\r\n"; + + if (!Socket.Send(Request.c_str(), Request.size())) + { + LOGWARNING("cAuthenticator: Writing SSL data failed: %s", Socket.GetLastErrorText().c_str()); + return false; + } + + // Read the HTTP response: + std::string Response; + for (;;) + { + ret = Socket.Receive(buf, sizeof(buf)); + + if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE)) + { + // This value should never be returned, it is handled internally by cBlockingSslClientSocket + LOGWARNING("cAuthenticator: SSL reading failed internally."); + return false; + } + if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) + { + break; + } + if (ret < 0) + { + LOGWARNING("cAuthenticator: SSL reading failed: -0x%x", -ret); + return false; + } + if (ret == 0) + { + break; + } + + Response.append((const char *)buf, (size_t)ret); + } + + Socket.Disconnect(); + + // Check the HTTP status line: + AString prefix("HTTP/1.1 200 OK"); + AString HexDump; + if (Response.compare(0, prefix.size(), prefix)) + { + LOGINFO("User \"%s\" failed to auth, bad http status line received", a_UserName.c_str()); + LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return false; + } + + // Erase the HTTP headers from the response: + size_t idxHeadersEnd = Response.find("\r\n\r\n"); + if (idxHeadersEnd == AString::npos) + { + LOGINFO("User \"%s\" failed to authenticate, bad http response header received", a_UserName.c_str()); + LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); + return false; + } + Response.erase(0, idxHeadersEnd + 4); + + // Parse the Json response: + if (Response.empty()) + { + return false; + } + Json::Value root; + Json::Reader reader; + if (!reader.parse(Response, root, false)) + { + LOGWARNING("cAuthenticator: Cannot parse Received Data to json!"); + return false; + } + a_UserName = root.get("name", "Unknown").asString(); + a_UUID = root.get("id", "").asString(); + + // If the UUID doesn't contain the hashes, insert them at the proper places: + if (a_UUID.size() == 32) + { + a_UUID.insert(8, "-"); + a_UUID.insert(13, "-"); + a_UUID.insert(18, "-"); + a_UUID.insert(23, "-"); + } + return true; +} + + + + + diff --git a/src/Authenticator.h b/src/Protocol/Authenticator.h index 02cd6f4c5..211f51394 100644 --- a/src/Authenticator.h +++ b/src/Protocol/Authenticator.h @@ -14,7 +14,7 @@ #ifndef CAUTHENTICATOR_H_INCLUDED #define CAUTHENTICATOR_H_INCLUDED -#include "OSSupport/IsThread.h" +#include "../OSSupport/IsThread.h" @@ -31,23 +31,23 @@ class cAuthenticator : public cIsThread { typedef cIsThread super; - + public: cAuthenticator(void); ~cAuthenticator(); - /// (Re-)read server and address from INI: + /** (Re-)read server and address from INI: */ void ReadINI(cIniFile & IniFile); - /// Queues a request for authenticating a user. If the auth fails, the user is kicked + /** Queues a request for authenticating a user. If the auth fails, the user will be kicked */ void Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash); - /// Starts the authenticator thread. The thread may be started and stopped repeatedly + /** Starts the authenticator thread. The thread may be started and stopped repeatedly */ void Start(cIniFile & IniFile); - - /// Stops the authenticator thread. The thread may be started and stopped repeatedly + + /** Stops the authenticator thread. The thread may be started and stopped repeatedly */ void Stop(void); - + private: class cUser @@ -56,30 +56,30 @@ private: int m_ClientID; AString m_Name; AString m_ServerID; - + cUser(int a_ClientID, const AString & a_Name, const AString & a_ServerID) : m_ClientID(a_ClientID), m_Name(a_Name), m_ServerID(a_ServerID) { } - } ; - + }; + typedef std::deque<cUser> cUserList; - + cCriticalSection m_CS; cUserList m_Queue; cEvent m_QueueNonempty; - + AString m_Server; AString m_Address; bool m_ShouldAuthenticate; - - // cIsThread override: + + /** cIsThread override: */ virtual void Execute(void) override; - - // Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep) - bool AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level = 1); + + /** Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep) */ + bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID); }; diff --git a/src/Protocol/CMakeLists.txt b/src/Protocol/CMakeLists.txt index 107b79627..849ec27ca 100644 --- a/src/Protocol/CMakeLists.txt +++ b/src/Protocol/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Protocol ${SOURCE}) diff --git a/src/Protocol/ChunkDataSerializer.cpp b/src/Protocol/ChunkDataSerializer.cpp index 78318a5ee..ebe61631b 100644 --- a/src/Protocol/ChunkDataSerializer.cpp +++ b/src/Protocol/ChunkDataSerializer.cpp @@ -105,7 +105,7 @@ void cChunkDataSerializer::Serialize29(AString & a_Data) a_Data.append((const char *)&BitMap1, sizeof(short)); a_Data.append((const char *)&BitMap2, sizeof(short)); - Int32 CompressedSizeBE = htonl(CompressedSize); + UInt32 CompressedSizeBE = htonl((UInt32)CompressedSize); a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE)); Int32 UnusedInt32 = 0; @@ -163,7 +163,7 @@ void cChunkDataSerializer::Serialize39(AString & a_Data) a_Data.append((const char *)&BitMap1, sizeof(short)); a_Data.append((const char *)&BitMap2, sizeof(short)); - Int32 CompressedSizeBE = htonl(CompressedSize); + UInt32 CompressedSizeBE = htonl((UInt32)CompressedSize); a_Data.append((const char *)&CompressedSizeBE, sizeof(CompressedSizeBE)); // Unlike 29, 39 doesn't have the "unused" int diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h index d3383bf0d..a543c6361 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -31,6 +31,7 @@ class cMonster; class cChunkDataSerializer; class cFallingBlock; class cCompositeChat; +class cStatManager; @@ -83,6 +84,7 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0; virtual void SendKeepAlive (int a_PingID) = 0; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0; + virtual void SendLoginSuccess (void) = 0; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) = 0; virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0; @@ -110,6 +112,7 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) = 0; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0; virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) = 0; + virtual void SendStatistics (const cStatManager & a_Manager) = 0; virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0; virtual void SendTeleportEntity (const cEntity & a_Entity) = 0; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0; @@ -122,7 +125,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) = 0; virtual void SendWindowClose (const cWindow & a_Window) = 0; virtual void SendWindowOpen (const cWindow & a_Window) = 0; - virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) = 0; + virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) = 0; /// Returns the ServerID used for authentication through session.minecraft.net virtual AString GetAuthServerID(void) = 0; @@ -132,7 +135,7 @@ protected: cCriticalSection m_CSPacket; //< Each SendXYZ() function must acquire this CS in order to send the whole packet at once /// A generic data-sending routine, all outgoing packet data needs to be routed through this so that descendants may override it - virtual void SendData(const char * a_Data, int a_Size) = 0; + virtual void SendData(const char * a_Data, size_t a_Size) = 0; /// Called after writing each packet, enables descendants to flush their buffers virtual void Flush(void) {}; @@ -143,10 +146,15 @@ protected: SendData((const char *)&a_Value, 1); } + void WriteChar(char a_Value) + { + SendData(&a_Value, 1); + } + void WriteShort(short a_Value) { - a_Value = htons(a_Value); - SendData((const char *)&a_Value, 2); + u_short Value = htons((u_short)a_Value); + SendData((const char *)&Value, 2); } /* @@ -159,8 +167,8 @@ protected: void WriteInt(int a_Value) { - a_Value = htonl(a_Value); - SendData((const char *)&a_Value, 4); + u_long Value = htonl((u_long)a_Value); + SendData((const char *)&Value, 4); } void WriteUInt(unsigned int a_Value) @@ -171,19 +179,19 @@ protected: void WriteInt64 (Int64 a_Value) { - a_Value = HostToNetwork8(&a_Value); - SendData((const char *)&a_Value, 8); + UInt64 Value = HostToNetwork8(&a_Value); + SendData((const char *)&Value, 8); } void WriteFloat (float a_Value) { - unsigned int val = HostToNetwork4(&a_Value); + UInt32 val = HostToNetwork4(&a_Value); SendData((const char *)&val, 4); } void WriteDouble(double a_Value) { - unsigned long long val = HostToNetwork8(&a_Value); + UInt64 val = HostToNetwork8(&a_Value); SendData((const char *)&val, 8); } @@ -191,7 +199,7 @@ protected: { AString UTF16; UTF8ToRawBEUTF16(a_Value.c_str(), a_Value.length(), UTF16); - WriteShort((unsigned short)(UTF16.size() / 2)); + WriteShort((short)(UTF16.size() / 2)); SendData(UTF16.data(), UTF16.size()); } @@ -211,7 +219,7 @@ protected: { // A 32-bit integer can be encoded by at most 5 bytes: unsigned char b[5]; - int idx = 0; + size_t idx = 0; do { b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); @@ -224,7 +232,7 @@ protected: void WriteVarUTF8String(const AString & a_String) { - WriteVarInt(a_String.size()); + WriteVarInt((UInt32)a_String.size()); SendData(a_String.data(), a_String.size()); } } ; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index 69f4934d8..f3bdae3ac 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -26,7 +26,7 @@ Documentation: #include "../Root.h" #include "../Server.h" -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" #include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" @@ -96,8 +96,10 @@ enum PACKET_INVENTORY_WHOLE = 0x68, PACKET_WINDOW_PROPERTY = 0x69, PACKET_CREATIVE_INVENTORY_ACTION = 0x6B, + PACKET_ENCHANT_ITEM = 0x6C, PACKET_UPDATE_SIGN = 0x82, PACKET_ITEM_DATA = 0x83, + PACKET_INCREMENT_STATISTIC = 0xC8, PACKET_PLAYER_LIST_ITEM = 0xC9, PACKET_PLAYER_ABILITIES = 0xca, PACKET_PLUGIN_MESSAGE = 0xfa, @@ -161,8 +163,8 @@ void cProtocol125::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha WriteInt (a_BlockX); WriteShort((short)a_BlockY); WriteInt (a_BlockZ); - WriteByte (a_Byte1); - WriteByte (a_Byte2); + WriteChar (a_Byte1); + WriteChar (a_Byte2); Flush(); } @@ -209,12 +211,12 @@ void cProtocol125::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV WriteByte (PACKET_MULTI_BLOCK); WriteInt (a_ChunkX); WriteInt (a_ChunkZ); - WriteShort((unsigned short)a_Changes.size()); - WriteUInt (sizeof(int) * a_Changes.size()); + WriteShort((short)a_Changes.size()); + WriteUInt ((UInt32)(4 * a_Changes.size())); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { - unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); - unsigned int Blocks = itr->BlockMeta | (itr->BlockType << 4); + UInt32 Coords = ((UInt32)itr->y) | ((UInt32)(itr->z << 8)) | ((UInt32)(itr->x << 12)); + UInt32 Blocks = ((UInt32)itr->BlockMeta) | ((UInt32)(itr->BlockType << 4)); WriteUInt(Coords << 16 | Blocks); } Flush(); @@ -239,32 +241,11 @@ void cProtocol125::SendChat(const AString & a_Message) void cProtocol125::SendChat(const cCompositeChat & a_Message) { // This version doesn't support composite messages, just extract each part's text and use it: - AString Msg; - const cCompositeChat::cParts & Parts = a_Message.GetParts(); - for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr) - { - switch ((*itr)->m_PartType) - { - case cCompositeChat::ptText: - case cCompositeChat::ptClientTranslated: - case cCompositeChat::ptRunCommand: - case cCompositeChat::ptSuggestCommand: - { - Msg.append((*itr)->m_Text); - break; - } - case cCompositeChat::ptUrl: - { - Msg.append(((cCompositeChat::cUrlPart *)(*itr))->m_Url); - break; - } - } // switch (PartType) - } // for itr - Parts[] // Send the message: cCSLock Lock(m_CSPacket); WriteByte (PACKET_CHAT); - WriteString(Msg); + WriteString(a_Message.ExtractText()); Flush(); } @@ -346,8 +327,8 @@ void cProtocol125::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in cCSLock Lock(m_CSPacket); WriteByte (PACKET_ENTITY_EFFECT); WriteInt (a_Entity.GetUniqueID()); - WriteByte (a_EffectID); - WriteByte (a_Amplifier); + WriteByte ((Byte)a_EffectID); + WriteByte ((Byte)a_Amplifier); WriteShort(a_Duration); Flush(); } @@ -378,7 +359,7 @@ void cProtocol125::SendEntityHeadLook(const cEntity & a_Entity) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_HEAD_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte((char)((a_Entity.GetHeadYaw() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetHeadYaw() / 360.f) * 256)); Flush(); } @@ -393,8 +374,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -442,9 +423,9 @@ void cProtocol125::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_REL_MOVE); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_RelX); - WriteByte(a_RelY); - WriteByte(a_RelZ); + WriteChar(a_RelX); + WriteChar(a_RelY); + WriteChar(a_RelZ); Flush(); } @@ -459,11 +440,11 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_REL_MOVE_LOOK); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_RelX); - WriteByte(a_RelY); - WriteByte(a_RelZ); - WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteChar(a_RelX); + WriteChar(a_RelY); + WriteChar(a_RelZ); + WriteChar((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteChar((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -476,7 +457,7 @@ void cProtocol125::SendEntityStatus(const cEntity & a_Entity, char a_Status) cCSLock Lock(m_CSPacket); WriteByte(PACKET_ENT_STATUS); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_Status); + WriteChar(a_Status); Flush(); } @@ -509,7 +490,7 @@ void cProtocol125::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc WriteDouble (a_BlockY); WriteDouble (a_BlockZ); WriteFloat (a_Radius); - WriteInt (a_BlocksAffected.size()); + WriteInt ((Int32)a_BlocksAffected.size()); int BlockX = (int)a_BlockX; int BlockY = (int)a_BlockY; int BlockZ = (int)a_BlockZ; @@ -534,7 +515,7 @@ void cProtocol125::SendGameMode(eGameMode a_GameMode) cCSLock Lock(m_CSPacket); WriteByte(PACKET_CHANGE_GAME_STATE); WriteByte(3); - WriteByte((char)a_GameMode); + WriteChar((char)a_GameMode); Flush(); } @@ -558,9 +539,10 @@ void cProtocol125::SendHealth(void) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_HEALTH); - WriteShort((short)m_Client->GetPlayer()->GetHealth()); - WriteShort(m_Client->GetPlayer()->GetFoodLevel()); - WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); + cPlayer * Player = m_Client->GetPlayer(); + WriteShort((short)Player->GetHealth()); + WriteShort((short)Player->GetFoodLevel()); + WriteFloat((float)Player->GetFoodSaturationLevel()); Flush(); } @@ -572,7 +554,7 @@ void cProtocol125::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt { cCSLock Lock(m_CSPacket); WriteByte (PACKET_INVENTORY_SLOT); - WriteByte (a_WindowID); + WriteChar (a_WindowID); WriteShort(a_SlotNum); WriteItem (a_Item); Flush(); @@ -615,23 +597,29 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +void cProtocol125::SendLoginSuccess(void) +{ + // Not supported in this protocol version +} + + + + + void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_ITEM_DATA); WriteShort(E_ITEM_MAP); - WriteShort(a_ID); - WriteShort(3 + a_Length); + WriteShort((short)a_ID); + WriteShort((short)(3 + a_Length)); WriteByte(0); - WriteByte(a_X); - WriteByte(a_Y); + WriteChar((char)a_X); + WriteChar((char)a_Y); - for (unsigned int i = 0; i < a_Length; ++i) - { - WriteByte(a_Colors[i]); - } + SendData((const char *)a_Colors, a_Length); Flush(); } @@ -646,16 +634,16 @@ void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor WriteByte (PACKET_ITEM_DATA); WriteShort(E_ITEM_MAP); - WriteShort(a_ID); - WriteShort(1 + (3 * a_Decorators.size())); + WriteShort((short)a_ID); + WriteShort((short)(1 + (3 * a_Decorators.size()))); WriteByte(1); for (cMapDecoratorList::const_iterator it = a_Decorators.begin(); it != a_Decorators.end(); ++it) { - WriteByte((it->GetType() << 4) | (it->GetRot() & 0xf)); - WriteByte(it->GetPixelX()); - WriteByte(it->GetPixelZ()); + WriteByte((Byte)(it->GetType() << 4) | (it->GetRot() & 0xf)); + WriteByte((Byte)it->GetPixelX()); + WriteByte((Byte)it->GetPixelZ()); } Flush(); @@ -666,18 +654,30 @@ void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor +void cProtocol125::SendMapInfo(int a_ID, unsigned int a_Scale) +{ + // This protocol doesn't support such message + UNUSED(a_ID); + UNUSED(a_Scale); +} + + + + + void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_PICKUP_SPAWN); WriteInt (a_Pickup.GetUniqueID()); - WriteShort (a_Pickup.GetItem().m_ItemType); - WriteByte (a_Pickup.GetItem().m_ItemCount); - WriteShort (a_Pickup.GetItem().m_ItemDamage); + const cItem & Item = a_Pickup.GetItem(); + WriteShort (Item.m_ItemType); + WriteChar (Item.m_ItemCount); + WriteShort (Item.m_ItemDamage); WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32)); - WriteByte ((char)(a_Pickup.GetSpeed().x * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().y * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().z * 8)); + WriteByte ((char)(a_Pickup.GetSpeedX() * 8)); + WriteByte ((char)(a_Pickup.GetSpeedY() * 8)); + WriteByte ((char)(a_Pickup.GetSpeedZ() * 8)); Flush(); } @@ -690,7 +690,7 @@ void cProtocol125::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio cCSLock Lock(m_CSPacket); WriteByte(PACKET_ANIMATION); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_Animation); + WriteChar(a_Animation); Flush(); } @@ -707,6 +707,16 @@ void cProtocol125::SendParticleEffect(const AString & a_ParticleName, float a_Sr +void cProtocol125::SendPaintingSpawn(const cPainting & a_Painting) +{ + // Not implemented in this protocol version + UNUSED(a_Painting); +} + + + + + void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) { cCSLock Lock(m_CSPacket); @@ -784,8 +794,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player) WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256)); - WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256)); WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); Flush(); } @@ -811,9 +821,9 @@ void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString & void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { cCSLock Lock(m_CSPacket); - WriteByte (PACKET_REMOVE_ENTITY_EFFECT); - WriteInt (a_Entity.GetUniqueID()); - WriteByte (a_EffectID); + WriteByte(PACKET_REMOVE_ENTITY_EFFECT); + WriteInt (a_Entity.GetUniqueID()); + WriteChar((char)a_EffectID); Flush(); } @@ -824,10 +834,11 @@ void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect void cProtocol125::SendRespawn(void) { cCSLock Lock(m_CSPacket); + cPlayer * Player = m_Client->GetPlayer(); WriteByte (PACKET_RESPAWN); - WriteInt ((int)(m_Client->GetPlayer()->GetWorld()->GetDimension())); + WriteInt ((int)(Player->GetWorld()->GetDimension())); WriteByte (2); // TODO: Difficulty; 2 = Normal - WriteByte ((char)m_Client->GetPlayer()->GetGameMode()); + WriteChar ((char)Player->GetGameMode()); WriteShort (256); // Current world height WriteString("default"); } @@ -839,10 +850,11 @@ void cProtocol125::SendRespawn(void) void cProtocol125::SendExperience(void) { cCSLock Lock(m_CSPacket); + cPlayer * Player = m_Client->GetPlayer(); WriteByte (PACKET_EXPERIENCE); - WriteFloat (m_Client->GetPlayer()->GetXpPercentage()); - WriteShort (m_Client->GetPlayer()->GetXpLevel()); - WriteShort (m_Client->GetPlayer()->GetCurrentXp()); + WriteFloat (Player->GetXpPercentage()); + WriteShort (Player->GetXpLevel()); + WriteShort (Player->GetCurrentXp()); Flush(); } @@ -858,7 +870,7 @@ void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb) WriteInt((int) a_ExpOrb.GetPosX()); WriteInt((int) a_ExpOrb.GetPosY()); WriteInt((int) a_ExpOrb.GetPosZ()); - WriteShort(a_ExpOrb.GetReward()); + WriteShort((short)a_ExpOrb.GetReward()); Flush(); } @@ -866,6 +878,18 @@ void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb) +void cProtocol125::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) +{ + // This protocol version doesn't support such message + UNUSED(a_Name); + UNUSED(a_DisplayName); + UNUSED(a_Mode); +} + + + + + void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) { // Not needed in this protocol version @@ -899,7 +923,7 @@ void cProtocol125::SendSpawnMob(const cMonster & a_Mob) cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_MOB); WriteInt (a_Mob.GetUniqueID()); - WriteByte (a_Mob.GetMobType()); + WriteByte ((Byte)a_Mob.GetMobType()); WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); WriteByte (0); WriteByte (0); @@ -924,7 +948,7 @@ void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, cCSLock Lock(m_CSPacket); WriteByte(PACKET_SPAWN_OBJECT); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_ObjectType); + WriteChar(a_ObjectType); WriteInt ((int)(a_Entity.GetPosX() * 32)); WriteInt ((int)(a_Entity.GetPosY() * 32)); WriteInt ((int)(a_Entity.GetPosZ() * 32)); @@ -949,7 +973,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_OBJECT); WriteInt (a_Vehicle.GetUniqueID()); - WriteByte (a_VehicleType); + WriteChar (a_VehicleType); WriteInt ((int)(a_Vehicle.GetPosX() * 32)); WriteInt ((int)(a_Vehicle.GetPosY() * 32)); WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); @@ -969,6 +993,33 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp +void cProtocol125::SendStatistics(const cStatManager & a_Manager) +{ + /* NOTE: + * Versions prior to minecraft 1.7 use an incremental statistic sync + * method. The current setup does not allow us to implement that, because + * of performance considerations. + */ +#if 0 + for (unsigned int i = 0; i < (unsigned int)statCount; ++i) + { + StatValue Value = m_Manager->GetValue((eStatistic) i); + + unsigned int StatID = cStatInfo::GetID((eStatistic) i); + + cCSLock Lock(m_CSPacket); + WriteByte(PACKET_INCREMENT_STATISTIC); + WriteInt(StatID); + WriteByte(Value); /* Can overflow! */ + Flush(); + } +#endif +} + + + + + void cProtocol125::SendTabCompletionResults(const AStringVector & a_Results) { // This protocol version doesn't support tab completion @@ -987,8 +1038,8 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity) WriteInt ((int)(floor(a_Entity.GetPosX() * 32))); WriteInt ((int)(floor(a_Entity.GetPosY() * 32))); WriteInt ((int)(floor(a_Entity.GetPosZ() * 32))); - WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256)); - WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256)); + WriteChar ((char)((a_Entity.GetYaw() / 360.f) * 256)); + WriteChar ((char)((a_Entity.GetPitch() / 360.f) * 256)); Flush(); } @@ -1063,7 +1114,7 @@ void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc WriteInt (a_Entity.GetUniqueID()); WriteByte(0); // Unknown byte only 0 has been observed WriteInt (a_BlockX); - WriteByte(a_BlockY); + WriteByte((Byte)a_BlockY); WriteInt (a_BlockZ); Flush(); } @@ -1107,7 +1158,7 @@ void cProtocol125::SendWholeInventory(const cWindow & a_Window) cCSLock Lock(m_CSPacket); cItems Slots; a_Window.GetSlots(*(m_Client->GetPlayer()), Slots); - SendWindowSlots(a_Window.GetWindowID(), Slots.size(), &(Slots[0])); + SendWindowSlots(a_Window.GetWindowID(), (int)Slots.size(), &(Slots[0])); } @@ -1124,7 +1175,7 @@ void cProtocol125::SendWindowClose(const cWindow & a_Window) cCSLock Lock(m_CSPacket); WriteByte(PACKET_WINDOW_CLOSE); - WriteByte(a_Window.GetWindowID()); + WriteChar(a_Window.GetWindowID()); Flush(); } @@ -1141,10 +1192,10 @@ void cProtocol125::SendWindowOpen(const cWindow & a_Window) } cCSLock Lock(m_CSPacket); WriteByte (PACKET_WINDOW_OPEN); - WriteByte (a_Window.GetWindowID()); - WriteByte (a_Window.GetWindowType()); + WriteChar (a_Window.GetWindowID()); + WriteByte ((Byte)a_Window.GetWindowType()); WriteString(a_Window.GetWindowTitle()); - WriteByte (a_Window.GetNumNonInventorySlots()); + WriteByte ((Byte)a_Window.GetNumNonInventorySlots()); Flush(); } @@ -1152,11 +1203,11 @@ void cProtocol125::SendWindowOpen(const cWindow & a_Window) -void cProtocol125::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) +void cProtocol125::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_WINDOW_PROPERTY); - WriteByte (a_Window.GetWindowID()); + WriteChar (a_Window.GetWindowID()); WriteShort(a_Property); WriteShort(a_Value); Flush(); @@ -1177,7 +1228,7 @@ AString cProtocol125::GetAuthServerID(void) -void cProtocol125::SendData(const char * a_Data, int a_Size) +void cProtocol125::SendData(const char * a_Data, size_t a_Size) { m_Client->SendData(a_Data, a_Size); } @@ -1260,6 +1311,7 @@ int cProtocol125::ParsePacket(unsigned char a_PacketType) case PACKET_SLOT_SELECTED: return ParseSlotSelected(); case PACKET_UPDATE_SIGN: return ParseUpdateSign(); case PACKET_USE_ENTITY: return ParseUseEntity(); + case PACKET_ENCHANT_ITEM: return ParseEnchantItem(); case PACKET_WINDOW_CLICK: return ParseWindowClick(); case PACKET_WINDOW_CLOSE: return ParseWindowClose(); } @@ -1548,7 +1600,7 @@ int cProtocol125::ParsePluginMessage(void) HANDLE_PACKET_READ(ReadBEUTF16String16, AString, ChannelName); HANDLE_PACKET_READ(ReadBEShort, short, Length); AString Data; - if (!m_ReceivedData.ReadString(Data, Length)) + if (!m_ReceivedData.ReadString(Data, (size_t)Length)) { m_ReceivedData.CheckValid(); return PARSE_INCOMPLETE; @@ -1621,6 +1673,20 @@ int cProtocol125::ParseUseEntity(void) +int cProtocol125::ParseEnchantItem(void) +{ + HANDLE_PACKET_READ(ReadByte, Byte, WindowID); + HANDLE_PACKET_READ(ReadByte, Byte, Enchantment); + + m_Client->HandleEnchantItem(WindowID, Enchantment); + + return PARSE_OK; +} + + + + + int cProtocol125::ParseWindowClick(void) { HANDLE_PACKET_READ(ReadChar, char, WindowID); @@ -1709,7 +1775,7 @@ void cProtocol125::SendPreChunk(int a_ChunkX, int a_ChunkZ, bool a_ShouldLoad) void cProtocol125::SendWindowSlots(char a_WindowID, int a_NumItems, const cItem * a_Items) { WriteByte (PACKET_INVENTORY_WHOLE); - WriteByte (a_WindowID); + WriteChar (a_WindowID); WriteShort((short)a_NumItems); for (int j = 0; j < a_NumItems; j++) @@ -1739,7 +1805,7 @@ void cProtocol125::WriteItem(const cItem & a_Item) return; } - WriteByte (a_Item.m_ItemCount); + WriteChar (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); if (cItem::IsEnchantable(a_Item.m_ItemType)) @@ -1786,7 +1852,7 @@ int cProtocol125::ParseItem(cItem & a_Item) } // TODO: Enchantment not implemented yet! - if (!m_ReceivedData.SkipRead(EnchantNumBytes)) + if (!m_ReceivedData.SkipRead((size_t)EnchantNumBytes)) { return PARSE_INCOMPLETE; } @@ -1871,7 +1937,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) case cMonster::mtCreeper: { WriteByte(0x10); - WriteByte(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up? + WriteChar(((const cCreeper &)a_Mob).IsBlowing() ? 1 : -1); // Blowing up? WriteByte(0x11); WriteByte(((const cCreeper &)a_Mob).IsCharged() ? 1 : 0); // Lightning-charged? break; @@ -1941,9 +2007,9 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteByte(0x10); Byte SheepMetadata = 0; - SheepMetadata = ((const cSheep &)a_Mob).GetFurColor(); // Fur colour + SheepMetadata = (Byte)((const cSheep &)a_Mob).GetFurColor(); - if (((const cSheep &)a_Mob).IsSheared()) // Is sheared? + if (((const cSheep &)a_Mob).IsSheared()) { SheepMetadata |= 0x16; } @@ -1972,17 +2038,25 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); // Aggravated? Doesn't seem to do anything break; } + case cMonster::mtWither: + { + WriteByte(0x54); // Int at index 20 + WriteInt((Int32)((const cWither &)a_Mob).GetWitherInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 + WriteFloat((float)(a_Mob.GetHealth())); + break; + } case cMonster::mtSlime: case cMonster::mtMagmaCube: { WriteByte(0x10); if (a_Mob.GetMobType() == cMonster::mtSlime) { - WriteByte(((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME + WriteByte((Byte)((const cSlime &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME } else { - WriteByte(((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME + WriteByte((Byte)((const cMagmaCube &)a_Mob).GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME } break; } @@ -2021,7 +2095,7 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteInt(Flags); WriteByte(0x13); - WriteByte(((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.) + WriteByte((Byte)((const cHorse &)a_Mob).GetHorseType()); // Type of horse (donkey, chestnut, etc.) WriteByte(0x54); int Appearance = 0; @@ -2033,6 +2107,10 @@ void cProtocol125::WriteMobMetadata(const cMonster & a_Mob) WriteInt(((const cHorse &)a_Mob).GetHorseArmour()); // Horshey armour break; } + default: + { + break; + } } } diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index aca24c03a..18a626a2d 100644 --- a/src/Protocol/Protocol125.h +++ b/src/Protocol/Protocol125.h @@ -56,19 +56,12 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendLoginSuccess (void) override; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; - virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override - { - // This protocol doesn't support such message - UNUSED(a_ID); - UNUSED(a_Scale); - } + virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override; - virtual void SendPaintingSpawn (const cPainting & a_Painting) override - { - UNUSED(a_Painting); - }; + virtual void SendPaintingSpawn (const cPainting & a_Painting) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; @@ -82,12 +75,7 @@ public: virtual void SendRespawn (void) override; virtual void SendExperience (void) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; - virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override - { - UNUSED(a_Name); - UNUSED(a_DisplayName); - UNUSED(a_Mode); - } // This protocol doesn't support such message + virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override; virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8 @@ -96,6 +84,7 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; + virtual void SendStatistics (const cStatManager & a_Manager) override; virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; @@ -108,7 +97,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) override; virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; + virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; virtual AString GetAuthServerID(void) override; @@ -125,7 +114,7 @@ protected: AString m_Username; ///< Stored in ParseHandshake(), compared to Login username - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; /// Sends the Handshake packet void SendHandshake(const AString & a_ConnectionHash); @@ -155,6 +144,7 @@ protected: virtual int ParseSlotSelected (void); virtual int ParseUpdateSign (void); virtual int ParseUseEntity (void); + virtual int ParseEnchantItem (void); virtual int ParseWindowClick (void); virtual int ParseWindowClose (void); diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp index be9c503ed..f4717f592 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -18,19 +18,7 @@ #include "../WorldStorage/FastNBT.h" #include "../WorldStorage/EnchantmentSerializer.h" #include "../StringCompression.h" - -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable:4127) - #pragma warning(disable:4244) - #pragma warning(disable:4231) - #pragma warning(disable:4189) - #pragma warning(disable:4702) -#endif - -#ifdef _MSC_VER - #pragma warning(pop) -#endif +#include "PolarSSL++/Sha1Checksum.h" @@ -115,7 +103,7 @@ void cProtocol132::DataReceived(const char * a_Data, size_t a_Size) Byte Decrypted[512]; while (a_Size > 0) { - int NumBytes = (a_Size > (int)sizeof(Decrypted)) ? (int)sizeof(Decrypted) : a_Size; + size_t NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; m_Decryptor.ProcessData(Decrypted, (Byte *)a_Data, NumBytes); super::DataReceived((const char *)Decrypted, NumBytes); a_Size -= NumBytes; @@ -139,8 +127,8 @@ void cProtocol132::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha WriteInt (a_BlockX); WriteShort((short)a_BlockY); WriteInt (a_BlockZ); - WriteByte (a_Byte1); - WriteByte (a_Byte2); + WriteChar (a_Byte1); + WriteChar (a_Byte2); WriteShort(a_BlockType); Flush(); } @@ -157,7 +145,7 @@ void cProtocol132::SendBlockBreakAnim(int a_entityID, int a_BlockX, int a_BlockY WriteInt (a_BlockX); WriteInt (a_BlockY); WriteInt (a_BlockZ); - WriteByte (stage); + WriteChar (stage); Flush(); } @@ -259,7 +247,7 @@ void cProtocol132::SendLogin(const cPlayer & a_Player, const cWorld & a_World) WriteByte (PACKET_LOGIN); WriteInt (a_Player.GetUniqueID()); // EntityID of the player WriteString("default"); // Level type - WriteByte ((int)a_Player.GetGameMode()); + WriteByte ((Byte)a_Player.GetGameMode()); WriteByte ((Byte)(a_World.GetDimension())); WriteByte (2); // TODO: Difficulty WriteByte (0); // Unused, used to be world height @@ -283,8 +271,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player) WriteInt ((int)(a_Player.GetPosX() * 32)); WriteInt ((int)(a_Player.GetPosY() * 32)); WriteInt ((int)(a_Player.GetPosZ() * 32)); - WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256)); - WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetYaw() / 360.f) * 256)); + WriteChar ((char)((a_Player.GetPitch() / 360.f) * 256)); WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType); // Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata: WriteByte (0); // Index 0, byte (flags) @@ -306,7 +294,7 @@ void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int WriteInt (a_SrcY); WriteInt (a_SrcZ); WriteFloat (a_Volume); - WriteByte ((char)(a_Pitch * 63.0f)); + WriteChar ((char)(a_Pitch * 63.0f)); Flush(); } @@ -320,7 +308,7 @@ void cProtocol132::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src WriteByte(PACKET_SOUND_PARTICLE_EFFECT); WriteInt (a_EffectID); WriteInt (a_SrcX); - WriteByte(a_SrcY); + WriteByte((Byte)a_SrcY); WriteInt (a_SrcZ); WriteInt (a_Data); Flush(); @@ -335,7 +323,7 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob) cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_MOB); WriteInt (a_Mob.GetUniqueID()); - WriteByte (a_Mob.GetMobType()); + WriteByte ((Byte)a_Mob.GetMobType()); WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32)); WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256)); WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256)); @@ -408,21 +396,22 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window) super::SendWholeInventory(a_Window); // Send the player inventory and hotbar: - const cInventory & Inventory = m_Client->GetPlayer()->GetInventory(); + cPlayer * Player = m_Client->GetPlayer(); + const cInventory & Inventory = Player->GetInventory(); int BaseOffset = a_Window.GetNumSlots() - (cInventory::invNumSlots - cInventory::invInventoryOffset); // Number of non-inventory slots char WindowID = a_Window.GetWindowID(); - for (int i = 0; i < cInventory::invInventoryCount; i++) + for (short i = 0; i < cInventory::invInventoryCount; i++) { SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetInventorySlot(i)); } // for i - Inventory[] BaseOffset += cInventory::invInventoryCount; - for (int i = 0; i < cInventory::invHotbarCount; i++) + for (short i = 0; i < cInventory::invHotbarCount; i++) { SendInventorySlot(WindowID, BaseOffset + i, Inventory.GetHotbarSlot(i)); } // for i - Hotbar[] // Send even the item being dragged: - SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem()); + SendInventorySlot(-1, -1, Player->GetDraggingItem()); } @@ -527,21 +516,30 @@ int cProtocol132::ParseClientStatuses(void) int cProtocol132::ParseEncryptionKeyResponse(void) { + // Read the encryption key: HANDLE_PACKET_READ(ReadBEShort, short, EncKeyLength); + if (EncKeyLength > MAX_ENC_LEN) + { + LOGD("Too long encryption key"); + m_Client->Kick("Hacked client"); + return PARSE_OK; + } AString EncKey; - if (!m_ReceivedData.ReadString(EncKey, EncKeyLength)) + if (!m_ReceivedData.ReadString(EncKey, (size_t)EncKeyLength)) { return PARSE_INCOMPLETE; } + + // Read the encryption nonce: HANDLE_PACKET_READ(ReadBEShort, short, EncNonceLength); AString EncNonce; - if (!m_ReceivedData.ReadString(EncNonce, EncNonceLength)) + if (!m_ReceivedData.ReadString(EncNonce, (size_t)EncNonceLength)) { return PARSE_INCOMPLETE; } - if ((EncKeyLength > MAX_ENC_LEN) || (EncNonceLength > MAX_ENC_LEN)) + if (EncNonceLength > MAX_ENC_LEN) { - LOGD("Too long encryption"); + LOGD("Too long encryption nonce"); m_Client->Kick("Hacked client"); return PARSE_OK; } @@ -605,7 +603,7 @@ int cProtocol132::ParseTabCompletion(void) -void cProtocol132::SendData(const char * a_Data, int a_Size) +void cProtocol132::SendData(const char * a_Data, size_t a_Size) { m_DataToSend.append(a_Data, a_Size); } @@ -623,23 +621,23 @@ void cProtocol132::Flush(void) LOGD("Flushing empty"); return; } - const char * a_Data = m_DataToSend.data(); - int a_Size = m_DataToSend.size(); + const char * Data = m_DataToSend.data(); + size_t Size = m_DataToSend.size(); if (m_IsEncrypted) { Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) - while (a_Size > 0) + while (Size > 0) { - int NumBytes = (a_Size > (int)sizeof(Encrypted)) ? (int)sizeof(Encrypted) : a_Size; - m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes); + size_t NumBytes = (Size > sizeof(Encrypted)) ? sizeof(Encrypted) : Size; + m_Encryptor.ProcessData(Encrypted, (Byte *)Data, NumBytes); super::SendData((const char *)Encrypted, NumBytes); - a_Size -= NumBytes; - a_Data += NumBytes; + Size -= NumBytes; + Data += NumBytes; } } else { - super::SendData(a_Data, a_Size); + super::SendData(Data, Size); } m_DataToSend.clear(); } @@ -665,7 +663,7 @@ void cProtocol132::WriteItem(const cItem & a_Item) } WriteShort(ItemType); - WriteByte (a_Item.m_ItemCount); + WriteChar (a_Item.m_ItemCount); WriteShort(a_Item.m_ItemDamage); if (a_Item.m_Enchantments.IsEmpty()) @@ -681,7 +679,7 @@ void cProtocol132::WriteItem(const cItem & a_Item) Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); SendData(Compressed.data(), Compressed.size()); } @@ -717,8 +715,8 @@ int cProtocol132::ParseItem(cItem & a_Item) // Read the metadata AString Metadata; - Metadata.resize(MetadataLength); - if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), MetadataLength)) + Metadata.resize((size_t)MetadataLength); + if (!m_ReceivedData.ReadBuf((void *)Metadata.data(), (size_t)MetadataLength)) { return PARSE_INCOMPLETE; } @@ -791,10 +789,12 @@ void cProtocol132::SendCompass(const cWorld & a_World) void cProtocol132::SendEncryptionKeyRequest(void) { cCSLock Lock(m_CSPacket); + cServer * Server = cRoot::Get()->GetServer(); WriteByte(0xfd); - WriteString(cRoot::Get()->GetServer()->GetServerID()); - WriteShort((short)(cRoot::Get()->GetServer()->GetPublicKeyDER().size())); - SendData(cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); + WriteString(Server->GetServerID()); + const AString & PublicKeyDER = Server->GetPublicKeyDER(); + WriteShort((short)(PublicKeyDER.size())); + SendData(PublicKeyDER.data(), PublicKeyDER.size()); WriteShort(4); WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) Flush(); @@ -807,7 +807,7 @@ void cProtocol132::SendEncryptionKeyRequest(void) void cProtocol132::HandleEncryptionKeyResponse(const AString & a_EncKey, const AString & a_EncNonce) { // Decrypt EncNonce using privkey - cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); + cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; int res = rsaDecryptor.Decrypt((const Byte *)a_EncNonce.data(), a_EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce)); @@ -864,14 +864,15 @@ void cProtocol132::StartEncryption(const Byte * a_Key) m_IsEncrypted = true; // Prepare the m_AuthServerID: - cSHA1Checksum Checksum; - AString ServerID = cRoot::Get()->GetServer()->GetServerID(); + cSha1Checksum Checksum; + cServer * Server = cRoot::Get()->GetServer(); + AString ServerID = Server->GetServerID(); Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); Checksum.Update(a_Key, 16); - Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); + Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size()); Byte Digest[20]; Checksum.Finalize(Digest); - cSHA1Checksum::DigestToJava(Digest, m_AuthServerID); + cSha1Checksum::DigestToJava(Digest, m_AuthServerID); } diff --git a/src/Protocol/Protocol132.h b/src/Protocol/Protocol132.h index 0702fbf5a..32bc7d581 100644 --- a/src/Protocol/Protocol132.h +++ b/src/Protocol/Protocol132.h @@ -24,7 +24,8 @@ #pragma warning(pop) #endif -#include "../Crypto.h" +#include "PolarSSL++/AesCfb128Decryptor.h" +#include "PolarSSL++/AesCfb128Encryptor.h" @@ -79,15 +80,15 @@ public: protected: bool m_IsEncrypted; - cAESCFBDecryptor m_Decryptor; - cAESCFBEncryptor m_Encryptor; + cAesCfb128Decryptor m_Decryptor; + cAesCfb128Encryptor m_Encryptor; AString m_DataToSend; /// The ServerID used for session authentication; set in StartEncryption(), used in GetAuthServerID() AString m_AuthServerID; - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; // DEBUG: virtual void Flush(void) override; diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp index 232b2718e..f60e756fd 100644 --- a/src/Protocol/Protocol14x.cpp +++ b/src/Protocol/Protocol14x.cpp @@ -103,9 +103,9 @@ void cProtocol142::SendPickupSpawn(const cPickup & a_Pickup) WriteInt (a_Pickup.GetUniqueID()); WriteItem (a_Pickup.GetItem()); WriteVectorI((Vector3i)(a_Pickup.GetPosition() * 32)); - WriteByte ((char)(a_Pickup.GetSpeed().x * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().y * 8)); - WriteByte ((char)(a_Pickup.GetSpeed().z * 8)); + WriteChar((char)(a_Pickup.GetSpeedX() * 8)); + WriteChar((char)(a_Pickup.GetSpeedY() * 8)); + WriteChar((char)(a_Pickup.GetSpeedZ() * 8)); Flush(); } @@ -119,7 +119,7 @@ void cProtocol142::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src WriteByte(PACKET_SOUND_PARTICLE_EFFECT); WriteInt (a_EffectID); WriteInt (a_SrcX); - WriteByte(a_SrcY); + WriteByte((Byte)a_SrcY); WriteInt (a_SrcZ); WriteInt (a_Data); WriteBool(0); @@ -170,9 +170,9 @@ void cProtocol146::SendPickupSpawn(const cPickup & a_Pickup) WriteInt ((int)(a_Pickup.GetPosY() * 32)); WriteInt ((int)(a_Pickup.GetPosZ() * 32)); WriteInt (1); - WriteShort((short)(a_Pickup.GetSpeed().x * 32)); - WriteShort((short)(a_Pickup.GetSpeed().y * 32)); - WriteShort((short)(a_Pickup.GetSpeed().z * 32)); + WriteShort((short)(a_Pickup.GetSpeedX() * 32)); + WriteShort((short)(a_Pickup.GetSpeedY() * 32)); + WriteShort((short)(a_Pickup.GetSpeedZ() * 32)); WriteByte(0); WriteByte(0); @@ -218,7 +218,7 @@ void cProtocol146::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, cCSLock Lock(m_CSPacket); WriteByte(PACKET_SPAWN_OBJECT); WriteInt (a_Entity.GetUniqueID()); - WriteByte(a_ObjectType); + WriteChar(a_ObjectType); WriteInt ((int)(a_Entity.GetPosX() * 32)); WriteInt ((int)(a_Entity.GetPosY() * 32)); WriteInt ((int)(a_Entity.GetPosZ() * 32)); @@ -243,7 +243,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp cCSLock Lock(m_CSPacket); WriteByte (PACKET_SPAWN_OBJECT); WriteInt (a_Vehicle.GetUniqueID()); - WriteByte (a_VehicleType); + WriteChar (a_VehicleType); WriteInt ((int)(a_Vehicle.GetPosX() * 32)); WriteInt ((int)(a_Vehicle.GetPosY() * 32)); WriteInt ((int)(a_Vehicle.GetPosZ() * 32)); diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index ecb24254f..714bf5e46 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -18,6 +18,7 @@ Implements the 1.6.x protocol classes: #include "../Entities/Entity.h" #include "../Entities/Player.h" #include "../UI/Window.h" +#include "../CompositeChat.h" @@ -89,6 +90,18 @@ void cProtocol161::SendChat(const AString & a_Message) +void cProtocol161::SendChat(const cCompositeChat & a_Message) +{ + // This protocol version doesn't support composite messages to the full + // Just extract each part's text and use it: + + super::SendChat(Printf("{\"text\":\"%s\"}", EscapeString(a_Message.ExtractText()).c_str())); +} + + + + + void cProtocol161::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) { cCSLock Lock(m_CSPacket); @@ -118,9 +131,10 @@ void cProtocol161::SendHealth(void) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_HEALTH); - WriteFloat((float)m_Client->GetPlayer()->GetHealth()); - WriteShort(m_Client->GetPlayer()->GetFoodLevel()); - WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); + cPlayer * Player = m_Client->GetPlayer(); + WriteFloat((float)Player->GetHealth()); + WriteShort((short)Player->GetFoodLevel()); + WriteFloat((float)Player->GetFoodSaturationLevel()); Flush(); } @@ -131,11 +145,12 @@ void cProtocol161::SendHealth(void) void cProtocol161::SendPlayerMaxSpeed(void) { cCSLock Lock(m_CSPacket); + cPlayer * Player = m_Client->GetPlayer(); WriteByte(PACKET_ENTITY_PROPERTIES); - WriteInt(m_Client->GetPlayer()->GetUniqueID()); + WriteInt(Player->GetUniqueID()); WriteInt(1); WriteString("generic.movementSpeed"); - WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed()); + WriteDouble(0.1 * Player->GetMaxSpeed()); Flush(); } @@ -163,10 +178,10 @@ void cProtocol161::SendWindowOpen(const cWindow & a_Window) } cCSLock Lock(m_CSPacket); WriteByte (PACKET_WINDOW_OPEN); - WriteByte (a_Window.GetWindowID()); - WriteByte (a_Window.GetWindowType()); + WriteChar (a_Window.GetWindowID()); + WriteByte ((Byte)a_Window.GetWindowType()); WriteString(a_Window.GetWindowTitle()); - WriteByte (a_Window.GetNumNonInventorySlots()); + WriteByte ((Byte)a_Window.GetNumNonInventorySlots()); WriteByte (1); // Use title if (a_Window.GetWindowType() == cWindow::wtAnimalChest) { @@ -201,6 +216,25 @@ int cProtocol161::ParseEntityAction(void) +int cProtocol161::ParseLogin(void) +{ + // The login packet is sent by Forge clients only + // Only parse the packet, do no extra processing + // Note that the types and the names have been only guessed and are not verified at all! + HANDLE_PACKET_READ(ReadBEInt, int, Int1); + HANDLE_PACKET_READ(ReadBEUTF16String16, AString, String1); + HANDLE_PACKET_READ(ReadChar, char, Char1); + HANDLE_PACKET_READ(ReadChar, char, Char2); + HANDLE_PACKET_READ(ReadChar, char, Char3); + HANDLE_PACKET_READ(ReadByte, Byte, Byte1); + HANDLE_PACKET_READ(ReadByte, Byte, Byte2); + return PARSE_OK; +} + + + + + int cProtocol161::ParsePlayerAbilities(void) { HANDLE_PACKET_READ(ReadByte, Byte, Flags); @@ -263,11 +297,12 @@ cProtocol162::cProtocol162(cClientHandle * a_Client) : void cProtocol162::SendPlayerMaxSpeed(void) { cCSLock Lock(m_CSPacket); + cPlayer * Player = m_Client->GetPlayer(); WriteByte(PACKET_ENTITY_PROPERTIES); - WriteInt(m_Client->GetPlayer()->GetUniqueID()); + WriteInt(Player->GetUniqueID()); WriteInt(1); WriteString("generic.movementSpeed"); - WriteDouble(0.1 * m_Client->GetPlayer()->GetMaxSpeed()); + WriteDouble(0.1 * Player->GetMaxSpeed()); WriteShort(0); Flush(); } diff --git a/src/Protocol/Protocol16x.h b/src/Protocol/Protocol16x.h index 325e41c5a..8eedce8d5 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -37,6 +37,7 @@ protected: // cProtocol150 overrides: virtual void SendAttachEntity (const cEntity & a_Entity, const cEntity * a_Vehicle) override; virtual void SendChat (const AString & a_Message) override; + virtual void SendChat (const cCompositeChat & a_Message) override; virtual void SendEditSign (int a_BlockX, int a_BlockY, int a_BlockZ) override; ///< Request the client to open up the sign editor for the sign (1.6+) virtual void SendGameMode (eGameMode a_GameMode) override; virtual void SendHealth (void) override; @@ -45,6 +46,7 @@ protected: virtual void SendWindowOpen (const cWindow & a_Window) override; virtual int ParseEntityAction (void) override; + virtual int ParseLogin (void) override; virtual int ParsePlayerAbilities(void) override; // New packets: diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp index 721ed349e..f7564fe6d 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -11,13 +11,19 @@ Implements the 1.7.x protocol classes: #include "json/json.h" #include "Protocol17x.h" #include "ChunkDataSerializer.h" +#include "PolarSSL++/Sha1Checksum.h" + #include "../ClientHandle.h" #include "../Root.h" #include "../Server.h" #include "../World.h" +#include "../StringCompression.h" +#include "../CompositeChat.h" +#include "../Statistics.h" + #include "../WorldStorage/FastNBT.h" #include "../WorldStorage/EnchantmentSerializer.h" -#include "../StringCompression.h" + #include "../Entities/ExpOrb.h" #include "../Entities/Minecart.h" #include "../Entities/FallingBlock.h" @@ -25,12 +31,15 @@ Implements the 1.7.x protocol classes: #include "../Entities/Pickup.h" #include "../Entities/Player.h" #include "../Entities/ItemFrame.h" +#include "../Entities/ArrowEntity.h" +#include "../Entities/FireworkEntity.h" + #include "../Mobs/IncludeAllMonsters.h" #include "../UI/Window.h" + #include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" -#include "../CompositeChat.h" @@ -88,8 +97,9 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd // Create the comm log file, if so requested: if (g_ShouldLogCommIn || g_ShouldLogCommOut) { + static int sCounter = 0; cFile::CreateFolder("CommLogs"); - AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str()); + AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(NULL), sCounter++, a_Client->GetIPString().c_str()); m_CommLogFile.Open(FileName, cFile::fmWrite); } } @@ -124,6 +134,8 @@ void cProtocol172::DataReceived(const char * a_Data, size_t a_Size) void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x1b); // Attach Entity packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0); @@ -136,6 +148,8 @@ void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x24); // Block Action packet Pkt.WriteInt(a_BlockX); Pkt.WriteShort(a_BlockY); @@ -151,6 +165,8 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x25); // Block Break Animation packet Pkt.WriteVarInt(a_EntityID); Pkt.WriteInt(a_BlockX); @@ -165,6 +181,8 @@ void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x23); // Block Change packet Pkt.WriteInt(a_BlockX); Pkt.WriteByte(a_BlockY); @@ -179,11 +197,13 @@ void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x22); // Multi Block Change packet Pkt.WriteInt(a_ChunkX); Pkt.WriteInt(a_ChunkZ); Pkt.WriteShort((short)a_Changes.size()); - Pkt.WriteInt(a_Changes.size() * 4); + Pkt.WriteInt((int)a_Changes.size() * 4); for (sSetBlockVector::const_iterator itr = a_Changes.begin(), end = a_Changes.end(); itr != end; ++itr) { unsigned int Coords = itr->y | (itr->z << 8) | (itr->x << 12); @@ -198,6 +218,8 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV void cProtocol172::SendChat(const AString & a_Message) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x02); // Chat Message packet Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); } @@ -208,9 +230,12 @@ void cProtocol172::SendChat(const AString & a_Message) void cProtocol172::SendChat(const cCompositeChat & a_Message) { + ASSERT(m_State == 3); // In game mode? + // Compose the complete Json string to send: Json::Value msg; - msg["text"] = ""; // The client crashes without this + cWorld * World = m_Client->GetPlayer()->GetWorld(); + msg["text"] = cClientHandle::FormatMessageType((World == NULL) ? false : World->ShouldUseChatPrefixes(), a_Message.GetMessageType(), a_Message.GetAdditionalMessageTypeData()); // The client crashes without this field being present const cCompositeChat::cParts & Parts = a_Message.GetParts(); for (cCompositeChat::cParts::const_iterator itr = Parts.begin(), end = Parts.end(); itr != end; ++itr) { @@ -265,6 +290,35 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message) AddChatPartStyle(Part, p.m_Style); break; } + + case cCompositeChat::ptShowAchievement: + { + const cCompositeChat::cShowAchievementPart & p = (const cCompositeChat::cShowAchievementPart &)**itr; + Part["translate"] = "chat.type.achievement"; + + Json::Value Ach; + Ach["action"] = "show_achievement"; + Ach["value"] = p.m_Text; + + Json::Value AchColourAndName; + AchColourAndName["color"] = "green"; + AchColourAndName["translate"] = p.m_Text; + AchColourAndName["hoverEvent"] = Ach; + + Json::Value Extra; + Extra.append(AchColourAndName); + + Json::Value Name; + Name["text"] = p.m_PlayerName; + + Json::Value With; + With.append(Name); + With.append(Extra); + + Part["with"] = With; + AddChatPartStyle(Part, p.m_Style); + break; + } } msg["extra"].append(Part); } // for itr - Parts[] @@ -280,6 +334,8 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message) void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer) { + ASSERT(m_State == 3); // In game mode? + // Serialize first, before creating the Packetizer (the packetizer locks a CS) // This contains the flags and bitmasks, too const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2); @@ -296,6 +352,8 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x0d); // Collect Item packet Pkt.WriteInt(a_Pickup.GetUniqueID()); Pkt.WriteInt(a_Player.GetUniqueID()); @@ -307,6 +365,8 @@ void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a void cProtocol172::SendDestroyEntity(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x13); // Destroy Entities packet Pkt.WriteByte(1); Pkt.WriteInt(a_Entity.GetUniqueID()); @@ -343,6 +403,8 @@ void cProtocol172::SendDisconnect(const AString & a_Reason) void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockY); @@ -355,6 +417,8 @@ void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ) void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x1D); // Entity Effect packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteByte(a_EffectID); @@ -368,6 +432,8 @@ void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x04); // Entity Equipment packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteShort(a_SlotNum); @@ -380,6 +446,8 @@ void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x19); // Entity Head Look packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); @@ -391,6 +459,8 @@ void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity) void cProtocol172::SendEntityLook(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x16); // Entity Look packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteByteAngle(a_Entity.GetYaw()); @@ -403,6 +473,8 @@ void cProtocol172::SendEntityLook(const cEntity & a_Entity) void cProtocol172::SendEntityMetadata(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteEntityMetadata(a_Entity); @@ -415,6 +487,8 @@ void cProtocol172::SendEntityMetadata(const cEntity & a_Entity) void cProtocol172::SendEntityProperties(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x20); // Entity Properties packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteEntityProperties(a_Entity); @@ -426,6 +500,8 @@ void cProtocol172::SendEntityProperties(const cEntity & a_Entity) void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteByte(a_RelX); @@ -439,6 +515,8 @@ void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteByte(a_RelX); @@ -454,6 +532,8 @@ void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x1a); // Entity Status packet Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteChar(a_Status); @@ -465,6 +545,8 @@ void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status) void cProtocol172::SendEntityVelocity(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x12); // Entity Velocity packet Pkt.WriteInt(a_Entity.GetUniqueID()); // 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick @@ -479,12 +561,14 @@ void cProtocol172::SendEntityVelocity(const cEntity & a_Entity) void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x27); // Explosion packet Pkt.WriteFloat((float)a_BlockX); Pkt.WriteFloat((float)a_BlockY); Pkt.WriteFloat((float)a_BlockZ); Pkt.WriteFloat((float)a_Radius); - Pkt.WriteInt(a_BlocksAffected.size()); + Pkt.WriteInt((int)a_BlocksAffected.size()); for (cVector3iArray::const_iterator itr = a_BlocksAffected.begin(), end = a_BlocksAffected.end(); itr != end; ++itr) { Pkt.WriteChar((char)itr->x); @@ -502,6 +586,8 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc void cProtocol172::SendGameMode(eGameMode a_GameMode) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x2b); // Change Game State packet Pkt.WriteByte(3); // Reason: Change game mode Pkt.WriteFloat((float)a_GameMode); @@ -513,10 +599,13 @@ void cProtocol172::SendGameMode(eGameMode a_GameMode) void cProtocol172::SendHealth(void) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x06); // Update Health packet - Pkt.WriteFloat((float)m_Client->GetPlayer()->GetHealth()); - Pkt.WriteShort(m_Client->GetPlayer()->GetFoodLevel()); - Pkt.WriteFloat((float)m_Client->GetPlayer()->GetFoodSaturationLevel()); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteFloat((float)Player->GetHealth()); + Pkt.WriteShort(Player->GetFoodLevel()); + Pkt.WriteFloat((float)Player->GetFoodSaturationLevel()); } @@ -525,6 +614,8 @@ void cProtocol172::SendHealth(void) void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x2f); // Set Slot packet Pkt.WriteChar(a_WindowID); Pkt.WriteShort(a_SlotNum); @@ -537,6 +628,13 @@ void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt void cProtocol172::SendKeepAlive(int a_PingID) { + // Drop the packet if the protocol is not in the Game state yet (caused a client crash): + if (m_State != 3) + { + LOGWARNING("Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet.", m_State); + return; + } + cPacketizer Pkt(*this, 0x00); // Keep Alive packet Pkt.WriteInt(a_PingID); } @@ -549,12 +647,13 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) { // Send the Join Game packet: { + cServer * Server = cRoot::Get()->GetServer(); cPacketizer Pkt(*this, 0x01); // Join Game packet Pkt.WriteInt(a_Player.GetUniqueID()); - Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (cRoot::Get()->GetServer()->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 + Pkt.WriteByte((Byte)a_Player.GetEffectiveGameMode() | (Server->IsHardcore() ? 0x08 : 0)); // Hardcore flag bit 4 Pkt.WriteChar((char)a_World.GetDimension()); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte(std::min(cRoot::Get()->GetServer()->GetMaxPlayers(), 60)); + Pkt.WriteByte(std::min(Server->GetMaxPlayers(), 60)); Pkt.WriteString("default"); // Level type - wtf? } @@ -573,8 +672,27 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World) +void cProtocol172::SendLoginSuccess(void) +{ + ASSERT(m_State == 2); // State: login? + + { + cPacketizer Pkt(*this, 0x02); // Login success packet + Pkt.WriteString(m_Client->GetUUID()); + Pkt.WriteString(m_Client->GetUsername()); + } + + m_State = 3; // State = Game +} + + + + + void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x10); // Spawn Painting packet Pkt.WriteVarInt(a_Painting.GetUniqueID()); Pkt.WriteString(a_Painting.GetName().c_str()); @@ -590,6 +708,8 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting) void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x34); Pkt.WriteVarInt(a_ID); Pkt.WriteShort (3 + a_Length); @@ -610,9 +730,11 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x34); Pkt.WriteVarInt(a_ID); - Pkt.WriteShort (1 + (3 * a_Decorators.size())); + Pkt.WriteShort ((short)(1 + (3 * a_Decorators.size()))); Pkt.WriteByte(1); @@ -630,6 +752,8 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x34); Pkt.WriteVarInt(a_ID); Pkt.WriteShort (2); @@ -645,6 +769,8 @@ void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale) void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup) { + ASSERT(m_State == 3); // In game mode? + { cPacketizer Pkt(*this, 0x0e); // Spawn Object packet Pkt.WriteVarInt(a_Pickup.GetUniqueID()); @@ -671,24 +797,27 @@ void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup) void cProtocol172::SendPlayerAbilities(void) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x39); // Player Abilities packet Byte Flags = 0; - if (m_Client->GetPlayer()->IsGameModeCreative()) + cPlayer * Player = m_Client->GetPlayer(); + if (Player->IsGameModeCreative()) { Flags |= 0x01; Flags |= 0x08; // Godmode, used for creative } - if (m_Client->GetPlayer()->IsFlying()) + if (Player->IsFlying()) { Flags |= 0x02; } - if (m_Client->GetPlayer()->CanFly()) + if (Player->CanFly()) { Flags |= 0x04; } Pkt.WriteByte(Flags); - Pkt.WriteFloat((float)(0.05 * m_Client->GetPlayer()->GetFlyingMaxSpeed())); - Pkt.WriteFloat((float)(0.1 * m_Client->GetPlayer()->GetMaxSpeed())); + Pkt.WriteFloat((float)(0.05 * Player->GetFlyingMaxSpeed())); + Pkt.WriteFloat((float)(0.1 * Player->GetMaxSpeed())); } @@ -697,6 +826,8 @@ void cProtocol172::SendPlayerAbilities(void) void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x0b); // Animation packet Pkt.WriteVarInt(a_Entity.GetUniqueID()); Pkt.WriteChar(a_Animation); @@ -708,6 +839,8 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x2A); Pkt.WriteString(a_ParticleName); Pkt.WriteFloat(a_SrcX); @@ -726,6 +859,8 @@ void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_Sr void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x38); // Playerlist Item packet Pkt.WriteString(a_Player.GetName()); Pkt.WriteBool(a_IsOnline); @@ -738,18 +873,21 @@ void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline) void cProtocol172::SendPlayerMaxSpeed(void) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x20); // Entity Properties - Pkt.WriteInt(m_Client->GetPlayer()->GetUniqueID()); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteInt(Player->GetUniqueID()); Pkt.WriteInt(1); // Count Pkt.WriteString("generic.movementSpeed"); // The default game speed is 0.1, multiply that value by the relative speed: - Pkt.WriteDouble(0.1 * m_Client->GetPlayer()->GetNormalMaxSpeed()); - if (m_Client->GetPlayer()->IsSprinting()) + Pkt.WriteDouble(0.1 * Player->GetNormalMaxSpeed()); + if (Player->IsSprinting()) { Pkt.WriteShort(1); // Modifier count Pkt.WriteInt64(0x662a6b8dda3e4c1c); Pkt.WriteInt64(0x881396ea6097278d); // UUID of the modifier - Pkt.WriteDouble(m_Client->GetPlayer()->GetSprintingMaxSpeed() - m_Client->GetPlayer()->GetNormalMaxSpeed()); + Pkt.WriteDouble(Player->GetSprintingMaxSpeed() - Player->GetNormalMaxSpeed()); Pkt.WriteByte(2); } else @@ -764,17 +902,20 @@ void cProtocol172::SendPlayerMaxSpeed(void) void cProtocol172::SendPlayerMoveLook(void) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x08); // Player Position And Look packet - Pkt.WriteDouble(m_Client->GetPlayer()->GetPosX()); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteDouble(Player->GetPosX()); // Protocol docs say this is PosY, but #323 says this is eye-pos // Moreover, the "+ 0.001" is there because otherwise the player falls through the block they were standing on. - Pkt.WriteDouble(m_Client->GetPlayer()->GetStance() + 0.001); + Pkt.WriteDouble(Player->GetStance() + 0.001); - Pkt.WriteDouble(m_Client->GetPlayer()->GetPosZ()); - Pkt.WriteFloat((float)m_Client->GetPlayer()->GetYaw()); - Pkt.WriteFloat((float)m_Client->GetPlayer()->GetPitch()); - Pkt.WriteBool(m_Client->GetPlayer()->IsOnGround()); + Pkt.WriteDouble(Player->GetPosZ()); + Pkt.WriteFloat((float)Player->GetYaw()); + Pkt.WriteFloat((float)Player->GetPitch()); + Pkt.WriteBool(Player->IsOnGround()); } @@ -793,10 +934,12 @@ void cProtocol172::SendPlayerPosition(void) void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) { + ASSERT(m_State == 3); // In game mode? + // Called to spawn another player for the client cPacketizer Pkt(*this, 0x0c); // Spawn Player packet Pkt.WriteVarInt(a_Player.GetUniqueID()); - Pkt.WriteString(Printf("%d", a_Player.GetUniqueID())); // TODO: Proper UUID + Pkt.WriteString(a_Player.GetClientHandle()->GetUUID()); Pkt.WriteString(a_Player.GetName()); Pkt.WriteFPInt(a_Player.GetPosX()); Pkt.WriteFPInt(a_Player.GetPosY()); @@ -816,6 +959,8 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x3f); Pkt.WriteString(a_Channel); Pkt.WriteShort((short)a_Message.size()); @@ -828,7 +973,9 @@ void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID) { - cPacketizer Pkt(*this, 0x1E); + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x1e); Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteByte(a_EffectID); } @@ -840,9 +987,10 @@ void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_Effect void cProtocol172::SendRespawn(void) { cPacketizer Pkt(*this, 0x07); // Respawn packet - Pkt.WriteInt(m_Client->GetPlayer()->GetWorld()->GetDimension()); + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteInt(Player->GetWorld()->GetDimension()); Pkt.WriteByte(2); // TODO: Difficulty (set to Normal) - Pkt.WriteByte((Byte)m_Client->GetPlayer()->GetEffectiveGameMode()); + Pkt.WriteByte((Byte)Player->GetEffectiveGameMode()); Pkt.WriteString("default"); } @@ -852,10 +1000,13 @@ void cProtocol172::SendRespawn(void) void cProtocol172::SendExperience (void) { - cPacketizer Pkt(*this, 0x1F); //Experience Packet - Pkt.WriteFloat(m_Client->GetPlayer()->GetXpPercentage()); - Pkt.WriteShort(m_Client->GetPlayer()->GetXpLevel()); - Pkt.WriteShort(m_Client->GetPlayer()->GetCurrentXp()); + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x1f); // Experience Packet + cPlayer * Player = m_Client->GetPlayer(); + Pkt.WriteFloat(Player->GetXpPercentage()); + Pkt.WriteShort(Player->GetXpLevel()); + Pkt.WriteShort(Player->GetCurrentXp()); } @@ -864,6 +1015,8 @@ void cProtocol172::SendExperience (void) void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x11); Pkt.WriteVarInt(a_ExpOrb.GetUniqueID()); Pkt.WriteInt((int) a_ExpOrb.GetPosX()); @@ -878,7 +1031,9 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) { - cPacketizer Pkt(*this, 0x3B); + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3b); Pkt.WriteString(a_Name); Pkt.WriteString(a_DisplayName); Pkt.WriteByte(a_Mode); @@ -890,7 +1045,9 @@ void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) { - cPacketizer Pkt(*this, 0x3C); + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3c); Pkt.WriteString(a_Player); Pkt.WriteByte(a_Mode); @@ -907,7 +1064,9 @@ void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) { - cPacketizer Pkt(*this, 0x3D); + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x3d); Pkt.WriteByte((int) a_Display); Pkt.WriteString(a_Objective); } @@ -918,6 +1077,8 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8 { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x29); // Sound Effect packet Pkt.WriteString(a_SoundName); Pkt.WriteInt(a_SrcX); @@ -933,6 +1094,8 @@ void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x28); // Effect packet Pkt.WriteInt(a_EffectID); Pkt.WriteInt(a_SrcX); @@ -948,6 +1111,8 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x0e); // Spawn Object packet Pkt.WriteVarInt(a_FallingBlock.GetUniqueID()); Pkt.WriteByte(70); // Falling block @@ -968,6 +1133,8 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock) void cProtocol172::SendSpawnMob(const cMonster & a_Mob) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet Pkt.WriteVarInt(a_Mob.GetUniqueID()); Pkt.WriteByte((Byte)a_Mob.GetMobType()); @@ -990,6 +1157,8 @@ void cProtocol172::SendSpawnMob(const cMonster & a_Mob) void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0xe); // Spawn Object packet Pkt.WriteVarInt(a_Entity.GetUniqueID()); Pkt.WriteByte(a_ObjectType); @@ -1013,6 +1182,8 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0xe); // Spawn Object packet Pkt.WriteVarInt(a_Vehicle.GetUniqueID()); Pkt.WriteByte(a_VehicleType); @@ -1034,10 +1205,34 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp +void cProtocol172::SendStatistics(const cStatManager & a_Manager) +{ + ASSERT(m_State == 3); // In game mode? + + cPacketizer Pkt(*this, 0x37); + Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only + + for (unsigned int i = 0; i < (unsigned int)statCount; ++i) + { + StatValue Value = a_Manager.GetValue((eStatistic) i); + + const AString & StatName = cStatInfo::GetName((eStatistic) i); + + Pkt.WriteString(StatName); + Pkt.WriteVarInt(Value); + } +} + + + + + void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet - Pkt.WriteVarInt(a_Results.size()); + Pkt.WriteVarInt((int)a_Results.size()); for (AStringVector::const_iterator itr = a_Results.begin(), end = a_Results.end(); itr != end; ++itr) { @@ -1051,6 +1246,8 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results) void cProtocol172::SendTeleportEntity(const cEntity & a_Entity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x18); Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteFPInt(a_Entity.GetPosX()); @@ -1066,6 +1263,8 @@ void cProtocol172::SendTeleportEntity(const cEntity & a_Entity) void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet Pkt.WriteVarInt(0); // EntityID = 0, always Pkt.WriteByte(1); // Type = Thunderbolt @@ -1080,6 +1279,8 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ) void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x03); Pkt.WriteInt64(a_WorldAge); Pkt.WriteInt64(a_TimeOfDay); @@ -1091,6 +1292,8 @@ void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay) void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x21); // Chunk Data packet Pkt.WriteInt(a_ChunkX); Pkt.WriteInt(a_ChunkZ); @@ -1105,6 +1308,8 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ) void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x35); // Update tile entity packet Pkt.WriteInt(a_BlockEntity.GetPosX()); Pkt.WriteShort(a_BlockEntity.GetPosY()); @@ -1130,6 +1335,8 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x33); Pkt.WriteInt(a_BlockX); Pkt.WriteShort((short)a_BlockY); @@ -1147,6 +1354,8 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x0a); Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_BlockX); @@ -1160,6 +1369,8 @@ void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc void cProtocol172::SendWeather(eWeather a_Weather) { + ASSERT(m_State == 3); // In game mode? + { cPacketizer Pkt(*this, 0x2b); // Change Game State packet Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain @@ -1175,6 +1386,8 @@ void cProtocol172::SendWeather(eWeather a_Weather) void cProtocol172::SendWholeInventory(const cWindow & a_Window) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x30); // Window Items packet Pkt.WriteChar(a_Window.GetWindowID()); Pkt.WriteShort(a_Window.GetNumSlots()); @@ -1192,6 +1405,8 @@ void cProtocol172::SendWholeInventory(const cWindow & a_Window) void cProtocol172::SendWindowClose(const cWindow & a_Window) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x2e); Pkt.WriteChar(a_Window.GetWindowID()); } @@ -1202,6 +1417,8 @@ void cProtocol172::SendWindowClose(const cWindow & a_Window) void cProtocol172::SendWindowOpen(const cWindow & a_Window) { + ASSERT(m_State == 3); // In game mode? + if (a_Window.GetWindowType() < 0) { // Do not send this packet for player inventory windows @@ -1224,8 +1441,10 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window) -void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) +void cProtocol172::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) { + ASSERT(m_State == 3); // In game mode? + cPacketizer Pkt(*this, 0x31); // Window Property packet Pkt.WriteChar(a_Window.GetWindowID()); Pkt.WriteShort(a_Property); @@ -1236,7 +1455,7 @@ void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property -void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) +void cProtocol172::AddReceivedData(const char * a_Data, size_t a_Size) { // Write the incoming data into the comm log file: if (g_ShouldLogCommIn) @@ -1258,7 +1477,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) AString Hex; CreateHexDump(Hex, a_Data, a_Size, 16); m_CommLogFile.Printf("Incoming data: %d (0x%x) bytes: \n%s\n", - a_Size, a_Size, Hex.c_str() + (unsigned)a_Size, (unsigned)a_Size, Hex.c_str() ); m_CommLogFile.Flush(); } @@ -1431,6 +1650,7 @@ bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType) case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true; case 0x0f: // Confirm transaction - not used in MCS case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true; + case 0x11: HandlePacketEnchantItem (a_ByteBuffer); return true; case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true; case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true; case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true; @@ -1485,15 +1705,16 @@ void cProtocol172::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) { // Send the response: AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{"; + cServer * Server = cRoot::Get()->GetServer(); AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},", - cRoot::Get()->GetServer()->GetMaxPlayers(), - cRoot::Get()->GetServer()->GetNumPlayers() + Server->GetMaxPlayers(), + Server->GetNumPlayers() ); AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},", - cRoot::Get()->GetServer()->GetDescription().c_str() + Server->GetDescription().c_str() ); AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"", - cRoot::Get()->GetServer()->GetFaviconData().c_str() + Server->GetFaviconData().c_str() ); Response.append("}"); @@ -1528,7 +1749,7 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe } // Decrypt EncNonce using privkey - cRSAPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); + cRsaPrivateKey & rsaDecryptor = cRoot::Get()->GetServer()->GetPrivateKey(); Int32 DecryptedNonce[MAX_ENC_LEN / sizeof(Int32)]; int res = rsaDecryptor.Decrypt((const Byte *)EncNonce.data(), EncNonce.size(), (Byte *)DecryptedNonce, sizeof(DecryptedNonce)); if (res != 4) @@ -1555,15 +1776,6 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe } StartEncryption(DecryptedKey); - - // Send login success: - { - cPacketizer Pkt(*this, 0x02); // Login success packet - Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID - Pkt.WriteString(m_Client->GetUsername()); - } - - m_State = 3; // State = Game m_Client->HandleLogin(4, m_Client->GetUsername()); } @@ -1582,13 +1794,14 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) return; } + cServer * Server = cRoot::Get()->GetServer(); // If auth is required, then send the encryption request: - if (cRoot::Get()->GetServer()->ShouldAuthenticate()) + if (Server->ShouldAuthenticate()) { cPacketizer Pkt(*this, 0x01); - Pkt.WriteString(cRoot::Get()->GetServer()->GetServerID()); - const AString & PubKeyDer = cRoot::Get()->GetServer()->GetPublicKeyDER(); - Pkt.WriteShort(PubKeyDer.size()); + Pkt.WriteString(Server->GetServerID()); + const AString & PubKeyDer = Server->GetPublicKeyDER(); + Pkt.WriteShort((short)PubKeyDer.size()); Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); Pkt.WriteShort(4); Pkt.WriteInt((int)(intptr_t)this); // Using 'this' as the cryptographic nonce, so that we don't have to generate one each time :) @@ -1596,14 +1809,6 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer) return; } - // Send login success: - { - cPacketizer Pkt(*this, 0x02); // Login success packet - Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID - Pkt.WriteString(Username); - } - - m_State = 3; // State = Game m_Client->HandleLogin(4, Username); } @@ -1696,13 +1901,15 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer) case 1: { // Request stats - // TODO + const cStatManager & Manager = m_Client->GetPlayer()->GetStatManager(); + SendStatistics(Manager); + break; } case 2: { // Open Inventory achievement - // TODO + m_Client->GetPlayer()->AwardAchievement(achOpenInv); break; } } @@ -1912,6 +2119,18 @@ void cProtocol172::HandlePacketUseEntity(cByteBuffer & a_ByteBuffer) +void cProtocol172::HandlePacketEnchantItem(cByteBuffer & a_ByteBuffer) +{ + HANDLE_READ(a_ByteBuffer, ReadByte, Byte, WindowID); + HANDLE_READ(a_ByteBuffer, ReadByte, Byte, Enchantment); + + m_Client->HandleEnchantItem(WindowID, Enchantment); +} + + + + + void cProtocol172::HandlePacketWindowClick(cByteBuffer & a_ByteBuffer) { HANDLE_READ(a_ByteBuffer, ReadChar, char, WindowID); @@ -1979,7 +2198,7 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet) cCSLock Lock(m_CSPacket); AString Pkt; a_Packet.ReadAll(Pkt); - WriteVarInt(Pkt.size()); + WriteVarInt((UInt32)Pkt.size()); SendData(Pkt.data(), Pkt.size()); Flush(); } @@ -1988,14 +2207,14 @@ void cProtocol172::WritePacket(cByteBuffer & a_Packet) -void cProtocol172::SendData(const char * a_Data, int a_Size) +void cProtocol172::SendData(const char * a_Data, size_t a_Size) { if (m_IsEncrypted) { Byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) while (a_Size > 0) { - size_t NumBytes = ((size_t)a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : (size_t)a_Size; + size_t NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; m_Encryptor.ProcessData(Encrypted, (Byte *)a_Data, NumBytes); m_Client->SendData((const char *)Encrypted, NumBytes); a_Size -= NumBytes; @@ -2119,6 +2338,13 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata) } break; } + case TAG_Int: + { + if (TagName == "RepairCost") + { + a_Item.m_RepairCost = NBT.GetInt(tag); + } + } default: LOGD("Unimplemented NBT data when parsing!"); break; } } @@ -2135,14 +2361,15 @@ void cProtocol172::StartEncryption(const Byte * a_Key) m_IsEncrypted = true; // Prepare the m_AuthServerID: - cSHA1Checksum Checksum; - const AString & ServerID = cRoot::Get()->GetServer()->GetServerID(); + cSha1Checksum Checksum; + cServer * Server = cRoot::Get()->GetServer(); + const AString & ServerID = Server->GetServerID(); Checksum.Update((const Byte *)ServerID.c_str(), ServerID.length()); Checksum.Update(a_Key, 16); - Checksum.Update((const Byte *)cRoot::Get()->GetServer()->GetPublicKeyDER().data(), cRoot::Get()->GetServer()->GetPublicKeyDER().size()); + Checksum.Update((const Byte *)Server->GetPublicKeyDER().data(), Server->GetPublicKeyDER().size()); Byte Digest[20]; Checksum.Finalize(Digest); - cSHA1Checksum::DigestToJava(Digest, m_AuthServerID); + cSha1Checksum::DigestToJava(Digest, m_AuthServerID); } @@ -2236,7 +2463,7 @@ cProtocol172::cPacketizer::~cPacketizer() AString DataToSend; // Send the packet length - UInt32 PacketLen = m_Out.GetUsedSpace(); + UInt32 PacketLen = (UInt32)m_Out.GetUsedSpace(); m_Protocol.m_OutPacketLenBuffer.WriteVarInt(PacketLen); m_Protocol.m_OutPacketLenBuffer.ReadAll(DataToSend); m_Protocol.SendData(DataToSend.data(), DataToSend.size()); @@ -2291,6 +2518,10 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) // Send the enchantments and custom names: cFastNBTWriter Writer; + if (a_Item.m_RepairCost != 0) + { + Writer.AddInt("RepairCost", a_Item.m_RepairCost); + } if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; @@ -2329,7 +2560,7 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item) Writer.Finish(); AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } @@ -2399,7 +2630,7 @@ void cProtocol172::cPacketizer::WriteBlockEntity(const cBlockEntity & a_BlockEnt AString Compressed; CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed); - WriteShort(Compressed.size()); + WriteShort((short)Compressed.size()); WriteBuf(Compressed.data(), Compressed.size()); } @@ -2481,11 +2712,12 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone) { cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity); - if (!RideableMinecart.GetContent().IsEmpty()) + const cItem & MinecartContent = RideableMinecart.GetContent(); + if (!MinecartContent.IsEmpty()) { WriteByte(0x54); - int Content = RideableMinecart.GetContent().m_ItemType; - Content |= RideableMinecart.GetContent().m_ItemDamage << 8; + int Content = MinecartContent.m_ItemType; + Content |= MinecartContent.m_ItemDamage << 8; WriteInt(Content); WriteByte(0x55); WriteInt(RideableMinecart.GetBlockHeight()); @@ -2535,6 +2767,7 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity) WriteByte(Frame.GetRotation()); break; } + default: break; } } @@ -2659,6 +2892,15 @@ void cProtocol172::cPacketizer::WriteMobMetadata(const cMonster & a_Mob) WriteByte(((const cWitch &)a_Mob).IsAngry() ? 1 : 0); break; } + + case cMonster::mtWither: + { + WriteByte(0x54); // Int at index 20 + WriteInt(((const cWither &)a_Mob).GetWitherInvulnerableTicks()); + WriteByte(0x66); // Float at index 6 + WriteFloat((float)(a_Mob.GetHealth())); + break; + } case cMonster::mtSlime: { @@ -2745,3 +2987,64 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity) + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cProtocol176: + +cProtocol176::cProtocol176(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : + super(a_Client, a_ServerAddress, a_ServerPort, a_State) +{ +} + + + + + +void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player) +{ + // Called to spawn another player for the client + cPacketizer Pkt(*this, 0x0c); // Spawn Player packet + Pkt.WriteVarInt(a_Player.GetUniqueID()); + Pkt.WriteString(a_Player.GetClientHandle()->GetUUID()); + Pkt.WriteString(a_Player.GetName()); + Pkt.WriteVarInt(0); // We have no data to send here + Pkt.WriteFPInt(a_Player.GetPosX()); + Pkt.WriteFPInt(a_Player.GetPosY()); + Pkt.WriteFPInt(a_Player.GetPosZ()); + Pkt.WriteByteAngle(a_Player.GetYaw()); + Pkt.WriteByteAngle(a_Player.GetPitch()); + short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType; + Pkt.WriteShort(ItemType); + Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6 + Pkt.WriteFloat((float)a_Player.GetHealth()); + Pkt.WriteByte(0x7f); // Metadata: end +} + + + + + +void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) +{ + // Send the response: + AString Response = "{\"version\":{\"name\":\"1.7.6\",\"protocol\":5},\"players\":{"; + AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},", + cRoot::Get()->GetServer()->GetMaxPlayers(), + cRoot::Get()->GetServer()->GetNumPlayers() + ); + AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},", + cRoot::Get()->GetServer()->GetDescription().c_str() + ); + AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"", + cRoot::Get()->GetServer()->GetFaviconData().c_str() + ); + Response.append("}"); + + cPacketizer Pkt(*this, 0x00); // Response packet + Pkt.WriteString(Response); +} + + + + + diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h index 41163009e..3c6a8c085 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -30,7 +30,8 @@ Declares the 1.7.x protocol classes: #pragma warning(pop) #endif -#include "../Crypto.h" +#include "PolarSSL++/AesCfb128Decryptor.h" +#include "PolarSSL++/AesCfb128Encryptor.h" @@ -87,6 +88,7 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendLoginSuccess (void) override; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; @@ -114,6 +116,7 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; + virtual void SendStatistics (const cStatManager & a_Manager) override; virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; @@ -126,7 +129,7 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) override; virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; + virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; virtual AString GetAuthServerID(void) override { return m_AuthServerID; } @@ -196,7 +199,7 @@ protected: m_Out.WriteVarUTF8String(a_Value); } - void WriteBuf(const char * a_Data, int a_Size) + void WriteBuf(const char * a_Data, size_t a_Size) { m_Out.Write(a_Data, a_Size); } @@ -235,15 +238,15 @@ protected: bool m_IsEncrypted; - cAESCFBDecryptor m_Decryptor; - cAESCFBEncryptor m_Encryptor; + cAesCfb128Decryptor m_Decryptor; + cAesCfb128Encryptor m_Encryptor; /** The logfile where the comm is logged, when g_ShouldLogComm is true */ cFile m_CommLogFile; /** Adds the received (unencrypted) data to m_ReceivedData, parses complete packets */ - void AddReceivedData(const char * a_Data, int a_Size); + void AddReceivedData(const char * a_Data, size_t a_Size); /** Reads and handles the packet. The packet length and type have already been read. Returns true if the packet was understood, false if it was an unknown packet @@ -252,7 +255,7 @@ protected: // Packet handlers while in the Status state (m_State == 1): void HandlePacketStatusPing (cByteBuffer & a_ByteBuffer); - void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer); + virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer); // Packet handlers while in the Login state (m_State == 2): void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer); @@ -279,6 +282,7 @@ protected: void HandlePacketTabComplete (cByteBuffer & a_ByteBuffer); void HandlePacketUpdateSign (cByteBuffer & a_ByteBuffer); void HandlePacketUseEntity (cByteBuffer & a_ByteBuffer); + void HandlePacketEnchantItem (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClick (cByteBuffer & a_ByteBuffer); void HandlePacketWindowClose (cByteBuffer & a_ByteBuffer); @@ -287,7 +291,7 @@ protected: void WritePacket(cByteBuffer & a_Packet); /** Sends the data to the client, encrypting them if needed. */ - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; void SendCompass(const cWorld & a_World); @@ -306,3 +310,22 @@ protected: + +/** The version 5 lengthed protocol, used by 1.7.6 through 1.7.9. */ +class cProtocol176 : + public cProtocol172 +{ + typedef cProtocol172 super; + +public: + cProtocol176(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); + + // cProtocol172 overrides: + virtual void SendPlayerSpawn(const cPlayer & a_Player) override; + virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override; + +} ; + + + + diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp index 3b9003e60..b0cbb6def 100644 --- a/src/Protocol/ProtocolRecognizer.cpp +++ b/src/Protocol/ProtocolRecognizer.cpp @@ -59,6 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion) case PROTO_VERSION_1_6_3: return "1.6.3"; case PROTO_VERSION_1_6_4: return "1.6.4"; case PROTO_VERSION_1_7_2: return "1.7.2"; + case PROTO_VERSION_1_7_6: return "1.7.6"; } ASSERT(!"Unknown protocol version"); return Printf("Unknown protocol (%d)", a_ProtocolVersion); @@ -356,7 +357,7 @@ void cProtocolRecognizer::SendHealth(void) -void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value) +void cProtocolRecognizer::SendWindowProperty(const cWindow & a_Window, int a_Property, int a_Value) { ASSERT(m_Protocol != NULL); m_Protocol->SendWindowProperty(a_Window, a_Property, a_Value); @@ -396,6 +397,16 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W +void cProtocolRecognizer::SendLoginSuccess(void) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendLoginSuccess(); +} + + + + + void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) { ASSERT(m_Protocol != NULL); @@ -664,6 +675,16 @@ void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_Veh +void cProtocolRecognizer::SendStatistics(const cStatManager & a_Manager) +{ + ASSERT(m_Protocol != NULL); + m_Protocol->SendStatistics(a_Manager); +} + + + + + void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Results) { ASSERT(m_Protocol != NULL); @@ -794,7 +815,7 @@ AString cProtocolRecognizer::GetAuthServerID(void) -void cProtocolRecognizer::SendData(const char * a_Data, int a_Size) +void cProtocolRecognizer::SendData(const char * a_Data, size_t a_Size) { // This is used only when handling the server ping m_Client->SendData(a_Data, a_Size); @@ -854,13 +875,13 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) // This must be a lengthed protocol, try if it has the entire initial handshake packet: m_Buffer.ResetRead(); UInt32 PacketLen; - UInt32 ReadSoFar = m_Buffer.GetReadableSpace(); + UInt32 ReadSoFar = (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.ReadVarInt(PacketLen)) { // Not enough bytes for the packet length, keep waiting return false; } - ReadSoFar -= m_Buffer.GetReadableSpace(); + ReadSoFar -= (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.CanReadBytes(PacketLen)) { // Not enough bytes for the packet, keep waiting @@ -931,7 +952,7 @@ bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining) { UInt32 PacketType; - UInt32 NumBytesRead = m_Buffer.GetReadableSpace(); + UInt32 NumBytesRead = (UInt32)m_Buffer.GetReadableSpace(); if (!m_Buffer.ReadVarInt(PacketType)) { return false; @@ -950,7 +971,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema { return false; } - NumBytesRead -= m_Buffer.GetReadableSpace(); + NumBytesRead -= (UInt32)m_Buffer.GetReadableSpace(); switch (ProtocolVersion) { case PROTO_VERSION_1_7_2: @@ -962,7 +983,19 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema m_Buffer.ReadBEShort(ServerPort); m_Buffer.ReadVarInt(NextState); m_Buffer.CommitRead(); - m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState); + m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState); + return true; + } + case PROTO_VERSION_1_7_6: + { + AString ServerAddress; + short ServerPort; + UInt32 NextState; + m_Buffer.ReadVarUTF8String(ServerAddress); + m_Buffer.ReadBEShort(ServerPort); + m_Buffer.ReadVarInt(NextState); + m_Buffer.CommitRead(); + m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState); return true; } } @@ -980,6 +1013,7 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema void cProtocolRecognizer::SendLengthlessServerPing(void) { AString Reply; + cServer * Server = cRoot::Get()->GetServer(); switch (cRoot::Get()->GetPrimaryServerVersion()) { case PROTO_VERSION_1_2_5: @@ -987,11 +1021,11 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) { // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3099#Server_List_Ping_.280xFE.29 Printf(Reply, "%s%s%i%s%i", - cRoot::Get()->GetServer()->GetDescription().c_str(), + Server->GetDescription().c_str(), cChatColor::Delimiter.c_str(), - cRoot::Get()->GetServer()->GetNumPlayers(), + Server->GetNumPlayers(), cChatColor::Delimiter.c_str(), - cRoot::Get()->GetServer()->GetMaxPlayers() + Server->GetMaxPlayers() ); break; } @@ -1021,9 +1055,9 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) // http://wiki.vg/wiki/index.php?title=Server_List_Ping&oldid=3100 AString NumPlayers; - Printf(NumPlayers, "%d", cRoot::Get()->GetServer()->GetNumPlayers()); + Printf(NumPlayers, "%d", Server->GetNumPlayers()); AString MaxPlayers; - Printf(MaxPlayers, "%d", cRoot::Get()->GetServer()->GetMaxPlayers()); + Printf(MaxPlayers, "%d", Server->GetMaxPlayers()); AString ProtocolVersionNum; Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion()); @@ -1037,7 +1071,7 @@ void cProtocolRecognizer::SendLengthlessServerPing(void) Reply.push_back(0); Reply.append(ProtocolVersionTxt); Reply.push_back(0); - Reply.append(cRoot::Get()->GetServer()->GetDescription()); + Reply.append(Server->GetDescription()); Reply.push_back(0); Reply.append(NumPlayers); Reply.push_back(0); diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h index d7fb8fad2..3a291bf7a 100644 --- a/src/Protocol/ProtocolRecognizer.h +++ b/src/Protocol/ProtocolRecognizer.h @@ -18,8 +18,8 @@ // Adjust these if a new protocol is added or an old one is removed: -#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4" -#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4" +#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9" +#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4, 5" @@ -50,6 +50,7 @@ public: // These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols PROTO_VERSION_1_7_2 = 4, + PROTO_VERSION_1_7_6 = 5, } ; cProtocolRecognizer(cClientHandle * a_Client); @@ -90,6 +91,7 @@ public: virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendKeepAlive (int a_PingID) override; virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override; + virtual void SendLoginSuccess (void) override; virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override; virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; @@ -117,6 +119,7 @@ public: virtual void SendSpawnMob (const cMonster & a_Mob) override; virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override; virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override; + virtual void SendStatistics (const cStatManager & a_Manager) override; virtual void SendTabCompletionResults(const AStringVector & a_Results) override; virtual void SendTeleportEntity (const cEntity & a_Entity) override; virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override; @@ -129,11 +132,11 @@ public: virtual void SendWholeInventory (const cWindow & a_Window) override; virtual void SendWindowClose (const cWindow & a_Window) override; virtual void SendWindowOpen (const cWindow & a_Window) override; - virtual void SendWindowProperty (const cWindow & a_Window, short a_Property, short a_Value) override; + virtual void SendWindowProperty (const cWindow & a_Window, int a_Property, int a_Value) override; virtual AString GetAuthServerID(void) override; - virtual void SendData(const char * a_Data, int a_Size) override; + virtual void SendData(const char * a_Data, size_t a_Size) override; protected: cProtocol * m_Protocol; //< The recognized protocol diff --git a/src/RCONServer.cpp b/src/RCONServer.cpp index 72f2d9ba9..c511968be 100644 --- a/src/RCONServer.cpp +++ b/src/RCONServer.cpp @@ -59,7 +59,7 @@ public: virtual void Finished(void) override { - m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, m_Buffer.size(), m_Buffer.c_str()); + m_Connection.SendResponse(m_RequestID, RCON_PACKET_RESPONSE, (int)m_Buffer.size(), m_Buffer.c_str()); delete this; } @@ -169,7 +169,7 @@ cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_So -void cRCONServer::cConnection::DataReceived(const char * a_Data, int a_Size) +bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size) { // Append data to the buffer: m_Buffer.append(a_Data, a_Size); @@ -187,12 +187,12 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, int a_Size) m_RCONServer.m_SocketThreads.RemoveClient(this); m_Socket.CloseSocket(); delete this; - return; + return false; } if (Length > (int)(m_Buffer.size() + 4)) { // Incomplete packet yet, wait for more data to come - return; + return false; } int RequestID = IntFromBuffer(m_Buffer.data() + 4); @@ -202,10 +202,11 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, int a_Size) m_RCONServer.m_SocketThreads.RemoveClient(this); m_Socket.CloseSocket(); delete this; - return; + return false; } m_Buffer.erase(0, Length + 4); } // while (m_Buffer.size() >= 14) + return false; } diff --git a/src/RCONServer.h b/src/RCONServer.h index 88aac4b5f..47c746736 100644 --- a/src/RCONServer.h +++ b/src/RCONServer.h @@ -65,7 +65,7 @@ protected: // cSocketThreads::cCallback overrides: - virtual void DataReceived(const char * a_Data, int a_Size) override; + virtual bool DataReceived(const char * a_Data, size_t a_Size) override; virtual void GetOutgoingData(AString & a_Data) override; virtual void SocketClosed(void) override; diff --git a/src/Root.cpp b/src/Root.cpp index 3555afb45..c82b05a66 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -304,6 +304,7 @@ void cRoot::LoadWorlds(cIniFile & IniFile) { if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld") { + IniFile.DeleteKeyComment("Worlds", 0); IniFile.AddKeyComment("Worlds", " World=secondworld"); } } @@ -498,9 +499,9 @@ void cRoot::KickUser(int a_ClientID, const AString & a_Reason) -void cRoot::AuthenticateUser(int a_ClientID) +void cRoot::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID) { - m_Server->AuthenticateUser(a_ClientID); + m_Server->AuthenticateUser(a_ClientID, a_Name, a_UUID); } @@ -589,13 +590,13 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac { class cCallback : public cPlayerListCallback { - unsigned m_BestRating; - unsigned m_NameLength; + size_t m_BestRating; + size_t m_NameLength; const AString m_PlayerName; virtual bool Item (cPlayer * a_pPlayer) { - unsigned int Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName()); + size_t Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName()); if ((Rating > 0) && (Rating >= m_BestRating)) { m_BestMatch = a_pPlayer; @@ -625,7 +626,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallbac cPlayer * m_BestMatch; unsigned m_NumMatches; } Callback (a_PlayerName); - ForEachPlayer( Callback ); + ForEachPlayer(Callback); if (Callback.m_NumMatches == 1) { @@ -762,8 +763,8 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output) { cWorld * World = itr->second; int NumInGenerator = World->GetGeneratorQueueLength(); - int NumInSaveQueue = World->GetStorageSaveQueueLength(); - int NumInLoadQueue = World->GetStorageLoadQueueLength(); + int NumInSaveQueue = (int)World->GetStorageSaveQueueLength(); + int NumInLoadQueue = (int)World->GetStorageLoadQueueLength(); int NumValid = 0; int NumDirty = 0; int NumInLighting = 0; @@ -783,8 +784,6 @@ void cRoot::LogChunkStats(cCommandOutputCallback & a_Output) a_Output.Out(" block lighting: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", 2 * sizeof(cChunkDef::BlockNibbles), (2 * sizeof(cChunkDef::BlockNibbles) + 1023) / 1024); a_Output.Out(" heightmap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::HeightMap), (sizeof(cChunkDef::HeightMap) + 1023) / 1024); a_Output.Out(" biomemap: " SIZE_T_FMT_PRECISION(6) " bytes (" SIZE_T_FMT_PRECISION(3) " KiB)", sizeof(cChunkDef::BiomeMap), (sizeof(cChunkDef::BiomeMap) + 1023) / 1024); - int Rest = sizeof(cChunk) - sizeof(cChunkDef::BlockTypes) - 3 * sizeof(cChunkDef::BlockNibbles) - sizeof(cChunkDef::HeightMap) - sizeof(cChunkDef::BiomeMap); - a_Output.Out(" other: %6d bytes (%3d KiB)", Rest, (Rest + 1023) / 1024); SumNumValid += NumValid; SumNumDirty += NumDirty; SumNumInLighting += NumInLighting; diff --git a/src/Root.h b/src/Root.h index 4bbd7586f..d2a4d1eed 100644 --- a/src/Root.h +++ b/src/Root.h @@ -1,7 +1,7 @@ #pragma once -#include "Authenticator.h" +#include "Protocol/Authenticator.h" #include "HTTPServer/HTTPServer.h" #include "Defines.h" @@ -89,7 +89,7 @@ public: void KickUser(int a_ClientID, const AString & a_Reason); /// Called by cAuthenticator to auth the specified user - void AuthenticateUser(int a_ClientID); + void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID); /// Executes commands queued in the command queue void TickCommands(void); diff --git a/src/Scoreboard.cpp b/src/Scoreboard.cpp index 4c89ce265..250f63aa9 100644 --- a/src/Scoreboard.cpp +++ b/src/Scoreboard.cpp @@ -261,7 +261,7 @@ void cTeam::SetDisplayName(const AString & a_Name) -unsigned int cTeam::GetNumPlayers(void) const +size_t cTeam::GetNumPlayers(void) const { return m_Players.size(); } @@ -569,7 +569,7 @@ void cScoreboard::SendTo(cClientHandle & a_Client) -unsigned int cScoreboard::GetNumObjectives(void) const +size_t cScoreboard::GetNumObjectives(void) const { return m_Objectives.size(); } @@ -578,7 +578,7 @@ unsigned int cScoreboard::GetNumObjectives(void) const -unsigned int cScoreboard::GetNumTeams(void) const +size_t cScoreboard::GetNumTeams(void) const { return m_Teams.size(); } diff --git a/src/Scoreboard.h b/src/Scoreboard.h index 2fae5e499..1e1973a10 100644 --- a/src/Scoreboard.h +++ b/src/Scoreboard.h @@ -153,7 +153,7 @@ public: // tolua_begin /** Returns the number of registered players */ - unsigned int GetNumPlayers(void) const; + size_t GetNumPlayers(void) const; bool AllowsFriendlyFire(void) const { return m_AllowsFriendlyFire; } bool CanSeeFriendlyInvisible(void) const { return m_CanSeeFriendlyInvisible; } @@ -248,9 +248,9 @@ public: cObjective * GetObjectiveIn(eDisplaySlot a_Slot); - unsigned int GetNumObjectives(void) const; + size_t GetNumObjectives(void) const; - unsigned int GetNumTeams(void) const; + size_t GetNumTeams(void) const; void AddPlayerScore(const AString & a_Name, cObjective::eType a_Type, cObjective::Score a_Value = 1); diff --git a/src/Server.cpp b/src/Server.cpp index d1e53bfff..aa731cdd2 100644 --- a/src/Server.cpp +++ b/src/Server.cpp @@ -190,7 +190,7 @@ void cServer::PlayerDestroying(const cPlayer * a_Player) bool cServer::InitServer(cIniFile & a_SettingsIni) { - m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!").c_str(); + m_Description = a_SettingsIni.GetValueSet("Server", "Description", "MCServer - in C++!"); m_MaxPlayers = a_SettingsIni.GetValueSetI("Server", "MaxPlayers", 100); m_bIsHardcore = a_SettingsIni.GetValueSetB("Server", "HardcoreEnabled", false); m_PlayerCount = 0; @@ -275,7 +275,7 @@ bool cServer::InitServer(cIniFile & a_SettingsIni) -int cServer::GetNumPlayers(void) +int cServer::GetNumPlayers(void) const { cCSLock Lock(m_CSPlayerCount); return m_PlayerCount; @@ -476,7 +476,37 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac a_Output.Finished(); return; } - + if (split[0] == "load") + { + if (split.size() > 1) + { + cPluginManager::Get()->LoadPlugin(split[1]); + + return; + } + else + { + a_Output.Out("No plugin given! Command: load <pluginname>"); + a_Output.Finished(); + return; + } + } + + if (split[0] == "unload") + { + if (split.size() > 1) + { + cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1])); + return; + } + else + { + a_Output.Out("No plugin given! Command: unload <pluginname>"); + a_Output.Finished(); + return; + } + } + // There is currently no way a plugin can do these (and probably won't ever be): if (split[0].compare("chunkstats") == 0) { @@ -567,6 +597,9 @@ void cServer::BindBuiltInConsoleCommands(void) PlgMgr->BindConsoleCommand("restart", NULL, " - Restarts the server cleanly"); PlgMgr->BindConsoleCommand("stop", NULL, " - Stops the server cleanly"); PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics"); + PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin"); + PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin"); + #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml"); #endif @@ -615,14 +648,14 @@ void cServer::KickUser(int a_ClientID, const AString & a_Reason) -void cServer::AuthenticateUser(int a_ClientID) +void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID) { cCSLock Lock(m_CSClients); for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) { if ((*itr)->GetUniqueID() == a_ClientID) { - (*itr)->Authenticate(); + (*itr)->Authenticate(a_Name, a_UUID); return; } } // for itr - m_Clients[] diff --git a/src/Server.h b/src/Server.h index b5280c59d..3d76c8ccf 100644 --- a/src/Server.h +++ b/src/Server.h @@ -23,7 +23,7 @@ #pragma warning(disable:4702) #endif -#include "Crypto.h" +#include "PolarSSL++/RsaPrivateKey.h" #ifdef _MSC_VER #pragma warning(pop) @@ -59,7 +59,7 @@ public: // tolua_export // Player counts: int GetMaxPlayers(void) const {return m_MaxPlayers; } - int GetNumPlayers(void); + int GetNumPlayers(void) const; void SetMaxPlayers(int a_MaxPlayers) { m_MaxPlayers = a_MaxPlayers; } // Hardcore mode or not: @@ -83,7 +83,7 @@ public: // tolua_export void Shutdown(void); void KickUser(int a_ClientID, const AString & a_Reason); - void AuthenticateUser(int a_ClientID); // Called by cAuthenticator to auth the specified user + void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator to auth the specified user const AString & GetServerID(void) const { return m_ServerID; } // tolua_export @@ -109,7 +109,7 @@ public: // tolua_export /** Returns base64 encoded favicon data (obtained from favicon.png) */ const AString & GetFaviconData(void) const { return m_FaviconData; } - cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; } + cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; } const AString & GetPublicKeyDER(void) const { return m_PublicKeyDER; } bool ShouldAuthenticate(void) const { return m_ShouldAuthenticate; } @@ -168,7 +168,7 @@ private: cClientHandleList m_Clients; ///< Clients that are connected to the server and not yet assigned to a cWorld cClientHandleList m_ClientsToRemove; ///< Clients that have just been moved into a world and are to be removed from m_Clients in the next Tick() - cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount + mutable cCriticalSection m_CSPlayerCount; ///< Locks the m_PlayerCount int m_PlayerCount; ///< Number of players currently playing in the server cCriticalSection m_CSPlayerCountDiff; ///< Locks the m_PlayerCountDiff int m_PlayerCountDiff; ///< Adjustment to m_PlayerCount to be applied in the Tick thread @@ -182,7 +182,7 @@ private: bool m_bRestarting; /** The private key used for the assymetric encryption start in the protocols */ - cRSAPrivateKey m_PrivateKey; + cRsaPrivateKey m_PrivateKey; /** Public key for m_PrivateKey, ASN1-DER-encoded */ AString m_PublicKeyDER; diff --git a/src/Simulator/CMakeLists.txt b/src/Simulator/CMakeLists.txt index 4f3f1ad0e..b2a29d45c 100644 --- a/src/Simulator/CMakeLists.txt +++ b/src/Simulator/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Simulator ${SOURCE}) diff --git a/src/Simulator/DelayedFluidSimulator.cpp b/src/Simulator/DelayedFluidSimulator.cpp index bc5158d95..5ff736231 100644 --- a/src/Simulator/DelayedFluidSimulator.cpp +++ b/src/Simulator/DelayedFluidSimulator.cpp @@ -148,7 +148,7 @@ void cDelayedFluidSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_Chunk { SimulateBlock(a_Chunk, itr->x, itr->y, itr->z); } - m_TotalBlocks -= Blocks.size(); + m_TotalBlocks -= (int)Blocks.size(); Blocks.clear(); } } diff --git a/src/Simulator/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 470dfc791..311f8b4c4 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -95,8 +95,10 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun int NumMSecs = (int)a_Dt; for (cCoordWithIntList::iterator itr = Data.begin(); itr != Data.end();) { - int idx = cChunkDef::MakeIndexNoCheck(itr->x, itr->y, itr->z); - BLOCKTYPE BlockType = a_Chunk->GetBlock(idx); + int x = itr->x; + int y = itr->y; + int z = itr->z; + BLOCKTYPE BlockType = a_Chunk->GetBlock(x,y,z); if (!IsAllowedBlock(BlockType)) { @@ -125,7 +127,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun itr->x + a_ChunkX * cChunkDef::Width, itr->y, itr->z + a_ChunkZ * cChunkDef::Width ); */ - NIBBLETYPE BlockMeta = a_Chunk->GetMeta(idx); + NIBBLETYPE BlockMeta = a_Chunk->GetMeta(x, y, z); if (BlockMeta == 0x0f) { // The fire burnt out completely @@ -140,7 +142,7 @@ void cFireSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun if((itr->y > 0) && (!DoesBurnForever(a_Chunk->GetBlock(itr->x, itr->y - 1, itr->z)))) { - a_Chunk->SetMeta(idx, BlockMeta + 1); + a_Chunk->SetMeta(x, y, z, BlockMeta + 1); } itr->Data = GetBurnStepTime(a_Chunk, itr->x, itr->y, itr->z); // TODO: Add some randomness into this } // for itr - Data[] @@ -350,7 +352,7 @@ void cFireSimulator::RemoveFuelNeighbors(cChunk * a_Chunk, int a_RelX, int a_Rel { continue; } - BlockType = Neighbour->GetBlock(X, a_RelY + gCrossCoords[i].y, Z); + BlockType = Neighbour->GetBlock(X, a_RelY + gNeighborCoords[i].y, Z); if (!IsFuel(BlockType)) { diff --git a/src/Simulator/FloodyFluidSimulator.cpp b/src/Simulator/FloodyFluidSimulator.cpp index 03e94e791..e95af3a1c 100644 --- a/src/Simulator/FloodyFluidSimulator.cpp +++ b/src/Simulator/FloodyFluidSimulator.cpp @@ -119,7 +119,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re if (SpreadFurther && (NewMeta < 8)) { // Spread to the neighbors: - Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta); + SpreadXZ(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta); } // Mark as processed: @@ -130,7 +130,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re -void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) +void cFloodyFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) { SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta); SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta); diff --git a/src/Simulator/FloodyFluidSimulator.h b/src/Simulator/FloodyFluidSimulator.h index 632de3bb2..8e1be5e6b 100644 --- a/src/Simulator/FloodyFluidSimulator.h +++ b/src/Simulator/FloodyFluidSimulator.h @@ -48,16 +48,13 @@ protected: bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ); /** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block. - * - * Returns whether the block was changed or not. - */ + Returns whether the block was changed or not. */ bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta); - /** Spread water to neighbors. - * - * May be overridden to provide more sophisticated algorithms. - */ - virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta); + /** Spread fluid to XZ neighbors. + The coords are of the block currently being processed; a_NewMeta is the new meta for the new fluid block. + Descendants may overridde to provide more sophisticated algorithms. */ + virtual void SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta); } ; diff --git a/src/Simulator/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp index 61c93ed73..4a84084d2 100644 --- a/src/Simulator/FluidSimulator.cpp +++ b/src/Simulator/FluidSimulator.cpp @@ -36,6 +36,7 @@ bool cFluidSimulator::CanWashAway(BLOCKTYPE a_BlockType) case E_BLOCK_COBWEB: case E_BLOCK_CROPS: case E_BLOCK_DEAD_BUSH: + case E_BLOCK_LILY_PAD: case E_BLOCK_RAIL: case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: @@ -154,7 +155,7 @@ Direction cFluidSimulator::GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a Points.push_back(new Vector3i(a_X, a_Y, a_Z + 1)); Points.push_back(new Vector3i(a_X, a_Y, a_Z - 1)); - for (std::vector<Vector3i *>::iterator it = Points.begin(); it < Points.end(); it++) + for (std::vector<Vector3i *>::iterator it = Points.begin(); it < Points.end(); ++it) { Vector3i *Pos = (*it); char BlockID = m_World.GetBlock(Pos->x, Pos->y, Pos->z); diff --git a/src/Simulator/IncrementalRedstoneSimulator.cpp b/src/Simulator/IncrementalRedstoneSimulator.cpp index 92659fab7..074063add 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -9,11 +9,13 @@ #include "../Entities/Pickup.h" #include "../Blocks/BlockTorch.h" #include "../Blocks/BlockDoor.h" +#include "../Blocks/BlockButton.h" +#include "../Blocks/BlockLever.h" #include "../Piston.h" - + cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulator(cWorld & a_World) : super(a_World) @@ -69,18 +71,19 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, // Checking only when a block is changed, as opposed to every tick, also improves performance PoweredBlocksList * PoweredBlocks = a_Chunk->GetRedstoneSimulatorPoweredBlocksList(); - for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end(); ++itr) + for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end();) { if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { + ++itr; continue; } if (!IsPotentialSource(Block)) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - PoweredBlocks->erase(itr); - break; + itr = PoweredBlocks->erase(itr); + continue; } else if ( // Changeable sources @@ -93,29 +96,10 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, ) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); - PoweredBlocks->erase(itr); - break; - } - else if (Block == E_BLOCK_DAYLIGHT_SENSOR) - { - if (!a_Chunk->IsLightValid()) - { - m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ()); - break; - } - else - { - NIBBLETYPE SkyLight; - a_Chunk->UnboundedRelGetBlockSkyLight(RelX, itr->a_SourcePos.y + 1, RelZ, SkyLight); - - if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness(); - { - LOGD("cIncrementalRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level"); - PoweredBlocks->erase(itr); - break; - } - } + itr = PoweredBlocks->erase(itr); + continue; } + ++itr; } LinkedBlocksList * LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList(); @@ -134,7 +118,9 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, // Things that can send power through a block but which depends on meta ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || - (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) + (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || + (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) || + (((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) ) { LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); @@ -157,14 +143,14 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, SimulatedPlayerToggleableList * SimulatedPlayerToggleableBlocks = a_Chunk->GetRedstoneSimulatorSimulatedPlayerToggleableList(); for (SimulatedPlayerToggleableList::iterator itr = SimulatedPlayerToggleableBlocks->begin(); itr != SimulatedPlayerToggleableBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ))) { continue; } if (!IsAllowedBlock(Block)) { - LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); + LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z); SimulatedPlayerToggleableBlocks->erase(itr); break; } @@ -173,7 +159,7 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY, RepeatersDelayList * RepeatersDelayList = a_Chunk->GetRedstoneSimulatorRepeatersDelayList(); for (RepeatersDelayList::iterator itr = RepeatersDelayList->begin(); itr != RepeatersDelayList->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(RelX, a_BlockY, RelZ))) { continue; } @@ -239,9 +225,6 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int m_LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList(); m_Chunk = a_Chunk; - int BaseX = a_Chunk->GetPosX() * cChunkDef::Width; - int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width; - for (cRedstoneSimulatorChunkData::iterator dataitr = m_RedstoneSimulatorChunkData->begin(); dataitr != m_RedstoneSimulatorChunkData->end();) { if (dataitr->DataTwo) @@ -250,67 +233,65 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int continue; } - int a_X = BaseX + dataitr->x; - int a_Z = BaseZ + dataitr->z; switch (dataitr->Data) { - case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break; - case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break; - case E_BLOCK_FENCE_GATE: HandleFenceGate(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break; - case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break; - case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break; - case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break; - case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break; - case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break; + case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_LEVER: HandleRedstoneLever(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(dataitr->x, dataitr->y, dataitr->z); break; + case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_REDSTONE_TORCH_OFF: case E_BLOCK_REDSTONE_TORCH_ON: { - HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneTorch(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_STONE_BUTTON: case E_BLOCK_WOODEN_BUTTON: { - HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneButton(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_REDSTONE_REPEATER_OFF: case E_BLOCK_REDSTONE_REPEATER_ON: { - HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneRepeater(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_PISTON: case E_BLOCK_STICKY_PISTON: { - HandlePiston(a_X, dataitr->y, a_Z); + HandlePiston(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_REDSTONE_LAMP_OFF: case E_BLOCK_REDSTONE_LAMP_ON: { - HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRedstoneLamp(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_DISPENSER: case E_BLOCK_DROPPER: { - HandleDropSpenser(a_X, dataitr->y, a_Z); + HandleDropSpenser(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_WOODEN_DOOR: case E_BLOCK_IRON_DOOR: { - HandleDoor(a_X, dataitr->y, a_Z); + HandleDoor(dataitr->x, dataitr->y, dataitr->z); break; } case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_POWERED_RAIL: { - HandleRail(a_X, dataitr->y, a_Z, dataitr->Data); + HandleRail(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } case E_BLOCK_WOODEN_PRESSURE_PLATE: @@ -318,7 +299,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: { - HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data); + HandlePressurePlate(dataitr->x, dataitr->y, dataitr->z, dataitr->Data); break; } default: LOGD("Unhandled block (!) or unimplemented redstone block: %s", ItemToString(dataitr->Data).c_str()); break; @@ -360,7 +341,7 @@ void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_Blo -void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { static const struct // Define which directions the torch can power { @@ -377,54 +358,58 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc if (a_MyState == E_BLOCK_REDSTONE_TORCH_ON) { // Check if the block the torch is on is powered - int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; - AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on if (AreCoordsDirectlyPowered(X, Y, Z)) { // There was a match, torch goes off - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); return; } // Torch still on, make all 4(X, Z) + 1(Y) sides powered for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) { - BLOCKTYPE Type = m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z); + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type)) + { + continue; + } if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) { if ( ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc. - (!Vector3i(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on + (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on ) { - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); } } else { // Top side, power whatever is there, including blocks - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Power all blocks surrounding block above torch - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_REDSTONE_TORCH_ON); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YP); } } - if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath + if (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) != 0x5) // Is torch standing on ground? If NOT (i.e. on wall), power block beneath { - BLOCKTYPE Type = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ); if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though! { - SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON); + SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); } } } else { // Check if the block the torch is on is powered - int X = a_BlockX; int Y = a_BlockY; int Z = a_BlockZ; - AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)), true); // Inverse true to get the block torch is on + int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ; + AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on // See if off state torch can be turned on again if (AreCoordsDirectlyPowered(X, Y, Z)) @@ -433,7 +418,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc } // Block torch on not powered, can be turned on again! - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ)); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_ON, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); } } @@ -441,28 +426,47 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_BlockX, int a_Bloc -void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_BLOCK_OF_REDSTONE); // Set self as powered + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Set self as powered } -void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (IsLeverOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (IsLeverOn(Meta)) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_LEVER); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_LEVER); + NIBBLETYPE Dir = cBlockLeverHandler::BlockMetaDataToBlockFace(Meta); + switch (Dir) // Now, flip the direction into the type used by SetBlockLinkedPowered() + { + case BLOCK_FACE_YP: + case BLOCK_FACE_XP: + case BLOCK_FACE_ZP: + { + Dir--; + break; + } + case BLOCK_FACE_XM: + case BLOCK_FACE_ZM: + case BLOCK_FACE_YM: + { + Dir++; + break; + } + default: + { + ASSERT(!"Unhandled lever metadata!"); + return; + } + } + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); } } @@ -470,27 +474,29 @@ void cIncrementalRedstoneSimulator::HandleRedstoneLever(int a_BlockX, int a_Bloc -void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; cChunkInterface ChunkInterface(m_World.GetChunkMap()); - NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE MetaData = ChunkInterface.GetBlockMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData | 0x4); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData | 0x4); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaData & 0xFFFFFFFB); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MetaData & 0xFFFFFFFB); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -499,18 +505,35 @@ void cIncrementalRedstoneSimulator::HandleFenceGate(int a_BlockX, int a_BlockY, -void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType) +void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (IsButtonOn(m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ))) + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (IsButtonOn(Meta)) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_BlockType); - - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YP, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, a_BlockType); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, a_BlockType); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + + NIBBLETYPE Dir = cBlockButtonHandler::BlockMetaDataToBlockFace(Meta); + switch (Dir) // Now, flip the direction into the type used by SetBlockLinkedPowered() + { + case BLOCK_FACE_XP: + case BLOCK_FACE_ZP: + { + Dir--; + break; + } + case BLOCK_FACE_XM: + case BLOCK_FACE_ZM: + { + Dir++; + break; + } + default: + { + ASSERT(!"Unhandled button metadata!"); + return; + } + } + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Dir); } } @@ -518,7 +541,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneButton(int a_BlockX, int a_Blo -void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { static const struct // Define which directions the wire can receive power from { @@ -552,128 +575,122 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block }; // Check to see if directly beside a power source - if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ)) + unsigned char MyPower; + if (!IsWirePowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + return; } - else + + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + + if (MyPower < 1) { - NIBBLETYPE MetaToSet = 0; - NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - int TimesMetaSmaller = 0, TimesFoundAWire = 0; + return; + } - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + MyPower--; + + for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + { + if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... { - if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... + BLOCKTYPE Type = 0; + if (a_RelBlockY + 1 >= cChunkDef::Height) { - if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)... - { - continue; // We don't receive power from that wire - } + continue; } - else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, Type)) { - if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z))) - { - continue; - } + continue; } - - BLOCKTYPE SurroundType; - NIBBLETYPE SurroundMeta; - m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta); - - if (SurroundType == E_BLOCK_REDSTONE_WIRE) + if (cBlockInfo::IsSolid(Type)) // If there is something solid above us (wire cut off)... { - TimesFoundAWire++; - - if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking - { - // Does surrounding wire have a higher power level than self? - // >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list - if (SurroundMeta >= MyMeta) - { - MetaToSet = SurroundMeta - 1; // To improve performance - } - } - - if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's - { - TimesMetaSmaller++; - } - } + continue; // We don't receive power from that wire + } + } + else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + { + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY, a_RelBlockZ + gCrossCoords[i].z, Type)) + { + continue; + } + if (cBlockInfo::IsSolid(Type)) + { + continue; + } } - if ((TimesMetaSmaller == TimesFoundAWire) && (MyMeta != 0)) + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, Type)) { - // All surrounding metas were smaller - self must have been a wire that was - // transferring power to other wires around. - // However, self not directly powered anymore, so source must have been removed, - // therefore, self must be set to meta zero - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock - return; // No need to process block power sets because self not powered + continue; } - else if (MyMeta != MetaToSet) + if (Type == E_BLOCK_REDSTONE_WIRE) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); } } - if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire + for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them { - for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them + BLOCKTYPE Type = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, Type)) { - if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF) - { - SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - } + continue; + } + if (Type == E_BLOCK_REDSTONE_REPEATER_OFF) + { + SetBlockPowered(a_RelBlockX + gSideCoords[i].x, a_RelBlockY + gSideCoords[i].y, a_RelBlockZ + gSideCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); } + } - // Wire still powered, power blocks beneath - SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE); + // Wire still powered, power blocks beneath + SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, MyPower); - switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) + switch (GetWireDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) + { + case REDSTONE_NONE: { - case REDSTONE_NONE: - { - SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); + SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); - break; - } - case REDSTONE_X_POS: - { - SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE); - break; - } - case REDSTONE_X_NEG: - { - SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE); - break; - } - case REDSTONE_Z_POS: - { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); - break; - } - case REDSTONE_Z_NEG: - { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE); - break; - } + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); + break; + } + case REDSTONE_X_POS: + { + SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP, MyPower); + break; + } + case REDSTONE_X_NEG: + { + SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM, MyPower); + break; + } + case REDSTONE_Z_POS: + { + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP, MyPower); + break; + } + case REDSTONE_Z_NEG: + { + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MyPower); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM, MyPower); + break; } } } @@ -682,25 +699,49 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block -void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { - NIBBLETYPE a_Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + /* Repeater Orientation Mini Guide: + =================================== - bool IsOn = ((a_MyState == E_BLOCK_REDSTONE_REPEATER_ON) ? true : false); // Cache if repeater is on - bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3); // Cache if repeater is pwoered + | + | Z Axis + V - if (IsSelfPowered && !IsOn) // Queue a power change if I am receiving power but not on - { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, true); - } - else if (!IsSelfPowered && IsOn) // Queue a power change if I am not receiving power but on + X Axis ----> + + Repeater directions, values from a cWorld::GetBlockMeta(a_RelBlockX , a_RelBlockY, a_RelBlockZ) lookup: + + East (Right) (X+): 0x1 + West (Left) (X-): 0x3 + North (Up) (Z-): 0x2 + South (Down) (Z+): 0x0 + // TODO: Add E_META_XXX enum entries for all meta values and update project with them + + Sun rises from East (X+) + + */ + + // Create a variable holding my meta to avoid multiple lookups. + NIBBLETYPE a_Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON); + + if (!IsRepeaterLocked(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta)) // If we're locked, change nothing. Otherwise: { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, false); + bool IsSelfPowered = IsRepeaterPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta); + if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. + { + QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, true); + } + else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. + { + QueueRepeaterPowerChange(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_Meta, false); + } } for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } @@ -711,33 +752,33 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B { if (!IsOn) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_REPEATER_ON, a_Meta); // For performance } switch (a_Meta & 0x3) // We only want the direction (bottom) bits { case 0x0: { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZM); break; } case 0x1: { - SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XP); break; } case 0x2: { - SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_ZP); break; } case 0x3: { - SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_ON); - SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_REPEATER_ON); + SetBlockPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_XM); break; } } @@ -750,7 +791,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B { if (IsOn) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta); } m_RepeatersDelayList->erase(itr); // We can remove off repeaters which don't need further updating return; @@ -761,7 +802,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B // Apparently, incrementing ticks only works reliably here, and not in SimChunk; // With a world with lots of redstone, the repeaters simply do not delay // I am confounded to say why. Perhaps optimisation failure. - LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); + LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); itr->a_ElapsedTicks++; } } @@ -771,16 +812,19 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_B -void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { cPiston Piston(&m_World); - if (IsPistonPowered(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (IsPistonPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7)) // We only want the bottom three bits (4th controls extended-ness) { - Piston.ExtendPiston(a_BlockX, a_BlockY, a_BlockZ); + Piston.ExtendPiston(BlockX, a_RelBlockY, BlockZ); } else { - Piston.RetractPiston(a_BlockX, a_BlockY, a_BlockZ); + Piston.RetractPiston(BlockX, a_RelBlockY, BlockZ); } } @@ -788,7 +832,7 @@ void cIncrementalRedstoneSimulator::HandlePiston(int a_BlockX, int a_BlockY, int -void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { class cSetPowerToDropSpenser : public cDropSpenserCallback @@ -802,29 +846,31 @@ void cIncrementalRedstoneSimulator::HandleDropSpenser(int a_BlockX, int a_BlockY a_DropSpenser->SetRedstonePower(m_IsPowered); return false; } - } DrSpSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + } DrSpSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - m_World.DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, DrSpSP); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->DoWithDropSpenserAt(BlockX, a_RelBlockY, BlockZ, DrSpSP); } -void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState) +void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState) { if (a_MyState == E_BLOCK_REDSTONE_LAMP_OFF) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_ON, 0); } } else { - if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (!AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_LAMP_OFF, 0); } } } @@ -833,13 +879,16 @@ void cIncrementalRedstoneSimulator::HandleRedstoneLamp(int a_BlockX, int a_Block -void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.6f); - m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0); - m_World.SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom + m_Chunk->BroadcastSoundEffect("game.tnt.primed", BlockX * 8, a_RelBlockY * 8, BlockZ * 8, 0.5f, 0.6f); + m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0); + m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom } } @@ -847,26 +896,29 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_ -void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { cChunkInterface ChunkInterface(m_World.GetChunkMap()); - cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + cBlockDoorHandler::ChangeDoor(ChunkInterface, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { cChunkInterface ChunkInterface(m_World.GetChunkMap()); - cBlockDoorHandler::ChangeDoor(ChunkInterface, a_BlockX, a_BlockY, a_BlockZ); - m_World.BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + cBlockDoorHandler::ChangeDoor(ChunkInterface, a_RelBlockX, a_RelBlockY, a_RelBlockZ); + m_Chunk->BroadcastSoundParticleEffect(1003, BlockX, a_RelBlockY, BlockZ, 0); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -875,7 +927,7 @@ void cIncrementalRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a -void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { class cSetPowerToCommandBlock : public cCommandBlockCallback @@ -889,37 +941,39 @@ void cIncrementalRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_Block a_CommandBlock->SetRedstonePower(m_IsPowered); return false; } - } CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)); + } CmdBlockSP (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)); - m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->DoWithCommandBlockAt(BlockX, a_RelBlockY, BlockZ, CmdBlockSP); } -void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) +void cIncrementalRedstoneSimulator::HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) { switch (a_MyType) { case E_BLOCK_DETECTOR_RAIL: { - if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08) + if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType); } break; } case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_POWERED_RAIL: { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) | 0x08); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) | 0x08); } else { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x07); } break; } @@ -931,22 +985,25 @@ void cIncrementalRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a -void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ)) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { - m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, true); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, true); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { - m_World.SetTrapdoorOpen(a_BlockX, a_BlockY, a_BlockZ, false); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + m_World.SetTrapdoorOpen(BlockX, a_RelBlockY, BlockZ, false); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -955,13 +1012,13 @@ void cIncrementalRedstoneSimulator::HandleTrapdoor(int a_BlockX, int a_BlockY, i -void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - bool m_bAreCoordsPowered = AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ); + bool m_bAreCoordsPowered = AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (m_bAreCoordsPowered) { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true)) { class cSetPowerToNoteBlock : public cNoteBlockCallback @@ -980,15 +1037,17 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, } } NoteBlockSP(m_bAreCoordsPowered); - m_World.DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, NoteBlockSP); - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + m_Chunk->DoWithNoteBlockAt(BlockX, a_RelBlockY, BlockZ, NoteBlockSP); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, true); } } else { - if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false)) + if (!AreCoordsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false)) { - SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false); + SetPlayerToggleableBlockAsSimulated(a_RelBlockX, a_RelBlockY, a_RelBlockZ, false); } } } @@ -997,10 +1056,10 @@ void cIncrementalRedstoneSimulator::HandleNoteBlock(int a_BlockX, int a_BlockY, -void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ) +void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { int a_ChunkX, a_ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, a_ChunkX, a_ChunkZ); + cChunkDef::BlockToChunk(a_RelBlockX, a_RelBlockZ, a_ChunkX, a_ChunkZ); if (!m_World.IsChunkLighted(a_ChunkX, a_ChunkZ)) { @@ -1008,10 +1067,12 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_Blo } else { - NIBBLETYPE SkyLight = m_World.GetBlockSkyLight(a_BlockX, a_BlockY + 1, a_BlockZ) - m_World.GetSkyDarkness(); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + NIBBLETYPE SkyLight = m_Chunk->GetTimeAlteredLight(m_World.GetBlockSkyLight(BlockX, a_RelBlockY + 1, BlockZ)); if (SkyLight > 8) { - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DAYLIGHT_SENSOR); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } } } @@ -1020,38 +1081,175 @@ void cIncrementalRedstoneSimulator::HandleDaylightSensor(int a_BlockX, int a_Blo -void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType) +void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType) { + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + switch (a_MyType) { case E_BLOCK_STONE_PRESSURE_PLATE: { // MCS feature - stone pressure plates can only be triggered by players :D - cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(a_BlockX + 0.5f, (float)a_BlockY, a_BlockZ + 0.5f), 0.5f, false); + cPlayer * a_Player = m_World.FindClosestPlayer(Vector3f(BlockX + 0.5f, (float)a_RelBlockY, BlockZ + 0.5f), 0.7f, false); if (a_Player != NULL) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_STONE_PRESSURE_PLATE); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x1); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); } else { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); } break; } case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: + { + class cPressurePlateCallback : + public cEntityCallback + { + public: + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_NumberOfEntities(0), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + double Distance = (EntityPos - BlockPos).Length(); + + if (Distance <= 0.7) + { + m_NumberOfEntities++; + } + return false; + } + + bool GetPowerLevel(unsigned char & a_PowerLevel) const + { + a_PowerLevel = std::min(m_NumberOfEntities, MAX_POWER_LEVEL); + return (a_PowerLevel > 0); + } + + protected: + int m_NumberOfEntities; + + int m_X; + int m_Y; + int m_Z; + }; + + cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); + m_World.ForEachEntity(PressurePlateCallback); + + unsigned char Power; + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) + { + if (Meta == E_META_PRESSURE_PLATE_RAISED) + { + m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + } + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); + } + else + { + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) + { + m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + } + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + } + + break; + } case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: + { + class cPressurePlateCallback : + public cEntityCallback + { + public: + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_NumberOfEntities(0), + m_X(a_BlockX), + m_Y(a_BlockY), + m_Z(a_BlockZ) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + Vector3f EntityPos = a_Entity->GetPosition(); + Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f); + double Distance = (EntityPos - BlockPos).Length(); + + if (Distance <= 0.7) + { + m_NumberOfEntities++; + } + return false; + } + + bool GetPowerLevel(unsigned char & a_PowerLevel) const + { + a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL); + return (a_PowerLevel > 0); + } + + protected: + int m_NumberOfEntities; + + int m_X; + int m_Y; + int m_Z; + }; + + cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); + m_World.ForEachEntity(PressurePlateCallback); + + unsigned char Power; + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) + { + if (Meta == E_META_PRESSURE_PLATE_RAISED) + { + m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + } + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); + } + else + { + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) + { + m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + } + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); + } + + break; + } case E_BLOCK_WOODEN_PRESSURE_PLATE: { class cPressurePlateCallback : public cEntityCallback { public: - cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : - m_Entity(NULL), - m_World(a_World), + cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) : + m_FoundEntity(false), m_X(a_BlockX), m_Y(a_BlockY), m_Z(a_BlockZ) @@ -1066,7 +1264,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc if (Distance <= 0.7) { - m_Entity = a_Entity; + m_FoundEntity = true; return true; // Break out, we only need to know for plates that at least one entity is on top } return false; @@ -1074,45 +1272,47 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc bool FoundEntity(void) const { - return m_Entity != NULL; + return m_FoundEntity; } protected: - cEntity * m_Entity; - cWorld * m_World; + bool m_FoundEntity; int m_X; int m_Y; int m_Z; } ; - cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World); + cPressurePlateCallback PressurePlateCallback(BlockX, a_RelBlockY, BlockZ); m_World.ForEachEntity(PressurePlateCallback); - NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + NIBBLETYPE Meta = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ); if (PressurePlateCallback.FoundEntity()) { - if (Meta == 0x0) + if (Meta == E_META_PRESSURE_PLATE_RAISED) { - m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F); + m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); - SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); + SetDirectionLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, BLOCK_FACE_YM, a_MyType); } else { - if (Meta == 0x1) + if (Meta == E_META_PRESSURE_PLATE_DEPRESSED) { - m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F); + m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); } - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); - m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(BlockX, a_RelBlockY, BlockZ); } break; } default: + { LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str()); break; + } } } @@ -1120,11 +1320,15 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc -bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + + PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); // Torches want to access neighbour's data when on a wall + for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } @@ -1136,11 +1340,14 @@ bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_BlockX, int a -bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } @@ -1151,36 +1358,39 @@ bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_B - -bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) +// IsRepeaterPowered tests if a repeater should be powered by testing for power sources behind the repeater. +// It takes the coordinates of the repeater the the meta value. +bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) { // Repeaters cannot be powered by any face except their back; verify that this is true for a source + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - switch (a_Meta) + switch (a_Meta & 0x3) { case 0x0: { // Flip the coords to check the back of the repeater - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; } break; } case 0x1: { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; } break; } case 0x2: { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; } break; } case 0x3: { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_SourcePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; } break; } } @@ -1188,28 +1398,28 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - switch (a_Meta) + switch (a_Meta & 0x3) { case 0x0: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ + 1))) { return true; } break; } case 0x1: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX - 1, a_RelBlockY, BlockZ))) { return true; } break; } case 0x2: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ - 1))) { return true; } break; } case 0x3: { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } + if (itr->a_MiddlePos.Equals(Vector3i(BlockX + 1, a_RelBlockY, BlockZ))) { return true; } break; } } @@ -1220,43 +1430,101 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY -bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) + +bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) +{ + switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata + { + // If the repeater is looking up or down (If parallel to the Z axis) + case 0x0: + case 0x2: + { + // Check if eastern(right) neighbor is a powered on repeater who is facing us. + BLOCKTYPE Block = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) // Is right neighbor a powered repeater? + { + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ) & 0x3; + if (OtherRepeaterDir == 0x3) { return true; } // If so, I am latched/locked. + } + + // Check if western(left) neighbor is a powered on repeater who is facing us. + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) + { + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX -1, a_RelBlockY, a_RelBlockZ) & 0x3; + if (OtherRepeaterDir == 0x1) { return true; } // If so, I am latched/locked. + } + + break; + } + + // If the repeater is looking left or right (If parallel to the x axis) + case 0x1: + case 0x3: + { + // Check if southern(down) neighbor is a powered on repeater who is facing us. + BLOCKTYPE Block = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) + { + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1) & 0x3; + if (OtherRepeaterDir == 0x0) { return true; } // If so, am latched/locked. + } + + // Check if northern(up) neighbor is a powered on repeater who is facing us. + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, Block) && (Block == E_BLOCK_REDSTONE_REPEATER_ON)) + { + NIBBLETYPE OtherRepeaterDir = m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1) & 0x3; + if (OtherRepeaterDir == 0x2) { return true; } // If so, I am latched/locked. + } + + break; + } + } + + return false; // None of the checks succeeded, I am not a locked repeater. +} + + + + +bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta) { // Pistons cannot be powered through their front face; this function verifies that a source meets this requirement - int OldX = a_BlockX, OldY = a_BlockY, OldZ = a_BlockZ; + int OldX = a_RelBlockX, OldY = a_RelBlockY, OldZ = a_RelBlockZ; eBlockFace Face = cPiston::MetaDataToDirection(a_Meta); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face); + AddFaceDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face); - if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } - a_BlockX = OldX; - a_BlockY = OldY; - a_BlockZ = OldZ; + a_RelBlockX = OldX; + a_RelBlockY = OldY; + a_RelBlockZ = OldZ; } for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { continue; } - AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, Face); + AddFaceDirection(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Face); - if (!itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_MiddlePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { return true; } - a_BlockX = OldX; - a_BlockY = OldY; - a_BlockZ = OldZ; + a_RelBlockX = OldX; + a_RelBlockY = OldY; + a_RelBlockZ = OldZ; } return false; // Source was in front of the piston's front face } @@ -1264,39 +1532,42 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, -bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ) +bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel) { - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) - { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } + a_PowerLevel = 0; + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; - if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE) + for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list + { + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { - return true; + continue; } + a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel); } - for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) + for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - - if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE) + if (!itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ))) { - return true; + continue; } + a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel); } - return false; // Source was in front of the piston's front face + + return (a_PowerLevel != 0); // Source was in front of the piston's front face } -bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered) +bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered) { for (SimulatedPlayerToggleableList::const_iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { if (itr->WasLastStatePowered != IsCurrentStatePowered) // Was the last power state different to the current? { @@ -1315,79 +1586,98 @@ bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_Block -void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType) +void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel) { + BLOCKTYPE MiddleBlock = 0; switch (a_Direction) { case BLOCK_FACE_XM: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_RelBlockX - 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_XP: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_RelBlockX + 2, a_RelBlockY, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_YM: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_YP: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 2, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_ZM: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } case BLOCK_FACE_ZP: { - BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, MiddleBlock)) + { + return; + } - SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); - SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 2, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY + 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); + SetBlockLinkedPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, a_RelBlockX, a_RelBlockY, a_RelBlockZ, MiddleBlock, a_PowerLevel); break; } @@ -1403,7 +1693,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int -void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock) +void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel) { static const struct { @@ -1411,16 +1701,16 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc } gCrossCoords[] = { { 1, 0, 0 }, - {-1, 0, 0 }, + { -1, 0, 0 }, { 0, 0, 1 }, - { 0, 0,-1 }, + { 0, 0, -1 }, { 0, 1, 0 }, - { 0,-1, 0 } + { 0, -1, 0 } }; for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions { - SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock); + SetBlockPowered(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z, a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_PowerLevel); } } @@ -1428,32 +1718,55 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc -void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock) +void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel) { - BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; + int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; + + BLOCKTYPE Block = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block)) + { + return; + } if (Block == E_BLOCK_AIR) { // Don't set air, fixes some bugs (wires powering themselves) return; } - PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); + PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); + for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list + { + if ( + itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && + itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) + ) + { + // Check for duplicates, update power level, don't add a new listing + itr->a_PowerLevel = a_PowerLevel; + return; + } + } - for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list + PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); + for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list { if ( - itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && - itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) + itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) && + itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) ) { - // Check for duplicates + // Powered wires try to power their source - don't let them! return; } } sPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); - RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ); + RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ); + RC.a_PowerLevel = a_PowerLevel; Powered->push_back(RC); } @@ -1462,42 +1775,58 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( - int a_BlockX, int a_BlockY, int a_BlockZ, - int a_MiddleX, int a_MiddleY, int a_MiddleZ, - int a_SourceX, int a_SourceY, int a_SourceZ, - BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock -) + int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, + int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, + int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, + BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel + ) { - BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); + int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; + int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; + int MiddleX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelMiddleX; + int MiddleZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelMiddleZ; + int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; + int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; + + BLOCKTYPE DestBlock = 0; + if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock)) + { + return; + } if (DestBlock == E_BLOCK_AIR) { // Don't set air, fixes some bugs (wires powering themselves) return; } + if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)) + { + return; + } if (!IsViableMiddleBlock(a_MiddleBlock)) { return; } - LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); - - for (LinkedBlocksList::const_iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list + LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); + for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list { if ( - itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && - itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) && - itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) - ) + itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && + itr->a_MiddlePos.Equals(Vector3i(MiddleX, a_RelMiddleY, MiddleZ)) && + itr->a_SourcePos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) + ) { - // Check for duplicates + // Check for duplicates, update power level, don't add a new listing + itr->a_PowerLevel = a_PowerLevel; return; } } sLinkedPoweredBlocks RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); - RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); - RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_BlockPos = Vector3i(BlockX, a_RelBlockY, BlockZ); + RC.a_MiddlePos = Vector3i(MiddleX, a_RelMiddleY, MiddleZ); + RC.a_SourcePos = Vector3i(SourceX, a_RelSourceY, SourceZ); + RC.a_PowerLevel = a_PowerLevel; Linked->push_back(RC); } @@ -1505,11 +1834,11 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( -void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered) +void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered) { for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks->begin(); itr != m_SimulatedPlayerToggleableBlocks->end(); ++itr) { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (!itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { continue; } @@ -1529,7 +1858,7 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl // We have arrive here; no block must be in list - add one sSimulatedPlayerToggleableList RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); RC.WasLastStatePowered = WasLastStatePowered; m_SimulatedPlayerToggleableBlocks->push_back(RC); } @@ -1538,11 +1867,11 @@ void cIncrementalRedstoneSimulator::SetPlayerToggleableBlockAsSimulated(int a_Bl -void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn) +void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn) { for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) { - if (itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) + if (itr->a_RelBlockPos.Equals(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ))) { if (ShouldPowerOn == itr->ShouldPowerOn) // We are queued already for the same thing, don't replace entry { @@ -1559,10 +1888,10 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a // Self not in list, add self to list sRepeatersDelayList RC; - RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); + RC.a_RelBlockPos = Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ); // Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.) - // * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed + // * 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2; RC.a_ElapsedTicks = 0; @@ -1575,52 +1904,64 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a -cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_BlockX, int a_BlockY, int a_BlockZ) +cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { int Dir = REDSTONE_NONE; - BLOCKTYPE NegX = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); - if (IsPotentialSource(NegX)) + BLOCKTYPE NegX = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX - 1, a_RelBlockY, a_RelBlockZ, NegX)) { - Dir |= (REDSTONE_X_POS); + if (IsPotentialSource(NegX)) + { + Dir |= (REDSTONE_X_POS); + } } - BLOCKTYPE PosX = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); - if (IsPotentialSource(PosX)) + BLOCKTYPE PosX = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX + 1, a_RelBlockY, a_RelBlockZ, PosX)) { - Dir |= (REDSTONE_X_NEG); + if (IsPotentialSource(PosX)) + { + Dir |= (REDSTONE_X_NEG); + } } - BLOCKTYPE NegZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); - if (IsPotentialSource(NegZ)) + BLOCKTYPE NegZ = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ - 1, NegZ)) { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner - { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + if (IsPotentialSource(NegZ)) { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_POS; } - Dir |= REDSTONE_Z_POS; } - BLOCKTYPE PosZ = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); - if (IsPotentialSource(PosZ)) + BLOCKTYPE PosZ = 0; + if (m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ + 1, PosZ)) { - if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + if (IsPotentialSource(PosZ)) { - Dir ^= REDSTONE_X_POS; - Dir |= REDSTONE_X_NEG; - } - if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner - { - Dir ^= REDSTONE_X_NEG; - Dir |= REDSTONE_X_POS; + if ((Dir & REDSTONE_X_POS) && !(Dir & REDSTONE_X_NEG)) // corner + { + Dir ^= REDSTONE_X_POS; + Dir |= REDSTONE_X_NEG; + } + if ((Dir & REDSTONE_X_NEG) && !(Dir & REDSTONE_X_POS)) // corner + { + Dir ^= REDSTONE_X_NEG; + Dir |= REDSTONE_X_POS; + } + Dir |= REDSTONE_Z_NEG; } - Dir |= REDSTONE_Z_NEG; } return (eRedstoneDirection)Dir; } @@ -1638,12 +1979,3 @@ bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta) - -bool cIncrementalRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta) -{ - return IsLeverOn(a_BlockMeta); -} - - - - diff --git a/src/Simulator/IncrementalRedstoneSimulator.h b/src/Simulator/IncrementalRedstoneSimulator.h index 8b7363366..233a3d408 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.h +++ b/src/Simulator/IncrementalRedstoneSimulator.h @@ -36,31 +36,35 @@ public: private: + #define MAX_POWER_LEVEL 15 + struct sPoweredBlocks // Define structure of the directly powered blocks list { Vector3i a_BlockPos; // Position of powered block Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos + unsigned char a_PowerLevel; }; struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side) { Vector3i a_BlockPos; - Vector3i a_MiddlePos; + Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination Vector3i a_SourcePos; + unsigned char a_PowerLevel; }; - struct sSimulatedPlayerToggleableList + struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player) { - Vector3i a_BlockPos; - bool WasLastStatePowered; + Vector3i a_RelBlockPos; + bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate }; - struct sRepeatersDelayList + struct sRepeatersDelayList // Define structure of list containing repeaters' delay states { - Vector3i a_BlockPos; - unsigned char a_DelayTicks; - unsigned char a_ElapsedTicks; - bool ShouldPowerOn; + Vector3i a_RelBlockPos; + unsigned char a_DelayTicks; // For how many ticks should the repeater delay + unsigned char a_ElapsedTicks; // How much of the previous has been elapsed? + bool ShouldPowerOn; // What happens when the delay time is fulfilled? }; public: @@ -87,85 +91,86 @@ private: /* ====== SOURCES ====== */ /** Handles the redstone torch */ - void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); /** Handles the redstone block */ - void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles levers */ - void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles buttons */ - void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType); + void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles daylight sensors */ - void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles pressure plates */ - void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); + void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); /* ==================== */ /* ====== CARRIERS ====== */ /** Handles redstone wire */ - void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles repeaters */ - void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); /* ====================== */ /* ====== DEVICES ====== */ /** Handles pistons */ - void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles dispensers and droppers */ - void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles TNT (exploding) */ - void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles redstone lamps */ - void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState); + void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); /** Handles doords */ - void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles command blocks */ - void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles activator, detector, and powered rails */ - void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType); + void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType); /** Handles trapdoors */ - void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles fence gates */ - void HandleFenceGate(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Handles noteblocks */ - void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ); + void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /* ===================== */ /* ====== Helper functions ====== */ /** Marks a block as powered */ - void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock); + void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks a block as being powered through another block */ - void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock); + void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */ - void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered); + void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered); /** Marks the second block in a direction as linked powered */ - void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock); + void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Marks all blocks immediately surrounding a coordinate as powered */ - void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock); + void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); /** Queues a repeater to be powered or unpowered */ - void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); + void QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); /** Returns if a coordinate is powered or linked powered */ - bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); } + bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } /** Returns if a coordinate is in the directly powered blocks list */ - bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ); + bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Returns if a coordinate is in the indirectly powered blocks list */ - bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ); + bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */ - bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered); + bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered); /** Returns if a repeater is powered */ - bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); + /** Returns if a repeater is locked */ + bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); /** Returns if a piston is powered */ - bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); + bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta); /** Returns if a wire is powered - The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire - */ - bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ); + The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */ + bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel); /** Returns if lever metadata marks it as emitting power */ bool IsLeverOn(NIBBLETYPE a_BlockMeta); /** Returns if button metadata marks it as emitting power */ - bool IsButtonOn(NIBBLETYPE a_BlockMeta); + bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); } /* ============================== */ /* ====== Misc Functions ====== */ diff --git a/src/Simulator/SandSimulator.cpp b/src/Simulator/SandSimulator.cpp index f305ba61a..b8f34559f 100644 --- a/src/Simulator/SandSimulator.cpp +++ b/src/Simulator/SandSimulator.cpp @@ -64,7 +64,7 @@ void cSandSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChun a_Chunk->SetBlock(itr->x, itr->y, itr->z, E_BLOCK_AIR, 0); } } - m_TotalBlocks -= ChunkData.size(); + m_TotalBlocks -= (int)ChunkData.size(); ChunkData.clear(); } @@ -254,6 +254,10 @@ void cSandSimulator::FinishFalling( { // Rematerialize the material here: a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FallingBlockType, a_FallingBlockMeta); + if (a_FallingBlockType == E_BLOCK_ANVIL) + { + a_World->BroadcastSoundParticleEffect(1022, a_BlockX, a_BlockY, a_BlockZ, 0); + } return; } diff --git a/src/Simulator/VanillaFluidSimulator.cpp b/src/Simulator/VanillaFluidSimulator.cpp index 78aff9d68..18d9b07e1 100644 --- a/src/Simulator/VanillaFluidSimulator.cpp +++ b/src/Simulator/VanillaFluidSimulator.cpp @@ -35,14 +35,16 @@ cVanillaFluidSimulator::cVanillaFluidSimulator( -void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) +void cVanillaFluidSimulator::SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) { + // Calculate the distance to the nearest "hole" in each direction: int Cost[4]; Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS); Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS); Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS); Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS); + // Find the minimum distance: int MinCost = InfiniteCost; for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i) { @@ -52,6 +54,7 @@ void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, in } } + // Spread in all directions where the distance matches the minimum: if (Cost[0] == MinCost) { SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta); @@ -86,7 +89,10 @@ int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int { return Cost; } - if (!IsPassableForFluid(BlockType) && !IsBlockLiquid(BlockType)) + if ( + !IsPassableForFluid(BlockType) || // The block cannot be passed by the liquid ... + (IsAllowedBlock(BlockType) && (BlockMeta == 0)) // ... or if it is liquid, it is a source block + ) { return Cost; } diff --git a/src/Simulator/VanillaFluidSimulator.h b/src/Simulator/VanillaFluidSimulator.h index a9ea98b5a..89a56ca14 100644 --- a/src/Simulator/VanillaFluidSimulator.h +++ b/src/Simulator/VanillaFluidSimulator.h @@ -30,7 +30,7 @@ public: protected: // cFloodyFluidSimulator overrides: - virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override; + virtual void SpreadXZ(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override; /** Recursively calculates the minimum number of blocks needed to descend a level. */ int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0); diff --git a/src/StackWalker.cpp b/src/StackWalker.cpp index b4f8ed8c7..b608d69e6 100644 --- a/src/StackWalker.cpp +++ b/src/StackWalker.cpp @@ -935,7 +935,8 @@ BOOL StackWalker::LoadModules() break; } } // for (search for path separator...) - if (strlen(szTemp) > 0) + + if (szTemp[0] != '\0') // If szTemp is not empty (Note: This is more efficient than using strlen) { strcat_s(szSymPath, nSymPathLen, szTemp); strcat_s(szSymPath, nSymPathLen, ";"); diff --git a/src/Statistics.cpp b/src/Statistics.cpp new file mode 100644 index 000000000..5c0524f9e --- /dev/null +++ b/src/Statistics.cpp @@ -0,0 +1,196 @@ + +// Statistics.cpp + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Statistics.h" + + + +cStatInfo cStatInfo::ms_Info[statCount] = { + // The order must match the order of enum eStatistic + + // http://minecraft.gamepedia.com/Achievements + + /* Type | Name | Prerequisite */ + cStatInfo(achOpenInv, "achievement.openInventory"), + cStatInfo(achMineWood, "achievement.mineWood", achOpenInv), + cStatInfo(achCraftWorkbench, "achievement.buildWorkBench", achMineWood), + cStatInfo(achCraftPickaxe, "achievement.buildPickaxe", achCraftWorkbench), + cStatInfo(achCraftFurnace, "achievement.buildFurnace", achCraftPickaxe), + cStatInfo(achAcquireIron, "achievement.acquireIron", achCraftFurnace), + cStatInfo(achCraftHoe, "achievement.buildHoe", achCraftWorkbench), + cStatInfo(achMakeBread, "achievement.makeBread", achCraftHoe), + cStatInfo(achBakeCake, "achievement.bakeCake", achCraftHoe), + cStatInfo(achCraftBetterPick, "achievement.buildBetterPickaxe", achCraftPickaxe), + cStatInfo(achCookFish, "achievement.cookFish", achAcquireIron), + cStatInfo(achOnARail, "achievement.onARail", achAcquireIron), + cStatInfo(achCraftSword, "achievement.buildSword", achCraftWorkbench), + cStatInfo(achKillMonster, "achievement.killEnemy", achCraftSword), + cStatInfo(achKillCow, "achievement.killCow", achCraftSword), + cStatInfo(achFlyPig, "achievement.flyPig", achKillCow), + cStatInfo(achSnipeSkeleton, "achievement.snipeSkeleton", achKillMonster), + cStatInfo(achDiamonds, "achievement.diamonds", achAcquireIron), + cStatInfo(achEnterPortal, "achievement.portal", achDiamonds), + cStatInfo(achReturnToSender, "achievement.ghast", achEnterPortal), + cStatInfo(achBlazeRod, "achievement.blazeRod", achEnterPortal), + cStatInfo(achBrewPotion, "achievement.potion", achBlazeRod), + cStatInfo(achEnterTheEnd, "achievement.theEnd", achBlazeRod), + cStatInfo(achDefeatDragon, "achievement.theEnd2", achEnterTheEnd), + cStatInfo(achCraftEnchantTable, "achievement.enchantments", achDiamonds), + cStatInfo(achOverkill, "achievement.overkill", achCraftEnchantTable), + cStatInfo(achBookshelf, "achievement.bookcase", achCraftEnchantTable), + cStatInfo(achExploreAllBiomes, "achievement.exploreAllBiomes", achEnterTheEnd), + cStatInfo(achSpawnWither, "achievement.spawnWither", achDefeatDragon), + cStatInfo(achKillWither, "achievement.killWither", achSpawnWither), + cStatInfo(achFullBeacon, "achievement.fullBeacon", achKillWither), + cStatInfo(achBreedCow, "achievement.breedCow", achKillCow), + cStatInfo(achThrowDiamonds, "achievement.diamondsToYou", achDiamonds), + + // http://minecraft.gamepedia.com/Statistics + + /* Type | Name */ + cStatInfo(statGamesQuit, "stat.leaveGame"), + cStatInfo(statMinutesPlayed, "stat.playOneMinute"), + cStatInfo(statDistWalked, "stat.walkOneCm"), + cStatInfo(statDistSwum, "stat.swimOneCm"), + cStatInfo(statDistFallen, "stat.fallOneCm"), + cStatInfo(statDistClimbed, "stat.climbOneCm"), + cStatInfo(statDistFlown, "stat.flyOneCm"), + cStatInfo(statDistDove, "stat.diveOneCm"), + cStatInfo(statDistMinecart, "stat.minecartOneCm"), + cStatInfo(statDistBoat, "stat.boatOneCm"), + cStatInfo(statDistPig, "stat.pigOneCm"), + cStatInfo(statDistHorse, "stat.horseOneCm"), + cStatInfo(statJumps, "stat.jump"), + cStatInfo(statItemsDropped, "stat.drop"), + cStatInfo(statDamageDealt, "stat.damageDealt"), + cStatInfo(statDamageTaken, "stat.damageTaken"), + cStatInfo(statDeaths, "stat.deaths"), + cStatInfo(statMobKills, "stat.mobKills"), + cStatInfo(statAnimalsBred, "stat.animalsBred"), + cStatInfo(statPlayerKills, "stat.playerKills"), + cStatInfo(statFishCaught, "stat.fishCaught"), + cStatInfo(statJunkFished, "stat.junkFished"), + cStatInfo(statTreasureFished, "stat.treasureFished") +}; + + + + + + +cStatInfo::cStatInfo() + : m_Type(statInvalid) + , m_Depends(statInvalid) +{} + + + + + +cStatInfo::cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends) + : m_Type(a_Type) + , m_Name(a_Name) + , m_Depends(a_Depends) +{} + + + + + +const AString & cStatInfo::GetName(const eStatistic a_Type) +{ + ASSERT((a_Type > statInvalid) && (a_Type < statCount)); + + return ms_Info[a_Type].m_Name; +} + + + + + +eStatistic cStatInfo::GetType(const AString & a_Name) +{ + for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i) + { + if (NoCaseCompare(ms_Info[i].m_Name, a_Name) == 0) + { + return ms_Info[i].m_Type; + } + } + + return statInvalid; +} + + + + + +eStatistic cStatInfo::GetPrerequisite(const eStatistic a_Type) +{ + ASSERT((a_Type > statInvalid) && (a_Type < statCount)); + + return ms_Info[a_Type].m_Depends; +} + + + + + +cStatManager::cStatManager() +{ + Reset(); +} + + + + + +StatValue cStatManager::GetValue(const eStatistic a_Stat) const +{ + ASSERT((a_Stat > statInvalid) && (a_Stat < statCount)); + + return m_MainStats[a_Stat]; +} + + + + + +void cStatManager::SetValue(const eStatistic a_Stat, const StatValue a_Value) +{ + ASSERT((a_Stat > statInvalid) && (a_Stat < statCount)); + + m_MainStats[a_Stat] = a_Value; +} + + + + + +StatValue cStatManager::AddValue(const eStatistic a_Stat, const StatValue a_Delta) +{ + ASSERT((a_Stat > statInvalid) && (a_Stat < statCount)); + + m_MainStats[a_Stat] += a_Delta; + + return m_MainStats[a_Stat]; +} + + + + + +void cStatManager::Reset(void) +{ + for (unsigned int i = 0; i < (unsigned int)statCount; ++i) + { + m_MainStats[i] = 0; + } +} + + + + + diff --git a/src/Statistics.h b/src/Statistics.h new file mode 100644 index 000000000..f37f32e1e --- /dev/null +++ b/src/Statistics.h @@ -0,0 +1,164 @@ + +// Statistics.h + + + + +#pragma once + + + + +// tolua_begin +enum eStatistic +{ + // The order must match the order of cStatInfo::ms_Info + + statInvalid = -1, + + /* Achievements */ + achOpenInv, /* Taking Inventory */ + achMineWood, /* Getting Wood */ + achCraftWorkbench, /* Benchmarking */ + achCraftPickaxe, /* Time to Mine! */ + achCraftFurnace, /* Hot Topic */ + achAcquireIron, /* Acquire Hardware */ + achCraftHoe, /* Time to Farm! */ + achMakeBread, /* Bake Bread */ + achBakeCake, /* The Lie */ + achCraftBetterPick, /* Getting an Upgrade */ + achCookFish, /* Delicious Fish */ + achOnARail, /* On A Rail */ + achCraftSword, /* Time to Strike! */ + achKillMonster, /* Monster Hunter */ + achKillCow, /* Cow Tipper */ + achFlyPig, /* When Pigs Fly */ + achSnipeSkeleton, /* Sniper Duel */ + achDiamonds, /* DIAMONDS! */ + achEnterPortal, /* We Need to Go Deeper */ + achReturnToSender, /* Return to Sender */ + achBlazeRod, /* Into Fire */ + achBrewPotion, /* Local Brewery */ + achEnterTheEnd, /* The End? */ + achDefeatDragon, /* The End. */ + achCraftEnchantTable, /* Enchanter */ + achOverkill, /* Overkill */ + achBookshelf, /* Librarian */ + achExploreAllBiomes, /* Adventuring Time */ + achSpawnWither, /* The Beginning? */ + achKillWither, /* The Beginning. */ + achFullBeacon, /* Beaconator */ + achBreedCow, /* Repopulation */ + achThrowDiamonds, /* Diamonds to you! */ + + /* Statistics */ + statGamesQuit, + statMinutesPlayed, + statDistWalked, + statDistSwum, + statDistFallen, + statDistClimbed, + statDistFlown, + statDistDove, + statDistMinecart, + statDistBoat, + statDistPig, + statDistHorse, + statJumps, + statItemsDropped, + statDamageDealt, + statDamageTaken, + statDeaths, + statMobKills, + statAnimalsBred, + statPlayerKills, + statFishCaught, + statJunkFished, + statTreasureFished, + + statCount +}; +// tolua_end + + + + + + +/** Class used to store and query statistic-related information. */ +class cStatInfo +{ +public: + + cStatInfo(); + + cStatInfo(const eStatistic a_Type, const AString & a_Name, const eStatistic a_Depends = statInvalid); + + /** Type -> Name */ + static const AString & GetName(const eStatistic a_Type); + + /** Name -> Type */ + static eStatistic GetType(const AString & a_Name); + + /** Returns stat prerequisite. (Used for achievements) */ + static eStatistic GetPrerequisite(const eStatistic a_Type); + +private: + + eStatistic m_Type; + + AString m_Name; + + eStatistic m_Depends; + + static cStatInfo ms_Info[statCount]; +}; + + + + +/* Signed (?) integral value. */ +typedef int StatValue; // tolua_export + + + + +/** Class that manages the statistics and achievements of a single player. */ +// tolua_begin +class cStatManager +{ +public: + // tolua_end + + cStatManager(); + + // tolua_begin + + /** Return the value of the specified stat. */ + StatValue GetValue(const eStatistic a_Stat) const; + + /** Set the value of the specified stat. */ + void SetValue(const eStatistic a_Stat, const StatValue a_Value); + + /** Reset everything. */ + void Reset(); + + /** Increment the specified stat. + * + * Returns the new value. + */ + StatValue AddValue(const eStatistic a_Stat, const StatValue a_Delta = 1); + + // tolua_end + +private: + + StatValue m_MainStats[statCount]; + + // TODO 10-05-2014 xdot: Use, mine, craft statistics + + +}; // tolua_export + + + diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp index 5b9a3bb0a..71d64e71e 100644 --- a/src/StringCompression.cpp +++ b/src/StringCompression.cpp @@ -11,15 +11,15 @@ /// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2() -int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor) +int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor) { - uLongf CompressedSize = compressBound(a_Length); + uLongf CompressedSize = compressBound((uLong)a_Length); // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer! // It saves us one allocation and one memcpy of the entire compressed data // It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010) a_Compressed.resize(CompressedSize); - int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor); + int errorcode = compress2((Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef *)a_Data, (uLong)a_Length, a_Factor); if (errorcode != Z_OK) { return errorcode; @@ -33,14 +33,14 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, in /// Uncompresses a_Data into a_Decompressed; returns Z_XXX error constants same as zlib's uncompress() -int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize) +int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize) { // HACK: We're assuming that AString returns its internal buffer in its data() call and we're overwriting that buffer! // It saves us one allocation and one memcpy of the entire compressed data // It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010) a_Uncompressed.resize(a_UncompressedSize); uLongf UncompressedSize = (uLongf)a_UncompressedSize; // On some architectures the uLongf is different in size to int, that may be the cause of the -5 error - int errorcode = uncompress((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, a_Length); + int errorcode = uncompress((Bytef*)a_Uncompressed.data(), &UncompressedSize, (const Bytef*)a_Data, (uLong)a_Length); if (errorcode != Z_OK) { return errorcode; @@ -53,7 +53,7 @@ int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed -int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed) +int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed) { // Compress a_Data into a_Compressed using GZIP; return Z_XXX error constants same as zlib's compress2() @@ -63,7 +63,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed z_stream strm; memset(&strm, 0, sizeof(strm)); strm.next_in = (Bytef *)a_Data; - strm.avail_in = a_Length; + strm.avail_in = (uInt)a_Length; strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); @@ -83,6 +83,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed { // Some data has been compressed. Consume the buffer and continue compressing a_Compressed.append(Buffer, sizeof(Buffer) - strm.avail_out); + strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); if (strm.avail_in == 0) { @@ -116,7 +117,7 @@ int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed -extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed) +extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed) { // Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib @@ -126,7 +127,7 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U z_stream strm; memset(&strm, 0, sizeof(strm)); strm.next_in = (Bytef *)a_Data; - strm.avail_in = a_Length; + strm.avail_in = (uInt)a_Length; strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); @@ -139,13 +140,14 @@ extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_U for (;;) { - res = inflate(&strm, Z_FINISH); + res = inflate(&strm, Z_NO_FLUSH); switch (res) { case Z_OK: { // Some data has been uncompressed. Consume the buffer and continue uncompressing a_Uncompressed.append(Buffer, sizeof(Buffer) - strm.avail_out); + strm.next_out = (Bytef *)Buffer; strm.avail_out = sizeof(Buffer); if (strm.avail_in == 0) { diff --git a/src/StringCompression.h b/src/StringCompression.h index 3f4e12d2d..038240797 100644 --- a/src/StringCompression.h +++ b/src/StringCompression.h @@ -10,16 +10,16 @@ /// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2() -extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor); +extern int CompressString(const char * a_Data, size_t a_Length, AString & a_Compressed, int a_Factor); /// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress() -extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize); +extern int UncompressString(const char * a_Data, size_t a_Length, AString & a_Uncompressed, size_t a_UncompressedSize); /// Compresses a_Data into a_Compressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib -extern int CompressStringGZIP(const char * a_Data, int a_Length, AString & a_Compressed); +extern int CompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Compressed); /// Uncompresses a_Data into a_Uncompressed using GZIP; returns Z_OK for success or Z_XXX error constants same as zlib -extern int UncompressStringGZIP(const char * a_Data, int a_Length, AString & a_Uncompressed); +extern int UncompressStringGZIP(const char * a_Data, size_t a_Length, AString & a_Uncompressed); diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp index ad622d707..7488a3073 100644 --- a/src/StringUtils.cpp +++ b/src/StringUtils.cpp @@ -247,18 +247,22 @@ int NoCaseCompare(const AString & s1, const AString & s2) -unsigned int RateCompareString(const AString & s1, const AString & s2 ) +size_t RateCompareString(const AString & s1, const AString & s2) { - unsigned int MatchedLetters = 0; - unsigned int s1Length = s1.length(); + size_t MatchedLetters = 0; + size_t s1Length = s1.length(); - if( s1Length > s2.length() ) return 0; // Definitely not a match + if (s1Length > s2.length()) + { + // Definitely not a match + return 0; + } - for (unsigned int i = 0; i < s1Length; i++) + for (size_t i = 0; i < s1Length; i++) { - char c1 = (char)toupper( s1[i] ); - char c2 = (char)toupper( s2[i] ); - if( c1 == c2 ) + char c1 = (char)toupper(s1[i]); + char c2 = (char)toupper(s2[i]); + if (c1 == c2) { ++MatchedLetters; } @@ -288,11 +292,11 @@ void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & // Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 -AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8) +AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8) { a_UTF8.clear(); a_UTF8.reserve(3 * a_NumShorts / 2); // a quick guess of the resulting size - for (int i = 0; i < a_NumShorts; i++) + for (size_t i = 0; i < a_NumShorts; i++) { int c = GetBEShort(&a_RawData[i * 2]); if (c < 0x80) @@ -531,32 +535,32 @@ AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a format binary data this way: 00001234: 31 32 33 34 35 36 37 38 39 30 61 62 63 64 65 66 1234567890abcdef */ -AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_LineLength) +AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, size_t a_BytesPerLine) { - ASSERT(a_LineLength <= 120); // Due to using a fixed size line buffer; increase line[]'s size to lift this max + ASSERT(a_BytesPerLine <= 120); // Due to using a fixed size line buffer; increase line[]'s size to lift this max char line[512]; char * p; char * q; - a_Out.reserve(a_Size / a_LineLength * (18 + 6 * a_LineLength)); - for (int i = 0; i < a_Size; i += a_LineLength) + a_Out.reserve(a_Size / a_BytesPerLine * (18 + 6 * a_BytesPerLine)); + for (size_t i = 0; i < a_Size; i += a_BytesPerLine) { - int k = a_Size - i; - if (k > a_LineLength) + size_t k = a_Size - i; + if (k > a_BytesPerLine) { - k = a_LineLength; + k = a_BytesPerLine; } #ifdef _MSC_VER // MSVC provides a "secure" version of sprintf() - int Count = sprintf_s(line, sizeof(line), "%08x:", i); + int Count = sprintf_s(line, sizeof(line), "%08x:", (unsigned)i); #else - int Count = sprintf(line, "%08x:", i); + int Count = sprintf(line, "%08x:", (unsigned)i); #endif // Remove the terminating NULL / leftover garbage in line, after the sprintf-ed value memset(line + Count, 32, sizeof(line) - Count); p = line + 10; - q = p + 2 + a_LineLength * 3 + 1; - for (int j = 0; j < k; j++) + q = p + 2 + a_BytesPerLine * 3 + 1; + for (size_t j = 0; j < k; j++) { unsigned char c = ((unsigned char *)a_Data)[i + j]; p[0] = HEX(c >> 4); diff --git a/src/StringUtils.h b/src/StringUtils.h index 4feff7553..87b574a34 100644 --- a/src/StringUtils.h +++ b/src/StringUtils.h @@ -11,6 +11,9 @@ +#include <string> + + typedef std::string AString; @@ -52,19 +55,19 @@ extern AString & StrToLower(AString & s); extern int NoCaseCompare(const AString & s1, const AString & s2); // tolua_export /// Case-insensitive string comparison that returns a rating of equal-ness between [0 - s1.length()] -extern unsigned int RateCompareString(const AString & s1, const AString & s2 ); +extern size_t RateCompareString(const AString & s1, const AString & s2); /// Replaces *each* occurence of iNeedle in iHayStack with iReplaceWith extern void ReplaceString(AString & iHayStack, const AString & iNeedle, const AString & iReplaceWith); // tolua_export /// Converts a stream of BE shorts into UTF-8 string; returns a ref to a_UTF8 -extern AString & RawBEToUTF8(const char * a_RawData, int a_NumShorts, AString & a_UTF8); +extern AString & RawBEToUTF8(const char * a_RawData, size_t a_NumShorts, AString & a_UTF8); /// Converts a UTF-8 string into a UTF-16 BE string, packing that back into AString; return a ref to a_UTF16 extern AString & UTF8ToRawBEUTF16(const char * a_UTF8, size_t a_UTF8Length, AString & a_UTF16); /// Creates a nicely formatted HEX dump of the given memory block. Max a_BytesPerLine is 120 -extern AString & CreateHexDump(AString & a_Out, const void * a_Data, int a_Size, int a_BytesPerLine); +extern AString & CreateHexDump(AString & a_Out, const void * a_Data, size_t a_Size, size_t a_BytesPerLine); /// Returns a copy of a_Message with all quotes and backslashes escaped by a backslash extern AString EscapeString(const AString & a_Message); // tolua_export @@ -79,10 +82,10 @@ extern AString URLDecode(const AString & a_String); // Cannot export to Lua aut extern AString ReplaceAllCharOccurrences(const AString & a_String, char a_From, char a_To); // Needn't export to Lua, since Lua doesn't have chars anyway /// Decodes a Base64-encoded string into the raw data -extern AString Base64Decode(const AString & a_Base64String); +extern AString Base64Decode(const AString & a_Base64String); // Exported manually due to embedded NULs and extra parameter /// Encodes a string into Base64 -extern AString Base64Encode(const AString & a_Input); +extern AString Base64Encode(const AString & a_Input); // Exported manually due to embedded NULs and extra parameter /// Reads two bytes from the specified memory location and interprets them as BigEndian short extern short GetBEShort(const char * a_Mem); diff --git a/src/Tracer.cpp b/src/Tracer.cpp index 6da6b2ad7..be42430a5 100644 --- a/src/Tracer.cpp +++ b/src/Tracer.cpp @@ -219,6 +219,10 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int return false; } + if ((pos.y < 0) || (pos.y >= cChunkDef::Height)) + { + return false; + } BLOCKTYPE BlockID = m_World->GetBlock(pos.x, pos.y, pos.z); // Block is counted as a collision if we are not doing a line of sight and it is solid, // or if the block is not air and not water. That way mobs can still see underwater. @@ -226,7 +230,7 @@ bool cTracer::Trace( const Vector3f & a_Start, const Vector3f & a_Direction, int { BlockHitPosition = pos; int Normal = GetHitNormal(a_Start, End, pos ); - if(Normal > 0) + if (Normal > 0) { HitNormal = m_NormalTable[Normal-1]; } diff --git a/src/UI/CMakeLists.txt b/src/UI/CMakeLists.txt index cef2a9f35..5b5b8cc18 100644 --- a/src/UI/CMakeLists.txt +++ b/src/UI/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(UI ${SOURCE}) diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp index 88977e005..507b45833 100644 --- a/src/UI/SlotArea.cpp +++ b/src/UI/SlotArea.cpp @@ -13,6 +13,8 @@ #include "Window.h" #include "../CraftingRecipes.h" #include "../Root.h" +#include "../FastRandom.h" +#include "../BlockArea.h" @@ -145,6 +147,7 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA FreeSlots = 0; } int Filling = (FreeSlots > DraggingItem.m_ItemCount) ? DraggingItem.m_ItemCount : FreeSlots; + Slot.m_ItemCount += (char)Filling; DraggingItem.m_ItemCount -= (char)Filling; if (DraggingItem.m_ItemCount <= 0) @@ -167,7 +170,6 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA { m_ParentWindow.BroadcastWholeWindow(); } - } @@ -242,7 +244,7 @@ void cSlotArea::OnPlayerRemoved(cPlayer & a_Player) -void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) +void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) { for (int i = 0; i < m_NumSlots; i++) { @@ -262,7 +264,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ { NumFit = a_ItemStack.m_ItemCount; } - if (a_Apply) + if (a_ShouldApply) { cItem NewSlot(a_ItemStack); NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; @@ -483,6 +485,7 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) // Get the current recipe: cCraftingRecipe & Recipe = GetRecipeForPlayer(a_Player); + const cItem & Result = Recipe.GetResult(); cItem * PlayerSlots = GetPlayerSlots(a_Player) + 1; cCraftingGrid Grid(PlayerSlots, m_GridSize, m_GridSize); @@ -490,18 +493,22 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) // If possible, craft: if (DraggingItem.IsEmpty()) { - DraggingItem = Recipe.GetResult(); + DraggingItem = Result; Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); + + HandleCraftItem(Result, a_Player); } - else if (DraggingItem.IsEqual(Recipe.GetResult())) + else if (DraggingItem.IsEqual(Result)) { - cItemHandler * Handler = ItemHandler(Recipe.GetResult().m_ItemType); - if (DraggingItem.m_ItemCount + Recipe.GetResult().m_ItemCount <= Handler->GetMaxStackSize()) + cItemHandler * Handler = ItemHandler(Result.m_ItemType); + if (DraggingItem.m_ItemCount + Result.m_ItemCount <= Handler->GetMaxStackSize()) { - DraggingItem.m_ItemCount += Recipe.GetResult().m_ItemCount; + DraggingItem.m_ItemCount += Result.m_ItemCount; Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); + + HandleCraftItem(Result, a_Player); } } @@ -591,6 +598,731 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player) +void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Player) +{ + switch (a_Result.m_ItemType) + { + case E_BLOCK_WORKBENCH: a_Player.AwardAchievement(achCraftWorkbench); break; + case E_BLOCK_FURNACE: a_Player.AwardAchievement(achCraftFurnace); break; + case E_BLOCK_CAKE: a_Player.AwardAchievement(achBakeCake); break; + case E_BLOCK_ENCHANTMENT_TABLE: a_Player.AwardAchievement(achCraftEnchantTable); break; + case E_BLOCK_BOOKCASE: a_Player.AwardAchievement(achBookshelf); break; + case E_ITEM_WOODEN_PICKAXE: a_Player.AwardAchievement(achCraftPickaxe); break; + case E_ITEM_WOODEN_SWORD: a_Player.AwardAchievement(achCraftSword); break; + case E_ITEM_STONE_PICKAXE: a_Player.AwardAchievement(achCraftBetterPick); break; + case E_ITEM_WOODEN_HOE: a_Player.AwardAchievement(achCraftHoe); break; + case E_ITEM_BREAD: a_Player.AwardAchievement(achMakeBread); break; + default: break; + } +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSlotAreaAnvil: + +cSlotAreaAnvil::cSlotAreaAnvil(cAnvilWindow & a_ParentWindow) : + cSlotAreaTemporary(3, a_ParentWindow), + m_MaximumCost(0) +{ +} + + + + + +void cSlotAreaAnvil::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + if (a_SlotNum != 2) + { + super::Clicked(a_Player, a_SlotNum, a_ClickAction, a_ClickedItem); + UpdateResult(a_Player); + return; + } + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + if (a_ClickAction == caDblClick) + { + return; + } + + if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + + if (Slot.IsEmpty()) + { + return; + } + if (!DraggingItem.IsEmpty()) + { + if (!(DraggingItem.IsEqual(Slot) && ((DraggingItem.m_ItemCount + Slot.m_ItemCount) <= cItemHandler::GetItemHandler(Slot)->GetMaxStackSize()))) + { + return; + } + } + + if (!CanTakeResultItem(a_Player)) + { + return; + } + + cItem NewItem = cItem(Slot); + NewItem.m_ItemCount += DraggingItem.m_ItemCount; + + Slot.Empty(); + DraggingItem.Empty(); + SetSlot(a_SlotNum, a_Player, Slot); + + DraggingItem = NewItem; + OnTakeResult(a_Player); + + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +void cSlotAreaAnvil::ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) +{ + if (a_SlotNum != 2) + { + super::ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + UpdateResult(a_Player); + return; + } + + // Make a copy of the slot, distribute it among the other areas, then update the slot to contain the leftover: + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + + if (Slot.IsEmpty() || !CanTakeResultItem(a_Player)) + { + return; + } + + m_ParentWindow.DistributeStack(Slot, a_Player, this, true); + if (Slot.IsEmpty()) + { + Slot.Empty(); + OnTakeResult(a_Player); + } + SetSlot(a_SlotNum, a_Player, Slot); + + // Some clients try to guess our actions and not always right (armor slots in 1.2.5), so we fix them: + m_ParentWindow.BroadcastWholeWindow(); +} + + + + + +void cSlotAreaAnvil::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) +{ + for (int i = 0; i < 2; i++) + { + const cItem * Slot = GetSlot(i, a_Player); + if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots)) + { + // Different items + continue; + } + int NumFit = ItemHandler(Slot->m_ItemType)->GetMaxStackSize() - Slot->m_ItemCount; + if (NumFit <= 0) + { + // Full stack already + continue; + } + if (NumFit > a_ItemStack.m_ItemCount) + { + NumFit = a_ItemStack.m_ItemCount; + } + if (a_ShouldApply) + { + cItem NewSlot(a_ItemStack); + NewSlot.m_ItemCount = Slot->m_ItemCount + NumFit; + SetSlot(i, a_Player, NewSlot); + } + a_ItemStack.m_ItemCount -= NumFit; + if (a_ItemStack.IsEmpty()) + { + UpdateResult(a_Player); + return; + } + } // for i - Slots + UpdateResult(a_Player); +} + + + + + +void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player) +{ + if (!a_Player.IsGameModeCreative()) + { + a_Player.DeltaExperience(-cPlayer::XpForLevel(m_MaximumCost)); + } + SetSlot(0, a_Player, cItem()); + + if (m_StackSizeToBeUsedInRepair > 0) + { + const cItem * Item = GetSlot(1, a_Player); + if (!Item->IsEmpty() && (Item->m_ItemCount > m_StackSizeToBeUsedInRepair)) + { + cItem NewSecondItem(*Item); + NewSecondItem.m_ItemCount -= m_StackSizeToBeUsedInRepair; + SetSlot(1, a_Player, NewSecondItem); + } + else + { + SetSlot(1, a_Player, cItem()); + } + } + else + { + SetSlot(1, a_Player, cItem()); + } + m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player); + + m_MaximumCost = 0; + ((cAnvilWindow*)&m_ParentWindow)->SetRepairedItemName("", NULL); + + int PosX, PosY, PosZ; + ((cAnvilWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); + + BLOCKTYPE Block; + NIBBLETYPE BlockMeta; + a_Player.GetWorld()->GetBlockTypeMeta(PosX, PosY, PosZ, Block, BlockMeta); + + cFastRandom Random; + if (!a_Player.IsGameModeCreative() && (Block == E_BLOCK_ANVIL) && (Random.NextFloat(1.0F) < 0.12F)) + { + NIBBLETYPE Orientation = BlockMeta & 0x3; + NIBBLETYPE AnvilDamage = BlockMeta >> 2; + ++AnvilDamage; + + if (AnvilDamage > 2) + { + // Anvil will break + a_Player.GetWorld()->SetBlock(PosX, PosY, PosZ, E_BLOCK_AIR, (NIBBLETYPE)0); + a_Player.GetWorld()->BroadcastSoundParticleEffect(1020, PosX, PosY, PosZ, 0); + a_Player.CloseWindow(false); + } + else + { + a_Player.GetWorld()->SetBlockMeta(PosX, PosY, PosZ, Orientation | (AnvilDamage << 2)); + a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0); + } + } + else + { + a_Player.GetWorld()->BroadcastSoundParticleEffect(1021, PosX, PosY, PosZ, 0); + } +} + + + + + +bool cSlotAreaAnvil::CanTakeResultItem(cPlayer & a_Player) +{ + return ( + ( + a_Player.IsGameModeCreative() || // Is the player in gamemode? + (a_Player.GetXpLevel() >= m_MaximumCost) // or the player have enough exp? + ) && + (!GetSlot(2, a_Player)->IsEmpty()) && // Is a item in the result slot? + (m_MaximumCost > 0) // When no maximum cost is set, the item isn't set from the UpdateResult() method and can't be a valid enchanting result. + ); +} + + + + + +void cSlotAreaAnvil::OnPlayerRemoved(cPlayer & a_Player) +{ + TossItems(a_Player, 0, 2); + super::OnPlayerRemoved(a_Player); +} + + + + + +void cSlotAreaAnvil::UpdateResult(cPlayer & a_Player) +{ + cItem Input(*GetSlot(0, a_Player)); + cItem SecondInput(*GetSlot(1, a_Player)); + cItem Output(*GetSlot(2, a_Player)); + + if (Input.IsEmpty() && !Output.IsEmpty()) + { + Output.Empty(); + SetSlot(2, a_Player, Output); + m_ParentWindow.SetProperty(0, 0, a_Player); + return; + } + + m_MaximumCost = 0; + m_StackSizeToBeUsedInRepair = 0; + int RepairCost = Input.m_RepairCost; + int NeedExp = 0; + bool IsEnchantBook = false; + if (!SecondInput.IsEmpty()) + { + IsEnchantBook = (SecondInput.m_ItemType == E_ITEM_ENCHANTED_BOOK); + + RepairCost += SecondInput.m_RepairCost; + if (Input.IsDamageable() && cItemHandler::GetItemHandler(Input)->CanRepairWithRawMaterial(SecondInput.m_ItemType)) + { + // Tool and armor repair with special item (iron / gold / diamond / ...) + int DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4); + if (DamageDiff <= 0) + { + // No enchantment + Output.Empty(); + SetSlot(2, a_Player, Output); + m_ParentWindow.SetProperty(0, 0, a_Player); + return; + } + + int x = 0; + while ((DamageDiff > 0) && (x < SecondInput.m_ItemCount)) + { + Input.m_ItemDamage -= DamageDiff; + NeedExp += std::max(1, DamageDiff / 100) + (int)Input.m_Enchantments.Count(); + DamageDiff = std::min((int)Input.m_ItemDamage, (int)Input.GetMaxDamage() / 4); + + ++x; + } + m_StackSizeToBeUsedInRepair = x; + } + else + { + // Tool and armor repair with two tools / armors + if (!IsEnchantBook && (!Input.IsSameType(SecondInput) || !Input.IsDamageable())) + { + // No enchantment + Output.Empty(); + SetSlot(2, a_Player, Output); + m_ParentWindow.SetProperty(0, 0, a_Player); + return; + } + + if ((Input.GetMaxDamage() > 0) && !IsEnchantBook) + { + int FirstDamageDiff = Input.GetMaxDamage() - Input.m_ItemDamage; + int SecondDamageDiff = SecondInput.GetMaxDamage() - SecondInput.m_ItemDamage; + int Damage = SecondDamageDiff + Input.GetMaxDamage() * 12 / 100; + + int NewItemDamage = Input.GetMaxDamage() - (FirstDamageDiff + Damage); + if (NewItemDamage > 0) + { + NewItemDamage = 0; + } + + if (NewItemDamage < Input.m_ItemDamage) + { + Input.m_ItemDamage = NewItemDamage; + NeedExp += std::max(1, Damage / 100); + } + } + + // TODO: Add enchantments. + } + } + + int NameChangeExp = 0; + const AString & RepairedItemName = ((cAnvilWindow*)&m_ParentWindow)->GetRepairedItemName(); + if (RepairedItemName.empty()) + { + // Remove custom name + if (!Input.m_CustomName.empty()) + { + NameChangeExp = (Input.IsDamageable()) ? 7 : (Input.m_ItemCount * 5); + NeedExp += NameChangeExp; + Input.m_CustomName = ""; + } + } + else if (RepairedItemName != Input.m_CustomName) + { + // Change custom name + NameChangeExp = (Input.IsDamageable()) ? 7 : (Input.m_ItemCount * 5); + NeedExp += NameChangeExp; + + if (!Input.m_CustomName.empty()) + { + RepairCost += NameChangeExp / 2; + } + + Input.m_CustomName = RepairedItemName; + } + + // TODO: Add enchantment exp cost. + + m_MaximumCost = RepairCost + NeedExp; + + if (NeedExp < 0) + { + Input.Empty(); + } + + if ((NameChangeExp == NeedExp) && (NameChangeExp > 0) && (m_MaximumCost >= 40)) + { + m_MaximumCost = 39; + } + if (m_MaximumCost >= 40 && !a_Player.IsGameModeCreative()) + { + Input.Empty(); + } + + if (!Input.IsEmpty()) + { + RepairCost = std::max(Input.m_RepairCost, SecondInput.m_RepairCost); + if (!Input.m_CustomName.empty()) + { + RepairCost -= 9; + } + RepairCost = std::max(RepairCost, 0); + RepairCost += 2; + Input.m_RepairCost = RepairCost; + } + + SetSlot(2, a_Player, Input); + m_ParentWindow.SetProperty(0, m_MaximumCost, a_Player); +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSlotAreaEnchanting: + +cSlotAreaEnchanting::cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow) : + cSlotAreaTemporary(1, a_ParentWindow) +{ + a_ParentWindow.m_SlotArea = this; +} + + + + + +void cSlotAreaEnchanting::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + switch (a_ClickAction) + { + case caShiftLeftClick: + case caShiftRightClick: + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + case caDblClick: + { + DblClicked(a_Player, a_SlotNum); + return; + } + default: + { + break; + } + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + switch (a_ClickAction) + { + case caRightClick: + { + // Right-clicked + if (DraggingItem.IsEmpty()) + { + DraggingItem = Slot.CopyOne(); + Slot.Empty(); + break; + } + + if (Slot.IsEmpty()) + { + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + if (DraggingItem.m_ItemCount <= 0) + { + DraggingItem.Empty(); + } + } + else if ((!DraggingItem.IsEqual(Slot)) && (DraggingItem.m_ItemCount == 1)) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + break; + } + + case caLeftClick: + { + // Left-clicked + if (DraggingItem.IsEmpty()) + { + DraggingItem = Slot.CopyOne(); + Slot.Empty(); + break; + } + + if (DraggingItem.IsEqual(Slot)) + { + // Do nothing + break; + } + + if (!Slot.IsEmpty()) + { + if (DraggingItem.m_ItemCount == 1) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + } + else + { + Slot = DraggingItem.CopyOne(); + DraggingItem.m_ItemCount -= 1; + if (DraggingItem.m_ItemCount <= 0) + { + DraggingItem.Empty(); + } + } + break; + } + default: + { + LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); + m_ParentWindow.BroadcastWholeWindow(); + return; + } + } // switch (a_ClickAction + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } + UpdateResult(a_Player); +} + + + + + +void cSlotAreaEnchanting::DblClicked(cPlayer & a_Player, int a_SlotNum) +{ + cItem & Dragging = a_Player.GetDraggingItem(); + if ((!Dragging.IsEmpty()) || (a_SlotNum != 0)) + { + return; + } + + cItem Item = *GetSlot(0, a_Player); + if (!m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, false)) + { + m_ParentWindow.CollectItemsToHand(Item, *this, a_Player, true); + } +} + + + + + +void cSlotAreaEnchanting::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_Apply, bool a_KeepEmptySlots) +{ + const cItem * Slot = GetSlot(0, a_Player); + if (!Slot->IsEmpty()) + { + return; + } + + if (a_Apply) + { + SetSlot(0, a_Player, a_ItemStack.CopyOne()); + } + a_ItemStack.m_ItemCount -= 1; + if (a_ItemStack.m_ItemCount <= 0) + { + a_ItemStack.Empty(); + } + + UpdateResult(a_Player); +} + + + + + +void cSlotAreaEnchanting::OnPlayerRemoved(cPlayer & a_Player) +{ + // Toss the item in the enchanting slot + TossItems(a_Player, 0, 1); + + super::OnPlayerRemoved(a_Player); +} + + + + + +void cSlotAreaEnchanting::UpdateResult(cPlayer & a_Player) +{ + cItem Item = *GetSlot(0, a_Player); + + if (Item.IsEmpty() || !Item.m_Enchantments.IsEmpty()) + { + m_ParentWindow.SetProperty(0, 0, a_Player); + m_ParentWindow.SetProperty(1, 0, a_Player); + m_ParentWindow.SetProperty(2, 0, a_Player); + } + else if (cItem::IsEnchantable(Item.m_ItemType) || Item.m_ItemType == E_ITEM_BOOK) + { + int Bookshelves = std::min(GetBookshelvesCount(a_Player.GetWorld()), 15); + + cFastRandom Random; + int base = (Random.GenerateRandomInteger(1, 8) + (int)floor((float)Bookshelves / 2) + Random.GenerateRandomInteger(0, Bookshelves)); + int topSlot = std::max(base / 3, 1); + int middleSlot = (base * 2) / 3 + 1; + int bottomSlot = std::max(base, Bookshelves * 2); + + m_ParentWindow.SetProperty(0, topSlot, a_Player); + m_ParentWindow.SetProperty(1, middleSlot, a_Player); + m_ParentWindow.SetProperty(2, bottomSlot, a_Player); + } + else + { + m_ParentWindow.SetProperty(0, 0, a_Player); + m_ParentWindow.SetProperty(1, 0, a_Player); + m_ParentWindow.SetProperty(2, 0, a_Player); + } +} + + + + + +int cSlotAreaEnchanting::GetBookshelvesCount(cWorld * a_World) +{ + int PosX, PosY, PosZ; + ((cEnchantingWindow*)&m_ParentWindow)->GetBlockPos(PosX, PosY, PosZ); + + int Bookshelves = 0; + cBlockArea Area; + Area.Read(a_World, PosX - 2, PosX + 2, PosY, PosY + 1, PosZ - 2, PosZ + 2); + + static const struct + { + int m_BookX, m_BookY, m_BookZ; // Coords to check for bookcases + int m_AirX, m_AirY, m_AirZ; // Coords to check for air; if not air, the bookcase won't be counted + } CheckCoords[] = + { + { 0, 0, 0, 1, 0, 1 }, // Bookcase at {0, 0, 0}, air at {1, 0, 1} + { 0, 0, 1, 1, 0, 1 }, // Bookcase at {0, 0, 1}, air at {1, 0, 1} + { 0, 0, 2, 1, 0, 2 }, // Bookcase at {0, 0, 2}, air at {1, 0, 2} + { 0, 0, 3, 1, 0, 3 }, // Bookcase at {0, 0, 3}, air at {1, 0, 3} + { 0, 0, 4, 1, 0, 3 }, // Bookcase at {0, 0, 4}, air at {1, 0, 3} + { 1, 0, 4, 1, 0, 3 }, // Bookcase at {1, 0, 4}, air at {1, 0, 3} + { 2, 0, 4, 2, 0, 3 }, // Bookcase at {2, 0, 4}, air at {2, 0, 3} + { 3, 0, 4, 3, 0, 3 }, // Bookcase at {3, 0, 4}, air at {3, 0, 3} + { 4, 0, 4, 3, 0, 3 }, // Bookcase at {4, 0, 4}, air at {3, 0, 3} + { 4, 0, 3, 3, 0, 3 }, // Bookcase at {4, 0, 3}, air at {3, 0, 3} + { 4, 0, 2, 3, 0, 2 }, // Bookcase at {4, 0, 2}, air at {3, 0, 2} + { 4, 0, 1, 3, 0, 1 }, // Bookcase at {4, 0, 1}, air at {3, 0, 1} + { 4, 0, 0, 3, 0, 1 }, // Bookcase at {4, 0, 0}, air at {3, 0, 1} + { 3, 0, 0, 3, 0, 1 }, // Bookcase at {3, 0, 0}, air at {3, 0, 1} + { 2, 0, 0, 2, 0, 1 }, // Bookcase at {2, 0, 0}, air at {2, 0, 1} + { 1, 0, 0, 1, 0, 1 }, // Bookcase at {1, 0, 0}, air at {1, 0, 1} + + { 0, 1, 0, 1, 1, 1 }, // Bookcase at {0, 1, 0}, air at {1, 1, 1} + { 0, 1, 1, 1, 1, 1 }, // Bookcase at {0, 1, 1}, air at {1, 1, 1} + { 0, 1, 2, 1, 1, 2 }, // Bookcase at {0, 1, 2}, air at {1, 1, 2} + { 0, 1, 3, 1, 1, 3 }, // Bookcase at {0, 1, 3}, air at {1, 1, 3} + { 0, 1, 4, 1, 1, 3 }, // Bookcase at {0, 1, 4}, air at {1, 1, 3} + { 1, 1, 4, 1, 1, 3 }, // Bookcase at {1, 1, 4}, air at {1, 1, 3} + { 2, 1, 4, 2, 1, 3 }, // Bookcase at {2, 1, 4}, air at {2, 1, 3} + { 3, 1, 4, 3, 1, 3 }, // Bookcase at {3, 1, 4}, air at {3, 1, 3} + { 4, 1, 4, 3, 1, 3 }, // Bookcase at {4, 1, 4}, air at {3, 1, 3} + { 4, 1, 3, 3, 1, 3 }, // Bookcase at {4, 1, 3}, air at {3, 1, 3} + { 4, 1, 2, 3, 1, 2 }, // Bookcase at {4, 1, 2}, air at {3, 1, 2} + { 4, 1, 1, 3, 1, 1 }, // Bookcase at {4, 1, 1}, air at {3, 1, 1} + { 4, 1, 0, 3, 1, 1 }, // Bookcase at {4, 1, 0}, air at {3, 1, 1} + { 3, 1, 0, 3, 1, 1 }, // Bookcase at {3, 1, 0}, air at {3, 1, 1} + { 2, 1, 0, 2, 1, 1 }, // Bookcase at {2, 1, 0}, air at {2, 1, 1} + { 1, 1, 0, 1, 1, 1 }, // Bookcase at {1, 1, 0}, air at {1, 1, 1} + }; + + for (size_t i = 0; i < ARRAYCOUNT(CheckCoords); i++) + { + if ( + (Area.GetRelBlockType(CheckCoords[i].m_AirX, CheckCoords[i].m_AirY, CheckCoords[i].m_AirZ) == E_BLOCK_AIR) && // There's air in the checkspot + (Area.GetRelBlockType(CheckCoords[i].m_BookX, CheckCoords[i].m_BookY, CheckCoords[i].m_BookZ) == E_BLOCK_BOOKCASE) // There's bookcase in the wanted place + ) + { + Bookshelves++; + } + } // for i - CheckCoords + + return Bookshelves; +} + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaEnderChest: @@ -686,7 +1418,7 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) { // Something has changed in the window, broadcast the entire window to all clients ASSERT(a_ItemGrid == &(m_Furnace->GetContents())); - + m_ParentWindow.BroadcastWholeWindow(); } @@ -694,6 +1426,21 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) +void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player) +{ + /** TODO 2014-05-12 xdot: Figure out when to call this method. */ + switch (a_Result.m_ItemType) + { + case E_ITEM_IRON: a_Player.AwardAchievement(achAcquireIron); break; + case E_ITEM_COOKED_FISH: a_Player.AwardAchievement(achCookFish); break; + default: break; + } +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaInventoryBase: @@ -787,6 +1534,80 @@ void cSlotAreaArmor::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bo +void cSlotAreaArmor::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) +{ + ASSERT((a_SlotNum >= 0) && (a_SlotNum < GetNumSlots())); + + bool bAsync = false; + if (GetSlot(a_SlotNum, a_Player) == NULL) + { + LOGWARNING("GetSlot(%d) returned NULL! Ignoring click", a_SlotNum); + return; + } + + if ((a_ClickAction == caShiftLeftClick) || (a_ClickAction == caShiftRightClick)) + { + ShiftClicked(a_Player, a_SlotNum, a_ClickedItem); + return; + } + + // Armors haven't a dbl click + if (a_ClickAction == caDblClick) + { + return; + } + + cItem Slot(*GetSlot(a_SlotNum, a_Player)); + if (!Slot.IsSameType(a_ClickedItem)) + { + LOGWARNING("*** Window lost sync at item %d in SlotArea with %d items ***", a_SlotNum, m_NumSlots); + LOGWARNING("My item: %s", ItemToFullString(Slot).c_str()); + LOGWARNING("Their item: %s", ItemToFullString(a_ClickedItem).c_str()); + bAsync = true; + } + cItem & DraggingItem = a_Player.GetDraggingItem(); + if ((a_ClickAction != caRightClick) && (a_ClickAction != caLeftClick)) + { + LOGWARNING("SlotArea: Unhandled click action: %d (%s)", a_ClickAction, ClickActionToString(a_ClickAction)); + m_ParentWindow.BroadcastWholeWindow(); + return; + } + + if (DraggingItem.IsEmpty() || CanPlaceInSlot(a_SlotNum, DraggingItem)) + { + // Swap contents + cItem tmp(DraggingItem); + DraggingItem = Slot; + Slot = tmp; + } + + SetSlot(a_SlotNum, a_Player, Slot); + if (bAsync) + { + m_ParentWindow.BroadcastWholeWindow(); + } +} + + + + + +bool cSlotAreaArmor::CanPlaceInSlot(int a_SlotNum, const cItem & a_Item) +{ + switch (a_SlotNum) + { + case 0: return ItemCategory::IsHelmet (a_Item.m_ItemType); + case 1: return ItemCategory::IsChestPlate(a_Item.m_ItemType); + case 2: return ItemCategory::IsLeggings (a_Item.m_ItemType); + case 3: return ItemCategory::IsBoots (a_Item.m_ItemType); + } + return false; +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cSlotAreaItemGrid: diff --git a/src/UI/SlotArea.h b/src/UI/SlotArea.h index 25b367cff..e297bcff7 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -9,6 +9,7 @@ #pragma once #include "../Inventory.h" +#include "Window.h" @@ -19,6 +20,8 @@ class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cCraftingRecipe; +class cEnchantingWindow; +class cWorld; @@ -66,7 +69,7 @@ public: /// If a_CollectFullStacks is false, slots with full stacks are skipped while collecting. /// Returns true if full stack has been collected in a_Dragging, false if there's space remaining to fill. virtual bool CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool a_CollectFullStacks); - + protected: int m_NumSlots; cWindow & m_ParentWindow; @@ -143,8 +146,13 @@ public: { } - // Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) + /** Distributing the stack is allowed only for compatible items (helmets into helmet slot etc.) */ virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + + /** Called when a player clicks in the window. Parameters taken from the click packet. */ + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + + bool CanPlaceInSlot(int a_SlotNum, const cItem & a_Item); } ; @@ -246,12 +254,80 @@ protected: /// Retrieves the recipe for the specified player from the map, or creates one if not found cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player); + + /// Called after an item has been crafted to handle statistics e.t.c. + void HandleCraftItem(const cItem & a_Result, cPlayer & a_Player); +} ; + + + + + +class cSlotAreaAnvil : + public cSlotAreaTemporary +{ + typedef cSlotAreaTemporary super; + +public: + cSlotAreaAnvil(cAnvilWindow & a_ParentWindow); + + // cSlotArea overrides: + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void ShiftClicked(cPlayer & a_Player, int a_SlotNum, const cItem & a_ClickedItem) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + + // cSlotAreaTemporary overrides: + virtual void OnPlayerRemoved(cPlayer & a_Player) override; + + /** Can the player take the item from the slot? */ + bool CanTakeResultItem(cPlayer & a_Player); + + /** This function will call, when the player take the item from the slot. */ + void OnTakeResult(cPlayer & a_Player); + + /** Handles a click in the item slot. */ + void UpdateResult(cPlayer & a_Player); + +protected: + /** The maximum cost of repairing/renaming in the anvil. */ + int m_MaximumCost; + + /** The stack size of the second item where was used for repair */ + char m_StackSizeToBeUsedInRepair; } ; +class cSlotAreaEnchanting : + public cSlotAreaTemporary +{ + typedef cSlotAreaTemporary super; + +public: + cSlotAreaEnchanting(cEnchantingWindow & a_ParentWindow); + + // cSlotArea overrides: + virtual void Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) override; + virtual void DblClicked(cPlayer & a_Player, int a_SlotNum) override; + virtual void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_ShouldApply, bool a_KeepEmptySlots) override; + + // cSlotAreaTemporary overrides: + virtual void OnPlayerRemoved(cPlayer & a_Player) override; + + /* Get the count of bookshelves who stand in the near of the enchanting table */ + int GetBookshelvesCount(cWorld * a_World); + +protected: + /** Handles a click in the item slot. */ + void UpdateResult(cPlayer & a_Player); +}; + + + + + class cSlotAreaChest : public cSlotArea { @@ -324,6 +400,9 @@ protected: // cItemGrid::cListener overrides: virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override; + + /// Called after an item has been smelted to handle statistics e.t.c. + void HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player); } ; diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index aae7b99a3..46885390b 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -591,7 +591,7 @@ void cWindow::OnLeftPaintEnd(cPlayer & a_Player) const cSlotNums & SlotNums = a_Player.GetInventoryPaintSlots(); cItem ToDistribute(a_Player.GetDraggingItem()); - int ToEachSlot = (int)ToDistribute.m_ItemCount / SlotNums.size(); + int ToEachSlot = (int)ToDistribute.m_ItemCount / (int)SlotNums.size(); int NumDistributed = DistributeItemToSlots(a_Player, ToDistribute, ToEachSlot, SlotNums); @@ -805,6 +805,111 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cAnvilWindow: + +cAnvilWindow::cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtAnvil, "Repair"), + m_RepairedItemName(""), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_AnvilSlotArea = new cSlotAreaAnvil(*this); + m_SlotAreas.push_back(m_AnvilSlotArea); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cAnvilWindow::SetRepairedItemName(const AString & a_Name, cPlayer * a_Player) +{ + m_RepairedItemName = a_Name; + + if (a_Player != NULL) + { + m_AnvilSlotArea->UpdateResult(*a_Player); + } +} + + + + + +void cAnvilWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) +{ + a_PosX = m_BlockX; + a_PosY = m_BlockY; + a_PosZ = m_BlockZ; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cEnchantingWindow: + +cEnchantingWindow::cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(wtEnchantment, "Enchant"), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_SlotAreas.push_back(new cSlotAreaEnchanting(*this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +void cEnchantingWindow::SetProperty(int a_Property, int a_Value) +{ + m_PropertyValue[a_Property] = a_Value; + + super::SetProperty(a_Property, a_Value); +} + + + + + +void cEnchantingWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) +{ + m_PropertyValue[a_Property] = a_Value; + + super::SetProperty(a_Property, a_Value, a_Player); +} + + + + + +int cEnchantingWindow::GetPropertyValue(int a_Property) +{ + return m_PropertyValue[a_Property]; +} + + + + + +void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ) +{ + a_PosX = m_BlockX; + a_PosY = m_BlockY; + a_PosZ = m_BlockZ; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cChestWindow: cChestWindow::cChestWindow(cChestEntity * a_Chest) : diff --git a/src/UI/Window.h b/src/UI/Window.h index 030182888..542dccb88 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -24,6 +24,7 @@ class cEnderChestEntity; class cFurnaceEntity; class cHopperEntity; class cSlotArea; +class cSlotAreaAnvil; class cWorld; typedef std::list<cPlayer *> cPlayerList; @@ -136,11 +137,11 @@ public: void SetWindowTitle(const AString & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; } /// Sends the UpdateWindowProperty (0x69) packet to all clients of the window - void SetProperty(int a_Property, int a_Value); + virtual void SetProperty(int a_Property, int a_Value); /// Sends the UpdateWindowPropert(0x69) packet to the specified player - void SetProperty(int a_Property, int a_Value, cPlayer & a_Player); - + virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player); + // tolua_end void OwnerDestroyed(void); @@ -165,7 +166,7 @@ public: /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum); - + protected: cSlotAreas m_SlotAreas; @@ -231,6 +232,58 @@ public: +class cAnvilWindow : + public cWindow +{ + typedef cWindow super; +public: + cAnvilWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + + /** Gets the repaired item name. */ + AString GetRepairedItemName(void) const { return m_RepairedItemName; } + + /** Set the repaired item name. */ + void SetRepairedItemName(const AString & a_Name, cPlayer * a_Player); + + /** Gets the Position from the Anvil */ + void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); + +protected: + cSlotAreaAnvil * m_AnvilSlotArea; + AString m_RepairedItemName; + int m_BlockX, m_BlockY, m_BlockZ; +} ; + + + + + +class cEnchantingWindow : + public cWindow +{ + typedef cWindow super; +public: + cEnchantingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); + virtual void SetProperty(int a_Property, int a_Value, cPlayer & a_Player) override; + virtual void SetProperty(int a_Property, int a_Value) override; + + /** Return the Value of a Property */ + int GetPropertyValue(int a_Property); + + /** Get the Position from the Enchantment Table */ + void GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ); + + cSlotArea * m_SlotArea; + +protected: + int m_PropertyValue[3]; + int m_BlockX, m_BlockY, m_BlockZ; +}; + + + + + class cFurnaceWindow : public cWindow { diff --git a/src/Vector3.h b/src/Vector3.h index a00e14508..5faac1457 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -5,6 +5,8 @@ #define _USE_MATH_DEFINES // Enable non-standard math defines (MSVC) #include <math.h> +#include <list> +#include <vector> @@ -40,7 +42,6 @@ public: Vector3(const Vector3<_T> * a_Rhs) : x(a_Rhs->x), y(a_Rhs->y), z(a_Rhs->z) {} // tolua_begin - inline void Set(T a_x, T a_y, T a_z) { x = a_x; @@ -105,13 +106,18 @@ public: inline bool Equals(const Vector3<T> & a_Rhs) const { - return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z; + // Perform a bitwise comparison of the contents - we want to know whether this object is exactly equal + // To perform EPS-based comparison, use the EqualsEps() function + return ( + (memcmp(&x, &a_Rhs.x, sizeof(x)) == 0) && + (memcmp(&y, &a_Rhs.y, sizeof(y)) == 0) && + (memcmp(&z, &a_Rhs.z, sizeof(z)) == 0) + ); } - - inline bool operator < (const Vector3<T> & a_Rhs) + + inline bool EqualsEps(const Vector3<T> & a_Rhs, T a_Eps) const { - // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ? - return (x < a_Rhs.x) || (x == a_Rhs.x && y < a_Rhs.y) || (x == a_Rhs.x && y == a_Rhs.y && z < a_Rhs.z); + return (Abs(x - a_Rhs.x) < a_Eps) && (Abs(y - a_Rhs.y) < a_Eps) && (Abs(z - a_Rhs.z) < a_Eps); } inline void Move(T a_X, T a_Y, T a_Z) @@ -130,6 +136,16 @@ public: // tolua_end + inline bool operator != (const Vector3<T> & a_Rhs) const + { + return !Equals(a_Rhs); + } + + inline bool operator == (const Vector3<T> & a_Rhs) const + { + return Equals(a_Rhs); + } + inline void operator += (const Vector3<T> & a_Rhs) { x += a_Rhs.x; @@ -158,8 +174,16 @@ public: z *= a_v; } - // tolua_begin + inline Vector3<T> & operator = (const Vector3<T> & a_Rhs) + { + x = a_Rhs.x; + y = a_Rhs.y; + z = a_Rhs.z; + return *this; + } + // tolua_begin + inline Vector3<T> operator + (const Vector3<T>& a_Rhs) const { return Vector3<T>( @@ -212,7 +236,7 @@ public: */ inline double LineCoeffToXYPlane(const Vector3<T> & a_OtherEnd, T a_Z) const { - if (abs(z - a_OtherEnd.z) < EPS) + if (Abs(z - a_OtherEnd.z) < EPS) { return NO_INTERSECTION; } @@ -227,7 +251,7 @@ public: */ inline double LineCoeffToXZPlane(const Vector3<T> & a_OtherEnd, T a_Y) const { - if (abs(y - a_OtherEnd.y) < EPS) + if (Abs(y - a_OtherEnd.y) < EPS) { return NO_INTERSECTION; } @@ -242,7 +266,7 @@ public: */ inline double LineCoeffToYZPlane(const Vector3<T> & a_OtherEnd, T a_X) const { - if (abs(x - a_OtherEnd.x) < EPS) + if (Abs(x - a_OtherEnd.x) < EPS) { return NO_INTERSECTION; } @@ -255,7 +279,15 @@ public: /** Return value of LineCoeffToPlane() if the line is parallel to the plane. */ static const double NO_INTERSECTION; + +protected: + /** Returns the absolute value of the given argument. + Templatized because the standard library differentiates between abs() and fabs(). */ + static T Abs(T a_Value) + { + return (a_Value < 0) ? -a_Value : a_Value; + } }; // tolua_end diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index 402cd3035..08e164d78 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -89,6 +89,7 @@ bool cWebAdmin::Init(void) m_IniFile.AddHeaderComment(" Password format: Password=*password*; for example:"); m_IniFile.AddHeaderComment(" [User:admin]"); m_IniFile.AddHeaderComment(" Password=admin"); + m_IniFile.WriteFile("webadmin.ini"); } if (!m_IniFile.GetValueSetB("WebAdmin", "Enabled", true)) @@ -229,10 +230,11 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque } // for itr - Data->m_Form[] // Parse the URL into individual params: - size_t idxQM = a_Request.GetURL().find('?'); + const AString & URL = a_Request.GetURL(); + size_t idxQM = URL.find('?'); if (idxQM != AString::npos) { - cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, a_Request.GetURL().c_str() + idxQM + 1, a_Request.GetURL().length() - idxQM - 1, *Data); + cHTTPFormParser URLParams(cHTTPFormParser::fpkURL, URL.c_str() + idxQM + 1, URL.length() - idxQM - 1, *Data); URLParams.Finish(); for (cHTTPFormParser::const_iterator itr = URLParams.begin(), end = URLParams.end(); itr != end; ++itr) { @@ -284,11 +286,6 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque Content = GetDefaultPage(); } - if (ShouldWrapInTemplate && (URL.size() > 1)) - { - Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>"; - } - int MemUsageKiB = cRoot::GetPhysicalRAMUsage(); if (MemUsageKiB > 0) { @@ -388,7 +385,6 @@ AString cWebAdmin::GetDefaultPage(void) { continue; } - AString VersionNum; AppendPrintf(Content, "<li>%s V.%i</li>", itr->second->GetName().c_str(), itr->second->GetVersion()); } Content += "</ul>"; @@ -490,7 +486,7 @@ void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_ -void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) +void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) { UNUSED(a_Connection); cRequestData * Data = (cRequestData *)(a_Request.GetUserData()); @@ -537,7 +533,7 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cWebAdmin::cWebadminRequestData -void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, int a_Size) +void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, size_t a_Size) { m_Form.Parse(a_Data, a_Size); } diff --git a/src/WebAdmin.h b/src/WebAdmin.h index a2a07a543..d5e45828f 100644 --- a/src/WebAdmin.h +++ b/src/WebAdmin.h @@ -151,7 +151,7 @@ protected: virtual ~cRequestData() {} // Force a virtual destructor in all descendants /** Called when a new chunk of body data is received */ - virtual void OnBody(const char * a_Data, int a_Size) = 0; + virtual void OnBody(const char * a_Data, size_t a_Size) = 0; } ; /** The body handler for requests in the "/webadmin" and "/~webadmin" paths */ @@ -169,14 +169,14 @@ protected: } // cRequestData overrides: - virtual void OnBody(const char * a_Data, int a_Size) override; + virtual void OnBody(const char * a_Data, size_t a_Size) override; // cHTTPFormParser::cCallbacks overrides. Files are ignored: - virtual void OnFileStart(cHTTPFormParser &, const AString & a_FileName) override + virtual void OnFileStart(cHTTPFormParser &, const AString & a_FileName) override { UNUSED(a_FileName); } - virtual void OnFileData(cHTTPFormParser &, const char * a_Data, int a_Size) override + virtual void OnFileData(cHTTPFormParser &, const char * a_Data, size_t a_Size) override { UNUSED(a_Data); UNUSED(a_Size); @@ -216,7 +216,7 @@ protected: // cHTTPServer::cCallbacks overrides: virtual void OnRequestBegun (cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override; - virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override; + virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override; virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override; } ; // tolua_export diff --git a/src/World.cpp b/src/World.cpp index e39a605bb..807065bfa 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -316,12 +316,9 @@ int cWorld::GetDefaultWeatherInterval(eWeather a_Weather) { return 2400 + (m_TickRand.randInt() % 4800); // 2 - 6 minutes } - default: - { - LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather); - return -1; - } - } // switch (Weather) + } + LOGWARNING("%s: Missing default weather interval for weather %d.", __FUNCTION__, a_Weather); + return -1; } @@ -397,10 +394,14 @@ void cWorld::InitializeSpawn(void) // For the debugging builds, don't make the server build too much world upon start: #if defined(_DEBUG) || defined(ANDROID_NDK) - int ViewDist = 9; + const int DefaultViewDist = 9; #else - int ViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is + const int DefaultViewDist = 20; // Always prepare an area 20 chunks across, no matter what the actual cClientHandle::VIEWDISTANCE is #endif // _DEBUG + cIniFile IniFile; + IniFile.ReadFile(m_IniFileName); + int ViewDist = IniFile.GetValueSetI("SpawnPosition", "PregenerateDistance", DefaultViewDist); + IniFile.WriteFile(m_IniFileName); LOG("Preparing spawn area in world \"%s\"...", m_WorldName.c_str()); for (int x = 0; x < ViewDist; x++) @@ -521,21 +522,6 @@ void cWorld::Start(void) } AString Dimension = IniFile.GetValueSet("General", "Dimension", "Overworld"); m_Dimension = StringToDimension(Dimension); - switch (m_Dimension) - { - case dimNether: - case dimOverworld: - case dimEnd: - { - break; - } - default: - { - LOGWARNING("Unknown dimension: \"%s\". Setting to Overworld", Dimension.c_str()); - m_Dimension = dimOverworld; - break; - } - } // switch (m_Dimension) // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); @@ -574,7 +560,7 @@ void cWorld::Start(void) m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true); m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true); - int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone); + int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slAll); m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false); m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true); m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true); @@ -592,12 +578,6 @@ void cWorld::Start(void) case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break; case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break; case dimEnd: DefaultMonsters = "enderman"; break; - default: - { - ASSERT(!"Unhandled world dimension"); - DefaultMonsters = "wither"; - break; - } } m_bAnimals = IniFile.GetValueSetB("Monsters", "AnimalsOn", true); AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters); @@ -687,6 +667,30 @@ void cWorld::GenerateRandomSpawn(void) +eWeather cWorld::ChooseNewWeather() +{ + // Pick a new weather. Only reasonable transitions allowed: + switch (m_Weather) + { + case eWeather_Sunny: + case eWeather_ThunderStorm: return eWeather_Rain; + + case eWeather_Rain: + { + // 1/8 chance of turning into a thunderstorm + return ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny; + } + } + + LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather); + ASSERT(!"Unknown weather"); + return eWeather_Sunny; +} + + + + + void cWorld::Stop(void) { // Delete the clients that have been in this world: @@ -786,30 +790,8 @@ void cWorld::TickWeather(float a_Dt) else { // Change weather: - - // Pick a new weather. Only reasonable transitions allowed: - eWeather NewWeather = m_Weather; - switch (m_Weather) - { - case eWeather_Sunny: NewWeather = eWeather_Rain; break; - case eWeather_ThunderStorm: NewWeather = eWeather_Rain; break; - case eWeather_Rain: - { - // 1/8 chance of turning into a thunderstorm - NewWeather = ((m_TickRand.randInt() % 256) < 32) ? eWeather_ThunderStorm : eWeather_Sunny; - break; - } - - default: - { - LOGWARNING("Unknown current weather: %d. Setting sunny.", m_Weather); - ASSERT(!"Unknown weather"); - NewWeather = eWeather_Sunny; - } - } - - SetWeather(NewWeather); - } // else (m_WeatherInterval > 0) + SetWeather(ChooseNewWeather()); + } if (m_Weather == eWeather_ThunderStorm) { @@ -860,7 +842,7 @@ void cWorld::TickMobs(float a_Dt) { m_ChunkMap->SpawnMobs(Spawner); // do the spawn - for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++) + for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2) { SpawnMobFinalize(*itr2); } @@ -870,14 +852,14 @@ void cWorld::TickMobs(float a_Dt) // move close mobs cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(-1, 64 * 16);// MG TODO : deal with this magic number (the 16 is the size of a block) - for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; ++itr) { itr->second.m_Monster.Tick(a_Dt, itr->second.m_Chunk); } // remove too far mobs cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(128 * 16, -1);// MG TODO : deal with this magic number (the 16 is the size of a block) - for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; ++itr) { itr->second.m_Monster.Destroy(true); } @@ -1632,7 +1614,6 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated) { - MTRand r1; a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr) { @@ -1642,9 +1623,9 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double continue; } - float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5)); - float SpeedY = (float)(a_FlyAwaySpeed * r1.randInt(50)); - float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5)); + float SpeedX = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5)); + float SpeedY = (float)(a_FlyAwaySpeed * GetTickRandomNumber(50)); + float SpeedZ = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5)); cPickup * Pickup = new cPickup( a_BlockX, a_BlockY, a_BlockZ, @@ -1692,6 +1673,11 @@ int cWorld::SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NI int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) { + if (a_Reward < 1) + { + return -1; + } + cExpOrb * ExpOrb = new cExpOrb(a_X, a_Y, a_Z, a_Reward); ExpOrb->Initialize(this); return ExpOrb->GetUniqueID(); @@ -2420,13 +2406,13 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback) { cPlayer * BestMatch = NULL; - unsigned int BestRating = 0; - unsigned int NameLength = a_PlayerNameHint.length(); + size_t BestRating = 0; + size_t NameLength = a_PlayerNameHint.length(); cCSLock Lock(m_CSPlayers); for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { - unsigned int Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName()); + size_t Rating = RateCompareString (a_PlayerNameHint, (*itr)->GetName()); if (Rating >= BestRating) { BestMatch = *itr; @@ -2440,7 +2426,6 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCa if (BestMatch != NULL) { - LOG("Compared %s and %s with rating %i", a_PlayerNameHint.c_str(), BestMatch->GetName().c_str(), BestRating); return a_Callback.Item (BestMatch); } return false; @@ -2890,7 +2875,7 @@ void cWorld::TickQueuedBlocks(void) m_BlockTickQueueCopy.clear(); m_BlockTickQueue.swap(m_BlockTickQueueCopy); - for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); itr++) + for (std::vector<BlockTickQueueItem *>::iterator itr = m_BlockTickQueueCopy.begin(); itr != m_BlockTickQueueCopy.end(); ++itr) { BlockTickQueueItem * Block = (*itr); Block->TicksToWait -= 1; @@ -2981,7 +2966,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster) -int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed) +int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed) { cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed); if (Projectile == NULL) @@ -2993,7 +2978,6 @@ int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProje delete Projectile; return -1; } - BroadcastSpawnEntity(*Projectile); return Projectile->GetUniqueID(); } diff --git a/src/World.h b/src/World.h index bb2eb0b21..86cbb3e7e 100644 --- a/src/World.h +++ b/src/World.h @@ -126,15 +126,15 @@ public: int GetTicksUntilWeatherChange(void) const { return m_WeatherInterval; } - virtual Int64 GetWorldAge (void) const { return m_WorldAge; } // override, cannot specify due to tolua - virtual Int64 GetTimeOfDay(void) const { return m_TimeOfDay; } // override, cannot specify due to tolua + virtual Int64 GetWorldAge (void) const override { return m_WorldAge; } + virtual Int64 GetTimeOfDay(void) const override { return m_TimeOfDay; } void SetTicksUntilWeatherChange(int a_WeatherInterval) { m_WeatherInterval = a_WeatherInterval; } - virtual void SetTimeOfDay(Int64 a_TimeOfDay) // override, cannot specify due to tolua + virtual void SetTimeOfDay(Int64 a_TimeOfDay) override { m_TimeOfDay = a_TimeOfDay; m_TimeOfDaySecs = (double)a_TimeOfDay / 20.0; @@ -351,7 +351,7 @@ public: /** Is the trapdoor open? Returns false if there is no trapdoor at the specified coords. */ bool IsTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export - /** Set the state of a trapdoor. Returns true if the trapdoor was update, false if there was no trapdoor at those coords. */ + /** Set the state of a trapdoor. Returns true if the trapdoor was updated, false if there was no trapdoor at those coords. */ bool SetTrapdoorOpen(int a_BlockX, int a_BlockY, int a_BlockZ, bool a_Open); // tolua_export /** Regenerate the given chunk: */ @@ -430,10 +430,10 @@ public: // tolua_begin /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ - virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false); // override; cannot specify it here due to tolua + virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) override; /** Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified: */ - virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false); // override; cannot specify it here due to tolua + virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false) override; /** Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block. */ int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta); @@ -457,7 +457,7 @@ public: // tolua_begin bool DigBlock (int a_X, int a_Y, int a_Z); - virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player); // override, cannot specify due to tolua + virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player) override; double GetSpawnX(void) const { return m_SpawnX; } double GetSpawnY(void) const { return m_SpawnY; } @@ -508,7 +508,7 @@ public: | esWitherBirth | cMonster * | | esPlugin | void * | */ - virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData); // tolua_export // override, cannot specify due to tolua + virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) override; // tolua_export /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp @@ -646,9 +646,9 @@ public: // Various queues length queries (cannot be const, they lock their CS): inline int GetGeneratorQueueLength (void) { return m_Generator.GetQueueLength(); } // tolua_export - inline int GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export - inline int GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export - inline int GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export + inline size_t GetLightingQueueLength (void) { return m_Lighting.GetQueueLength(); } // tolua_export + inline size_t GetStorageLoadQueueLength(void) { return m_Storage.GetLoadQueueLength(); } // tolua_export + inline size_t GetStorageSaveQueueLength(void) { return m_Storage.GetSaveQueueLength(); } // tolua_export void InitializeSpawn(void); @@ -707,11 +707,13 @@ public: bool IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export /** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */ - virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export // override, cannot specify due to tolua + virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) override; // tolua_export int SpawnMobFinalize(cMonster* a_Monster); - /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise */ - int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem a_Item, const Vector3d * a_Speed = NULL); // tolua_export + /** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise + Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata + */ + int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed = NULL); // tolua_export /** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */ int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); } @@ -938,7 +940,10 @@ private: /** <summary>Generates a random spawnpoint on solid land by walking chunks and finding their biomes</summary> */ void GenerateRandomSpawn(void); - + + /** Chooses a reasonable transition from the current weather to a new weather **/ + eWeather ChooseNewWeather(void); + /** Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section) */ cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock); diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt index 2c83c4662..2844f7fe5 100644 --- a/src/WorldStorage/CMakeLists.txt +++ b/src/WorldStorage/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(WorldStorage ${SOURCE}) diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index be25fd1a4..a047d67c7 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -29,7 +29,7 @@ // cParsedNBT: #define NEEDBYTES(N) \ - if (m_Length - m_Pos < N) \ + if (m_Length - m_Pos < (size_t)N) \ { \ return false; \ } @@ -38,7 +38,7 @@ -cParsedNBT::cParsedNBT(const char * a_Data, int a_Length) : +cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) : m_Data(a_Data), m_Length(a_Length), m_Pos(0) @@ -79,14 +79,14 @@ bool cParsedNBT::Parse(void) -bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen) +bool cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringLen) { NEEDBYTES(2); a_StringStart = m_Pos + 2; - a_StringLen = GetBEShort(m_Data + m_Pos); - if (a_StringLen < 0) + a_StringLen = (size_t)GetBEShort(m_Data + m_Pos); + if (a_StringLen > 0xffff) { - // Invalid string length + // Suspicious string length return false; } m_Pos += 2 + a_StringLen; @@ -99,8 +99,10 @@ bool cParsedNBT::ReadString(int & a_StringStart, int & a_StringLen) bool cParsedNBT::ReadCompound(void) { + ASSERT(m_Tags.size() > 0); + // Reads the latest tag as a compound - int ParentIdx = m_Tags.size() - 1; + int ParentIdx = (int)m_Tags.size() - 1; int PrevSibling = -1; for (;;) { @@ -114,13 +116,13 @@ bool cParsedNBT::ReadCompound(void) m_Tags.push_back(cFastNBTTag(TagType, ParentIdx, PrevSibling)); if (PrevSibling >= 0) { - m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1; + m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1; } else { - m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1; + m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1; } - PrevSibling = m_Tags.size() - 1; + PrevSibling = (int)m_Tags.size() - 1; RETURN_FALSE_IF_FALSE(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength)); RETURN_FALSE_IF_FALSE(ReadTag()); } // while (true) @@ -146,20 +148,20 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType) } // Read items: - int ParentIdx = m_Tags.size() - 1; + int ParentIdx = (int)m_Tags.size() - 1; int PrevSibling = -1; for (int i = 0; i < Count; i++) { m_Tags.push_back(cFastNBTTag(a_ChildrenType, ParentIdx, PrevSibling)); if (PrevSibling >= 0) { - m_Tags[PrevSibling].m_NextSibling = m_Tags.size() - 1; + m_Tags[PrevSibling].m_NextSibling = (int)m_Tags.size() - 1; } else { - m_Tags[ParentIdx].m_FirstChild = m_Tags.size() - 1; + m_Tags[ParentIdx].m_FirstChild = (int)m_Tags.size() - 1; } - PrevSibling = m_Tags.size() - 1; + PrevSibling = (int)m_Tags.size() - 1; RETURN_FALSE_IF_FALSE(ReadTag()); } // for (i) m_Tags[ParentIdx].m_LastChild = PrevSibling; @@ -279,7 +281,7 @@ int cParsedNBT::FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLen for (int Child = m_Tags[a_Tag].m_FirstChild; Child != -1; Child = m_Tags[Child].m_NextSibling) { if ( - (m_Tags[Child].m_NameLength == (int)a_NameLength) && + (m_Tags[Child].m_NameLength == a_NameLength) && (memcmp(m_Data + m_Tags[Child].m_NameStart, a_Name, a_NameLength) == 0) ) { @@ -336,7 +338,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) : m_Stack[0].m_Type = TAG_Compound; m_Result.reserve(100 * 1024); m_Result.push_back(TAG_Compound); - WriteString(a_RootTagName.data(), a_RootTagName.size()); + WriteString(a_RootTagName.data(), (UInt16)a_RootTagName.size()); } @@ -345,7 +347,7 @@ cFastNBTWriter::cFastNBTWriter(const AString & a_RootTagName) : void cFastNBTWriter::BeginCompound(const AString & a_Name) { - if (m_CurrentStack >= MAX_STACK) + if (m_CurrentStack >= MAX_STACK - 1) { ASSERT(!"Stack overflow"); return; @@ -376,7 +378,7 @@ void cFastNBTWriter::EndCompound(void) void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType) { - if (m_CurrentStack >= MAX_STACK) + if (m_CurrentStack >= MAX_STACK - 1) { ASSERT(!"Stack overflow"); return; @@ -389,7 +391,7 @@ void cFastNBTWriter::BeginList(const AString & a_Name, eTagType a_ChildrenType) ++m_CurrentStack; m_Stack[m_CurrentStack].m_Type = TAG_List; - m_Stack[m_CurrentStack].m_Pos = m_Result.size() - 4; + m_Stack[m_CurrentStack].m_Pos = (int)m_Result.size() - 4; m_Stack[m_CurrentStack].m_Count = 0; m_Stack[m_CurrentStack].m_ItemType = a_ChildrenType; } @@ -493,7 +495,7 @@ void cFastNBTWriter::AddString(const AString & a_Name, const AString & a_Value) void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements) { TagCommon(a_Name, TAG_ByteArray); - Int32 len = htonl(a_NumElements); + u_long len = htonl((u_long)a_NumElements); m_Result.append((const char *)&len, 4); m_Result.append(a_Value, a_NumElements); } @@ -505,7 +507,7 @@ void cFastNBTWriter::AddByteArray(const AString & a_Name, const char * a_Value, void cFastNBTWriter::AddIntArray(const AString & a_Name, const int * a_Value, size_t a_NumElements) { TagCommon(a_Name, TAG_IntArray); - Int32 len = htonl(a_NumElements); + u_long len = htonl((u_long)a_NumElements); size_t cap = m_Result.capacity(); size_t size = m_Result.length(); if ((cap - size) < (4 + a_NumElements * 4)) @@ -534,7 +536,7 @@ void cFastNBTWriter::Finish(void) -void cFastNBTWriter::WriteString(const char * a_Data, short a_Length) +void cFastNBTWriter::WriteString(const char * a_Data, UInt16 a_Length) { Int16 Len = htons(a_Length); m_Result.append((const char *)&Len, 2); diff --git a/src/WorldStorage/FastNBT.h b/src/WorldStorage/FastNBT.h index 1b8b09c21..fe28005ac 100644 --- a/src/WorldStorage/FastNBT.h +++ b/src/WorldStorage/FastNBT.h @@ -61,10 +61,10 @@ public: // The following members are indices into the data stream. m_DataLength == 0 if no data available // They must not be pointers, because the datastream may be copied into another AString object in the meantime. - int m_NameStart; - int m_NameLength; - int m_DataStart; - int m_DataLength; + size_t m_NameStart; + size_t m_NameLength; + size_t m_DataStart; + size_t m_DataLength; // The following members are indices into the array returned; -1 if not valid // They must not be pointers, because pointers would not survive std::vector reallocation @@ -114,7 +114,7 @@ Each primitive tag also stores the length of the contained data, in bytes. class cParsedNBT { public: - cParsedNBT(const char * a_Data, int a_Length); + cParsedNBT(const char * a_Data, size_t a_Length); bool IsValid(void) const {return m_IsValid; } @@ -122,33 +122,33 @@ public: int GetRoot(void) const {return 0; } /** Returns the first child of the specified tag, or -1 if none / not applicable. */ - int GetFirstChild (int a_Tag) const { return m_Tags[a_Tag].m_FirstChild; } + int GetFirstChild (int a_Tag) const { return m_Tags[(size_t)a_Tag].m_FirstChild; } /** Returns the last child of the specified tag, or -1 if none / not applicable. */ - int GetLastChild (int a_Tag) const { return m_Tags[a_Tag].m_LastChild; } + int GetLastChild (int a_Tag) const { return m_Tags[(size_t)a_Tag].m_LastChild; } /** Returns the next sibling of the specified tag, or -1 if none. */ - int GetNextSibling(int a_Tag) const { return m_Tags[a_Tag].m_NextSibling; } + int GetNextSibling(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_NextSibling; } /** Returns the previous sibling of the specified tag, or -1 if none. */ - int GetPrevSibling(int a_Tag) const { return m_Tags[a_Tag].m_PrevSibling; } + int GetPrevSibling(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_PrevSibling; } /** Returns the length of the tag's data, in bytes. Not valid for Compound or List tags! */ - int GetDataLength (int a_Tag) const + size_t GetDataLength (int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type != TAG_List); - ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound); - return m_Tags[a_Tag].m_DataLength; + ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List); + ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound); + return m_Tags[(size_t)a_Tag].m_DataLength; } /** Returns the data stored in this tag. Not valid for Compound or List tags! */ const char * GetData(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type != TAG_List); - ASSERT(m_Tags[a_Tag].m_Type != TAG_Compound); - return m_Data + m_Tags[a_Tag].m_DataStart; + ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_List); + ASSERT(m_Tags[(size_t)a_Tag].m_Type != TAG_Compound); + return m_Data + m_Tags[(size_t)a_Tag].m_DataStart; } /** Returns the direct child tag of the specified name, or -1 if no such tag. */ @@ -163,47 +163,47 @@ public: /** Returns the child tag of the specified path (Name1\Name2\Name3...), or -1 if no such tag. */ int FindTagByPath(int a_Tag, const AString & a_Path) const; - eTagType GetType(int a_Tag) const { return m_Tags[a_Tag].m_Type; } + eTagType GetType(int a_Tag) const { return m_Tags[(size_t)a_Tag].m_Type; } /** Returns the children type for a List tag; undefined on other tags. If list empty, returns TAG_End. */ eTagType GetChildrenType(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_List); - return (m_Tags[a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[m_Tags[a_Tag].m_FirstChild].m_Type; + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_List); + return (m_Tags[(size_t)a_Tag].m_FirstChild < 0) ? TAG_End : m_Tags[(size_t)m_Tags[(size_t)a_Tag].m_FirstChild].m_Type; } /** Returns the value stored in a Byte tag. Not valid for any other tag type. */ inline unsigned char GetByte(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_Byte); - return (unsigned char)(m_Data[m_Tags[a_Tag].m_DataStart]); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Byte); + return (unsigned char)(m_Data[(size_t)m_Tags[(size_t)a_Tag].m_DataStart]); } /** Returns the value stored in a Short tag. Not valid for any other tag type. */ inline Int16 GetShort(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_Short); - return GetBEShort(m_Data + m_Tags[a_Tag].m_DataStart); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Short); + return GetBEShort(m_Data + m_Tags[(size_t)a_Tag].m_DataStart); } /** Returns the value stored in an Int tag. Not valid for any other tag type. */ inline Int32 GetInt(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_Int); - return GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Int); + return GetBEInt(m_Data + m_Tags[(size_t)a_Tag].m_DataStart); } /** Returns the value stored in a Long tag. Not valid for any other tag type. */ inline Int64 GetLong(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_Long); - return NetworkToHostLong8(m_Data + m_Tags[a_Tag].m_DataStart); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Long); + return NetworkToHostLong8(m_Data + m_Tags[(size_t)a_Tag].m_DataStart); } /** Returns the value stored in a Float tag. Not valid for any other tag type. */ inline float GetFloat(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_Float); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Float); // Cause a compile-time error if sizeof(float) != 4 // If your platform produces a compiler error here, you'll need to add code that manually decodes 32-bit floats @@ -212,7 +212,7 @@ public: UNUSED(Check1); UNUSED(Check2); - Int32 i = GetBEInt(m_Data + m_Tags[a_Tag].m_DataStart); + Int32 i = GetBEInt(m_Data + m_Tags[(size_t)a_Tag].m_DataStart); float f; memcpy(&f, &i, sizeof(f)); return f; @@ -228,16 +228,16 @@ public: UNUSED(Check1); UNUSED(Check2); - ASSERT(m_Tags[a_Tag].m_Type == TAG_Double); - return NetworkToHostDouble8(m_Data + m_Tags[a_Tag].m_DataStart); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_Double); + return NetworkToHostDouble8(m_Data + m_Tags[(size_t)a_Tag].m_DataStart); } /** Returns the value stored in a String tag. Not valid for any other tag type. */ inline AString GetString(int a_Tag) const { - ASSERT(m_Tags[a_Tag].m_Type == TAG_String); + ASSERT(m_Tags[(size_t)a_Tag].m_Type == TAG_String); AString res; - res.assign(m_Data + m_Tags[a_Tag].m_DataStart, m_Tags[a_Tag].m_DataLength); + res.assign(m_Data + m_Tags[(size_t)a_Tag].m_DataStart, (size_t)m_Tags[(size_t)a_Tag].m_DataLength); return res; } @@ -245,21 +245,21 @@ public: inline AString GetName(int a_Tag) const { AString res; - res.assign(m_Data + m_Tags[a_Tag].m_NameStart, m_Tags[a_Tag].m_NameLength); + res.assign(m_Data + m_Tags[(size_t)a_Tag].m_NameStart, (size_t)m_Tags[(size_t)a_Tag].m_NameLength); return res; } protected: const char * m_Data; - int m_Length; + size_t m_Length; std::vector<cFastNBTTag> m_Tags; bool m_IsValid; // True if parsing succeeded // Used while parsing: - int m_Pos; + size_t m_Pos; bool Parse(void); - bool ReadString(int & a_StringStart, int & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors + bool ReadString(size_t & a_StringStart, size_t & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors bool ReadCompound(void); // Reads the latest tag as a compound bool ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType bool ReadTag(void); // Reads the latest tag, depending on its m_Type setting @@ -319,7 +319,7 @@ protected: bool IsStackTopCompound(void) const { return (m_Stack[m_CurrentStack].m_Type == TAG_Compound); } - void WriteString(const char * a_Data, short a_Length); + void WriteString(const char * a_Data, UInt16 a_Length); inline void TagCommon(const AString & a_Name, eTagType a_Type) { @@ -330,7 +330,7 @@ protected: { // Compound: add the type and name: m_Result.push_back((char)a_Type); - WriteString(a_Name.c_str(), (short)a_Name.length()); + WriteString(a_Name.c_str(), (UInt16)a_Name.length()); } else { diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp index 744fc731f..181cfde0d 100644 --- a/src/WorldStorage/FireworksSerializer.cpp +++ b/src/WorldStorage/FireworksSerializer.cpp @@ -96,7 +96,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB if (ExplosionName == "Colors") { // Divide by four as data length returned in bytes - int DataLength = a_NBT.GetDataLength(explosiontag); + size_t DataLength = a_NBT.GetDataLength(explosiontag); // round to the next highest multiple of four DataLength -= DataLength % 4; if (DataLength == 0) @@ -105,14 +105,14 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB } const char * ColourData = (a_NBT.GetData(explosiontag)); - for (int i = 0; i < DataLength; i += 4 /* Size of network int*/) + for (size_t i = 0; i < DataLength; i += 4) { a_FireworkItem.m_Colours.push_back(GetBEInt(ColourData + i)); } } else if (ExplosionName == "FadeColors") { - int DataLength = a_NBT.GetDataLength(explosiontag) / 4; + size_t DataLength = a_NBT.GetDataLength(explosiontag) / 4; // round to the next highest multiple of four DataLength -= DataLength % 4; if (DataLength == 0) @@ -121,7 +121,7 @@ void cFireworkItem::ParseFromNBT(cFireworkItem & a_FireworkItem, const cParsedNB } const char * FadeColourData = (a_NBT.GetData(explosiontag)); - for (int i = 0; i < DataLength; i += 4 /* Size of network int*/) + for (size_t i = 0; i < DataLength; i += 4) { a_FireworkItem.m_FadeColours.push_back(GetBEInt(FadeColourData + i)); } @@ -231,7 +231,7 @@ void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkIte -int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta) +int cFireworkItem::GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta) { /* Colours are supposed to be calculated via: R << 16 + G << 8 + B diff --git a/src/WorldStorage/FireworksSerializer.h b/src/WorldStorage/FireworksSerializer.h index 5b87bafdb..59f1b09b0 100644 --- a/src/WorldStorage/FireworksSerializer.h +++ b/src/WorldStorage/FireworksSerializer.h @@ -81,7 +81,7 @@ public: static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem); /** Returns a colour code for fireworks used by the network code */ - static int GetVanillaColourCodeFromDye(short a_DyeMeta); + static int GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta); bool m_HasFlicker; bool m_HasTrail; @@ -89,4 +89,4 @@ public: short m_FlightTimeInTicks; std::vector<int> m_Colours; std::vector<int> m_FadeColours; -};
\ No newline at end of file +}; diff --git a/src/WorldStorage/MapSerializer.cpp b/src/WorldStorage/MapSerializer.cpp index df72d1cc9..012fc52f3 100644 --- a/src/WorldStorage/MapSerializer.cpp +++ b/src/WorldStorage/MapSerializer.cpp @@ -152,6 +152,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT) if (CurrLine >= 0) { unsigned int Width = a_NBT.GetShort(CurrLine); + if (Width != 128) + { + return false; + } m_Map->m_Width = Width; } @@ -159,6 +163,10 @@ bool cMapSerializer::LoadMapFromNBT(const cParsedNBT & a_NBT) if (CurrLine >= 0) { unsigned int Height = a_NBT.GetShort(CurrLine); + if (Height >= 256) + { + return false; + } m_Map->m_Height = Height; } diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 415693ae2..a3b0d57be 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -28,7 +28,7 @@ #include "../Entities/Boat.h" #include "../Entities/Minecart.h" #include "../Entities/Pickup.h" -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" #include "../Entities/TNTEntity.h" #include "../Entities/ExpOrb.h" #include "../Entities/HangingEntity.h" @@ -39,7 +39,7 @@ #include "../Mobs/Creeper.h" #include "../Mobs/Enderman.h" #include "../Mobs/Horse.h" -#include "../Mobs/Magmacube.h" +#include "../Mobs/MagmaCube.h" #include "../Mobs/Sheep.h" #include "../Mobs/Slime.h" #include "../Mobs/Skeleton.h" @@ -88,23 +88,48 @@ void cNBTChunkSerializer::Finish(void) void cNBTChunkSerializer::AddItem(const cItem & a_Item, int a_Slot, const AString & a_CompoundName) { m_Writer.BeginCompound(a_CompoundName); - m_Writer.AddShort("id", (short)(a_Item.m_ItemType)); - m_Writer.AddShort("Damage", a_Item.m_ItemDamage); - m_Writer.AddByte ("Count", a_Item.m_ItemCount); + m_Writer.AddShort("id", (short)(a_Item.m_ItemType)); + m_Writer.AddShort("Damage", a_Item.m_ItemDamage); + m_Writer.AddByte ("Count", a_Item.m_ItemCount); if (a_Slot >= 0) { m_Writer.AddByte ("Slot", (unsigned char)a_Slot); } - // Write the enchantments: - if (!a_Item.m_Enchantments.IsEmpty() || ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR))) + // Write the tag compound (for enchantment, firework, custom name and repair cost): + if ( + (!a_Item.m_Enchantments.IsEmpty()) || + ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) || + (a_Item.m_RepairCost > 0) || + (a_Item.m_CustomName != "") || + (a_Item.m_Lore != "") + ) { m_Writer.BeginCompound("tag"); + if (a_Item.m_RepairCost > 0) + { + m_Writer.AddInt("RepairCost", a_Item.m_RepairCost); + } + + if ((a_Item.m_CustomName != "") || (a_Item.m_Lore != "")) + { + m_Writer.BeginCompound("display"); + if (a_Item.m_CustomName != "") + { + m_Writer.AddString("Name", a_Item.m_CustomName); + } + if (a_Item.m_Lore != "") + { + m_Writer.AddString("Lore", a_Item.m_Lore); + } + m_Writer.EndCompound(); + } + if ((a_Item.m_ItemType == E_ITEM_FIREWORK_ROCKET) || (a_Item.m_ItemType == E_ITEM_FIREWORK_STAR)) { cFireworkItem::WriteToNBTCompound(a_Item.m_FireworkItem, m_Writer, (ENUM_ITEM_ID)a_Item.m_ItemType); } - + if (!a_Item.m_Enchantments.IsEmpty()) { const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; @@ -366,38 +391,41 @@ void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock) void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart) { - const char * EntityClass = NULL; - switch (a_Minecart->GetPayload()) - { - case cMinecart::mpNone: EntityClass = "MinecartRideable"; break; - case cMinecart::mpChest: EntityClass = "MinecartChest"; break; - case cMinecart::mpFurnace: EntityClass = "MinecartFurnace"; break; - case cMinecart::mpTNT: EntityClass = "MinecartTNT"; break; - case cMinecart::mpHopper: EntityClass = "MinecartHopper"; break; - default: - { - ASSERT(!"Unhandled minecart payload type"); - return; - } - } // switch (payload) - m_Writer.BeginCompound(""); - AddBasicEntity(a_Minecart, EntityClass); + switch (a_Minecart->GetPayload()) { case cMinecart::mpChest: { + AddBasicEntity(a_Minecart, "MinecartChest"); // Add chest contents into the Items tag: AddMinecartChestContents((cMinecartWithChest *)a_Minecart); break; } - case cMinecart::mpFurnace: { + AddBasicEntity(a_Minecart, "MinecartFurnace"); // TODO: Add "Push" and "Fuel" tags break; } + case cMinecart::mpHopper: + { + AddBasicEntity(a_Minecart, "MinecartHopper"); + // TODO: Add hopper contents? + break; + } + case cMinecart::mpTNT: + { + AddBasicEntity(a_Minecart, "MinecartTNT"); + break; + } + case cMinecart::mpNone: + { + AddBasicEntity(a_Minecart, "MinecartRideable"); + break; + } } // switch (Payload) + m_Writer.EndCompound(); } @@ -490,7 +518,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) } case cMonster::mtMagmaCube: { - m_Writer.AddByte("Size", ((const cMagmaCube *)a_Monster)->GetSize()); + m_Writer.AddInt("Size", ((const cMagmaCube *)a_Monster)->GetSize()); break; } case cMonster::mtSheep: @@ -516,7 +544,7 @@ void cNBTChunkSerializer::AddMonsterEntity(cMonster * a_Monster) } case cMonster::mtWither: { - m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetNumInvulnerableTicks()); + m_Writer.AddInt("Invul", ((const cWither *)a_Monster)->GetWitherInvulnerableTicks()); break; } case cMonster::mtWolf: @@ -621,10 +649,17 @@ void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging) m_Writer.AddInt("TileZ", a_Hanging->GetTileZ()); switch (a_Hanging->GetDirection()) { - case 0: m_Writer.AddByte("Dir", (unsigned char)2); break; - case 1: m_Writer.AddByte("Dir", (unsigned char)1); break; - case 2: m_Writer.AddByte("Dir", (unsigned char)0); break; - case 3: m_Writer.AddByte("Dir", (unsigned char)3); break; + case BLOCK_FACE_YM: m_Writer.AddByte("Dir", (unsigned char)2); break; + case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break; + case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break; + case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break; + + case BLOCK_FACE_XM: + case BLOCK_FACE_XP: + case BLOCK_FACE_NONE: + { + break; + } } } @@ -692,10 +727,9 @@ void cNBTChunkSerializer::AddMinecartChestContents(cMinecartWithChest * a_Mineca -bool cNBTChunkSerializer::LightIsValid(bool a_IsLightValid) +void cNBTChunkSerializer::LightIsValid(bool a_IsLightValid) { m_IsLightValid = a_IsLightValid; - return a_IsLightValid; // We want lighting only if it's valid, otherwise don't bother } diff --git a/src/WorldStorage/NBTChunkSerializer.h b/src/WorldStorage/NBTChunkSerializer.h index 51d104970..112afc27e 100644 --- a/src/WorldStorage/NBTChunkSerializer.h +++ b/src/WorldStorage/NBTChunkSerializer.h @@ -9,7 +9,7 @@ #pragma once -#include "../ChunkDef.h" +#include "ChunkDataCallback.h" @@ -121,7 +121,7 @@ protected: void AddMinecartChestContents(cMinecartWithChest * a_Minecart); // cChunkDataSeparateCollector overrides: - virtual bool LightIsValid(bool a_IsLightValid) override; + virtual void LightIsValid(bool a_IsLightValid) override; virtual void BiomeData(const cChunkDef::BiomeMap * a_BiomeMap) override; virtual void Entity(cEntity * a_Entity) override; virtual void BlockEntity(cBlockEntity * a_Entity) override; diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp index d8531d965..1cf99efd9 100644 --- a/src/WorldStorage/SchematicFileSerializer.cpp +++ b/src/WorldStorage/SchematicFileSerializer.cpp @@ -14,6 +14,39 @@ +#ifdef SELF_TEST + +static class cSchematicStringSelfTest +{ +public: + cSchematicStringSelfTest(void) + { + cBlockArea ba; + ba.Create(21, 256, 21); + ba.RelLine(0, 0, 0, 9, 8, 7, cBlockArea::baTypes | cBlockArea::baMetas, E_BLOCK_WOODEN_STAIRS, 1); + AString Schematic; + if (!cSchematicFileSerializer::SaveToSchematicString(ba, Schematic)) + { + assert_test(!"Schematic failed to save!"); + } + cBlockArea ba2; + if (!cSchematicFileSerializer::LoadFromSchematicString(ba2, Schematic)) + { + assert_test(!"Schematic failed to load!"); + } + } +} g_SelfTest; + +#endif + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cSchematicFileSerializer: + bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName) { // Un-GZip the contents: @@ -159,7 +192,7 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP int SizeX = a_NBT.GetShort(TSizeX); int SizeY = a_NBT.GetShort(TSizeY); int SizeZ = a_NBT.GetShort(TSizeZ); - if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1)) + if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > 256) || (SizeZ < 1) || (SizeZ > 65535)) { LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ); return false; @@ -197,11 +230,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP } // Copy the block types and metas: - int NumBytes = a_BlockArea.GetBlockCount(); + size_t NumBytes = a_BlockArea.GetBlockCount(); if (a_NBT.GetDataLength(TBlockTypes) < NumBytes) { LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.", - NumBytes, a_NBT.GetDataLength(TBlockTypes) + (int)NumBytes, (int)a_NBT.GetDataLength(TBlockTypes) ); NumBytes = a_NBT.GetDataLength(TBlockTypes); } @@ -209,11 +242,11 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP if (AreMetasPresent) { - int NumBytes = a_BlockArea.GetBlockCount(); + size_t NumBytes = a_BlockArea.GetBlockCount(); if (a_NBT.GetDataLength(TBlockMetas) < NumBytes) { LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.", - NumBytes, a_NBT.GetDataLength(TBlockMetas) + (int)NumBytes, (int)a_NBT.GetDataLength(TBlockMetas) ); NumBytes = a_NBT.GetDataLength(TBlockMetas); } diff --git a/src/WorldStorage/StatSerializer.cpp b/src/WorldStorage/StatSerializer.cpp new file mode 100644 index 000000000..74113941c --- /dev/null +++ b/src/WorldStorage/StatSerializer.cpp @@ -0,0 +1,146 @@ + +// StatSerializer.cpp + + +#include "Globals.h" +#include "StatSerializer.h" + +#include "../Statistics.h" + + + + + +cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager) + : m_Manager(a_Manager) +{ + // Even though stats are shared between worlds, they are (usually) saved + // inside the folder of the default world. + + AString StatsPath; + Printf(StatsPath, "%s/stats", a_WorldName.c_str()); + + m_Path = StatsPath + "/" + a_PlayerName + ".json"; + + // Ensure that the directory exists. + cFile::CreateFolder(FILE_IO_PREFIX + StatsPath); +} + + + + + +bool cStatSerializer::Load(void) +{ + AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path); + if (Data.empty()) + { + return false; + } + + Json::Value Root; + Json::Reader Reader; + + if (Reader.parse(Data, Root, false)) + { + return LoadStatFromJSON(Root); + } + + return false; +} + + + + + +bool cStatSerializer::Save(void) +{ + Json::Value Root; + SaveStatToJSON(Root); + + cFile File; + if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite)) + { + return false; + } + + Json::StyledWriter Writer; + AString JsonData = Writer.write(Root); + + File.Write(JsonData.data(), JsonData.size()); + File.Close(); + + return true; +} + + + + + +void cStatSerializer::SaveStatToJSON(Json::Value & a_Out) +{ + for (unsigned int i = 0; i < (unsigned int)statCount; ++i) + { + StatValue Value = m_Manager->GetValue((eStatistic) i); + + if (Value != 0) + { + const AString & StatName = cStatInfo::GetName((eStatistic) i); + + a_Out[StatName] = Value; + } + + // TODO 2014-05-11 xdot: Save "progress" + } +} + + + + + +bool cStatSerializer::LoadStatFromJSON(const Json::Value & a_In) +{ + m_Manager->Reset(); + + for (Json::ValueIterator it = a_In.begin() ; it != a_In.end() ; ++it) + { + AString StatName = it.key().asString(); + + eStatistic StatType = cStatInfo::GetType(StatName); + + if (StatType == statInvalid) + { + LOGWARNING("Invalid statistic type \"%s\"", StatName.c_str()); + continue; + } + + Json::Value & Node = *it; + + if (Node.isInt()) + { + m_Manager->SetValue(StatType, Node.asInt()); + } + else if (Node.isObject()) + { + StatValue Value = Node.get("value", 0).asInt(); + + // TODO 2014-05-11 xdot: Load "progress" + + m_Manager->SetValue(StatType, Value); + } + else + { + LOGWARNING("Invalid statistic value for type \"%s\"", StatName.c_str()); + } + } + + return true; +} + + + + + + + + diff --git a/src/WorldStorage/StatSerializer.h b/src/WorldStorage/StatSerializer.h new file mode 100644 index 000000000..72f8d74f1 --- /dev/null +++ b/src/WorldStorage/StatSerializer.h @@ -0,0 +1,55 @@ + +// StatSerializer.h + +// Declares the cStatSerializer class that is used for saving stats into JSON + + + + + +#pragma once + +#include "json/json.h" + + + + + +// fwd: +class cStatManager; + + + + +class cStatSerializer +{ +public: + + cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager); + + /* Try to load the player statistics. Returns whether the operation was successful or not. */ + bool Load(void); + + /* Try to save the player statistics. Returns whether the operation was successful or not. */ + bool Save(void); + + +protected: + + void SaveStatToJSON(Json::Value & a_Out); + + bool LoadStatFromJSON(const Json::Value & a_In); + + +private: + + cStatManager* m_Manager; + + AString m_Path; + + +} ; + + + + diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 48934d074..d310c9124 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -27,7 +27,6 @@ #include "../BlockEntities/MobHeadEntity.h" #include "../BlockEntities/FlowerPotEntity.h" - #include "../Mobs/Monster.h" #include "../Mobs/IncludeAllMonsters.h" @@ -36,7 +35,12 @@ #include "../Entities/FallingBlock.h" #include "../Entities/Minecart.h" #include "../Entities/Pickup.h" -#include "../Entities/ProjectileEntity.h" +#include "../Entities/ArrowEntity.h" +#include "../Entities/ThrownEggEntity.h" +#include "../Entities/ThrownEnderPearlEntity.h" +#include "../Entities/ThrownSnowballEntity.h" +#include "../Entities/FireChargeEntity.h" +#include "../Entities/GhastFireballEntity.h" #include "../Entities/TNTEntity.h" #include "../Entities/ExpOrb.h" #include "../Entities/HangingEntity.h" @@ -92,7 +96,7 @@ cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) : gzFile gz = gzopen((FILE_IO_PREFIX + fnam).c_str(), "wb"); if (gz != NULL) { - gzwrite(gz, Writer.GetResult().data(), Writer.GetResult().size()); + gzwrite(gz, Writer.GetResult().data(), (unsigned)Writer.GetResult().size()); } gzclose(gz); } @@ -248,7 +252,7 @@ bool cWSSAnvil::LoadChunkFromData(const cChunkCoords & a_Chunk, const AString & strm.next_out = (Bytef *)Uncompressed; strm.avail_out = sizeof(Uncompressed); strm.next_in = (Bytef *)a_Data.data(); - strm.avail_in = a_Data.size(); + strm.avail_in = (uInt)a_Data.size(); int res = inflate(&strm, Z_FINISH); inflateEnd(&strm); if (res != Z_STREAM_END) @@ -401,7 +405,7 @@ bool cWSSAnvil::LoadChunkFromNBT(const cChunkCoords & a_Chunk, const cParsedNBT -void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length) +void cWSSAnvil::CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length) { int Child = a_NBT.FindChildByName(a_Tag, a_ChildName); if ((Child >= 0) && (a_NBT.GetType(Child) == TAG_ByteArray) && (a_NBT.GetDataLength(Child) == a_Length)) @@ -436,8 +440,8 @@ bool cWSSAnvil::SaveChunkToNBT(const cChunkCoords & a_Chunk, cFastNBTWriter & a_ // Save blockdata: a_Writer.BeginList("Sections", TAG_Compound); - int SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16; - int SliceSizeNibble = SliceSizeBlock / 2; + size_t SliceSizeBlock = cChunkDef::Width * cChunkDef::Width * 16; + size_t SliceSizeNibble = SliceSizeBlock / 2; const char * BlockTypes = (const char *)(Serializer.m_BlockTypes); const char * BlockMetas = (const char *)(Serializer.m_BlockMetas); #ifdef DEBUG_SKYLIGHT @@ -641,18 +645,16 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ } int Damage = a_NBT.FindChildByName(a_TagIdx, "Damage"); - if ((Damage < 0) || (a_NBT.GetType(Damage) != TAG_Short)) + if ((Damage > 0) && (a_NBT.GetType(Damage) == TAG_Short)) { - return false; + a_Item.m_ItemDamage = a_NBT.GetShort(Damage); } - a_Item.m_ItemDamage = a_NBT.GetShort(Damage); int Count = a_NBT.FindChildByName(a_TagIdx, "Count"); - if ((Count < 0) || (a_NBT.GetType(Count) != TAG_Byte)) + if ((Count > 0) && (a_NBT.GetType(Count) == TAG_Byte)) { - return false; + a_Item.m_ItemCount = a_NBT.GetByte(Count); } - a_Item.m_ItemCount = a_NBT.GetByte(Count); // Find the "tag" tag, used for enchantments and other extra data int TagTag = a_NBT.FindChildByName(a_TagIdx, "tag"); @@ -662,6 +664,29 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ return true; } + // Load repair cost: + int RepairCost = a_NBT.FindChildByName(TagTag, "RepairCost"); + if ((RepairCost > 0) && (a_NBT.GetType(RepairCost) == TAG_Int)) + { + a_Item.m_RepairCost = a_NBT.GetInt(RepairCost); + } + + // Load display name: + int DisplayTag = a_NBT.FindChildByName(TagTag, "display"); + if (DisplayTag > 0) + { + int DisplayName = a_NBT.FindChildByName(DisplayTag, "Name"); + if ((DisplayName > 0) && (a_NBT.GetType(DisplayName) == TAG_String)) + { + a_Item.m_CustomName = a_NBT.GetString(DisplayName); + } + int Lore = a_NBT.FindChildByName(DisplayTag, "Lore"); + if ((Lore > 0) && (a_NBT.GetType(Lore) == TAG_String)) + { + a_Item.m_Lore = a_NBT.GetString(Lore); + } + } + // Load enchantments: const char * EnchName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench"; int EnchTag = a_NBT.FindChildByName(TagTag, EnchName); @@ -670,6 +695,7 @@ bool cWSSAnvil::LoadItemFromNBT(cItem & a_Item, const cParsedNBT & a_NBT, int a_ EnchantmentSerializer::ParseFromNBT(a_Item.m_Enchantments, a_NBT, EnchTag); } + // Load firework data: int FireworksTag = a_NBT.FindChildByName(TagTag, ((a_Item.m_ItemType == E_ITEM_FIREWORK_STAR) ? "Fireworks" : "Explosion")); if (EnchTag > 0) { @@ -1052,7 +1078,7 @@ void cWSSAnvil::LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, cons -void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength) +void cWSSAnvil::LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength) { if (strncmp(a_IDTag, "Boat", a_IDTagLength) == 0) { @@ -1757,7 +1783,7 @@ void cWSSAnvil::LoadBlazeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ void cWSSAnvil::LoadCaveSpiderFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx) { - std::auto_ptr<cCavespider> Monster(new cCavespider()); + std::auto_ptr<cCaveSpider> Monster(new cCaveSpider()); if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx)) { return; @@ -1970,7 +1996,10 @@ void cWSSAnvil::LoadMagmaCubeFromNBT(cEntityList & a_Entities, const cParsedNBT { int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size"); - if (SizeIdx < 0) { return; } + if (SizeIdx < 0) + { + return; + } int Size = a_NBT.GetInt(SizeIdx); @@ -2128,7 +2157,10 @@ void cWSSAnvil::LoadSlimeFromNBT(cEntityList & a_Entities, const cParsedNBT & a_ { int SizeIdx = a_NBT.FindChildByName(a_TagIdx, "Size"); - if (SizeIdx < 0) { return; } + if (SizeIdx < 0) + { + return; + } int Size = a_NBT.GetInt(SizeIdx); @@ -2272,7 +2304,7 @@ void cWSSAnvil::LoadWitherFromNBT(cEntityList & a_Entities, const cParsedNBT & a int CurrLine = a_NBT.FindChildByName(a_TagIdx, "Invul"); if (CurrLine > 0) { - Monster->SetNumInvulnerableTicks(a_NBT.GetInt(CurrLine)); + Monster->SetWitherInvulnerableTicks(a_NBT.GetInt(CurrLine)); } a_Entities.push_back(Monster.release()); @@ -2598,14 +2630,14 @@ bool cWSSAnvil::cMCAFile::GetChunkData(const cChunkCoords & a_Chunk, AString & a unsigned ChunkLocation = ntohl(m_Header[LocalX + 32 * LocalZ]); unsigned ChunkOffset = ChunkLocation >> 8; - m_File.Seek(ChunkOffset * 4096); + m_File.Seek((int)ChunkOffset * 4096); int ChunkSize = 0; if (m_File.Read(&ChunkSize, 4) != 4) { return false; } - ChunkSize = ntohl(ChunkSize); + ChunkSize = ntohl((u_long)ChunkSize); char CompressionType = 0; if (m_File.Read(&CompressionType, 1) != 1) { @@ -2650,7 +2682,7 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri // Store the chunk data: m_File.Seek(ChunkSector * 4096); - unsigned ChunkSize = htonl(a_Data.size() + 1); + u_long ChunkSize = htonl((u_long)a_Data.size() + 1); if (m_File.Write(&ChunkSize, 4) != 4) { LOGWARNING("Cannot save chunk [%d, %d], writing(1) data to file \"%s\" failed", a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ, GetFileName().c_str()); @@ -2668,8 +2700,13 @@ bool cWSSAnvil::cMCAFile::SetChunkData(const cChunkCoords & a_Chunk, const AStri return false; } + // Add padding to 4K boundary: + size_t BytesWritten = a_Data.size() + MCA_CHUNK_HEADER_LENGTH; + static const char Padding[4095] = {0}; + m_File.Write(Padding, 4096 - (BytesWritten % 4096)); + // Store the header: - ChunkSize = (a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number + ChunkSize = ((u_long)a_Data.size() + MCA_CHUNK_HEADER_LENGTH + 4095) / 4096; // Round data size *up* to nearest 4KB sector, make it a sector number ASSERT(ChunkSize < 256); m_Header[LocalX + 32 * LocalZ] = htonl((ChunkSector << 8) | ChunkSize); if (m_File.Seek(0) < 0) diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h index 1773ee882..7542a828a 100644 --- a/src/WorldStorage/WSSAnvil.h +++ b/src/WorldStorage/WSSAnvil.h @@ -145,7 +145,7 @@ protected: void LoadMobHeadFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadCommandBlockFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); - void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, int a_IDTagLength); + void LoadEntityFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_EntityTagIdx, const char * a_IDTag, size_t a_IDTagLength); void LoadBoatFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadEnderCrystalFromNBT (cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx); @@ -221,7 +221,7 @@ protected: cMCAFile * LoadMCAFile(const cChunkCoords & a_Chunk); /// Copies a_Length bytes of data from the specified NBT Tag's Child into the a_Destination buffer - void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, int a_Length); + void CopyNBTData(const cParsedNBT & a_NBT, int a_Tag, const AString & a_ChildName, char * a_Destination, size_t a_Length); // cWSSchema overrides: virtual bool LoadChunk(const cChunkCoords & a_Chunk) override; diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index bb9d4b9e6..7a113849a 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -107,15 +107,13 @@ void cJsonChunkSerializer::BlockEntity(cBlockEntity * a_BlockEntity) -bool cJsonChunkSerializer::LightIsValid(bool a_IsLightValid) +void cJsonChunkSerializer::LightIsValid(bool a_IsLightValid) { - if (!a_IsLightValid) + if (a_IsLightValid) { - return false; + m_Root["IsLightValid"] = true; + m_HasJsonData = true; } - m_Root["IsLightValid"] = true; - m_HasJsonData = true; - return true; } @@ -468,7 +466,15 @@ cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_ for (int i = 0; i < NumChunks; i++) { sChunkHeader * Header = new sChunkHeader; - READ(*Header); + + // Here we do not use the READ macro, as it does not free the resources + // allocated with new in case of error. + if (f.Read(Header, sizeof(*Header)) != sizeof(*Header)) + { + LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", "Header", m_FileName.c_str(), __LINE__, f.Tell()); + delete Header; + return; + } m_ChunkHeaders.push_back(Header); } // for i - chunk headers @@ -593,7 +599,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() // Decompress the data: AString UncompressedData; { - int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize); + int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize); if (errorcode != Z_OK) { LOGERROR("Error %d decompressing data for chunk [%d, %d]", @@ -673,7 +679,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() // Re-compress data AString CompressedData; { - int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor); + int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor); if (errorcode != Z_OK) { LOGERROR("Error %d compressing data for chunk [%d, %d]", @@ -685,9 +691,9 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2() } // Save into file's cache - Header->m_UncompressedSize = Converted.size(); - Header->m_CompressedSize = CompressedData.size(); - NewDataContents.append( CompressedData ); + Header->m_UncompressedSize = (int)Converted.size(); + Header->m_CompressedSize = (int)CompressedData.size(); + NewDataContents.append(CompressedData); } // Done converting @@ -723,7 +729,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() Offset += Header->m_CompressedSize; // Crude data integrity check: - const 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", @@ -737,7 +743,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() // Decompress the data: AString UncompressedData; { - int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, UncompressedSize); + int errorcode = UncompressString(Data.data(), Data.size(), UncompressedData, (size_t)UncompressedSize); if (errorcode != Z_OK) { LOGERROR("Error %d decompressing data for chunk [%d, %d]", @@ -797,7 +803,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() ++index2; } InChunkOffset += index2 / 2; - index2 = 0; AString Converted(ConvertedData, ExpectedSize); @@ -822,9 +827,9 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() } // Save into file's cache - Header->m_UncompressedSize = Converted.size(); - Header->m_CompressedSize = CompressedData.size(); - NewDataContents.append( CompressedData ); + Header->m_UncompressedSize = (int)Converted.size(); + Header->m_CompressedSize = (int)CompressedData.size(); + NewDataContents.append(CompressedData); } // Done converting @@ -839,7 +844,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() -bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World) +bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World) { // Crude data integrity check: if (a_UncompressedSize < cChunkDef::BlockDataSize) @@ -854,7 +859,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp // Decompress the data: AString UncompressedData; - int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, a_UncompressedSize); + int errorcode = UncompressString(a_Data.data(), a_Data.size(), UncompressedData, (size_t)a_UncompressedSize); if (errorcode != Z_OK) { LOGERROR("Error %d decompressing data for chunk [%d, %d]", @@ -866,7 +871,7 @@ bool cWSSCompact::LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_Uncomp if (a_UncompressedSize != (int)UncompressedData.size()) { - LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", + LOGWARNING("Uncompressed data size differs (exp %d bytes, got " SIZE_T_FMT ") for chunk [%d, %d]", a_UncompressedSize, UncompressedData.size(), a_Chunk.m_ChunkX, a_Chunk.m_ChunkZ ); diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h index 4df146ec3..b148005f6 100644 --- a/src/WorldStorage/WSSCompact.h +++ b/src/WorldStorage/WSSCompact.h @@ -14,6 +14,7 @@ #include "WorldStorage.h" #include "../Vector3.h" #include "json/json.h" +#include "ChunkDataCallback.h" @@ -21,7 +22,7 @@ /// Helper class for serializing a chunk into Json class cJsonChunkSerializer : - public cChunkDataCollector + public cChunkDataArrayCollector { public: @@ -42,7 +43,7 @@ protected: // cChunkDataCollector overrides: virtual void Entity (cEntity * a_Entity) override; virtual void BlockEntity (cBlockEntity * a_Entity) override; - virtual bool LightIsValid (bool a_IsLightValid) override; + virtual void LightIsValid (bool a_IsLightValid) override; } ; @@ -135,7 +136,7 @@ protected: bool EraseChunkData(const cChunkCoords & a_Chunk); /// Loads the chunk from the data (no locking needed) - bool LoadChunkFromData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, const AString & a_Data, cWorld * a_World); + bool LoadChunkFromData(const cChunkCoords & a_Chunk, int a_UncompressedSize, const AString & a_Data, cWorld * a_World); void LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_Entities, cBlockEntityList & a_BlockEntities, cWorld * a_World); diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp index 711c8612f..6867ad5bc 100644 --- a/src/WorldStorage/WorldStorage.cpp +++ b/src/WorldStorage/WorldStorage.cpp @@ -150,7 +150,7 @@ size_t cWorldStorage::GetSaveQueueLength(void) void cWorldStorage::QueueLoadChunk(int a_ChunkX, int a_ChunkY, int a_ChunkZ, bool a_Generate) { - m_LoadQueue.EnqueueItemIfNotPresent(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); + m_LoadQueue.EnqueueItem(sChunkLoad(a_ChunkX, a_ChunkY, a_ChunkZ, a_Generate)); m_Event.Set(); } @@ -243,7 +243,6 @@ void cWorldStorage::Execute(void) bool Success; do { - Success = false; if (m_ShouldTerminate) { return; diff --git a/src/main.cpp b/src/main.cpp index 68eea7f4d..6925d9ff1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -61,7 +61,7 @@ void NonCtrlHandler(int a_Signal) std::signal(SIGSEGV, SIG_DFL); LOGERROR(" D: | MCServer has encountered an error and needs to close"); LOGERROR("Details | SIGSEGV: Segmentation fault"); - exit(EXIT_FAILURE); + abort(); } case SIGABRT: #ifdef SIGABRT_COMPAT @@ -71,7 +71,7 @@ void NonCtrlHandler(int a_Signal) std::signal(a_Signal, SIG_DFL); LOGERROR(" D: | MCServer has encountered an error and needs to close"); LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault"); - exit(EXIT_FAILURE); + abort(); } case SIGINT: case SIGTERM: |