1
0

Merge pull request #1154 from mc-server/trappedchests

Implemented trapped chests & others
This commit is contained in:
Tiger Wang 2014-07-12 23:24:32 +01:00
commit 5f72cdac38
26 changed files with 387 additions and 218 deletions

View File

@ -28,24 +28,26 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); 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_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World, a_BlockType);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(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); case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_FLOWER_POT: return new cFlowerPotEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World); case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HEAD: return new cMobHeadEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_TRAPPED_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World, a_BlockType);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World); case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
} }
LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)", LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str() __FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()
); );
ASSERT(!"Requesting creation of an unknown block entity");
return NULL; return NULL;
} }

View File

@ -11,8 +11,9 @@
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) :
super(E_BLOCK_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World) super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_NumActivePlayers(0)
{ {
cBlockEntityWindowOwner::SetBlockEntity(this); cBlockEntityWindowOwner::SetBlockEntity(this);
} }
@ -113,7 +114,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
// The few false positives aren't much to worry about // The few false positives aren't much to worry about
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ); cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
m_World->MarkChunkDirty(ChunkX, ChunkZ); m_World->MarkChunkDirty(ChunkX, ChunkZ, true);
} }

View File

@ -34,8 +34,8 @@ public:
// tolua_end // tolua_end
/// Constructor used for normal operation /** Constructor used for normal operation */
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type);
virtual ~cChestEntity(); virtual ~cChestEntity();
@ -48,8 +48,20 @@ public:
virtual void SendTo(cClientHandle & a_Client) override; virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override; virtual void UsedBy(cPlayer * a_Player) override;
/// Opens a new chest window for this chest. Scans for neighbors to open a double chest window, if appropriate. /** Opens a new chest window for this chest.
Scans for neighbors to open a double chest window, if appropriate. */
void OpenNewWindow(void); void OpenNewWindow(void);
/** Gets the number of players who currently have this chest open */
int GetNumberOfPlayers(void) const { return m_NumActivePlayers; }
/** Sets the number of players who currently have this chest open */
void SetNumberOfPlayers(int a_NumActivePlayers) { m_NumActivePlayers = a_NumActivePlayers; }
private:
/** Number of players who currently have this chest open */
int m_NumActivePlayers;
} ; // tolua_export } ; // tolua_export

View File

