diff options
156 files changed, 9281 insertions, 3448 deletions
diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 233bdbc46..1423d64bc 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -699,7 +699,7 @@ end</pre> GetLevel = { Params = "EnchantmentNumID", Return = "number", Notes = "Returns the level of the specified enchantment stored in this object; 0 if not stored" }, IsEmpty = { Params = "", Return = "bool", Notes = "Returns true if the object stores no enchantments" }, SetLevel = { Params = "EnchantmentNumID, Level", Return = "", Notes = "Sets the level for the specified enchantment, adding it if not stored before or removing it if level < = 0" }, - StringToEnchantmentID = { Params = "EnchantmentTextID", Return = "number", Notes = "(static) Returns the enchantment numerical ID, -1 if not understood. Case insensitive" }, + StringToEnchantmentID = { Params = "EnchantmentTextID", Return = "number", Notes = "(static) Returns the enchantment numerical ID, -1 if not understood. Case insensitive. Also understands plain numbers." }, ToString = { Params = "", Return = "string", Notes = "Returns the string description of all the enchantments stored in this object, in numerical-ID form" }, }, Constants = @@ -2929,9 +2929,10 @@ end { -- No sorting is provided for these, they will be output in the same order as defined here { FileName = "Writing-a-MCServer-plugin.html", Title = "Writing a MCServer plugin" }, - { FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" }, - { FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" }, - { FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" }, + { FileName = "SettingUpDecoda.html", Title = "Setting up the Decoda Lua IDE" }, + { FileName = "SettingUpZeroBrane.html", Title = "Setting up the ZeroBrane Studio Lua IDE" }, + { FileName = "UsingChunkStays.html", Title = "Using ChunkStays" }, + { FileName = "WebWorldThreads.html", Title = "Webserver vs World threads" }, } } ; diff --git a/MCServer/Plugins/APIDump/UsingChunkStays.html b/MCServer/Plugins/APIDump/UsingChunkStays.html new file mode 100644 index 000000000..d3ecc6674 --- /dev/null +++ b/MCServer/Plugins/APIDump/UsingChunkStays.html @@ -0,0 +1,167 @@ +<!DOCTYPE html> +<html> + <head> + <title>MCServer - Using ChunkStays</title> + <link rel="stylesheet" type="text/css" href="main.css" /> + <link rel="stylesheet" type="text/css" href="prettify.css" /> + <script src="prettify.js"></script> + <script src="lang-lua.js"></script> + <meta charset="UTF-8"> + </head> + <body> + <div id="content"> + <h1>Using ChunkStays</h1> + <p> + A plugin may need to manipulate data in arbitrary chunks, and it needs a way to make the server + guarantee that the chunks are available in memory.</p> + + <h2>The problem</h2> + <p> + Usually when plugins want to manipulate larger areas of world data, they need to make sure that the + server has the appropriate chunks loaded in the memory. When the data being manipulated can be further + away from the connected players, or the data is being manipulated from a console handler, there is a + real chance that the chunks are not loaded.</p> + <p> + This gets even more important when using the <a href="cBlockArea.html">cBlockArea</a> class for reading + and writing. Those functions will fail when any of the required chunks aren't valid. This means that + either the block area has incomplete data (Read() failed) or incomplete data has been written to the + world (Write() failed). Recovery from this is near impossible - you can't simply read or write again + later, because the world may have changed in the meantime.</p> + + <h2>The solution</h2> + <p> + The naive solution would be to monitor chunk loads and unloads, and postpone the operations until all + the chunks are available. This would be quite ineffective and also very soon it would become very + difficult to maintain, if there were multiple code paths requiring this handling.</p> + <p> + An alternate approach has been implemented, accessible through a single (somewhat hidden) function + call: <a href="cWorld.html">cWorld:ChunkStay()</a>. All that this call basically does is, it tells the + server "Load these chunks for me, and call this callback function once you have them all." And the + server does exactly that - it remembers the callback and asks the world loader / generator to provide + the chunks. Once the chunks become available, it calls the callback function for the plugin.</p> + <p> + There are a few gotcha-s, though. If the code that was requesting the read or write had access to some + of the volatile objects, such as <a href="cPlayer.html">cPlayer</a> or + <a href="cEntity.html">cEntity</a> objects, those cannot be accessed by the callback anymore, because + they may have become invalid in the meantime - the player may have disconnected, the entity may have + despawned. So the callback must use the longer way to access such objects, such as calling + <a href="cWorld.html">cWorld:DoWithEntityByID()</a> or + <a href="cWorld.html">cWorld:DoWithPlayer()</a>.</p> + + <h2>The example</h2> + <p> + As a simple example, consider a theoretical plugin that allows a player to save the immediate + surroundings of the spawn into a schematic file. The player issues a command to initiate the save, and + the plugin reads a 50 x 50 x 50 block area around the spawn into a cBlockArea and saves it on the disk + as "<PlayerName>_spawn.schematic". When it's done with the saving, it wants to send a message to the + player to let them know the command has succeeded.</p> + <p> + The first attempt shows the naive approach. It simply reads the block area and saves it, then sends the + message. I'll repeat once more, this code is <b>the wrong way</b> to do it!</p> +<pre class="prettyprint lang-lua"> +function HandleCommandSaveSpawn(a_Split, a_Player) + -- Get the coords for the spawn: + local SpawnX = a_Player:GetWorld():GetSpawnX() + local SpawnY = a_Player:GetWorld():GetSpawnY() + local SpawnZ = a_Player:GetWorld():GetSpawnZ() + local Bounds = cCuboid(SpawnX - 25, SpawnY - 25, SpawnZ - 25, SpawnX + 25, SpawnY + 25, SpawnZ + 25) + Bounds:ClampY(0, 255) + + -- Read the area around spawn into a cBlockArea, save to file: + local Area = cBlockArea() + local FileName = a_Player:GetName() .. "_spawn.schematic" + Area:Read(a_Player:GetWorld(), Bounds, cBlockArea.baTypes + cBlockArea.baMetas) + Area:SaveToSchematicFile(FileName) + + -- Notify the player: + a_Player:SendMessage(cCompositeChat("The spawn has been saved", mtInfo)) + return true +end +</pre> + <p> + Now if the player goes exploring far and uses the command to save their spawn, the chunks aren't + loaded, so the BlockArea reading fails, the BlockArea contains bad data. Note that the plugin fails to + do any error checking and if the area isn't read from the world, it happily saves the incomplete data + and says "hey, everything's right", althought it has just trashed any previous backup of the spawn + schematic with nonsense data.</p> + <hr/> + <p> + The following script uses the ChunkStay method to alleviate chunk-related problems. This is <b>the + right way</b> of doing it:</p> +<pre class="prettyprint lang-lua"> +function HandleCommandSaveSpawn(a_Split, a_Player) + -- Get the coords for the spawn: + local SpawnX = a_Player:GetWorld():GetSpawnX() + local SpawnY = a_Player:GetWorld():GetSpawnY() + local SpawnZ = a_Player:GetWorld():GetSpawnZ() + local Bounds = cCuboid(SpawnX - 25, SpawnY - 25, SpawnZ - 25, SpawnX + 25, SpawnY + 25, SpawnZ + 25) + Bounds:ClampY(0, 255) + + -- Get a list of chunks that we need loaded: + local MinChunkX = math.floor((SpawnX - 25) / 16) + local MaxChunkX = math.ceil ((SpawnX + 25) / 16) + local MinChunkZ = math.floor((SpawnZ - 25) / 16) + local MaxChunkZ = math.ceil ((SpawnZ + 25) / 16) + local Chunks = {} + for x = MinChunkX, MaxChunkX do + for z = MinChunkZ, MaxChunkZ do + table.insert(Chunks, {x, z}) + end + end -- for x + + -- Store the player's name and world to use in the callback, because the a_Player object may no longer be valid: + local PlayerName = a_Player:GetName() + local World = a_Player:GetWorld() + + -- This is the callback that is executed once all the chunks are loaded: + local OnAllChunksAvailable = function() + -- Read the area around spawn into a cBlockArea, save to file: + local Area = cBlockArea() + local FileName = PlayerName .. "_spawn.schematic" + if (Area:Read(World, Bounds, cBlockArea.baTypes + cBlockArea.baMetas)) then + Area:SaveToSchematicFile(FileName) + Msg = cCompositeChat("The spawn has been saved", mtInfo) + else + Msg = cCompositeChat("Cannot save the spawn", mtFailure) + end + + -- Notify the player: + -- Note that we cannot use a_Player here, because it may no longer be valid (if the player disconnected before the command completes) + World:DoWithPlayer(PlayerName, + function (a_CBPlayer) + a_CBPlayer:SendMessage(Msg) + end + ) + end + + -- Ask the server to load our chunks and notify us once it's done: + World:ChunkStay(Chunks, nil, OnAllChunksAvailable) + + -- Note that code here may get executed before the callback is called! + -- The ChunkStay says "once you have the chunks", not "wait until you have the chunks" + -- So you can't notify the player here, because the saving needn't have occurred yet. + + return true +end +</pre> + <p> + Note that this code does its error checking of the Area:Read() function, and it will not overwrite the + previous file unless it actually has the correct data. If you're wondering how the reading could fail + when we've got the chunks loaded, there's still the issue of free RAM - if the memory for the area + cannot be allocated, it cannot be read even with all the chunks present. So we still do need that + check.</p> + + <h2>The conclusion</h2> + <p> + Although it makes the code a little bit longer and is a bit more difficult to grasp at first, the + ChunkStay is a useful technique to add to your repertoire. It is to be used whenever you need access to + chunks that may potentially be inaccessible, and you really need the data.</p> + <p>Possibly the biggest hurdle in using the ChunkStay is the fact that it does its work in the + background, thus invalidating all cPlayer and cEntity objects your function may hold, so you need to + re-acquire them from their IDs and names. This is the penalty for using multi-threaded code.</p> + <script> + prettyPrint(); + </script> + </div> + </body> +</html> diff --git a/MCServer/Plugins/APIDump/WebWorldThreads.html b/MCServer/Plugins/APIDump/WebWorldThreads.html index fc80a6178..ee0b172e6 100644 --- a/MCServer/Plugins/APIDump/WebWorldThreads.html +++ b/MCServer/Plugins/APIDump/WebWorldThreads.html @@ -39,31 +39,31 @@ <h2>Example</h2> The Core has the facility to kick players using the web interface. It used the following code for the kicking (inside the webadmin handler): - <pre class="prettyprint lang-lua"> - local KickPlayerName = Request.Params["players-kick"] - local FoundPlayerCallback = function(Player) - if (Player:GetName() == KickPlayerName) then - Player:GetClientHandle():Kick("You were kicked from the game!") - end +<pre class="prettyprint lang-lua"> +local KickPlayerName = Request.Params["players-kick"] +local FoundPlayerCallback = function(Player) + if (Player:GetName() == KickPlayerName) then + Player:GetClientHandle():Kick("You were kicked from the game!") + end +end +cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback) +</pre> +The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds: +<pre class="prettyprint lang-lua"> +cRoot:Get():ForEachWorld( -- For each world... + function(World) + World:QueueTask( -- ... queue a task... + function(a_World) + a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist... + function (a_Player) + a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player end - cRoot:Get():FindAndDoWithPlayer(KickPlayerName, FoundPlayerCallback) - </pre> - The cRoot:FindAndDoWithPlayer() is unsafe and could have caused a deadlock. The new solution is queue a task; but since we don't know in which world the player is, we need to queue the task to all worlds: - <pre class="prettyprint lang-lua"> - cRoot:Get():ForEachWorld( -- For each world... - function(World) - World:QueueTask( -- ... queue a task... - function(a_World) - a_World:DoWithPlayer(KickPlayerName, -- ... to walk the playerlist... - function (a_Player) - a_Player:GetClientHandle():Kick("You were kicked from the game!") -- ... and kick the player - end - ) - end - ) - end - ) - </pre> + ) + end + ) + end +) +</pre> <script> prettyPrint(); </script> diff --git a/MCServer/Plugins/InfoReg.lua b/MCServer/Plugins/InfoReg.lua index 27e63aa5b..da5a9972c 100644 --- a/MCServer/Plugins/InfoReg.lua +++ b/MCServer/Plugins/InfoReg.lua @@ -16,22 +16,22 @@ local function ListSubcommands(a_Player, a_Subcommands, a_CmdString) end -- Enum all the subcommands: - local Verbs = {}; + local Verbs = {} for cmd, info in pairs(a_Subcommands) do - if (a_Player:HasPermission(info.Permission or "")) then - table.insert(Verbs, " " .. a_CmdString .. " " .. cmd); + if ((a_Player == nil) or (a_Player:HasPermission(info.Permission or ""))) then + table.insert(Verbs, a_CmdString .. " " .. cmd) end end - table.sort(Verbs); + table.sort(Verbs) -- Send the list: if (a_Player == nil) then for idx, verb in ipairs(Verbs) do - LOGINFO(verb); + LOGINFO(" " .. verb) end else for idx, verb in ipairs(Verbs) do - a_Player:SendMessage(verb); + a_Player:SendMessage(cCompositeChat(" ", mtInfo):AddSuggestCommandPart(verb, verb)) end end end diff --git a/MCServer/monsters.ini b/MCServer/monsters.ini index 8cd956157..b631fc1a9 100644 --- a/MCServer/monsters.ini +++ b/MCServer/monsters.ini @@ -47,14 +47,15 @@ AttackDamage=4.0 SightDistance=25.0 MaxHealth=40 -[Zombiepigman] +[ZombiePigman] AttackRange=2.0 AttackRate=1 AttackDamage=7.0 SightDistance=25.0 MaxHealth=20 +IsFireproof=1 -[Cavespider] +[CaveSpider] AttackRange=2.0 AttackRate=1 AttackDamage=2.0 @@ -74,6 +75,7 @@ AttackRate=1 AttackDamage=0.0 SightDistance=50.0 MaxHealth=10 +IsFireproof=1 [Silverfish] AttackRange=2.0 @@ -115,6 +117,7 @@ AttackRate=1 AttackDamage=6.0 SightDistance=25.0 MaxHealth=20 +IsFireproof=1 [Villager] AttackRange=2.0 @@ -122,6 +125,7 @@ AttackRate=1 AttackDamage=0.0 SightDistance=25.0 MaxHealth=20 +IsFireproof=0 [Witch] AttackRange=2.0 @@ -145,12 +149,13 @@ AttackDamage=0.0 SightDistance=25.0 MaxHealth=10 -[Magmacube] +[MagmaCube] AttackRange=2.0 AttackRate=1 AttackDamage=6.0 SightDistance=25.0 MaxHealth=16 +IsFireproof=1 [Horse] AttackRange=2.0 diff --git a/MakeLuaAPI.cmd b/MakeLuaAPI.cmd index 7054977a0..90b8cf53e 100644 --- a/MakeLuaAPI.cmd +++ b/MakeLuaAPI.cmd @@ -30,7 +30,7 @@ if "a%ftpsite%" == "a" ( cd MCServer copy /Y settings_apidump.ini settings.ini -echo stop | MCServer +echo api | MCServer cd .. diff --git a/SetFlags.cmake b/SetFlags.cmake index c5a3a0697..4eed529bd 100644 --- a/SetFlags.cmake +++ b/SetFlags.cmake @@ -45,6 +45,8 @@ macro(set_flags) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11") + add_flags_cxx("-stdlib=libc++") + add_flags_lnk("-stdlib=libc++") else() add_flags_cxx("-pthread") endif() diff --git a/Tools/ProtoProxy/Connection.cpp b/Tools/ProtoProxy/Connection.cpp index d9b8e3dd1..b21d2ae59 100644 --- a/Tools/ProtoProxy/Connection.cpp +++ b/Tools/ProtoProxy/Connection.cpp @@ -2197,11 +2197,39 @@ bool cConnection::HandleServerSpawnMob(void) +struct sSpawnData +{ + AString m_Name; + AString m_Value; + AString m_Signature; + sSpawnData(const AString & a_Name, const AString & a_Value, const AString & a_Signature) : + m_Name(a_Name), + m_Value(a_Value), + m_Signature(a_Signature) + { + } +}; + +typedef std::vector<sSpawnData> sSpawnDatas; + + + + + bool cConnection::HandleServerSpawnNamedEntity(void) { HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName); + HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, DataCount); + sSpawnDatas Data; + for (UInt32 i = 0; i < DataCount; i++) + { + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Name) + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Value) + HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Signature) + Data.push_back(sSpawnData(Name, Value, Signature)); + } HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosZ); @@ -2219,6 +2247,13 @@ bool cConnection::HandleServerSpawnNamedEntity(void) Log(" EntityID = %u (0x%x)", EntityID, EntityID); Log(" UUID = \"%s\"", EntityUUID.c_str()); Log(" Name = \"%s\"", EntityName.c_str()); + Log(" NumData = %u", DataCount); + for (sSpawnDatas::const_iterator itr = Data.begin(), end = Data.end(); itr != end; ++itr) + { + Log(" Name = \"%s\", Value = \"%s\", Signature = \"%s\"", + itr->m_Name.c_str(), itr->m_Value.c_str(), itr->m_Signature.c_str() + ); + } // for itr - Data[] Log(" Pos = %s", PrintableAbsIntTriplet(PosX, PosY, PosZ).c_str()); Log(" Rotation = <yaw %d, pitch %d>", Yaw, Pitch); Log(" CurrentItem = %d", CurrentItem); diff --git a/lib/expat/CMakeLists.txt b/lib/expat/CMakeLists.txt index 667804b9a..a23f16609 100644 --- a/lib/expat/CMakeLists.txt +++ b/lib/expat/CMakeLists.txt @@ -4,12 +4,11 @@ project (expat) file(GLOB SOURCE "*.c" + "*.h" ) -# add headers to MSVC project files: -if (WIN32) - file(GLOB HEADERS "*.h") - set(SOURCE ${SOURCE} ${HEADERS}) +# Set files to go to a "Sources" folder in MSVC project files: +if (MSVC) source_group("Sources" FILES ${SOURCE}) endif() diff --git a/lib/inifile/CMakeLists.txt b/lib/inifile/CMakeLists.txt index efbd09796..321d501d7 100644 --- a/lib/inifile/CMakeLists.txt +++ b/lib/inifile/CMakeLists.txt @@ -1,7 +1,11 @@ - cmake_minimum_required (VERSION 2.6) project (iniFile) include_directories ("${PROJECT_SOURCE_DIR}/../../src/") -add_library(iniFile iniFile) +file(GLOB SOURCE + "*.h" + "*.cpp" +) + +add_library(iniFile ${SOURCE}) diff --git a/lib/inifile/iniFile.cpp b/lib/inifile/iniFile.cpp index cf8b63987..19db9723a 100644 --- a/lib/inifile/iniFile.cpp +++ b/lib/inifile/iniFile.cpp @@ -154,7 +154,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) case ';': case '#': { - if (names.size() == 0) + if (names.empty()) { AddHeaderComment(line.substr(pLeft + 1)); } @@ -168,8 +168,9 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect) } // while (getline()) f.close(); - if (names.size() == 0) + if (keys.empty() && names.empty() && comments.empty()) { + // File be empty or unreadable, equivalent to nonexistant return false; } diff --git a/lib/luaexpat/CMakeLists.txt b/lib/luaexpat/CMakeLists.txt index 7eef5c8ce..f6b21c1d7 100644 --- a/lib/luaexpat/CMakeLists.txt +++ b/lib/luaexpat/CMakeLists.txt @@ -7,6 +7,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.c" + "*.h" ) add_library(luaexpat ${SOURCE}) diff --git a/lib/md5/CMakeLists.txt b/lib/md5/CMakeLists.txt index 8ba09a0dd..cd9fe6320 100644 --- a/lib/md5/CMakeLists.txt +++ b/lib/md5/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../src/") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(md5 ${SOURCE}) diff --git a/lib/zlib/CMakeLists.txt b/lib/zlib/CMakeLists.txt index 6c52578ee..74cf94f8b 100644 --- a/lib/zlib/CMakeLists.txt +++ b/lib/zlib/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../src/") file(GLOB SOURCE "*.c" + "*.h" ) if(NOT TARGET zlib) 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/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp index 92b410481..b3f75aff1 100644 --- a/src/Bindings/ManualBindings.cpp +++ b/src/Bindings/ManualBindings.cpp @@ -1750,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); @@ -1760,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; } 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/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/BlockID.cpp b/src/BlockID.cpp index 79e122032..bf95d0798 100644 --- a/src/BlockID.cpp +++ b/src/BlockID.cpp @@ -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/Blocks/BlockChest.h b/src/Blocks/BlockChest.h index a1ded4c26..c9a769c75 100644 --- a/src/Blocks/BlockChest.h +++ b/src/Blocks/BlockChest.h @@ -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/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/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp index 4a29ff628..a764c6f44 100644 --- a/src/Blocks/BlockHandler.cpp +++ b/src/Blocks/BlockHandler.cpp @@ -25,6 +25,7 @@ #include "BlockDirt.h" #include "BlockDoor.h" #include "BlockDropSpenser.h" +#include "BlockEnchantmentTable.h" #include "BlockEnderchest.h" #include "BlockEntity.h" #include "BlockFarmland.h" @@ -119,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); diff --git a/src/Blocks/BlockLeaves.h b/src/Blocks/BlockLeaves.h index 8af14686e..d21227b07 100644 --- a/src/Blocks/BlockLeaves.h +++ b/src/Blocks/BlockLeaves.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; \ } diff --git a/src/Blocks/BlockRail.h b/src/Blocks/BlockRail.h index ad78d290a..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)); 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/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..c634dc308 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 diff --git a/src/ByteBuffer.h b/src/ByteBuffer.h index 1915467f3..44f43e17f 100644 --- a/src/ByteBuffer.h +++ b/src/ByteBuffer.h @@ -27,7 +27,7 @@ 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 30e9dbfd4..9cc5fcb1e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,7 @@ if (NOT MSVC) file(GLOB SOURCE "*.cpp" + "*.h" ) list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp") diff --git a/src/Chunk.cpp b/src/Chunk.cpp index 22b33c595..cd3bceda2 100644 --- a/src/Chunk.cpp +++ b/src/Chunk.cpp @@ -240,11 +240,24 @@ 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); + + COMPRESSED_BLOCKTYPE Blocks = m_BlockTypes; + Blocks.resize(NumBlocks); + a_Callback.BlockTypes (&Blocks[0]); + + COMPRESSED_NIBBLETYPE Metas = m_BlockMeta; + Metas.resize(NumBlocks / 2); + a_Callback.BlockMeta (&Metas[0]); + a_Callback.LightIsValid (m_IsLightValid); - a_Callback.BlockLight (m_BlockLight); - a_Callback.BlockSkyLight(m_BlockSkyLight); + + COMPRESSED_NIBBLETYPE BlockLights = m_BlockLight; + BlockLights.resize(NumBlocks / 2); + a_Callback.BlockLight (&BlockLights[0]); + + COMPRESSED_NIBBLETYPE BlockSkyLights = m_BlockSkyLight; + BlockSkyLights.resize(NumBlocks / 2, 0xff); + a_Callback.BlockSkyLight(&BlockSkyLights[0]); for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { @@ -262,7 +275,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 +285,61 @@ void cChunk::SetAllData( ) { memcpy(m_BiomeMap, a_BiomeMap, sizeof(m_BiomeMap)); - + if (a_HeightMap != NULL) { memcpy(m_HeightMap, a_HeightMap, sizeof(m_HeightMap)); } + + if (a_HeightMap == NULL) + { + CalculateHeightmap(a_BlockTypes); + } + + int IdxWhereNonEmptyStarts = 0; + { // Blocktype compression + unsigned char Highest = 0; + int X = 0, Z = 0; + m_BlockTypes.clear(); + + for (int x = 0; x < Width; x++) + { + for (int z = 0; z < Width; z++) + { + unsigned char Height = m_HeightMap[x + z * Width]; + if (Height > Highest) + { + Highest = Height; + X = x; Z = z; + } + } + } + + IdxWhereNonEmptyStarts = MakeIndexNoCheck(X, Highest + 1, Z); + + m_BlockTypes.insert(m_BlockTypes.end(), &a_BlockTypes[0], &a_BlockTypes[IdxWhereNonEmptyStarts]); + } + + { // Blockmeta compression + m_BlockMeta.clear(); + m_BlockMeta.insert(m_BlockMeta.end(), &a_BlockMeta[0], &a_BlockMeta[IdxWhereNonEmptyStarts / 2]); + } - 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)); + // Compress blocklight + m_BlockLight.clear(); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[IdxWhereNonEmptyStarts / 2]); } + if (a_BlockSkyLight != NULL) { - memcpy(m_BlockSkyLight, a_BlockSkyLight, sizeof(m_BlockSkyLight)); + // Compress skylight + m_BlockSkyLight.clear(); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_BlockSkyLight[0], &a_BlockSkyLight[IdxWhereNonEmptyStarts / 2]); } 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 +377,17 @@ 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)); + + { // Compress blocklight + m_BlockLight.clear(); + m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size()]); + } + + { // Compress skylight + m_BlockSkyLight.clear(); + m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size()]); + } + m_IsLightValid = true; } @@ -343,7 +397,8 @@ void cChunk::SetLight( void cChunk::GetBlockTypes(BLOCKTYPE * a_BlockTypes) { - memcpy(a_BlockTypes, m_BlockTypes, NumBlocks); + std::copy(m_BlockTypes.begin(), m_BlockTypes.end(), a_BlockTypes); + std::fill_n(&a_BlockTypes[m_BlockTypes.size()], NumBlocks - m_BlockTypes.size(), E_BLOCK_AIR); } @@ -452,7 +507,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 +655,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: @@ -630,7 +685,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(Index)); ASSERT(Handler != NULL); // Happenned on server restart, FS #243 cChunkInterface ChunkInterface(this->GetWorld()->GetChunkMap()); cBlockInServerPluginInterface PluginInterface(*this->GetWorld()); @@ -751,7 +806,7 @@ void cChunk::BroadcastPendingBlockChanges(void) void cChunk::CheckBlocks() { - if (m_ToTickBlocks.size() == 0) + if (m_ToTickBlocks.empty()) { return; } @@ -811,7 +866,7 @@ void cChunk::TickBlocks(void) } unsigned int Index = MakeIndexNoCheck(m_BlockTickX, m_BlockTickY, m_BlockTickZ); - cBlockHandler * Handler = BlockHandler(m_BlockTypes[Index]); + cBlockHandler * Handler = BlockHandler(GetBlock(Index)); 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 @@ -1296,9 +1351,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 +1404,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 +1439,7 @@ void cChunk::WakeUpSimulators(void) -void cChunk::CalculateHeightmap() +void cChunk::CalculateHeightmap(const BLOCKTYPE * a_BlockTypes) { for (int x = 0; x < Width; x++) { @@ -1392,7 +1448,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; @@ -1429,6 +1485,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: @@ -1515,7 +1572,7 @@ 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 OldBlockType = GetBlock(index); const BLOCKTYPE OldBlockMeta = GetNibble(m_BlockMeta, index); if ((OldBlockType == a_BlockType) && (OldBlockMeta == a_BlockMeta)) { @@ -1523,7 +1580,11 @@ void cChunk::FastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockT } MarkDirty(); - + + if ((size_t)index >= m_BlockTypes.size()) + { + m_BlockTypes.resize(index + 1); + } m_BlockTypes[index] = a_BlockType; // The client doesn't need to distinguish between stationary and nonstationary fluids: @@ -1563,7 +1624,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(MakeIndexNoCheck(a_RelX, y, a_RelZ)) != E_BLOCK_AIR) { m_HeightMap[a_RelX + a_RelZ * Width] = (unsigned char)y; break; @@ -2450,7 +2511,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)]; + return GetBlock(MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ)); } @@ -2464,8 +2525,13 @@ BLOCKTYPE cChunk::GetBlock(int a_BlockIdx) const ASSERT(!"GetBlock(idx) out of bounds!"); return 0; } - - return m_BlockTypes[ a_BlockIdx ]; + + if ((size_t)a_BlockIdx >= m_BlockTypes.size()) + { + return E_BLOCK_AIR; + } + + return m_BlockTypes[a_BlockIdx]; } @@ -2475,7 +2541,7 @@ 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_BlockType = GetBlock(Idx); a_BlockMeta = cChunkDef::GetNibble(m_BlockMeta, Idx); } @@ -2486,7 +2552,7 @@ 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_BlockType = GetBlock(Idx); a_Meta = cChunkDef::GetNibble(m_BlockMeta, Idx); a_SkyLight = cChunkDef::GetNibble(m_BlockSkyLight, Idx); a_BlockLight = cChunkDef::GetNibble(m_BlockLight, Idx); @@ -2511,7 +2577,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..a15d43e00 100644 --- a/src/Chunk.h +++ b/src/Chunk.h @@ -267,7 +267,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) @@ -326,9 +326,9 @@ public: inline void SetMeta(int a_BlockIdx, NIBBLETYPE a_Meta) { cChunkDef::SetNibble(m_BlockMeta, a_BlockIdx, 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 GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ, true); } 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 GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx, true); } /** 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 +382,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) { } } ; @@ -421,10 +421,10 @@ private: 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]; + COMPRESSED_BLOCKTYPE m_BlockTypes; + COMPRESSED_NIBBLETYPE m_BlockMeta; + COMPRESSED_NIBBLETYPE m_BlockLight; + COMPRESSED_NIBBLETYPE m_BlockSkyLight; cChunkDef::HeightMap m_HeightMap; cChunkDef::BiomeMap m_BiomeMap; diff --git a/src/ChunkDef.h b/src/ChunkDef.h index 9c7753820..054168bdd 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)) + { + int Index = MakeIndexNoCheck(x, y, z); + if ((size_t)(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, 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) || @@ -271,24 +298,32 @@ public: } 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 - ); + if ((size_t)(Index / 2) >= a_Buffer.size()) + { + a_Buffer.resize((size_t)((Index / 2) + 1)); + } + a_Buffer[(size_t)(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble); } - inline static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos ) +private: + + + inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index, NIBBLETYPE a_Nibble) { - return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); + 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 + ); } - - - inline static void SetNibble(NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos, NIBBLETYPE a_Value ) + + + inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index) { - SetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z, a_Value ); + return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f; } + } ; diff --git a/src/ChunkMap.cpp b/src/ChunkMap.cpp index e695f0ab2..0fb6988b5 100644 --- a/src/ChunkMap.cpp +++ b/src/ChunkMap.cpp @@ -346,9 +346,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 +915,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 +1145,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) { @@ -1654,7 +1654,7 @@ 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->IsValid()) { 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 +1689,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 +1721,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 +1971,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 +1986,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 +2001,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 +2016,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 +2031,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 +2046,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 +2064,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 +2082,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 +2100,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 +2118,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 +2136,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 +2154,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 +2171,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 +2188,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 +2206,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 +2224,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 +2242,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 +2974,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 +3022,7 @@ void cChunkMap::DelChunkStay(cChunkStay & a_ChunkStay) } Chunk->Stay(false); } // for itr - Chunks[] + a_ChunkStay.OnDisabled(); } 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 5876e55c7..fc3f98aaf 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,79 @@ 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 AString(); + 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!"); +} + + + + + +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 +263,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 +272,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()); @@ -412,14 +493,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); } @@ -994,7 +1077,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e { 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()) { @@ -1175,8 +1258,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); @@ -1677,13 +1760,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 +1889,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 +1908,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 +2107,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); } @@ -2685,4 +2691,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 0c367ec7d..9f8d44129 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" @@ -62,8 +64,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. **/ + AString FormatMessageType(bool ShouldAppendChatPrefixes, eMessageType a_ChatPrefix, const AString & a_AdditionalData); + + 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); @@ -230,6 +251,9 @@ public: /** Called when the player moves into a different world; queues sreaming the new chunks */ void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket); + /** 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) */ @@ -326,6 +350,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; diff --git a/src/CraftingRecipes.cpp b/src/CraftingRecipes.cpp index 30e7a8733..b0af8f271 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) ) ) { @@ -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; diff --git a/src/Crypto.cpp b/src/Crypto.cpp index 26500f263..16be5ec35 100644 --- a/src/Crypto.cpp +++ b/src/Crypto.cpp @@ -206,7 +206,7 @@ int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte ASSERT(!"Invalid a_DecryptedMaxLength!"); return -1; } - if (a_EncryptedMaxLength < m_Rsa.len) + 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) diff --git a/src/DeadlockDetect.cpp b/src/DeadlockDetect.cpp index 322084dc4..38a3c369e 100644 --- a/src/DeadlockDetect.cpp +++ b/src/DeadlockDetect.cpp @@ -112,18 +112,21 @@ void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age) ASSERT(!"Unknown world in cDeadlockDetect"); 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..9fa3b3a8e 100644 --- a/src/Defines.h +++ b/src/Defines.h @@ -493,15 +493,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; } diff --git a/src/Enchantments.cpp b/src/Enchantments.cpp index 1d8188e96..64f89815b 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); @@ -150,7 +159,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 +190,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,8 +231,782 @@ 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..ec42257c8 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,87 @@ 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 + /** 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); - /// 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, int a_EnchantmentID); + + /** 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/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt index 85cc45494..c9ca44d38 100644 --- a/src/Entities/CMakeLists.txt +++ b/src/Entities/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Entities ${SOURCE}) diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 8ef45f1a5..7c8e18b51 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -45,6 +45,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_IsInitialized(false) , m_EntityType(a_EntityType) , m_World(NULL) + , m_IsFireproof(false) , m_TicksSinceLastBurnDamage(0) , m_TicksSinceLastLavaDamage(0) , m_TicksSinceLastFireDamage(0) @@ -325,12 +326,41 @@ 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); if (m_Health <= 0) { @@ -380,11 +410,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 +426,33 @@ 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!"); +} + + + + + +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 +530,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); } @@ -519,37 +570,36 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) } else { - if (a_Chunk.IsValid()) + if (!a_Chunk.IsValid()) { - cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT); + return; + } - if ((NextChunk == NULL) || !NextChunk->IsValid()) - { - return; - } + // Position changed -> super::Tick() called + GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, POSX_TOINT, POSZ_TOINT) - TickBurning(*NextChunk); + TickBurning(*NextChunk); - if (GetPosY() < VOID_BOUNDARY) - { - TickInVoid(*NextChunk); - } - else - { - m_TicksSinceLastVoidDamage = 0; - } - - if (IsMob() || IsPlayer()) - { - // Set swimming state - SetSwimState(*NextChunk); + if (GetPosY() < VOID_BOUNDARY) + { + TickInVoid(*NextChunk); + } + else + { + m_TicksSinceLastVoidDamage = 0; + } - // Handle drowning - HandleAir(); - } + 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 +609,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 +662,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; @@ -764,20 +810,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 +822,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 +837,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 +851,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 +908,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 +929,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; } } @@ -981,13 +1032,13 @@ void cEntity::HandleAir(void) } else { - m_AirTickTimer -= 1; + m_AirTickTimer--; } } else { // Reduce air supply - m_AirLevel -= 1; + m_AirLevel--; } } else @@ -1040,6 +1091,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,15 +1160,15 @@ 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)) + // Send velocity packet every two ticks if: speed is not negligible or speed was set (as indicated by the DirtySpeed flag) + 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 + // Have to process position related packets this every two ticks if (m_World->GetWorldAge() % 2 == 0) { int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0)); diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 6e3f8292b..9b8011b55 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); @@ -248,6 +270,9 @@ public: /// 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); @@ -307,6 +332,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); @@ -413,6 +443,9 @@ protected: 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; diff --git a/src/Entities/FallingBlock.cpp b/src/Entities/FallingBlock.cpp index a66c7e4ae..bcdac0291 100644 --- a/src/Entities/FallingBlock.cpp +++ b/src/Entities/FallingBlock.cpp @@ -87,7 +87,9 @@ 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. + static const float epsilon = 0.000000001; + if ((fabs(GetSpeedX()) > epsilon) || (fabs(GetSpeedZ()) > epsilon)) { BroadcastMovementUpdate(); } diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp index 7f38aa35a..db55eb058 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()) diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 7fc89b62b..497b41683 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; 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 7f2e5b4c2..fedb62527 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -85,9 +85,10 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) 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() @@ -437,7 +438,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; @@ -466,7 +467,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 +591,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); @@ -1165,9 +1166,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); } @@ -1519,22 +1520,16 @@ 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(m_PlayerName, "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(), m_PlayerName.c_str()); } - } - else - { - AddToGroup("Default"); + AddToGroup(*itr); } AString Color = IniFile.GetValue(m_PlayerName, "Color", "-"); @@ -1546,8 +1541,10 @@ void cPlayer::LoadPermissionsFromDisk() else { cGroupManager::GenerateDefaultUsersIni(IniFile); + IniFile.AddValue("Groups", m_PlayerName, "Default"); AddToGroup("Default"); } + IniFile.WriteFile("users.ini"); ResolvePermissions(); } @@ -1899,9 +1896,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 05377a117..78d661015 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -181,7 +181,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 diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp index e86bb48bd..fd3e80e5f 100644 --- a/src/Entities/ProjectileEntity.cpp +++ b/src/Entities/ProjectileEntity.cpp @@ -440,6 +440,7 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : m_IsCritical((a_Force >= 1)), m_Timer(0), m_HitGroundTimer(0), + m_HasTeleported(false), m_bIsCollected(false), m_HitBlockPos(0, 0, 0) { @@ -562,12 +563,12 @@ void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk) // 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_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_HitGroundTimer = -1; + m_HasTeleported = true; } else { @@ -611,6 +612,32 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, 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); @@ -622,7 +649,6 @@ void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_H 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(); } @@ -644,15 +670,39 @@ cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X 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) { - // 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(); } @@ -696,6 +746,7 @@ void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & TotalDamage = 1; } } + // TODO: If entity is Ender Crystal, destroy it a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1); Destroy(true); @@ -791,7 +842,7 @@ void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk) if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) { - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE); + m_World->BroadcastEntityStatus(*this, esFireworkExploding); Destroy(); } diff --git a/src/Entities/ProjectileEntity.h b/src/Entities/ProjectileEntity.h index efb7ae783..731dd060e 100644 --- a/src/Entities/ProjectileEntity.h +++ b/src/Entities/ProjectileEntity.h @@ -166,6 +166,9 @@ protected: /// 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; @@ -205,7 +208,11 @@ 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_begin } ; @@ -233,6 +240,10 @@ 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_begin diff --git a/src/FastRandom.cpp b/src/FastRandom.cpp index e6634bb0d..c45261947 100644 --- a/src/FastRandom.cpp +++ b/src/FastRandom.cpp @@ -172,3 +172,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/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..5cad11d2a 100644 --- a/src/Generating/Caves.cpp +++ b/src/Generating/Caves.cpp @@ -200,13 +200,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; @@ -244,11 +245,12 @@ bool cCaveTunnel::RefineDefPoints(const cCaveDefPoints & a_Src, cCaveDefPoints & 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; + 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 (int i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; @@ -310,9 +312,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 +436,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); diff --git a/src/Generating/NetherFortGen.cpp b/src/Generating/NetherFortGen.cpp index 02779a8a3..d90fdeb0a 100644 --- a/src/Generating/NetherFortGen.cpp +++ b/src/Generating/NetherFortGen.cpp @@ -71,6 +71,40 @@ public: /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// 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: cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) : @@ -80,9 +114,9 @@ cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) : m_MaxDepth(a_MaxDepth) { // Initialize the prefabs: - for (size_t i = 0; i < g_NetherFortPrefabs1Count; i++) + for (size_t i = 0; i < g_NetherFortPrefabsCount; i++) { - cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs1[i]); + cPrefab * Prefab = new cPrefab(g_NetherFortPrefabs[i]); m_AllPieces.push_back(Prefab); if (Prefab->HasConnectorType(0)) { @@ -95,15 +129,17 @@ cNetherFortGen::cNetherFortGen(int a_Seed, int a_GridSize, int a_MaxDepth) : } // Initialize the starting piece prefabs: - for (size_t i = 0; i < g_NetherFortStartingPrefabs1Count; i++) + for (size_t i = 0; i < g_NetherFortStartingPrefabsCount; i++) { - m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs1[i])); + m_StartingPieces.push_back(new cPrefab(g_NetherFortStartingPrefabs[i])); } + /* // DEBUG: Try one round of placement: cPlacedPieces Pieces; cBFSPieceGenerator pg(*this, a_Seed); pg.PlacePieces(0, 64, 0, a_MaxDepth, Pieces); + */ } @@ -256,6 +292,15 @@ cPieces cNetherFortGen::GetStartingPieces(void) +int cNetherFortGen::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) +{ + return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector); +} + + + + + void cNetherFortGen::PiecePlaced(const cPiece & a_Piece) { UNUSED(a_Piece); diff --git a/src/Generating/NetherFortGen.h b/src/Generating/NetherFortGen.h index 10ba01396..d51596b9e 100644 --- a/src/Generating/NetherFortGen.h +++ b/src/Generating/NetherFortGen.h @@ -26,6 +26,7 @@ public: virtual ~cNetherFortGen(); protected: + friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp class cNetherFort; // fwd: NetherFortGen.cpp typedef std::list<cNetherFort *> cNetherForts; @@ -77,6 +78,7 @@ protected: // 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 void PiecePlaced(const cPiece & a_Piece) override; virtual void Reset(void) override; } ; diff --git a/src/Generating/PieceGenerator.cpp b/src/Generating/PieceGenerator.cpp index 8999a5ff7..8e9a48be6 100644 --- a/src/Generating/PieceGenerator.cpp +++ b/src/Generating/PieceGenerator.cpp @@ -392,14 +392,17 @@ bool cPieceGenerator::TryPlacePieceAtConnector( 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) { @@ -419,7 +422,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 +432,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 +456,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 +525,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..f4433b947 100644 --- a/src/Generating/PieceGenerator.h +++ b/src/Generating/PieceGenerator.h @@ -85,6 +85,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 +108,16 @@ 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. + 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; } + /** 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; @@ -157,8 +174,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 131b6acb2..c0c9e8a13 100644 --- a/src/Generating/Prefab.cpp +++ b/src/Generating/Prefab.cpp @@ -23,6 +23,10 @@ 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 */ @@ -91,7 +95,19 @@ static const cPrefab::sDef g_TestPrefabDef = 7, /* 1, 2, 3 CCW rotations */ // Merge strategy: - cBlockArea::msImprint + cBlockArea::msImprint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 1000, }; static cPrefab g_TestPrefab(g_TestPrefabDef); @@ -103,15 +119,22 @@ static cPrefab g_TestPrefab(g_TestPrefabDef); 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_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); // 1 CCW rotation: if ((m_AllowedRotations & 0x01) != 0) @@ -142,12 +165,53 @@ cPrefab::cPrefab(const cPrefab::sDef & a_Def) : void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const { + // Draw the basic image: Vector3i Placement = a_Placement->GetCoords(); 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_Placement->GetNumCCWRotations()]; + 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) + 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 } @@ -170,6 +234,26 @@ 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::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef) { ASSERT(a_CharMapDef != NULL); @@ -277,6 +361,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 04c4f09da..37db2ff16 100644 --- a/src/Generating/Prefab.h +++ b/src/Generating/Prefab.h @@ -37,11 +37,51 @@ 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; }; cPrefab(const sDef & a_Def); @@ -51,6 +91,10 @@ public: /** 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; protected: /** Packs complete definition of a single block, for per-letter assignment. */ @@ -60,9 +104,12 @@ protected: NIBBLETYPE m_BlockMeta; }; - /** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | 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. The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */ @@ -71,7 +118,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 */ @@ -82,6 +129,26 @@ 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; // cPiece overrides: @@ -98,6 +165,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/Prefabs/CMakeLists.txt b/src/Generating/Prefabs/CMakeLists.txt index 1e60447e7..a1f09112d 100644 --- a/src/Generating/Prefabs/CMakeLists.txt +++ b/src/Generating/Prefabs/CMakeLists.txt @@ -6,6 +6,7 @@ include_directories ("${PROJECT_SOURCE_DIR}/../../") file(GLOB SOURCE "*.cpp" + "*.h" ) add_library(Generating_Prefabs ${SOURCE}) diff --git a/src/Generating/Prefabs/NetherFortPrefabs.cpp b/src/Generating/Prefabs/NetherFortPrefabs.cpp index 5e8685e32..d2ef5663d 100644 --- a/src/Generating/Prefabs/NetherFortPrefabs.cpp +++ b/src/Generating/Prefabs/NetherFortPrefabs.cpp @@ -1,7 +1,10 @@ // NetherFortPrefabs.cpp -// Defines all the prefabs for nether forts +// 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" @@ -10,347 +13,437 @@ -/* -The nether fortress has two types of connectors, Outer and Inner. Outer is Type 0, Inner is Type 1. -*/ - - - - - -const cPrefab::sDef g_NetherFortPrefabs1[] = +const cPrefab::sDef g_NetherFortPrefabs[] = { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BalconyCorridor: - // The data has been exported from gallery Nether, area index 37, ID 288 + // 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: 19: 0\n" /* sponge */ - "c:114: 4\n" /* netherbrickstairs */ - "d:114: 7\n" /* netherbrickstairs */ - "e:114: 5\n" /* netherbrickstairs */ - "f: 44: 6\n" /* step */ - "g:113: 0\n" /* netherbrickfence */ - "h:114: 2\n" /* netherbrickstairs */ - "i:114: 3\n" /* netherbrickstairs */ - "j:114: 0\n" /* netherbrickstairs */ - "k:114: 1\n" /* netherbrickstairs */ - ".: 0: 0\n" /* air */, + "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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "bbbbaaaaabbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" + /* 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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaa.aaa.aaaa" - "bbcdaaaaadebb" - "bbbcdddddebbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "aaaa.eee.aaaa" + /* 5 */ "mmaaaaaaaaamm" + /* 6 */ "mmaaaaaaaaamm" + /* 7 */ "mmaaaaaaaaamm" + /* 8 */ "mmaaaaaaaaamm" // Level 3 - "aaaaaaaaaaaaa" - "............." - "............." - "............." - "aaaa.fff.aaaa" - "bbaaaaaaaaabb" - "bbaaaaaaaaabb" - "bbaaaaaaaaabb" - "bbaaaaaaaaabb" + /* 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 - "agagagagagaga" - "............." - "............." - "............." - "agaa.....aaga" - "bbaaa...aaabb" - "bbg.......gbb" - "bbg.......gbb" - "bbgggggggggbb" + /* 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 - "agagagagagaga" - "............." - "............." - "............." - "agaa.....aaga" - "bbaaa...aaabb" - "bb.........bb" - "bb.........bb" - "bb.........bb" + /* 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 - "agagagagagaga" - "............." - "............." - "............." - "agaa.....aaga" - "bbaaa...aaabb" - "bb.........bb" - "bb.........bb" - "bb.........bb" + /* 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- */, - // Level 7 - "hhhhhhhhhhhhh" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "iijaaaaaaaiii" - "bbjiiiiiiikbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb", - - // Connections: - "1: 0, 2, 2: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 12, 2, 2: 5\n" /* Type 1, BLOCK_FACE_XP */, - // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // BalconyCorridor + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BalconyTee2: - // The data has been exported from gallery Nether, area index 38, ID 289 + // 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: - "a: 19: 0\n" /* sponge */ - "b:112: 0\n" /* netherbrick */ - "c:114: 4\n" /* netherbrickstairs */ - "d:114: 7\n" /* netherbrickstairs */ - "e:114: 5\n" /* netherbrickstairs */ - "f: 44: 6\n" /* step */ - "g:113: 0\n" /* netherbrickfence */ - "h:114: 0\n" /* netherbrickstairs */ - "i:114: 1\n" /* netherbrickstairs */ - "j:114: 2\n" /* netherbrickstairs */ - "k:114: 3\n" /* netherbrickstairs */ - ".: 0: 0\n" /* air */, + ".: 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 - "aaaabbbbbaaaa" - "aaaabbbbbaaaa" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "aaaabbbbbaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "aaaabbbbbaaaa" - "aaaabbbbbaaaa" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbb.bbb.bbbb" - "aacdbbbbbdeaa" - "aaacdddddeaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "aaaab...baaaa" - "aaaab...baaaa" - "bbbbb...bbbbb" - "............." - "............." - "............." - "bbbb.fff.bbbb" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" + /* 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 - "aaaab...baaaa" - "aaaag...gaaaa" - "bgbgb...bgbgb" - "............." - "............." - "............." - "bgbb.....bbgb" - "aabbb...bbbaa" - "aag.......gaa" - "aag.......gaa" - "aagggggggggaa" + /* 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 - "aaaab...baaaa" - "aaaag...gaaaa" - "bgbgb...bgbgb" - "............." - "............." - "............." - "bgbb.....bbgb" - "aabbb...bbbaa" - "aa.........aa" - "aa.........aa" - "aa.........aa" + /* 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 - "aaaab...baaaa" - "aaaag...gaaaa" - "bgbgb...bgbgb" - "............." - "............." - "............." - "bgbb.....bbgb" - "aabbb...bbbaa" - "aa.........aa" - "aa.........aa" - "aa.........aa" + /* 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- */, - // Level 7 - "aaaahbbbiaaaa" - "aaaahbbbiaaaa" - "jjjjjbbbjjjjj" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "bbbbbbbbbbbbb" - "kkhbbbbbbbkkk" - "aahkkkkkkkiaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa", - - // Connections: - "1: 0, 2, 4: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 12, 2, 4: 5\n" /* Type 1, BLOCK_FACE_XP */ - "1: 6, 2, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */, - // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // BalconyTee2 + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // BlazePlatform - // The data has been exported from gallery Nether, area index 26, ID 276 + // 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 */, + "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 - ".........." - "aaaaaaaaaa" - "aaaaaaaaaa" - "aaaaaaaaaa" - "aaaaaaaaaa" - "aaaaaaaaaa" - ".........." + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmmmmmmm" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "..aaaaaaaa" + /* 3 */ "..aaaaaaaa" + /* 4 */ "..aaaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "mmmmmmmmmm" // Level 2 - ".........." - "aaaaaaaaaa" - "..aaaaaaaa" - "..aaaaaaaa" - "..aaaaaaaa" - "aaaaaaaaaa" - ".........." + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmaaaaaa" + /* 1 */ "aaaaaaaaaa" + /* 2 */ "...aaaaaaa" + /* 3 */ "...aaaaaaa" + /* 4 */ "...aaaaaaa" + /* 5 */ "aaaaaaaaaa" + /* 6 */ "mmmmaaaaaa" // Level 3 - "....aaaaaa" - "aaaaaaaaaa" - "...aaaaaaa" - "...aaaaaaa" - "...aaaaaaa" - "aaaaaaaaaa" - "....aaaaaa" + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmaaaaaa" + /* 1 */ "mmaaa....a" + /* 2 */ ".........a" + /* 3 */ "......b..a" + /* 4 */ ".........a" + /* 5 */ "mmaaa....a" + /* 6 */ "mmmmaaaaaa" // Level 4 - "....aaaaaa" - "..aaa....a" - ".........a" - "......b..a" - ".........a" - "..aaa....a" - "....aaaaaa" + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmcccccc" + /* 1 */ "mmmcc....c" + /* 2 */ ".........c" + /* 3 */ ".........c" + /* 4 */ ".........c" + /* 5 */ "mmmcc....c" + /* 6 */ "mmmmcccccc" // Level 5 - "....cccccc" - "...cc....c" - ".........c" - ".........c" - ".........c" - "...cc....c" - "....cccccc" + /* z\x* */ + /* * 0123456789 */ + /* 0 */ "mmmmmmmmmm" + /* 1 */ "mmmmm....c" + /* 2 */ "m........c" + /* 3 */ "m........c" + /* 4 */ "m........c" + /* 5 */ "mmmmm....c" + /* 6 */ "mmmmmmmmmm" // Level 6 - ".........." - ".........c" - ".........c" - ".........c" - ".........c" - ".........c" - ".........." + /* 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- */, - // Level 7 - ".........." - ".........." - ".........c" - ".........c" - ".........c" - ".........." - "..........", - - // Connections: - "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */, - // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, }, // BlazePlatform + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BlazePlatformOverhang: - // The data has been exported from gallery Nether, area index 20, ID 162 + // The data has been exported from the gallery Nether, area index 20, ID 162, created by STR_Warrior { // Size: - 14, 9, 7, // SizeX = 14, SizeY = 9, SizeZ = 7 + 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 */ @@ -366,105 +459,362 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "mmmmmmmmmmmmmm" - "mmmmmmmmmmmmmm" - "aammmmmmmmmmmm" - "aammmmmmmmmmmm" - "aammmmmmmmmmmm" - "mmmmmmmmmmmmmm" - "mmmmmmmmmmmmmm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmmmmm" + /* 2 */ "aabcmmmmmmmmmm" + /* 3 */ "aabcmmmmmmmmmm" + /* 4 */ "aabcmmmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" // Level 2 - "mmmmmmmmmmmmmm" - "mmmmmmmmmmmmmm" - "aabcmmmmmmmmmm" - "aabcmmmmmmmmmm" - "aabcmmmmmmmmmm" - "mmmmmmmmmmmmmm" - "mmmmmmmmmmmmmm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "mmmmmmmmmmmmmm" + /* 2 */ "aaaaabmmmmmmmm" + /* 3 */ "aaaaabmmmmmmmm" + /* 4 */ "aaaaabmmmmmmmm" + /* 5 */ "mmmmmmmmmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" // Level 3 - "mmmmmmmmmmmmmm" - "mmmmmmmmmmmmmm" - "aaaaabmmmmmmmm" - "aaaaabmmmmmmmm" - "aaaaabmmmmmmmm" - "mmmmmmmmmmmmmm" - "mmmmmmmmmmmmmm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "dddddddmmmmmmm" + /* 2 */ "aaaaaabmmmmmmm" + /* 3 */ "aaaaaabmmmmmmm" + /* 4 */ "aaaaaabmmmmmmm" + /* 5 */ "eeeeeeemmmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" // Level 4 - "mmmmmmmmmmmmmm" - "dddddddmmmmmmm" - "aaaaaabmmmmmmm" - "aaaaaabmmmmmmm" - "aaaaaabmmmmmmm" - "eeeeeeemmmmmmm" - "mmmmmmmmmmmmmm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "aaaaaaadmmmmmm" + /* 2 */ "aaaaaaabmmmmmm" + /* 3 */ "aaaaaaabmmmmmm" + /* 4 */ "aaaaaaabmmmmmm" + /* 5 */ "aaaaaaaemmmmmm" + /* 6 */ "mmmmmmmmmmmmmm" // Level 5 - "mmmmmmmmmmmmmm" - "aaaaaaadmmmmmm" - "aaaaaaabmmmmmm" - "aaaaaaabmmmmmm" - "aaaaaaabmmmmmm" - "aaaaaaaemmmmmm" - "mmmmmmmmmmmmmm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmmmmmmm" + /* 1 */ "aaaaaaaabddddm" + /* 2 */ "......faaaaabm" + /* 3 */ "......faaaaabm" + /* 4 */ "......faaaaabm" + /* 5 */ "aaaaaaaaabeebm" + /* 6 */ "mmmmmmmmmmmmmm" // Level 6 - "mmmmmmmmmmmmmm" - "aaaaaaaabddddm" - "......faaaaabm" - "......faaaaabm" - "......faaaaabm" - "aaaaaaaaabeebm" - "mmmmmmmmmmmmmm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmgdddbm" + /* 1 */ "mmmmmmaaaaaaad" + /* 2 */ ".......faaaaab" + /* 3 */ ".......faaaaab" + /* 4 */ ".......faaaaab" + /* 5 */ "mmmmmmaaaaaaae" + /* 6 */ "mmmmmmmmgeeebm" // Level 7 - "mmmmmmmmgdddbm" - "......aaaaaaad" - ".......faaaaab" - ".......faaaaab" - ".......faaaaab" - "......aaaaaaae" - "mmmmmmmmgeeebm" + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmmaaaaam" + /* 1 */ "mmmmmmhaa...aa" + /* 2 */ ".............a" + /* 3 */ "..........i..a" + /* 4 */ ".............a" + /* 5 */ "mmmmmmhaa...aa" + /* 6 */ "mmmmmmmmaaaaam" // Level 8 - "mmmmmmmmaaaaam" - "......haa...aa" - ".............a" - "..........i..a" - ".............a" - "......haa...aa" - "mmmmmmmmaaaaam" + /* 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 - "mmmmmmmmhhhhhm" - "......hhh...hh" - ".............h" - ".............h" - ".............h" - "......hhh...hh" - "mmmmmmmmhhhhhm", + /* z\x* 1111 */ + /* * 01234567890123 */ + /* 0 */ "mmmmmmmm.....m" + /* 1 */ "mmmmmm........" + /* 2 */ "mmmm.........." + /* 3 */ "mmmm.........." + /* 4 */ "mmmm.........." + /* 5 */ "mmmmmm........" + /* 6 */ "mmmmmmmm.....m" - // Connections: - "0: 0, 5, 3: 4\n" /* Type 0, BLOCK_FACE_XM */, + // 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, }, // 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: + false, + + // DefaultWeight: + 5, + + // DepthWeight: + "", + + // AddWeightIfSame: + -1000, + }, // BridgeCircleCrossing + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BridgeCrossing: - // The data has been exported from gallery Nether, area index 17, ID 159 + // 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 */ @@ -476,300 +826,808 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "aammmmmmmmmmmaa" - "aammmmmmmmmmmaa" - "aammmmmmmmmmmaa" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" + /* 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 - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" - "mmmmmmbbbmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "aacmmmmmmmmmdaa" - "aacmmmmmmmmmdaa" - "aacmmmmmmmmmdaa" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmeeemmmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" + /* 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 - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" - "mmmmmmbbbmmmmmm" - "mmmmmmfffmmmmmm" - "mmmmmmmmmmmmmmm" - "aaacfmmmmmfdaaa" - "aaacfmmmmmfdaaa" - "aaacfmmmmmfdaaa" - "mmmmmmmmmmmmmmm" - "mmmmmmfffmmmmmm" - "mmmmmmeeemmmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" + /* 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 - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "eeeeeeaaaeeeeee" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "bbbbbdaaacbbbbb" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" - "mmmmmdaaacmmmmm" + /* 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 - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" + /* 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 - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "aaaaaa...aaaaaa" - "..............." - "..............." - "..............." - "aaaaaa...aaaaaa" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" + /* 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 - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "..............." - "..............." - "..............." - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - - // Level 8 - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "..............." - "..............." - "..............." - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm", - - // Connections: - "0: 0, 5, 7: 4\n" /* Type 0, BLOCK_FACE_XM */ - "0: 7, 5, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */ - "0: 14, 5, 7: 5\n" /* Type 0, BLOCK_FACE_XP */ - "0: 7, 5, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */, + /* 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "1:1000", + + // AddWeightIfSame: + 0, }, // BridgeCrossing + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BridgeCrumble1: - // The data has been exported from gallery Nether, area index 19, ID 161 + // 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: - ".: 19: 0\n" /* sponge */ + ".: 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 */, + "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 - "........." - "aa......." - "aa......." - "aa......." - "........." + /* z\x* 012345678 */ + /* 0 */ "mmmmmmmmm" + /* 1 */ "aabmmmmmm" + /* 2 */ "aabmmmmmm" + /* 3 */ "aabmmmmmm" + /* 4 */ "mmmmmmmmm" // Level 2 - "........." - "aab......" - "aab......" - "aab......" - "........." + /* z\x* 012345678 */ + /* 0 */ "mmmmmmmmm" + /* 1 */ "aaabcmmmm" + /* 2 */ "aaabcmmmm" + /* 3 */ "aaabcmmmm" + /* 4 */ "mmmmmmmmm" // Level 3 - "........." - "aaabc...." - "aaabc...." - "aaabc...." - "........." + /* z\x* 012345678 */ + /* 0 */ "dddddddmm" + /* 1 */ "aaaaaaaam" + /* 2 */ "aaaaaaaaa" + /* 3 */ "aaaaaaamm" + /* 4 */ "eeeeemmmm" // Level 4 - "ddddddd.." - "aaaaaaaa." - "aaaaaaaaa" - "aaaaaaa.." - "eeeee...." + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaammmm" + /* 2 */ "aaaaaammm" + /* 3 */ "aaaaaammm" + /* 4 */ "aaaaaaaam" // Level 5 - "aaaaaaaaa" - "aaaaa...." - "aaaaaa..." - "aaaaaa..." - "aaaaaaaa." - - // Level 6 - "aaaaaa..." - "........." - "........." - "........." - "aaaaaaa..", + /* z\x* 012345678 */ + /* 0 */ "aaaaaammm" + /* 1 */ "mmmmmmmmm" + /* 2 */ "mmmmmmmmm" + /* 3 */ "mmmmmmmmm" + /* 4 */ "aaaaaaamm", - // Connections: - "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */, + // 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, }, // BridgeCrumble1 + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // BridgeCrumble2 - // The data has been exported from gallery Nether, area index 18, ID 160 + // 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: - ".: 19: 0\n" /* sponge */ + ".: 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 */, + "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: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|2:0|3:0|4:0|5:0", + + // AddWeightIfSame: + 0, + }, // 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, 6, 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 - "............." - "aa..........." - "aa..........." - "aa..........." - "............." + /* 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 - "............." - "aab.........." - "aab.........." - "aab.........." - "............." + /* 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 - "............." - "aaabc........" - "aaabc........" - "aaabc........" - "............." + /* 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 - "ddddddddd...." - "aaaaaaaaaaaaa" - "aaaaaaaaa...." - "aaaaaaaaaaaa." - "eeeeeeeee...." + /* 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 - "aaaaaaaaaaaa." - "aaaaaaaaaa..." - "aaaaaaaaaaa.." - "aaaaaaaaa...." - "aaaaaaaaaaaaa" + /* 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 - "aaaaaaaaa...." - "............." - "............." - "............." - "aaaaaaaaaa...", + /* 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+ */, - // Connections: - "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */, + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 1000, + }, // 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, - }, // BridgeCrumble2 + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 5, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // BridgeFunnelDown + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // BridgeSegment: - // The data has been exported from gallery Nether, area index 16, ID 158 + // BridgeLevelCrossing: + // The data has been exported from the gallery Nether, area index 61, ID 321, created by Aloe_vera { // Size: - 15, 8, 5, // SizeX = 15, SizeY = 8, SizeZ = 5 + 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 */ @@ -782,80 +1640,443 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "mmmmmmmmmmmmmmm" - "aammmmmmmmmmmaa" - "aammmmmmmmmmmaa" - "aammmmmmmmmmmaa" - "mmmmmmmmmmmmmmm" + /* 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 - "mmmmmmmmmmmmmmm" - "aabmmmmmmmmmcaa" - "aabmmmmmmmmmcaa" - "aabmmmmmmmmmcaa" - "mmmmmmmmmmmmmmm" + /* 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 - "mmmmmmmmmmmmmmm" - "aaabdmmmmmdcaaa" - "aaabdmmmmmdcaaa" - "aaabdmmmmmdcaaa" - "mmmmmmmmmmmmmmm" + /* 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 - "eeeeeeeeeeeeeee" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "fffffffffffffff" + /* 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 - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaaaaa" - "..............." - "..............." - "..............." - "aaaaaaaaaaaaaaa" + /* 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 - "mmmmmmmmmmmmmmm" - "..............." - "..............." - "..............." - "mmmmmmmmmmmmmmm" + /* 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 - "mmmmmmmmmmmmmmm" - "..............." - "..............." - "..............." - "mmmmmmmmmmmmmmm", + /* 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: + false, + + // DefaultWeight: + 20, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // 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" - // Connections: - "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */ - "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */, + // 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 500, + + // DepthWeight: + "4:-3000|8:-3000|12:-3000|16:-3000|20:-3000", + + // AddWeightIfSame: + 1000, }, // BridgeSegment + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BridgeTee: - // The data has been exported from gallery Nether, area index 39, ID 290 + // 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 */ @@ -867,258 +2088,446 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "mmmmmmmmmmmmmmm" - "aammmmmmmmmmmaa" - "aammmmmmmmmmmaa" - "aammmmmmmmmmmaa" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" + /* 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 - "mmmmmmmmmmmmmmm" - "aabmmmmmmmmmcaa" - "aabmmmmmmmmmcaa" - "aabmmmmmmmmmcaa" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmmmmmmmmmm" - "mmmmmmdddmmmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" + /* 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 - "mmmmmmmmmmmmmmm" - "aaabemmmmmecaaa" - "aaabemmmmmecaaa" - "aaabemmmmmecaaa" - "mmmmmmmmmmmmmmm" - "mmmmmmeeemmmmmm" - "mmmmmmdddmmmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" - "mmmmmmaaammmmmm" + /* 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 - "ddddddddddddddd" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "fffffcaaabfffff" - "mmmmmcaaabmmmmm" - "mmmmmcaaabmmmmm" - "mmmmmcaaabmmmmm" - "mmmmmcaaabmmmmm" - "mmmmmcaaabmmmmm" + /* 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 - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" - "mmmmmaaaaammmmm" + /* 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 - "aaaaaaaaaaaaaaa" - "..............." - "..............." - "..............." - "aaaaaa...aaaaaa" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" - "mmmmma...ammmmm" + /* 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 - "mmmmmmmmmmmmmmm" - "..............." - "..............." - "..............." - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - - // Level 8 - "mmmmmmmmmmmmmmm" - "..............." - "..............." - "..............." - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm" - "mmmmmm...mmmmmm", - - // Connections: - "0: 0, 5, 2: 4\n" /* Type 0, BLOCK_FACE_XM */ - "0: 14, 5, 2: 5\n" /* Type 0, BLOCK_FACE_XP */ - "0: 7, 5, 9: 3\n" /* Type 0, BLOCK_FACE_ZP */, + /* 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "1:500", + + // AddWeightIfSame: + 0, }, // BridgeTee + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Corridor11: - // The data has been exported from gallery Nether, area index 36, ID 287 + // 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 */, + "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 - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "aaaaaaaaaaa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "aaaaaaaaaaa" // Level 2 - "aaaaaaaaaaa" - "..........." - "..........." - "..........." - "aaaaaaaaaaa" + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "abababababa" // Level 3 - "abababababa" - "..........." - "..........." - "..........." - "abababababa" + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "abababababa" // Level 4 - "abababababa" - "..........." - "..........." - "..........." - "abababababa" + /* z\x* 1 */ + /* * 01234567890 */ + /* 0 */ "abababababa" + /* 1 */ "..........." + /* 2 */ "..........." + /* 3 */ "..........." + /* 4 */ "abababababa" // Level 5 - "abababababa" - "..........." - "..........." - "..........." - "abababababa" - - // Level 6 - "ccccccccccc" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "ddddddddddd", - - // Connections: - "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */, + /* 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- */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 300, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // Corridor11 + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Corridor13: - // The data has been exported from gallery Nether, area index 35, ID 286 + // 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: - "a:112: 0\n" /* netherbrick */ ".: 0: 0\n" /* air */ - "c:113: 0\n" /* netherbrickfence */ - "d:114: 2\n" /* netherbrickstairs */ - "e:114: 3\n" /* netherbrickstairs */, + "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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "aaaaaaaaaaaaa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "aaaaaaaaaaaaa" // Level 2 - "aaaaaaaaaaaaa" - "............." - "............." - "............." - "aaaaaaaaaaaaa" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ababababababa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "ababababababa" // Level 3 - "acacacacacaca" - "............." - "............." - "............." - "acacacacacaca" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ababababababa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "ababababababa" // Level 4 - "acacacacacaca" - "............." - "............." - "............." - "acacacacacaca" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "ababababababa" + /* 1 */ "............." + /* 2 */ "............." + /* 3 */ "............." + /* 4 */ "ababababababa" // Level 5 - "acacacacacaca" - "............." - "............." - "............." - "acacacacacaca" + /* 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- */, - // Level 6 - "ddddddddddddd" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "eeeeeeeeeeeee", - - // Connections: - "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 12, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */, - // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 300, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // 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- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 500, + + // DepthWeight: + "6:0|12:0|18:0", + + // AddWeightIfSame: + 500, + }, // Corridor5 + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CorridorCorner5: - // The data has been exported from gallery Nether, area index 10, ID 40 + // 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 */ @@ -1130,211 +2539,391 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" + /* 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 - "aaaaaaaaaaa" - "a.........." - "a.........." - "a.........." - "a...aaaaaaa" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" + /* 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 - "abababababa" - "b.........." - "a.........." - "b.........." - "a...abababa" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" + /* 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 - "abababababa" - "b.........." - "a.........." - "b.........." - "a...abababa" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" + /* 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 - "abababababa" - "b.........." - "a.........." - "b.........." - "a...abababa" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - - // Level 6 - "ccccccccccc" - "daaaaaaaaaa" - "daaaaaaaaaa" - "daaaaaaaaaa" - "daaaeeeeeee" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm", - - // Connections: - "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */ - "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */, + /* 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+ */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // CorridorCorner5 - // CorridorCorner5: - // The data has been exported from gallery Nether, area index 10, ID 40 + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // 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:113: 0\n" /* netherbrickfence */ - "c:114: 2\n" /* netherbrickstairs */ + "b: 54: 5\n" /* chest */ + "c:113: 0\n" /* netherbrickfence */ "d:114: 0\n" /* netherbrickstairs */ - "e:114: 3\n" /* netherbrickstairs */ + "e:114: 2\n" /* netherbrickstairs */ "f:114: 1\n" /* netherbrickstairs */ - "g: 54: 5\n" /* chest */ + "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 - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaaaaaaaa" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" - "aaaaammmmmm" + /* 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 - "aaaaaaaaaaa" - "ag........." - "a.........." - "a.........." - "a...aaaaaaa" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" - "a...ammmmmm" + /* 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 - "abababababa" - "b.........." - "a.........." - "b.........." - "a...abababa" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" + /* 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 - "abababababa" - "b.........." - "a.........." - "b.........." - "a...abababa" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" + /* 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 - "abababababa" - "b.........." - "a.........." - "b.........." - "a...abababa" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" - "b...bmmmmmm" - "a...ammmmmm" + /* 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+ */, - // Level 6 - "ccccccccccc" - "daaaaaaaaaa" - "daaaaaaaaaa" - "daaaaaaaaaa" - "daaaeeeeeee" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm" - "daaafmmmmmm", - - // Connections: - "1: 10, 1, 2: 5\n" /* Type 1, BLOCK_FACE_XP */ - "1: 2, 1, 10: 3\n" /* Type 1, BLOCK_FACE_ZP */, + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // 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- */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, - }, // CorridorCorner5Chest + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -50, + }, // CorridorCrossing + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CorridorStairs: - // The data has been exported from gallery Nether, area index 12, ID 42 + // 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 */ @@ -1342,611 +2931,1109 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "c:113: 0\n" /* netherbrickfence */ "d:114: 2\n" /* netherbrickstairs */ "e:114: 3\n" /* netherbrickstairs */ - "f: 19: 0\n" /* sponge */, + "m: 19: 0\n" /* sponge */, // Block data: + // Level 0 + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ "aaaaaaaaa" + /* 2 */ "aaaaaaaaa" + /* 3 */ "aaaaaaaaa" + /* 4 */ "aaaaaaaaa" + // Level 1 - "aaaaaaaaa" - "aaaaaaaaa" - "aaaaaaaaa" - "aaaaaaaaa" - "aaaaaaaaa" + /* z\x* 012345678 */ + /* 0 */ "aaaaaaaaa" + /* 1 */ ".baaaaaaa" + /* 2 */ ".baaaaaaa" + /* 3 */ ".baaaaaaa" + /* 4 */ "aaaaaaaaa" // Level 2 - "aaaaaaaaa" - ".baaaaaaa" - ".baaaaaaa" - ".baaaaaaa" - "aaaaaaaaa" + /* z\x* 012345678 */ + /* 0 */ "acaaaaaaa" + /* 1 */ "..baaaaaa" + /* 2 */ "..baaaaaa" + /* 3 */ "..baaaaaa" + /* 4 */ "acaaaaaaa" // Level 3 - "acaaaaaaa" - "..baaaaaa" - "..baaaaaa" - "..baaaaaa" - "acaaaaaaa" + /* z\x* 012345678 */ + /* 0 */ "acaaaaaaa" + /* 1 */ "...baaaaa" + /* 2 */ "...baaaaa" + /* 3 */ "...baaaaa" + /* 4 */ "acaaaaaaa" // Level 4 - "acaaaaaaa" - "...baaaaa" - "...baaaaa" - "...baaaaa" - "acaaaaaaa" + /* z\x* 012345678 */ + /* 0 */ "acacaaaaa" + /* 1 */ "....baaaa" + /* 2 */ "....baaaa" + /* 3 */ "....baaaa" + /* 4 */ "acacaaaaa" // Level 5 - "acacaaaaa" - "....baaaa" - "....baaaa" - "....baaaa" - "acacaaaaa" + /* z\x* 012345678 */ + /* 0 */ "aaacaaaaa" + /* 1 */ ".....baaa" + /* 2 */ ".....baaa" + /* 3 */ ".....baaa" + /* 4 */ "aaacaaaaa" // Level 6 - "aaacaaaaa" - ".....baaa" - ".....baaa" - ".....baaa" - "aaacaaaaa" + /* z\x* 012345678 */ + /* 0 */ "daacacaaa" + /* 1 */ "a.....baa" + /* 2 */ "a.....baa" + /* 3 */ "a.....baa" + /* 4 */ "eaacacaaa" // Level 7 - "daacacaaa" - "a.....baa" - "a.....baa" - "a.....baa" - "eaacacaaa" + /* z\x* 012345678 */ + /* 0 */ "mdaaacaaa" + /* 1 */ "ma.....ba" + /* 2 */ "ma.....ba" + /* 3 */ "ma.....ba" + /* 4 */ "meaaacaaa" // Level 8 - "fdaaacaaa" - "fa.....ba" - "fa.....ba" - "fa.....ba" - "feaaacaaa" + /* z\x* 012345678 */ + /* 0 */ "mmdaacaca" + /* 1 */ "mma......" + /* 2 */ "mma......" + /* 3 */ "mma......" + /* 4 */ "mmeaacaca" // Level 9 - "ffdaacaca" - "ffa......" - "ffa......" - "ffa......" - "ffeaacaca" + /* z\x* 012345678 */ + /* 0 */ "mmmdaaaca" + /* 1 */ "mmma....." + /* 2 */ "mmma....." + /* 3 */ "mmma....." + /* 4 */ "mmmeaaaca" // Level 10 - "fffdaaaca" - "fffa....." - "fffa....." - "fffa....." - "fffeaaaca" + /* z\x* 012345678 */ + /* 0 */ "mmmmdaaca" + /* 1 */ "mmmma...." + /* 2 */ "mmmma...." + /* 3 */ "mmmma...." + /* 4 */ "mmmmeaaca" // Level 11 - "ffffdaaca" - "ffffa...." - "ffffa...." - "ffffa...." - "ffffeaaca" + /* z\x* 012345678 */ + /* 0 */ "mmmmmdaaa" + /* 1 */ "mmmmma..." + /* 2 */ "mmmmma..." + /* 3 */ "mmmmma..." + /* 4 */ "mmmmmeaaa" // Level 12 - "fffffdaaa" - "fffffa..." - "fffffa..." - "fffffa..." - "fffffeaaa" + /* 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+ */, - // Level 13 - "ffffffddd" - "ffffffaaa" - "ffffffaaa" - "ffffffaaa" - "ffffffeee", - - // Connections: - "1: 0, 1, 2: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 8, 8, 2: 5\n" /* Type 1, BLOCK_FACE_XP */, - // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // 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, }, // 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+ */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // DarkCorridor + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // LavaStaircase: - // The data has been exported from gallery Nether, area index 28, ID 278 + // 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: 11: 0\n" /* lava */, + "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 - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" + /* 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 - "aaaaaaaa...aaaa" - "aaaaa.........a" - "aaaaa.........a" - "aaaaab........a" - "accca...aaaa..a" - "accca...acca..a" - "acccaaaaacca..a" - "acccccccccca..a" - "acccaaaaacca..a" - "accca...acca..a" - "accca...aaaa..a" - "aaaaab........a" - "aaaaa.........a" - "aaaaa.........a" - "aaaaaaaa...aaaa" + /* 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 - "aaaaaaaa...aaaa" - "aaaa..........a" - "aaaa..........a" - "aaaabb........a" - "aaaa..........a" - "a.............a" - "a.............a" - "a.............a" - "a.............a" - "a.............a" - "aaaa..........a" - "aaaabb........a" - "aaaa..........a" - "aaaa..........a" - "aaaaaaaa...aaaa" + /* 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 - "aaaaaaaa...aaaa" - "a.............a" - "a.............a" - "a..bb.........a" - "aaaa..........a" - "aaaa..........a" - "a.............a" - "a.............a" - "a.............a" - "aaaa..........a" - "aaaa..........a" - "a..bb.........a" - "a.............a" - "a.............a" - "aaaaaaaa...aaaa" + /* 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 - "aaaaaaaabbbaaaa" - "a.............a" - "a.............a" - "a..b..........a" - "a..b..........a" - "aaaa..........a" - "aaaa..........a" - "a.............a" - "aaaa..........a" - "aaaa..........a" - "a..b..........a" - "a..b..........a" - "a.............a" - "a.............a" - "aaaaaaaabbbaaaa" + /* 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 - "aaaaaaaaaaaaaaa" - "a.............a" - "a.............a" - "a.............a" - "a..b..........a" - "a..b..........a" - "aaaa..........a" - "aaaa..........a" - "aaaa..........a" - "a..b..........a" - "a..b..........a" - "a.............a" - "a.............a" - "a.............a" - "aaaaaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaaaaa" - "a.............a" - "a.............a" - "a.............a" - "a.............a" - "a..b..........a" - "...b..........a" - "...b..........a" - "...b..........a" - "a..b..........a" - "a.............a" - "a.............a" - "a.............a" - "a.............a" - "aaaaaaaaaaaaaaa" + /* 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 - "aababababababaa" - "a.............a" - "b.............b" - "a.............a" - "b.............b" - "a.............a" - "..............b" - "..............a" - "..............b" - "a.............a" - "b.............b" - "a.............a" - "b.............b" - "a.............a" - "aababababababaa" + /* 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 - "aababababababaa" - "a.............a" - "b.............b" - "a.............a" - "b.............b" - "a.............a" - "..............b" - "..............a" - "..............b" - "a.............a" - "b.............b" - "a.............a" - "b.............b" - "a.............a" - "aababababababaa" + /* 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 - "aababababababaa" - "a.............a" - "b.............b" - "a.............a" - "b.............b" - "a.............a" - "..............b" - "..............a" - "..............b" - "a.............a" - "b.............b" - "a.............a" - "b.............b" - "a.............a" - "aababababababaa" - - // Level 11 - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa" - "aaaaaaaaaaaaaaa", - - // Connections: - "1: 0, 6, 7: 4\n" /* Type 1, BLOCK_FACE_XM */ - "0: 9, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */ - "0: 9, 1, 14: 3\n" /* Type 0, BLOCK_FACE_ZP */, + /* 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- */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // LavaStaircase + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // LavaStaircaseBig: - // The data has been exported from gallery Nether, area index 31, ID 282 + // 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 */, + "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 - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "abbbbbaaaaaa" - "abbbbbbaaaaa" - "abbbbbba...." - "abbbbbba...." - "abbbbbba...." - "abbbbbbaaaaa" - "abbbbb.aaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "abbbbbaaaaaa" - "abbbbbba...a" - "abbbbbba...." - "abbbbbba...." - "abbbbbba...." - "abbbbbba...a" - "abbbbb.aaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "abbbbbaa...a" - "abbbbbba...a" - "abbbbbba...." - "abbbbbba...." - "abbbbbba...." - "abbbbbba...a" - "abbbbbaa...a" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "aaaaa......a" - "aaaaa......a" - "aaaaacc....a" - "a.....cc...a" - "a......c...a" - "a......c...." - "a......c...." - "a......c...." - "a......c...a" - "a.....cc...a" - "aaaaacc....a" - "aaaaa......a" - "aaaaa......a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "aaaa.......a" - "aaaa.......a" - "aaaacc.....a" - "aaaa.......a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "aaaa.......a" - "aaaacc.....a" - "aaaa.......a" - "aaaa.......a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..cc......a" - "aaaa.......a" - "aaaa.......a" - "a..........a" - "a..........a" - "a..........a" - "aaaa.......a" - "aaaa.......a" - "a..cc......a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..c.......a" - "a..c.......a" - "aaaa.......a" - "aaaa.......a" - "a..........a" - "aaaa.......a" - "aaaa.......a" - "a..c.......a" - "a..c.......a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..........a" - "a..c.......a" - "a..c.......a" - "aaaa.......a" - "aaaa.......a" - "aaaa.......a" - "a..c.......a" - "a..c.......a" - "a..........a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..c.......a" - "...c.......a" - "...c.......a" - "...c.......a" - "a..c.......a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "...........a" - "...........a" - "...........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "...........a" - "...........a" - "...........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "...........a" - "...........a" - "...........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "a..........a" - "aaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - "aaaaaaaaaaaa" - - // Level 15 - "aaaaaaaaaaaa" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "abbbbbbbbbba" - "aaaaaaaaaaaa", - - // Connections: - "1: 0, 9, 7: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 11, 1, 7: 5\n" /* Type 1, BLOCK_FACE_XP */, + /* 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- */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + -1000, }, // 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: + false, + + // DefaultWeight: + 10, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // LavaStairsBridge + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // MidStaircase: - // The data has been exported from gallery Nether, area index 23, ID 165 + // 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 */ @@ -1957,148 +4044,182 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "f:114: 1\n" /* netherbrickstairs */ "g:114: 2\n" /* netherbrickstairs */ "h: 10: 0\n" /* lava */ - "i:113: 0\n" /* netherbrickfence */, + "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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaabbbbbaaaa" - "aaaabbbbbaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaabbbbbaaaa" - "aaaabbbbbaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaacccccaaaa" - "addecccccfdda" - "...eaaaaad..." - "...eaaaaa...." - "...eaaaaag..." - "agggcccccfgga" - "aaaacccccaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaaa" - "aha.......aha" - "aaa.......aaa" - "a...........a" - "a...........a" - "....eaaaa...." - "....eaaaa...." - "....eaaaa...." - "a...........a" - "a...........a" - "aaa.......aaa" - "aha.......aha" - "aaaaaaaaaaaaa" + /* 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 - "aaaiiaaaiiaaa" - "a...........a" - "a...........a" - "a...........a" - "a...........a" - ".....eaaa...." - ".....eaaa...." - ".....eaaa...." - "a...........a" - "a...........a" - "a...........a" - "a...........a" - "aaaiiaaaiiaaa" + /* 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 - "aaaiiaaaiiaaa" - "a...........a" - "a...........a" - "a...........a" - "a...........a" - "......eaa...." - "......eaa...." - "......eaa...." - "a...........a" - "a...........a" - "a...........a" - "a...........a" - "aaaiiaaaiiaaa" + /* 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 - "aaaaaaaaaaaaa" - "a...........a" - "a...........a" - "a...........a" - "a...........a" - "a......ea...a" - "a......ea...a" - "a......ea...a" - "a...........a" - "a...........a" - "a...........a" - "a...........a" - "aaaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaa....eaaaa" - "aaaa....eaaaa" - "aaaa....eaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - - // Level 8 - "iaiaiaiaiaiai" - "a...........a" - "i...........i" - "a...........a" - "i...........i" - "a............" - "i............" - "a............" - "i...........i" - "a...........a" - "i...........i" - "a...........a" - "iaiaiaiaiaiai", - - // Connections: - "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */ - "1: 12, 7, 6: 5\n" /* Type 1, BLOCK_FACE_XP */, + /* 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- */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -1000, }, // MidStaircase + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // StairsToOpen1: - // The data has been exported from gallery Nether, area index 27, ID 277 + // 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 */ @@ -2106,114 +4227,142 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" // Level 2 - "aa...aa" - "a.....a" - "a.....a" - "a.....a" - "a.....a" - "aaaaaaa" - "aaaaaaa" + /* 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 - "aa...aa" - "a.....a" - "b.....b" - "a.....a" - "b.....b" - "a.aaaaa" - "aabaaba" + /* 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 - "aa...aa" - "a.....a" - "b.....b" - "a.....a" - "b.....b" - "a..aaaa" - "aabaaba" + /* z\x* 0123456 */ + /* 0 */ "aabbbaa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a...aaa" + /* 6 */ "aabaaba" // Level 5 - "aabbbaa" - "a.....a" - "b.....b" - "a.....a" - "b.....b" - "a...aaa" - "aabaaba" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "a....aa" + /* 6 */ "aaaaaaa" // Level 6 - "aaaaaaa" - "a.....a" - "a.....a" - "a.....a" - "a.....a" - "a....aa" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" // Level 7 - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "a.....a" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a......" + /* 3 */ "a......" + /* 4 */ "a......" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" // Level 8 - "aaaaaaa" - "a.....a" - "a......" - "a......" - "a......" - "a.....a" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "m.....m" + /* 2 */ "m......" + /* 3 */ "m......" + /* 4 */ "m......" + /* 5 */ "m.....m" + /* 6 */ "mmmmmmm" // Level 9 - "mmmmmmm" - "m.....m" - "m......" - "m......" - "m......" - "m.....m" - "mmmmmmm" - - // Level 10 - "mmmmmmm" - "m.....m" - "m......" - "m......" - "m......" - "m.....m" - "mmmmmmm", - - // Connections: - "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */ - "0: 6, 7, 3: 5\n" /* Type 0, BLOCK_FACE_XP */, + /* 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|3:0|5:0|7:0|9:0|11:0|13:0|15:0", + + // AddWeightIfSame: + 0, }, // StairsToOpen1 + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // StairsToOpen2: - // The data has been exported from gallery Nether, area index 8, ID 35 + // 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 */ @@ -2221,114 +4370,142 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "aaaaaaa" + /* 6 */ "aaaaaaa" // Level 2 - "aa...aa" - "a.....a" - "a.....a" - "a.....a" - "a.....a" - "aaaaaaa" - "aaaaaaa" + /* 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 - "aa...aa" - "a.....a" - "b.....b" - "a.....a" - "b.....b" - "a.aaaaa" - "aabaaba" + /* 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 - "aa...aa" - "a.....a" - "b.....b" - "a.....a" - "b.....b" - "a..aaaa" - "aabaaba" + /* z\x* 0123456 */ + /* 0 */ "aabbbaa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "a.....a" + /* 4 */ "b.....b" + /* 5 */ "a...aaa" + /* 6 */ "aabaaba" // Level 5 - "aabbbaa" - "a.....a" - "b.....b" - "a.....a" - "b.....b" - "a...aaa" - "aabaaba" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "a....aa" + /* 6 */ "aaaaaaa" // Level 6 - "aaaaaaa" - "a.....a" - "a.....a" - "a.....a" - "a.....a" - "a....aa" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "aaaaaaa" + /* 2 */ "aaaaaaa" + /* 3 */ "aaaaaaa" + /* 4 */ "aaaaaaa" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" // Level 7 - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "a.....a" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "......a" + /* 3 */ "......a" + /* 4 */ "......a" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" // Level 8 - "aaaaaaa" - "a.....a" - "......a" - "......a" - "......a" - "a.....a" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "mmmmmmm" + /* 1 */ "m.....m" + /* 2 */ "......m" + /* 3 */ "......m" + /* 4 */ "......m" + /* 5 */ "m.....m" + /* 6 */ "mmmmmmm" // Level 9 - "mmmmmmm" - "m.....m" - "......m" - "......m" - "......m" - "m.....m" - "mmmmmmm" - - // Level 10 - "mmmmmmm" - "m.....m" - "......m" - "......m" - "......m" - "m.....m" - "mmmmmmm", - - // Connections: - "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */ - "0: 0, 7, 3: 4\n" /* Type 0, BLOCK_FACE_XM */, + /* 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:0|3:0|5:0|7:0|9:0|11:0|13:0|15:0", + + // AddWeightIfSame: + 0, }, // StairsToOpen2 + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Tee2x4: - // The data has been exported from gallery Nether, area index 40, ID 291 + // 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 */ @@ -2340,79 +4517,109 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "mmmmaaaaammmm" - "mmmmaaaaammmm" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmma...ammmm" + /* 2 */ "aaaaa...aaaaa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "aaaaaaaaaaaaa" // Level 2 - "mmmma...ammmm" - "mmmma...ammmm" - "aaaaa...aaaaa" - "............." - "............." - "............." - "aaaaaaaaaaaaa" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "ababa...ababa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "ababababababa" // Level 3 - "mmmma...ammmm" - "mmmmb...bmmmm" - "ababa...ababa" - "............." - "............." - "............." - "ababababababa" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "ababa...ababa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "ababababababa" // Level 4 - "mmmma...ammmm" - "mmmmb...bmmmm" - "ababa...ababa" - "............." - "............." - "............." - "ababababababa" + /* z\x* 111 */ + /* * 0123456789012 */ + /* 0 */ "mmmma...ammmm" + /* 1 */ "mmmmb...bmmmm" + /* 2 */ "ababa...ababa" + /* 3 */ "............." + /* 4 */ "............." + /* 5 */ "............." + /* 6 */ "ababababababa" // Level 5 - "mmmma...ammmm" - "mmmmb...bmmmm" - "ababa...ababa" - "............." - "............." - "............." - "ababababababa" - - // Level 6 - "mmmmcaaadmmmm" - "mmmmcaaadmmmm" - "eeeecaaadeeee" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "fffffffffffff", - - // Connections: - "1: 0, 1, 4: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */ - "1: 12, 1, 4: 5\n" /* Type 1, BLOCK_FACE_XP */, + /* 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+ */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // Tee2x4 + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Tee4x4: - // The data has been exported from gallery Nether, area index 41, ID 292 + // 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 */ @@ -2424,335 +4631,718 @@ const cPrefab::sDef g_NetherFortPrefabs1[] = "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 - "mmmmaaaaammmm" - "mmmmaaaaammmm" - "mmmmaaaaammmm" - "mmmmaaaaammmm" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "mmmma...ammmm" - "mmmma...ammmm" - "mmmma...ammmm" - "mmmma...ammmm" - "aaaaa...aaaaa" - "............." - "............." - "............." - "aaaaaaaaaaaaa" + /* 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 - "mmmma...ammmm" - "mmmmb...bmmmm" - "mmmma...ammmm" - "mmmmb...bmmmm" - "ababa...ababa" - "............." - "............." - "............." - "ababababababa" + /* 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 - "mmmma...ammmm" - "mmmmb...bmmmm" - "mmmma...ammmm" - "mmmmb...bmmmm" - "ababa...ababa" - "............." - "............." - "............." - "ababababababa" + /* 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 - "mmmma...ammmm" - "mmmmb...bmmmm" - "mmmma...ammmm" - "mmmmb...bmmmm" - "ababa...ababa" - "............." - "............." - "............." - "ababababababa" - - // Level 6 - "mmmmcaaadmmmm" - "mmmmcaaadmmmm" - "mmmmcaaadmmmm" - "mmmmcaaadmmmm" - "eeeecaaadeeee" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "fffffffffffff", - - // Connections: - "1: 0, 1, 6: 4\n" /* Type 1, BLOCK_FACE_XM */ - "1: 12, 1, 6: 5\n" /* Type 1, BLOCK_FACE_XP */ - "1: 6, 1, 0: 2\n" /* Type 1, BLOCK_FACE_ZM */, + /* 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+ */, // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, }, // 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- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -50, + }, // 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- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // 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- */, + + // AllowedRotations: + 7, /* 1, 2, 3 CCW rotation allowed */ + + // Merge strategy: + cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "1:200|2:400|3:0|4:500", + + // AddWeightIfSame: + -50, + }, // TinyCorridorCrossing + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Turret: - // The data has been exported from gallery Nether, area index 7, ID 34 + // The data has been exported from the gallery Nether, area index 7, ID 34, created by xoft { // Size: - 7, 6, 7, // SizeX = 7, SizeY = 6, SizeZ = 7 + 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 */, + "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 - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" - "aaaaaaa" + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "a.....a" + /* 6 */ "aa...aa" // Level 2 - "aa...aa" - "a.....a" - "......." - "......." - "......." - "a.....a" - "aa...aa" + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "a.....a" + /* 6 */ "aa...aa" // Level 3 - "aa...aa" - "a.....a" - "......." - "......." - "......." - "a.....a" - "aa...aa" + /* z\x* 0123456 */ + /* 0 */ "aa...aa" + /* 1 */ "a.....a" + /* 2 */ "......." + /* 3 */ "......." + /* 4 */ "......." + /* 5 */ "a.....a" + /* 6 */ "aa...aa" // Level 4 - "aa...aa" - "a.....a" - "......." - "......." - "......." - "a.....a" - "aa...aa" + /* z\x* 0123456 */ + /* 0 */ "aabbbaa" + /* 1 */ "a.....a" + /* 2 */ "b.....b" + /* 3 */ "b.....b" + /* 4 */ "b.....b" + /* 5 */ "a.....a" + /* 6 */ "aabbbaa" // Level 5 - "aabbbaa" - "a.....a" - "b.....b" - "b.....b" - "b.....b" - "a.....a" - "aabbbaa" + /* z\x* 0123456 */ + /* 0 */ "aaaaaaa" + /* 1 */ "a.....a" + /* 2 */ "a.....a" + /* 3 */ "a.....a" + /* 4 */ "a.....a" + /* 5 */ "a.....a" + /* 6 */ "aaaaaaa" // Level 6 - "aaaaaaa" - "a.....a" - "a.....a" - "a.....a" - "a.....a" - "a.....a" - "aaaaaaa", - - // Connections: - "0: 0, 1, 3: 4\n" /* Type 0, BLOCK_FACE_XM */ - "0: 3, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */ - "0: 6, 1, 3: 5\n" /* Type 0, BLOCK_FACE_XP */ - "0: 3, 1, 6: 3\n" /* Type 0, BLOCK_FACE_ZP */, + /* 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 rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, + + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + -99, }, // Turret +}; // g_NetherFortPrefabs -} ; // g_NetherFortPrefabs1 -const cPrefab::sDef g_NetherFortStartingPrefabs1[] = +const cPrefab::sDef g_NetherFortStartingPrefabs[] = { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // CentralRoom: - // The data has been exported from gallery Nether, area index 22, ID 164 + // 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: 0: 0\n" /* air */ - "c: 10: 0\n" /* lava */ - "d:113: 0\n" /* netherbrickfence */, + "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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "aaaaabbbaaaaa" - "aaaaabbbaaaaa" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" - "aabbbaaabbbaa" - "aabbbacabbbaa" - "aabbbaaabbbaa" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" - "aabbbbbbbbbaa" - "aaaaabbbaaaaa" - "aaaaabbbaaaaa" + /* 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 - "aaaaabbbaaaaa" - "aaadabbbadaaa" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "aaadabbbadaaa" - "aaaaabbbaaaaa" + /* 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 - "aaaaabbbaaaaa" - "aaadabbbadaaa" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "adbbbbbbbbbda" - "aabbbbbbbbbaa" - "aaadabbbadaaa" - "aaaaabbbaaaaa" + /* 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 - "adadadddadada" - "daaaabbbaaaad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "daaaabbbaaaad" - "adadabbbadada" + /* 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 - "adadaaaaadada" - "daaaaaaaaaaad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "dabbbbbbbbbad" - "aabbbbbbbbbaa" - "daaaaaaaaaaad" - "adadaaaaadada" + /* 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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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 - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" - "aaaaaaaaaaaaa" + /* 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+ */, - // Level 9 - "dadadadadadad" - "abbbbbbbbbbba" - "dbbbbbbbbbbbd" - "abbbbbbbbbbba" - "dbbbbbbbbbbbd" - "abbbbbbbbbbba" - "dbbbbbbbbbbbd" - "abbbbbbbbbbba" - "dbbbbbbbbbbbd" - "abbbbbbbbbbba" - "dbbbbbbbbbbbd" - "abbbbbbbbbbba" - "dadadadadadad", - - // Connections: - "0: 6, 1, 0: 2\n" /* Type 0, BLOCK_FACE_ZM */ - "1: 6, 1, 12: 3\n" /* Type 1, BLOCK_FACE_ZP */, - // AllowedRotations: - 7, /* 1, 2, 3 CCW rotations */ - + 7, /* 1, 2, 3 CCW rotation allowed */ + // Merge strategy: cBlockArea::msSpongePrint, - }, -} ; // g_NetherFortStartingPrefabs1 -const size_t g_NetherFortPrefabs1Count = ARRAYCOUNT(g_NetherFortPrefabs1); -const size_t g_NetherFortStartingPrefabs1Count = ARRAYCOUNT(g_NetherFortStartingPrefabs1); + // ShouldExtendFloor: + false, + + // DefaultWeight: + 100, + + // DepthWeight: + "", + + // AddWeightIfSame: + 0, + }, // 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 index 37a91689d..04edc2953 100644 --- a/src/Generating/Prefabs/NetherFortPrefabs.h +++ b/src/Generating/Prefabs/NetherFortPrefabs.h @@ -1,7 +1,7 @@ // NetherFortPrefabs.h -// Declares the data used for nether fortress prefabs +// Declares the prefabs in the group NetherFort #include "../Prefab.h" @@ -9,7 +9,7 @@ -extern const cPrefab::sDef g_NetherFortPrefabs1[]; -extern const cPrefab::sDef g_NetherFortStartingPrefabs1[]; -extern const size_t g_NetherFortPrefabs1Count; -extern const size_t g_NetherFortStartingPrefabs1Count; +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/Ravines.cpp b/src/Generating/Ravines.cpp index e64f55214..267dcbbf9 100644 --- a/src/Generating/Ravines.cpp +++ b/src/Generating/Ravines.cpp @@ -269,7 +269,7 @@ void cStructGenRavines::cRavine::GenerateBaseDefPoints(int a_BlockX, int a_Block 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); @@ -311,12 +311,13 @@ void cStructGenRavines::cRavine::RefineDefPoints(const cRavDefPoints & a_Src, cR 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; + 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 (int i = 0; i <= Num; ++i, ++itr) { int dx = itr->m_BlockX - PrevX; diff --git a/src/Group.cpp b/src/Group.cpp index 9c2467144..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; } 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/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/Item.cpp b/src/Item.cpp index 856b68be6..7e472f6d8 100644 --- a/src/Item.cpp +++ b/src/Item.cpp @@ -5,6 +5,8 @@ #include "json/json.h" #include "Items/ItemHandler.h" +#include "FastRandom.h" + @@ -196,9 +198,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 +208,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 910ecb382..00316c188 100644 --- a/src/Item.h +++ b/src/Item.h @@ -175,6 +175,13 @@ 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; 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..08cddb1ad --- /dev/null +++ b/src/Items/ItemArmor.h @@ -0,0 +1,67 @@ + +#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; + } + +} ; + + + + diff --git a/src/Items/ItemHandler.cpp b/src/Items/ItemHandler.cpp index 1e77717e3..ce9593a70 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" @@ -222,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); + } } } @@ -431,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); } diff --git a/src/Items/ItemHandler.h b/src/Items/ItemHandler.h index 5b6c239cc..4993eac85 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,48 @@ 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. + /** 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 +96,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/LightingThread.cpp b/src/LightingThread.cpp index 302473d71..5ba2940d2 100644 --- a/src/LightingThread.cpp +++ b/src/LightingThread.cpp @@ -286,6 +286,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/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 80fa7b173..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 } @@ -178,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; } @@ -211,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 c0150c124..114210f63 100644 --- a/src/MCLogger.h +++ b/src/MCLogger.h @@ -52,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/MobProximityCounter.cpp b/src/MobProximityCounter.cpp index 6c44ea458..519757c2c 100644 --- a/src/MobProximityCounter.cpp +++ b/src/MobProximityCounter.cpp @@ -34,7 +34,7 @@ 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))); } @@ -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/MobSpawner.cpp b/src/MobSpawner.cpp index 05da5d01c..ce8e06777 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) { @@ -112,7 +112,7 @@ cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) for(int i = 0; i < iRandom; i++) { - itr++; + ++itr; } return *itr; diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp index 0901f85a9..3e5f72dbf 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,18 @@ void cAggressiveMonster::Attack(float a_Dt) +bool cAggressiveMonster::IsMovingToTargetPosition() +{ + float epsilon = 0.000000000001; + // Difference between destination x and target x is negligible (to 10^-12 precision) + if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < epsilon) + { + return false; + } + // Difference between destination z and target z is negligible (to 10^-12 precision) + else if (fabsf(m_FinalDestination.z - (float)m_Target->GetPosZ()) > 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/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/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 aa6071515..14d951393 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -111,9 +111,9 @@ void cMonster::SpawnOn(cClientHandle & a_Client) void cMonster::TickPathFinding() { - const int PosX = (int)floor(GetPosX()); - const int PosY = (int)floor(GetPosY()); - const 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); @@ -148,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)); } @@ -402,7 +416,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; } } @@ -411,7 +425,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; @@ -526,7 +540,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; } @@ -744,8 +761,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; @@ -756,17 +775,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; } @@ -777,10 +799,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; @@ -842,13 +866,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; @@ -966,15 +991,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()) { @@ -986,7 +1011,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..6b9c4fab8 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 @@ -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/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/Villager.cpp b/src/Mobs/Villager.cpp index bbd8d6aaa..d049acc1e 100644 --- a/src/Mobs/Villager.cpp +++ b/src/Mobs/Villager.cpp @@ -30,7 +30,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI) { if (m_World->GetTickRandomNumber(5) == 3) { - m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY); + m_World->BroadcastEntityStatus(*this, esVillagerAngry); } } } diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp index 0d3619166..f02b8a4fc 100644 --- a/src/Mobs/Wolf.cpp +++ b/src/Mobs/Wolf.cpp @@ -75,12 +75,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..5925373e1 100644 --- a/src/Mobs/Wolf.h +++ b/src/Mobs/Wolf.h @@ -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 32922c8f3..95a022ea3 100644 --- a/src/Noise.cpp +++ b/src/Noise.cpp @@ -744,6 +744,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++) @@ -840,12 +842,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 +906,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/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/File.cpp b/src/OSSupport/File.cpp index 7f0f0ad2f..f1b3bcf9e 100644 --- a/src/OSSupport/File.cpp +++ b/src/OSSupport/File.cpp @@ -67,11 +67,11 @@ 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 diff --git a/src/OSSupport/GZipFile.cpp b/src/OSSupport/GZipFile.cpp index 7a8433f4f..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) { } 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/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/Protocol/Authenticator.cpp b/src/Protocol/Authenticator.cpp new file mode 100644 index 000000000..bbc656eda --- /dev/null +++ b/src/Protocol/Authenticator.cpp @@ -0,0 +1,347 @@ + +#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 "../ClientHandle.h" + +#include "inifile/iniFile.h" +#include "json/json.h" + +#include "polarssl/config.h" +#include "polarssl/net.h" +#include "polarssl/ssl.h" +#include "polarssl/entropy.h" +#include "polarssl/ctr_drbg.h" +#include "polarssl/error.h" +#include "polarssl/certs.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, server_fd = -1; + unsigned char buf[1024]; + const char *pers = "cAuthenticator"; + + entropy_context entropy; + ctr_drbg_context ctr_drbg; + ssl_context ssl; + x509_crt cacert; + + /* Initialize the RNG and the session data */ + memset(&ssl, 0, sizeof(ssl_context)); + x509_crt_init(&cacert); + + entropy_init(&entropy); + if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) + { + LOGWARNING("cAuthenticator: ctr_drbg_init returned %d", ret); + + // Free all resources which have been initialized up to this line + x509_crt_free(&cacert); + entropy_free(&entropy); + return false; + } + + /* Initialize certificates */ + // TODO: Grab the sessionserver's root CA and any intermediates and hard-code them here, instead of test_ca_list + ret = x509_crt_parse(&cacert, (const unsigned char *)test_ca_list, strlen(test_ca_list)); + + if (ret < 0) + { + LOGWARNING("cAuthenticator: x509_crt_parse returned -0x%x", -ret); + + // Free all resources which have been initialized up to this line + x509_crt_free(&cacert); + entropy_free(&entropy); + return false; + } + + /* Connect */ + if ((ret = net_connect(&server_fd, m_Server.c_str(), 443)) != 0) + { + LOGWARNING("cAuthenticator: Can't connect to %s: %d", m_Server.c_str(), ret); + + // Free all resources which have been initialized up to this line + x509_crt_free(&cacert); + entropy_free(&entropy); + return false; + } + + /* Setup */ + if ((ret = ssl_init(&ssl)) != 0) + { + LOGWARNING("cAuthenticator: ssl_init returned %d", ret); + + // Free all resources which have been initialized up to this line + x509_crt_free(&cacert); + net_close(server_fd); + ssl_free(&ssl); + entropy_free(&entropy); + memset(&ssl, 0, sizeof(ssl)); + return false; + } + ssl_set_endpoint(&ssl, SSL_IS_CLIENT); + ssl_set_authmode(&ssl, SSL_VERIFY_OPTIONAL); + ssl_set_ca_chain(&ssl, &cacert, NULL, "PolarSSL Server 1"); + ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg); + ssl_set_bio(&ssl, net_recv, &server_fd, net_send, &server_fd); + + /* Handshake */ + while ((ret = ssl_handshake(&ssl)) != 0) + { + if ((ret != POLARSSL_ERR_NET_WANT_READ) && (ret != POLARSSL_ERR_NET_WANT_WRITE)) + { + LOGWARNING("cAuthenticator: ssl_handshake returned -0x%x", -ret); + + // Free all resources which have been initialized up to this line + x509_crt_free(&cacert); + net_close(server_fd); + ssl_free(&ssl); + entropy_free(&entropy); + memset(&ssl, 0, sizeof(ssl)); + return false; + } + } + + /* Write the GET request */ + AString ActualAddress = m_Address; + ReplaceString(ActualAddress, "%USERNAME%", a_UserName); + ReplaceString(ActualAddress, "%SERVERID%", a_ServerId); + + AString Request; + Request += "GET " + ActualAddress + " HTTP/1.1\r\n"; + Request += "Host: " + m_Server + "\r\n"; + Request += "User-Agent: MCServer\r\n"; + Request += "Connection: close\r\n"; + Request += "\r\n"; + + ret = ssl_write(&ssl, (const unsigned char *)Request.c_str(), Request.size()); + if (ret <= 0) + { + LOGWARNING("cAuthenticator: ssl_write returned %d", ret); + + // Free all resources which have been initialized up to this line + x509_crt_free(&cacert); + net_close(server_fd); + ssl_free(&ssl); + entropy_free(&entropy); + memset(&ssl, 0, sizeof(ssl)); + return false; + } + + /* Read the HTTP response */ + std::string Response; + for (;;) + { + memset(buf, 0, sizeof(buf)); + ret = ssl_read(&ssl, buf, sizeof(buf)); + + if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE)) + { + continue; + } + if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) + { + break; + } + if (ret < 0) + { + LOGWARNING("cAuthenticator: ssl_read returned %d", ret); + break; + } + if (ret == 0) + { + LOGWARNING("cAuthenticator: EOF"); + break; + } + + Response.append((const char *)buf, ret); + } + + ssl_close_notify(&ssl); + x509_crt_free(&cacert); + net_close(server_fd); + ssl_free(&ssl); + entropy_free(&entropy); + memset(&ssl, 0, sizeof(ssl)); + + // 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/Protocol.h b/src/Protocol/Protocol.h index 939170f0e..2fbeef0fa 100644 --- a/src/Protocol/Protocol.h +++ b/src/Protocol/Protocol.h @@ -83,6 +83,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; diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp index bf946ef19..3282a827f 100644 --- a/src/Protocol/Protocol125.cpp +++ b/src/Protocol/Protocol125.cpp @@ -96,6 +96,7 @@ 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_PLAYER_LIST_ITEM = 0xC9, @@ -537,9 +538,10 @@ void cProtocol125::SendHealth(void) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_HEALTH); - WriteShort((short)m_Client->GetPlayer()->GetHealth()); - WriteShort((short)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(); } @@ -594,6 +596,15 @@ 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); @@ -642,18 +653,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); - WriteChar (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(); } @@ -683,6 +706,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); @@ -800,10 +833,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 - WriteChar ((char)m_Client->GetPlayer()->GetGameMode()); + WriteChar ((char)Player->GetGameMode()); WriteShort (256); // Current world height WriteString("default"); } @@ -815,10 +849,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(); } @@ -842,6 +877,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 @@ -1236,6 +1283,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(); } @@ -1597,6 +1645,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); diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h index 08d3ebbe9..89e64f386 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 @@ -155,6 +143,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 ce5942a5c..53d8c1561 100644 --- a/src/Protocol/Protocol132.cpp +++ b/src/Protocol/Protocol132.cpp @@ -408,7 +408,8 @@ 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 (short i = 0; i < cInventory::invInventoryCount; i++) @@ -422,7 +423,7 @@ void cProtocol132::SendWholeInventory(const cWindow & a_Window) } // for i - Hotbar[] // Send even the item being dragged: - SendInventorySlot(-1, -1, m_Client->GetPlayer()->GetDraggingItem()); + SendInventorySlot(-1, -1, Player->GetDraggingItem()); } @@ -800,10 +801,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(); @@ -874,10 +877,11 @@ void cProtocol132::StartEncryption(const Byte * a_Key) // Prepare the m_AuthServerID: cSHA1Checksum Checksum; - AString ServerID = cRoot::Get()->GetServer()->GetServerID(); + 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); diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp index f694af1eb..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)); - WriteChar ((char)(a_Pickup.GetSpeed().x * 8)); - WriteChar ((char)(a_Pickup.GetSpeed().y * 8)); - WriteChar ((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(); } @@ -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); diff --git a/src/Protocol/Protocol16x.cpp b/src/Protocol/Protocol16x.cpp index 3da23a1dc..714bf5e46 100644 --- a/src/Protocol/Protocol16x.cpp +++ b/src/Protocol/Protocol16x.cpp @@ -131,9 +131,10 @@ void cProtocol161::SendHealth(void) { cCSLock Lock(m_CSPacket); WriteByte (PACKET_UPDATE_HEALTH); - WriteFloat((float)m_Client->GetPlayer()->GetHealth()); - WriteShort((short)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(); } @@ -144,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(); } @@ -214,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); @@ -276,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 ae1388649..8eedce8d5 100644 --- a/src/Protocol/Protocol16x.h +++ b/src/Protocol/Protocol16x.h @@ -46,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 a4319df37..8f9e3abd8 100644 --- a/src/Protocol/Protocol17x.cpp +++ b/src/Protocol/Protocol17x.cpp @@ -88,8 +88,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 +125,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 +139,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 +156,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 +172,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,6 +188,8 @@ 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); @@ -198,6 +209,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,6 +221,8 @@ 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 @@ -280,6 +295,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 +313,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 +326,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 +364,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 +378,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 +393,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 +407,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 +420,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 +434,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 +448,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 +461,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 +476,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 +493,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 +506,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,6 +522,8 @@ 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); @@ -502,6 +547,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 +560,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 +575,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 +589,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 +608,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 +633,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 +669,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,6 +691,8 @@ 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())); @@ -630,6 +713,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 +730,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 +758,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 +787,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 +800,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 +820,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 +834,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 +863,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 +895,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 +920,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 +934,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 +948,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 +961,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 +976,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 +992,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 +1006,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 +1025,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 +1038,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 +1055,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 +1072,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 +1094,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 +1118,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 +1143,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); @@ -1036,6 +1168,8 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp 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()); @@ -1051,6 +1185,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 +1202,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 +1218,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 +1231,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 +1247,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 +1274,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 +1293,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 +1308,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 +1325,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 +1344,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 +1356,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 @@ -1226,6 +1382,8 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window) void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short 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); @@ -1431,6 +1589,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 +1644,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("}"); @@ -1555,15 +1715,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,12 +1733,13 @@ 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.WriteString(Server->GetServerID()); + const AString & PubKeyDer = Server->GetPublicKeyDER(); Pkt.WriteShort(PubKeyDer.size()); Pkt.WriteBuf(PubKeyDer.data(), PubKeyDer.size()); Pkt.WriteShort(4); @@ -1596,14 +1748,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); } @@ -1912,6 +2056,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); @@ -2136,10 +2292,11 @@ void cProtocol172::StartEncryption(const Byte * a_Key) // Prepare the m_AuthServerID: cSHA1Checksum Checksum; - const AString & ServerID = cRoot::Get()->GetServer()->GetServerID(); + 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); @@ -2481,11 +2638,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()); @@ -2755,3 +2913,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 91186b270..6a3e81eff 100644 --- a/src/Protocol/Protocol17x.h +++ b/src/Protocol/Protocol17x.h @@ -87,6 +87,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; @@ -252,7 +253,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 +280,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); @@ -306,3 +308,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 3f7d7b254..2ccb9f197 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); @@ -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); @@ -965,6 +976,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema 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; + } } LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)", m_Client->GetIPString().c_str(), ProtocolVersion @@ -980,6 +1003,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 +1011,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 +1045,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 +1061,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 072d7c2d2..408109ef4 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; diff --git a/src/Root.cpp b/src/Root.cpp index ba4398b35..5d32bdd87 100644 --- a/src/Root.cpp +++ b/src/Root.cpp @@ -499,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); } 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/Server.cpp b/src/Server.cpp index d1e53bfff..bfb1b1cbb 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; @@ -615,14 +615,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..51c450ebd 100644 --- a/src/Server.h +++ b/src/Server.h @@ -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 @@ -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 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/FireSimulator.cpp b/src/Simulator/FireSimulator.cpp index 470dfc791..4fbfffd43 100644 --- a/src/Simulator/FireSimulator.cpp +++ b/src/Simulator/FireSimulator.cpp @@ -350,7 +350,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/FluidSimulator.cpp b/src/Simulator/FluidSimulator.cpp index 7779573d7..4a84084d2 100644 --- a/src/Simulator/FluidSimulator.cpp +++ b/src/Simulator/FluidSimulator.cpp @@ -155,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 0c032eeab..d37d2eecf 100644 --- a/src/Simulator/IncrementalRedstoneSimulator.cpp +++ b/src/Simulator/IncrementalRedstoneSimulator.cpp @@ -1,3 +1,4 @@ + #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "IncrementalRedstoneSimulator.h" @@ -12,7 +13,7 @@ - + cIncrementalRedstoneSimulator::cIncrementalRedstoneSimulator(cWorld & a_World) : super(a_World) @@ -68,18 +69,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 @@ -92,29 +94,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(); @@ -551,128 +534,96 @@ 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_BlockX, a_BlockY, a_BlockZ, MyPower)) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); + return; } - else + + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MyPower); + + if (MyPower < 1) { - NIBBLETYPE MetaToSet = 0; - NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); - int TimesMetaSmaller = 0, TimesFoundAWire = 0; + return; + } + + MyPower--; - for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power + 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... + if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)... { - 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; // We don't receive power from that wire } - else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + } + else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us + { + if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ))) { - 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) - { - 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++; - } - } } - if ((TimesMetaSmaller == TimesFoundAWire) && (MyMeta != 0)) - { - // 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 - } - else if (MyMeta != MetaToSet) + if (m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z) == E_BLOCK_REDSTONE_WIRE) { - m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet); + 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_WIRE, 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 + if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF) { - 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); - } + 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, 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_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE, MyPower); - switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) + switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) + { + 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); - - 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; - } + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower); + break; + } + case REDSTONE_X_POS: + { + SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower); + break; + } + case REDSTONE_X_NEG: + { + SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower); + break; + } + case REDSTONE_Z_POS: + { + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower); + break; + } + case REDSTONE_Z_NEG: + { + SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower); + SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower); + break; } } } @@ -683,19 +634,42 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block void cIncrementalRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, 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 powered. - bool IsLocked = IsRepeaterLocked(a_BlockX, a_BlockY, a_BlockZ, a_Meta & 0x3); // Cache if repeater is locked. + | + | Z Axis + V - if (IsSelfPowered && !IsOn && !IsLocked) // Queue a power change if powered, but not on and not locked. - { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, true); - } - else if (!IsSelfPowered && IsOn && !IsLocked) // Queue a power change if unpowered, on, and not locked. + X Axis ----> + + Repeater directions, values from a cWorld::GetBlockMeta(a_BlockX , a_BlockY, a_BlockZ) 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_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + bool IsOn = (a_MyState == E_BLOCK_REDSTONE_REPEATER_ON); + + if (!IsRepeaterLocked(a_BlockX, a_BlockY, a_BlockZ, a_Meta)) // If we're locked, change nothing. Otherwise: { - QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, false); + bool IsSelfPowered = IsRepeaterPowered(a_BlockX, a_BlockY, a_BlockZ, a_Meta); + if (IsSelfPowered && !IsOn) // Queue a power change if powered, but not on and not locked. + { + QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, true); + } + else if (!IsSelfPowered && IsOn) // Queue a power change if unpowered, on, and not locked. + { + QueueRepeaterPowerChange(a_BlockX, a_BlockY, a_BlockZ, a_Meta, false); + } } for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end(); ++itr) @@ -1042,16 +1016,146 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc 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(a_BlockX, a_BlockY, a_BlockZ); + m_World.ForEachEntity(PressurePlateCallback); + + unsigned char Power; + NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) + { + 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power); + } + else + { + 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_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(a_BlockX, a_BlockY, a_BlockZ); + m_World.ForEachEntity(PressurePlateCallback); + + unsigned char Power; + NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); + if (PressurePlateCallback.GetPowerLevel(Power)) + { + 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); + SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power); + } + else + { + 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); + m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_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 +1170,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 +1178,46 @@ 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(a_BlockX, a_BlockY, a_BlockZ); m_World.ForEachEntity(PressurePlateCallback); NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED); SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, 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_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0); + m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED); m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); } break; } default: + { LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str()); break; + } } } @@ -1151,7 +1256,8 @@ bool cIncrementalRedstoneSimulator::AreCoordsLinkedPowered(int a_BlockX, int a_B - +// 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_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) { // Repeaters cannot be powered by any face except their back; verify that this is true for a source @@ -1160,7 +1266,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - switch (a_Meta) + switch (a_Meta & 0x3) { case 0x0: { @@ -1190,7 +1296,7 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY { if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - switch (a_Meta) + switch (a_Meta & 0x3) { case 0x0: { @@ -1222,58 +1328,53 @@ bool cIncrementalRedstoneSimulator::IsRepeaterPowered(int a_BlockX, int a_BlockY bool cIncrementalRedstoneSimulator::IsRepeaterLocked(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta) -{ - // Repeaters can be locked by either of their sides - for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) +{ + switch (a_Meta & 0x3) // We only want the 'direction' part of our metadata { - if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; } - - switch (a_Meta) + // If the repeater is looking up or down (If parallel to the Z axis) + case 0x0: + case 0x2: { - // If N/S check E/W - case 0x0: - case 0x2: + // Check if eastern(right) neighbor is a powered on repeater who is facing us. + if (m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ) == E_BLOCK_REDSTONE_REPEATER_ON) // Is right neighbor a powered repeater? { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } - break; + NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX + 1, a_BlockY, a_BlockZ) & 0x3; + if (OtherRepeaterDir == 0x3) { return true; } // If so, I am latched/locked. } - // If E/W check N/S - case 0x1: - case 0x3: + + // Check if western(left) neighbor is a powered on repeater who is facing us. + if (m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ) == E_BLOCK_REDSTONE_REPEATER_ON) { - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } - if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } - break; + NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX -1, a_BlockY, a_BlockZ) & 0x3; + if (OtherRepeaterDir == 0x1) { return true; } // If so, I am latched/locked. } - } - } - 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; } + break; + } - switch (a_Meta) + // If the repeater is looking left or right (If parallel to the x axis) + case 0x1: + case 0x3: { - // If N/S check E/W - case 0x0: - case 0x2: - { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX + 1, a_BlockY, a_BlockZ))) { return true; } - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX - 1, a_BlockY, a_BlockZ))) { return true; } - break; + // Check if southern(down) neighbor is a powered on repeater who is facing us. + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1) == E_BLOCK_REDSTONE_REPEATER_ON) + { + NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ + 1) & 0x3; + if (OtherRepeaterDir == 0x0) { return true; } // If so, am latched/locked. } - // If E/W check N/S - case 0x1: - case 0x3: - { - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ + 1))) { return true; } - if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ - 1))) { return true; } - break; + + // Check if northern(up) neighbor is a powered on repeater who is facing us. + if (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ -1) == E_BLOCK_REDSTONE_REPEATER_ON) + { + NIBBLETYPE OtherRepeaterDir = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ - 1) & 0x3; + if (OtherRepeaterDir == 0x2) { return true; } // If so, I am latched/locked. } + + break; } } - return false; // Repeater is not being powered from either side, therefore it is not locked. + + return false; // None of the checks succeeded, I am not a locked repeater. } @@ -1323,28 +1424,29 @@ 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_BlockX, int a_BlockY, int a_BlockZ, 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; - 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(a_BlockX, a_BlockY, a_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(a_BlockX, a_BlockY, a_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 } @@ -1374,7 +1476,7 @@ 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_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType, unsigned char a_PowerLevel) { switch (a_Direction) { @@ -1382,11 +1484,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int { BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ); - 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_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); break; } @@ -1394,11 +1496,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int { BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); - 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_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); break; } @@ -1406,11 +1508,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int { BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); - 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_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); break; } @@ -1418,11 +1520,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int { BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); - 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_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); break; } @@ -1430,11 +1532,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int { BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); - 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_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); break; } @@ -1442,11 +1544,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int { BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); - 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_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); + 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, a_PowerLevel); break; } @@ -1462,7 +1564,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_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel) { static const struct { @@ -1479,7 +1581,7 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc 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_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock, a_PowerLevel); } } @@ -1487,7 +1589,7 @@ 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_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel) { BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); if (Block == E_BLOCK_AIR) @@ -1497,15 +1599,31 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, } PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); - - for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list + for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->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)) - ) + ) { - // Check for duplicates + // Check for duplicates, update power level if everything else the same but either way, don't add a new listing + if (itr->a_PowerLevel != a_PowerLevel) + { + itr->a_PowerLevel = a_PowerLevel; + } + return; + } + } + + PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); + for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list + { + if ( + itr->a_BlockPos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) && + itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) + ) + { + // Powered wires try to power their source - don't let them! return; } } @@ -1513,6 +1631,7 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, sPoweredBlocks RC; RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); + RC.a_PowerLevel = a_PowerLevel; Powered->push_back(RC); } @@ -1524,7 +1643,7 @@ 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 + BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel ) { BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ); @@ -1539,16 +1658,19 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( } 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 + 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)) - ) + ) { - // Check for duplicates + // Check for duplicates, update power level if everything else the same but either way, don't add a new listing + if (itr->a_PowerLevel != a_PowerLevel) + { + itr->a_PowerLevel = a_PowerLevel; + } return; } } @@ -1557,6 +1679,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered( 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_PowerLevel = a_PowerLevel; Linked->push_back(RC); } @@ -1621,7 +1744,7 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); // 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; @@ -1697,12 +1820,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 f93f86898..a42cce79a 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; + 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; + 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: @@ -132,15 +136,15 @@ private: /* ====== 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_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, 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_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, 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); /** 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_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock, 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_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, 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); @@ -159,15 +163,14 @@ private: /** Returns if a piston is powered */ bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, 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_BlockX, int a_BlockY, int a_BlockZ, 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/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/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..87b4032e0 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(); } - } @@ -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,16 +493,16 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player) // If possible, craft: if (DraggingItem.IsEmpty()) { - DraggingItem = Recipe.GetResult(); + DraggingItem = Result; Recipe.ConsumeIngredients(Grid); Grid.CopyToItems(PlayerSlots); } - 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); } @@ -593,6 +596,307 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & 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: cSlotAreaEnderChest::cSlotAreaEnderChest(cEnderChestEntity * a_EnderChest, cWindow & a_ParentWindow) : @@ -787,6 +1091,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..254722822 100644 --- a/src/UI/SlotArea.h +++ b/src/UI/SlotArea.h @@ -19,6 +19,8 @@ class cDropSpenserEntity; class cEnderChestEntity; class cFurnaceEntity; class cCraftingRecipe; +class cEnchantingWindow; +class cWorld; @@ -66,7 +68,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 +145,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); } ; @@ -252,6 +259,34 @@ protected: +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 { diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp index aae7b99a3..0a78578fc 100644 --- a/src/UI/Window.cpp +++ b/src/UI/Window.cpp @@ -805,6 +805,66 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_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..1ca67bfd8 100644 --- a/src/UI/Window.h +++ b/src/UI/Window.h @@ -136,11 +136,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 +165,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 +231,32 @@ public: +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); + + /** Set the Position Values to the Position of 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..2c79f9ff1 100644 --- a/src/Vector3.h +++ b/src/Vector3.h @@ -108,6 +108,11 @@ public: return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z; } + inline bool operator == (const Vector3<T> & a_Rhs) const + { + return Equals(a_Rhs); + } + inline bool operator < (const Vector3<T> & a_Rhs) { // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ? diff --git a/src/WebAdmin.cpp b/src/WebAdmin.cpp index cd141f7eb..a3b3cc5be 100644 --- a/src/WebAdmin.cpp +++ b/src/WebAdmin.cpp @@ -229,10 +229,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) { @@ -388,7 +389,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>"; diff --git a/src/World.cpp b/src/World.cpp index c188fd522..5ac8e0a6e 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; } @@ -521,21 +518,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 +556,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 +574,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 +663,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 +786,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 +838,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 +848,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 +1610,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 +1619,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 +1669,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(); @@ -2890,7 +2872,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 +2963,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) diff --git a/src/World.h b/src/World.h index e08ef7f53..f789916df 100644 --- a/src/World.h +++ b/src/World.h @@ -711,7 +711,7 @@ public: 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 + 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 +938,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..ac9a21205 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -345,7 +345,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 +376,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; diff --git a/src/WorldStorage/FireworksSerializer.cpp b/src/WorldStorage/FireworksSerializer.cpp index 744fc731f..e0cd69634 100644 --- a/src/WorldStorage/FireworksSerializer.cpp +++ b/src/WorldStorage/FireworksSerializer.cpp @@ -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 cbc544a14..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; diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp index 415693ae2..773954f73 100644 --- a/src/WorldStorage/NBTChunkSerializer.cpp +++ b/src/WorldStorage/NBTChunkSerializer.cpp @@ -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" @@ -621,10 +621,10 @@ 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; } } diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp index 48934d074..66144dbd5 100644 --- a/src/WorldStorage/WSSAnvil.cpp +++ b/src/WorldStorage/WSSAnvil.cpp @@ -1757,7 +1757,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; diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp index bb9d4b9e6..359bac4a8 100644 --- a/src/WorldStorage/WSSCompact.cpp +++ b/src/WorldStorage/WSSCompact.cpp @@ -468,7 +468,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 @@ -797,7 +805,6 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3() ++index2; } InChunkOffset += index2 / 2; - index2 = 0; AString Converted(ConvertedData, ExpectedSize); @@ -839,7 +846,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) diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h index 4df146ec3..97e3b82f9 100644 --- a/src/WorldStorage/WSSCompact.h +++ b/src/WorldStorage/WSSCompact.h @@ -135,7 +135,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..54eaaca5c 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(); } |