1
0

Reorganised the redstone simulator

-> Many thanks to @worktycho for the idea, and @Haxi52 for the implementation plan!
* Uses classes and inheritance now
* Speed should be improved
This commit is contained in:
Tiger Wang 2015-06-26 17:24:51 -05:00
parent dae27fa9ec
commit 5b62c4c314
55 changed files with 2337 additions and 3122 deletions

View File

@ -42,7 +42,6 @@ SET (HDRS
MobHeadEntity.h
MobSpawnerEntity.h
NoteEntity.h
RedstonePoweredEntity.h
SignEntity.h
)

View File

@ -20,7 +20,6 @@
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
m_ShouldExecute(false),
m_IsPowered(false),
m_Result(0)
{}
@ -113,19 +112,6 @@ void cCommandBlockEntity::Activate(void)
void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered)
{
if (a_IsPowered && !m_IsPowered)
{
Activate();
}
m_IsPowered = a_IsPowered;
}
bool cCommandBlockEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);

View File

@ -10,7 +10,6 @@
#pragma once
#include "BlockEntity.h"
#include "RedstonePoweredEntity.h"
@ -19,8 +18,7 @@
// tolua_begin
class cCommandBlockEntity :
public cBlockEntity,
public cRedstonePoweredEntity
public cBlockEntity
{
typedef cBlockEntity super;
@ -43,9 +41,6 @@ public:
// tolua_begin
/** Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate */
virtual void SetRedstonePower(bool a_IsPowered) override;
/** Sets the command block to execute a command in the next tick */
void Activate(void);
@ -69,7 +64,6 @@ private:
void Execute();
bool m_ShouldExecute;
bool m_IsPowered;
AString m_Command;

View File

@ -17,8 +17,7 @@
cDropSpenserEntity::cDropSpenserEntity(BLOCKTYPE a_BlockType, int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(a_BlockType, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World),
m_ShouldDropSpense(false),
m_IsPowered(false)
m_ShouldDropSpense(false)
{
}
@ -114,19 +113,6 @@ void cDropSpenserEntity::Activate(void)
void cDropSpenserEntity::SetRedstonePower(bool a_IsPowered)
{
if (a_IsPowered && !m_IsPowered)
{
Activate();
}
m_IsPowered = a_IsPowered;
}
bool cDropSpenserEntity::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
UNUSED(a_Dt);

View File

@ -11,7 +11,6 @@
#pragma once
#include "BlockEntityWithItems.h"
#include "RedstonePoweredEntity.h"
@ -26,9 +25,6 @@ class cClientHandle;
// tolua_begin
class cDropSpenserEntity :
public cBlockEntityWithItems
// tolua_end
, public cRedstonePoweredEntity
// tolua_begin
{
typedef cBlockEntityWithItems super;
@ -61,12 +57,8 @@ public:
// tolua_end
/** Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate */
virtual void SetRedstonePower(bool a_IsPowered) override;
protected:
bool m_ShouldDropSpense; ///< If true, the dropspenser will dropspense an item in the next tick
bool m_IsPowered; ///< Set to true when the dropspenser receives redstone power.
/** Does the actual work on dropspensing an item. Chooses the slot, calls DropSpenseFromSlot() and handles smoke / sound effects */
void DropSpense(cChunk & a_Chunk);

View File

@ -44,7 +44,7 @@ void cNoteEntity::MakeSound(void)
{
// TODO: add other wood-based blocks if needed
instrument = E_INST_DOUBLE_BASS;
sampleName = "note.db";
sampleName = "note.bassattack";
break;
}
@ -76,7 +76,7 @@ void cNoteEntity::MakeSound(void)
{
// TODO: add other stone-based blocks if needed
instrument = E_INST_BASS_DRUM;
sampleName = "note.bassattack";
sampleName = "note.bd";
break;
}

View File

@ -2,7 +2,6 @@
#pragma once
#include "BlockEntity.h"
#include "RedstonePoweredEntity.h"
@ -25,9 +24,6 @@ enum ENUM_NOTE_INSTRUMENTS
class cNoteEntity :
public cBlockEntity
// tolua_end
, public cRedstonePoweredEntity
// tolua_begin
{
typedef cBlockEntity super;
public:
@ -52,14 +48,6 @@ public:
virtual bool UsedBy(cPlayer * a_Player) override;
virtual void SendTo(cClientHandle &) override {}
virtual void SetRedstonePower(bool a_Value) override
{
if (a_Value)
{
MakeSound();
}
}
private:
char m_Pitch;
} ; // tolua_export

View File

@ -1,30 +0,0 @@
// RedstonePoweredEntity.h
// Declares the cRedstonePoweredEntity class representing a mix-in for block entities that respond to redstone
#pragma once
/** Interface class representing a mix-in for block entities that respond to redstone */
class cRedstonePoweredEntity
{
public:
virtual ~cRedstonePoweredEntity() {}
/** Sets the internal redstone power flag to "on" or "off", depending on the parameter.
Calls Activate() if appropriate */
virtual void SetRedstonePower(bool a_IsPowered) = 0;
};

View File

@ -38,14 +38,18 @@ public:
a_WorldInterface.GetBroadcastManager().BroadcastSoundEffect("random.click", x, y, z, 0.5f, 0.6f);
// Queue a button reset (unpress)
int delay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30;
a_ChunkInterface.QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, (a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07), delay, m_BlockType, a_WorldInterface);
a_Player->GetWorld()->ScheduleTask(delay, [x, y, z](cWorld & a_World)
auto TickDelay = (m_BlockType == E_BLOCK_STONE_BUTTON) ? 20 : 30;
a_Player->GetWorld()->ScheduleTask(TickDelay, [x, y, z, a_BlockX, a_BlockY, a_BlockZ, this](cWorld & a_World)
{
if (a_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == m_BlockType)
{
// Block hasn't change in the meantime; set its meta
a_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, a_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x07);
a_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
a_World.BroadcastSoundEffect("random.click", x, y, z, 0.5f, 0.5f);
});
}
}
);
return true;
}
@ -129,6 +133,12 @@ public:
UNUSED(a_Meta);
return 0;
}
/** Extracts the ON bit from metadata and returns if true if it is set */
static bool IsButtonOn(NIBBLETYPE a_BlockMeta)
{
return ((a_BlockMeta & 0x8) == 0x8);
}
} ;

View File

@ -60,16 +60,17 @@ public:
return true;
}
inline static Vector3i GetSideCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool a_bInverse)
inline static Vector3i GetSideCoordinate(const Vector3i & a_Position, NIBBLETYPE a_Meta, bool a_bInverse)
{
auto Position = a_Position;
if (!a_bInverse)
{
switch (a_Meta)
{
case 0x0: a_BlockX++; break;
case 0x1: a_BlockZ--; break;
case 0x2: a_BlockX--; break;
case 0x3: a_BlockZ++; break;
case 0x0: Position.x++; break;
case 0x1: Position.z--; break;
case 0x2: Position.x--; break;
case 0x3: Position.z++; break;
default:
{
LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta);
@ -82,10 +83,10 @@ public:
{
switch (a_Meta)
{
case 0x0: a_BlockX--; break;
case 0x1: a_BlockZ++; break;
case 0x2: a_BlockX++; break;
case 0x3: a_BlockZ--; break;
case 0x0: Position.x--; break;
case 0x1: Position.z++; break;
case 0x2: Position.x++; break;
case 0x3: Position.z--; break;
default:
{
LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta);
@ -95,17 +96,18 @@ public:
}
}
return Vector3i(a_BlockX, a_BlockY, a_BlockZ);
return Position;
}
inline static Vector3i GetRearCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
inline static Vector3i GetRearCoordinate(const Vector3i & a_Position, NIBBLETYPE a_Meta)
{
auto Position = a_Position;
switch (a_Meta)
{
case 0x0: a_BlockZ++; break;
case 0x1: a_BlockX--; break;
case 0x2: a_BlockZ--; break;
case 0x3: a_BlockX++; break;
case 0x0: Position.z++; break;
case 0x1: Position.x--; break;
case 0x2: Position.z--; break;
case 0x3: Position.x++; break;
default:
{
LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta);
@ -114,17 +116,18 @@ public:
}
}
return Vector3i(a_BlockX, a_BlockY, a_BlockZ);
return Position;
}
inline static Vector3i GetFrontCoordinate(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta)
inline static Vector3i GetFrontCoordinate(const Vector3i & a_Position, NIBBLETYPE a_Meta)
{
auto Position = a_Position;
switch (a_Meta)
{
case 0x0: a_BlockZ--; break;
case 0x1: a_BlockX++; break;
case 0x2: a_BlockZ++; break;
case 0x3: a_BlockX--; break;
case 0x0: Position.z--; break;
case 0x1: Position.x++; break;
case 0x2: Position.z++; break;
case 0x3: Position.x--; break;
default:
{
LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta);
@ -133,7 +136,7 @@ public:
}
}
return Vector3i(a_BlockX, a_BlockY, a_BlockZ);
return Position;
}
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override

View File

@ -156,6 +156,12 @@ public:
UNUSED(a_Meta);
return 0;
}
/** Extracts the ON bit from metadata and returns if true if it is set */
static bool IsLeverOn(NIBBLETYPE a_BlockMeta)
{
return ((a_BlockMeta & 0x8) == 0x8);
}
} ;

View File

@ -65,7 +65,7 @@ public:
static eBlockFace MetaDataToDirection(NIBBLETYPE a_MetaData)
{
switch (a_MetaData)
switch (a_MetaData & 0x7) // We only want the bottom three bits (4th controls extended-ness))
{
case 0x0: return BLOCK_FACE_YM;
case 0x1: return BLOCK_FACE_YP;

View File

@ -73,10 +73,11 @@ public:
virtual void OnNeighborChanged(cChunkInterface & a_ChunkInterface, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_WhichNeighbor) override
{
NIBBLETYPE Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ) && (Meta != FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ)))
auto Meta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
auto NewMeta = FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ);
if (IsUnstable(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ) && (Meta != NewMeta))
{
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, FindMeta(a_ChunkInterface, a_BlockX, a_BlockY, a_BlockZ));
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, m_BlockType, (m_BlockType == E_BLOCK_RAIL) ? NewMeta : NewMeta | (Meta & 0x08));
}
}

View File