@ -157,6 +157,7 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
bool res = false; bool res = false;
switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ)) switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ))
{ {
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
{ {
// Chests have special handling because of double-chests // Chests have special handling because of double-chests
@ -322,6 +323,7 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
bool res = false; bool res = false;
switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ)) switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ))
{ {
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
{ {
// Chests have special handling because of double-chests // Chests have special handling because of double-chests
@ -378,7 +380,7 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
return true; return true;
} }
// Check if the chest is a double-chest, if so, try to move from there: // Check if the chest is a double-chest (chest directly above was empty), if so, try to move from there:
static const struct static const struct
{ {
int x, z; int x, z;
@ -395,13 +397,18 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
int x = m_RelX + Coords[i].x; int x = m_RelX + Coords[i].x;
int z = m_RelZ + Coords[i].z; int z = m_RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z); cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if ( if (Neighbor == NULL)
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
)
{ {
continue; continue;
} }
BLOCKTYPE Block = Neighbor->GetBlock(x, m_PosY + 1, z);
if (Block != Chest->GetBlockType())
{
// Not the same kind of chest
continue;
}
Chest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z); Chest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
if (Chest == NULL) if (Chest == NULL)
{ {
@ -550,10 +557,11 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
} }
if (MoveItemsToGrid(*Chest)) if (MoveItemsToGrid(*Chest))
{ {
// Chest block directly connected was not full
return true; return true;
} }
// Check if the chest is a double-chest, if so, try to move into the other half: // Check if the chest is a double-chest (chest block directly connected was full), if so, try to move into the other half:
static const struct static const struct
{ {
int x, z; int x, z;
@ -572,13 +580,18 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
int x = RelX + Coords[i].x; int x = RelX + Coords[i].x;
int z = RelZ + Coords[i].z; int z = RelZ + Coords[i].z;
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z); cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
if ( if (Neighbor == NULL)
(Neighbor == NULL) ||
(Neighbor->GetBlock(x, a_BlockY, z) != E_BLOCK_CHEST)
)
{ {
continue; continue;
} }
BLOCKTYPE Block = Neighbor->GetBlock(x, a_BlockY, z);
if (Block != Chest->GetBlockType())
{
// Not the same kind of chest
continue;
}
Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z); Chest = (cChestEntity *)Neighbor->GetBlockEntity(a_BlockX + Coords[i].x, a_BlockY, a_BlockZ + Coords[i].z);
if (Chest == NULL) if (Chest == NULL)
{ {

View File

@ -101,6 +101,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_SIGN_POST ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_TORCH ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRAPPED_CHEST ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRIPWIRE ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_TRIPWIRE ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_SpreadLightFalloff = 1;
a_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1; a_Info[E_BLOCK_VINES ].m_SpreadLightFalloff = 1;
@ -162,6 +163,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true; a_Info[E_BLOCK_STATIONARY_WATER ].m_Transparent = true;
a_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true; a_Info[E_BLOCK_STONE_BUTTON ].m_Transparent = true;
a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true; a_Info[E_BLOCK_STONE_PRESSURE_PLATE].m_Transparent = true;
a_Info[E_BLOCK_TRAPPED_CHEST ].m_Transparent = true;
a_Info[E_BLOCK_TRIPWIRE ].m_Transparent = true; a_Info[E_BLOCK_TRIPWIRE ].m_Transparent = true;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_Transparent = true;
a_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true; a_Info[E_BLOCK_TALL_GRASS ].m_Transparent = true;
@ -287,6 +289,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
a_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false; a_Info[E_BLOCK_TALL_GRASS ].m_IsSnowable = false;
a_Info[E_BLOCK_TNT ].m_IsSnowable = false; a_Info[E_BLOCK_TNT ].m_IsSnowable = false;
a_Info[E_BLOCK_TORCH ].m_IsSnowable = false; a_Info[E_BLOCK_TORCH ].m_IsSnowable = false;
a_Info[E_BLOCK_TRAPPED_CHEST ].m_IsSnowable = false;
a_Info[E_BLOCK_TRIPWIRE ].m_IsSnowable = false; a_Info[E_BLOCK_TRIPWIRE ].m_IsSnowable = false;
a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_IsSnowable = false; a_Info[E_BLOCK_TRIPWIRE_HOOK ].m_IsSnowable = false;
a_Info[E_BLOCK_VINES ].m_IsSnowable = false; a_Info[E_BLOCK_VINES ].m_IsSnowable = false;

View File

@ -44,16 +44,16 @@ public:
} }
double yaw = a_Player->GetYaw(); double yaw = a_Player->GetYaw();
if ( if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
) )
{ {
a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3; a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true; return true;
} }
if ( if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
) )
{ {
// FIXME: This is unreachable, as the condition is the same as the above one // FIXME: This is unreachable, as the condition is the same as the above one
@ -130,12 +130,12 @@ public:
} }
int NumChestNeighbors = 0; int NumChestNeighbors = 0;
if (Area.GetRelBlockType(1, 0, 2) == E_BLOCK_CHEST) if (Area.GetRelBlockType(1, 0, 2) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(0, 0, 2) == E_BLOCK_CHEST) || (Area.GetRelBlockType(0, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST) (Area.GetRelBlockType(1, 0, 3) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -143,12 +143,12 @@ public:
} }
NumChestNeighbors += 1; NumChestNeighbors += 1;
} }
if (Area.GetRelBlockType(3, 0, 2) == E_BLOCK_CHEST) if (Area.GetRelBlockType(3, 0, 2) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(4, 0, 2) == E_BLOCK_CHEST) || (Area.GetRelBlockType(4, 0, 2) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(3, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST) (Area.GetRelBlockType(3, 0, 3) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -156,12 +156,12 @@ public:
} }
NumChestNeighbors += 1; NumChestNeighbors += 1;
} }
if (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST) if (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(2, 0, 0) == E_BLOCK_CHEST) || (Area.GetRelBlockType(2, 0, 0) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) || (Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST) (Area.GetRelBlockType(3, 0, 1) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -169,12 +169,12 @@ public:
} }
NumChestNeighbors += 1; NumChestNeighbors += 1;
} }
if (Area.GetRelBlockType(2, 0, 3) == E_BLOCK_CHEST) if (Area.GetRelBlockType(2, 0, 3) == m_BlockType)
{ {
if ( if (
(Area.GetRelBlockType(2, 0, 4) == E_BLOCK_CHEST) || (Area.GetRelBlockType(2, 0, 4) == m_BlockType) ||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST) || (Area.GetRelBlockType(1, 0, 3) == m_BlockType) ||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST) (Area.GetRelBlockType(3, 0, 3) == m_BlockType)
) )
{ {
// Already a doublechest neighbor, disallow: // Already a doublechest neighbor, disallow:
@ -217,7 +217,7 @@ public:
/// If there's a chest in the a_Area in the specified coords, modifies its meta to a_NewMeta and returns true. /// If there's a chest in the a_Area in the specified coords, modifies its meta to a_NewMeta and returns true.
bool CheckAndAdjustNeighbor(cChunkInterface & a_ChunkInterface, const cBlockArea & a_Area, int a_RelX, int a_RelZ, NIBBLETYPE a_NewMeta) bool CheckAndAdjustNeighbor(cChunkInterface & a_ChunkInterface, const cBlockArea & a_Area, int a_RelX, int a_RelZ, NIBBLETYPE a_NewMeta)
{ {
if (a_Area.GetRelBlockType(a_RelX, 0, a_RelZ) != E_BLOCK_CHEST) if (a_Area.GetRelBlockType(a_RelX, 0, a_RelZ) != m_BlockType)
{ {
return false; return false;
} }
@ -228,7 +228,7 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{ {
a_Pickups.push_back(cItem(E_BLOCK_CHEST, 1, 0)); a_Pickups.push_back(cItem(m_BlockType, 1, 0));
} }
} ; } ;

View File

@ -176,7 +176,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
{ {
switch(a_BlockType) switch(a_BlockType)
{ {
// Block handlers, alphabetically sorted: // Block handlers, alphabetically sorted:
case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType); case E_BLOCK_ACACIA_WOOD_STAIRS: return new cBlockStairsHandler (a_BlockType);
case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType); case E_BLOCK_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType); case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
@ -238,9 +238,9 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_LAPIS_ORE: return new cBlockOreHandler (a_BlockType); case E_BLOCK_LAPIS_ORE: return new cBlockOreHandler (a_BlockType);
case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType); case E_BLOCK_LAVA: return new cBlockLavaHandler (a_BlockType);
case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType); case E_BLOCK_LEAVES: return new cBlockLeavesHandler (a_BlockType);
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(a_BlockType);
case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType); case E_BLOCK_LILY_PAD: return new cBlockLilypadHandler (a_BlockType);
case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType); case E_BLOCK_LIT_FURNACE: return new cBlockFurnaceHandler (a_BlockType);
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: return new cBlockPressurePlateHandler(a_BlockType);
case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType); case E_BLOCK_LOG: return new cBlockSidewaysHandler (a_BlockType);
case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType); case E_BLOCK_MELON: return new cBlockMelonHandler (a_BlockType);
case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType); case E_BLOCK_MELON_STEM: return new cBlockStemsHandler (a_BlockType);
@ -293,6 +293,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType); case E_BLOCK_TORCH: return new cBlockTorchHandler (a_BlockType);
case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType); case E_BLOCK_TRAPDOOR: return new cBlockTrapdoorHandler (a_BlockType);
case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType); case E_BLOCK_TNT: return new cBlockTNTHandler (a_BlockType);
case E_BLOCK_TRAPPED_CHEST: return new cBlockChestHandler (a_BlockType);
case E_BLOCK_TRIPWIRE: return new cBlockTripwireHandler (a_BlockType); case E_BLOCK_TRIPWIRE: return new cBlockTripwireHandler (a_BlockType);
case E_BLOCK_TRIPWIRE_HOOK: return new cBlockTripwireHookHandler (a_BlockType); case E_BLOCK_TRIPWIRE_HOOK: return new cBlockTripwireHookHandler (a_BlockType);
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType); case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);

