1
0

Basic command block implementation

This commit is contained in:
andrew 2014-01-18 15:16:47 +02:00
parent 9aca5b4b99
commit 9a9b51a513
12 changed files with 396 additions and 33 deletions

View File

@ -20,5 +20,6 @@ worktycho
Sxw1212
tonibm19
Diusrex
structinf (xdot)
Please add yourself to this list if you contribute to MCServer.

View File

@ -6,6 +6,7 @@
#include "Globals.h"
#include "BlockEntity.h"
#include "ChestEntity.h"
#include "CommandBlockEntity.h"
#include "DispenserEntity.h"
#include "DropperEntity.h"
#include "EnderChestEntity.h"
@ -23,17 +24,18 @@ cBlockEntity * cBlockEntity::CreateByBlockType(BLOCKTYPE a_BlockType, NIBBLETYPE
{
switch (a_BlockType)
{
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_CHEST: return new cChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_COMMAND_BLOCK: return new cCommandBlockEntity(a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DISPENSER: return new cDispenserEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_DROPPER: return new cDropperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_ENDER_CHEST: return new cEnderChestEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_LIT_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_FURNACE: return new cFurnaceEntity (a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_World);
case E_BLOCK_HOPPER: return new cHopperEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_SIGN_POST: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_WALLSIGN: return new cSignEntity (a_BlockType, a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_NOTE_BLOCK: return new cNoteEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
case E_BLOCK_JUKEBOX: return new cJukeboxEntity (a_BlockX, a_BlockY, a_BlockZ, a_World);
}
LOGD("%s: Requesting creation of an unknown block entity - block type %d (%s)",
__FUNCTION__, a_BlockType, ItemTypeToString(a_BlockType).c_str()

View File

@ -0,0 +1,173 @@
// CommandBlockEntity.cpp
// Implements the cCommandBlockEntity class representing a single command block in the world
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "json/json.h"
#include "CommandBlockEntity.h"
#include "../Entities/Player.h"
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)
{
SetBlockEntity(this); // cBlockEntityWindowOwner
}
cCommandBlockEntity::~cCommandBlockEntity()
{
// Tell window its owner is destroyed
cWindow * Window = GetWindow();
if (Window != NULL)
{
Window->OwnerDestroyed();
}
}
void cCommandBlockEntity::UsedBy(cPlayer * a_Player)
{
cWindow * Window = GetWindow();
if (Window == NULL)
{
//OpenWindow(new cDropSpenserWindow(m_PosX, m_PosY, m_PosZ, this));
Window = GetWindow();
}
if (Window != NULL)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(Window);
}
}
}
void cCommandBlockEntity::SetCommand(const AString & a_Cmd)
{
m_Command = a_Cmd;LOGD("Hrey %s", a_Cmd.c_str());
}
const AString & cCommandBlockEntity::GetCommand(void) const
{
return m_Command;
}
const AString & cCommandBlockEntity::GetLastOutput(void) const
{
return m_LastOutput;
}
void cCommandBlockEntity::Activate(void)
{
m_ShouldExecute = true;
}
void cCommandBlockEntity::SetRedstonePower(bool a_IsPowered)
{
if (a_IsPowered && !m_IsPowered)
{
Activate();
}
m_IsPowered = a_IsPowered;
}
bool cCommandBlockEntity::Tick(float a_Dt, cChunk & a_Chunk)
{
if (!m_ShouldExecute)
{
return false;
}
m_ShouldExecute = false;
Execute();
return true;
}
void cCommandBlockEntity::SendTo(cClientHandle & a_Client)
{
// Nothing needs to be sent
UNUSED(a_Client);
}
bool cCommandBlockEntity::LoadFromJson(const Json::Value & a_Value)
{
m_Command = a_Value.get("Command", "").asString();
m_LastOutput = a_Value.get("LastOutput", "").asString();
return true;
}
void cCommandBlockEntity::SaveToJson(Json::Value & a_Value)
{
a_Value["Command"] = m_Command;
a_Value["LastOutput"] = m_LastOutput;
}
void cCommandBlockEntity::Execute()
{
// TODO: Parse arguments and dispatch command
LOGD("Command: %s", m_Command.c_str());
m_LastOutput = "";
}

View File

@ -0,0 +1,85 @@
// CommandBlockEntity.h
// Declares the cCommandBlockEntity class representing a single command block in the world
#pragma once
#include "BlockEntityWithItems.h"
#include "../UI/WindowOwner.h"
namespace Json
{
class Value;
}
// tolua_begin
class cCommandBlockEntity :
public cBlockEntity,
public cBlockEntityWindowOwner
{
typedef cBlockEntity super;
public:
// tolua_end
/// Creates a new empty command block entity
cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
virtual ~cCommandBlockEntity();
bool LoadFromJson( const Json::Value& a_Value );
virtual void SaveToJson(Json::Value& a_Value ) override;
virtual bool Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override;
// tolua_begin
/// Sets the internal redstone power flag to "on" or "off", depending on the parameter. Calls Activate() if appropriate
void SetRedstonePower(bool a_IsPowered);
/// Sets the command block to execute a command in the next tick
void Activate(void);
/// Sets the command
void SetCommand(const AString & a_Cmd);
/// Retrieves stored command
const AString & GetCommand(void) const;
/// Retrieves the last line of output generated by the command block
const AString & GetLastOutput(void) const;
// tolua_end
private:
/// Executes the associated command
void Execute();
bool m_ShouldExecute;
bool m_IsPowered;
AString m_Command;
AString m_LastOutput;
} ; // tolua_export

View File

@ -1298,6 +1298,7 @@ void cChunk::CreateBlockEntities(void)
switch (BlockType)
{
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENDER_CHEST:
@ -1425,6 +1426,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
switch (a_BlockType)
{
case E_BLOCK_CHEST:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENDER_CHEST:
@ -2268,6 +2270,38 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl
bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & 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;
}
if ((*itr)->GetBlockType() != E_BLOCK_COMMAND_BLOCK)
{
// 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;
}
// The correct block entity is here,
if (a_Callback.Item((cCommandBlockEntity *)*itr))
{
return false;
}
return true;
} // for itr - m_BlockEntitites[]
// Not found:
return false;
}
bool cChunk::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
// The blockentity list is locked by the parent chunkmap's CS

View File

@ -40,12 +40,13 @@ class cFluidSimulatorData;
class cMobCensus;
class cMobSpawner;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
@ -237,6 +238,9 @@ public:
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback);
/// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -1968,6 +1968,23 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNot
bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{
int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
cChunkDef::AbsoluteToRelative(BlockX, BlockY, BlockZ, ChunkX, ChunkZ);
cCSLock Lock(m_CSLayers);
cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ);
if ((Chunk == NULL) && !Chunk->IsValid())
{
return false;
}
return Chunk->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cChunkMap::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{

View File

@ -23,6 +23,7 @@ class cDropperEntity;
class cDropSpenserEntity;
class cFurnaceEntity;
class cNoteEntity;
class cCommandBlockEntity;
class cPawn;
class cPickup;
class cChunkDataSerializer;
@ -32,15 +33,16 @@ class cMobSpawner;
typedef std::list<cClientHandle *> cClientHandleList;
typedef cChunk * cChunkPtr;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cChunk> cChunkCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cDropperEntity> cDropperCallback;
typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cChunk> cChunkCallback;
@ -236,6 +238,9 @@ public:
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible
/// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -4,6 +4,7 @@
#include "RedstoneSimulator.h"
#include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../Entities/TNTEntity.h"
#include "../Blocks/BlockTorch.h"
#include "../Blocks/BlockDoor.h"
@ -215,11 +216,12 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
{
case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TNT: HandleTNT(a_X, dataitr->y, a_Z); break;
case E_BLOCK_TRAPDOOR: HandleTrapdoor(a_X, dataitr->y, a_Z); break;
case E_BLOCK_REDSTONE_WIRE: HandleRedstoneWire(a_X, dataitr->y, a_Z); break;
case E_BLOCK_NOTE_BLOCK: HandleNoteBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_DAYLIGHT_SENSOR: HandleDaylightSensor(a_X, dataitr->y, a_Z); break;
case E_BLOCK_COMMAND_BLOCK: HandleCommandBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
@ -763,6 +765,29 @@ void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
void cRedstoneSimulator::HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ)
{
class cSetPowerToCommandBlock :
public cCommandBlockCallback
{
bool m_IsPowered;
public:
cSetPowerToCommandBlock(bool a_IsPowered) : m_IsPowered(a_IsPowered) {}
virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
{
a_CommandBlock->SetRedstonePower(m_IsPowered);
return false;
}
} CmdBlockSP (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ));
m_World.DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockSP);
}
void cRedstoneSimulator::HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType)
{
switch (a_MyType)

View File

@ -110,6 +110,8 @@ private:
void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
/** Handles doords */
void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Handles command blocks */
void HandleCommandBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Handles activator, detector, and powered rails */
void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
/** Handles trapdoors */
@ -166,6 +168,7 @@ private:
switch (Block)
{
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_PISTON:
case E_BLOCK_STICKY_PISTON:
case E_BLOCK_DISPENSER:
@ -220,6 +223,7 @@ private:
case E_BLOCK_ACTIVATOR_RAIL:
case E_BLOCK_ACTIVE_COMPARATOR:
case E_BLOCK_BLOCK_OF_REDSTONE:
case E_BLOCK_COMMAND_BLOCK:
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_DISPENSER:
case E_BLOCK_DAYLIGHT_SENSOR:

View File

@ -1149,6 +1149,15 @@ bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBl
bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{
return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
}
bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4)
{
return m_ChunkMap->GetSignLines(a_BlockX, a_BlockY, a_BlockZ, a_Line1, a_Line2, a_Line3, a_Line4);

View File

@ -46,12 +46,13 @@ class cMobCensus;
typedef std::list< cPlayer * > cPlayerList;
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
@ -466,6 +467,9 @@ public:
/// Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp
/// Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // TODO: Export
/// Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp