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:
parent
dae27fa9ec
commit
5b62c4c314
@ -42,7 +42,6 @@ SET (HDRS
|
||||
MobHeadEntity.h
|
||||
MobSpawnerEntity.h
|
||||
NoteEntity.h
|
||||
RedstonePoweredEntity.h
|
||||
SignEntity.h
|
||||
)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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};
|
||||
}
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
14
src/Chunk.h
14
src/Chunk.h
@ -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;
|
||||
|
123
src/ChunkMap.cpp
123
src/ChunkMap.cpp
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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())
|
||||
{
|
||||
|
@ -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
@ -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 };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
38
src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
Normal file
38
src/Simulator/IncrementalRedstoneSimulator/CMakeLists.txt
Normal 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()
|
||||
|
@ -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());;
|
||||
}
|
||||
};
|
59
src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
Normal file
59
src/Simulator/IncrementalRedstoneSimulator/DoorHandler.h
Normal 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());;
|
||||
}
|
||||
};
|
@ -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());
|
||||
}
|
||||
};
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
} ;
|
@ -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());;
|
||||
}
|
||||
};
|
68
src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h
Normal file
68
src/Simulator/IncrementalRedstoneSimulator/PistonHandler.h
Normal 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);
|
||||
}
|
||||
};
|
100
src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h
Normal file
100
src/Simulator/IncrementalRedstoneSimulator/PoweredRailHandler.h
Normal 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());
|
||||
}
|
||||
};
|
@ -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 {};
|
||||
}
|
||||
};
|
@ -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 {};
|
||||
}
|
||||
};
|
@ -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)};
|
||||
}
|
||||
};
|
130
src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h
Normal file
130
src/Simulator/IncrementalRedstoneSimulator/RedstoneHandler.h
Normal 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 },
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
@ -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());
|
||||
}
|
||||
};
|
@ -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 };
|
||||
}
|
||||
};
|
@ -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;
|
||||
|
||||
};
|
@ -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 {};
|
||||
}
|
||||
};
|
@ -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)) };
|
||||
}
|
||||
};
|
134
src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
Normal file
134
src/Simulator/IncrementalRedstoneSimulator/RedstoneWireHandler.h
Normal 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)));
|
||||
}
|
||||
};
|
@ -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());;
|
||||
}
|
||||
};
|
@ -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());
|
||||
}
|
||||
};
|
58
src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h
Normal file
58
src/Simulator/IncrementalRedstoneSimulator/TNTHandler.h
Normal 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());;
|
||||
}
|
||||
};
|
@ -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 {};
|
||||
}
|
||||
};
|
136
src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h
Normal file
136
src/Simulator/IncrementalRedstoneSimulator/TripwireHookHandler.h
Normal 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 {};
|
||||
}
|
||||
};
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
} ;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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>(
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user