View File

@ -85,7 +85,7 @@ int cBlockPistonHandler::FirstPassthroughBlock(int a_PistonX, int a_PistonY, int
NIBBLETYPE currMeta; NIBBLETYPE currMeta;
AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1); AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1);
a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta); a_World->GetBlockTypeMeta(a_PistonX, a_PistonY, a_PistonZ, currBlock, currMeta);
if (CanBreakPush(currBlock)) if (cBlockInfo::IsPistonBreakable(currBlock))
{ {
// This block breaks when pushed, extend up to here // This block breaks when pushed, extend up to here
return ret; return ret;

View File

@ -104,6 +104,7 @@ private:
case E_BLOCK_ENCHANTMENT_TABLE: case E_BLOCK_ENCHANTMENT_TABLE:
case E_BLOCK_END_PORTAL: case E_BLOCK_END_PORTAL:
case E_BLOCK_END_PORTAL_FRAME: case E_BLOCK_END_PORTAL_FRAME:
// Notice the lack of an E_BLOCK_ENDER_CHEST here; its because ender chests can totally be pushed/pulled in MCS :)
case E_BLOCK_FURNACE: case E_BLOCK_FURNACE:
case E_BLOCK_LIT_FURNACE: case E_BLOCK_LIT_FURNACE:
case E_BLOCK_HOPPER: case E_BLOCK_HOPPER:
@ -113,6 +114,7 @@ private:
case E_BLOCK_NOTE_BLOCK: case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_OBSIDIAN: case E_BLOCK_OBSIDIAN:
case E_BLOCK_PISTON_EXTENSION: case E_BLOCK_PISTON_EXTENSION:
case E_BLOCK_TRAPPED_CHEST:
{ {
return false; return false;
} }
@ -126,24 +128,10 @@ private:
return true; return true;
} }
/// Returns true if the specified block can be pushed by a piston and broken / replaced
static inline bool CanBreakPush(BLOCKTYPE a_BlockType) { return cBlockInfo::IsPistonBreakable(a_BlockType); }
/// Returns true if the specified block can be pulled by a sticky piston /// Returns true if the specified block can be pulled by a sticky piston
static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{ {
switch (a_BlockType) if (cBlockInfo::IsPistonBreakable(a_BlockType))
{
case E_BLOCK_LAVA:
case E_BLOCK_STATIONARY_LAVA:
case E_BLOCK_STATIONARY_WATER:
case E_BLOCK_WATER:
{
return false;
}
}
if (CanBreakPush(a_BlockType))
{ {
return false; // CanBreakPush returns true, but we need false to prevent pulling return false; // CanBreakPush returns true, but we need false to prevent pulling
} }

View File

@ -1301,6 +1301,7 @@ void cChunk::CreateBlockEntities(void)
switch (BlockType) switch (BlockType)
{ {
case E_BLOCK_BEACON: case E_BLOCK_BEACON:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER: case E_BLOCK_DISPENSER:
@ -1431,6 +1432,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_BEACON: case E_BLOCK_BEACON:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_CHEST: case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK: case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER: case E_BLOCK_DISPENSER:
@ -2150,7 +2152,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
{ {
continue; continue;
} }
if ((*itr)->GetBlockType() != E_BLOCK_CHEST) if (((*itr)->GetBlockType() != E_BLOCK_CHEST) && ((*itr)->GetBlockType() != E_BLOCK_TRAPPED_CHEST)) // Trapped chests use normal chests' handlers
{ {
// There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out // There is a block entity here, but of different type. No other block entity can be here, so we can safely bail out
return false; return false;
@ -2530,8 +2532,8 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
{ {
int BlockX = m_PosX * cChunkDef::Width + a_RelX; int BlockX = m_PosX * cChunkDef::Width + a_RelX;
int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ; int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
int BlockY, ChunkX, ChunkZ; int ChunkX, ChunkZ;
AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ); BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ); return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
} }

View File

@ -847,7 +847,22 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M
void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ) void cChunkMap::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ)
{
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
if ((Chunk == NULL) || !Chunk->IsValid())
{
return;
}
Chunk->SetIsRedstoneDirty(true);
}
void cChunkMap::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty)
{ {
cCSLock Lock(m_CSLayers); cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
@ -856,6 +871,10 @@ void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ)
return; return;
} }
Chunk->MarkDirty(); Chunk->MarkDirty();
if (a_MarkRedstoneDirty)
{
Chunk->SetIsRedstoneDirty(true);
}
} }

View File

@ -106,7 +106,8 @@ public:
/** Wakes up the simulators for the specified area of blocks */ /** Wakes up the simulators for the specified area of blocks */
void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ); void WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_MinBlockY, int a_MaxBlockY, int a_MinBlockZ, int a_MaxBlockZ);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); void MarkRedstoneDirty (int a_ChunkX, int a_ChunkZ);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty = false);
void MarkChunkSaving (int a_ChunkX, int a_ChunkZ); void MarkChunkSaving (int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);

View File

@ -11,7 +11,7 @@
class cExpOrb : class cExpOrb :
public cEntity public cEntity
{ {
typedef cExpOrb super; typedef cEntity super;
public: public:
// tolua_end // tolua_end

View File

@ -200,8 +200,8 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
int BlockX = m_CenterX + ((a_X - (m_Width / 2)) * PixelWidth); int BlockX = m_CenterX + ((a_X - (m_Width / 2)) * PixelWidth);
int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth); int BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth);
int ChunkX, ChunkY, ChunkZ; int ChunkX, ChunkZ;
m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ); cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
int RelX = BlockX - (ChunkX * cChunkDef::Width); int RelX = BlockX - (ChunkX * cChunkDef::Width);
int RelZ = BlockZ - (ChunkZ * cChunkDef::Width); int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);

View File

@ -262,7 +262,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
AString HexDump; AString HexDump;
if (Response.compare(0, prefix.size(), prefix)) if (Response.compare(0, prefix.size(), prefix))
{ {
LOGINFO("User \"%s\" failed to auth, bad http status line received", a_UserName.c_str()); 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()); LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false; return false;
} }
@ -271,7 +271,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
size_t idxHeadersEnd = Response.find("\r\n\r\n"); size_t idxHeadersEnd = Response.find("\r\n\r\n");
if (idxHeadersEnd == AString::npos) if (idxHeadersEnd == AString::npos)
{ {
LOGINFO("User \"%s\" failed to authenticate, bad http response header received", a_UserName.c_str()); 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()); LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
return false; return false;
} }

View File

@ -5,6 +5,7 @@
#include "BoundingBox.h" #include "BoundingBox.h"
#include "../BlockEntities/DropSpenserEntity.h" #include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/NoteEntity.h" #include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h" #include "../BlockEntities/CommandBlockEntity.h"
#include "../Entities/TNTEntity.h" #include "../Entities/TNTEntity.h"
#include "../Entities/Pickup.h" #include "../Entities/Pickup.h"
@ -15,8 +16,6 @@
#include "../Blocks/BlockPiston.h" #include "../Blocks/BlockPiston.h"
#include "../Blocks/BlockTripwireHook.h" #include "../Blocks/BlockTripwireHook.h"
#define WAKE_SIMULATOR_IF_DIRTY(a_Chunk, a_BlockX, a_BlockY, a_BlockZ) if (a_Chunk->IsRedstoneDirty()) WakeUp(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
@ -63,14 +62,16 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
int RelZ = 0; int RelZ = 0;
BLOCKTYPE Block; BLOCKTYPE Block;
NIBBLETYPE Meta; NIBBLETYPE Meta;
cChunk * OtherChunk = a_Chunk;
if (a_OtherChunk != NULL) if (a_OtherChunk != NULL)
{ {
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width; RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width; RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta); a_OtherChunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
OtherChunk = a_OtherChunk;
// If a_OtherChunk is passed (not NULL), it is the chunk that had a block change, and a_Chunk will be the neighbouring chunk of that block
// Because said neighbouring chunk does not know of this change but still needs to update its redstone, we set it to dirty
a_Chunk->SetIsRedstoneDirty(true);
} }
else else
{ {
@ -95,8 +96,6 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{ {
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); 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);
itr = PoweredBlocks->erase(itr); itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
else if ( else if (
@ -105,34 +104,13 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) || ((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
(((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) ||
(((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0)) ||
((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0)) ((Block == E_BLOCK_TRIPWIRE_HOOK) && ((Meta & 0x08) == 0))
) )
{ {
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); 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);
itr = PoweredBlocks->erase(itr); itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
{
if (!m_World.IsChunkLighted(OtherChunk->GetPosX(), OtherChunk->GetPosZ()))
{
m_World.QueueLightChunk(OtherChunk->GetPosX(), OtherChunk->GetPosZ());
}
else
{
if (OtherChunk->GetTimeAlteredLight(OtherChunk->GetSkyLight(RelX, a_BlockY + 1, RelZ)) <= 7)
{
itr = PoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue;
}
}
}
++itr; ++itr;
} }
@ -146,23 +124,17 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{ {
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr); itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
else if ( else if (
// Things that can send power through a block but which depends on meta // Things that can send power through a block but which depends on meta
((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) || ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) || ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) || (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
(((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0)) ||
(((Block == E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE) || (Block == E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE)) && (Meta == 0))
) )
{ {
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr); itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
} }
@ -172,8 +144,6 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
{ {
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z); LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
itr = LinkedPoweredBlocks->erase(itr); itr = LinkedPoweredBlocks->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
OtherChunk->SetIsRedstoneDirty(true);
continue; continue;
} }
} }
@ -320,6 +290,7 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_FENCE_GATE: HandleFenceGate(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_TNT: HandleTNT(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break; case E_BLOCK_TRAPDOOR: HandleTrapdoor(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_TRAPPED_CHEST: HandleTrappedChest(dataitr->x, dataitr->y, dataitr->z); break;
case E_BLOCK_ACTIVATOR_RAIL: case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_DETECTOR_RAIL: case E_BLOCK_DETECTOR_RAIL:
@ -382,18 +353,13 @@ void cIncrementalRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int
void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) void cIncrementalRedstoneSimulator::WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk)
{ {
if ( if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
((a_BlockX % cChunkDef::Width) <= 1) ||
((a_BlockX % cChunkDef::Width) >= 14) ||
((a_BlockZ % cChunkDef::Width) <= 1) ||
((a_BlockZ % cChunkDef::Width) >= 14)
) // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks
{ {
// On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk) // On a chunk boundary, alert all four sides (i.e. at least one neighbouring chunk)
AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk); AddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk);
// Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position // Pass the original coordinates, because when adding things to our simulator lists, we get the chunk that they are in, and therefore any updates need to preseve their position
// RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordiantes are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries // RedstoneAddBlock to pass both the neighbouring chunk and the chunk which the coordinates are in and +- 2 in GetNeighbour() to accomodate for LinkedPowered blocks being 2 away from chunk boundaries
RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk); RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX - 2, a_BlockZ), a_Chunk);
RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk); RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX + 2, a_BlockZ), a_Chunk);
RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk); RedstoneAddBlock(a_BlockX, a_BlockY, a_BlockZ, a_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ - 2), a_Chunk);
@ -448,7 +414,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last) if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
{ {
if ( if (
((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc. IsMechanism(Type) && // Is it a mechanism? Not block/other torch etc.
(!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on (!Vector3i(a_RelBlockX + gCrossCoords[i].x, a_RelBlockY + gCrossCoords[i].y, a_RelBlockZ + gCrossCoords[i].z).Equals(Vector3i(X, Y, Z))) // CAN'T power block is that it is on
) )
{ {
@ -468,7 +434,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
{ {
BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ); BLOCKTYPE Type = m_Chunk->GetBlock(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ);
if ((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) // Still can't make a normal block powered though! if (IsMechanism(Type)) // Still can't make a normal block powered though!
{ {
SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ); SetBlockPowered(a_RelBlockX, a_RelBlockY - 1, a_RelBlockZ, a_RelBlockX, a_RelBlockY, a_RelBlockZ);
} }
@ -780,17 +746,20 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
{ {
for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();) for (RepeatersDelayList::iterator itr = m_RepeatersDelayList->begin(); itr != m_RepeatersDelayList->end();)
{ {
if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks? if (itr->a_ElapsedTicks >= itr->a_DelayTicks) // Has the elapsed ticks reached the target ticks?
{ {
int RelBlockX = itr->a_RelBlockPos.x; int RelBlockX = itr->a_RelBlockPos.x;
int RelBlockY = itr->a_RelBlockPos.y; int RelBlockY = itr->a_RelBlockPos.y;
int RelBlockZ = itr->a_RelBlockPos.z; int RelBlockZ = itr->a_RelBlockPos.z;
NIBBLETYPE Meta = m_Chunk->GetMeta(RelBlockX, RelBlockY, RelBlockZ); BLOCKTYPE Block;
NIBBLETYPE Meta;
m_Chunk->GetBlockTypeMeta(RelBlockX, RelBlockY, RelBlockZ, Block, Meta);
if (itr->ShouldPowerOn) if (itr->ShouldPowerOn)
{ {
if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); // For performance {
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta);
}
switch (Meta & 0x3) // We only want the direction (bottom) bits switch (Meta & 0x3) // We only want the direction (bottom) bits
{ {
@ -820,17 +789,14 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
} }
} }
} }
else else if (Block != E_BLOCK_REDSTONE_REPEATER_OFF)
{ {
m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta); m_Chunk->SetBlock(RelBlockX, RelBlockY, RelBlockZ, E_BLOCK_REDSTONE_REPEATER_OFF, Meta);
} }
itr = m_RepeatersDelayList->erase(itr); itr = m_RepeatersDelayList->erase(itr);
} }
else else
{ {
// Apparently, incrementing ticks only works reliably here, and not in SimChunk;
// With a world with lots of redstone, the repeaters simply do not delay
// I am confounded to say why. Perhaps optimisation failure.
LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks); LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_RelBlockPos.x, itr->a_RelBlockPos.y, itr->a_RelBlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
itr->a_ElapsedTicks++; itr->a_ElapsedTicks++;
itr++; itr++;
@ -1139,7 +1105,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
else else
{ {
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, 0x0);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
} }
break; break;
} }
@ -1206,7 +1172,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
} }
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
} }
break; break;
@ -1274,7 +1240,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
} }
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
} }
break; break;
@ -1341,7 +1307,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F); m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
} }
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_RAISED);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
} }
break; break;
} }
@ -1384,14 +1350,14 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{ {
if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards) if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards)
{ {
// Other hook not facing in opposite direction // Other hook facing in opposite direction - circuit completed!
break; break;
} }
else else
{ {
// Tripwire hook not connected at all, AND away all the power state bits // Tripwire hook not connected at all, AND away all the power state bits
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
return; return;
} }
} }
@ -1399,7 +1365,7 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{ {
// Tripwire hook not connected at all, AND away all the power state bits // Tripwire hook not connected at all, AND away all the power state bits
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x3);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
return; return;
} }
} }
@ -1414,7 +1380,51 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
{ {
// Connected but not activated, AND away the highest bit // Connected but not activated, AND away the highest bit
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4); m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, (m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x7) | 0x4);
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ); SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
}
}
void cIncrementalRedstoneSimulator::HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{
class cGetTrappedChestPlayers :
public cChestCallback
{
public:
cGetTrappedChestPlayers(void) :
m_NumberOfPlayers(0)
{
}
virtual bool Item(cChestEntity * a_Chest) override
{
ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST);
m_NumberOfPlayers = a_Chest->GetNumberOfPlayers();
return (m_NumberOfPlayers <= 0);
}
unsigned char GetPowerLevel(void) const
{
return std::min(m_NumberOfPlayers, MAX_POWER_LEVEL);
}
private:
int m_NumberOfPlayers;
} GTCP;
int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ;
if (m_Chunk->DoWithChestAt(BlockX, a_RelBlockY, BlockZ, GTCP))
{
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, GTCP.GetPowerLevel());
}
else
{
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
} }
} }
@ -1691,8 +1701,8 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_RelBlockX, int a_RelBl
bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel) bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel)
{ {
a_PowerLevel = 0; a_PowerLevel = 0;
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX; int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ; int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ;
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list
{ {
@ -1709,6 +1719,14 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBloc
{ {
continue; continue;
} }
BLOCKTYPE Type = E_BLOCK_AIR;
int RelSourceX = itr->a_SourcePos.x - m_Chunk->GetPosX() * cChunkDef::Width;
int RelSourceZ = itr->a_SourcePos.z - m_Chunk->GetPosZ() * cChunkDef::Width;
if (!m_Chunk->UnboundedRelGetBlockType(RelSourceX, itr->a_SourcePos.y, RelSourceZ, Type) || (Type == E_BLOCK_REDSTONE_WIRE))
{
continue;
}
a_PowerLevel = std::max(itr->a_PowerLevel, a_PowerLevel); a_PowerLevel = std::max(itr->a_PowerLevel, a_PowerLevel);
} }
@ -1881,20 +1899,9 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl
int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
BLOCKTYPE Block = 0; cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block)) PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList(); // We need to insert the value into the chunk who owns the block position
{ for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr)
return;
}
if (Block == E_BLOCK_AIR)
{
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ);
PoweredBlocksList * Powered = Neighbour->GetRedstoneSimulatorPoweredBlocksList();
for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
{ {
if ( if (
itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) && itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
@ -1907,16 +1914,33 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl
} }
} }
PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList(); // No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk
for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list // TODO: on C++11 support, change this to a llama function pased to a std::remove_if
for (PoweredBlocksList::iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
{ {
if ( if (
itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) && itr->a_BlockPos.Equals(Vector3i(SourceX, a_RelSourceY, SourceZ)) &&
itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) itr->a_SourcePos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
(m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE)
) )
{ {
// Powered wires try to power their source - don't let them! BLOCKTYPE Block;
return; NIBBLETYPE Meta;
Neighbour->GetBlockTypeMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block, Meta);
if (Block == E_BLOCK_REDSTONE_WIRE)
{
if (Meta < a_PowerLevel)
{
m_PoweredBlocks->erase(itr); // Powering source with higher power level, allow it
break;
}
else
{
// Powered wires try to power their source - don't let them!
return;
}
}
} }
} }
@ -1947,20 +1971,6 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX; int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ; int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
BLOCKTYPE DestBlock = 0;
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock))
{
return;
}
if (DestBlock == E_BLOCK_AIR)
{
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE))
{
return;
}
if (!IsViableMiddleBlock(a_MiddleBlock)) if (!IsViableMiddleBlock(a_MiddleBlock))
{ {
return; return;
@ -2066,6 +2076,45 @@ bool cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_RelBlockX, in
void cIncrementalRedstoneSimulator::SetSourceUnpowered(int a_SourceX, int a_SourceY, int a_SourceZ, cChunk * a_Chunk, bool a_IsFirstCall)
{
// TODO: on C++11 support, change both of these to llama functions pased to a std::remove_if
for (PoweredBlocksList::iterator itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end();)
{
if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)))
{
itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
continue;
}
++itr;
}
for (LinkedBlocksList::iterator itr = a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->end();)
{
if (itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)))
{
itr = a_Chunk->GetRedstoneSimulatorLinkedBlocksList()->erase(itr);
a_Chunk->SetIsRedstoneDirty(true);
continue;
}
++itr;
}
if (a_IsFirstCall && AreCoordsOnChunkBoundary(a_SourceX, a_SourceY, a_SourceZ))
{
// +- 2 to accomodate linked powered blocks
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX - 2, a_SourceZ), false);
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX + 2, a_SourceZ), false);
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ - 2), false);
SetSourceUnpowered(a_SourceX, a_SourceY, a_SourceZ, a_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ + 2), false);
}
}
cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) cIncrementalRedstoneSimulator::eRedstoneDirection cIncrementalRedstoneSimulator::GetWireDirection(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
{ {
int Dir = REDSTONE_NONE; int Dir = REDSTONE_NONE;

View File

@ -107,6 +107,8 @@ private:
If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task If this line is complete, it verifies that at least on wire reports an entity is on top (via its meta), and performs its task
*/ */
void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); void HandleTripwireHook(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles trapped chests */
void HandleTrappedChest(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/* ==================== */ /* ==================== */
/* ====== CARRIERS ====== */ /* ====== CARRIERS ====== */
@ -114,8 +116,6 @@ private:
void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ); void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles repeaters */ /** Handles repeaters */
void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState); void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles delayed updates to Repeaters **/
void HandleRedstoneRepeaterDelays();
/* ====================== */ /* ====================== */
/* ====== DEVICES ====== */ /* ====== DEVICES ====== */
@ -156,6 +156,10 @@ private:
void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL); void SetAllDirsAsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Queues a repeater to be powered or unpowered and returns if the m_RepeatersDelayList iterators were invalidated */ /** Queues a repeater to be powered or unpowered and returns if the m_RepeatersDelayList iterators were invalidated */
bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); bool QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
/** Removes a block from the Powered and LinkedPowered lists
Used for variable sources such as tripwire hooks, daylight sensors, and trapped chests
*/
void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk, bool a_IsFirstCall = true);
/** Returns if a coordinate is powered or linked powered */ /** Returns if a coordinate is powered or linked powered */
bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); } bool AreCoordsPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ) { return AreCoordsDirectlyPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }
@ -174,7 +178,8 @@ private:
/** Returns if a wire is powered /** 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 */ The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */
bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel); bool IsWirePowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, unsigned char & a_PowerLevel);
/** Handles delayed updates to repeaters **/
void HandleRedstoneRepeaterDelays(void);
/** Returns if lever metadata marks it as emitting power */ /** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta); bool IsLeverOn(NIBBLETYPE a_BlockMeta);
@ -186,7 +191,9 @@ private:
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */ /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); } inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return cBlockInfo::FullyOccupiesVoxel(Block); }
/** Returns if a block is a mechanism (something that accepts power and does something) */ /** Returns if a block is a mechanism (something that accepts power and does something)
Used by torches to determine if they power a block whilst not standing on the ground
*/
inline static bool IsMechanism(BLOCKTYPE Block) inline static bool IsMechanism(BLOCKTYPE Block)
{ {
switch (Block) switch (Block)
@ -209,6 +216,7 @@ private:
case E_BLOCK_REDSTONE_REPEATER_OFF: case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON: case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_POWERED_RAIL: case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_WIRE:
{ {
return true; return true;
} }
@ -235,6 +243,7 @@ private:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_TRAPPED_CHEST:
{ {
return true; return true;
} }
@ -277,6 +286,7 @@ private:
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_TNT: case E_BLOCK_TNT:
case E_BLOCK_TRAPDOOR: case E_BLOCK_TRAPDOOR:
case E_BLOCK_TRAPPED_CHEST:
case E_BLOCK_TRIPWIRE_HOOK: case E_BLOCK_TRIPWIRE_HOOK:
case E_BLOCK_TRIPWIRE: case E_BLOCK_TRIPWIRE:
case E_BLOCK_WOODEN_BUTTON: case E_BLOCK_WOODEN_BUTTON:
@ -289,6 +299,16 @@ private:
default: return false; default: return false;
} }
} }
inline static bool AreCoordsOnChunkBoundary(int a_BlockX, int a_BlockY, int a_BlockZ)
{
return ( // Are we on a chunk boundary? +- 2 because of LinkedPowered blocks
((a_BlockX % cChunkDef::Width) <= 1) ||
((a_BlockX % cChunkDef::Width) >= 14) ||
((a_BlockZ % cChunkDef::Width) <= 1) ||
((a_BlockZ % cChunkDef::Width) >= 14)
);
}
}; };

View File

@ -905,11 +905,13 @@ void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
// cChestWindow: // cChestWindow:
cChestWindow::cChestWindow(cChestEntity * a_Chest) : cChestWindow::cChestWindow(cChestEntity * a_Chest) :
cWindow(wtChest, "Chest"), cWindow(wtChest, (a_Chest->GetBlockType() == E_BLOCK_CHEST) ? "Chest" : "Trapped Chest"),
m_World(a_Chest->GetWorld()), m_World(a_Chest->GetWorld()),
m_BlockX(a_Chest->GetPosX()), m_BlockX(a_Chest->GetPosX()),
m_BlockY(a_Chest->GetPosY()), m_BlockY(a_Chest->GetPosY()),
m_BlockZ(a_Chest->GetPosZ()) m_BlockZ(a_Chest->GetPosZ()),
m_PrimaryChest(a_Chest),
m_SecondaryChest(NULL)
{ {
m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this)); m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this));
@ -919,7 +921,7 @@ cChestWindow::cChestWindow(cChestEntity * a_Chest) :
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1); m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
// Send out the chest-open packet: // Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST); m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_Chest->GetBlockType());
} }
@ -927,11 +929,13 @@ cChestWindow::cChestWindow(cChestEntity * a_Chest) :
cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) : cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) :
cWindow(wtChest, "Double Chest"), cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
m_World(a_PrimaryChest->GetWorld()), m_World(a_PrimaryChest->GetWorld()),
m_BlockX(a_PrimaryChest->GetPosX()), m_BlockX(a_PrimaryChest->GetPosX()),
m_BlockY(a_PrimaryChest->GetPosY()), m_BlockY(a_PrimaryChest->GetPosY()),
m_BlockZ(a_PrimaryChest->GetPosZ()) m_BlockZ(a_PrimaryChest->GetPosZ()),
m_PrimaryChest(a_PrimaryChest),
m_SecondaryChest(a_SecondaryChest)
{ {
m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this)); m_SlotAreas.push_back(new cSlotAreaDoubleChest(a_PrimaryChest, a_SecondaryChest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this));
@ -943,7 +947,52 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1); m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
// Send out the chest-open packet: // Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST); m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, a_PrimaryChest->GetBlockType());
}
void cChestWindow::OpenedByPlayer(cPlayer & a_Player)
{
int ChunkX, ChunkZ;
m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() + 1);
cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
if (m_SecondaryChest != NULL)
{
m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
}
cWindow::OpenedByPlayer(a_Player);
}
bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
{
int ChunkX, ChunkZ;
m_PrimaryChest->SetNumberOfPlayers(m_PrimaryChest->GetNumberOfPlayers() - 1);
cChunkDef::BlockToChunk(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosZ(), ChunkX, ChunkZ);
m_PrimaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
if (m_SecondaryChest != NULL)
{
m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
}
cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
return true;
} }
@ -953,7 +1002,7 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
cChestWindow::~cChestWindow() cChestWindow::~cChestWindow()
{ {
// Send out the chest-close packet: // Send out the chest-close packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_CHEST); m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, m_PrimaryChest->GetBlockType());
m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1); m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
} }
@ -966,7 +1015,7 @@ cChestWindow::~cChestWindow()
// cDropSpenserWindow: // cDropSpenserWindow:
cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) :
cWindow(wtDropSpenser, "Dropspenser") cWindow(wtDropSpenser, (a_DropSpenser->GetBlockType() == E_BLOCK_DISPENSER) ? "Dispenser" : "Dropper")
{ {
m_ShouldDistributeToHotbarFirst = false; m_ShouldDistributeToHotbarFirst = false;
m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this)); m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this));

View File

@ -114,7 +114,7 @@ public:
const cItem & a_ClickedItem const cItem & a_ClickedItem
); );
void OpenedByPlayer(cPlayer & a_Player); virtual void OpenedByPlayer(cPlayer & a_Player);
/// Called when a player closes this window; notifies all slot areas. Returns true if close accepted /// Called when a player closes this window; notifies all slot areas. Returns true if close accepted
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse); virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse);
@ -327,10 +327,15 @@ public:
cChestWindow(cChestEntity * a_Chest); cChestWindow(cChestEntity * a_Chest);
cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest); cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
~cChestWindow(); ~cChestWindow();
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
virtual void OpenedByPlayer(cPlayer & a_Player) override;
protected: protected:
cWorld * m_World; cWorld * m_World;
int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
cChestEntity * m_PrimaryChest;
cChestEntity * m_SecondaryChest;
} ; } ;

View File

@ -389,8 +389,8 @@ void cWorld::InitializeSpawn(void)
IniFile.WriteFile(m_IniFileName); IniFile.WriteFile(m_IniFileName);
} }
int ChunkX = 0, ChunkY = 0, ChunkZ = 0; int ChunkX = 0, ChunkZ = 0;
BlockToChunk((int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ); cChunkDef::BlockToChunk((int)m_SpawnX, (int)m_SpawnZ, ChunkX, ChunkZ);
// For the debugging builds, don't make the server build too much world upon start: // For the debugging builds, don't make the server build too much world upon start:
#if defined(_DEBUG) || defined(ANDROID_NDK) #if defined(_DEBUG) || defined(ANDROID_NDK)
@ -2182,9 +2182,18 @@ void cWorld::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHa
void cWorld::MarkChunkDirty (int a_ChunkX, int a_ChunkZ) void cWorld::MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ)
{ {
m_ChunkMap->MarkChunkDirty (a_ChunkX, a_ChunkZ); m_ChunkMap->MarkRedstoneDirty(a_ChunkX, a_ChunkZ);
}
void cWorld::MarkChunkDirty(int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty)
{
m_ChunkMap->MarkChunkDirty(a_ChunkX, a_ChunkZ, a_MarkRedstoneDirty);
} }