@ -110,6 +110,42 @@ public:
UNUSED(a_Meta);
return 11;
}
inline static Vector3i GetRearCoordinateOffset(NIBBLETYPE a_Meta)
{
switch (a_Meta & 0x3) // We only want the direction (bottom) bits
{
case 0x0: return {0, 0, 1};
case 0x1: return {-1, 0, 0};
case 0x2: return {0, 0, -1};
case 0x3: return {1, 0, 0};
default:
{
LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta);
ASSERT(!"Unknown metadata while determining orientation of repeater!");
return {0, 0, 0};
}
}
}
inline static Vector3i GetFrontCoordinateOffset(NIBBLETYPE a_Meta)
{
switch (a_Meta & 0x3) // We only want the direction (bottom) bits
{
case 0x0: return {0, 0, -1};
case 0x1: return {1, 0, 0};
case 0x2: return {0, 0, 1};
case 0x3: return {-1, 0, 0};
default:
{
LOGWARNING("%s: Unknown metadata: %d", __FUNCTION__, a_Meta);
ASSERT(!"Unknown metadata while determining orientation of repeater!");
return {0, 0, 0};
}
}
}
} ;

View File

@ -72,16 +72,6 @@ void cChunkInterface::SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIB
void cChunkInterface::QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay, BLOCKTYPE a_PreviousBlockType, cWorldInterface & a_WorldInterface)
{
m_ChunkMap->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_WorldInterface.GetWorldAge() + a_TickDelay, a_PreviousBlockType);
}
/** Sets the block at the specified coords to the specified value.
The replacement doesn't trigger block updates.
The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block)

View File

@ -29,8 +29,6 @@ public:
void SetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_MetaData);
void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay, BLOCKTYPE a_PreviousBlockType, cWorldInterface & a_WorldInterface);
/** Sets the block at the specified coords to the specified value.
The replacement doesn't trigger block updates.
The replaced blocks aren't checked for block entities (block entity is leaked if it exists at this block)

View File

@ -9,8 +9,8 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include
set(FOLDERS
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
WorldStorage Mobs Entities Simulator BlockEntities UI
Noise
WorldStorage Mobs Entities Simulator Simulator/IncrementalRedstoneSimulator
BlockEntities UI Noise
)
SET (SRCS
@ -366,7 +366,8 @@ if (NOT MSVC)
target_link_libraries(${EXECUTABLE}
OSSupport HTTPServer Bindings Items Blocks Noise
Protocol Generating WorldStorage
Mobs Entities Simulator BlockEntities UI PolarSSL++
Mobs Entities Simulator IncrementalRedstoneSimulator
BlockEntities UI PolarSSL++
)
endif ()
if (WIN32)

View File

@ -605,9 +605,6 @@ void cChunk::Tick(std::chrono::milliseconds a_Dt)
{
BroadcastPendingBlockChanges();
// Set all blocks that have been queued for setting later:
ProcessQueuedSetBlocks();
CheckBlocks();
// Tick simulators:
@ -726,50 +723,6 @@ void cChunk::MoveEntityToNewChunk(cEntity * a_Entity)
void cChunk::ProcessQueuedSetBlocks(void)
{
Int64 CurrTick = m_World->GetWorldAge();
for (sSetBlockQueueVector::iterator itr = m_SetBlockQueue.begin(); itr != m_SetBlockQueue.end();)
{
if (itr->m_Tick <= CurrTick)
{
if (itr->m_PreviousType != E_BLOCK_AIR) // PreviousType defaults to 0 if not specified
{
if (GetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ) == itr->m_PreviousType)
{
// Current world age is bigger than / equal to target world age - delay time reached AND
// Previous block type was the same as current block type (to prevent duplication)
SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta); // SetMeta doesn't send to client
itr = m_SetBlockQueue.erase(itr);
LOGD("Successfully set queued block - previous and current types matched");
}
else
{
itr = m_SetBlockQueue.erase(itr);
LOGD("Failure setting queued block - previous and current blocktypes didn't match");
}
}
else
{
// Current world age is bigger than / equal to target world age - delay time reached
SetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta);
itr = m_SetBlockQueue.erase(itr);
LOGD("Successfully set queued block - previous type ignored");
}
}
else
{
// Not yet
++itr;
continue;
}
} // for itr - m_SetBlockQueue[]
}
void cChunk::BroadcastPendingBlockChanges(void)
{
if (m_PendingSendBlocks.empty())
@ -1505,15 +1458,6 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
void cChunk::QueueSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType)
{
m_SetBlockQueue.push_back(sSetBlockQueueItem(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType));
}
void cChunk::QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ)
{
ASSERT (
@ -2221,46 +2165,6 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBloc
bool cChunk::DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS
for (cBlockEntityList::iterator itr = m_BlockEntities.begin(), itr2 = itr; itr != m_BlockEntities.end(); itr = itr2)
{
++itr2;
if (((*itr)->GetPosX() != a_BlockX) || ((*itr)->GetPosY() != a_BlockY) || ((*itr)->GetPosZ() != a_BlockZ))
{
continue;
}
switch ((*itr)->GetBlockType())
{
case E_BLOCK_DROPPER:
case E_BLOCK_DISPENSER:
case E_BLOCK_NOTE_BLOCK:
{
break;
}
default:
{
// 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;
}
}
if (a_Callback.Item(dynamic_cast<cRedstonePoweredEntity *>(*itr))) // Needs dynamic_cast due to multiple inheritance
{
return false;
}
return true;
} // for itr - m_BlockEntitites[]
// Not found:
return false;
}
bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback)
{
// The blockentity list is locked by the parent chunkmap's CS

View File

@ -7,7 +7,7 @@
#include "Simulator/FireSimulator.h"
#include "Simulator/SandSimulator.h"
#include "Simulator/IncrementalRedstoneSimulator.h"
#include "Simulator/RedstoneSimulator.h"
#include "Blocks/GetHandlerCompileTimeTemplate.h"
@ -49,7 +49,6 @@ class cBlockArea;
class cFluidSimulatorData;
class cMobCensus;
class cMobSpawner;
class cRedstonePoweredEntity;
class cSetChunkData;
typedef std::list<cClientHandle *> cClientHandleList;
@ -63,7 +62,6 @@ typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
typedef cItemCallback<cRedstonePoweredEntity> cRedstonePoweredCallback;
@ -176,9 +174,6 @@ public:
// SetBlock() does a lot of work (heightmap, tickblocks, blockentities) so a BlockIdx version doesn't make sense
void SetBlock( const Vector3i & a_RelBlockPos, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) { SetBlock( a_RelBlockPos.x, a_RelBlockPos.y, a_RelBlockPos.z, a_BlockType, a_BlockMeta); }
/** Queues a block change till the specified world tick */
void QueueSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, Int64 a_Tick, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR);
/** Queues block for ticking (m_ToTickQueue) */
void QueueTickBlock(int a_RelX, int a_RelY, int a_RelZ);
@ -279,8 +274,6 @@ public:
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible
/** Calls the callback for the redstone powered entity at the specified coords; returns false if there's no redstone powered entity at those coords, true if found */
bool DoWithRedstonePoweredEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cRedstonePoweredCallback & a_Callback);
/** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible
@ -489,8 +482,6 @@ private:
std::vector<Vector3i> m_ToTickBlocks;
sSetBlockVector m_PendingSendBlocks; ///< Blocks that have changed and need to be sent to all clients
sSetBlockQueueVector m_SetBlockQueue; ///< Block changes that are queued to a specific tick
// A critical section is not needed, because all chunk access is protected by its parent ChunkMap's csLayers
std::vector<cClientHandle *> m_LoadedByClient;
cEntityList m_Entities;
@ -569,9 +560,6 @@ private:
/** Called by Tick() when an entity moves out of this chunk into a neighbor; moves the entity and sends spawn / despawn packet to clients */
void MoveEntityToNewChunk(cEntity * a_Entity);
/** Processes all blocks that have been scheduled for replacement by the QueueSetBlock() function */
void ProcessQueuedSetBlocks(void);
};
typedef cChunk * cChunkPtr;

View File

@ -1099,58 +1099,6 @@ bool cChunkMap::TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height)
void cChunkMap::FastSetBlocks(sSetBlockList & a_BlockList)
{
sSetBlockList Failed;
// Process all items from a_BlockList, either successfully or by placing into Failed
while (!a_BlockList.empty())
{
int ChunkX = a_BlockList.front().m_ChunkX;
int ChunkZ = a_BlockList.front().m_ChunkZ;
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid())
{
for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();)
{
if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{
Chunk->FastSetBlock(itr->m_RelX, itr->m_RelY, itr->m_RelZ, itr->m_BlockType, itr->m_BlockMeta);
itr = a_BlockList.erase(itr);
}
else
{
++itr;
}
} // for itr - a_BlockList[]
}
else
{
// The chunk is not valid, move all blocks within this chunk to Failed
for (sSetBlockList::iterator itr = a_BlockList.begin(); itr != a_BlockList.end();)
{
if ((itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{
Failed.push_back(*itr);
itr = a_BlockList.erase(itr);
}
else
{
++itr;
}
} // for itr - a_BlockList[]
}
}
// Return the failed:
std::swap(Failed, a_BlockList);
}
void cChunkMap::SetBlocks(const sSetBlockVector & a_Blocks)
{
cCSLock lock(m_CSLayers);
@ -1212,19 +1160,7 @@ BLOCKTYPE cChunkMap::GetBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
// First check if it isn't queued in the m_FastSetBlockQueue:
{
cCSLock Lock(m_CSFastSetBlock);
for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr)
{
if ((itr->m_RelX == X) && (itr->m_RelY == Y) && (itr->m_RelZ == Z) && (itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{
return itr->m_BlockType;
}
} // for itr - m_FastSetBlockQueue[]
}
// Not in the queue, query the chunk, if loaded:
// Query the chunk, if loaded:
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid())
@ -1244,19 +1180,7 @@ NIBBLETYPE cChunkMap::GetBlockMeta(int a_BlockX, int a_BlockY, int a_BlockZ)
int ChunkX, ChunkZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
// First check if it isn't queued in the m_FastSetBlockQueue:
{
cCSLock Lock(m_CSFastSetBlock);
for (sSetBlockList::iterator itr = m_FastSetBlockQueue.begin(); itr != m_FastSetBlockQueue.end(); ++itr)
{
if ((itr->m_RelX == X) && (itr->m_RelY == Y) && (itr->m_RelZ == Z) && (itr->m_ChunkX == ChunkX) && (itr->m_ChunkZ == ChunkZ))
{
return itr->m_BlockMeta;
}
} // for itr - m_FastSetBlockQueue[]
}
// Not in the queue, query the chunk, if loaded:
// Query the chunk, if loaded:
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid())
@ -1346,23 +1270,6 @@ void cChunkMap::SetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_B
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);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid())
{
Chunk->QueueSetBlock(X, Y, Z, a_BlockType, a_BlockMeta, a_Tick, a_PreviousBlockType);
}
}
bool cChunkMap::GetBlockTypeMeta(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta)
{
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
@ -3187,28 +3094,14 @@ void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
void cChunkMap::FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
{
cCSLock Lock(m_CSFastSetBlock);
m_FastSetBlockQueue.push_back(sSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta));
}
int ChunkX, ChunkZ, X = a_BlockX, Y = a_BlockY, Z = a_BlockZ;
cChunkDef::AbsoluteToRelative(X, Y, Z, ChunkX, ChunkZ);
void cChunkMap::FastSetQueuedBlocks()
{
// Asynchronously set blocks:
sSetBlockList FastSetBlockQueueCopy;
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunk(ChunkX, ChunkZ);
if ((Chunk != nullptr) && Chunk->IsValid())
{
cCSLock Lock(m_CSFastSetBlock);
std::swap(FastSetBlockQueueCopy, m_FastSetBlockQueue);
}
this->FastSetBlocks(FastSetBlockQueueCopy);
if (!FastSetBlockQueueCopy.empty())
{
// Some blocks failed, store them for next tick:
cCSLock Lock(m_CSFastSetBlock);
m_FastSetBlockQueue.splice(m_FastSetBlockQueue.end(), FastSetBlockQueueCopy);
Chunk->FastSetBlock(X, Y, Z, a_BlockType, a_BlockMeta);
}
}

