Merge branch 'master' into potions
commit
8e946da8ac
|
@ -22,6 +22,8 @@ function Initialize(Plugin)
|
|||
Plugin:SetVersion(1);
|
||||
|
||||
cPluginManager.AddHook(cPluginManager.HOOK_PLAYER_USED_ITEM, OnPlayerUsedItem);
|
||||
|
||||
LOG("Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion());
|
||||
return true;
|
||||
end
|
||||
|
||||
|
@ -36,8 +38,8 @@ function OnPlayerUsedItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cu
|
|||
return false;
|
||||
end;
|
||||
|
||||
if (Player:HasPermission("diamondmover.move") == false) then
|
||||
return true;
|
||||
if (not Player:HasPermission("diamondmover.move")) then
|
||||
return false;
|
||||
end;
|
||||
|
||||
-- Rclk with a diamond to push in the direction the player is facing
|
||||
|
@ -56,7 +58,7 @@ function OnPlayerUsedItem(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, Cu
|
|||
if (PlayerPitch > 70) then -- looking down
|
||||
BlockY = BlockY - 1;
|
||||
else
|
||||
local PlayerRot = Player:GetRotation() + 180; -- Convert [-180, 180] into [0, 360] for simpler conditions
|
||||
local PlayerRot = Player:GetYaw() + 180; -- Convert [-180, 180] into [0, 360] for simpler conditions
|
||||
if ((PlayerRot < 45) or (PlayerRot > 315)) then
|
||||
BlockZ = BlockZ - 1;
|
||||
else
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 1ed82759c68f92c4acc7e3f33b850cf9f01c8aba
|
||||
Subproject commit 784b04ff9afd5faeaeb15c3fa159ff98adf55182
|
|
@ -6,21 +6,21 @@ if mobdebugfound then mobdebug.start() end
|
|||
-- The list of valid arguments that the ToLua scripts can process:
|
||||
local KnownArgs = {
|
||||
['v'] = true,
|
||||
['h'] = true,
|
||||
['p'] = true,
|
||||
['P'] = true,
|
||||
['o'] = true,
|
||||
['n'] = true,
|
||||
['H'] = true,
|
||||
['S'] = true,
|
||||
['1'] = true,
|
||||
['L'] = true,
|
||||
['D'] = true,
|
||||
['W'] = true,
|
||||
['C'] = true,
|
||||
['E'] = true,
|
||||
['t'] = true,
|
||||
['q'] = true,
|
||||
['h'] = true,
|
||||
['p'] = true,
|
||||
['P'] = true,
|
||||
['o'] = true,
|
||||
['n'] = true,
|
||||
['H'] = true,
|
||||
['S'] = true,
|
||||
['1'] = true,
|
||||
['L'] = true,
|
||||
['D'] = true,
|
||||
['W'] = true,
|
||||
['C'] = true,
|
||||
['E'] = true,
|
||||
['t'] = true,
|
||||
['q'] = true,
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ void InternalMergeBlocks(
|
|||
}
|
||||
else
|
||||
{
|
||||
BLOCKTYPE FakeDestMeta = 0;
|
||||
NIBBLETYPE FakeDestMeta = 0;
|
||||
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0);
|
||||
}
|
||||
++DstIdx;
|
||||
|
|
|
@ -28,24 +28,26 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
|
|||
switch (a_BlockType)
|
||||
{
|
||||
case E_BLOCK_BEACON: return new cBeaconEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
|
||||
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
|
||||
case E_BLOCK_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_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_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_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_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_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_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_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)",
|
||||
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()
|
||||
);
|
||||
ASSERT(!"Requesting creation of an unknown block entity");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,8 +11,9 @@
|
|||
|
||||
|
||||
|
||||
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
|
||||
super(E_BLOCK_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World)
|
||||
cChestEntity::cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type) :
|
||||
super(a_Type, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
|
||||
m_NumActivePlayers(0)
|
||||
{
|
||||
cBlockEntityWindowOwner::SetBlockEntity(this);
|
||||
}
|
||||
|
@ -113,7 +114,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player)
|
|||
// The few false positives aren't much to worry about
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
|
||||
m_World->MarkChunkDirty(ChunkX, ChunkZ);
|
||||
m_World->MarkChunkDirty(ChunkX, ChunkZ, true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ public:
|
|||
|
||||
// tolua_end
|
||||
|
||||
/// Constructor used for normal operation
|
||||
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
|
||||
/** Constructor used for normal operation */
|
||||
cChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World, BLOCKTYPE a_Type);
|
||||
|
||||
virtual ~cChestEntity();
|
||||
|
||||
|
@ -48,8 +48,20 @@ public:
|
|||
virtual void SendTo(cClientHandle & a_Client) 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);
|
||||
|
||||
/** 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
|
||||
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
cItem GetItem(void) const { return m_Item; }
|
||||
|
||||
/** Set the item in the flower pot */
|
||||
void SetItem(const cItem a_Item) { m_Item = a_Item; }
|
||||
void SetItem(const cItem & a_Item) { m_Item = a_Item; }
|
||||
|
||||
// tolua_end
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@ bool cHopperEntity::MoveItemsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
|
|||
bool res = false;
|
||||
switch (a_Chunk.GetBlock(m_RelX, m_PosY + 1, m_RelZ))
|
||||
{
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
case E_BLOCK_CHEST:
|
||||
{
|
||||
// Chests have special handling because of double-chests
|
||||
|
@ -322,6 +323,7 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
|
|||
bool res = false;
|
||||
switch (DestChunk->GetBlock(OutRelX, OutY, OutRelZ))
|
||||
{
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
case E_BLOCK_CHEST:
|
||||
{
|
||||
// Chests have special handling because of double-chests
|
||||
|
@ -366,19 +368,19 @@ bool cHopperEntity::MoveItemsOut(cChunk & a_Chunk, Int64 a_CurrentTick)
|
|||
/// Moves items from a chest (dblchest) above the hopper into this hopper. Returns true if contents have changed.
|
||||
bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
|
||||
{
|
||||
cChestEntity * Chest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
|
||||
if (Chest == NULL)
|
||||
cChestEntity * MainChest = (cChestEntity *)a_Chunk.GetBlockEntity(m_PosX, m_PosY + 1, m_PosZ);
|
||||
if (MainChest == NULL)
|
||||
{
|
||||
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX, m_PosY + 1, m_PosZ);
|
||||
return false;
|
||||
}
|
||||
if (MoveItemsFromGrid(*Chest))
|
||||
if (MoveItemsFromGrid(*MainChest))
|
||||
{
|
||||
// Moved the item from the chest directly above the hopper
|
||||
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
|
||||
{
|
||||
int x, z;
|
||||
|
@ -395,21 +397,26 @@ bool cHopperEntity::MoveItemsFromChest(cChunk & a_Chunk)
|
|||
int x = m_RelX + Coords[i].x;
|
||||
int z = m_RelZ + Coords[i].z;
|
||||
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
|
||||
if (
|
||||
(Neighbor == NULL) ||
|
||||
(Neighbor->GetBlock(x, m_PosY + 1, z) != E_BLOCK_CHEST)
|
||||
)
|
||||
if (Neighbor == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Chest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
|
||||
if (Chest == NULL)
|
||||
|
||||
BLOCKTYPE Block = Neighbor->GetBlock(x, m_PosY + 1, z);
|
||||
if (Block != MainChest->GetBlockType())
|
||||
{
|
||||
// Not the same kind of chest
|
||||
continue;
|
||||
}
|
||||
|
||||
cChestEntity * SideChest = (cChestEntity *)Neighbor->GetBlockEntity(m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
|
||||
if (SideChest == NULL)
|
||||
{
|
||||
LOGWARNING("%s: A chest entity was not found where expected, at {%d, %d, %d}", __FUNCTION__, m_PosX + Coords[i].x, m_PosY + 1, m_PosZ + Coords[i].z);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MoveItemsFromGrid(*Chest))
|
||||
if (MoveItemsFromGrid(*SideChest))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -550,10 +557,11 @@ bool cHopperEntity::MoveItemsToChest(cChunk & a_Chunk, int a_BlockX, int a_Block
|
|||
}
|
||||
if (MoveItemsToGrid(*Chest))
|
||||
{
|
||||
// Chest block directly connected was not full
|
||||
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
|
||||
{
|
||||
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 z = RelZ + Coords[i].z;
|
||||
cChunk * Neighbor = a_Chunk.GetRelNeighborChunkAdjustCoords(x, z);
|
||||
if (
|
||||
(Neighbor == NULL) ||
|
||||
(Neighbor->GetBlock(x, a_BlockY, z) != E_BLOCK_CHEST)
|
||||
)
|
||||
if (Neighbor == NULL)
|
||||
{
|
||||
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);
|
||||
if (Chest == NULL)
|
||||
{
|
||||
|
|
|
@ -91,7 +91,7 @@ void cNoteEntity::MakeSound(void)
|
|||
|
||||
// TODO: instead of calculating the power function over and over, make a precalculated table - there's only 24 pitches after all
|
||||
float calcPitch = pow(2.0f, ((float)m_Pitch - 12.0f) / 12.0f);
|
||||
m_World->BroadcastSoundEffect(sampleName, m_PosX * 8, m_PosY * 8, m_PosZ * 8, 3.0f, calcPitch);
|
||||
m_World->BroadcastSoundEffect(sampleName, (double)m_PosX, (double)m_PosY, (double)m_PosZ, 3.0f, calcPitch);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -101,6 +101,7 @@ void cBlockInfo::Initialize(cBlockInfoArray & a_Info)
|
|||
a_Info[E_BLOCK_NEW_LEAVES ].m_SpreadLightFalloff = 1;
|
||||
a_Info[E_BLOCK_SIGN_POST ].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_HOOK ].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_STONE_BUTTON ].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_HOOK ].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_TNT ].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_HOOK ].m_IsSnowable = false;
|
||||
a_Info[E_BLOCK_VINES ].m_IsSnowable = false;
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
||||
a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||
|
||||
// Queue a button reset (unpress)
|
||||
a_ChunkInterface.QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07), m_BlockType == E_BLOCK_STONE_BUTTON ? 20 : 30, m_BlockType, a_WorldInterface);
|
||||
|
|
|
@ -44,16 +44,16 @@ public:
|
|||
}
|
||||
double yaw = a_Player->GetYaw();
|
||||
if (
|
||||
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
|
||||
(Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(2, 0, 1) == m_BlockType)
|
||||
)
|
||||
{
|
||||
a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
|
||||
(Area.GetRelBlockType(0, 0, 1) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(2, 0, 1) == m_BlockType)
|
||||
)
|
||||
{
|
||||
// FIXME: This is unreachable, as the condition is the same as the above one
|
||||
|
@ -130,12 +130,12 @@ public:
|
|||
}
|
||||
|
||||
int NumChestNeighbors = 0;
|
||||
if (Area.GetRelBlockType(1, 0, 2) == E_BLOCK_CHEST)
|
||||
if (Area.GetRelBlockType(1, 0, 2) == m_BlockType)
|
||||
{
|
||||
if (
|
||||
(Area.GetRelBlockType(0, 0, 2) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST)
|
||||
(Area.GetRelBlockType(0, 0, 2) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(1, 0, 3) == m_BlockType)
|
||||
)
|
||||
{
|
||||
// Already a doublechest neighbor, disallow:
|
||||
|
@ -143,12 +143,12 @@ public:
|
|||
}
|
||||
NumChestNeighbors += 1;
|
||||
}
|
||||
if (Area.GetRelBlockType(3, 0, 2) == E_BLOCK_CHEST)
|
||||
if (Area.GetRelBlockType(3, 0, 2) == m_BlockType)
|
||||
{
|
||||
if (
|
||||
(Area.GetRelBlockType(4, 0, 2) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST)
|
||||
(Area.GetRelBlockType(4, 0, 2) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(3, 0, 1) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(3, 0, 3) == m_BlockType)
|
||||
)
|
||||
{
|
||||
// Already a doublechest neighbor, disallow:
|
||||
|
@ -156,12 +156,12 @@ public:
|
|||
}
|
||||
NumChestNeighbors += 1;
|
||||
}
|
||||
if (Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
|
||||
if (Area.GetRelBlockType(2, 0, 1) == m_BlockType)
|
||||
{
|
||||
if (
|
||||
(Area.GetRelBlockType(2, 0, 0) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(1, 0, 1) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(3, 0, 1) == E_BLOCK_CHEST)
|
||||
(Area.GetRelBlockType(2, 0, 0) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(1, 0, 1) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(3, 0, 1) == m_BlockType)
|
||||
)
|
||||
{
|
||||
// Already a doublechest neighbor, disallow:
|
||||
|
@ -169,12 +169,12 @@ public:
|
|||
}
|
||||
NumChestNeighbors += 1;
|
||||
}
|
||||
if (Area.GetRelBlockType(2, 0, 3) == E_BLOCK_CHEST)
|
||||
if (Area.GetRelBlockType(2, 0, 3) == m_BlockType)
|
||||
{
|
||||
if (
|
||||
(Area.GetRelBlockType(2, 0, 4) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(1, 0, 3) == E_BLOCK_CHEST) ||
|
||||
(Area.GetRelBlockType(3, 0, 3) == E_BLOCK_CHEST)
|
||||
(Area.GetRelBlockType(2, 0, 4) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(1, 0, 3) == m_BlockType) ||
|
||||
(Area.GetRelBlockType(3, 0, 3) == m_BlockType)
|
||||
)
|
||||
{
|
||||
// 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.
|
||||
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;
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ public:
|
|||
|
||||
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));
|
||||
}
|
||||
} ;
|
||||
|
||||
|
|
|
@ -16,13 +16,6 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
a_Pickups.push_back(cItem(E_BLOCK_WOOL, 1, a_BlockMeta));
|
||||
}
|
||||
|
||||
|
||||
virtual const char * GetStepSound(void) override
|
||||
{
|
||||
return "step.cloth";
|
||||
|
|
|
@ -19,15 +19,13 @@
|
|||
class cBlockFarmlandHandler :
|
||||
public cBlockHandler
|
||||
{
|
||||
typedef cBlockHandler super;
|
||||
|
||||
public:
|
||||
cBlockFarmlandHandler(void) :
|
||||
super(E_BLOCK_FARMLAND)
|
||||
cBlockFarmlandHandler(BLOCKTYPE a_BlockType) :
|
||||
cBlockHandler(a_BlockType)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual void OnUpdate(cChunkInterface & cChunkInterface, cWorldInterface & a_WorldInterface, cBlockPluginInterface & a_PluginInterface, cChunk & a_Chunk, int a_RelX, int a_RelY, int a_RelZ) override
|
||||
{
|
||||
bool Found = false;
|
||||
|
@ -105,6 +103,11 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
a_Pickups.Add(E_BLOCK_DIRT, 1, 0); // Reset meta
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE 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_ACTIVATOR_RAIL: return new cBlockRailHandler (a_BlockType);
|
||||
case E_BLOCK_ANVIL: return new cBlockAnvilHandler (a_BlockType);
|
||||
|
@ -211,7 +211,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
|
|||
case E_BLOCK_EMERALD_ORE: return new cBlockOreHandler (a_BlockType);
|
||||
case E_BLOCK_ENCHANTMENT_TABLE: return new cBlockEnchantmentTableHandler(a_BlockType);
|
||||
case E_BLOCK_ENDER_CHEST: return new cBlockEnderchestHandler (a_BlockType);
|
||||
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler ( );
|
||||
case E_BLOCK_FARMLAND: return new cBlockFarmlandHandler (a_BlockType);
|
||||
case E_BLOCK_FENCE_GATE: return new cBlockFenceGateHandler (a_BlockType);
|
||||
case E_BLOCK_FIRE: return new cBlockFireHandler (a_BlockType);
|
||||
case E_BLOCK_FLOWER_POT: return new cBlockFlowerPotHandler (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_LAVA: return new cBlockLavaHandler (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_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_MELON: return new cBlockMelonHandler (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_TRAPDOOR: return new cBlockTrapdoorHandler (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_HOOK: return new cBlockTripwireHookHandler (a_BlockType);
|
||||
case E_BLOCK_VINES: return new cBlockVineHandler (a_BlockType);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BlockHandler.h"
|
||||
#include "BlockSideways.h"
|
||||
|
||||
|
||||
|
|
|
@ -41,21 +41,27 @@ public:
|
|||
}
|
||||
|
||||
|
||||
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction) // tolua_export
|
||||
{ // tolua_export
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
a_Pickups.Add(m_BlockType, 1, 0); // Reset meta
|
||||
}
|
||||
|
||||
|
||||
static NIBBLETYPE DirectionToMetaData(eBlockFace a_Direction)
|
||||
{
|
||||
switch (a_Direction)
|
||||
{
|
||||
case BLOCK_FACE_ZM: return 0x2;
|
||||
case BLOCK_FACE_ZP: return 0x3;
|
||||
case BLOCK_FACE_XM: return 0x4;
|
||||
case BLOCK_FACE_XP: return 0x5;
|
||||
default: return 0x2;
|
||||
default: return 0x2;
|
||||
}
|
||||
} // tolua_export
|
||||
}
|
||||
|
||||
|
||||
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData) // tolua_export
|
||||
{ // tolua_export
|
||||
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
|
||||
{
|
||||
switch (a_MetaData)
|
||||
{
|
||||
case 0x2: return BLOCK_FACE_ZM;
|
||||
|
@ -64,10 +70,10 @@ public:
|
|||
case 0x5: return BLOCK_FACE_XP;
|
||||
default: return BLOCK_FACE_ZM;
|
||||
}
|
||||
} // tolua_export
|
||||
}
|
||||
|
||||
|
||||
/// Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure
|
||||
/** Finds a suitable Direction for the Ladder. Returns BLOCK_FACE_BOTTOM on failure */
|
||||
static eBlockFace FindSuitableBlockFace(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
for (int FaceInt = BLOCK_FACE_ZM; FaceInt <= BLOCK_FACE_XP; FaceInt++)
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
|
||||
a_WorldInterface.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ int cBlockPistonHandler::FirstPassthroughBlock(int a_PistonX, int a_PistonY, int
|
|||
NIBBLETYPE currMeta;
|
||||
AddPistonDir(a_PistonX, a_PistonY, a_PistonZ, pistonmeta, 1);
|
||||
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
|
||||
return ret;
|
||||
|
@ -124,7 +124,7 @@ void cBlockPistonHandler::ExtendPiston(int a_BlockX, int a_BlockY, int a_BlockZ,
|
|||
}
|
||||
|
||||
a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 0, pistonMeta, pistonBlock);
|
||||
a_World->BroadcastSoundEffect("tile.piston.out", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f);
|
||||
a_World->BroadcastSoundEffect("tile.piston.out", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, 0.7f);
|
||||
|
||||
// Drop the breakable block in the line, if appropriate:
|
||||
AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, dist + 1); // "a_Block" now at the breakable / empty block
|
||||
|
@ -198,7 +198,7 @@ void cBlockPistonHandler::RetractPiston(int a_BlockX, int a_BlockY, int a_BlockZ
|
|||
AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, -1);
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, pistonBlock, pistonMeta & ~(8));
|
||||
a_World->BroadcastBlockAction(a_BlockX, a_BlockY, a_BlockZ, 1, pistonMeta & ~(8), pistonBlock);
|
||||
a_World->BroadcastSoundEffect("tile.piston.in", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, 0.7f);
|
||||
a_World->BroadcastSoundEffect("tile.piston.in", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 0.5f, 0.7f);
|
||||
AddPistonDir(a_BlockX, a_BlockY, a_BlockZ, pistonMeta, 1);
|
||||
|
||||
// Retract the extension, pull block if appropriate
|
||||
|
|
|
@ -104,6 +104,7 @@ private:
|
|||
case E_BLOCK_ENCHANTMENT_TABLE:
|
||||
case E_BLOCK_END_PORTAL:
|
||||
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_LIT_FURNACE:
|
||||
case E_BLOCK_HOPPER:
|
||||
|
@ -113,6 +114,7 @@ private:
|
|||
case E_BLOCK_NOTE_BLOCK:
|
||||
case E_BLOCK_OBSIDIAN:
|
||||
case E_BLOCK_PISTON_EXTENSION:
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -126,24 +128,10 @@ private:
|
|||
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
|
||||
static inline bool CanPull(BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
switch (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))
|
||||
if (cBlockInfo::IsPistonBreakable(a_BlockType))
|
||||
{
|
||||
return false; // CanBreakPush returns true, but we need false to prevent pulling
|
||||
}
|
||||
|
|
|
@ -32,36 +32,36 @@ public:
|
|||
|
||||
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
|
||||
{
|
||||
a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3);
|
||||
a_Pickups.Add(m_BlockType, 1, a_BlockMeta & 0x3); // Reset meta
|
||||
}
|
||||
|
||||
|
||||
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_WoodMeta)
|
||||
inline static NIBBLETYPE BlockFaceToMetaData(eBlockFace a_BlockFace, NIBBLETYPE a_Meta)
|
||||
{
|
||||
switch (a_BlockFace)
|
||||
{
|
||||
case BLOCK_FACE_YM:
|
||||
case BLOCK_FACE_YP:
|
||||
{
|
||||
return a_WoodMeta; // Top or bottom, just return original
|
||||
return a_Meta; // Top or bottom, just return original
|
||||
}
|
||||
|
||||
case BLOCK_FACE_ZP:
|
||||
case BLOCK_FACE_ZM:
|
||||
{
|
||||
return a_WoodMeta | 0x8; // North or south
|
||||
return a_Meta | 0x8; // North or south
|
||||
}
|
||||
|
||||
case BLOCK_FACE_XP:
|
||||
case BLOCK_FACE_XM:
|
||||
{
|
||||
return a_WoodMeta | 0x4; // East or west
|
||||
return a_Meta | 0x4; // East or west
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled block face!");
|
||||
return a_WoodMeta | 0xC; // No idea, give a special meta (all sides bark)
|
||||
return a_Meta | 0xC; // No idea, give a special meta
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ public:
|
|||
virtual ~cBroadcastInterface() {}
|
||||
|
||||
virtual void BroadcastUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
|
||||
virtual void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
|
||||
virtual void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL) = 0;
|
||||
virtual void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL) = 0;
|
||||
};
|
||||
|
|
|
@ -1301,6 +1301,7 @@ void cChunk::CreateBlockEntities(void)
|
|||
switch (BlockType)
|
||||
{
|
||||
case E_BLOCK_BEACON:
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
case E_BLOCK_CHEST:
|
||||
case E_BLOCK_COMMAND_BLOCK:
|
||||
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)
|
||||
{
|
||||
case E_BLOCK_BEACON:
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
case E_BLOCK_CHEST:
|
||||
case E_BLOCK_COMMAND_BLOCK:
|
||||
case E_BLOCK_DISPENSER:
|
||||
|
@ -2150,7 +2152,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallb
|
|||
{
|
||||
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
|
||||
return false;
|
||||
|
@ -2530,8 +2532,8 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ)
|
|||
{
|
||||
int BlockX = m_PosX * cChunkDef::Width + a_RelX;
|
||||
int BlockZ = m_PosZ * cChunkDef::Width + a_RelZ;
|
||||
int BlockY, ChunkX, ChunkZ;
|
||||
AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
|
||||
int ChunkX, ChunkZ;
|
||||
BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
||||
return m_ChunkMap->GetChunkNoLoad(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
}
|
||||
|
||||
|
@ -2954,7 +2956,7 @@ void cChunk::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_EffectI
|
|||
|
||||
|
||||
|
||||
void cChunk::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
|
||||
void cChunk::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
|
||||
{
|
||||
for (cClientHandleList::iterator itr = m_LoadedByClient.begin(); itr != m_LoadedByClient.end(); ++itr )
|
||||
{
|
||||
|
@ -2962,7 +2964,7 @@ void cChunk::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a
|
|||
{
|
||||
continue;
|
||||
}
|
||||
(*itr)->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
|
||||
(*itr)->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
|
||||
} // for itr - LoadedByClient[]
|
||||
}
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ public:
|
|||
void BroadcastEntityAnimation (const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
|
||||
void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
|
||||
|
|
|
@ -647,19 +647,19 @@ void cChunkMap::BroadcastRemoveEntityEffect(const cEntity & a_Entity, int a_Effe
|
|||
|
||||
|
||||
|
||||
void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
|
||||
void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
int ChunkX, ChunkZ;
|
||||
|
||||
cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ);
|
||||
cChunkDef::BlockToChunk((int)std::floor(a_X), (int)std::floor(a_Z), ChunkX, ChunkZ);
|
||||
cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// It's perfectly legal to broadcast packets even to invalid chunks!
|
||||
Chunk->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude);
|
||||
Chunk->BroadcastSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch, a_Exclude);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ);
|
||||
|
@ -856,6 +871,10 @@ void cChunkMap::MarkChunkDirty (int a_ChunkX, int a_ChunkZ)
|
|||
return;
|
||||
}
|
||||
Chunk->MarkDirty();
|
||||
if (a_MarkRedstoneDirty)
|
||||
{
|
||||
Chunk->SetIsRedstoneDirty(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1259,7 +1278,7 @@ void cChunkMap::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYP
|
|||
|
||||
|
||||
|
||||
void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients)
|
||||
void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients)
|
||||
{
|
||||
cChunkInterface ChunkInterface(this);
|
||||
if (a_BlockType == E_BLOCK_AIR)
|
||||
|
@ -1284,7 +1303,7 @@ void cChunkMap::SetBlock(cWorldInterface & a_WorldInterface, int a_BlockX, int a
|
|||
|
||||
|
||||
|
||||
void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType)
|
||||
void cChunkMap::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType)
|
||||
{
|
||||
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
|
||||
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
|
||||
|
@ -1530,7 +1549,7 @@ void cChunkMap::SendBlockTo(int a_X, int a_Y, int a_Z, cPlayer * a_Player)
|
|||
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkPtr Chunk = GetChunk(ChunkX, ZERO_CHUNK_Y, ChunkZ);
|
||||
if (Chunk->IsValid())
|
||||
if ((Chunk != NULL) && (Chunk->IsValid()))
|
||||
{
|
||||
Chunk->SendBlockTo(a_X, a_Y, a_Z, a_Player->GetClientHandle());
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ public:
|
|||
void BroadcastEntityAnimation(const cEntity & a_Entity, char a_Animation, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount, cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // a_Src coords are Block * 8
|
||||
void BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastSpawnEntity(cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, const cClientHandle * a_Exclude = NULL);
|
||||
|
@ -106,7 +106,8 @@ public:
|
|||
/** 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 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 MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
|
@ -153,9 +154,9 @@ public:
|
|||
NIBBLETYPE GetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
NIBBLETYPE GetBlockSkyLight (int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockMeta);
|
||||
void SetBlock (cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, bool a_SendToClients = true);
|
||||
void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, BLOCKTYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
|
||||
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta);
|
||||
void SetBlock (cWorldInterface & a_WorldInterface, int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, bool a_SendToClients = true);
|
||||
void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
|
||||
bool GetBlockTypeMeta (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta);
|
||||
bool GetBlockInfo (int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_Meta, NIBBLETYPE & a_SkyLight, NIBBLETYPE & a_BlockLight);
|
||||
|
||||
|
|
|
@ -40,9 +40,6 @@
|
|||
/** Maximum number of block change interactions a player can perform per tick - exceeding this causes a kick */
|
||||
#define MAX_BLOCK_CHANGE_INTERACTIONS 20
|
||||
|
||||
/** How many ticks before the socket is closed after the client is destroyed (#31) */
|
||||
static const int TICKS_BEFORE_CLOSE = 20;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -79,7 +76,6 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
|
|||
m_PingID(1),
|
||||
m_BlockDigAnimStage(-1),
|
||||
m_HasStartedDigging(false),
|
||||
m_TicksSinceDestruction(0),
|
||||
m_State(csConnected),
|
||||
m_ShouldCheckDownloaded(false),
|
||||
m_NumExplosionsThisTick(0),
|
||||
|
@ -104,7 +100,7 @@ cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) :
|
|||
|
||||
cClientHandle::~cClientHandle()
|
||||
{
|
||||
ASSERT(m_State >= csDestroyedWaiting); // Has Destroy() been called?
|
||||
ASSERT(m_State == csDestroyed); // Has Destroy() been called?
|
||||
|
||||
LOGD("Deleting client \"%s\" at %p", GetUsername().c_str(), this);
|
||||
|
||||
|
@ -169,7 +165,7 @@ void cClientHandle::Destroy(void)
|
|||
RemoveFromAllChunks();
|
||||
m_Player->GetWorld()->RemoveClientFromChunkSender(this);
|
||||
}
|
||||
m_State = csDestroyedWaiting;
|
||||
m_State = csDestroyed;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1366,7 +1362,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
|||
NewBlock->OnPlacedByPlayer(ChunkInterface,*World, m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
||||
|
||||
// Step sound with 0.8f pitch is used as block placement sound
|
||||
World->BroadcastSoundEffect(NewBlock->GetStepSound(), a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.8f);
|
||||
World->BroadcastSoundEffect(NewBlock->GetStepSound(), (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.8f);
|
||||
cRoot::Get()->GetPluginManager()->CallHookPlayerPlacedBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, BlockType, BlockMeta);
|
||||
}
|
||||
|
||||
|
@ -1824,18 +1820,7 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
|
|||
|
||||
|
||||
void cClientHandle::Tick(float a_Dt)
|
||||
{
|
||||
// Handle clients that are waiting for final close while destroyed:
|
||||
if (m_State == csDestroyedWaiting)
|
||||
{
|
||||
m_TicksSinceDestruction += 1; // This field is misused for the timeout counting
|
||||
if (m_TicksSinceDestruction > TICKS_BEFORE_CLOSE)
|
||||
{
|
||||
m_State = csDestroyed;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Process received network data:
|
||||
AString IncomingData;
|
||||
{
|
||||
|
@ -1901,15 +1886,7 @@ void cClientHandle::Tick(float a_Dt)
|
|||
|
||||
|
||||
void cClientHandle::ServerTick(float a_Dt)
|
||||
{
|
||||
// Handle clients that are waiting for final close while destroyed:
|
||||
if (m_State == csDestroyedWaiting)
|
||||
{
|
||||
// Do not wait while the client is not in the world, simply cut them off.
|
||||
m_State = csDestroyed;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Process received network data:
|
||||
AString IncomingData;
|
||||
{
|
||||
|
@ -2450,9 +2427,9 @@ void cClientHandle::SendDisplayObjective(const AString & a_Objective, cScoreboar
|
|||
|
||||
|
||||
|
||||
void cClientHandle::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
|
||||
void cClientHandle::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
|
||||
{
|
||||
m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
|
||||
m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ public:
|
|||
void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
|
||||
void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
|
||||
void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
|
||||
void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch); // a_Src coords are Block * 8
|
||||
void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch); // tolua_export
|
||||
void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data);
|
||||
void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock);
|
||||
void SendSpawnMob (const cMonster & a_Mob);
|
||||
|
@ -325,9 +325,6 @@ private:
|
|||
int m_LastDigBlockX;
|
||||
int m_LastDigBlockY;
|
||||
int m_LastDigBlockZ;
|
||||
|
||||
/** Used while csDestroyedWaiting for counting the ticks until the connection is closed */
|
||||
int m_TicksSinceDestruction;
|
||||
|
||||
enum eState
|
||||
{
|
||||
|
@ -338,7 +335,6 @@ private:
|
|||
csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back
|
||||
csPlaying, ///< Normal gameplay
|
||||
csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks
|
||||
csDestroyedWaiting, ///< The client has been destroyed, but is still kept so that the Kick packet is delivered (#31)
|
||||
csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread
|
||||
|
||||
// TODO: Add Kicking here as well
|
||||
|
|
|
@ -79,8 +79,8 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
|
|||
}
|
||||
|
||||
Vector3d Hit = a_HitPos;
|
||||
Vector3d SinkMovement = (GetSpeed() / 800);
|
||||
Hit += (SinkMovement * 0.01) / SinkMovement.Length(); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
|
||||
Vector3d SinkMovement = (GetSpeed() / 1000);
|
||||
Hit += SinkMovement * (0.0005 / SinkMovement.Length()); // Make arrow sink into block a centimetre so it lodges (but not to far so it goes black clientside)
|
||||
|
||||
super::OnHitSolidBlock(Hit, a_HitFace);
|
||||
Vector3i BlockHit = Hit.Floor();
|
||||
|
@ -89,7 +89,7 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
|
|||
m_HitBlockPos = Vector3i(X, Y, Z);
|
||||
|
||||
// Broadcast arrow hit sound
|
||||
m_World->BroadcastSoundEffect("random.bowhit", X * 8, Y * 8, Z * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_World->BroadcastSoundEffect("random.bowhit", (double)X, (double)Y, (double)Z, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,7 +106,7 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
||||
|
||||
// Broadcast successful hit sound
|
||||
GetWorld()->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
GetWorld()->BroadcastSoundEffect("random.successful_hit", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ void cArrowEntity::CollectedBy(cPlayer * a_Dest)
|
|||
}
|
||||
|
||||
GetWorld()->BroadcastCollectEntity(*this, *a_Dest);
|
||||
GetWorld()->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
GetWorld()->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_bIsCollected = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
|
|||
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
|
||||
a_ClosestPlayer->DeltaExperience(m_Reward);
|
||||
|
||||
m_World->BroadcastSoundEffect("random.orb", (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_World->BroadcastSoundEffect("random.orb", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
class cExpOrb :
|
||||
public cEntity
|
||||
{
|
||||
typedef cExpOrb super;
|
||||
typedef cEntity super;
|
||||
|
||||
public:
|
||||
// tolua_end
|
||||
|
|
|
@ -134,7 +134,7 @@ void cFloater::Tick(float a_Dt, cChunk & a_Chunk)
|
|||
{
|
||||
if (m_CountDownTime <= 0)
|
||||
{
|
||||
m_World->BroadcastSoundEffect("random.splash", (int) floor(GetPosX() * 8), (int) floor(GetPosY() * 8), (int) floor(GetPosZ() * 8), 1, 1);
|
||||
m_World->BroadcastSoundEffect("random.splash", GetPosX(), GetPosY(), GetPosZ(), 1, 1);
|
||||
SetPosY(GetPosY() - 1);
|
||||
m_CanPickupItem = true;
|
||||
m_PickupCountDown = 20;
|
||||
|
|
|
@ -226,7 +226,7 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
|
|||
m_Item.m_ItemCount -= NumAdded;
|
||||
m_World->BroadcastCollectEntity(*this, *a_Dest);
|
||||
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
||||
m_World->BroadcastSoundEffect("random.pop",(int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_World->BroadcastSoundEffect("random.pop", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
if (m_Item.m_ItemCount <= 0)
|
||||
{
|
||||
// All of the pickup has been collected, schedule the pickup for destroying
|
||||
|
|
|
@ -1917,7 +1917,7 @@ void cPlayer::UseEquippedItem(void)
|
|||
|
||||
if (GetInventory().DamageEquippedItem())
|
||||
{
|
||||
m_World->BroadcastSoundEffect("random.break", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
|
|||
|
||||
|
||||
|
||||
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed)
|
||||
cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed)
|
||||
{
|
||||
Vector3d Speed;
|
||||
if (a_Speed != NULL)
|
||||
|
@ -264,12 +264,13 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator,
|
|||
case pkWitherSkull: return new cWitherSkullEntity (a_Creator, a_X, a_Y, a_Z, Speed);
|
||||
case pkFirework:
|
||||
{
|
||||
if (a_Item.m_FireworkItem.m_Colours.empty())
|
||||
ASSERT(a_Item != NULL);
|
||||
if (a_Item->m_FireworkItem.m_Colours.empty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, a_Item);
|
||||
return new cFireworkEntity(a_Creator, a_X, a_Y, a_Z, *a_Item);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
|
||||
cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height);
|
||||
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item, const Vector3d * a_Speed = NULL);
|
||||
static cProjectileEntity * Create(eKind a_Kind, cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem * a_Item, const Vector3d * a_Speed = NULL);
|
||||
|
||||
/// Called by the physics blocktracer when the entity hits a solid block, the hit position and the face hit (BLOCK_FACE_) is given
|
||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace);
|
||||
|
|
|
@ -290,7 +290,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
|
|||
LOGWARNING("%s: MaxRelX less than zero, adjusting to zero", __FUNCTION__);
|
||||
a_MaxRelX = 0;
|
||||
}
|
||||
else if (a_MinRelX >= cChunkDef::Width)
|
||||
else if (a_MaxRelX >= cChunkDef::Width)
|
||||
{
|
||||
LOGWARNING("%s: MaxRelX more than chunk width, adjusting to chunk width", __FUNCTION__);
|
||||
a_MaxRelX = cChunkDef::Width - 1;
|
||||
|
@ -311,7 +311,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
|
|||
LOGWARNING("%s: MaxRelY less than zero, adjusting to zero", __FUNCTION__);
|
||||
a_MaxRelY = 0;
|
||||
}
|
||||
else if (a_MinRelY >= cChunkDef::Height)
|
||||
else if (a_MaxRelY >= cChunkDef::Height)
|
||||
{
|
||||
LOGWARNING("%s: MaxRelY more than chunk height, adjusting to chunk height", __FUNCTION__);
|
||||
a_MaxRelY = cChunkDef::Height - 1;
|
||||
|
@ -332,7 +332,7 @@ void cChunkDesc::ReadBlockArea(cBlockArea & a_Dest, int a_MinRelX, int a_MaxRelX
|
|||
LOGWARNING("%s: MaxRelZ less than zero, adjusting to zero", __FUNCTION__);
|
||||
a_MaxRelZ = 0;
|
||||
}
|
||||
else if (a_MinRelZ >= cChunkDef::Width)
|
||||
else if (a_MaxRelZ >= cChunkDef::Width)
|
||||
{
|
||||
LOGWARNING("%s: MaxRelZ more than chunk width, adjusting to chunk width", __FUNCTION__);
|
||||
a_MaxRelZ = cChunkDef::Width - 1;
|
||||
|
|
|
@ -44,6 +44,7 @@ cGridStructGen::cGridStructGen(
|
|||
int a_MaxStructureSizeX, int a_MaxStructureSizeZ,
|
||||
size_t a_MaxCacheSize
|
||||
) :
|
||||
m_Seed(a_Seed),
|
||||
m_Noise(a_Seed),
|
||||
m_GridSizeX(a_GridSizeX),
|
||||
m_GridSizeZ(a_GridSizeZ),
|
||||
|
@ -53,6 +54,16 @@ cGridStructGen::cGridStructGen(
|
|||
m_MaxStructureSizeZ(a_MaxStructureSizeZ),
|
||||
m_MaxCacheSize(a_MaxCacheSize)
|
||||
{
|
||||
if (m_GridSizeX == 0)
|
||||
{
|
||||
LOG("Grid Size cannot be zero, setting to 1");
|
||||
m_GridSizeX = 1;
|
||||
}
|
||||
if (m_GridSizeZ == 0)
|
||||
{
|
||||
LOG("Grid Size cannot be zero, setting to 1");
|
||||
m_GridSizeZ = 1;
|
||||
}
|
||||
size_t NumStructuresPerQuery = (size_t)(((m_MaxStructureSizeX + m_MaxOffsetX) / m_GridSizeX + 1) * ((m_MaxStructureSizeZ + m_MaxOffsetZ) / m_GridSizeZ + 1));
|
||||
if (NumStructuresPerQuery > m_MaxCacheSize)
|
||||
{
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", (int)a_Player->GetPosX() * 8, (int)a_Player->GetPosY() * 8, (int)a_Player->GetPosZ() * 8, 0.5, (float)Force);
|
||||
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force);
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
a_Player->UseEquippedItem();
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
|
||||
bool ScoopUpFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace)
|
||||
{
|
||||
if (a_BlockFace > 0)
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -95,29 +95,15 @@ public:
|
|||
|
||||
bool PlaceFluid(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_FluidBlock)
|
||||
{
|
||||
if (a_BlockFace < 0)
|
||||
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BLOCKTYPE CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
bool CanWashAway = cFluidSimulator::CanWashAway(CurrentBlock);
|
||||
if (!CanWashAway)
|
||||
BLOCKTYPE CurrentBlock;
|
||||
Vector3i BlockPos;
|
||||
if (!GetPlacementCoordsFromTrace(a_World, a_Player, BlockPos, CurrentBlock))
|
||||
{
|
||||
// The block pointed at cannot be washed away, so put fluid on top of it / on its sides
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||
CurrentBlock = a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
}
|
||||
if (
|
||||
!CanWashAway &&
|
||||
(CurrentBlock != E_BLOCK_AIR) &&
|
||||
(CurrentBlock != E_BLOCK_WATER) &&
|
||||
(CurrentBlock != E_BLOCK_STATIONARY_WATER) &&
|
||||
(CurrentBlock != E_BLOCK_LAVA) &&
|
||||
(CurrentBlock != E_BLOCK_STATIONARY_LAVA)
|
||||
)
|
||||
{
|
||||
// Cannot place water here
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -138,7 +124,7 @@ public:
|
|||
}
|
||||
|
||||
// Wash away anything that was there prior to placing:
|
||||
if (CanWashAway)
|
||||
if (cFluidSimulator::CanWashAway(CurrentBlock))
|
||||
{
|
||||
cBlockHandler * Handler = BlockHandler(CurrentBlock);
|
||||
if (Handler->DoesDropOnUnsuitable())
|
||||
|
@ -149,13 +135,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, a_FluidBlock, 0);
|
||||
a_World->SetBlock(BlockPos.x, BlockPos.y, BlockPos.z, a_FluidBlock, 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & BlockPos)
|
||||
bool GetBlockFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos)
|
||||
{
|
||||
class cCallbacks :
|
||||
public cBlockTracer::cCallbacks
|
||||
|
@ -198,8 +184,49 @@ public:
|
|||
}
|
||||
|
||||
|
||||
BlockPos.Set(Callbacks.m_Pos.x, Callbacks.m_Pos.y, Callbacks.m_Pos.z);
|
||||
a_BlockPos = Callbacks.m_Pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GetPlacementCoordsFromTrace(cWorld * a_World, cPlayer * a_Player, Vector3i & a_BlockPos, BLOCKTYPE & a_BlockType)
|
||||
{
|
||||
class cCallbacks :
|
||||
public cBlockTracer::cCallbacks
|
||||
{
|
||||
public:
|
||||
Vector3i m_Pos;
|
||||
BLOCKTYPE m_ReplacedBlock;
|
||||
|
||||
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
|
||||
{
|
||||
if (a_BlockType != E_BLOCK_AIR)
|
||||
{
|
||||
m_ReplacedBlock = a_BlockType;
|
||||
if (!cFluidSimulator::CanWashAway(a_BlockType) && !IsBlockLiquid(a_BlockType))
|
||||
{
|
||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, (eBlockFace)a_EntryFace); // Was an unwashawayable block, can't overwrite it!
|
||||
}
|
||||
m_Pos.Set(a_BlockX, a_BlockY, a_BlockZ); // (Block could be washed away, replace it)
|
||||
return true; // Abort tracing
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} Callbacks;
|
||||
|
||||
cLineBlockTracer Tracer(*a_World, Callbacks);
|
||||
Vector3d Start(a_Player->GetEyePosition() + a_Player->GetLookVector());
|
||||
Vector3d End(a_Player->GetEyePosition() + a_Player->GetLookVector() * 5);
|
||||
|
||||
// cTracer::Trace returns true when whole line was traversed. By returning true when we hit something, we ensure that this never happens if liquid could be placed
|
||||
// Use this to judge whether the position is valid
|
||||
if (!Tracer.Trace(Start.x, Start.y, Start.z, End.x, End.y, End.z))
|
||||
{
|
||||
a_BlockPos = Callbacks.m_Pos;
|
||||
a_BlockType = Callbacks.m_ReplacedBlock;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -52,8 +52,8 @@ public:
|
|||
case E_BLOCK_TNT:
|
||||
{
|
||||
// Activate the TNT:
|
||||
a_World->BroadcastSoundEffect("game.tnt.primed", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 1.0f);
|
||||
a_World->SetBlock(a_BlockX,a_BlockY,a_BlockZ, E_BLOCK_AIR, 0);
|
||||
a_World->BroadcastSoundEffect("game.tnt.primed", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 1.0f);
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_AIR, 0);
|
||||
a_World->SpawnPrimedTNT(a_BlockX + 0.5, a_BlockY + 0.5, a_BlockZ + 0.5); // 80 ticks to boom
|
||||
break;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public:
|
|||
if (a_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
||||
{
|
||||
a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 0);
|
||||
a_World->BroadcastSoundEffect("fire.ignite", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0F, 1.04F);
|
||||
a_World->BroadcastSoundEffect("fire.ignite", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0F, 1.04F);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,16 +33,9 @@ public:
|
|||
|
||||
// Play sound
|
||||
cFastRandom Random;
|
||||
a_World->BroadcastSoundEffect(
|
||||
"random.bow",
|
||||
(int)std::floor(a_Player->GetPosX() * 8.0),
|
||||
(int)std::floor((a_Player->GetPosY() - a_Player->GetHeight()) * 8.0),
|
||||
(int)std::floor(a_Player->GetPosZ() * 8.0),
|
||||
0.5F,
|
||||
0.4F / (Random.NextFloat(1.0F) * 0.4F + 0.8F)
|
||||
);
|
||||
a_World->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY() - a_Player->GetHeight(), a_Player->GetPosZ(), 0.5f, 0.4f / (Random.NextFloat(1.0f) * 0.4f + 0.8f));
|
||||
|
||||
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, a_Player->GetEquippedItem(), &Speed) < 0)
|
||||
if (a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem(), &Speed) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -142,7 +135,7 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, a_Player->GetEquippedItem()) < 0)
|
||||
if (a_World->CreateProjectile(a_BlockX + 0.5, a_BlockY + 1, a_BlockZ + 0.5, m_ProjectileKind, a_Player, &a_Player->GetEquippedItem()) < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -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 BlockZ = m_CenterZ + ((a_Z - (m_Height / 2)) * PixelWidth);
|
||||
|
||||
int ChunkX, ChunkY, ChunkZ;
|
||||
m_World->BlockToChunk(BlockX, 0, BlockZ, ChunkX, ChunkY, ChunkZ);
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
|
||||
|
||||
int RelX = BlockX - (ChunkX * cChunkDef::Width);
|
||||
int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);
|
||||
|
|
|
@ -125,7 +125,7 @@ void cCreeper::Attack(float a_Dt)
|
|||
|
||||
if (!m_bIsBlowing)
|
||||
{
|
||||
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_bIsBlowing = true;
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ void cCreeper::OnRightClicked(cPlayer & a_Player)
|
|||
{
|
||||
a_Player.UseEquippedItem();
|
||||
}
|
||||
m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
m_bIsBlowing = true;
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
m_BurnedWithFlintAndSteel = true;
|
||||
|
|
|
@ -479,7 +479,7 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||
|
||||
if (!m_SoundHurt.empty() && (m_Health > 0))
|
||||
{
|
||||
m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
|
||||
m_World->BroadcastSoundEffect(m_SoundHurt, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
|
||||
}
|
||||
|
||||
if (a_TDI.Attacker != NULL)
|
||||
|
@ -498,7 +498,7 @@ void cMonster::KilledBy(cEntity * a_Killer)
|
|||
super::KilledBy(a_Killer);
|
||||
if (m_SoundHurt != "")
|
||||
{
|
||||
m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
|
||||
m_World->BroadcastSoundEffect(m_SoundDeath, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
|
||||
}
|
||||
int Reward;
|
||||
switch (m_MobType)
|
||||
|
@ -920,7 +920,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
|
|||
case mtMooshroom: toReturn = new cMooshroom(); break;
|
||||
case mtOcelot: toReturn = new cOcelot(); break;
|
||||
case mtPig: toReturn = new cPig(); break;
|
||||
case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
|
||||
case mtSheep: toReturn = new cSheep(); break;
|
||||
case mtSilverfish: toReturn = new cSilverfish(); break;
|
||||
case mtSnowGolem: toReturn = new cSnowGolem(); break;
|
||||
case mtSpider: toReturn = new cSpider(); break;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "../BlockID.h"
|
||||
#include "../Entities/Player.h"
|
||||
#include "../World.h"
|
||||
#include "FastRandom.h"
|
||||
|
||||
|
||||
|
||||
|
@ -16,6 +17,16 @@ cSheep::cSheep(int a_Color) :
|
|||
m_WoolColor(a_Color),
|
||||
m_TimeToStopEating(-1)
|
||||
{
|
||||
// Generate random wool color.
|
||||
if (m_WoolColor == -1)
|
||||
{
|
||||
m_WoolColor = GenerateNaturalRandomColor();
|
||||
}
|
||||
|
||||
if ((m_WoolColor < 0) || (m_WoolColor > 15))
|
||||
{
|
||||
m_WoolColor = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,7 +48,7 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||
void cSheep::OnRightClicked(cPlayer & a_Player)
|
||||
{
|
||||
const cItem & EquippedItem = a_Player.GetEquippedItem();
|
||||
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
|
||||
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
|
||||
{
|
||||
m_IsSheared = true;
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
|
@ -51,6 +62,7 @@ void cSheep::OnRightClicked(cPlayer & a_Player)
|
|||
int NumDrops = m_World->GetTickRandomNumber(2) + 1;
|
||||
Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
|
||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
|
||||
m_World->BroadcastSoundEffect("mob.sheep.shear", GetPosX(), GetPosY(), GetPosZ(), 1.0f, 1.0f);
|
||||
}
|
||||
else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage))
|
||||
{
|
||||
|
@ -109,3 +121,38 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
NIBBLETYPE cSheep::GenerateNaturalRandomColor(void)
|
||||
{
|
||||
cFastRandom Random;
|
||||
int Chance = Random.NextInt(101);
|
||||
|
||||
if (Chance <= 81)
|
||||
{
|
||||
return E_META_WOOL_WHITE;
|
||||
}
|
||||
else if (Chance <= 86)
|
||||
{
|
||||
return E_META_WOOL_BLACK;
|
||||
}
|
||||
else if (Chance <= 91)
|
||||
{
|
||||
return E_META_WOOL_GRAY;
|
||||
}
|
||||
else if (Chance <= 96)
|
||||
{
|
||||
return E_META_WOOL_LIGHTGRAY;
|
||||
}
|
||||
else if (Chance <= 99)
|
||||
{
|
||||
return E_META_WOOL_BROWN;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_META_WOOL_PINK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,21 +13,32 @@ class cSheep :
|
|||
typedef cPassiveMonster super;
|
||||
|
||||
public:
|
||||
cSheep(int a_Color);
|
||||
|
||||
|
||||
/** The number is the color of the sheep.
|
||||
Use E_META_WOOL_* constants for the wool color.
|
||||
If you type -1, the server will generate a random color
|
||||
with the GenerateNaturalRandomColor() function. */
|
||||
cSheep(int a_Color = -1);
|
||||
|
||||
CLASS_PROTODEF(cSheep);
|
||||
|
||||
|
||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
|
||||
|
||||
/** Generates a random color for the sheep like the vanilla server.
|
||||
The percent's where used are from the wiki: http://minecraft.gamepedia.com/Sheep#Breeding */
|
||||
static NIBBLETYPE GenerateNaturalRandomColor(void);
|
||||
|
||||
bool IsSheared(void) const { return m_IsSheared; }
|
||||
void SetSheared(bool a_IsSheared) { m_IsSheared = a_IsSheared; }
|
||||
|
||||
int GetFurColor(void) const { return m_WoolColor; }
|
||||
void SetFurColor(int a_WoolColor) { m_WoolColor = a_WoolColor; }
|
||||
|
||||
private:
|
||||
|
||||
bool m_IsSheared;
|
||||
int m_WoolColor;
|
||||
int m_TimeToStopEating;
|
||||
|
|
|
@ -262,7 +262,7 @@ bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_S
|
|||
AString HexDump;
|
||||
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());
|
||||
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");
|
||||
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());
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ public:
|
|||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) = 0;
|
||||
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) = 0;
|
||||
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) = 0;
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) = 0; // a_Src coords are Block * 8
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) = 0;
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) = 0;
|
||||
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) = 0;
|
||||
virtual void SendSpawnMob (const cMonster & a_Mob) = 0;
|
||||
|
|
|
@ -899,7 +899,7 @@ void cProtocol125::SendScoreboardObjective(const AString & a_Name, const AString
|
|||
|
||||
|
||||
|
||||
void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
|
||||
void cProtocol125::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
|
||||
{
|
||||
// Not needed in this protocol version
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
|
||||
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
|
||||
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
|
||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||
|
|
|
@ -195,13 +195,6 @@ void cProtocol132::SendCollectEntity(const cEntity & a_Entity, const cPlayer & a
|
|||
WriteInt (a_Entity.GetUniqueID());
|
||||
WriteInt (a_Player.GetUniqueID());
|
||||
Flush();
|
||||
|
||||
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
||||
SendSoundEffect(
|
||||
"random.pop",
|
||||
(int)(a_Entity.GetPosX() * 8), (int)(a_Entity.GetPosY() * 8), (int)(a_Entity.GetPosZ() * 8),
|
||||
0.5, (float)(0.75 + ((float)((a_Entity.GetUniqueID() * 23) % 32)) / 64)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -285,14 +278,14 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
|
|||
|
||||
|
||||
|
||||
void cProtocol132::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
|
||||
void cProtocol132::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
WriteByte (PACKET_SOUND_EFFECT);
|
||||
WriteString (a_SoundName);
|
||||
WriteInt (a_SrcX);
|
||||
WriteInt (a_SrcY);
|
||||
WriteInt (a_SrcZ);
|
||||
WriteInt ((int)(a_X * 8.0));
|
||||
WriteInt ((int)(a_Y * 8.0));
|
||||
WriteInt ((int)(a_Z * 8.0));
|
||||
WriteFloat (a_Volume);
|
||||
WriteChar ((char)(a_Pitch * 63.0f));
|
||||
Flush();
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
virtual void SendEntityEquipment (const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
||||
|
|
|
@ -1084,15 +1084,15 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard
|
|||
|
||||
|
||||
|
||||
void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8
|
||||
void cProtocol172::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
|
||||
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
|
||||
Pkt.WriteString(a_SoundName);
|
||||
Pkt.WriteInt(a_SrcX);
|
||||
Pkt.WriteInt(a_SrcY);
|
||||
Pkt.WriteInt(a_SrcZ);
|
||||
Pkt.WriteInt((int)(a_X * 8.0));
|
||||
Pkt.WriteInt((int)(a_Y * 8.0));
|
||||
Pkt.WriteInt((int)(a_Z * 8.0));
|
||||
Pkt.WriteFloat(a_Volume);
|
||||
Pkt.WriteByte((Byte)(a_Pitch * 63));
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ public:
|
|||
virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
|
||||
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
|
||||
virtual void SendRespawn (const cWorld & a_World, bool a_ShouldIgnoreDimensionChecks = false) override;
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendExperience (void) override;
|
||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
|
||||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
|
||||
|
|
|
@ -616,10 +616,10 @@ void cProtocolRecognizer::SendDisplayObjective(const AString & a_Objective, cSco
|
|||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
|
||||
void cProtocolRecognizer::SendSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch)
|
||||
{
|
||||
ASSERT(m_Protocol != NULL);
|
||||
m_Protocol->SendSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch);
|
||||
m_Protocol->SendSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@ public:
|
|||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
|
||||
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override;
|
||||
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override;
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch) override;
|
||||
virtual void SendSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data) override;
|
||||
virtual void SendSpawnFallingBlock (const cFallingBlock & a_FallingBlock) override;
|
||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||
|
|
|
@ -221,14 +221,12 @@ bool cServer::InitServer(cIniFile & a_SettingsIni)
|
|||
|
||||
bool HasAnyPorts = false;
|
||||
AString Ports = a_SettingsIni.GetValueSet("Server", "Port", "25565");
|
||||
m_ListenThreadIPv4.SetReuseAddr(true);
|
||||
if (m_ListenThreadIPv4.Initialize(Ports))
|
||||
{
|
||||
HasAnyPorts = true;
|
||||
}
|
||||
|
||||
Ports = a_SettingsIni.GetValueSet("Server", "PortsIPv6", "25565");
|
||||
m_ListenThreadIPv6.SetReuseAddr(true);
|
||||
if (m_ListenThreadIPv6.Initialize(Ports))
|
||||
{
|
||||
HasAnyPorts = true;
|
||||
|
|
|
@ -254,7 +254,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
|
|||
);
|
||||
a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0);
|
||||
|
||||
a_NearChunk->BroadcastSoundEffect("random.fizz", BlockX * 8, a_RelY * 8, BlockZ * 8, 0.5f, 1.5f);
|
||||
a_NearChunk->BroadcastSoundEffect("random.fizz", (double)BlockX, (double)a_RelY, (double)BlockZ, 0.5f, 1.5f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -269,7 +269,7 @@ void cFloodyFluidSimulator::SpreadToNeighbor(cChunk * a_NearChunk, int a_RelX, i
|
|||
);
|
||||
a_NearChunk->SetBlock(a_RelX, a_RelY, a_RelZ, NewBlock, 0);
|
||||
|
||||
a_NearChunk->BroadcastSoundEffect("random.fizz", BlockX * 8, a_RelY * 8, BlockZ * 8, 0.5f, 1.5f);
|
||||
a_NearChunk->BroadcastSoundEffect("random.fizz", (double)BlockX, (double)a_RelY, (double)BlockZ, 0.5f, 1.5f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "BoundingBox.h"
|
||||
#include "../BlockEntities/DropSpenserEntity.h"
|
||||
#include "../BlockEntities/NoteEntity.h"
|
||||
#include "../BlockEntities/ChestEntity.h"
|
||||
#include "../BlockEntities/CommandBlockEntity.h"
|
||||
#include "../Entities/TNTEntity.h"
|
||||
#include "../Entities/Pickup.h"
|
||||
|
@ -15,8 +16,6 @@
|
|||
#include "../Blocks/BlockPiston.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;
|
||||
BLOCKTYPE Block;
|
||||
NIBBLETYPE Meta;
|
||||
cChunk * OtherChunk = a_Chunk;
|
||||
|
||||
if (a_OtherChunk != NULL)
|
||||
{
|
||||
RelX = a_BlockX - a_OtherChunk->GetPosX() * cChunkDef::Width;
|
||||
RelZ = a_BlockZ - a_OtherChunk->GetPosZ() * cChunkDef::Width;
|
||||
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
|
||||
{
|
||||
|
@ -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);
|
||||
itr = PoweredBlocks->erase(itr);
|
||||
a_Chunk->SetIsRedstoneDirty(true);
|
||||
OtherChunk->SetIsRedstoneDirty(true);
|
||||
continue;
|
||||
}
|
||||
else if (
|
||||
|
@ -105,34 +104,13 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
|
|||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
|
||||
((Block == E_BLOCK_DETECTOR_RAIL) && ((Meta & 0x08) == 0)) ||
|
||||
(((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))
|
||||
)
|
||||
{
|
||||
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);
|
||||
a_Chunk->SetIsRedstoneDirty(true);
|
||||
OtherChunk->SetIsRedstoneDirty(true);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
itr = LinkedPoweredBlocks->erase(itr);
|
||||
a_Chunk->SetIsRedstoneDirty(true);
|
||||
OtherChunk->SetIsRedstoneDirty(true);
|
||||
continue;
|
||||
}
|
||||
else if (
|
||||
// Things that can send power through a block but which depends on meta
|
||||
((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
|
||||
((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
|
||||
(((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
|
||||
(((Block == E_BLOCK_STONE_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_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
|
||||
)
|
||||
{
|
||||
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);
|
||||
a_Chunk->SetIsRedstoneDirty(true);
|
||||
OtherChunk->SetIsRedstoneDirty(true);
|
||||
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);
|
||||
itr = LinkedPoweredBlocks->erase(itr);
|
||||
a_Chunk->SetIsRedstoneDirty(true);
|
||||
OtherChunk->SetIsRedstoneDirty(true);
|
||||
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_TNT: HandleTNT(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_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)
|
||||
{
|
||||
if (
|
||||
((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
|
||||
if (AreCoordsOnChunkBoundary(a_BlockX, a_BlockY, a_BlockZ))
|
||||
{
|
||||
// On a chunk boundary, alert all four sides (i.e. at least one neighbouring 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
|
||||
// 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, a_BlockZ - 2), a_Chunk);
|
||||
|
@ -430,7 +396,13 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
|
|||
int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
|
||||
AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
|
||||
|
||||
if (AreCoordsDirectlyPowered(X, Y, Z))
|
||||
cChunk * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z);
|
||||
if ((Neighbour == NULL) || !Neighbour->IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour))
|
||||
{
|
||||
// There was a match, torch goes off
|
||||
m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_REDSTONE_TORCH_OFF, m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ));
|
||||
|
@ -448,7 +420,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
|
|||
if (i + 1 < ARRAYCOUNT(gCrossCoords)) // Sides of torch, not top (top is last)
|
||||
{
|
||||
if (
|
||||
((IsMechanism(Type)) || (Type == E_BLOCK_REDSTONE_WIRE)) && // Is it a mechanism or wire? Not block/other torch etc.
|
||||
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
|
||||
)
|
||||
{
|
||||
|
@ -468,7 +440,7 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
@ -479,9 +451,15 @@ void cIncrementalRedstoneSimulator::HandleRedstoneTorch(int a_RelBlockX, int a_R
|
|||
// Check if the block the torch is on is powered
|
||||
int X = a_RelBlockX; int Y = a_RelBlockY; int Z = a_RelBlockZ;
|
||||
AddFaceDirection(X, Y, Z, cBlockTorchHandler::MetaDataToDirection(m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ)), true); // Inverse true to get the block torch is on
|
||||
|
||||
|
||||
cChunk * Neighbour = m_Chunk->GetRelNeighborChunk(X, Z);
|
||||
if ((Neighbour == NULL) || !Neighbour->IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// See if off state torch can be turned on again
|
||||
if (AreCoordsDirectlyPowered(X, Y, Z))
|
||||
if (AreCoordsDirectlyPowered(X, Y, Z, Neighbour))
|
||||
{
|
||||
return; // Something matches, torch still powered
|
||||
}
|
||||
|
@ -780,17 +758,20 @@ void cIncrementalRedstoneSimulator::HandleRedstoneRepeaterDelays()
|
|||
{
|
||||
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?
|
||||
{
|
||||
int RelBlockX = itr->a_RelBlockPos.x;
|
||||
int RelBlockY = itr->a_RelBlockPos.y;
|
||||
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)
|
||||
{
|
||||
|
||||
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta); // For performance
|
||||
if (Block != E_BLOCK_REDSTONE_REPEATER_ON) // For performance
|
||||
{
|
||||
m_Chunk->SetBlock(itr->a_RelBlockPos, E_BLOCK_REDSTONE_REPEATER_ON, Meta);
|
||||
}
|
||||
|
||||
switch (Meta & 0x3) // We only want the direction (bottom) bits
|
||||
{
|
||||
|
@ -820,17 +801,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);
|
||||
}
|
||||
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);
|
||||
itr->a_ElapsedTicks++;
|
||||
itr++;
|
||||
|
@ -915,7 +893,7 @@ void cIncrementalRedstoneSimulator::HandleTNT(int a_RelBlockX, int a_RelBlockY,
|
|||
|
||||
if (AreCoordsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ))
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("game.tnt.primed", BlockX * 8, a_RelBlockY * 8, BlockZ * 8, 0.5f, 0.6f);
|
||||
m_Chunk->BroadcastSoundEffect("game.tnt.primed", (double)BlockX, (double)a_RelBlockY, (double)BlockZ, 0.5f, 0.6f);
|
||||
m_Chunk->SetBlock(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_BLOCK_AIR, 0);
|
||||
m_World.SpawnPrimedTNT(BlockX + 0.5, a_RelBlockY + 0.5, BlockZ + 0.5); // 80 ticks to boom
|
||||
}
|
||||
|
@ -1139,7 +1117,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -1193,7 +1171,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_RAISED)
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F);
|
||||
}
|
||||
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
|
||||
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power);
|
||||
|
@ -1203,10 +1181,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F);
|
||||
}
|
||||
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;
|
||||
|
@ -1261,7 +1239,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_RAISED)
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F);
|
||||
}
|
||||
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
|
||||
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Power);
|
||||
|
@ -1271,10 +1249,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F);
|
||||
}
|
||||
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;
|
||||
|
@ -1328,7 +1306,7 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_RAISED)
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.5F);
|
||||
}
|
||||
m_Chunk->SetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
|
||||
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ);
|
||||
|
@ -1338,10 +1316,10 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_RelBlockX, int a_R
|
|||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
|
||||
{
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (int)((BlockX + 0.5) * 8.0), (int)((a_RelBlockY + 0.1) * 8.0), (int)((BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
|
||||
m_Chunk->BroadcastSoundEffect("random.click", (double)BlockX + 0.5, (double)a_RelBlockY + 0.1, (double)BlockZ + 0.5, 0.3F, 0.6F);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -1384,14 +1362,14 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
|
|||
{
|
||||
if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards)
|
||||
{
|
||||
// Other hook not facing in opposite direction
|
||||
// Other hook facing in opposite direction - circuit completed!
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 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);
|
||||
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
|
||||
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1399,7 +1377,7 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
|
|||
{
|
||||
// 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);
|
||||
WAKE_SIMULATOR_IF_DIRTY(m_Chunk, BlockX, a_RelBlockY, BlockZ);
|
||||
SetSourceUnpowered(BlockX, a_RelBlockY, BlockZ, m_Chunk);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1414,7 +1392,51 @@ void cIncrementalRedstoneSimulator::HandleTripwireHook(int a_RelBlockX, int a_Re
|
|||
{
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1482,13 +1504,14 @@ void cIncrementalRedstoneSimulator::HandleTripwire(int a_RelBlockX, int a_RelBlo
|
|||
|
||||
|
||||
|
||||
bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ)
|
||||
bool cIncrementalRedstoneSimulator::AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk)
|
||||
{
|
||||
// Torches want to access neighbour's data when on a wall, hence the extra chunk parameter
|
||||
|
||||
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
|
||||
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
|
||||
|
||||
PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(BlockX, BlockZ)->GetRedstoneSimulatorPoweredBlocksList(); // Torches want to access neighbour's data when on a wall
|
||||
for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
|
||||
for (PoweredBlocksList::const_iterator itr = a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->begin(); itr != a_Chunk->GetRedstoneSimulatorPoweredBlocksList()->end(); ++itr) // Check powered list
|
||||
{
|
||||
if (itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)))
|
||||
{
|
||||
|
@ -1691,8 +1714,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)
|
||||
{
|
||||
a_PowerLevel = 0;
|
||||
int BlockX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelBlockX;
|
||||
int BlockZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelBlockZ;
|
||||
int BlockX = m_Chunk->GetPosX() * cChunkDef::Width + a_RelBlockX;
|
||||
int BlockZ = m_Chunk->GetPosZ() * cChunkDef::Width + a_RelBlockZ;
|
||||
|
||||
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list
|
||||
{
|
||||
|
@ -1709,6 +1732,14 @@ bool cIncrementalRedstoneSimulator::IsWirePowered(int a_RelBlockX, int a_RelBloc
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1881,20 +1912,14 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl
|
|||
int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
|
||||
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
|
||||
|
||||
BLOCKTYPE Block = 0;
|
||||
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, Block))
|
||||
cChunk * Neighbour = m_Chunk->GetRelNeighborChunkAdjustCoords(a_RelBlockX, a_RelBlockZ); // Adjust coordinates for the later call using these values
|
||||
if ((Neighbour == NULL) || !Neighbour->IsValid())
|
||||
{
|
||||
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
|
||||
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)
|
||||
{
|
||||
if (
|
||||
itr->a_BlockPos.Equals(Vector3i(BlockX, a_RelBlockY, BlockZ)) &&
|
||||
|
@ -1907,16 +1932,33 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_RelBlockX, int a_RelBl
|
|||
}
|
||||
}
|
||||
|
||||
PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(SourceX, SourceZ)->GetRedstoneSimulatorPoweredBlocksList();
|
||||
for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list
|
||||
// No need to get neighbouring chunk as we can guarantee that when something is powering us, the entry will be in our chunk
|
||||
// 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 (
|
||||
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!
|
||||
return;
|
||||
BLOCKTYPE Block;
|
||||
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,26 +1989,17 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
|
|||
int SourceX = (m_Chunk->GetPosX() * cChunkDef::Width) + a_RelSourceX;
|
||||
int SourceZ = (m_Chunk->GetPosZ() * cChunkDef::Width) + a_RelSourceZ;
|
||||
|
||||
BLOCKTYPE DestBlock = 0;
|
||||
if (!m_Chunk->UnboundedRelGetBlockType(a_RelBlockX, a_RelBlockY, a_RelBlockZ, DestBlock))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (DestBlock == E_BLOCK_AIR)
|
||||
{
|
||||
// Don't set air, fixes some bugs (wires powering themselves)
|
||||
return;
|
||||
}
|
||||
if ((DestBlock == E_BLOCK_REDSTONE_WIRE) && (m_Chunk->GetBlock(a_RelSourceX, a_RelSourceY, a_RelSourceZ) == E_BLOCK_REDSTONE_WIRE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!IsViableMiddleBlock(a_MiddleBlock))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cChunk * Neighbour = m_Chunk->GetNeighborChunk(BlockX, BlockZ);
|
||||
if ((Neighbour == NULL) || !Neighbour->IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedBlocksList * Linked = Neighbour->GetRedstoneSimulatorLinkedBlocksList();
|
||||
for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
|
||||
{
|
||||
|
@ -2066,6 +2099,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)
|
||||
{
|
||||
int Dir = REDSTONE_NONE;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
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 ====== */
|
||||
|
@ -114,8 +116,6 @@ private:
|
|||
void HandleRedstoneWire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
|
||||
/** Handles repeaters */
|
||||
void HandleRedstoneRepeater(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
|
||||
/** Handles delayed updates to Repeaters **/
|
||||
void HandleRedstoneRepeaterDelays();
|
||||
/* ====================== */
|
||||
|
||||
/* ====== DEVICES ====== */
|
||||
|
@ -156,11 +156,15 @@ private:
|
|||
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 */
|
||||
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 */
|
||||
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, m_Chunk) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ); }
|
||||
/** Returns if a coordinate is in the directly powered blocks list */
|
||||
bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
|
||||
bool AreCoordsDirectlyPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk);
|
||||
/** Returns if a coordinate is in the indirectly powered blocks list */
|
||||
bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
|
||||
/** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
|
||||
|
@ -174,7 +178,8 @@ private:
|
|||
/** Returns if a wire is powered
|
||||
The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */
|
||||
bool IsWirePowered(int a_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 */
|
||||
bool IsLeverOn(NIBBLETYPE a_BlockMeta);
|
||||
|
@ -186,7 +191,9 @@ private:
|
|||
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
|
||||
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)
|
||||
{
|
||||
switch (Block)
|
||||
|
@ -209,6 +216,7 @@ private:
|
|||
case E_BLOCK_REDSTONE_REPEATER_OFF:
|
||||
case E_BLOCK_REDSTONE_REPEATER_ON:
|
||||
case E_BLOCK_POWERED_RAIL:
|
||||
case E_BLOCK_REDSTONE_WIRE:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -235,6 +243,7 @@ private:
|
|||
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
|
||||
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -277,6 +286,7 @@ private:
|
|||
case E_BLOCK_STONE_PRESSURE_PLATE:
|
||||
case E_BLOCK_TNT:
|
||||
case E_BLOCK_TRAPDOOR:
|
||||
case E_BLOCK_TRAPPED_CHEST:
|
||||
case E_BLOCK_TRIPWIRE_HOOK:
|
||||
case E_BLOCK_TRIPWIRE:
|
||||
case E_BLOCK_WOODEN_BUTTON:
|
||||
|
@ -289,6 +299,16 @@ private:
|
|||
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)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ void cVaporizeFluidSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ,
|
|||
)
|
||||
{
|
||||
a_Chunk->SetBlock(RelX, a_BlockY, RelZ, E_BLOCK_AIR, 0);
|
||||
a_Chunk->BroadcastSoundEffect("random.fizz", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 1.0f, 0.6f);
|
||||
a_Chunk->BroadcastSoundEffect("random.fizz", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -905,21 +905,23 @@ void cEnchantingWindow::GetBlockPos(int & a_PosX, int & a_PosY, int & a_PosZ)
|
|||
// cChestWindow:
|
||||
|
||||
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_BlockX(a_Chest->GetPosX()),
|
||||
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 cSlotAreaInventory(*this));
|
||||
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
|
||||
|
||||
// Play the opening sound:
|
||||
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
|
||||
m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
|
||||
|
||||
// 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) :
|
||||
cWindow(wtChest, "Double Chest"),
|
||||
cWindow(wtChest, (a_PrimaryChest->GetBlockType() == E_BLOCK_CHEST) ? "Double Chest" : "Double Trapped Chest"),
|
||||
m_World(a_PrimaryChest->GetWorld()),
|
||||
m_BlockX(a_PrimaryChest->GetPosX()),
|
||||
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 cSlotAreaInventory(*this));
|
||||
|
@ -940,10 +944,55 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
|
|||
m_ShouldDistributeToHotbarFirst = false;
|
||||
|
||||
// Play the opening sound:
|
||||
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
|
||||
m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
|
||||
|
||||
// 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,9 +1002,9 @@ cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_Secon
|
|||
cChestWindow::~cChestWindow()
|
||||
{
|
||||
// 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", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -966,7 +1015,7 @@ cChestWindow::~cChestWindow()
|
|||
// cDropSpenserWindow:
|
||||
|
||||
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_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this));
|
||||
|
@ -993,7 +1042,7 @@ cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
|
|||
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
|
||||
|
||||
// Play the opening sound:
|
||||
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
|
||||
m_World->BroadcastSoundEffect("random.chestopen", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
|
||||
|
||||
// Send out the chest-open packet:
|
||||
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
|
||||
|
@ -1009,7 +1058,7 @@ cEnderChestWindow::~cEnderChestWindow()
|
|||
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
|
||||
|
||||
// Play the closing sound
|
||||
m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
|
||||
m_World->BroadcastSoundEffect("random.chestclosed", (double)m_BlockX, (double)m_BlockY, (double)m_BlockZ, 1, 1);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ public:
|
|||
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
|
||||
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse);
|
||||
|
@ -327,10 +327,15 @@ public:
|
|||
cChestWindow(cChestEntity * a_Chest);
|
||||
cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest);
|
||||
~cChestWindow();
|
||||
|
||||
virtual bool ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) override;
|
||||
virtual void OpenedByPlayer(cPlayer & a_Player) override;
|
||||
|
||||
protected:
|
||||
cWorld * m_World;
|
||||
int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet
|
||||
cChestEntity * m_PrimaryChest;
|
||||
cChestEntity * m_SecondaryChest;
|
||||
} ;
|
||||
|
||||
|
||||
|
|
|
@ -389,8 +389,8 @@ void cWorld::InitializeSpawn(void)
|
|||
IniFile.WriteFile(m_IniFileName);
|
||||
}
|
||||
|
||||
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
|
||||
BlockToChunk((int)m_SpawnX, (int)m_SpawnY, (int)m_SpawnZ, ChunkX, ChunkY, ChunkZ);
|
||||
int ChunkX = 0, ChunkZ = 0;
|
||||
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:
|
||||
#if defined(_DEBUG) || defined(ANDROID_NDK)
|
||||
|
@ -1088,7 +1088,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
|||
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
|
||||
cVector3iArray BlocksAffected;
|
||||
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
||||
BroadcastSoundEffect("random.explode", (int)floor(a_BlockX * 8), (int)floor(a_BlockY * 8), (int)floor(a_BlockZ * 8), 1.0f, 0.6f);
|
||||
BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
|
||||
{
|
||||
cCSLock Lock(m_CSPlayers);
|
||||
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||
|
@ -2074,9 +2074,9 @@ void cWorld::BroadcastDisplayObjective(const AString & a_Objective, cScoreboard:
|
|||
|
||||
|
||||
|
||||
void cWorld::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
|
||||
void cWorld::BroadcastSoundEffect(const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude)
|
||||
{
|
||||
m_ChunkMap->BroadcastSoundEffect(a_SoundName, a_SrcX, a_SrcY, a_SrcZ, a_Volume, a_Pitch, a_Exclude);
|
||||
m_ChunkMap->BroadcastSoundEffect(a_SoundName, a_X, a_Y, a_Z, a_Volume, a_Pitch, a_Exclude);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -2989,7 +2998,7 @@ int cWorld::SpawnMobFinalize(cMonster * a_Monster)
|
|||
|
||||
|
||||
|
||||
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed)
|
||||
int cWorld::CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed)
|
||||
{
|
||||
cProjectileEntity * Projectile = cProjectileEntity::Create(a_Kind, a_Creator, a_PosX, a_PosY, a_PosZ, a_Item, a_Speed);
|
||||
if (Projectile == NULL)
|
||||
|
|
19
src/World.h
19
src/World.h
|
@ -224,7 +224,7 @@ public:
|
|||
void BroadcastScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode);
|
||||
void BroadcastScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode);
|
||||
void BroadcastDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display);
|
||||
void BroadcastSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export a_Src coords are Block * 8
|
||||
void BroadcastSoundEffect (const AString & a_SoundName, double a_X, double a_Y, double a_Z, float a_Volume, float a_Pitch, const cClientHandle * a_Exclude = NULL); // tolua_export
|
||||
void BroadcastSoundParticleEffect (int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data, const cClientHandle * a_Exclude = NULL); // tolua_export
|
||||
void BroadcastSpawnEntity (cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||
void BroadcastTeleportEntity (const cEntity & a_Entity, const cClientHandle * a_Exclude = NULL);
|
||||
|
@ -241,7 +241,8 @@ public:
|
|||
/** 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 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 MarkChunkSaved (int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
|
@ -634,18 +635,6 @@ public:
|
|||
|
||||
// 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 */
|
||||
void SaveAllChunks(void);
|
||||
|
||||
|
@ -762,7 +751,7 @@ public:
|
|||
/** Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
|
||||
Item parameter used currently for Fireworks to correctly set entity metadata based on item metadata
|
||||
*/
|
||||
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem & a_Item, const Vector3d * a_Speed = NULL); // tolua_export
|
||||
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const cItem * a_Item, const Vector3d * a_Speed = NULL); // tolua_export
|
||||
|
||||
/** Returns a random number from the m_TickRand in range [0 .. a_Range]. To be used only in the tick thread! */
|
||||
int GetTickRandomNumber(unsigned a_Range) { return (int)(m_TickRand.randInt(a_Range)); }
|
||||
|
|
|
@ -176,10 +176,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("");
|
||||
AddBasicTileEntity(a_Entity, "Chest");
|
||||
AddBasicTileEntity(a_Entity, (a_ChestType == E_BLOCK_CHEST) ? "Chest" : "TrappedChest");
|
||||
m_Writer.BeginList("Items", TAG_Compound);
|
||||
AddItemGrid(a_Entity->GetContents());
|
||||
m_Writer.EndList();
|
||||
|
@ -824,19 +824,21 @@ void cNBTChunkSerializer::BlockEntity(cBlockEntity * a_Entity)
|
|||
// Add tile-entity into NBT:
|
||||
switch (a_Entity->GetBlockType())
|
||||
{
|
||||
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity); break;
|
||||
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
|
||||
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
|
||||
case E_BLOCK_ENDER_CHEST: /* No need to be saved */ break;
|
||||
case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
|
||||
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
|
||||
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
|
||||
case E_BLOCK_SIGN_POST:
|
||||
case E_BLOCK_WALLSIGN: AddSignEntity ((cSignEntity *) a_Entity); break;
|
||||
case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break;
|
||||
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) a_Entity); break;
|
||||
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
|
||||
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *) a_Entity); break;
|
||||
case E_BLOCK_CHEST: AddChestEntity ((cChestEntity *) a_Entity, a_Entity->GetBlockType()); break;
|
||||
case E_BLOCK_COMMAND_BLOCK: AddCommandBlockEntity((cCommandBlockEntity *)a_Entity); break;
|
||||
case E_BLOCK_DISPENSER: AddDispenserEntity ((cDispenserEntity *) a_Entity); break;
|
||||
case E_BLOCK_DROPPER: AddDropperEntity ((cDropperEntity *) a_Entity); break;
|
||||
case E_BLOCK_ENDER_CHEST: /* No data to be saved */ break;
|
||||
case E_BLOCK_FLOWER_POT: AddFlowerPotEntity ((cFlowerPotEntity *) a_Entity); break;
|
||||
case E_BLOCK_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
|
||||
case E_BLOCK_HEAD: AddMobHeadEntity ((cMobHeadEntity *) a_Entity); break;
|
||||
case E_BLOCK_HOPPER: AddHopperEntity ((cHopperEntity *) a_Entity); break;
|
||||
case E_BLOCK_JUKEBOX: AddJukeboxEntity ((cJukeboxEntity *) a_Entity); break;
|
||||
case E_BLOCK_LIT_FURNACE: AddFurnaceEntity ((cFurnaceEntity *) a_Entity); break;
|
||||
case E_BLOCK_NOTE_BLOCK: AddNoteEntity ((cNoteEntity *) 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:
|
||||
{
|
||||
|
|
|
@ -93,7 +93,7 @@ protected:
|
|||
|
||||
// Block entities:
|
||||
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 AddDropperEntity (cDropperEntity * a_Entity);
|
||||
void AddFurnaceEntity (cFurnaceEntity * a_Furnace);
|
||||
|
|
|
@ -583,7 +583,7 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
|
|||
}
|
||||
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)
|
||||
{
|
||||
|
@ -625,6 +625,10 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
|
|||
{
|
||||
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
|
||||
} // for Child - tag children
|
||||
}
|
||||
|
@ -741,7 +745,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);
|
||||
int x, y, z;
|
||||
|
@ -754,7 +758,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
|
||||
}
|
||||
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);
|
||||
a_BlockEntities.push_back(Chest.release());
|
||||
}
|
||||
|
@ -2110,10 +2114,11 @@ void cWSSAnvil::LoadPigFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NB
|
|||
void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
|
||||
{
|
||||
int ColorIdx = a_NBT.FindChildByName(a_TagIdx, "Color");
|
||||
|
||||
if (ColorIdx < 0) { return; }
|
||||
|
||||
int Color = (int)a_NBT.GetByte(ColorIdx);
|
||||
int Color = -1;
|
||||
if (ColorIdx > 0)
|
||||
{
|
||||
Color = (int)a_NBT.GetByte(ColorIdx);
|
||||
}
|
||||
|
||||
std::auto_ptr<cSheep> Monster(new cSheep(Color));
|
||||
if (!LoadEntityBaseFromNBT(*Monster.get(), a_NBT, a_TagIdx))
|
||||
|
@ -2126,6 +2131,12 @@ void cWSSAnvil::LoadSheepFromNBT(cEntityList & a_Entities, const cParsedNBT & a_
|
|||
return;
|
||||
}
|
||||
|
||||
int ShearedIdx = a_NBT.FindChildByName(a_TagIdx, "Sheared");
|
||||
if (ShearedIdx > 0)
|
||||
{
|
||||
Monster->SetSheared(a_NBT.GetByte(ShearedIdx) != 0);
|
||||
}
|
||||
|
||||
a_Entities.push_back(Monster.release());
|
||||
}
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ protected:
|
|||
*/
|
||||
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 LoadDropperFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
void LoadFlowerPotFromNBT (cBlockEntityList & a_BlockEntities, const cParsedNBT & a_NBT, int a_TagIdx);
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
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))
|
||||
{
|
||||
LOGWARNING("ERROR READING CHEST FROM JSON!" );
|
||||
|
|
Loading…
Reference in New Issue