View File

@ -241,7 +241,8 @@ public:
/** If there is a block entity at the specified coords, sends it to the client specified */ /** If there is a block entity at the specified coords, sends it to the client specified */
void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client); void SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClientHandle & a_Client);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ); void MarkRedstoneDirty(int a_ChunkX, int a_ChunkZ);
void MarkChunkDirty (int a_ChunkX, int a_ChunkZ, bool a_MarkRedstoneDirty = false);
void MarkChunkSaving(int a_ChunkX, int a_ChunkZ); void MarkChunkSaving(int a_ChunkX, int a_ChunkZ);
void MarkChunkSaved (int a_ChunkX, int a_ChunkZ); void MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
@ -634,18 +635,6 @@ public:
// tolua_end // tolua_end
inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
{
// TODO: Use floor() instead of weird if statements
// Also fix Y
(void)a_Y; // not unused anymore
a_ChunkX = a_X/cChunkDef::Width;
if(a_X < 0 && a_X % cChunkDef::Width != 0) a_ChunkX--;
a_ChunkY = 0;
a_ChunkZ = a_Z/cChunkDef::Width;
if(a_Z < 0 && a_Z % cChunkDef::Width != 0) a_ChunkZ--;
}
/** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */ /** Saves all chunks immediately. Dangerous interface, may deadlock, use QueueSaveAllChunks() instead */
void SaveAllChunks(void); void SaveAllChunks(void);

