Merge branch 'master' into BlockEntitys
This commit is contained in:
commit
527f358510
@ -134,6 +134,7 @@ g_APIDesc =
|
||||
HasBlockSkyLights = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include skylight" },
|
||||
HasBlockTypes = { Params = "", Return = "bool", Notes = "Returns true if current datatypes include block types" },
|
||||
LoadFromSchematicFile = { Params = "FileName", Return = "", Notes = "Clears current content and loads new content from the specified schematic file. Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
|
||||
LoadFromSchematicString = { Params = "SchematicData", Return = "", Notes = "Clears current content and loads new content from the specified string (assumed to contain .schematic data). Returns true if successful. Returns false and logs error if unsuccessful, old content is preserved in such a case." },
|
||||
Merge =
|
||||
{
|
||||
{ Params = "BlockAreaSrc, {{Vector3i|RelMinCoords}}, Strategy", Return = "", Notes = "Merges BlockAreaSrc into this object at the specified relative coords, using the specified strategy" },
|
||||
@ -161,6 +162,7 @@ g_APIDesc =
|
||||
RotateCW = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Modifies blocks' metas (if present) to match." },
|
||||
RotateCWNoMeta = { Params = "", Return = "", Notes = "Rotates the block area around the Y axis, clockwise (north -> east). Doesn't modify blocks' metas." },
|
||||
SaveToSchematicFile = { Params = "FileName", Return = "", Notes = "Saves the current contents to a schematic file. Returns true if successful." },
|
||||
SaveToSchematicString = { Params = "", Return = "string", Notes = "Saves the current contents to a string (in a .schematic file format). Returns the data if successful, nil if failed." },
|
||||
SetBlockLight = { Params = "BlockX, BlockY, BlockZ, BlockLight", Return = "", Notes = "Sets the blocklight at the specified absolute coords" },
|
||||
SetBlockMeta = { Params = "BlockX, BlockY, BlockZ, BlockMeta", Return = "", Notes = "Sets the block meta at the specified absolute coords" },
|
||||
SetBlockSkyLight = { Params = "BlockX, BlockY, BlockZ, SkyLight", Return = "", Notes = "Sets the skylight at the specified absolute coords" },
|
||||
|
@ -71,6 +71,8 @@ function Initialize(Plugin)
|
||||
-- TestExpatBindings();
|
||||
-- TestPluginCalls();
|
||||
|
||||
TestBlockAreasString()
|
||||
|
||||
return true
|
||||
end;
|
||||
|
||||
@ -202,6 +204,42 @@ end
|
||||
|
||||
|
||||
|
||||
function TestBlockAreasString()
|
||||
-- Write one area to string, then to file:
|
||||
local BA1 = cBlockArea()
|
||||
BA1:Create(5, 5, 5, cBlockArea.baTypes + cBlockArea.baMetas)
|
||||
BA1:Fill(cBlockArea.baTypes, E_BLOCK_DIAMOND_BLOCK)
|
||||
BA1:FillRelCuboid(1, 3, 1, 3, 1, 3, cBlockArea.baTypes, E_BLOCK_GOLD_BLOCK)
|
||||
local Data = BA1:SaveToSchematicString()
|
||||
if ((type(Data) ~= "string") or (Data == "")) then
|
||||
LOG("Cannot save schematic to string")
|
||||
return
|
||||
end
|
||||
cFile:CreateFolder("schematics")
|
||||
local f = io.open("schematics/StringTest.schematic", "w")
|
||||
f:write(Data)
|
||||
f:close()
|
||||
|
||||
-- Load a second area from that file:
|
||||
local BA2 = cBlockArea()
|
||||
if not(BA2:LoadFromSchematicFile("schematics/StringTest.schematic")) then
|
||||
LOG("Cannot read schematic from string test file")
|
||||
return
|
||||
end
|
||||
BA2:Clear()
|
||||
|
||||
-- Load another area from a string in that file:
|
||||
f = io.open("schematics/StringTest.schematic", "r")
|
||||
Data = f:read("*all")
|
||||
if not(BA2:LoadFromSchematicString(Data)) then
|
||||
LOG("Cannot load schematic from string")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function TestSQLiteBindings()
|
||||
LOG("Testing SQLite bindings...");
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
macro (add_flags_lnk FLAGS)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${FLAGS}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${FLAGS}")
|
||||
@ -62,6 +60,7 @@ macro(set_flags)
|
||||
|
||||
# We use a signed char (fixes #640 on RasPi)
|
||||
add_flags_cxx("-fsigned-char")
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
@ -184,6 +183,14 @@ macro(set_exe_flags)
|
||||
string(REPLACE "-w" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
string(REPLACE "-w" "" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||
add_flags_cxx("-Wall -Wextra")
|
||||
|
||||
# we support non-IEEE 754 fpus so can make no guarentees about error
|
||||
add_flags_cxx("-ffast-math")
|
||||
|
||||
# clang does not provide the __extern_always_inline macro and a part of libm depends on this when using fast-math
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
add_flags_cxx("-D__extern_always_inline=inline")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2ceda579893ceb23c5eb0d56df47dc235644e0f4
|
||||
Subproject commit 2cb1a0c4009ecf368ecc74eb428394e10f9e6d00
|
@ -2457,7 +2457,7 @@ static int tolua_cBlockArea_GetSize(lua_State * tolua_S)
|
||||
static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
|
||||
{
|
||||
// function cBlockArea::LoadFromSchematicFile
|
||||
// Exported manually because function has been moved to SchematicFileSerilizer.cpp
|
||||
// Exported manually because function has been moved to SchematicFileSerializer.cpp
|
||||
cLuaState L(tolua_S);
|
||||
if (
|
||||
!L.CheckParamUserType(1, "cBlockArea") ||
|
||||
@ -2484,10 +2484,41 @@ static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
|
||||
|
||||
|
||||
|
||||
static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S)
|
||||
{
|
||||
// function cBlockArea::LoadFromSchematicString
|
||||
// Exported manually because function has been moved to SchematicFileSerializer.cpp
|
||||
cLuaState L(tolua_S);
|
||||
if (
|
||||
!L.CheckParamUserType(1, "cBlockArea") ||
|
||||
!L.CheckParamString (2) ||
|
||||
!L.CheckParamEnd (3)
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
|
||||
if (self == NULL)
|
||||
{
|
||||
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AString Data;
|
||||
L.GetStackValue(2, Data);
|
||||
bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data);
|
||||
tolua_pushboolean(tolua_S, res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
|
||||
{
|
||||
// function cBlockArea::SaveToSchematicFile
|
||||
// Exported manually because function has been moved to SchematicFileSerilizer.cpp
|
||||
// Exported manually because function has been moved to SchematicFileSerializer.cpp
|
||||
cLuaState L(tolua_S);
|
||||
if (
|
||||
!L.CheckParamUserType(1, "cBlockArea") ||
|
||||
@ -2513,6 +2544,38 @@ static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
|
||||
|
||||
|
||||
|
||||
static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S)
|
||||
{
|
||||
// function cBlockArea::SaveToSchematicString
|
||||
// Exported manually because function has been moved to SchematicFileSerializer.cpp
|
||||
cLuaState L(tolua_S);
|
||||
if (
|
||||
!L.CheckParamUserType(1, "cBlockArea") ||
|
||||
!L.CheckParamEnd (2)
|
||||
)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cBlockArea * self = (cBlockArea *)tolua_tousertype(tolua_S, 1, NULL);
|
||||
if (self == NULL)
|
||||
{
|
||||
tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
AString Data;
|
||||
if (cSchematicFileSerializer::SaveToSchematicString(*self, Data))
|
||||
{
|
||||
L.Push(Data);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
|
||||
{
|
||||
// function cCompositeChat:AddRunCommandPart(Message, Command, [Style])
|
||||
@ -2776,12 +2839,14 @@ void ManualBindings::Bind(lua_State * tolua_S)
|
||||
tolua_endmodule(tolua_S);
|
||||
|
||||
tolua_beginmodule(tolua_S, "cBlockArea");
|
||||
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
|
||||
tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
|
||||
tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
|
||||
tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
|
||||
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
|
||||
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
|
||||
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cBlockArea_GetBlockTypeMeta);
|
||||
tolua_function(tolua_S, "GetOrigin", tolua_cBlockArea_GetOrigin);
|
||||
tolua_function(tolua_S, "GetRelBlockTypeMeta", tolua_cBlockArea_GetRelBlockTypeMeta);
|
||||
tolua_function(tolua_S, "GetSize", tolua_cBlockArea_GetSize);
|
||||
tolua_function(tolua_S, "LoadFromSchematicFile", tolua_cBlockArea_LoadFromSchematicFile);
|
||||
tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString);
|
||||
tolua_function(tolua_S, "SaveToSchematicFile", tolua_cBlockArea_SaveToSchematicFile);
|
||||
tolua_function(tolua_S, "SaveToSchematicString", tolua_cBlockArea_SaveToSchematicString);
|
||||
tolua_endmodule(tolua_S);
|
||||
|
||||
tolua_beginmodule(tolua_S, "cCompositeChat");
|
||||
|
@ -26,6 +26,13 @@ public:
|
||||
}
|
||||
|
||||
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
||||
{
|
||||
UNUSED(a_ChunkInterface);
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
}
|
||||
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
// Reset meta to 0
|
||||
|
@ -55,6 +55,29 @@ void cBlockDoorHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||
|
||||
|
||||
|
||||
void cBlockDoorHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
||||
{
|
||||
UNUSED(a_ChunkInterface);
|
||||
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
|
||||
if (Meta & 8)
|
||||
{
|
||||
// Current block is top of the door
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY - 1, a_BlockZ, a_Player);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Current block is bottom of the door
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, a_Player);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cBlockDoorHandler::OnPlacedByPlayer(
|
||||
cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
|
@ -16,6 +16,7 @@ public:
|
||||
|
||||
virtual void OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||
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;
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override;
|
||||
virtual const char * GetStepSound(void) override;
|
||||
|
||||
|
||||
|
@ -48,6 +48,12 @@ public:
|
||||
}
|
||||
|
||||
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
||||
{
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
}
|
||||
|
||||
|
||||
virtual bool IsUseable(void) override
|
||||
{
|
||||
return true;
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "BlockRedstoneLamp.h"
|
||||
#include "BlockRedstoneRepeater.h"
|
||||
#include "BlockRedstoneTorch.h"
|
||||
#include "BlockTNT.h"
|
||||
#include "BlockSand.h"
|
||||
#include "BlockSapling.h"
|
||||
#include "BlockSideways.h"
|
||||
@ -185,6 +186,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
|
||||
case E_BLOCK_TALL_GRASS: return new cBlockTallGrassHandler (a_BlockType);
|
||||
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
|
||||
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
|
||||
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
|
||||
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
|
||||
case E_BLOCK_WALLSIGN: return new cBlockSignHandler (a_BlockType);
|
||||
case E_BLOCK_WATER: return new cBlockFluidHandler (a_BlockType);
|
||||
@ -320,6 +322,14 @@ void cBlockHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface &
|
||||
|
||||
|
||||
|
||||
void cBlockHandler::OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer *a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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.
|
||||
|
@ -69,6 +69,9 @@ public:
|
||||
/// Called if the user right clicks the block and the block is useable
|
||||
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);
|
||||
|
||||
/** Called when a Right Click to this Block is cancelled */
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace);
|
||||
|
||||
/// <summary>Called when the item is mined to convert it into pickups. Pickups may specify multiple items. Appends items to a_Pickups, preserves its original contents</summary>
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta);
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
@ -37,6 +37,13 @@ public:
|
||||
}
|
||||
|
||||
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
||||
{
|
||||
UNUSED(a_ChunkInterface);
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
}
|
||||
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
// Reset meta to 0
|
||||
|
32
src/Blocks/BlockTNT.h
Normal file
32
src/Blocks/BlockTNT.h
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BlockHandler.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockTNTHandler :
|
||||
public cBlockHandler
|
||||
{
|
||||
public:
|
||||
cBlockTNTHandler(BLOCKTYPE a_BlockType)
|
||||
: cBlockHandler(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
virtual const char * GetStepSound(void) override
|
||||
{
|
||||
return "step.grass";
|
||||
}
|
||||
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
||||
{
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -42,6 +42,12 @@ public:
|
||||
World->BroadcastSoundParticleEffect(1003, a_BlockX, a_BlockY, a_BlockZ, 0, a_Player->GetClientHandle());
|
||||
}
|
||||
|
||||
virtual void OnCancelRightClick(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace) override
|
||||
{
|
||||
UNUSED(a_ChunkInterface);
|
||||
a_WorldInterface.SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, a_Player);
|
||||
}
|
||||
|
||||
virtual bool GetPlacementBlockTypeMeta(
|
||||
cChunkInterface & a_ChunkInterface, cPlayer * a_Player,
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace,
|
||||
|
@ -27,4 +27,7 @@ public:
|
||||
|
||||
/** Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise */
|
||||
virtual int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType) = 0;
|
||||
|
||||
/** Sends the block on those coords to the player */
|
||||
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer * a_Player) = 0;
|
||||
};
|
||||
|
@ -920,14 +920,22 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, ItemToFullString(a_HeldItem).c_str()
|
||||
);
|
||||
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
|
||||
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
||||
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
||||
{
|
||||
// A plugin doesn't agree with the action, replace the block on the client and quit:
|
||||
cChunkInterface ChunkInterface(World->GetChunkMap());
|
||||
BLOCKTYPE BlockType = World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
cBlockHandler * BlockHandler = cBlockInfo::GetHandler(BlockType);
|
||||
BlockHandler->OnCancelRightClick(ChunkInterface, *World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
|
||||
if (a_BlockFace > -1)
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); //2 block high things
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -953,12 +961,10 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
||||
if (a_BlockFace > -1)
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
|
@ -204,6 +204,12 @@ void cInventory::SetSlot(int a_SlotNum, const cItem & a_Item)
|
||||
return;
|
||||
}
|
||||
Grid->SetSlot(GridSlotNum, a_Item);
|
||||
|
||||
// Broadcast the Equipped Item, if the Slot is changed.
|
||||
if ((Grid == &m_HotbarSlots) && (m_EquippedSlotNum == (a_SlotNum - invHotbarOffset)))
|
||||
{
|
||||
m_Owner.GetWorld()->BroadcastEntityEquipment(m_Owner, 0, a_Item, m_Owner.GetClientHandle());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -506,7 +506,7 @@ bool cScoreboard::ForEachObjective(cObjectiveCallback& a_Callback)
|
||||
|
||||
bool cScoreboard::ForEachTeam(cTeamCallback& a_Callback)
|
||||
{
|
||||
cCSLock Lock(m_CSObjectives);
|
||||
cCSLock Lock(m_CSTeams);
|
||||
|
||||
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
|
||||
{
|
||||
|
@ -54,14 +54,23 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
|
||||
a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ)
|
||||
);
|
||||
|
||||
NIBBLETYPE MyMeta = a_Chunk->GetMeta(a_RelX, a_RelY, a_RelZ);
|
||||
if (!IsAnyFluidBlock(a_Chunk->GetBlock(a_RelX, a_RelY, a_RelZ)))
|
||||
BLOCKTYPE MyBlock; NIBBLETYPE MyMeta;
|
||||
a_Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta);
|
||||
|
||||
if (!IsAnyFluidBlock(MyBlock))
|
||||
{
|
||||
// Can happen - if a block is scheduled for simulating and gets replaced in the meantime.
|
||||
FLOG(" BadBlockType exit");
|
||||
return;
|
||||
}
|
||||
|
||||
// When in contact with water, lava should harden
|
||||
if (HardenBlock(a_Chunk, a_RelX, a_RelY, a_RelZ, MyBlock, MyMeta))
|
||||
{
|
||||
// Block was changed, bail out
|
||||
return;
|
||||
}
|
||||
|
||||
if (MyMeta != 0)
|
||||
{
|
||||
// Source blocks aren't checked for tributaries, others are.
|
||||
@ -86,7 +95,12 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
|
||||
{
|
||||
// Spread only down, possibly washing away what's there or turning lava to stone / cobble / obsidian:
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY - 1, a_RelZ, 8);
|
||||
SpreadFurther = false;
|
||||
|
||||
// Source blocks spread both downwards and sideways
|
||||
if (MyMeta != 0)
|
||||
{
|
||||
SpreadFurther = false;
|
||||
}
|
||||
}
|
||||
// If source creation is on, check for it here:
|
||||
else if (
|
||||
@ -105,10 +119,7 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
|
||||
if (SpreadFurther && (NewMeta < 8))
|
||||
{
|
||||
// Spread to the neighbors:
|
||||
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, NewMeta);
|
||||
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, NewMeta);
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, NewMeta);
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, NewMeta);
|
||||
Spread(a_Chunk, a_RelX, a_RelY, a_RelZ, NewMeta);
|
||||
}
|
||||
|
||||
// Mark as processed:
|
||||
@ -119,6 +130,17 @@ void cFloodyFluidSimulator::SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_Re
|
||||
|
||||
|
||||
|
||||
void cFloodyFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
|
||||
{
|
||||
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
|
||||
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFloodyFluidSimulator::CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta)
|
||||
{
|
||||
// If we have a section above, check if there's fluid above this block that would feed it:
|
||||
@ -296,6 +318,8 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
|
||||
a_NewMeta
|
||||
);
|
||||
a_NearChunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
|
||||
|
||||
HardenBlock(a_NearChunk, a_RelX, a_RelY, a_RelZ, m_FluidBlock, a_NewMeta);
|
||||
}
|
||||
|
||||
|
||||
@ -348,3 +372,56 @@ bool cFloodyFluidSimulator::CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFloodyFluidSimulator::HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
|
||||
{
|
||||
// Only lava blocks can harden
|
||||
if (!IsBlockLava(a_BlockType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShouldHarden = false;
|
||||
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
static const Vector3i Coords[] =
|
||||
{
|
||||
Vector3i( 1, 0, 0),
|
||||
Vector3i(-1, 0, 0),
|
||||
Vector3i( 0, 0, 1),
|
||||
Vector3i( 0, 0, -1),
|
||||
};
|
||||
for (size_t i = 0; i < ARRAYCOUNT(Coords); i++)
|
||||
{
|
||||
if (!a_Chunk->UnboundedRelGetBlock(a_RelX + Coords[i].x, a_RelY, a_RelZ + Coords[i].z, BlockType, BlockMeta))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (IsBlockWater(BlockType))
|
||||
{
|
||||
ShouldHarden = true;
|
||||
}
|
||||
} // for i - Coords[]
|
||||
|
||||
if (ShouldHarden)
|
||||
{
|
||||
if (a_Meta == 0)
|
||||
{
|
||||
// Source lava block
|
||||
a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_OBSIDIAN, 0);
|
||||
return true;
|
||||
}
|
||||
// Ignore last lava level
|
||||
else if (a_Meta <= 4)
|
||||
{
|
||||
a_Chunk->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ, E_BLOCK_COBBLESTONE, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -38,14 +38,26 @@ protected:
|
||||
// cDelayedFluidSimulator overrides:
|
||||
virtual void SimulateBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override;
|
||||
|
||||
/// Checks tributaries, if not fed, decreases the block's level and returns true
|
||||
/** Checks tributaries, if not fed, decreases the block's level and returns true. */
|
||||
bool CheckTributaries(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_MyMeta);
|
||||
|
||||
/// Spreads into the specified block, if the blocktype there allows. a_Area is for checking.
|
||||
/** Spreads into the specified block, if the blocktype there allows. a_Area is for checking. */
|
||||
void SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
|
||||
|
||||
/// Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so
|
||||
/** Checks if there are enough neighbors to create a source at the coords specified; turns into source and returns true if so. */
|
||||
bool CheckNeighborsForSource(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ);
|
||||
|
||||
/** Checks if the specified block should harden (Water/Lava interaction) and if so, converts it to a suitable block.
|
||||
*
|
||||
* Returns whether the block was changed or not.
|
||||
*/
|
||||
bool HardenBlock(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta);
|
||||
|
||||
/** Spread water to neighbors.
|
||||
*
|
||||
* May be overridden to provide more sophisticated algorithms.
|
||||
*/
|
||||
virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta);
|
||||
} ;
|
||||
|
||||
|
||||
|
150
src/Simulator/VanillaFluidSimulator.cpp
Normal file
150
src/Simulator/VanillaFluidSimulator.cpp
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
// VanillaFluidSimulator.cpp
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include "VanillaFluidSimulator.h"
|
||||
#include "../World.h"
|
||||
#include "../Chunk.h"
|
||||
#include "../BlockArea.h"
|
||||
#include "../Blocks/BlockHandler.h"
|
||||
#include "../BlockInServerPluginInterface.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static const int InfiniteCost = 100;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cVanillaFluidSimulator::cVanillaFluidSimulator(
|
||||
cWorld & a_World,
|
||||
BLOCKTYPE a_Fluid,
|
||||
BLOCKTYPE a_StationaryFluid,
|
||||
NIBBLETYPE a_Falloff,
|
||||
int a_TickDelay,
|
||||
int a_NumNeighborsForSource
|
||||
) : super(a_World, a_Fluid, a_StationaryFluid, a_Falloff, a_TickDelay, a_NumNeighborsForSource)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cVanillaFluidSimulator::Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta)
|
||||
{
|
||||
int Cost[4];
|
||||
Cost[0] = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS);
|
||||
Cost[1] = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS);
|
||||
Cost[2] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS);
|
||||
Cost[3] = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS);
|
||||
|
||||
int MinCost = InfiniteCost;
|
||||
for (unsigned int i = 0; i < ARRAYCOUNT(Cost); ++i)
|
||||
{
|
||||
if (Cost[i] < MinCost)
|
||||
{
|
||||
MinCost = Cost[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (Cost[0] == MinCost)
|
||||
{
|
||||
SpreadToNeighbor(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, a_NewMeta);
|
||||
}
|
||||
if (Cost[1] == MinCost)
|
||||
{
|
||||
SpreadToNeighbor(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, a_NewMeta);
|
||||
}
|
||||
if (Cost[2] == MinCost)
|
||||
{
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, a_NewMeta);
|
||||
}
|
||||
if (Cost[3] == MinCost)
|
||||
{
|
||||
SpreadToNeighbor(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, a_NewMeta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cVanillaFluidSimulator::CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration)
|
||||
{
|
||||
int Cost = InfiniteCost;
|
||||
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
|
||||
// Check if block is passable
|
||||
if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ, BlockType, BlockMeta))
|
||||
{
|
||||
return Cost;
|
||||
}
|
||||
if (!IsPassableForFluid(BlockType) && !IsBlockLiquid(BlockType))
|
||||
{
|
||||
return Cost;
|
||||
}
|
||||
|
||||
// Check if block below is passable
|
||||
if (!a_Chunk->UnboundedRelGetBlock(a_RelX, a_RelY - 1, a_RelZ, BlockType, BlockMeta))
|
||||
{
|
||||
return Cost;
|
||||
}
|
||||
if (IsPassableForFluid(BlockType) || IsBlockLiquid(BlockType))
|
||||
{
|
||||
// Path found, exit
|
||||
return a_Iteration;
|
||||
}
|
||||
|
||||
// 5 blocks away, bail out
|
||||
if (a_Iteration > 3)
|
||||
{
|
||||
return Cost;
|
||||
}
|
||||
|
||||
// Recurse
|
||||
if (a_Dir != X_MINUS)
|
||||
{
|
||||
int NextCost = CalculateFlowCost(a_Chunk, a_RelX + 1, a_RelY, a_RelZ, X_PLUS, a_Iteration + 1);
|
||||
if (NextCost < Cost)
|
||||
{
|
||||
Cost = NextCost;
|
||||
}
|
||||
}
|
||||
if (a_Dir != X_PLUS)
|
||||
{
|
||||
int NextCost = CalculateFlowCost(a_Chunk, a_RelX - 1, a_RelY, a_RelZ, X_MINUS, a_Iteration + 1);
|
||||
if (NextCost < Cost)
|
||||
{
|
||||
Cost = NextCost;
|
||||
}
|
||||
}
|
||||
if (a_Dir != Z_MINUS)
|
||||
{
|
||||
int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ + 1, Z_PLUS, a_Iteration + 1);
|
||||
if (NextCost < Cost)
|
||||
{
|
||||
Cost = NextCost;
|
||||
}
|
||||
}
|
||||
if (a_Dir != Z_PLUS)
|
||||
{
|
||||
int NextCost = CalculateFlowCost(a_Chunk, a_RelX, a_RelY, a_RelZ - 1, Z_MINUS, a_Iteration + 1);
|
||||
if (NextCost < Cost)
|
||||
{
|
||||
Cost = NextCost;
|
||||
}
|
||||
}
|
||||
|
||||
return Cost;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
42
src/Simulator/VanillaFluidSimulator.h
Normal file
42
src/Simulator/VanillaFluidSimulator.h
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
// VanillaFluidSimulator.h
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FloodyFluidSimulator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class cBlockArea;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cVanillaFluidSimulator :
|
||||
public cFloodyFluidSimulator
|
||||
{
|
||||
typedef cFloodyFluidSimulator super;
|
||||
|
||||
public:
|
||||
cVanillaFluidSimulator(cWorld & a_World, BLOCKTYPE a_Fluid, BLOCKTYPE a_StationaryFluid, NIBBLETYPE a_Falloff, int a_TickDelay, int a_NumNeighborsForSource);
|
||||
|
||||
protected:
|
||||
// cFloodyFluidSimulator overrides:
|
||||
virtual void Spread(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE a_NewMeta) override;
|
||||
|
||||
/** Recursively calculates the minimum number of blocks needed to descend a level. */
|
||||
int CalculateFlowCost(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, Direction a_Dir, unsigned a_Iteration = 0);
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "Simulator/NoopRedstoneSimulator.h"
|
||||
#include "Simulator/SandSimulator.h"
|
||||
#include "Simulator/IncrementalRedstoneSimulator.h"
|
||||
#include "Simulator/VanillaFluidSimulator.h"
|
||||
#include "Simulator/VaporizeFluidSimulator.h"
|
||||
|
||||
// Mobs:
|
||||
@ -3062,8 +3063,8 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
||||
AString SimulatorName = a_IniFile.GetValueSet("Physics", SimulatorNameKey, "");
|
||||
if (SimulatorName.empty())
|
||||
{
|
||||
LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Floody\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
|
||||
SimulatorName = "Floody";
|
||||
LOGWARNING("[Physics] %s not present or empty in %s, using the default of \"Vanilla\".", SimulatorNameKey.c_str(), GetIniFileName().c_str());
|
||||
SimulatorName = "Vanilla";
|
||||
}
|
||||
|
||||
cFluidSimulator * res = NULL;
|
||||
@ -3087,15 +3088,24 @@ cFluidSimulator * cWorld::InitializeFluidSimulator(cIniFile & a_IniFile, const c
|
||||
}
|
||||
else
|
||||
{
|
||||
if (NoCaseCompare(SimulatorName, "floody") != 0)
|
||||
{
|
||||
// The simulator name doesn't match anything we have, issue a warning:
|
||||
LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Floody\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
|
||||
}
|
||||
int Falloff = a_IniFile.GetValueSetI(SimulatorSectionName, "Falloff", IsWater ? 1 : 2);
|
||||
int TickDelay = a_IniFile.GetValueSetI(SimulatorSectionName, "TickDelay", IsWater ? 5 : 30);
|
||||
int NumNeighborsForSource = a_IniFile.GetValueSetI(SimulatorSectionName, "NumNeighborsForSource", IsWater ? 2 : -1);
|
||||
res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||
|
||||
if (NoCaseCompare(SimulatorName, "floody") == 0)
|
||||
{
|
||||
res = new cFloodyFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||
}
|
||||
else if (NoCaseCompare(SimulatorName, "vanilla") == 0)
|
||||
{
|
||||
res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The simulator name doesn't match anything we have, issue a warning:
|
||||
LOGWARNING("%s [Physics]:%s specifies an unknown simulator, using the default \"Vanilla\".", GetIniFileName().c_str(), SimulatorNameKey.c_str());
|
||||
res = new cVanillaFluidSimulator(*this, a_SimulateBlock, a_StationaryBlock, Falloff, TickDelay, NumNeighborsForSource);
|
||||
}
|
||||
}
|
||||
|
||||
m_SimulatorManager->RegisterSimulator(res, Rate);
|
||||
|
@ -457,7 +457,7 @@ public:
|
||||
|
||||
// tolua_begin
|
||||
bool DigBlock (int a_X, int a_Y, int a_Z);
|
||||
void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player );
|
||||
virtual void SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player);
|
||||
|
||||
double GetSpawnX(void) const { return m_SpawnX; }
|
||||
double GetSpawnY(void) const { return m_SpawnY; }
|
||||
|
@ -1,10 +1,18 @@
|
||||
|
||||
// SchematicFileSerializer.cpp
|
||||
|
||||
// Implements the cSchematicFileSerializer class representing the interface to load and save cBlockArea to a .schematic file
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include "OSSupport/GZipFile.h"
|
||||
#include "FastNBT.h"
|
||||
|
||||
#include "SchematicFileSerializer.h"
|
||||
#include "../StringCompression.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
|
||||
{
|
||||
@ -40,48 +48,51 @@ bool cSchematicFileSerializer::LoadFromSchematicFile(cBlockArea & a_BlockArea, c
|
||||
|
||||
|
||||
|
||||
bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName)
|
||||
bool cSchematicFileSerializer::LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData)
|
||||
{
|
||||
cFastNBTWriter Writer("Schematic");
|
||||
Writer.AddShort("Width", a_BlockArea.m_SizeX);
|
||||
Writer.AddShort("Height", a_BlockArea.m_SizeY);
|
||||
Writer.AddShort("Length", a_BlockArea.m_SizeZ);
|
||||
Writer.AddString("Materials", "Alpha");
|
||||
if (a_BlockArea.HasBlockTypes())
|
||||
// Uncompress the data:
|
||||
AString UngzippedData;
|
||||
if (UncompressStringGZIP(a_SchematicData.data(), a_SchematicData.size(), UngzippedData) != Z_OK)
|
||||
{
|
||||
Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
|
||||
LOG("%s: Cannot unGZip the schematic data.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
||||
// Parse the NBT:
|
||||
cParsedNBT NBT(UngzippedData.data(), UngzippedData.size());
|
||||
if (!NBT.IsValid())
|
||||
{
|
||||
AString Dummy(a_BlockArea.GetBlockCount(), 0);
|
||||
Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
|
||||
LOG("%s: Cannot parse the NBT in the schematic data.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
if (a_BlockArea.HasBlockMetas())
|
||||
|
||||
return LoadFromSchematicNBT(a_BlockArea, NBT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSchematicFileSerializer::SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName)
|
||||
{
|
||||
// Serialize into NBT data:
|
||||
AString NBT = SaveToSchematicNBT(a_BlockArea);
|
||||
if (NBT.empty())
|
||||
{
|
||||
Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
|
||||
LOG("%s: Cannot serialize the area into an NBT representation for file \"%s\".", __FUNCTION__, a_FileName.c_str());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
AString Dummy(a_BlockArea.GetBlockCount(), 0);
|
||||
Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
|
||||
}
|
||||
// TODO: Save entities and block entities
|
||||
Writer.BeginList("Entities", TAG_Compound);
|
||||
Writer.EndList();
|
||||
Writer.BeginList("TileEntities", TAG_Compound);
|
||||
Writer.EndList();
|
||||
Writer.Finish();
|
||||
|
||||
// Save to file
|
||||
cGZipFile File;
|
||||
if (!File.Open(a_FileName, cGZipFile::fmWrite))
|
||||
{
|
||||
LOG("Cannot open file \"%s\" for writing.", a_FileName.c_str());
|
||||
LOG("%s: Cannot open file \"%s\" for writing.", __FUNCTION__, a_FileName.c_str());
|
||||
return false;
|
||||
}
|
||||
if (!File.Write(Writer.GetResult()))
|
||||
if (!File.Write(NBT))
|
||||
{
|
||||
LOG("Cannot write data to file \"%s\".", a_FileName.c_str());
|
||||
LOG("%s: Cannot write data to file \"%s\".", __FUNCTION__, a_FileName.c_str());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -92,6 +103,30 @@ bool cSchematicFileSerializer::SaveToSchematicFile(cBlockArea & a_BlockArea, con
|
||||
|
||||
|
||||
|
||||
bool cSchematicFileSerializer::SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out)
|
||||
{
|
||||
// Serialize into NBT data:
|
||||
AString NBT = SaveToSchematicNBT(a_BlockArea);
|
||||
if (NBT.empty())
|
||||
{
|
||||
LOG("%s: Cannot serialize the area into an NBT representation.", __FUNCTION__);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Gzip the data:
|
||||
int res = CompressStringGZIP(NBT.data(), NBT.size(), a_Out);
|
||||
if (res != Z_OK)
|
||||
{
|
||||
LOG("%s: Cannot Gzip the area data NBT representation: %d", __FUNCTION__, res);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT)
|
||||
{
|
||||
int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials");
|
||||
@ -170,3 +205,45 @@ bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cP
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cSchematicFileSerializer::SaveToSchematicNBT(const cBlockArea & a_BlockArea)
|
||||
{
|
||||
cFastNBTWriter Writer("Schematic");
|
||||
Writer.AddShort("Width", a_BlockArea.m_SizeX);
|
||||
Writer.AddShort("Height", a_BlockArea.m_SizeY);
|
||||
Writer.AddShort("Length", a_BlockArea.m_SizeZ);
|
||||
Writer.AddString("Materials", "Alpha");
|
||||
if (a_BlockArea.HasBlockTypes())
|
||||
{
|
||||
Writer.AddByteArray("Blocks", (const char *)a_BlockArea.m_BlockTypes, a_BlockArea.GetBlockCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
AString Dummy(a_BlockArea.GetBlockCount(), 0);
|
||||
Writer.AddByteArray("Blocks", Dummy.data(), Dummy.size());
|
||||
}
|
||||
if (a_BlockArea.HasBlockMetas())
|
||||
{
|
||||
Writer.AddByteArray("Data", (const char *)a_BlockArea.m_BlockMetas, a_BlockArea.GetBlockCount());
|
||||
}
|
||||
else
|
||||
{
|
||||
AString Dummy(a_BlockArea.GetBlockCount(), 0);
|
||||
Writer.AddByteArray("Data", Dummy.data(), Dummy.size());
|
||||
}
|
||||
|
||||
// TODO: Save entities and block entities
|
||||
Writer.BeginList("Entities", TAG_Compound);
|
||||
Writer.EndList();
|
||||
Writer.BeginList("TileEntities", TAG_Compound);
|
||||
Writer.EndList();
|
||||
Writer.Finish();
|
||||
|
||||
return Writer.GetResult();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,12 @@
|
||||
|
||||
// SchematicFileSerializer.h
|
||||
|
||||
// Declares the cSchematicFileSerializer class representing the interface to load and save cBlockArea to a .schematic file
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../BlockArea.h"
|
||||
@ -13,17 +21,34 @@ class cParsedNBT;
|
||||
|
||||
|
||||
|
||||
|
||||
class cSchematicFileSerializer
|
||||
{
|
||||
public:
|
||||
|
||||
/// Loads an area from a .schematic file. Returns true if successful
|
||||
/** Loads an area from a .schematic file. Returns true if successful. */
|
||||
static bool LoadFromSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
|
||||
|
||||
/// Saves the area into a .schematic file. Returns true if successful
|
||||
static bool SaveToSchematicFile(cBlockArea & a_BlockArea, const AString & a_FileName);
|
||||
/** Loads an area from a string containing the .schematic file data. Returns true if successful. */
|
||||
static bool LoadFromSchematicString(cBlockArea & a_BlockArea, const AString & a_SchematicData);
|
||||
|
||||
/** Saves the area into a .schematic file. Returns true if successful. */
|
||||
static bool SaveToSchematicFile(const cBlockArea & a_BlockArea, const AString & a_FileName);
|
||||
|
||||
/** Saves the area into a string containing the .schematic file data.
|
||||
Returns true if successful, false on failure. The data is stored into a_Out. */
|
||||
static bool SaveToSchematicString(const cBlockArea & a_BlockArea, AString & a_Out);
|
||||
|
||||
private:
|
||||
/// Loads the area from a schematic file uncompressed and parsed into a NBT tree. Returns true if successful.
|
||||
/** Loads the area from a schematic file uncompressed and parsed into a NBT tree.
|
||||
Returns true if successful. */
|
||||
static bool LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT);
|
||||
|
||||
/** Saves the area into a NBT representation and returns the NBT data as a string.
|
||||
Returns an empty string if failed. */
|
||||
static AString SaveToSchematicNBT(const cBlockArea & a_BlockArea);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user