View File

@ -148,9 +148,6 @@ public:
bool TryGetHeight (int a_BlockX, int a_BlockZ, int & a_Height); // Returns false if chunk not loaded / generated
void FastSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta);
void FastSetQueuedBlocks();
void FastSetBlocks(sSetBlockList & a_BlockList);
/** Performs the specified single-block set operations simultaneously, as if SetBlock() was called for each item.
Is more efficient than calling SetBlock() multiple times.
If the chunk for any of the blocks is not loaded, the set operation is ignored silently. */
@ -164,7 +161,6 @@ public:
NIBBLETYPE GetBlockBlockLight(int a_BlockX, int a_BlockY, int a_BlockZ);
void SetBlockMeta (int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_BlockMeta);
void SetBlock (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);
@ -516,9 +512,6 @@ private:
cWorld * m_World;
cCriticalSection m_CSFastSetBlock;
sSetBlockList m_FastSetBlockQueue;
/** The cChunkStay descendants that are currently enabled in this chunkmap */
cChunkStays m_ChunkStays;

View File

@ -927,6 +927,12 @@ void cClientHandle::HandleBeaconSelection(int a_PrimaryEffect, int a_SecondaryEf
void cClientHandle::HandleCommandBlockBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_NewCommand)
{
if (a_NewCommand.empty())
{
Kick("Command block string unexpectedly empty - hacked client?");
return;
}
cWorld * World = m_Player->GetWorld();
if (World->AreCommandBlocksEnabled())
{

View File

@ -9,7 +9,6 @@ SET (SRCS
FireSimulator.cpp
FloodyFluidSimulator.cpp
FluidSimulator.cpp
IncrementalRedstoneSimulator.cpp
SandSimulator.cpp
Simulator.cpp
SimulatorManager.cpp
@ -21,7 +20,6 @@ SET (HDRS
FireSimulator.h
FloodyFluidSimulator.h
FluidSimulator.h
IncrementalRedstoneSimulator.h
NoopFluidSimulator.h
NoopRedstoneSimulator.h
RedstoneSimulator.h
@ -35,7 +33,6 @@ SET (HDRS
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set_source_files_properties(FireSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion")
set_source_files_properties(FluidSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=sign-conversion -Wno-error=shadow")
set_source_files_properties(IncrementalRedstoneSimulator.cpp PROPERTIES COMPILE_FLAGS "-Wno-error=conversion ")
endif()
if(NOT MSVC)

File diff suppressed because it is too large Load Diff

View File

@ -1,419 +0,0 @@
#pragma once
#include "RedstoneSimulator.h"
#include "BlockEntities/RedstonePoweredEntity.h"
#include <unordered_map>
class cWorld;
class cChunk;
typedef cItemCallback<cRedstonePoweredEntity> cRedstonePoweredCallback;
class cIncrementalRedstoneSimulator :
public cRedstoneSimulator
{
typedef cRedstoneSimulator super;
public:
cIncrementalRedstoneSimulator(cWorld & a_World)
: cRedstoneSimulator(a_World),
m_Chunk(nullptr)
{
}
virtual cRedstoneSimulatorChunkData * CreateChunkData() override
{
return new cIncrementalRedstoneSimulatorChunkData;
}
virtual void Simulate(float a_Dt) override { UNUSED(a_Dt); } // not used
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override;
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override { return IsRedstone(a_BlockType); }
virtual void WakeUp(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
private:
#define MAX_POWER_LEVEL 15
struct sPoweredBlocks // Define structure of the directly powered blocks list
{
sPoweredBlocks(Vector3i a_BlockPos, Vector3i a_SourcePos, unsigned char a_PowerLevel) :
m_BlockPos(a_BlockPos),
m_SourcePos(a_SourcePos),
m_PowerLevel(a_PowerLevel)
{
}
Vector3i m_BlockPos; // Position of powered block
Vector3i m_SourcePos; // Position of source powering the block at a_BlockPos
unsigned char m_PowerLevel;
};
struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
{
Vector3i a_BlockPos;
Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination
Vector3i a_SourcePos;
unsigned char a_PowerLevel;
};
struct sRepeatersDelayList // Define structure of list containing repeaters' delay states
{
unsigned char a_DelayTicks; // For how many ticks should the repeater delay
unsigned char a_ElapsedTicks; // How much of the previous has been elapsed?
bool ShouldPowerOn; // What happens when the delay time is fulfilled?
};
/** Per-chunk data for the simulator, specified individual chunks to simulate */
class cIncrementalRedstoneSimulatorChunkData :
public cRedstoneSimulatorChunkData
{
public:
/** test */
std::unordered_map<Vector3i, std::pair<BLOCKTYPE, bool>, VectorHasher<int>> m_ChunkData;
std::vector<sPoweredBlocks> m_PoweredBlocks;
std::vector<sLinkedPoweredBlocks> m_LinkedBlocks;
std::unordered_map<Vector3i, bool, VectorHasher<int>> m_SimulatedPlayerToggleableBlocks;
std::unordered_map<Vector3i, sRepeatersDelayList, VectorHasher<int>> m_RepeatersDelayList;
};
public:
typedef std::vector <sPoweredBlocks> PoweredBlocksList;
typedef std::vector <sLinkedPoweredBlocks> LinkedBlocksList;
typedef std::unordered_map<Vector3i, bool, VectorHasher<int>> SimulatedPlayerToggleableList;
typedef std::unordered_map<Vector3i, sRepeatersDelayList, VectorHasher<int>> RepeatersDelayList;
private:
cIncrementalRedstoneSimulatorChunkData * m_RedstoneSimulatorChunkData;
PoweredBlocksList * m_PoweredBlocks;
LinkedBlocksList * m_LinkedPoweredBlocks;
SimulatedPlayerToggleableList * m_SimulatedPlayerToggleableBlocks;
RepeatersDelayList * m_RepeatersDelayList;
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override;
void AddBlock(const Vector3i & a_BlockPosition, cChunk * a_Chunk, cChunk * a_OtherChunk = nullptr);
cChunk * m_Chunk;
// We want a_MyState for devices needing a full FastSetBlock (as opposed to meta) because with our simulation model, we cannot keep setting the block if it is already set correctly
// In addition to being non-performant, it would stop the player from actually breaking said device
/** Handles the redstone torch */
void HandleRedstoneTorch(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles the redstone block */
void HandleRedstoneBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles levers */
void HandleRedstoneLever(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles buttons */
void HandleRedstoneButton(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles daylight sensors */
void HandleDaylightSensor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles pressure plates */
void HandlePressurePlate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
/** Handles tripwire hooks
Performs correct meta and power setting for self by going in the direction it faces and looking for a continous line of tripwire bounded by another oppositely facing hook
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);
/** Handles redstone wire */
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 comparators */
void HandleRedstoneComparator(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles pistons */
void HandlePiston(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles dispensers and droppers */
void HandleDropSpenser(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles TNT (exploding) */
void HandleTNT(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles redstone lamps */
void HandleRedstoneLamp(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyState);
/** Handles doords */
void HandleDoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles command blocks */
void HandleCommandBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles activator, detector, and powered rails */
void HandleRail(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, BLOCKTYPE a_MyType);
/** Handles trapdoors */
void HandleTrapdoor(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles fence gates */
void HandleFenceGate(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles noteblocks */
void HandleNoteBlock(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Handles tripwires */
void HandleTripwire(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ);
/** Marks a block as powered */
void SetBlockPowered(Vector3i a_RelBlockPosition, Vector3i a_RelSourcePosition, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
void SetBlockPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, unsigned char a_PowerLevel = MAX_POWER_LEVEL) { SetBlockPowered(Vector3i(a_RelBlockX, a_RelBlockY, a_RelBlockZ), Vector3i(a_RelSourceX, a_RelSourceY, a_RelSourceZ), a_PowerLevel); }
/** Recursively searches for a wire path and powers everything that should be powered */
void FindAndPowerBorderingWires(std::vector<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const Vector3i & a_EntryRelBlockPosition, cChunk * a_EntryChunk);
/** Powers a specified wire block position with the specified source wire position
Checks are performed to ensure one wire does not power the same location more than once
a_EntryChunk will be the chunk which the source resides, and a_NeighbourChunk will be that which the to-be-powered wire resides
a_PotentialWireList is updated to include the new powered wire so that FindAndPowerBorderingWires can continue the redstone wire line tracing process
*/
void PowerBorderingWires(std::vector<std::pair<Vector3i, cChunk *>> & a_PotentialWireList, const Vector3i & a_EntryRelSourcePosition, cChunk * a_EntryChunk, const Vector3i & a_AdjustedPos, cChunk * a_NeighbourChunk, unsigned char a_MyPower);
/** Marks a block as being powered through another block */
void SetBlockLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
void SetPlayerToggleableBlockAsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool WasLastStatePowered);
/** Marks the second block in a direction as linked powered */
void SetDirectionLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, char a_Direction, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
/** Marks all blocks immediately surrounding a coordinate as powered */
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 */
void QueueRepeaterPowerChange(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
/** Removes a block from the Powered and LinkedPowered lists
Recursively removes all blocks powered by the given one
*/
void SetSourceUnpowered(int a_RelSourceX, int a_RelSourceY, int a_RelSourceZ, cChunk * a_Chunk);
void SetInvalidMiddleBlock(int a_RelMiddleX, int a_RelMiddleY, int a_RelMiddleZ, cChunk * a_Chunk);
/** 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, m_Chunk) || AreCoordsLinkedPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, m_Chunk); }
/** Returns if a coordinate is in the directly powered blocks list */
static 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 */
static bool AreCoordsLinkedPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, cChunk * a_Chunk);
/** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
bool AreCoordsSimulated(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, bool IsCurrentStatePowered);
/** Returns if a repeater is powered by testing for power sources behind the repeater */
bool IsRepeaterPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
/** Returns if a repeater is locked */
bool IsRepeaterLocked(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
/** Returns if a piston is powered */
bool IsPistonPowered(int a_RelBlockX, int a_RelBlockY, int a_RelBlockZ, NIBBLETYPE a_Meta);
/** Returns if a wire is powered
The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */
static unsigned char IsWirePowered(Vector3i a_RelBlockPosition, cChunk * a_Chunk);
/** Handles delayed updates to repeaters */
void HandleRedstoneRepeaterDelays(void);
/** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta);
/** Returns if button metadata marks it as emitting power */
bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); }
/** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
inline static bool IsViableMiddleBlock(BLOCKTYPE a_Block) { return cBlockInfo::FullyOccupiesVoxel(a_Block); }
/** 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 a_Block)
{
switch (a_Block)
{
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_ACACIA_FENCE_GATE:
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_BIRCH_FENCE_GATE:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DARK_OAK_DOOR:
case E_BLOCK_DARK_OAK_FENCE_GATE:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_OAK_FENCE_GATE:
case E_BLOCK_HOPPER:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_IRON_DOOR:
case E_BLOCK_IRON_TRAPDOOR:
case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_JUNGLE_FENCE_GATE:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_PISTON:
case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_WIRE:
case E_BLOCK_SPRUCE_DOOR:
case E_BLOCK_SPRUCE_FENCE_GATE:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_TNT:
case E_BLOCK_TRAPDOOR:
case E_BLOCK_OAK_DOOR:
{
return true;
}
default: return false;
}
}
/** Returns if a block has the potential to output power */
inline static bool IsPotentialSource(BLOCKTYPE a_Block)
{
switch (a_Block)
{
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_WOODEN_BUTTON:
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_REDSTONE_WIRE:
case E_BLOCK_REDSTONE_TORCH_ON:
case E_BLOCK_LEVER:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_BLOCK_OF_REDSTONE:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
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;
}
default: return false;
}
}
/** Returns if a block is any sort of redstone device */
inline static bool IsRedstone(BLOCKTYPE a_Block)
{
switch (a_Block)
{
// All redstone devices, please alpha sort
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_ACACIA_FENCE_GATE:
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_BIRCH_FENCE_GATE:
case E_BLOCK_BLOCK_OF_REDSTONE:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DARK_OAK_DOOR:
case E_BLOCK_DARK_OAK_FENCE_GATE:
case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_OAK_FENCE_GATE:
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_HOPPER:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_IRON_DOOR:
case E_BLOCK_IRON_TRAPDOOR:
case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_JUNGLE_FENCE_GATE:
case E_BLOCK_LEVER:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
case E_BLOCK_REDSTONE_WIRE:
case E_BLOCK_SPRUCE_DOOR:
case E_BLOCK_SPRUCE_FENCE_GATE:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_STONE_BUTTON:
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:
case E_BLOCK_OAK_DOOR:
case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_PISTON:
{
return true;
}
default: return false;
}
}
inline static bool DoesIgnorePlayerToggle(BLOCKTYPE a_Block)
{
switch (a_Block)
{
case E_BLOCK_ACACIA_FENCE_GATE:
case E_BLOCK_BIRCH_FENCE_GATE:
case E_BLOCK_DARK_OAK_FENCE_GATE:
case E_BLOCK_OAK_FENCE_GATE:
case E_BLOCK_JUNGLE_FENCE_GATE:
case E_BLOCK_SPRUCE_FENCE_GATE:
case E_BLOCK_IRON_TRAPDOOR:
case E_BLOCK_TRAPDOOR:
{
return true;
}
default: return false;
}
}
inline static std::vector<cChunk *> GetAdjacentChunks(const Vector3i & a_RelBlockPosition, cChunk * a_Chunk);
inline static Vector3i AdjustRelativeCoords(const Vector3i & a_RelPosition)
{
return { (a_RelPosition.x % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width, a_RelPosition.y, (a_RelPosition.z % cChunkDef::Width + cChunkDef::Width) % cChunkDef::Width };
}
};

View File

@ -0,0 +1,38 @@
cmake_minimum_required (VERSION 2.6)
project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../")
set (SRCS
IncrementalRedstoneSimulator.cpp
)
set (HDRS
CommandBlockHandler.h
DoorHandler.h
DropSpenserHandler.h
IncrementalRedstoneSimulator.h
RedstoneHandler.h
RedstoneSimulatorChunkData.h
SolidBlockHandler.h
RedstoneComparatorHandler.h
RedstoneRepeaterHandler.h
RedstoneBlockHandler.h
RedstoneTorchHandler.h
RedstoneWireHandler.h
RedstoneLampHandler.h
RedstoneToggleHandler.h
PistonHandler.h
SmallGateHandler.h
NoteBlockHandler.h
TNTHandler.h
TrappedChestHandler.h
TripwireHookHandler.h
PoweredRailHandler.h
PressurePlateHandler.h
)
if(NOT MSVC)
add_library(IncrementalRedstoneSimulator ${SRCS} ${HDRS})
endif()

View File

@ -0,0 +1,70 @@
#pragma once
#include "RedstoneHandler.h"
#include "BlockEntities/CommandBlockEntity.h"
class cCommandBlockHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cCommandBlockHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating commander the cmdblck (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Previous = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0))
{
// If we're already powered or received an update of no power, don't activate
return {};
}
class cSetPowerToCommandBlock : public cCommandBlockCallback
{
public:
virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
{
a_CommandBlock->Activate();
return false;
}
} CmdBlockSP;
m_World.DoWithCommandBlockAt(a_Position.x, a_Position.y, a_Position.z, CmdBlockSP);
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
}
};

View File

@ -0,0 +1,59 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockDoor.h"
class cDoorHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cDoorHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating dori the door (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
{
cChunkInterface ChunkInterface(m_World.GetChunkMap());
cBlockDoorHandler::SetOpen(ChunkInterface, a_Position.x, a_Position.y, a_Position.z, (a_PoweringData.PowerLevel != 0));
m_World.BroadcastSoundParticleEffect(EffectID::SFX_RANDOM_DOOR_OPEN_CLOSE, a_Position.x, a_Position.y, a_Position.z, 0);
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
}
};

View File

@ -0,0 +1,69 @@
#pragma once
#include "RedstoneHandler.h"
#include "BlockEntities/DropSpenserEntity.h"
class cDropSpenserHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cDropSpenserHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating spencer the dropspenser (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData.PowerLevel > 0)
{
class cSetPowerToDropSpenser :
public cDropSpenserCallback
{
public:
virtual bool Item(cDropSpenserEntity * a_DropSpenser) override
{
a_DropSpenser->Activate();
return false;
}
} DrSpSP;
m_World.DoWithDropSpenserAt(a_Position.x, a_Position.y, a_Position.z, DrSpSP);
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
}
};

View File

@ -0,0 +1,170 @@
#include "Globals.h"
#include "IncrementalRedstoneSimulator.h"
#include "Chunk.h"
#include "CommandBlockHandler.h"
#include "DoorHandler.h"
#include "RedstoneHandler.h"
#include "RedstoneTorchHandler.h"
#include "RedstoneWireHandler.h"
#include "RedstoneRepeaterHandler.h"
#include "RedstoneToggleHandler.h"
#include "SolidBlockHandler.h"
#include "RedstoneLampHandler.h"
#include "RedstoneBlockHandler.h"
#include "PistonHandler.h"
#include "SmallGateHandler.h"
#include "NoteBlockHandler.h"
#include "TNTHandler.h"
#include "PoweredRailHandler.h"
#include "PressurePlateHandler.h"
#include "TripwireHookHandler.h"
#include "DropSpenserHandler.h"
#include "RedstoneComparatorHandler.h"
#include "TrappedChestHandler.h"
std::unique_ptr<cRedstoneHandler> cIncrementalRedstoneSimulator::CreateComponent(cWorld & a_World, BLOCKTYPE a_BlockType, cIncrementalRedstoneSimulatorChunkData * a_Data)
{
switch (a_BlockType)
{
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_POWERED_RAIL: return cpp14::make_unique<cPoweredRailHandler>(a_World);
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_INACTIVE_COMPARATOR: return cpp14::make_unique<cRedstoneComparatorHandler>(a_World);
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER: return cpp14::make_unique<cDropSpenserHandler>(a_World);
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_WOODEN_PRESSURE_PLATE: return cpp14::make_unique<cPressurePlateHandler>(a_World);
case E_BLOCK_FENCE_GATE:
case E_BLOCK_IRON_TRAPDOOR:
case E_BLOCK_TRAPDOOR: return cpp14::make_unique<cSmallGateHandler>(a_World);
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON: return cpp14::make_unique<cRedstoneLampHandler>(a_World);
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON: return cpp14::make_unique<cRedstoneRepeaterHandler>(a_World);
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON: return cpp14::make_unique<cRedstoneTorchHandler>(a_World);
case E_BLOCK_PISTON:
case E_BLOCK_STICKY_PISTON: return cpp14::make_unique<cPistonHandler>(a_World);
case E_BLOCK_LEVER:
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_WOODEN_BUTTON: return cpp14::make_unique<cRedstoneToggleHandler>(a_World);
case E_BLOCK_BLOCK_OF_REDSTONE: return cpp14::make_unique<cRedstoneBlockHandler>(a_World);
case E_BLOCK_COMMAND_BLOCK: return cpp14::make_unique<cCommandBlockHandler>(a_World);
case E_BLOCK_NOTE_BLOCK: return cpp14::make_unique<cNoteBlockHandler>(a_World);
case E_BLOCK_REDSTONE_WIRE: return cpp14::make_unique<cRedstoneWireHandler>(a_World);
case E_BLOCK_TNT: return cpp14::make_unique<cTNTHandler>(a_World);
case E_BLOCK_TRAPPED_CHEST: return cpp14::make_unique<cTrappedChestHandler>(a_World);
case E_BLOCK_TRIPWIRE_HOOK: return cpp14::make_unique<cTripwireHookHandler>(a_World);
default:
{
if (cBlockDoorHandler::IsDoorBlockType(a_BlockType))
{
return cpp14::make_unique<cDoorHandler>(a_World);
}
if (cBlockInfo::FullyOccupiesVoxel(a_BlockType))
{
return cpp14::make_unique<cSolidBlockHandler>(a_World);
}
return nullptr;
}
}
}
void cIncrementalRedstoneSimulator::Simulate(float a_dt)
{
for (auto & DelayInfo : m_Data.m_MechanismDelays)
{
if ((--DelayInfo.second.first) == 0)
{
m_Data.GetActiveBlocks().emplace_back(DelayInfo.first);
}
}
// Build our work queue
cVector3iArray WorkQueue;
std::swap(WorkQueue, m_Data.GetActiveBlocks());
// Process the work queue
while (!WorkQueue.empty())
{
// Grab the first element and remove it from the list
Vector3i CurrentLocation = WorkQueue.back();
WorkQueue.pop_back();
BLOCKTYPE CurrentBlock;
NIBBLETYPE CurrentMeta;
if (!m_World.GetBlockTypeMeta(CurrentLocation.x, CurrentLocation.y, CurrentLocation.z, CurrentBlock, CurrentMeta))
{
continue;
}
auto CurrentHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, CurrentBlock, &m_Data));
if (CurrentHandler == nullptr)
{
continue;
}
cRedstoneHandler::PoweringData Power;
for (const auto & Location : CurrentHandler->GetValidSourcePositions(CurrentLocation, CurrentBlock, CurrentMeta))
{
BLOCKTYPE PotentialBlock;
NIBBLETYPE PotentialMeta;
if ((Location.y < 0) || (Location.y > cChunkDef::Height))
{
continue;
}
m_World.GetBlockTypeMeta(Location.x, Location.y, Location.z, PotentialBlock, PotentialMeta);
auto PotentialSourceHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, PotentialBlock, &m_Data));
if (PotentialSourceHandler == nullptr)
{
continue;
}
decltype(Power) PotentialPower(PotentialBlock, PotentialSourceHandler->GetPowerDeliveredToPosition(Location, PotentialBlock, PotentialMeta, CurrentLocation, CurrentBlock));
Power = std::max(Power, PotentialPower);
}
// Inform the handler to update
cVector3iArray Updates = CurrentHandler->Update(CurrentLocation, CurrentBlock, CurrentMeta, Power);
WorkQueue.insert(WorkQueue.end(), Updates.begin(), Updates.end());
if (IsAlwaysTicked(CurrentBlock))
{
m_Data.GetActiveBlocks().emplace_back(CurrentLocation);
}
#ifdef _DEBUG
for (const auto & UpdateLocation : Updates)
{
LOGD("Queueing block for reupdate (%i %i %i)", UpdateLocation.x, UpdateLocation.y, UpdateLocation.z);
}
#endif
}
}

View File

@ -0,0 +1,167 @@
#pragma once
#include "../RedstoneSimulator.h"
#include "RedstoneSimulatorChunkData.h"
class cIncrementalRedstoneSimulator :
public cRedstoneSimulator
{
typedef cRedstoneSimulator super;
public:
cIncrementalRedstoneSimulator(cWorld & a_World) :
super(a_World)
{
}
virtual void Simulate(float a_dt) override;
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override {}
virtual cIncrementalRedstoneSimulatorChunkData * CreateChunkData() override
{
return new cIncrementalRedstoneSimulatorChunkData;
}
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) override
{
return IsRedstone(a_BlockType);
}
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) override
{
m_Data.WakeUp({ a_BlockX, a_BlockY, a_BlockZ });
}
/** Returns if a block is a mechanism (something that accepts power and does something)
Used by torches to determine if they will power a block
*/
inline static bool IsMechanism(BLOCKTYPE Block)
{
switch (Block)
{
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_ACACIA_FENCE_GATE:
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_BIRCH_FENCE_GATE:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DARK_OAK_DOOR:
case E_BLOCK_DARK_OAK_FENCE_GATE:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_FENCE_GATE:
case E_BLOCK_HOPPER:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_IRON_DOOR:
case E_BLOCK_IRON_TRAPDOOR:
case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_JUNGLE_FENCE_GATE:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_PISTON:
case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_WIRE:
case E_BLOCK_SPRUCE_DOOR:
case E_BLOCK_SPRUCE_FENCE_GATE:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_TNT:
case E_BLOCK_TRAPDOOR:
case E_BLOCK_WOODEN_DOOR:
{
return true;
}
default: return false;
}
}
/** Returns if a redstone device is always ticked due to influence by its environment */
inline static bool IsAlwaysTicked(BLOCKTYPE a_Block)
{
switch (a_Block) // Call the appropriate simulator for the entry's block type
{
case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_TRIPWIRE_HOOK:
case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_STONE_PRESSURE_PLATE:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: return true;
default: return false;
}
}
/** Returns if a block is any sort of redstone device */
inline static bool IsRedstone(BLOCKTYPE a_Block)
{
switch (a_Block)
{
// All redstone devices, please alpha sort
case E_BLOCK_ACACIA_DOOR:
case E_BLOCK_ACACIA_FENCE_GATE:
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BIRCH_DOOR:
case E_BLOCK_BIRCH_FENCE_GATE:
case E_BLOCK_BLOCK_OF_REDSTONE:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DARK_OAK_DOOR:
case E_BLOCK_DARK_OAK_FENCE_GATE:
case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_FENCE_GATE:
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_HOPPER:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_IRON_DOOR:
case E_BLOCK_IRON_TRAPDOOR:
case E_BLOCK_JUNGLE_DOOR:
case E_BLOCK_JUNGLE_FENCE_GATE:
case E_BLOCK_LEVER:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_NOTE_BLOCK:
case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
case E_BLOCK_REDSTONE_WIRE:
case E_BLOCK_SPRUCE_DOOR:
case E_BLOCK_SPRUCE_FENCE_GATE:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_STONE_BUTTON:
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:
case E_BLOCK_WOODEN_DOOR:
case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_PISTON:
{
return true;
}
default: return false;
}
}
cIncrementalRedstoneSimulatorChunkData * GetChunkData() { return &m_Data; }
static std::unique_ptr<cRedstoneHandler> CreateComponent(cWorld & a_World, BLOCKTYPE a_BlockType, cIncrementalRedstoneSimulatorChunkData * a_Data);
private:
// oh yea its crazy time
cIncrementalRedstoneSimulatorChunkData m_Data;
} ;

View File

@ -0,0 +1,71 @@
#pragma once
#include "RedstoneHandler.h"
#include "BlockEntities/NoteEntity.h"
class cNoteBlockHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cNoteBlockHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating sparky the magical note block (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel);
auto Previous = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if ((Previous.PowerLevel != 0) || (a_PoweringData.PowerLevel == 0))
{
// If we're already powered or received an update of no power, don't make a sound
return {};
}
class cSetPowerToNoteBlock : public cNoteBlockCallback
{
public:
virtual bool Item(cNoteEntity * a_NoteBlock) override
{
a_NoteBlock->MakeSound();
return false;
}
} NoteBlockSP;
m_World.DoWithNoteBlockAt(a_Position.x, a_Position.y, a_Position.z, NoteBlockSP);
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
}
};

View File

@ -0,0 +1,68 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockPiston.h"
class cPistonHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cPistonHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating pisty the piston (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData.PowerLevel > 0)
{
cBlockPistonHandler::ExtendPiston(a_Position, &m_World);
}
else
{
cBlockPistonHandler::RetractPiston(a_Position, &m_World);
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
auto PositionsOffset = GetRelativeAdjacents();
auto Face = cBlockPistonHandler::MetaDataToDirection(a_Meta);
int OffsetX = 0, OffsetY = 0, OffsetZ = 0;
AddFaceDirection(OffsetX, OffsetY, OffsetZ, Face);
PositionsOffset.erase(std::remove(PositionsOffset.begin(), PositionsOffset.end(), Vector3i(OffsetX, OffsetY, OffsetZ)), PositionsOffset.end());
return GetAdjustedRelatives(a_Position, PositionsOffset);
}
};

View File

@ -0,0 +1,100 @@
#pragma once
#include "RedstoneHandler.h"
class cPoweredRailHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cPoweredRailHandler(cWorld & a_World) :
super(a_World)
{
}
static const Vector3i GetPoweredRailAdjacentXZCoordinateOffset(NIBBLETYPE a_Meta) // Not in cBlockRailHandler since specific to powered rails
{
switch (a_Meta & 0x7)
{
case E_META_RAIL_ZM_ZP: return { 0, 0, 1 };
case E_META_RAIL_XM_XP: return { 1, 0, 0 };
case E_META_RAIL_ASCEND_XP: return { 1, 1, 0 };
case E_META_RAIL_ASCEND_XM: return { 1, 1, 0 };
case E_META_RAIL_ASCEND_ZM: return { 0, 1, 1 };
case E_META_RAIL_ASCEND_ZP: return { 0, 1, 1 };
default:
{
ASSERT(!"Impossible rail meta! wat wat wat");
return { 0, 0, 0 };
}
}
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_QueryBlockType);
auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
if (((Offset + a_Position) == a_QueryPosition) || ((-Offset + a_Position) == a_QueryPosition))
{
auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
return (Power <= 7) ? 0 : --Power;
}
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating tracky the rail (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
switch (a_BlockType)
{
case E_BLOCK_DETECTOR_RAIL:
{
/*
if ((m_Chunk->GetMeta(a_RelBlockX, a_RelBlockY, a_RelBlockZ) & 0x08) == 0x08)
{
SetAllDirsAsPowered(a_RelBlockX, a_RelBlockY, a_RelBlockZ, a_MyType);
}
*/
return {};
}
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_POWERED_RAIL:
{
auto Offset = GetPoweredRailAdjacentXZCoordinateOffset(a_Meta);
if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
{
m_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel == 0) ? (a_Meta & 0x07) : (a_Meta | 0x08));
return cVector3iArray{ { Offset + a_Position }, { -Offset + a_Position } };
}
return {};
}
default:
{
ASSERT(!"Unhandled type of rail in passed to rail handler!");
return {};
}
}
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
}
};

View File

@ -0,0 +1,111 @@
#pragma once
#include "RedstoneHandler.h"
#include "BoundingBox.h"
class cPressurePlateHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cPressurePlateHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
class cPressurePlateCallback :
public cEntityCallback
{
public:
cPressurePlateCallback(void) :
m_NumberOfEntities(0),
m_FoundPlayer(false)
{
}
virtual bool Item(cEntity * a_Entity) override
{
if (a_Entity->IsPlayer())
{
m_FoundPlayer = true;
}
m_NumberOfEntities++;
return false;
}
unsigned int m_NumberOfEntities;
bool m_FoundPlayer;
} PressurePlateCallback;
m_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + a_Position, 0.5, 0.5), PressurePlateCallback);
switch (a_BlockType)
{
case E_BLOCK_STONE_PRESSURE_PLATE:
{
return (PressurePlateCallback.m_FoundPlayer ? 15 : 0);
}
case E_BLOCK_WOODEN_PRESSURE_PLATE:
{
return (PressurePlateCallback.m_NumberOfEntities != 0 ? 15 : 0);
}
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
{
return std::min(static_cast<unsigned char>(CeilC(PressurePlateCallback.m_NumberOfEntities / 10.f)), static_cast<unsigned char>(15));
}
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
{
return std::min(static_cast<unsigned char>(PressurePlateCallback.m_NumberOfEntities), static_cast<unsigned char>(15));
}
default:
{
ASSERT(!"Unhandled/unimplemented block in pressure plate handler!");
return 0;
}
}
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
UNUSED(a_PoweringData.PowerLevel);
// LOGD("Evaluating clicky the pressure plate (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
if (Power != PreviousPower.PowerLevel)
{
m_World.SetBlockMeta(a_Position, (Power == 0) ? E_META_PRESSURE_PLATE_RAISED : E_META_PRESSURE_PLATE_DEPRESSED);
return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() }));
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return {};
}
};

View File

@ -0,0 +1,51 @@
#pragma once
#include "RedstoneHandler.h"
class cRedstoneBlockHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cRedstoneBlockHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 15;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 15;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating crimson the redstone block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return {};
}
};

View File

@ -0,0 +1,128 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockComparator.h"
class cRedstoneComparatorHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cRedstoneComparatorHandler(cWorld & a_World) :
super(a_World)
{
}
unsigned char GetFrontPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, unsigned char a_HighestSidePowerLevel)
{
class cContainerCallback : public cBlockEntityCallback
{
public:
cContainerCallback() : m_SignalStrength(0)
{
}
virtual bool Item(cBlockEntity * a_BlockEntity) override
{
auto & Contents = static_cast<cBlockEntityWithItems *>(a_BlockEntity)->GetContents();
float Fullness = 0; // Is a floating-point type to allow later calculation to produce a non-truncated value
for (int Slot = 0; Slot != Contents.GetNumSlots(); ++Slot)
{
Fullness += Contents.GetSlot(Slot).m_ItemCount / Contents.GetSlot(Slot).GetMaxStackSize();
}
m_SignalStrength = static_cast<unsigned char>(1 + (Fullness / Contents.GetNumSlots()) * 14);
return false;
}
unsigned char m_SignalStrength;
} CCB;
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3);
m_World.DoWithBlockEntityAt(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, CCB);
auto RearPower = CCB.m_SignalStrength;
auto PotentialSourceHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, m_World.GetBlock(RearCoordinate), static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()));
if (PotentialSourceHandler != nullptr)
{
BLOCKTYPE Type;
NIBBLETYPE Meta;
if (m_World.GetBlockTypeMeta(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, Type, Meta))
{
RearPower = std::max(CCB.m_SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition(RearCoordinate, Type, Meta, a_Position, a_BlockType));
}
}
if ((a_Meta & 0x4) == 0x4)
{
// Subtraction mode
return static_cast<unsigned char>(std::max(static_cast<char>(RearPower) - a_HighestSidePowerLevel, 0));
}
else
{
// Comparison mode
return (std::max(a_HighestSidePowerLevel, RearPower) == a_HighestSidePowerLevel) ? 0 : RearPower;
}
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return (cBlockComparatorHandler::GetFrontCoordinate(a_Position, a_Meta & 0x3) == a_QueryPosition) ? static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel : 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3);
auto PotentialSourceHandler = std::move(cIncrementalRedstoneSimulator::CreateComponent(m_World, m_World.GetBlock(RearCoordinate), static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()));
if (PotentialSourceHandler != nullptr)
{
BLOCKTYPE Type;
NIBBLETYPE Meta;
if (m_World.GetBlockTypeMeta(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, Type, Meta))
{
return PotentialSourceHandler->GetPowerDeliveredToPosition(RearCoordinate, Type, Meta, a_Position, a_BlockType);
}
}
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating ALU the comparator (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (GetPowerLevel(a_Position, a_BlockType, a_Meta) > 0)
{
m_World.SetBlockMeta(a_Position, a_Meta | 0x8);
}
else
{
m_World.SetBlockMeta(a_Position, a_Meta & 0x7);
}
auto Power = GetFrontPowerLevel(a_Position, a_BlockType, a_Meta, a_PoweringData.PowerLevel);
auto PreviousFrontPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_PoweringData.PoweringBlock, Power));
if (Power != PreviousFrontPower.PowerLevel)
{
return GetAdjustedRelatives(a_Position, GetRelativeLaterals());
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
return cVector3iArray {cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, false), cBlockComparatorHandler::GetSideCoordinate(a_Position, a_Meta & 0x3, true)};
}
};