View File

@ -175,10 +175,10 @@ void cNBTChunkSerializer::AddBasicTileEntity(cBlockEntity * a_Entity, const char
void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity) void cNBTChunkSerializer::AddChestEntity(cChestEntity * a_Entity, BLOCKTYPE a_ChestType)
{ {
m_Writer.BeginCompound(""); m_Writer.BeginCompound("");
AddBasicTileEntity(a_Entity, "Chest"); AddBasicTileEntity(a_Entity, (a_ChestType == E_BLOCK_CHEST) ? "Chest" : "TrappedChest");
m_Writer.BeginList("Items", TAG_Compound); m_Writer.BeginList("Items", TAG_Compound);
AddItemGrid(a_Entity->GetContents()); AddItemGrid(a_Entity->GetContents());
m_Writer.EndList(); m_Writer.EndList();
@ -813,19 +813,21 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
// Add tile-entity into NBT: // Add tile-entity into NBT:
switch (a_Entity->GetBlockType()) switch (a_Entity->GetBlockType())
{ {
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break; case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break; case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *)a_Entity); break;
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break; case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
case E_BLOCK_ENDER_CHEST: /* No need to be saved */ break; case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break; case E_BLOCK_ENDER_CHEST: /* No data to be saved */ break;
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break; case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break; case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_SIGN_POST: case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break;
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break; case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break; case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break; case E_BLOCK_LIT_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break; case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break; case E_BLOCK_SIGN_POST: AddSignEntity ((cSignEntity *) a_Entity); break;
case E_BLOCK_TRAPPED_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
default: default:
{ {

View File

@ -92,7 +92,7 @@ protected:
// Block entities: // Block entities:
void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID); void AddBasicTileEntity(cBlockEntity * a_Entity, const char * a_EntityTypeID);
void AddChestEntity (cChestEntity * a_Entity); void AddChestEntity (cChestEntity * a_Entity, BLOCKTYPE a_ChestType);
void AddDispenserEntity(cDispenserEntity * a_Entity); void AddDispenserEntity(cDispenserEntity * a_Entity);
void AddDropperEntity (cDropperEntity * a_Entity); void AddDropperEntity (cDropperEntity * a_Entity);
void AddFurnaceEntity (cFurnaceEntity * a_Furnace); void AddFurnaceEntity (cFurnaceEntity * a_Furnace);

View File

@ -582,7 +582,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
} }
if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0) if (strncmp(a_NBT.GetData(sID), "Chest", a_NBT.GetDataLength(sID)) == 0)
{ {
LoadChestFromNBT(a_BlockEntities, a_NBT, Child); LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_CHEST);
} }
else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0) else if (strncmp(a_NBT.GetData(sID), "Control", a_NBT.GetDataLength(sID)) == 0)
{ {
@ -624,6 +624,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
{ {
LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child); LoadDispenserFromNBT(a_BlockEntities, a_NBT, Child);
} }
else if (strncmp(a_NBT.GetData(sID), "TrappedChest", a_NBT.GetDataLength(sID)) == 0)
{
LoadChestFromNBT(a_BlockEntities, a_NBT, Child, E_BLOCK_TRAPPED_CHEST);
}
// TODO: Other block entities // TODO: Other block entities
} // for Child - tag children } // for Child - tag children
} }
@ -740,7 +744,7 @@ void cWSSAnvil::LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a
void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx) void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType)
{ {
ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound); ASSERT(a_NBT.GetType(a_TagIdx) == TAG_Compound);
int x, y, z; int x, y, z;
@ -753,7 +757,7 @@ void cWSSAnvil::LoadChestFromNBT(cBlockEntityList & a_BlockEntities, const cPars
{ {
return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this return; // Make it an empty chest - the chunk loader will provide an empty cChestEntity for this
} }
std::auto_ptr<cChestEntity> Chest(new cChestEntity(x, y, z, m_World)); std::auto_ptr<cChestEntity> Chest(new cChestEntity(x, y, z, m_World, a_ChestType));
LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items); LoadItemGridFromNBT(Chest->GetContents(), a_NBT, Items);
a_BlockEntities.push_back(Chest.release()); a_BlockEntities.push_back(Chest.release());
} }

View File

@ -133,7 +133,7 @@ protected:
*/ */
void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0); void LoadItemGridFromNBT(cItemGrid & a_ItemGrid, const cParsedNBT & a_NBT, int a_ItemsTagIdx, int s_SlotOffset = 0);
void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadChestFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx, BLOCKTYPE a_ChestType);
void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadDispenserFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx); void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);

View File

@ -273,7 +273,7 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
{ {
for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr ) for (Json::Value::iterator itr = AllChests.begin(); itr != AllChests.end(); ++itr )
{ {
std::auto_ptr<cChestEntity> ChestEntity(new cChestEntity(0, 0, 0, a_World)); std::auto_ptr<cChestEntity> ChestEntity(new cChestEntity(0, 0, 0, a_World, E_BLOCK_CHEST));
if (!ChestEntity->LoadFromJson(*itr)) if (!ChestEntity->LoadFromJson(*itr))
{ {
LOGWARNING("ERROR READING CHEST FROM JSON!" ); LOGWARNING("ERROR READING CHEST FROM JSON!" );