summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Bindings/BindingsProcessor.lua4
-rw-r--r--src/Bindings/LuaState.cpp83
-rw-r--r--src/Bindings/LuaState.h156
-rw-r--r--src/Blocks/BlockHandler.cpp1
-rw-r--r--src/Defines.h18
-rw-r--r--src/Generating/CMakeLists.txt2
-rw-r--r--src/Generating/Prefab.cpp49
-rw-r--r--src/Generating/Prefab.h25
-rw-r--r--src/Generating/PrefabPiecePool.cpp414
-rw-r--r--src/Generating/PrefabPiecePool.h79
-rw-r--r--src/Globals.h16
-rw-r--r--src/WorldStorage/CMakeLists.txt6
-rw-r--r--src/WorldStorage/SchematicFileSerializer.cpp24
13 files changed, 806 insertions, 71 deletions
diff --git a/src/Bindings/BindingsProcessor.lua b/src/Bindings/BindingsProcessor.lua
index fba992082..a398f5026 100644
--- a/src/Bindings/BindingsProcessor.lua
+++ b/src/Bindings/BindingsProcessor.lua
@@ -98,7 +98,9 @@ local function OutputLuaStateHelpers(a_Package)
f:write("// This file expects to be included form inside the cLuaState class definition\n")
f:write("\n\n\n\n\n")
for _, item in ipairs(types) do
- f:write("void Push(" .. item.name .. " * a_Value);\n")
+ if not(g_HasCustomPushImplementation[item.name]) then
+ f:write("void Push(" .. item.name .. " * a_Value);\n")
+ end
end
for _, item in ipairs(types) do
f:write("bool GetStackValue(int a_StackPos, Ptr" .. item.lname .. " & a_ReturnedVal);\n")
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 232432a99..9814d1c85 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -211,23 +211,31 @@ void cLuaState::AddPackagePath(const AString & a_PathVariable, const AString & a
-bool cLuaState::LoadFile(const AString & a_FileName)
+bool cLuaState::LoadFile(const AString & a_FileName, bool a_LogWarnings)
{
ASSERT(IsValid());
// Load the file:
int s = luaL_loadfile(m_LuaState, a_FileName.c_str());
- if (ReportErrors(s))
+ if (s != 0)
{
- LOGWARNING("Can't load %s because of an error in file %s", m_SubsystemName.c_str(), a_FileName.c_str());
+ if (a_LogWarnings)
+ {
+ LOGWARNING("Can't load %s because of a load error in file %s: %d (%s)", m_SubsystemName.c_str(), a_FileName.c_str(), s, lua_tostring(m_LuaState, -1));
+ }
+ lua_pop(m_LuaState, 1);
return false;
}
// Execute the globals:
s = lua_pcall(m_LuaState, 0, LUA_MULTRET, 0);
- if (ReportErrors(s))
+ if (s != 0)
{
- LOGWARNING("Error in %s in file %s", m_SubsystemName.c_str(), a_FileName.c_str());
+ if (a_LogWarnings)
+ {
+ LOGWARNING("Can't load %s because of an initialization error in file %s: %d (%s)", m_SubsystemName.c_str(), a_FileName.c_str(), s, lua_tostring(m_LuaState, -1));
+ }
+ lua_pop(m_LuaState, 1);
return false;
}
@@ -446,6 +454,18 @@ void cLuaState::Push(const cPlayer * a_Player)
+void cLuaState::Push(const cLuaState::cRef & a_Ref)
+{
+ ASSERT(IsValid());
+
+ lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, static_cast<int>(a_Ref));
+ m_NumCurrentFunctionArgs += 1;
+}
+
+
+
+
+
void cLuaState::Push(const HTTPRequest * a_Request)
{
ASSERT(IsValid());
@@ -765,14 +785,17 @@ bool cLuaState::GetStackValue(int a_StackPos, double & a_ReturnedVal)
-bool cLuaState::GetStackValue(int a_StackPos, float & a_ReturnedVal)
+bool cLuaState::GetStackValue(int a_StackPos, eBlockFace & a_ReturnedVal)
{
- if (lua_isnumber(m_LuaState, a_StackPos))
+ if (!lua_isnumber(m_LuaState, a_StackPos))
{
- a_ReturnedVal = static_cast<float>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal));
- return true;
+ return false;
}
- return false;
+ a_ReturnedVal = static_cast<eBlockFace>(Clamp(
+ static_cast<int>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal)),
+ static_cast<int>(BLOCK_FACE_MIN), static_cast<int>(BLOCK_FACE_MAX))
+ );
+ return true;
}
@@ -796,6 +819,46 @@ bool cLuaState::GetStackValue(int a_StackPos, eWeather & a_ReturnedVal)
+bool cLuaState::GetStackValue(int a_StackPos, float & a_ReturnedVal)
+{
+ if (lua_isnumber(m_LuaState, a_StackPos))
+ {
+ a_ReturnedVal = static_cast<float>(tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal));
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+cLuaState::cStackValue cLuaState::WalkToValue(const AString & a_Name)
+{
+ auto path = StringSplit(a_Name, ".");
+ lua_pushvalue(m_LuaState, -1); // Copy the stack value into the "working area"
+ for (const auto & elem: path)
+ {
+ // If the value is not a table, bail out (error):
+ if (!lua_istable(m_LuaState, -1))
+ {
+ lua_pop(m_LuaState, 1);
+ return cStackValue();
+ }
+
+ // Get the next part of the path:
+ lua_getfield(m_LuaState, -1, elem.c_str());
+
+ // Remove the previous value from the stack (keep only the new one):
+ lua_remove(m_LuaState, -2);
+ } // for elem - path[]
+ return std::move(cStackValue(*this));
+}
+
+
+
+
+
bool cLuaState::CallFunction(int a_NumResults)
{
ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 8a3411d30..cc8214646 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -78,11 +78,14 @@ public:
bool IsValid(void) const {return (m_Ref != LUA_REFNIL); }
/** Allows to use this class wherever an int (i. e. ref) is to be used */
- operator int(void) const { return m_Ref; }
-
+ explicit operator int(void) const { return m_Ref; }
+
protected:
cLuaState * m_LuaState;
int m_Ref;
+
+ // Remove the copy-constructor:
+ cRef(const cRef &) = delete;
} ;
@@ -98,6 +101,12 @@ public:
{
}
+ cTableRef(const cRef & a_TableRef, const char * a_FnName) :
+ m_TableRef(static_cast<int>(a_TableRef)),
+ m_FnName(a_FnName)
+ {
+ }
+
int GetTableRef(void) const { return m_TableRef; }
const char * GetFnName(void) const { return m_FnName; }
} ;
@@ -111,6 +120,61 @@ public:
static const cRet Return; // Use this constant to delimit function args from return values for cLuaState::Call()
+ /** A RAII class for values pushed onto the Lua stack.
+ Will pop the value off the stack in the destructor. */
+ class cStackValue
+ {
+ public:
+ cStackValue(void):
+ m_LuaState(nullptr)
+ {
+ }
+
+ cStackValue(cLuaState & a_LuaState):
+ m_LuaState(a_LuaState)
+ {
+ m_StackLen = lua_gettop(a_LuaState);
+ }
+
+ cStackValue(cStackValue && a_Src):
+ m_LuaState(nullptr),
+ m_StackLen(-1)
+ {
+ std::swap(m_LuaState, a_Src.m_LuaState);
+ std::swap(m_StackLen, a_Src.m_StackLen);
+ }
+
+ ~cStackValue()
+ {
+ if (m_LuaState != nullptr)
+ {
+ auto top = lua_gettop(m_LuaState);
+ ASSERT(m_StackLen == top);
+ lua_pop(m_LuaState, 1);
+ }
+ }
+
+ void Set(cLuaState & a_LuaState)
+ {
+ m_LuaState = a_LuaState;
+ m_StackLen = lua_gettop(a_LuaState);
+ }
+
+ bool IsValid(void) const
+ {
+ return (m_LuaState != nullptr);
+ }
+
+ protected:
+ lua_State * m_LuaState;
+
+ int m_StackLen;
+
+ // Remove the copy-constructor:
+ cStackValue(const cStackValue &) = delete;
+ };
+
+
/** Creates a new instance. The LuaState is not initialized.
a_SubsystemName is used for reporting problems in the console, it is "plugin %s" for plugins,
or "LuaScript" for the cLuaScript template
@@ -151,10 +215,9 @@ public:
void AddPackagePath(const AString & a_PathVariable, const AString & a_Path);
/** Loads the specified file
- Returns false and logs a warning to the console if not successful (but the LuaState is kept open).
- m_SubsystemName is displayed in the warning log message.
- */
- bool LoadFile(const AString & a_FileName);
+ Returns false and optionally logs a warning to the console if not successful (but the LuaState is kept open).
+ m_SubsystemName is displayed in the warning log message. */
+ bool LoadFile(const AString & a_FileName, bool a_LogWarnings = true);
/** Returns true if a_FunctionName is a valid Lua function that can be called */
bool HasFunction(const char * a_FunctionName);
@@ -169,6 +232,7 @@ public:
void Push(const char * a_Value);
void Push(const cItems & a_Items);
void Push(const cPlayer * a_Player);
+ void Push(const cRef & a_Ref);
void Push(const HTTPRequest * a_Request);
void Push(const HTTPTemplateRequest * a_Request);
void Push(const Vector3d & a_Vector);
@@ -178,22 +242,24 @@ public:
// Push a simple value onto the stack (keep alpha-sorted):
void Push(bool a_Value);
+ void Push(cEntity * a_Entity);
+ void Push(cLuaServerHandle * a_ServerHandle);
+ void Push(cLuaTCPLink * a_TCPLink);
+ void Push(cLuaUDPEndpoint * a_UDPEndpoint);
void Push(double a_Value);
void Push(int a_Value);
void Push(void * a_Ptr);
void Push(std::chrono::milliseconds a_time);
- void Push(cLuaServerHandle * a_ServerHandle);
- void Push(cLuaTCPLink * a_TCPLink);
- void Push(cLuaUDPEndpoint * a_UDPEndpoint);
// GetStackValue() retrieves the value at a_StackPos, if it is a valid type. If not, a_Value is unchanged.
// Returns whether value was changed
- // Enum values are clamped to their allowed range.
+ // Enum values are checked for their allowed values and fail if the value is not assigned.
bool GetStackValue(int a_StackPos, AString & a_Value);
bool GetStackValue(int a_StackPos, bool & a_Value);
bool GetStackValue(int a_StackPos, cPluginManager::CommandResult & a_Result);
bool GetStackValue(int a_StackPos, cRef & a_Ref);
bool GetStackValue(int a_StackPos, double & a_Value);
+ bool GetStackValue(int a_StackPos, eBlockFace & a_Value);
bool GetStackValue(int a_StackPos, eWeather & a_Value);
bool GetStackValue(int a_StackPos, float & a_ReturnedVal);
@@ -202,21 +268,53 @@ public:
bool GetStackValue(int a_StackPos, T & a_ReturnedVal, typename std::enable_if<std::is_integral<T>::value>::type * unused = nullptr)
{
UNUSED(unused);
- if (lua_isnumber(m_LuaState, a_StackPos))
+ if (!lua_isnumber(m_LuaState, a_StackPos)) // Also accepts strings representing a number: http://pgl.yoyo.org/luai/i/lua_isnumber
{
- lua_Number Val = tolua_tonumber(m_LuaState, a_StackPos, a_ReturnedVal);
- if (Val > std::numeric_limits<T>::max())
- {
- return false;
- }
- if (Val < std::numeric_limits<T>::min())
- {
- return false;
- }
- a_ReturnedVal = static_cast<T>(Val);
- return true;
+ return false;
+ }
+ lua_Number Val = lua_tonumber(m_LuaState, a_StackPos);
+ if (Val > std::numeric_limits<T>::max())
+ {
+ return false;
+ }
+ if (Val < std::numeric_limits<T>::min())
+ {
+ return false;
+ }
+ a_ReturnedVal = static_cast<T>(Val);
+ return true;
+ }
+
+ /** Pushes the named value in the table at the top of the stack.
+ a_Name may be a path containing multiple table levels, such as "_G.cChatColor.Blue".
+ If the value is found, it is pushed on top of the stack and the returned cStackValue is valid.
+ If the value is not found, the stack is unchanged and the returned cStackValue is invalid. */
+ cStackValue WalkToValue(const AString & a_Name);
+
+ /** Retrieves the named value in the table at the top of the Lua stack.
+ a_Name may be a path containing multiple table levels, such as "_G.cChatColor.Blue".
+ Returns true if the value was successfully retrieved, false on error. */
+ template <typename T> bool GetNamedValue(const AString & a_Name, T & a_Value)
+ {
+ auto stk = WalkToValue(a_Name);
+ if (!stk.IsValid())
+ {
+ // Name not found
+ return false;
}
- return false;
+ return GetStackValue(-1, a_Value);
+ }
+
+ /** Retrieves the named global value. a_Name may be a path containing multiple table levels, such as "_G.cChatColor.Blue".
+ Returns true if the value was successfully retrieved, false on error. */
+ template <typename T> bool GetNamedGlobal(const AString & a_Name, T & a_Value)
+ {
+ // Push the globals table onto the stack and make it RAII-removed:
+ lua_getglobal(m_LuaState, "_G");
+ cStackValue stk(*this);
+
+ // Get the named global:
+ return GetNamedValue(a_Name, a_Value);
}
// Include the auto-generated Push and GetStackValue() functions:
@@ -229,12 +327,12 @@ public:
template <typename FnT, typename... Args>
bool Call(const FnT & a_Function, Args &&... args)
{
- if (!PushFunction(a_Function))
+ if (!PushFunction(std::forward<const FnT &>(a_Function)))
{
// Pushing the function failed
return false;
}
- return PushCallPop(args...);
+ return PushCallPop(std::forward<Args>(args)...);
}
/** Retrieves a list of values from the Lua stack, starting at the specified index. */
@@ -343,10 +441,10 @@ protected:
/** Variadic template recursor: More params to push. Push them and recurse. */
template <typename T, typename... Args>
- inline bool PushCallPop(T a_Param, Args &&... args)
+ inline bool PushCallPop(T && a_Param, Args &&... args)
{
- Push(a_Param);
- return PushCallPop(args...);
+ Push(std::forward<T>(a_Param));
+ return PushCallPop(std::forward<Args>(args)...);
}
/** Variadic template terminator: If there's nothing more to push, but return values to collect, call the function and collect the returns. */
@@ -363,7 +461,7 @@ protected:
}
// Collect the return values:
- GetStackValues(-NumReturns, args...);
+ GetStackValues(-NumReturns, std::forward<Args>(args)...);
lua_pop(m_LuaState, NumReturns);
// All successful:
diff --git a/src/Blocks/BlockHandler.cpp b/src/Blocks/BlockHandler.cpp
index 452cc94a5..105765b5f 100644
--- a/src/Blocks/BlockHandler.cpp
+++ b/src/Blocks/BlockHandler.cpp
@@ -427,6 +427,7 @@ void cBlockHandler::NeighborChanged(cChunkInterface & a_ChunkInterface, int a_Bl
+
void cBlockHandler::ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta)
{
// Setting the meta to a_BlockMeta keeps most textures. The few other blocks have to override this.
diff --git a/src/Defines.h b/src/Defines.h
index b167f69e3..f3b742e09 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -29,16 +29,16 @@ enum
-/// Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc
+/** Block face constants, used in PlayerDigging and PlayerBlockPlacement packets and bbox collision calc */
enum eBlockFace
{
BLOCK_FACE_NONE = -1, // Interacting with no block face - swinging the item in the air
- BLOCK_FACE_XM = 4, // Interacting with the X- face of the block
- BLOCK_FACE_XP = 5, // Interacting with the X+ face of the block
- BLOCK_FACE_YM = 0, // Interacting with the Y- face of the block
- BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block
- BLOCK_FACE_ZM = 2, // Interacting with the Z- face of the block
- BLOCK_FACE_ZP = 3, // Interacting with the Z+ face of the block
+ BLOCK_FACE_XM = 4, // Interacting with the X- face of the block
+ BLOCK_FACE_XP = 5, // Interacting with the X+ face of the block
+ BLOCK_FACE_YM = 0, // Interacting with the Y- face of the block
+ BLOCK_FACE_YP = 1, // Interacting with the Y+ face of the block
+ BLOCK_FACE_ZM = 2, // Interacting with the Z- face of the block
+ BLOCK_FACE_ZP = 3, // Interacting with the Z+ face of the block
// Synonyms using the (deprecated) world directions:
BLOCK_FACE_BOTTOM = BLOCK_FACE_YM, // Interacting with the bottom face of the block
@@ -47,6 +47,10 @@ enum eBlockFace
BLOCK_FACE_SOUTH = BLOCK_FACE_ZP, // Interacting with the southern face of the block
BLOCK_FACE_WEST = BLOCK_FACE_XM, // Interacting with the western face of the block
BLOCK_FACE_EAST = BLOCK_FACE_XP, // Interacting with the eastern face of the block
+
+ // Bounds, used for range-checking:
+ BLOCK_FACE_MIN = -1,
+ BLOCK_FACE_MAX = 5,
} ;
diff --git a/src/Generating/CMakeLists.txt b/src/Generating/CMakeLists.txt
index ebba4cce8..f3fe5c55c 100644
--- a/src/Generating/CMakeLists.txt
+++ b/src/Generating/CMakeLists.txt
@@ -101,5 +101,5 @@ endif()
if(NOT MSVC)
add_library(Generating ${SRCS} ${HDRS})
- target_link_libraries(Generating OSSupport Blocks)
+ target_link_libraries(Generating OSSupport Blocks Bindings)
endif()
diff --git a/src/Generating/Prefab.cpp b/src/Generating/Prefab.cpp
index 1de0346bd..e5e6a1e06 100644
--- a/src/Generating/Prefab.cpp
+++ b/src/Generating/Prefab.cpp
@@ -166,6 +166,45 @@ cPrefab::cPrefab(const cBlockArea & a_Image, int a_AllowedRotations) :
+cPrefab::cPrefab(const cBlockArea & a_Image) :
+ m_Size(a_Image.GetSize()),
+ m_AllowedRotations(0),
+ m_MergeStrategy(cBlockArea::msOverwrite),
+ m_ShouldExtendFloor(false),
+ m_DefaultWeight(1),
+ m_AddWeightIfSame(0),
+ m_MoveToGround(false)
+{
+ m_HitBox.p1.Set(0, 0, 0);
+ m_HitBox.p2.Set(m_Size.x - 1, m_Size.y - 1, m_Size.z - 1);
+ m_BlockArea[0].CopyFrom(a_Image);
+}
+
+
+
+
+
+cPrefab::cPrefab(const AString & a_BlockDefinitions, const AString & a_BlockData, int a_SizeX, int a_SizeY, int a_SizeZ) :
+ m_Size(a_SizeX, a_SizeY, a_SizeZ),
+ m_AllowedRotations(0),
+ m_MergeStrategy(cBlockArea::msOverwrite),
+ m_ShouldExtendFloor(false),
+ m_DefaultWeight(1),
+ m_AddWeightIfSame(0),
+ m_MoveToGround(false)
+{
+ m_HitBox.p1.Set(0, 0, 0);
+ m_HitBox.p2.Set(m_Size.x - 1, m_Size.y - 1, m_Size.z - 1);
+ m_BlockArea[0].Create(m_Size);
+ CharMap cm;
+ ParseCharMap(cm, a_BlockDefinitions.c_str());
+ ParseBlockImage(cm, a_BlockData.c_str());
+}
+
+
+
+
+
void cPrefab::AddRotatedBlockAreas(void)
{
// 1 CCW rotation:
@@ -326,6 +365,16 @@ void cPrefab::AddConnector(int a_RelX, int a_RelY, int a_RelZ, eBlockFace a_Dire
+void cPrefab::SetAllowedRotations(int a_AllowedRotations)
+{
+ m_AllowedRotations = a_AllowedRotations;
+ AddRotatedBlockAreas();
+}
+
+
+
+
+
void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
{
ASSERT(a_CharMapDef != nullptr);
diff --git a/src/Generating/Prefab.h b/src/Generating/Prefab.h
index eb905e78e..45af4b282 100644
--- a/src/Generating/Prefab.h
+++ b/src/Generating/Prefab.h
@@ -95,6 +95,13 @@ public:
/** Creates a prefab based on the given BlockArea and allowed rotations. */
cPrefab(const cBlockArea & a_Image, int a_AllowedRotations);
+ /** Creates a prefab based on the given BlockArea. Allowed rotations can be added later on using SetAllowedRotations(). */
+ cPrefab(const cBlockArea & a_Image);
+
+ /** Creates a prefab based on the specified block data, using the char-to-block map in a_BlockDefinitions.
+ Allowed rotations can be added later on using SetAllowedRotations(). */
+ cPrefab(const AString & a_BlockDefinitions, const AString & a_BlockData, int a_SizeX, int a_SizeY, int a_SizeZ);
+
/** Draws the prefab into the specified chunk, according to the placement stored in the PlacedPiece. */
void Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const;
@@ -124,6 +131,21 @@ public:
at the coords governed by the connectors. */
bool ShouldMoveToGround(void) const { return m_MoveToGround; }
+ /** Sets the m_AllowedRotations bitmask and fills the m_BlockArea[] with rotated versions of m_BlockArea[0]. */
+ void SetAllowedRotations(int a_AllowedRotations);
+
+ /** Parses the per-depth weight into m_DepthWeight member. */
+ void ParseDepthWeight(const char * a_DepthWeightDef);
+
+ /** Sets the merge strategy to be used when drawing the piece. */
+ void SetMergeStrategy(cBlockArea::eMergeStrategy a_MergeStrategy) { m_MergeStrategy = a_MergeStrategy; }
+
+ /** Sets the flag whether the prefab should be moved to ground level before being drawn. */
+ void SetMoveToGround(bool a_MoveToGround) { m_MoveToGround = a_MoveToGround; }
+
+ /** Sets the flag whether the lowest layer of the prefab should be repeated downwards until it hits a solid block. */
+ void SetExtendFloor(bool a_ShouldExtendFloor) { m_ShouldExtendFloor = a_ShouldExtendFloor; }
+
protected:
/** Packs complete definition of a single block, for per-letter assignment. */
struct sBlockTypeDef
@@ -201,9 +223,6 @@ protected:
/** Parses the connectors definition text into m_Connectors member. */
void ParseConnectors(const char * a_ConnectorsDef);
-
- /** Parses the per-depth weight into m_DepthWeight member. */
- void ParseDepthWeight(const char * a_DepthWeightDef);
};
diff --git a/src/Generating/PrefabPiecePool.cpp b/src/Generating/PrefabPiecePool.cpp
index e4df8efa8..3f0ec8549 100644
--- a/src/Generating/PrefabPiecePool.cpp
+++ b/src/Generating/PrefabPiecePool.cpp
@@ -5,6 +5,54 @@
#include "Globals.h"
#include "PrefabPiecePool.h"
+#include "../Bindings/LuaState.h"
+#include "SelfTests.h"
+#include "WorldStorage/SchematicFileSerializer.h"
+
+
+
+
+
+// Conditionally log a warning
+#define CONDWARNING(ShouldLog, ...) \
+ if (ShouldLog) \
+ { \
+ LOGWARNING(__VA_ARGS__); \
+ }
+
+
+
+
+
+/** Returns the map of string => eMergeStrategy used when translating cubeset file merge strategies. */
+static std::map<AString, cBlockArea::eMergeStrategy> & GetMergeStrategyMap(void)
+{
+ static std::map<AString, cBlockArea::eMergeStrategy> msmap;
+ if (msmap.empty())
+ {
+ // This is the first use, initialize the map:
+ msmap["msOverwrite"] = cBlockArea::msOverwrite;
+ msmap["msFillAir"] = cBlockArea::msFillAir;
+ msmap["msImprint"] = cBlockArea::msImprint;
+ msmap["msLake"] = cBlockArea::msLake;
+ msmap["msSpongePrint"] = cBlockArea::msSpongePrint;
+ msmap["msDifference"] = cBlockArea::msDifference;
+ msmap["msSimpleCompare"] = cBlockArea::msSimpleCompare;
+ msmap["msMask"] = cBlockArea::msMask;
+ }
+ return msmap;
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPrefabPiecePool:
+
+cPrefabPiecePool::cPrefabPiecePool(void)
+{
+}
@@ -26,6 +74,15 @@ cPrefabPiecePool::cPrefabPiecePool(
+cPrefabPiecePool::cPrefabPiecePool(const AString & a_FileName, bool a_LogWarnings)
+{
+ LoadFromFile(a_FileName, a_LogWarnings);
+}
+
+
+
+
+
cPrefabPiecePool::~cPrefabPiecePool()
{
Clear();
@@ -83,6 +140,66 @@ void cPrefabPiecePool::AddStartingPieceDefs(const cPrefab::sDef * a_StartingPiec
+bool cPrefabPiecePool::LoadFromFile(const AString & a_FileName, bool a_LogWarnings)
+{
+ // Read the first 4 KiB of the file in order to auto-detect format:
+ cFile f;
+ if (!f.Open(a_FileName, cFile::fmRead))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot open file %s for reading", a_FileName.c_str());
+ return false;
+ }
+ char buf[4096];
+ auto len = f.Read(buf, sizeof(buf));
+ f.Close();
+ AString Header(buf, static_cast<size_t>(len));
+
+ if (Header.find("CubesetFormatVersion =") != AString::npos)
+ {
+ return LoadFromCubesetFile(a_FileName, a_LogWarnings);
+ }
+ CONDWARNING(a_LogWarnings, "Cannot load prefabs from file %s, unknown file format", a_FileName.c_str());
+ return false;
+}
+
+
+
+
+
+bool cPrefabPiecePool::LoadFromCubesetFile(const AString & a_FileName, bool a_LogWarnings)
+{
+ // Load the file in the Lua interpreter:
+ cLuaState Lua(Printf("LoadablePiecePool %s", a_FileName.c_str()));
+ Lua.Create();
+ if (!Lua.LoadFile(a_FileName, a_LogWarnings))
+ {
+ // Reason for failure has already been logged in LoadFile()
+ return false;
+ }
+
+ // Check the version:
+ int Version = 0;
+ if (!Lua.GetNamedGlobal("Cubeset.Metadata.CubesetFormatVersion", Version))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot load cubeset %s, it doesn't contain version information.", a_FileName.c_str());
+ return false;
+ }
+
+ // Load the data, using the correct version loader:
+ if (Version == 1)
+ {
+ return LoadFromCubesetFileVer1(a_FileName, Lua, a_LogWarnings);
+ }
+
+ // Unknown version:
+ CONDWARNING(a_LogWarnings, "Cannot load cubeset %s, version (%d) not supported.", a_FileName.c_str(), Version);
+ return false;
+}
+
+
+
+
+
void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab)
{
cPiece::cConnectors Connectors = (static_cast<const cPiece *>(a_Prefab))->GetConnectors();
@@ -95,6 +212,303 @@ void cPrefabPiecePool::AddToPerConnectorMap(cPrefab * a_Prefab)
+
+bool cPrefabPiecePool::LoadFromCubesetFileVer1(const AString & a_FileName, cLuaState & a_LuaState, bool a_LogWarnings)
+{
+ // Push the Cubeset.Pieces global value on the stack:
+ lua_getglobal(a_LuaState, "_G");
+ cLuaState::cStackValue stk(a_LuaState);
+ auto pieces = a_LuaState.WalkToValue("Cubeset.Pieces");
+ if (!pieces.IsValid() || !lua_istable(a_LuaState, -1))
+ {
+ CONDWARNING(a_LogWarnings, "The cubeset file %s doesn't contain any pieces", a_FileName.c_str());
+ return false;
+ }
+
+ // Iterate over all items in the Cubeset.Pieces value:
+ int idx = 1;
+ bool res = true;
+ while (true)
+ {
+ lua_pushinteger(a_LuaState, idx); // stk: [Pieces] [idx]
+ lua_gettable(a_LuaState, -2); // stk: [Pieces] [PieceItem]
+ if (!lua_istable(a_LuaState, -1))
+ {
+ // The PieceItem is not present, we've iterated over all items
+ lua_pop(a_LuaState, 1); // stk: [Pieces]
+ break;
+ }
+ if (!LoadCubesetPieceVer1(a_FileName, a_LuaState, idx, a_LogWarnings))
+ {
+ res = false;
+ }
+ lua_pop(a_LuaState, 1); // stk: [Pieces]
+ idx += 1;
+ }
+ return res;
+}
+
+
+
+
+
+bool cPrefabPiecePool::LoadCubesetPieceVer1(const AString & a_FileName, cLuaState & a_LuaState, int a_PieceIndex, bool a_LogWarnings)
+{
+ ASSERT(lua_istable(a_LuaState, -1));
+
+ // The piece name is optional, but useful for debugging messages:
+ AString PieceName;
+ if (!a_LuaState.GetNamedValue("OriginData.ExportName", PieceName))
+ {
+ Printf(PieceName, "Piece #%d", a_PieceIndex);
+ }
+
+ // Read the hitbox dimensions:
+ cCuboid Hitbox;
+ if (
+ !a_LuaState.GetNamedValue("Hitbox.MinX", Hitbox.p1.x) ||
+ !a_LuaState.GetNamedValue("Hitbox.MinY", Hitbox.p1.y) ||
+ !a_LuaState.GetNamedValue("Hitbox.MinZ", Hitbox.p1.z) ||
+ !a_LuaState.GetNamedValue("Hitbox.MaxX", Hitbox.p2.x) ||
+ !a_LuaState.GetNamedValue("Hitbox.MaxY", Hitbox.p2.y) ||
+ !a_LuaState.GetNamedValue("Hitbox.MaxZ", Hitbox.p2.z)
+ )
+ {
+ CONDWARNING(a_LogWarnings, "Cannot load piece %s from file %s, it's missing hitbox information", PieceName.c_str(), a_FileName.c_str());
+ return false;
+ }
+
+ // Load the prefab data:
+ auto prefab = LoadPrefabFromCubesetVer1(a_FileName, a_LuaState, PieceName, a_LogWarnings);
+ if (prefab == nullptr)
+ {
+ return false;
+ }
+
+ // Read the connectors
+ if (!ReadConnectorsCubesetVer1(a_FileName, a_LuaState, PieceName, prefab.get(), a_LogWarnings))
+ {
+ return false;
+ }
+
+ // Read the allowed rotations. It is an optional metadata value, default to 0:
+ int AllowedRotations = 0;
+ a_LuaState.GetNamedValue("Metadata.AllowedRotations", AllowedRotations);
+ prefab->SetAllowedRotations(AllowedRotations);
+
+ // Apply the relevant metadata:
+ if (!ApplyMetadataCubesetVer1(a_FileName, a_LuaState, PieceName, prefab.get(), a_LogWarnings))
+ {
+ return false;
+ }
+
+ // Add the prefab into the list of pieces:
+ int IsStartingPiece = 0;
+ a_LuaState.GetNamedValue("Metadata.IsStarting", IsStartingPiece);
+ if (IsStartingPiece != 0)
+ {
+ m_StartingPieces.push_back(prefab.release());
+ }
+ else
+ {
+ auto p = prefab.release();
+ m_AllPieces.push_back(p);
+ AddToPerConnectorMap(p);
+ }
+ return true;
+}
+
+
+
+
+
+UniquePtr<cPrefab> cPrefabPiecePool::LoadPrefabFromCubesetVer1(
+ const AString & a_FileName,
+ cLuaState & a_LuaState,
+ const AString & a_PieceName,
+ bool a_LogWarnings
+)
+{
+ // First try loading a referenced schematic file, if any:
+ AString SchematicFileName;
+ if (a_LuaState.GetNamedValue("SchematicFileName", SchematicFileName))
+ {
+ auto PathEnd = a_FileName.find_last_of("/\\"); // Find the last path separator
+ if (PathEnd != AString::npos)
+ {
+ SchematicFileName = a_FileName.substr(0, PathEnd) + SchematicFileName;
+ }
+ cBlockArea area;
+ if (!cSchematicFileSerializer::LoadFromSchematicFile(area, SchematicFileName))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot load schematic file \"%s\" for piece %s in cubeset %s.",
+ SchematicFileName.c_str(), a_PieceName.c_str(), a_FileName.c_str()
+ );
+ return nullptr;
+ }
+ return cpp14::make_unique<cPrefab>(area);
+ } // if (SchematicFileName)
+
+ // There's no referenced schematic file, load from BlockDefinitions / BlockData.
+ // Get references to the data and the table.concat function:
+ cLuaState::cRef TableConcat, BlockDefinitions, BlockData;
+ if (
+ !a_LuaState.GetNamedGlobal("table.concat", TableConcat) ||
+ !a_LuaState.GetNamedValue("BlockDefinitions", BlockDefinitions) ||
+ !a_LuaState.GetNamedValue("BlockData", BlockData)
+ )
+ {
+ CONDWARNING(a_LogWarnings, "Cannot parse block data for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
+ return nullptr;
+ }
+
+ // Call table.concat() on the BlockDefinitions:
+ AString BlockDefStr;
+ if (!a_LuaState.Call(TableConcat, BlockDefinitions, "\n", cLuaState::Return, BlockDefStr))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot concat block definitions for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
+ return nullptr;
+ }
+
+ // Call table.concat() on the BlockData:
+ AString BlockDataStr;
+ if (!a_LuaState.Call(TableConcat, BlockData, "", cLuaState::Return, BlockDataStr))
+ {
+ CONDWARNING(a_LogWarnings, "Cannot concat block data for piece %s in cubeset %s", a_PieceName.c_str(), a_FileName.c_str());
+ return nullptr;
+ }
+
+ // Read the size:
+ int SizeX = 0, SizeY = 0, SizeZ = 0;
+ if (
+ !a_LuaState.GetNamedValue("Size.x", SizeX) ||
+ !a_LuaState.GetNamedValue("Size.y", SizeY) ||
+ !a_LuaState.GetNamedValue("Size.z", SizeZ)
+ )
+ {
+ CONDWARNING(a_LogWarnings, "Cannot load piece %s from file %s, its size information is missing", a_PieceName.c_str(), a_FileName.c_str());
+ return nullptr;
+ }
+
+ // Check that the size matches the data length:
+ if (static_cast<size_t>(SizeX * SizeY * SizeZ) != BlockDataStr.size())
+ {
+ CONDWARNING(a_LogWarnings, "Cannot create piece %s from file %s, its size (%d) doesn't match the blockdata length (%u)",
+ a_PieceName.c_str(), a_FileName.c_str(),
+ SizeX * SizeY * SizeZ, static_cast<unsigned>(BlockDataStr.size())
+ );
+ return nullptr;
+ }
+
+ return cpp14::make_unique<cPrefab>(BlockDefStr, BlockDataStr, SizeX, SizeY, SizeZ);
+}
+
+
+
+
+
+bool cPrefabPiecePool::ReadConnectorsCubesetVer1(
+ const AString & a_FileName,
+ cLuaState & a_LuaState,
+ const AString & a_PieceName,
+ cPrefab * a_Prefab,
+ bool a_LogWarnings
+)
+{
+ // Get the Connectors subtable:
+ auto conns = a_LuaState.WalkToValue("Connectors");
+ if (!conns.IsValid())
+ {
+ CONDWARNING(a_LogWarnings, "Cannot load piece %s from file %s, it has no connectors definition.", a_PieceName.c_str(), a_FileName.c_str());
+ return false;
+ }
+
+ // Iterate over all items in the Connectors table:
+ int idx = 1;
+ bool res = true;
+ while (true)
+ {
+ lua_pushinteger(a_LuaState, idx); // stk: [Connectors] [idx]
+ lua_gettable(a_LuaState, -2); // stk: [Connectors] [conn]
+ if (!lua_istable(a_LuaState, -1))
+ {
+ // The connector is not present, we've iterated over all items
+ lua_pop(a_LuaState, 1); // stk: [Connectors]
+ break;
+ }
+ int Type = 0, RelX = 0, RelY = 0, RelZ = 0;
+ eBlockFace Direction = BLOCK_FACE_NONE;
+ if (
+ !a_LuaState.GetNamedValue("Type", Type) ||
+ !a_LuaState.GetNamedValue("RelX", RelX) ||
+ !a_LuaState.GetNamedValue("RelY", RelY) ||
+ !a_LuaState.GetNamedValue("RelZ", RelZ) ||
+ !a_LuaState.GetNamedValue("Direction", Direction)
+ )
+ {
+ CONDWARNING(a_LogWarnings, "Piece %s in file %s has a malformed Connector at index %d. Skipping the connector.", a_PieceName.c_str(), a_FileName.c_str(), idx);
+ res = false;
+ continue;
+ }
+ a_Prefab->AddConnector(RelX, RelY, RelZ, Direction, Type);
+ lua_pop(a_LuaState, 1); // stk: [Connectors]
+ idx += 1;
+ }
+ return res;
+}
+
+
+
+
+
+bool cPrefabPiecePool::ApplyMetadataCubesetVer1(
+ const AString & a_FileName,
+ cLuaState & a_LuaState,
+ const AString & a_PieceName,
+ cPrefab * a_Prefab,
+ bool a_LogWarnings
+)
+{
+ // Push the Metadata table on top of the Lua stack:
+ auto md = a_LuaState.WalkToValue("Metadata");
+ if (!md.IsValid())
+ {
+ return false;
+ }
+
+ // Get the values:
+ int AddWeightIfSame = 0, DefaultWeight = 100, MoveToGround = 0, ShouldExpandFloor = 0;
+ AString DepthWeight, MergeStrategy;
+ a_LuaState.GetNamedValue("AddWeightIfSame", AddWeightIfSame);
+ a_LuaState.GetNamedValue("DefaultWeight", DefaultWeight);
+ a_LuaState.GetNamedValue("DepthWeight", DepthWeight);
+ a_LuaState.GetNamedValue("MergeStrategy", MergeStrategy);
+ a_LuaState.GetNamedValue("MoveToGround", MoveToGround);
+ a_LuaState.GetNamedValue("ShouldExpandFloor", ShouldExpandFloor);
+
+ // Apply the values:
+ a_Prefab->SetAddWeightIfSame(AddWeightIfSame);
+ a_Prefab->SetDefaultWeight(DefaultWeight);
+ a_Prefab->ParseDepthWeight(DepthWeight.c_str());
+ auto msmap = GetMergeStrategyMap();
+ auto strategy = msmap.find(MergeStrategy);
+ if (strategy == msmap.end())
+ {
+ CONDWARNING(a_LogWarnings, "Unknown merge strategy (\"%s\") specified for piece %s in file %s. Using msSpongePrint instead.",
+ MergeStrategy.c_str(), a_PieceName.c_str(), a_FileName.c_str()
+ );
+ a_Prefab->SetMergeStrategy(cBlockArea::msSpongePrint);
+ }
+ a_Prefab->SetMoveToGround(MoveToGround != 0);
+ a_Prefab->SetExtendFloor(ShouldExpandFloor != 0);
+
+ return true;
+}
+
+
+
+
+
cPieces cPrefabPiecePool::GetPiecesWithConnector(int a_ConnectorType)
{
return m_PiecesByConnector[a_ConnectorType];
diff --git a/src/Generating/PrefabPiecePool.h b/src/Generating/PrefabPiecePool.h
index b9c1f0483..a22c6abd4 100644
--- a/src/Generating/PrefabPiecePool.h
+++ b/src/Generating/PrefabPiecePool.h
@@ -16,6 +16,13 @@
+// fwd:
+class cLuaState;
+
+
+
+
+
class cPrefabPiecePool :
public cPiecePool
{
@@ -34,6 +41,10 @@ public:
const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs
);
+ /** Creates a pool and loads the contents of the specified file into it.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ cPrefabPiecePool(const AString & a_FileName, bool a_LogWarnings);
+
/** Destroys the pool, freeing all pieces. */
~cPrefabPiecePool();
@@ -50,6 +61,20 @@ public:
May be called multiple times with different PieceDefs, will add all such pieces. */
void AddStartingPieceDefs(const cPrefab::sDef * a_StartingPieceDefs, size_t a_NumStartingPieceDefs);
+ /** Loads the pieces from the specified file. Returns true if successful, false on error.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ bool LoadFromFile(const AString & a_FileName, bool a_LogWarnings);
+
+ /** Loads the pieces from the specified Cubeset file. Returns true if successful, false on error.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ bool LoadFromCubesetFile(const AString & a_FileName, bool a_LogWarnings);
+
+ /** Returns the number of regular (non-starting) pieces. */
+ size_t GetAllPiecesCount(void) const { return m_AllPieces.size(); }
+
+ /** Returns the number of starting pieces. */
+ size_t GetStartingPiecesCount(void) const { return m_StartingPieces.size(); }
+
protected:
/** The type used to map a connector type to the list of pieces with that connector */
@@ -70,7 +95,61 @@ protected:
/** Adds the prefab to the m_PiecesByConnector map for all its connectors. */
void AddToPerConnectorMap(cPrefab * a_Prefab);
+
+ /** Loads the pieces from the cubeset file parsed into the specified Lua state.
+ Returns true on success, false on error.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ bool LoadFromCubesetFileVer1(const AString & a_FileName, cLuaState & a_LuaState, bool a_LogWarnings);
+
+ /** Loads a single piece from the cubeset file parsed into the specified Lua state.
+ The piece's definition table is expected to be at the top of the Lua stack.
+ Returns true on success, false on error.
+ a_PieceIndex is the index of the piece, in the Pieces table. It is used for logging only.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ bool LoadCubesetPieceVer1(const AString & a_FileName, cLuaState & a_LuaState, int a_PieceIndex, bool a_LogWarnings);
+
+ /** Loads a single piece's prefab from the cubeset file parsed into the specified Lua state.
+ The piece's definition table is expected to be at the top of the Lua stack.
+ Returns the prefab on success, nullptr on failure.
+ a_PieceName is the identification of the piece, used for logging only.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ UniquePtr<cPrefab> LoadPrefabFromCubesetVer1(
+ const AString & a_FileName,
+ cLuaState & a_LuaState,
+ const AString & a_PieceName,
+ bool a_LogWarnings
+ );
+ /** Reads a single piece's connectors from the cubeset file parsed into the specified Lua state.
+ The piece's definition table is expected to be at the top of the Lua stack.
+ Returns true on success, false on failure.
+ The connectors are added into the a_Prefab object.
+ No Connectors table is considered a failure, empty Connectors table is considered a success.
+ If any of the connectors are malformed, it is considered a failure, although the rest of the connectors will still load.
+ a_PieceName is the identification of the piece, used for logging only.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ bool ReadConnectorsCubesetVer1(
+ const AString & a_FileName,
+ cLuaState & a_LuaState,
+ const AString & a_PieceName,
+ cPrefab * a_Prefab,
+ bool a_LogWarnings
+ );
+
+ /** Reads a single piece's metadata from the cubeset file parsed into the specified Lua state.
+ The piece's definition table is expected to be at the top of the Lua stack.
+ Returns true on success, false on failure.
+ The metadata is applied into the a_Prefab object.
+ a_PieceName is the identification of the piece, used for logging only.
+ If a_LogWarnings is true, logs a warning to console when loading fails. */
+ bool ApplyMetadataCubesetVer1(
+ const AString & a_FileName,
+ cLuaState & a_LuaState,
+ const AString & a_PieceName,
+ cPrefab * a_Prefab,
+ bool a_LogWarnings
+ );
+
// cPiecePool overrides:
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
virtual cPieces GetStartingPieces(void) override;
diff --git a/src/Globals.h b/src/Globals.h
index b787a94da..f0e370d2c 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -261,14 +261,15 @@ template class SizeChecker<UInt8, 1>;
+// Common headers (part 1, without macros):
+#include "StringUtils.h"
+#include "OSSupport/CriticalSection.h"
+#include "OSSupport/Event.h"
+#include "OSSupport/File.h"
+#include "OSSupport/StackTrace.h"
+
#ifndef TEST_GLOBALS
- // Common headers (part 1, without macros):
- #include "StringUtils.h"
- #include "OSSupport/CriticalSection.h"
- #include "OSSupport/Event.h"
- #include "OSSupport/File.h"
#include "Logger.h"
- #include "OSSupport/StackTrace.h"
#else
// Logging functions
void inline LOGERROR(const char * a_Format, ...) FORMATSTRING(1, 2);
@@ -315,6 +316,9 @@ void inline LOG(const char * a_Format, ...)
va_end(argList);
}
+#define LOGINFO LOG
+#define LOGWARN LOGWARNING
+
#endif
diff --git a/src/WorldStorage/CMakeLists.txt b/src/WorldStorage/CMakeLists.txt
index 074958191..017d85f27 100644
--- a/src/WorldStorage/CMakeLists.txt
+++ b/src/WorldStorage/CMakeLists.txt
@@ -14,7 +14,8 @@ SET (SRCS
ScoreboardSerializer.cpp
StatSerializer.cpp
WSSAnvil.cpp
- WorldStorage.cpp)
+ WorldStorage.cpp
+)
SET (HDRS
EnchantmentSerializer.h
@@ -26,7 +27,8 @@ SET (HDRS
ScoreboardSerializer.h
StatSerializer.h
WSSAnvil.h
- WorldStorage.h)
+ WorldStorage.h
+)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_source_files_properties(EnchantmentSerializer.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=old-style-cast")
diff --git a/src/WorldStorage/SchematicFileSerializer.cpp b/src/WorldStorage/SchematicFileSerializer.cpp
index 199873968..3e9ed5bef 100644
--- a/src/WorldStorage/SchematicFileSerializer.cpp
+++ b/src/WorldStorage/SchematicFileSerializer.cpp
@@ -238,27 +238,27 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
}
// Copy the block types and metas:
- size_t NumBytes = a_BlockArea.GetBlockCount();
- if (a_NBT.GetDataLength(TBlockTypes) < NumBytes)
+ size_t NumTypeBytes = a_BlockArea.GetBlockCount();
+ if (a_NBT.GetDataLength(TBlockTypes) < NumTypeBytes)
{
- LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
- (int)NumBytes, (int)a_NBT.GetDataLength(TBlockTypes)
+ LOG("BlockTypes truncated in the schematic file (exp %u, got %u bytes). Loading partial.",
+ static_cast<unsigned>(NumTypeBytes), static_cast<unsigned>(a_NBT.GetDataLength(TBlockTypes))
);
- NumBytes = a_NBT.GetDataLength(TBlockTypes);
+ NumTypeBytes = a_NBT.GetDataLength(TBlockTypes);
}
- memcpy(a_BlockArea.m_BlockTypes, a_NBT.GetData(TBlockTypes), NumBytes);
+ memcpy(a_BlockArea.m_BlockTypes, a_NBT.GetData(TBlockTypes), NumTypeBytes);
if (AreMetasPresent)
{
- size_t NumBytes = a_BlockArea.GetBlockCount();
- if (a_NBT.GetDataLength(TBlockMetas) < NumBytes)
+ size_t NumMetaBytes = a_BlockArea.GetBlockCount();
+ if (a_NBT.GetDataLength(TBlockMetas) < NumMetaBytes)
{
- LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.",
- (int)NumBytes, (int)a_NBT.GetDataLength(TBlockMetas)
+ LOG("BlockMetas truncated in the schematic file (exp %u, got %u bytes). Loading partial.",
+ static_cast<unsigned>(NumMetaBytes), static_cast<unsigned>(a_NBT.GetDataLength(TBlockMetas))
);
- NumBytes = a_NBT.GetDataLength(TBlockMetas);
+ NumMetaBytes = a_NBT.GetDataLength(TBlockMetas);
}
- memcpy(a_BlockArea.m_BlockMetas, a_NBT.GetData(TBlockMetas), NumBytes);
+ memcpy(a_BlockArea.m_BlockMetas, a_NBT.GetData(TBlockMetas), NumMetaBytes);
}
return true;