1
0

Added basic ender chests

Note that they just mirror chests now, so no per player inventory.
This commit is contained in:
Tiger Wang 2013-12-07 00:18:58 +00:00
parent 30ead79049
commit 347e80bdd8
12 changed files with 363 additions and 14 deletions

View File

@ -224,6 +224,7 @@
<ResourceCompile Include="MCServer.rc" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\BlockEntities\EnderChestEntity.h" />
<ClInclude Include="resource_MCServer.h" />
<ClInclude Include="..\src\Authenticator.h" />
<ClInclude Include="..\src\BlockArea.h" />
@ -615,6 +616,7 @@
<ItemGroup>
<ClCompile Include="..\src\Authenticator.cpp" />
<ClCompile Include="..\src\BlockArea.cpp" />
<ClCompile Include="..\src\BlockEntities\EnderChestEntity.cpp" />
<ClCompile Include="..\src\BlockID.cpp" />
<ClCompile Include="..\src\BoundingBox.cpp" />
<ClCompile Include="..\src\ByteBuffer.cpp" />

View File

@ -945,6 +945,9 @@
<ClInclude Include="..\src\HTTPServer\NameValueParser.h">
<Filter>Source Files\HTTPServer</Filter>
</ClInclude>
<ClInclude Include="..\src\BlockEntities\EnderChestEntity.h">
<Filter>Source Files\BlockEntities</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\webadmin\template.html">
@ -1654,6 +1657,9 @@
<ClCompile Include="..\src\HTTPServer\NameValueParser.cpp">
<Filter>Source Files\HTTPServer</Filter>
</ClCompile>
<ClCompile Include="..\src\BlockEntities\EnderChestEntity.cpp">
<Filter>Source Files\BlockEntities</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="..\MCServer\API.txt">

View File

@ -8,6 +8,7 @@
#include "ChestEntity.h"
#include "DispenserEntity.h"
#include "DropperEntity.h"
#include "EnderChestEntity.h"
#include "FurnaceEntity.h"
#include "HopperEntity.h"
#include "JukeboxEntity.h"
@ -23,8 +24,9 @@ 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_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);

View File

@ -0,0 +1,130 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "EnderChestEntity.h"
#include "../Item.h"
#include "../Entities/Player.h"
#include "../UI/Window.h"
#include "json/json.h"
cEnderChestEntity::cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
super(E_BLOCK_ENDER_CHEST, a_BlockX, a_BlockY, a_BlockZ, ContentsWidth, ContentsHeight, a_World)
{
cBlockEntityWindowOwner::SetBlockEntity(this);
}
cEnderChestEntity::~cEnderChestEntity()
{
cWindow * Window = GetWindow();
if (Window != NULL)
{
Window->OwnerDestroyed();
}
}
bool cEnderChestEntity::LoadFromJson(const Json::Value & a_Value)
{
m_PosX = a_Value.get("x", 0).asInt();
m_PosY = a_Value.get("y", 0).asInt();
m_PosZ = a_Value.get("z", 0).asInt();
Json::Value AllSlots = a_Value.get("Slots", 0);
int SlotIdx = 0;
for (Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr)
{
cItem Item;
Item.FromJson(*itr);
SetSlot(SlotIdx, Item);
SlotIdx++;
}
return true;
}
void cEnderChestEntity::SaveToJson(Json::Value & a_Value)
{
a_Value["x"] = m_PosX;
a_Value["y"] = m_PosY;
a_Value["z"] = m_PosZ;
Json::Value AllSlots;
for (int i = m_Contents.GetNumSlots() - 1; i >= 0; i--)
{
Json::Value Slot;
m_Contents.GetSlot(i).GetJson(Slot);
AllSlots.append(Slot);
}
a_Value["Slots"] = AllSlots;
}
void cEnderChestEntity::SendTo(cClientHandle & a_Client)
{
// The chest entity doesn't need anything sent to the client when it's created / gets in the viewdistance
// All the actual handling is in the cWindow UI code that gets called when the chest is rclked
UNUSED(a_Client);
}
void cEnderChestEntity::UsedBy(cPlayer * a_Player)
{
// If the window is not created, open it anew:
cWindow * Window = GetWindow();
if (Window == NULL)
{
OpenNewWindow();
Window = GetWindow();
}
// Open the window for the player:
if (Window != NULL)
{
if (a_Player->GetWindow() != Window)
{
a_Player->OpenWindow(Window);
}
}
// This is rather a hack
// Instead of marking the chunk as dirty upon chest contents change, we mark it dirty now
// We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first.
// The few false positives aren't much to worry about
int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ);
m_World->MarkChunkDirty(ChunkX, ChunkZ);
}
void cEnderChestEntity::OpenNewWindow(void)
{
OpenWindow(new cEnderChestWindow(this));
}