View File

@ -0,0 +1,130 @@
#pragma once
#include "World.h"
#include "Vector3.h"
class cRedstoneHandler
{
public:
cRedstoneHandler(cWorld & a_World) :
m_World(a_World)
{
}
public:
// Disable the copy constructor and assignment operator
cRedstoneHandler(const cRedstoneHandler &) = delete;
cRedstoneHandler & operator=(const cRedstoneHandler &) = delete;
struct PoweringData
{
public:
PoweringData(BLOCKTYPE a_PoweringBlock, unsigned char a_PowerLevel) :
PoweringBlock(a_PoweringBlock),
PowerLevel(a_PowerLevel)
{
}
PoweringData(void) :
PoweringBlock(E_BLOCK_AIR),
PowerLevel(0)
{
}
BLOCKTYPE PoweringBlock;
unsigned char PowerLevel;
inline friend bool operator < (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
{
return (
(a_Lhs.PowerLevel < a_Rhs.PowerLevel) ||
(
(a_Lhs.PowerLevel == a_Rhs.PowerLevel) &&
((a_Lhs.PoweringBlock == E_BLOCK_REDSTONE_WIRE) && (a_Rhs.PoweringBlock != E_BLOCK_REDSTONE_WIRE))
)
);
}
inline friend bool operator == (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
{
return (a_Lhs.PowerLevel == a_Rhs.PowerLevel);
}
inline friend bool operator != (const PoweringData & a_Lhs, const PoweringData & a_Rhs)
{
return !operator ==(a_Lhs, a_Rhs);
}
};
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) = 0;
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) = 0;
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) = 0;
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) = 0;
// Force a virtual destructor
virtual ~cRedstoneHandler() {}
protected:
cWorld & m_World;
template <class Container>
static const Container StaticAppend(const Container && a_Lhs, const Container && a_Rhs)
{
Container ToReturn = a_Lhs;
std::copy(a_Rhs.begin(), a_Rhs.end(), std::back_inserter(ToReturn));
return ToReturn;
}
inline static const Vector3i OffsetYP()
{
return Vector3i(0, 1, 0);
}
inline static const Vector3i OffsetYM()
{
return Vector3i(0, -1, 0);
}
static const cVector3iArray GetAdjustedRelatives(const Vector3i & a_Position, const cVector3iArray & a_Relatives)
{
cVector3iArray Adjusted = a_Relatives;
std::for_each(Adjusted.begin(), Adjusted.end(), [a_Position](cVector3iArray::value_type & a_Entry) { a_Entry += a_Position; });
return Adjusted;
}
inline static const cVector3iArray GetRelativeAdjacents()
{
return
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 1, 0 },
{ 0, -1, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
}
inline static const cVector3iArray GetRelativeLaterals()
{
return
{
{
{ 1, 0, 0 },
{ -1, 0, 0 },
{ 0, 0, 1 },
{ 0, 0, -1 },
}
};
}
};

View File

@ -0,0 +1,62 @@
#pragma once
#include "IncrementalRedstoneSimulator.h"
class cRedstoneLampHandler : public cRedstoneHandler
{
public:
cRedstoneLampHandler(cWorld & a_World) :
cRedstoneHandler(a_World)
{
}
inline static bool IsOn(BLOCKTYPE a_BlockType)
{
return (a_BlockType == E_BLOCK_REDSTONE_LAMP_ON);
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating lamp (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData.PowerLevel > 0)
{
if (!IsOn(a_BlockType))
{
m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_REDSTONE_LAMP_ON, 0);
}
}
else
{
if (IsOn(a_BlockType))
{
m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_REDSTONE_LAMP_OFF, 0);
}
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Meta);
UNUSED(a_BlockType);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
}
};

View File

@ -0,0 +1,73 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockRedstoneRepeater.h"
class cRedstoneRepeaterHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cRedstoneRepeaterHandler(cWorld & a_World) :
super(a_World)
{
}
inline static bool IsOn(BLOCKTYPE a_Block)
{
return (a_Block == E_BLOCK_REDSTONE_REPEATER_ON);
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
return (a_QueryPosition == (a_Position + cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta))) ? GetPowerLevel(a_Position, a_BlockType, a_Meta) : 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_Meta);
return IsOn(a_BlockType) ? 15 : 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating loopy the repeater (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData();
auto DelayInfo = Data->GetMechanismDelayInfo(a_Position);
if (DelayInfo == nullptr)
{
bool ShouldBeOn = (a_PoweringData.PowerLevel != 0);
if (ShouldBeOn != IsOn(a_BlockType))
{
Data->m_MechanismDelays[a_Position] = std::make_pair((((a_Meta & 0xC) >> 0x2) + 1), ShouldBeOn);
}
}
else
{
int DelayTicks;
bool ShouldPowerOn;
std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
if (DelayTicks == 0)
{
m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, ShouldPowerOn ? E_BLOCK_REDSTONE_REPEATER_ON : E_BLOCK_REDSTONE_REPEATER_OFF, a_Meta);
Data->m_MechanismDelays.erase(a_Position);
return cVector3iArray{ cBlockRedstoneRepeaterHandler::GetFrontCoordinateOffset(a_Meta) + a_Position };
}
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
return { cBlockRedstoneRepeaterHandler::GetRearCoordinateOffset(a_Meta) + a_Position };
}
};

View File

@ -0,0 +1,70 @@
#pragma once
#include "Vector3.h"
#include "RedstoneHandler.h"
#include "../RedstoneSimulator.h"
#include <unordered_map>
class cIncrementalRedstoneSimulatorChunkData : public cRedstoneSimulatorChunkData
{
public:
void WakeUp(const Vector3i & a_Position)
{
m_ActiveBlocks.push_back(a_Position);
}
cVector3iArray & GetActiveBlocks()
{
return m_ActiveBlocks;
}
const cRedstoneHandler::PoweringData GetCachedPowerData(const Vector3i & a_Position) const
{
auto Result = m_CachedPowerLevels.find(a_Position);
return (Result == m_CachedPowerLevels.end()) ? cRedstoneHandler::PoweringData() : Result->second;
}
void SetCachedPowerData(const Vector3i & a_Position, cRedstoneHandler::PoweringData a_PoweringData)
{
m_CachedPowerLevels[a_Position] = a_PoweringData;
}
std::pair<int, bool> * GetMechanismDelayInfo(const Vector3i & a_Position)
{
auto Result = m_MechanismDelays.find(a_Position);
return (Result == m_MechanismDelays.end()) ? nullptr : &Result->second;
}
cRedstoneHandler::PoweringData ExchangeUpdateOncePowerData(const Vector3i & a_Position, cRedstoneHandler::PoweringData a_PoweringData)
{
auto Result = m_CachedPowerLevels.find(a_Position);
if (Result == m_CachedPowerLevels.end())
{
m_CachedPowerLevels[a_Position] = a_PoweringData;
return cRedstoneHandler::PoweringData();
}
std::swap(Result->second, a_PoweringData);
return a_PoweringData;
}
/** Structure storing position of mechanism + it's delay ticks (countdown) & if to power on */
std::unordered_map<Vector3i, std::pair<int, bool>, VectorHasher<int>> m_MechanismDelays;
std::unordered_map<Vector3i, bool, VectorHasher<int>> m_UpdateOncePositions;
private:
cVector3iArray m_ActiveBlocks;
// TODO: map<Vector3i, int> -> Position of torch + it's heat level
std::unordered_map<Vector3i, cRedstoneHandler::PoweringData, VectorHasher<int>> m_CachedPowerLevels;
friend class cRedstoneHandlerFactory;
};

View File

@ -0,0 +1,111 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockButton.h"
#include "Blocks/BlockLever.h"
class cRedstoneToggleHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cRedstoneToggleHandler(cWorld & a_World) :
super(a_World)
{
}
inline static const Vector3i GetPositionAttachedTo(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta)
{
switch (a_BlockType)
{
case E_BLOCK_LEVER:
{
switch (a_Meta & 0x7)
{
case 0x0:
case 0x7: return { a_Position + Vector3i(0, 1, 0) };
case 0x1: return { a_Position + Vector3i(-1, 0, 0) };
case 0x2: return { a_Position + Vector3i(1, 0, 0) };
case 0x3: return { a_Position + Vector3i(0, 0, -1) };
case 0x4: return { a_Position + Vector3i(0, 0, 1) };
case 0x5:
case 0x6: return { a_Position + Vector3i(0, -1, 0) };
default:
{
ASSERT(!"Unhandled lever metadata!");
return { 0, 0, 0 };
}
}
}
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_WOODEN_BUTTON:
{
switch (a_Meta & 0x7)
{
case 0x0: return { a_Position + Vector3i(0, 1, 0) };
case 0x1: return { a_Position + Vector3i(-1, 0, 0) };
case 0x2: return { a_Position + Vector3i(1, 0, 0) };
case 0x3: return { a_Position + Vector3i(0, 0, -1) };
case 0x4: return { a_Position + Vector3i(0, 0, 1) };
case 0x5: return { a_Position + Vector3i(0, -1, 0) };
default:
{
ASSERT(!"Unhandled button metadata!");
return { 0, 0, 0 };
}
}
}
default:
{
ASSERT(!"Unexpected block passed to button/lever handler");
return { 0, 0, 0 };
}
}
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_QueryBlockType);
if ((GetPositionAttachedTo(a_Position, a_BlockType, a_Meta) == a_QueryPosition) || cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType))
{
return GetPowerLevel(a_Position, a_BlockType, a_Meta);
}
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
switch (a_BlockType)
{
case E_BLOCK_LEVER: return cBlockLeverHandler::IsLeverOn(a_Meta) ? 15 : 0;
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_WOODEN_BUTTON: return cBlockButtonHandler::IsButtonOn(a_Meta) ? 15 : 0;
default:
{
ASSERT(!"Unexpected block passed to button/lever handler");
return 0;
}
}
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating templatio<> the lever/button (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return {};
}
};

View File

@ -0,0 +1,99 @@
#pragma once
#include "RedstoneHandler.h"
class cRedstoneTorchHandler : public cRedstoneHandler
{
public:
cRedstoneTorchHandler(cWorld & a_World) :
cRedstoneHandler(a_World)
{
}
inline static bool IsOn(BLOCKTYPE a_Block)
{
return (a_Block == E_BLOCK_REDSTONE_TORCH_ON);
}
inline static const Vector3i GetOffsetAttachedTo(const Vector3i & a_Position, NIBBLETYPE a_Meta)
{
switch (a_Meta)
{
case E_META_TORCH_FLOOR: return { 0, -1, 0 };
case E_META_TORCH_EAST: return { -1, 0, 0 };
case E_META_TORCH_WEST: return { 1, 0, 0 };
case E_META_TORCH_NORTH: return { 0, 0, 1 };
case E_META_TORCH_SOUTH: return { 0, 0, -1 };
default:
{
ASSERT(!"Unhandled torch metadata");
return { 0, 0, 0 };
}
}
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
if (
IsOn(a_BlockType) &&
(a_QueryPosition != (a_Position + GetOffsetAttachedTo(a_Position, a_Meta))) &&
(cIncrementalRedstoneSimulator::IsMechanism(a_QueryBlockType) || (cBlockInfo::FullyOccupiesVoxel(a_QueryBlockType) && (a_QueryPosition == (a_Position + OffsetYP()))))
)
{
return 15;
}
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
return IsOn(a_BlockType) ? 15 : 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating torchy the redstone torch (%i %i %i)", a_Position.x, a_Position.y, a_Position.z);
auto Data = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData();
auto DelayInfo = Data->GetMechanismDelayInfo(a_Position);
if (DelayInfo == nullptr)
{
bool ShouldBeOn = (a_PoweringData.PowerLevel == 0);
if (ShouldBeOn != IsOn(a_BlockType))
{
Data->m_MechanismDelays[a_Position] = std::make_pair(1, ShouldBeOn);
}
}
else
{
int DelayTicks;
bool ShouldPowerOn;
std::tie(DelayTicks, ShouldPowerOn) = *DelayInfo;
if (DelayTicks == 0)
{
m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, ShouldPowerOn ? E_BLOCK_REDSTONE_TORCH_ON : E_BLOCK_REDSTONE_TORCH_OFF, a_Meta);
Data->m_MechanismDelays.erase(a_Position);
cVector3iArray RelativePositions = GetRelativeAdjacents();
RelativePositions.erase(std::remove(RelativePositions.begin(), RelativePositions.end(), GetOffsetAttachedTo(a_Position, a_Meta)), RelativePositions.end());
return GetAdjustedRelatives(a_Position, RelativePositions);
}
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
return { (a_Position + GetOffsetAttachedTo(a_Position, a_Meta)) };
}
};

View File

@ -0,0 +1,134 @@
#pragma once
#include "RedstoneHandler.h"
class cRedstoneWireHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cRedstoneWireHandler(cWorld & a_World) :
super(a_World)
{
}
inline static bool IsDirectlyConnectingMechanism(BLOCKTYPE a_Block)
{
switch (a_Block)
{
case E_BLOCK_REDSTONE_REPEATER_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_INACTIVE_COMPARATOR:
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
case E_BLOCK_REDSTONE_WIRE: return true;
default: return false;
}
}
const cVector3iArray GetTerracingConnectionOffsets(const Vector3i & a_Position)
{
cVector3iArray RelativePositions;
bool IsYPTerracingBlocked = cBlockInfo::IsSolid(m_World.GetBlock(a_Position + OffsetYP()));
for (const auto Adjacent : GetRelativeLaterals())
{
if (
!IsYPTerracingBlocked &&
(m_World.GetBlock(a_Position + Adjacent + OffsetYP()) == E_BLOCK_REDSTONE_WIRE)
)
{
RelativePositions.emplace_back(Adjacent + OffsetYP());
}
if (
!cBlockInfo::IsSolid(m_World.GetBlock(a_Position + Adjacent)) && // IsYMTerracingBlocked (i.e. check block above lower terracing position, a.k.a. just the plain adjacent)
(m_World.GetBlock(a_Position + Adjacent + OffsetYM()) == E_BLOCK_REDSTONE_WIRE)
)
{
RelativePositions.emplace_back(Adjacent + OffsetYM());
}
}
return RelativePositions;
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
if (a_QueryPosition == (a_Position + OffsetYP()))
{
// Wires do not power things above them
return 0;
}
if (a_QueryBlockType != E_BLOCK_REDSTONE_WIRE)
{
// For mechanisms, wire of power one will still power them
a_Meta++;
}
if ((a_QueryPosition != (a_Position + OffsetYM())) && !IsDirectlyConnectingMechanism(a_QueryBlockType))
{
Vector3i PotentialOffset;
bool FoundOneBorderingMechanism = false;
for (const auto & Offset : StaticAppend(GetRelativeLaterals(), GetTerracingConnectionOffsets(a_Position)))
{
if (IsDirectlyConnectingMechanism(m_World.GetBlock(Offset + a_Position)))
{
if (FoundOneBorderingMechanism)
{
return 0;
}
else
{
FoundOneBorderingMechanism = true;
PotentialOffset = { -Offset.x, 0, -Offset.z };
}
}
}
if (FoundOneBorderingMechanism && (a_QueryPosition != (a_Position + PotentialOffset)))
{
return 0;
}
}
return (a_Meta != 0) ? --a_Meta : a_Meta;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
return a_Meta;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
UNUSED(a_BlockType);
LOGD("Evaluating dusty the wire (%d %d %d) %i", a_Position.x, a_Position.y, a_Position.z, a_PoweringData.PowerLevel);
if (a_Meta != a_PoweringData.PowerLevel)
{
m_World.SetBlockMeta(a_Position, a_PoweringData.PowerLevel);
return GetAdjustedRelatives(a_Position, StaticAppend(StaticAppend(GetRelativeLaterals(), GetTerracingConnectionOffsets(a_Position)), cVector3iArray{ OffsetYM() }));
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeAdjacents(), GetTerracingConnectionOffsets(a_Position)));
}
};

View File

@ -0,0 +1,56 @@
#pragma once
#include "RedstoneHandler.h"
class cSmallGateHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cSmallGateHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating gateydory the fence gate/trapdoor (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData != static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData))
{
m_World.SetBlockMeta(a_Position, (a_PoweringData.PowerLevel > 0) ? (a_Meta | 0x4) : (a_Meta & ~0x04));
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
}
};

View File

@ -0,0 +1,71 @@
#pragma once
#include "RedstoneHandler.h"
class cSolidBlockHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cSolidBlockHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
// TODO: wire isn't linked powered only if the source was a wire, not just because it is a wire
return (
!cIncrementalRedstoneSimulator::IsRedstone(a_QueryBlockType) ||
(
(a_QueryBlockType == E_BLOCK_REDSTONE_WIRE) &&
(static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PoweringBlock == E_BLOCK_REDSTONE_WIRE)
)
) ? 0 : GetPowerLevel(a_Position, a_BlockType, a_Meta);
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
LOGD("Evaluating blocky the generic block (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, a_PoweringData);
if ((a_PoweringData != PreviousPower) || (a_PoweringData.PoweringBlock != PreviousPower.PoweringBlock))
{
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
/* TODO: is this more performant?
cVector3iArray Adjacents;
for (const auto Offset : GetRelativeAdjacents())
{
auto Position = Offset + a_Position;
auto Block = m_World.GetBlock(Position);
if ((Block == E_BLOCK_REDSTONE_REPEATER_ON) || (Block == E_BLOCK_REDSTONE_WIRE) || (Block == E_BLOCK_TRIPWIRE_HOOK))
{
Adjacents.emplace_back(Position);
}
}
*/
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
}
};