View File

@ -0,0 +1,59 @@
#pragma once
#include "BlockEntityWithItems.h"
#include "../UI/WindowOwner.h"
namespace Json
{
class Value;
};
class cClientHandle;
class cServer;
class cNBTData;
class cEnderChestEntity : // tolua_export
public cBlockEntityWindowOwner,
// tolua_begin
public cBlockEntityWithItems
{
typedef cBlockEntityWithItems super;
public:
enum {
ContentsHeight = 3,
ContentsWidth = 9,
} ;
// tolua_end
/// Constructor used for normal operation
cEnderChestEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World);
virtual ~cEnderChestEntity();
static const char * GetClassStatic(void) { return "cEnderChestEntity"; }
bool LoadFromJson(const Json::Value & a_Value);
// cBlockEntity overrides:
virtual void SaveToJson(Json::Value & a_Value) override;
virtual void SendTo(cClientHandle & a_Client) override;
virtual void UsedBy(cPlayer * a_Player) override;
/// Opens a new chest window for this chest. Scans for neighbors to open a double chest window, if appropriate.
void OpenNewWindow(void);
} ; // tolua_export

View File

@ -1,18 +1,18 @@
#pragma once
#include "BlockHandler.h"
#include "BlockEntity.h"
class cBlockEnderchestHandler :
public cBlockHandler
public cBlockEntityHandler
{
public:
cBlockEnderchestHandler(BLOCKTYPE a_BlockType)
: cBlockHandler(a_BlockType)
: cBlockEntityHandler(a_BlockType)
{
}
@ -21,6 +21,49 @@ public:
//todo: Drop Ender Chest if using silk touch pickaxe
a_Pickups.push_back(cItem(E_BLOCK_OBSIDIAN, 8, 0));
}
virtual bool GetPlacementBlockTypeMeta(
cWorld * a_World, cPlayer * a_Player,
int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace,
int a_CursorX, int a_CursorY, int a_CursorZ,
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
a_BlockType = m_BlockType;
a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
return true;
}
virtual const char * GetStepSound(void) override
{
return "step.stone";
}
static NIBBLETYPE RotationToMetaData(double a_Rotation)
{
a_Rotation += 90 + 45; // So its not aligned with axis
if (a_Rotation > 360.f)
{
a_Rotation -= 360.f;
}
if ((a_Rotation >= 0.f) && (a_Rotation < 90.f))
{
return 0x4;
}
else if ((a_Rotation >= 180) && (a_Rotation < 270))
{
return 0x5;
}
else if ((a_Rotation >= 90) && (a_Rotation < 180))
{
return 0x2;
}
else
{
return 0x3;
}
}
} ;

View File

@ -4,7 +4,6 @@
#include "BlockEntity.h"
#include "../World.h"
#include "../Piston.h"
#include "../Entities/Player.h"

View File

@ -1301,6 +1301,7 @@ void cChunk::CreateBlockEntities(void)
case E_BLOCK_CHEST:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENDER_CHEST:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_FURNACE:
case E_BLOCK_HOPPER:
@ -1413,6 +1414,7 @@ void cChunk::SetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType,
case E_BLOCK_CHEST:
case E_BLOCK_DISPENSER:
case E_BLOCK_DROPPER:
case E_BLOCK_ENDER_CHEST:
case E_BLOCK_LIT_FURNACE:
case E_BLOCK_FURNACE:
case E_BLOCK_HOPPER:

View File

@ -8,6 +8,7 @@
#include "../Entities/Player.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/EnderChestEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
#include "../Items/ItemHandler.h"
#include "Window.h"
@ -556,6 +557,38 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaEnderChest:
cSlotAreaEnderChest::cSlotAreaEnderChest(cEnderChestEntity * a_EnderChest, cWindow & a_ParentWindow) :
cSlotArea(27, a_ParentWindow),
m_EnderChest(a_EnderChest)
{
}
const cItem * cSlotAreaEnderChest::GetSlot(int a_SlotNum, cPlayer & a_Player) const
{
// a_SlotNum ranges from 0 to 26, use that to index the chest entity's inventory directly:
return &(m_EnderChest->GetSlot(a_SlotNum));
}
void cSlotAreaEnderChest::SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item)
{
m_EnderChest->SetSlot(a_SlotNum, a_Item);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaFurnace:

View File

@ -16,6 +16,7 @@ class cWindow;
class cPlayer;
class cChestEntity;
class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cCraftingRecipe;
@ -286,6 +287,23 @@ protected:
class cSlotAreaEnderChest :
public cSlotArea
{
public:
cSlotAreaEnderChest(cEnderChestEntity * a_EnderChest, cWindow & a_ParentWindow);
virtual const cItem * GetSlot(int a_SlotNum, cPlayer & a_Player) const override;
virtual void SetSlot(int a_SlotNum, cPlayer & a_Player, const cItem & a_Item) override;
protected:
cEnderChestEntity * m_EnderChest;
};
class cSlotAreaFurnace :
public cSlotArea,
public cItemGrid::cListener

View File

@ -11,6 +11,7 @@
#include "../Items/ItemHandler.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/DropSpenserEntity.h"
#include "../BlockEntities/EnderChestEntity.h"
#include "../BlockEntities/HopperEntity.h"
@ -853,6 +854,43 @@ cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ,
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cEnderChestWindow:
cEnderChestWindow::cEnderChestWindow(cEnderChestEntity * a_EnderChest) :
cWindow(wtChest, "Ender Chest"),
m_World(a_EnderChest->GetWorld()),
m_BlockX(a_EnderChest->GetPosX()),
m_BlockY(a_EnderChest->GetPosY()),
m_BlockZ(a_EnderChest->GetPosZ())
{
m_SlotAreas.push_back(new cSlotAreaEnderChest(a_EnderChest, *this));
m_SlotAreas.push_back(new cSlotAreaInventory(*this));
m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
// Play the opening sound:
m_World->BroadcastSoundEffect("random.chestopen", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
// Send out the chest-open packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_ENDER_CHEST);
}
cEnderChestWindow::~cEnderChestWindow()
{
// Send out the chest-close packet:
m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_ENDER_CHEST);
m_World->BroadcastSoundEffect("random.chestclosed", m_BlockX * 8, m_BlockY * 8, m_BlockZ * 8, 1, 1);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHopperWindow:

View File

@ -20,6 +20,7 @@ class cWindowOwner;
class cClientHandle;
class cChestEntity;
class cDropSpenserEntity;
class cEnderChestEntity;
class cFurnaceEntity;
class cHopperEntity;
class cSlotArea;
@ -283,6 +284,22 @@ protected:
class cEnderChestWindow :
public cWindow
{
public:
cEnderChestWindow(cEnderChestEntity * a_EnderChest);
~cEnderChestWindow();
protected:
cWorld * m_World;
int m_BlockX, m_BlockY, m_BlockZ; // Position of the enderchest, for the window-close packet
};
class cInventoryWindow :
public cWindow
{