View File

@ -0,0 +1,58 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockButton.h"
#include "Blocks/BlockLever.h"
class cTNTHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cTNTHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating explodinator the trinitrotoluene (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
if (a_PoweringData.PowerLevel != 0)
{
m_World.BroadcastSoundEffect("game.tnt.primed", (double)a_Position.x, (double)a_Position.y, (double)a_Position.z, 0.5f, 0.6f);
m_World.SetBlock(a_Position.x, a_Position.y, a_Position.z, E_BLOCK_AIR, 0);
m_World.SpawnPrimedTNT(a_Position.x + 0.5, a_Position.y + 0.5, a_Position.z + 0.5); // 80 ticks to boom
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());;
}
};

View File

@ -0,0 +1,93 @@
#pragma once
#include "RedstoneHandler.h"
#include "BlockEntities/ChestEntity.h"
class cTrappedChestHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cTrappedChestHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_QueryPosition);
UNUSED(a_QueryBlockType);
return static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->GetCachedPowerData(a_Position).PowerLevel;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
class cGetTrappedChestPlayers :
public cItemCallback<cChestEntity>
{
public:
cGetTrappedChestPlayers(void) :
m_NumberOfPlayers(0)
{
}
virtual ~cGetTrappedChestPlayers()
{
}
virtual bool Item(cChestEntity * a_Chest) override
{
ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST);
m_NumberOfPlayers = a_Chest->GetNumberOfPlayers();
return true;
}
unsigned char GetPowerLevel(void) const
{
return static_cast<unsigned char>(std::min(m_NumberOfPlayers, 15));
}
private:
int m_NumberOfPlayers;
} GTCP;
VERIFY(!m_World.DoWithChestAt(a_Position.x, a_Position.y, a_Position.z, GTCP));
return GTCP.GetPowerLevel();
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
LOGD("Evaluating tricky the trapped chest (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
auto PreviousPower = static_cast<cIncrementalRedstoneSimulator *>(m_World.GetRedstoneSimulator())->GetChunkData()->ExchangeUpdateOncePowerData(a_Position, PoweringData(a_BlockType, Power));
if (Power != PreviousPower.PowerLevel)
{
return GetAdjustedRelatives(a_Position, StaticAppend(GetRelativeLaterals(), cVector3iArray{ OffsetYM() }));
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_Position);
UNUSED(a_BlockType);
UNUSED(a_Meta);
return {};
}
};

View File

@ -0,0 +1,136 @@
#pragma once
#include "RedstoneHandler.h"
#include "Blocks/BlockTripwireHook.h"
class cTripwireHookHandler : public cRedstoneHandler
{
typedef cRedstoneHandler super;
public:
cTripwireHookHandler(cWorld & a_World) :
super(a_World)
{
}
virtual unsigned char GetPowerDeliveredToPosition(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, const Vector3i & a_QueryPosition, BLOCKTYPE a_QueryBlockType) override
{
UNUSED(a_QueryBlockType);
UNUSED(a_QueryPosition);
return (GetPowerLevel(a_Position, a_BlockType, a_Meta) == 15) ? 15 : 0;
}
virtual unsigned char GetPowerLevel(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
bool FoundActivated = false;
auto Position = a_Position;
eBlockFace FaceToGoTowards = cBlockTripwireHookHandler::MetadataToDirection(a_Meta);
for (int i = 0; i < 40; ++i) // Tripwires can be connected up to 40 blocks
{
BLOCKTYPE Type;
NIBBLETYPE Meta;
AddFaceDirection(Position.x, Position.y, Position.z, FaceToGoTowards);
m_World.GetBlockTypeMeta(Position.x, Position.y, Position.z, Type, Meta);
if (Type == E_BLOCK_TRIPWIRE)
{
class cTripwireCallback :
public cEntityCallback
{
public:
cTripwireCallback(void) :
m_NumberOfEntities(0),
m_FoundPlayer(false)
{
}
virtual bool Item(cEntity * a_Entity) override
{
return true;
}
unsigned int m_NumberOfEntities;
bool m_FoundPlayer;
} TripwireCallback;
if (!m_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), TripwireCallback))
{
FoundActivated = true;
}
}
else if (Type == E_BLOCK_TRIPWIRE_HOOK)
{
if (ReverseBlockFace(cBlockTripwireHookHandler::MetadataToDirection(Meta)) == FaceToGoTowards)
{
// Other hook facing in opposite direction - circuit completed!
return FoundActivated ? 15 : 1;
}
else
{
// Tripwire hook not connected at all
return 0;
}
}
else
{
// Tripwire hook not connected at all
return 0;
}
}
return 0;
}
virtual cVector3iArray Update(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) override
{
// LOGD("Evaluating hooky the tripwire hook (%d %d %d)", a_Position.x, a_Position.y, a_Position.z);
auto Power = GetPowerLevel(a_Position, a_BlockType, a_Meta);
NIBBLETYPE Meta;
if (Power == 0)
{
Meta = (a_Meta & 0x3);
}
else if (Power == 1)
{
// Connected but not activated, AND away the highest bit
Meta = (a_Meta & 0x7) | 0x4;
}
else if (Power == 15)
{
// Connected and activated, set the 3rd and 4th highest bits
Meta = (a_Meta | 0xC);
}
else
{
ASSERT(!"Unexpected tripwire hook power level!");
return {};
}
if (Meta != a_Meta)
{
m_World.SetBlockMeta(a_Position, Meta);
return GetAdjustedRelatives(a_Position, GetRelativeAdjacents());
}
return {};
}
virtual cVector3iArray GetValidSourcePositions(const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta) override
{
UNUSED(a_BlockType);
UNUSED(a_Meta);
UNUSED(a_Position);
return {};
}
};

View File

@ -18,8 +18,6 @@ public:
{
}
// ~cRedstoneNoopSimulator();
virtual void Simulate(float a_Dt) override { UNUSED(a_Dt);} // not used
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) override
{

View File

@ -1,30 +1,41 @@
#pragma once
#include "Simulator.h"
#include "ChunkDef.h"
#include "Simulator/Simulator.h"
class cRedstoneSimulatorChunkData
{
public:
virtual ~cRedstoneSimulatorChunkData() = 0;
} ;
};
inline cRedstoneSimulatorChunkData::~cRedstoneSimulatorChunkData() {}
class cRedstoneSimulator :
public cSimulator
{
typedef cSimulator super;
public:
cRedstoneSimulator(cWorld & a_World) :
super(a_World)
{
}
virtual void Simulate(float a_Dt) = 0;
virtual void SimulateChunk(std::chrono::milliseconds a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk) = 0;
virtual bool IsAllowedBlock(BLOCKTYPE a_BlockType) = 0;
virtual void AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChunk * a_Chunk) = 0;
virtual cRedstoneSimulatorChunkData * CreateChunkData() = 0;
} ;
};

View File

@ -74,17 +74,13 @@ cChestWindow::~cChestWindow()
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);
m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ());
if (m_SecondaryChest != nullptr)
{
m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() - 1);
cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ());
}
cWindow::ClosedByPlayer(a_Player, a_CanRefuse);
@ -97,17 +93,13 @@ bool cChestWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
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);
m_PrimaryChest->GetWorld()->WakeUpSimulators(m_PrimaryChest->GetPosX(), m_PrimaryChest->GetPosY(), m_PrimaryChest->GetPosZ());
if (m_SecondaryChest != nullptr)
{
m_SecondaryChest->SetNumberOfPlayers(m_SecondaryChest->GetNumberOfPlayers() + 1);
cChunkDef::BlockToChunk(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosZ(), ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->MarkRedstoneDirty(ChunkX, ChunkZ);
m_SecondaryChest->GetWorld()->WakeUpSimulators(m_SecondaryChest->GetPosX(), m_SecondaryChest->GetPosY(), m_SecondaryChest->GetPosZ());
}
cWindow::OpenedByPlayer(a_Player);

View File

@ -255,6 +255,11 @@ public:
);
}
inline Vector3<T> operator - (void) const
{
return Vector3<T>(-x, -y, -z);
}
inline Vector3<T> operator * (const Vector3<T>& a_Rhs) const
{
return Vector3<T>(

View File

@ -34,8 +34,8 @@
#include "Simulator/FireSimulator.h"
#include "Simulator/NoopFluidSimulator.h"
#include "Simulator/NoopRedstoneSimulator.h"
#include "Simulator/IncrementalRedstoneSimulator/IncrementalRedstoneSimulator.h"
#include "Simulator/SandSimulator.h"
#include "Simulator/IncrementalRedstoneSimulator.h"
#include "Simulator/VanillaFluidSimulator.h"
#include "Simulator/VaporizeFluidSimulator.h"
@ -991,8 +991,6 @@ void cWorld::Tick(std::chrono::milliseconds a_Dt, std::chrono::milliseconds a_La
TickWeather(static_cast<float>(a_Dt.count()));
m_ChunkMap->FastSetQueuedBlocks();
if (m_WorldAge - m_LastSave > std::chrono::minutes(5)) // Save each 5 minutes
{
SaveAllChunks();
@ -3626,7 +3624,7 @@ cRedstoneSimulator * cWorld::InitializeRedstoneSimulator(cIniFile & a_IniFile)
res = new cRedstoneNoopSimulator(*this);
}
m_SimulatorManager->RegisterSimulator(res, 1);
m_SimulatorManager->RegisterSimulator(res, 2 /* Two game ticks is a redstone tick */);
return res;
}

View File

@ -392,14 +392,6 @@ public:
m_ChunkMap->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta);
}
/** Queues a SetBlock() with the specified parameters after the specified number of ticks.
Calls SetBlock(), so performs full processing of the replaced block.
*/
void QueueSetBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, int a_TickDelay, BLOCKTYPE a_PreviousBlockType = E_BLOCK_AIR)
{
m_ChunkMap->QueueSetBlock(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, GetWorldAge() + a_TickDelay, a_PreviousBlockType);
}
BLOCKTYPE GetBlock (int a_BlockX, int a_BlockY, int a_BlockZ)
{
return m_ChunkMap->GetBlock(a_BlockX, a_BlockY, a_BlockZ);