From f58c3f2e81e5cef689cf4b60a2616d062ee8edf6 Mon Sep 17 00:00:00 2001 From: "madmaxoft@gmail.com" Date: Sun, 23 Sep 2012 17:19:34 +0000 Subject: Source files cleanup: UI files renamed git-svn-id: http://mc-server.googlecode.com/svn/trunk@878 0a769ca7-a7f5-676a-18bf-c427514a06d6 --- source/Protocol125.cpp | 2 +- source/Protocol132.cpp | 2 +- source/UI/SlotArea.cpp | 2 +- source/UI/Window.cpp | 448 ++++++++++++++++++++++++++++++++++++++++ source/UI/Window.h | 181 +++++++++++++++++ source/UI/WindowOwner.h | 125 ++++++++++++ source/UI/cWindow.cpp | 451 ----------------------------------------- source/UI/cWindow.h | 181 ----------------- source/UI/cWindowOwner.h | 125 ------------ source/blocks/BlockWorkbench.h | 2 +- source/cChestEntity.cpp | 2 +- source/cChestEntity.h | 2 +- source/cClientHandle.cpp | 4 +- source/cFurnaceEntity.cpp | 2 +- source/cFurnaceEntity.h | 2 +- source/cInventory.cpp | 2 +- source/cPlayer.cpp | 4 +- 17 files changed, 767 insertions(+), 770 deletions(-) create mode 100644 source/UI/Window.cpp create mode 100644 source/UI/Window.h create mode 100644 source/UI/WindowOwner.h delete mode 100644 source/UI/cWindow.cpp delete mode 100644 source/UI/cWindow.h delete mode 100644 source/UI/cWindowOwner.h (limited to 'source') diff --git a/source/Protocol125.cpp b/source/Protocol125.cpp index 09e422c48..27b559ee1 100644 --- a/source/Protocol125.cpp +++ b/source/Protocol125.cpp @@ -20,7 +20,7 @@ Documentation: #include "cPickup.h" #include "cPlayer.h" #include "cChatColor.h" -#include "UI/cWindow.h" +#include "UI/Window.h" #include "cRoot.h" #include "cServer.h" diff --git a/source/Protocol132.cpp b/source/Protocol132.cpp index 48ecff0b2..b34ff485a 100644 --- a/source/Protocol132.cpp +++ b/source/Protocol132.cpp @@ -13,7 +13,7 @@ #include "ChunkDataSerializer.h" #include "cPlayer.h" #include "cMonster.h" -#include "UI/cWindow.h" +#include "UI/Window.h" diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 6da0a15b8..655f85524 100644 --- a/source/UI/SlotArea.cpp +++ b/source/UI/SlotArea.cpp @@ -9,7 +9,7 @@ #include "../cChestEntity.h" #include "../cFurnaceEntity.h" #include "../Items/Item.h" -#include "cWindow.h" +#include "Window.h" #include "../CraftingRecipes.h" #include "../cRoot.h" diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp new file mode 100644 index 000000000..e6c7a9feb --- /dev/null +++ b/source/UI/Window.cpp @@ -0,0 +1,448 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Window.h" +#include "../cItem.h" +#include "../cClientHandle.h" +#include "../cPlayer.h" +#include "../cPickup.h" +#include "../cInventory.h" +#include "WindowOwner.h" +#include "../items/Item.h" +#include "SlotArea.h" +#include "../cChestEntity.h" + + + + + +char cWindow::m_WindowIDCounter = 1; + + + + + +cWindow::cWindow(cWindow::WindowType a_WindowType, const AString & a_WindowTitle) + : m_WindowID(1 + (m_WindowIDCounter++ % 127)) + , m_WindowType(a_WindowType) + , m_WindowTitle(a_WindowTitle) + , m_Owner(NULL) + , m_IsDestroyed(false) +{ + if (a_WindowType == Inventory) + { + m_WindowID = 0; + } +} + + + + + +cWindow::~cWindow() +{ +} + + + + + +int cWindow::GetNumSlots(void) const +{ + int res = 0; + for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + res += (*itr)->GetNumSlots(); + } // for itr - m_SlotAreas[] + return res; +} + + + + + +void cWindow::GetSlots(cPlayer & a_Player, cItems & a_Slots) const +{ + a_Slots.clear(); + a_Slots.reserve(GetNumSlots()); + for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + int NumSlots = (*itr)->GetNumSlots(); + for (int i = 0; i < NumSlots; i++) + { + + const cItem * Item = (*itr)->GetSlot(i, a_Player); + if (Item == NULL) + { + a_Slots.push_back(cItem()); + } + else + { + a_Slots.push_back(*Item); + } + } + } // for itr - m_SlotAreas[] +} + + + + + +void cWindow::Clicked( + cPlayer & a_Player, + int a_WindowID, short a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, + const cItem & a_ClickedItem +) +{ + if (a_WindowID != m_WindowID) + { + LOG("WRONG WINDOW ID! (exp %d, got %d) received from \"%s\"", m_WindowID, a_WindowID, a_Player.GetName().c_str()); + return; + } + + if (a_SlotNum == -999) // Outside window click + { + if (a_IsRightClick) + { + a_Player.TossItem(true); + } + else + { + a_Player.TossItem(true, a_Player.GetDraggingItem().m_ItemCount); + } + return; + } + + int LocalSlotNum = a_SlotNum; + int idx = 0; + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (LocalSlotNum < (*itr)->GetNumSlots()) + { + (*itr)->Clicked(a_Player, LocalSlotNum, a_IsRightClick, a_IsShiftPressed, a_ClickedItem); + return; + } + LocalSlotNum -= (*itr)->GetNumSlots(); + idx++; + } + + LOGWARNING("Slot number higher than available window slots: %d, max %d received from \"%s\"; ignoring.", + a_SlotNum, GetNumSlots(), a_Player.GetName().c_str() + ); +} + + + + + +void cWindow::OpenedByPlayer(cPlayer & a_Player) +{ + { + cCSLock Lock(m_CS); + // If player is already in OpenedBy remove player first + m_OpenedBy.remove(&a_Player); + // Then add player + m_OpenedBy.push_back(&a_Player); + + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + (*itr)->OnPlayerAdded(a_Player); + } // for itr - m_SlotAreas[] + } + + // TODO: Notify all areas that a new player has opened the window + + a_Player.GetClientHandle()->SendWindowOpen(m_WindowID, m_WindowType, m_WindowTitle, GetNumSlots() - c_NumInventorySlots); +} + + + + + +void cWindow::ClosedByPlayer(cPlayer & a_Player) +{ + ASSERT(m_WindowType != Inventory); // Inventory windows must not be closed (the client would repeat the close packet, looping forever) + + // Checks whether the player is still holding an item + if (a_Player.IsDraggingItem()) + { + LOGD("Player holds item! Dropping it..."); + a_Player.TossItem(true, a_Player.GetDraggingItem().m_ItemCount); + } + + cClientHandle * ClientHandle = a_Player.GetClientHandle(); + if (ClientHandle != NULL) + { + ClientHandle->SendWindowClose(m_WindowID); + } + + { + cCSLock Lock(m_CS); + + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + (*itr)->OnPlayerRemoved(a_Player); + } // for itr - m_SlotAreas[] + + m_OpenedBy.remove(&a_Player); + if (m_OpenedBy.empty()) + { + Destroy(); + } + } + if (m_IsDestroyed) + { + delete this; + } +} + + + + + +void cWindow::OwnerDestroyed() +{ + m_Owner = NULL; + // Close window for each player. Note that the last one needs special handling + while (m_OpenedBy.size() > 1) + { + (*m_OpenedBy.begin() )->CloseWindow((char)GetWindowType()); + } + (*m_OpenedBy.begin() )->CloseWindow((char)GetWindowType()); +} + + + + + +bool cWindow::ForEachPlayer(cItemCallback & a_Callback) +{ + cCSLock Lock(m_CS); + for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) + { + if (a_Callback.Item(*itr)) + { + return false; + } + } // for itr - m_OpenedBy[] + return true; +} + + + + + +bool cWindow::ForEachClient(cItemCallback & a_Callback) +{ + cCSLock Lock(m_CS); + for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) + { + if (a_Callback.Item((*itr)->GetClientHandle())) + { + return false; + } + } // for itr - m_OpenedBy[] + return true; +} + + + + + +void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply) +{ + // Ask each slot area to take as much of the stack as it can. + // First ask only slots that already have the same kind of item + // Then ask any remaining slots + for (int Pass = 0; Pass < 2; ++Pass) + { + // First distribute into the hotbar: + if (a_ExcludeArea != m_SlotAreas.back()) + { + m_SlotAreas.back()->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); + if (a_ItemStack.IsEmpty()) + { + // Distributed it all + return; + } + } + // The distribute to all other areas: + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end() - 1; itr != end; ++itr) + { + if (*itr == a_ExcludeArea) + { + continue; + } + (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); + if (a_ItemStack.IsEmpty()) + { + // Distributed it all + return; + } + } // for itr - m_SlotAreas[] + } // for Pass - repeat twice +} + + + + + +void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum) +{ + int SlotBase = 0; + bool Found = false; + for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) + { + if (*itr == a_SlotArea) + { + Found = true; + break; + } + SlotBase += (*itr)->GetNumSlots(); + } // for itr - m_SlotAreas[] + if (!Found) + { + LOGERROR("cWindow::SendSlot(): unknown a_SlotArea"); + ASSERT(!"cWindow::SendSlot(): unknown a_SlotArea"); + return; + } + + a_Player.GetClientHandle()->SendInventorySlot( + m_WindowID, a_RelativeSlotNum + SlotBase, *(a_SlotArea->GetSlot(a_RelativeSlotNum, a_Player)) + ); +} + + + + + +void cWindow::Destroy(void) +{ + if (m_Owner != NULL) + { + m_Owner->CloseWindow(); + m_Owner = NULL; + } + m_IsDestroyed = true; +} + + + + + +void cWindow::SendWholeWindow(cClientHandle & a_Client) +{ + a_Client.SendWholeInventory(*this); +} + + + + + +void cWindow::BroadcastWholeWindow(void) +{ + cCSLock Lock(m_CS); + for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) + { + SendWholeWindow(*(*itr)->GetClientHandle()); + } // for itr - m_OpenedBy[] +} + + + + + +void cWindow::BroadcastInventoryProgress(short a_Progressbar, short a_Value) +{ + cCSLock Lock(m_CS); + for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) + { + (*itr)->GetClientHandle()->SendInventoryProgress(m_WindowID, a_Progressbar, a_Value); + } // for itr - m_OpenedBy[] +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cInventoryWindow: + +cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : + cWindow(cWindow::Inventory, "MCS-Inventory"), + m_Player(a_Player) +{ + m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers + m_SlotAreas.push_back(new cSlotAreaArmor(*this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cCraftingWindow: + +cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : + cWindow(cWindow::Workbench, "MCS-Workbench") +{ + m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cChestWindow: + +cChestWindow::cChestWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cChestEntity * a_Chest) : + cWindow(cWindow::Chest, "MCS-Chest"), + m_World(a_Chest->GetWorld()), + m_BlockX(a_BlockX), + m_BlockY(a_BlockY), + m_BlockZ(a_BlockZ) +{ + m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this)); + + // TODO: Double chests + + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); + + // Send out the chest-open packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST); +} + + + + + +cChestWindow::~cChestWindow() +{ + // Send out the chest-close packet: + m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_CHEST); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cFurnaceWindow: + +cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : + cWindow(cWindow::Furnace, "MCS-Furnace") +{ + m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this)); + m_SlotAreas.push_back(new cSlotAreaInventory(*this)); + m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); +} + + + + diff --git a/source/UI/Window.h b/source/UI/Window.h new file mode 100644 index 000000000..b3df1bc86 --- /dev/null +++ b/source/UI/Window.h @@ -0,0 +1,181 @@ + +// Window.h + +// Interfaces to the cWindow class representing a UI window for a specific block + + + + + +#pragma once + +#include "../cItem.h" + + + + + +class cPlayer; +class cWindowOwner; +class cClientHandle; +class cChestEntity; +class cFurnaceEntity; +class cSlotArea; +class cWorld; + +typedef std::list cPlayerList; +typedef std::vector cSlotAreas; + + + + + +/** +Represents a UI window. + +Each window has a list of players that are currently using it +When there's no player using a window, it is destroyed. +A window consists of several areas of slots with similar functionality - for example the crafting grid area, or +the inventory area. Each area knows what its slots are (GetSlot() function) and can handle mouse clicks. +The window acts only as a top-level container for those areas, redirecting the click events to the correct areas. +*/ +class cWindow +{ +public: + enum WindowType + { + Inventory = -1, // This value is never actually sent to a client + Chest = 0, + Workbench = 1, + Furnace = 2, + Dispenser = 3, + Enchantment = 4, + Brewery = 5 + }; + + static const int c_NumInventorySlots = 36; + + cWindow(WindowType a_WindowType, const AString & a_WindowTitle); + virtual ~cWindow(); + + char GetWindowID(void) const { return m_WindowID; } + int GetWindowType(void) const { return m_WindowType; } + + cWindowOwner * GetOwner() { return m_Owner; } + void SetOwner( cWindowOwner * a_Owner ) { m_Owner = a_Owner; } + + int GetNumSlots(void) const; + + /// Fills a_Slots with the slots read from m_SlotAreas[], for the specified player + void GetSlots(cPlayer & a_Player, cItems & a_Slots) const; + + void Clicked( + cPlayer & a_Player, int a_WindowID, + short a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, + const cItem & a_ClickedItem + ); + + void OpenedByPlayer(cPlayer & a_Player); + void ClosedByPlayer(cPlayer & a_Player); + + void SendWholeWindow(cClientHandle & a_Client); + void BroadcastWholeWindow(void); + void BroadcastInventoryProgress(short a_Progressbar, short a_Value); + + const AString & GetWindowTitle() const { return m_WindowTitle; } + void SetWindowTitle(const AString & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; } + + void OwnerDestroyed(void); + + /// Calls the callback safely for each player that has this window open; returns true if all players have been enumerated + bool ForEachPlayer(cItemCallback & a_Callback); + + /// Calls the callback safely for each client that has this window open; returns true if all clients have been enumerated + bool ForEachClient(cItemCallback & a_Callback); + + /** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed! + if a_ShouldApply is true, the changes are written into the slots; + if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) + */ + void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); + + /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea + void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum); + +protected: + cSlotAreas m_SlotAreas; + +private: + char m_WindowID; + int m_WindowType; + AString m_WindowTitle; + + cCriticalSection m_CS; + cPlayerList m_OpenedBy; + + bool m_IsDestroyed; + + cWindowOwner * m_Owner; + + static char m_WindowIDCounter; + + void Destroy(void); +} ; + + + + + +class cCraftingWindow : + public cWindow +{ +public: + cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); +} ; + + + + + +class cFurnaceWindow : + public cWindow +{ +public: + cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace); +} ; + + + + + +class cChestWindow : + public cWindow +{ +public: + cChestWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cChestEntity * a_Chest); + ~cChestWindow(); + +protected: + cWorld * m_World; + int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet +} ; + + + + + +class cInventoryWindow : + public cWindow +{ +public: + cInventoryWindow(cPlayer & a_Player); + +protected: + cPlayer & m_Player; + +} ; + + + + + diff --git a/source/UI/WindowOwner.h b/source/UI/WindowOwner.h new file mode 100644 index 000000000..e0cc8da8a --- /dev/null +++ b/source/UI/WindowOwner.h @@ -0,0 +1,125 @@ + +#pragma once + +#include "../cBlockEntity.h" +#include "../cEntity.h" +#include "Window.h" + +/* +Being a descendant of cWindowOwner means that the class can own one window. That window can be +queried, opened by other players, closed by players and finally destroyed. +Also, a cWindowOwner can be queried for the block coords where the window is displayed. That will be used +for entities / players in motion to close their windows when they get too far away from the window "source". +*/ + + + + + +// class cWindow; + + + + + +/** +Base class for the window owning +*/ +class cWindowOwner +{ +public: + cWindowOwner() : + m_Window(NULL) + { + } + + void CloseWindow(void) + { + m_Window = NULL; + } + + void OpenWindow(cWindow * a_Window) + { + m_Window = a_Window; + m_Window->SetOwner(this); + } + + cWindow * GetWindow(void) const + { + return m_Window; + } + + /// Returns the block position at which the element owning the window is + virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) = 0; + +private: + cWindow * m_Window; +} ; + + + + + +/** +Window owner that is associated with a block entity (chest, furnace, ...) +*/ +class cBlockEntityWindowOwner : + public cWindowOwner +{ +public: + cBlockEntityWindowOwner(void) : + m_BlockEntity(NULL) + { + } + + void SetBlockEntity(cBlockEntity * a_BlockEntity) + { + m_BlockEntity = a_BlockEntity; + } + + virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override + { + a_BlockX = m_BlockEntity->GetPosX(); + a_BlockY = m_BlockEntity->GetPosY(); + a_BlockZ = m_BlockEntity->GetPosZ(); + } + +private: + cBlockEntity * m_BlockEntity; +} ; + + + + + +/** +Window owner that is associated with an entity (chest minecart) +*/ +class cEntityWindowOwner : + public cWindowOwner +{ +public: + cEntityWindowOwner(void) : + m_Entity(NULL) + { + } + + void SetEntity(cEntity * a_Entity) + { + m_Entity = a_Entity; + } + + virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override + { + a_BlockX = (int)(m_Entity->GetPosX()); + a_BlockY = (int)(m_Entity->GetPosY()); + a_BlockZ = (int)(m_Entity->GetPosZ()); + } + +private: + cEntity * m_Entity; +} ; + + + + diff --git a/source/UI/cWindow.cpp b/source/UI/cWindow.cpp deleted file mode 100644 index bd6724751..000000000 --- a/source/UI/cWindow.cpp +++ /dev/null @@ -1,451 +0,0 @@ - -#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules - -#include "cWindow.h" -#include "../cItem.h" -#include "../cClientHandle.h" -#include "../cPlayer.h" -#include "../cPickup.h" -#include "../cInventory.h" -#include "cWindowOwner.h" -#include "../items/Item.h" -#include "SlotArea.h" -#include "../cChestEntity.h" - - - - - -char cWindow::m_WindowIDCounter = 1; - - - - - -cWindow::cWindow(cWindow::WindowType a_WindowType, const AString & a_WindowTitle) - : m_WindowID(1 + (m_WindowIDCounter++ % 127)) - , m_WindowType(a_WindowType) - , m_WindowTitle(a_WindowTitle) - , m_Owner(NULL) - , m_IsDestroyed(false) -{ - if (a_WindowType == Inventory) - { - m_WindowID = 0; - } -} - - - - - -cWindow::~cWindow() -{ -} - - - - - -int cWindow::GetNumSlots(void) const -{ - int res = 0; - for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - res += (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - return res; -} - - - - - -void cWindow::GetSlots(cPlayer & a_Player, cItems & a_Slots) const -{ - a_Slots.clear(); - a_Slots.reserve(GetNumSlots()); - for (cSlotAreas::const_iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - int NumSlots = (*itr)->GetNumSlots(); - for (int i = 0; i < NumSlots; i++) - { - - const cItem * Item = (*itr)->GetSlot(i, a_Player); - if (Item == NULL) - { - a_Slots.push_back(cItem()); - } - else - { - a_Slots.push_back(*Item); - } - } - } // for itr - m_SlotAreas[] -} - - - - - -void cWindow::Clicked( - cPlayer & a_Player, - int a_WindowID, short a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, - const cItem & a_ClickedItem -) -{ - LOGD("cWindow::Clicked(): ID %d (exp %d), SlotNum %d", a_WindowID, m_WindowID, a_SlotNum); - - if (a_WindowID != m_WindowID) - { - LOG("WRONG WINDOW ID! (exp %d, got %d) received from \"%s\"", m_WindowID, a_WindowID, a_Player.GetName().c_str()); - return; - } - - if (a_SlotNum == -999) // Outside window click - { - if (a_IsRightClick) - { - a_Player.TossItem(true); - } - else - { - a_Player.TossItem(true, a_Player.GetDraggingItem().m_ItemCount); - } - return; - } - - int LocalSlotNum = a_SlotNum; - int idx = 0; - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (LocalSlotNum < (*itr)->GetNumSlots()) - { - LOGD("SlotArea #%d (%d slots) handling the click", idx, (*itr)->GetNumSlots()); - (*itr)->Clicked(a_Player, LocalSlotNum, a_IsRightClick, a_IsShiftPressed, a_ClickedItem); - return; - } - LocalSlotNum -= (*itr)->GetNumSlots(); - idx++; - } - - LOGWARNING("Slot number higher than available window slots: %d, max %d received from \"%s\"; ignoring.", - a_SlotNum, GetNumSlots(), a_Player.GetName().c_str() - ); -} - - - - - -void cWindow::OpenedByPlayer(cPlayer & a_Player) -{ - { - cCSLock Lock(m_CS); - // If player is already in OpenedBy remove player first - m_OpenedBy.remove(&a_Player); - // Then add player - m_OpenedBy.push_back(&a_Player); - - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - (*itr)->OnPlayerAdded(a_Player); - } // for itr - m_SlotAreas[] - } - - // TODO: Notify all areas that a new player has opened the window - - a_Player.GetClientHandle()->SendWindowOpen(m_WindowID, m_WindowType, m_WindowTitle, GetNumSlots() - c_NumInventorySlots); -} - - - - - -void cWindow::ClosedByPlayer(cPlayer & a_Player) -{ - ASSERT(m_WindowType != Inventory); // Inventory windows must not be closed (the client would repeat the close packet, looping forever) - - // Checks whether the player is still holding an item - if (a_Player.IsDraggingItem()) - { - LOGD("Player holds item! Dropping it..."); - a_Player.TossItem(true, a_Player.GetDraggingItem().m_ItemCount); - } - - cClientHandle * ClientHandle = a_Player.GetClientHandle(); - if (ClientHandle != NULL) - { - ClientHandle->SendWindowClose(m_WindowID); - } - - { - cCSLock Lock(m_CS); - - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - (*itr)->OnPlayerRemoved(a_Player); - } // for itr - m_SlotAreas[] - - m_OpenedBy.remove(&a_Player); - if (m_OpenedBy.empty()) - { - Destroy(); - } - } - if (m_IsDestroyed) - { - delete this; - } -} - - - - - -void cWindow::OwnerDestroyed() -{ - m_Owner = NULL; - // Close window for each player. Note that the last one needs special handling - while (m_OpenedBy.size() > 1) - { - (*m_OpenedBy.begin() )->CloseWindow((char)GetWindowType()); - } - (*m_OpenedBy.begin() )->CloseWindow((char)GetWindowType()); -} - - - - - -bool cWindow::ForEachPlayer(cItemCallback & a_Callback) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) - { - if (a_Callback.Item(*itr)) - { - return false; - } - } // for itr - m_OpenedBy[] - return true; -} - - - - - -bool cWindow::ForEachClient(cItemCallback & a_Callback) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr) - { - if (a_Callback.Item((*itr)->GetClientHandle())) - { - return false; - } - } // for itr - m_OpenedBy[] - return true; -} - - - - - -void cWindow::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply) -{ - // Ask each slot area to take as much of the stack as it can. - // First ask only slots that already have the same kind of item - // Then ask any remaining slots - for (int Pass = 0; Pass < 2; ++Pass) - { - // First distribute into the hotbar: - if (a_ExcludeArea != m_SlotAreas.back()) - { - m_SlotAreas.back()->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); - if (a_ItemStack.IsEmpty()) - { - // Distributed it all - return; - } - } - // The distribute to all other areas: - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end() - 1; itr != end; ++itr) - { - if (*itr == a_ExcludeArea) - { - continue; - } - (*itr)->DistributeStack(a_ItemStack, a_Player, a_ShouldApply, (Pass == 0)); - if (a_ItemStack.IsEmpty()) - { - // Distributed it all - return; - } - } // for itr - m_SlotAreas[] - } // for Pass - repeat twice -} - - - - - -void cWindow::SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum) -{ - int SlotBase = 0; - bool Found = false; - for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr) - { - if (*itr == a_SlotArea) - { - Found = true; - break; - } - SlotBase += (*itr)->GetNumSlots(); - } // for itr - m_SlotAreas[] - if (!Found) - { - LOGERROR("cWindow::SendSlot(): unknown a_SlotArea"); - ASSERT(!"cWindow::SendSlot(): unknown a_SlotArea"); - return; - } - - a_Player.GetClientHandle()->SendInventorySlot( - m_WindowID, a_RelativeSlotNum + SlotBase, *(a_SlotArea->GetSlot(a_RelativeSlotNum, a_Player)) - ); -} - - - - - -void cWindow::Destroy(void) -{ - if (m_Owner != NULL) - { - m_Owner->CloseWindow(); - m_Owner = NULL; - } - m_IsDestroyed = true; -} - - - - - -void cWindow::SendWholeWindow(cClientHandle & a_Client) -{ - a_Client.SendWholeInventory(*this); -} - - - - - -void cWindow::BroadcastWholeWindow(void) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) - { - SendWholeWindow(*(*itr)->GetClientHandle()); - } // for itr - m_OpenedBy[] -} - - - - - -void cWindow::BroadcastInventoryProgress(short a_Progressbar, short a_Value) -{ - cCSLock Lock(m_CS); - for (cPlayerList::iterator itr = m_OpenedBy.begin(); itr != m_OpenedBy.end(); ++itr) - { - (*itr)->GetClientHandle()->SendInventoryProgress(m_WindowID, a_Progressbar, a_Value); - } // for itr - m_OpenedBy[] -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cInventoryWindow: - -cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : - cWindow(cWindow::Inventory, "MCS-Inventory"), - m_Player(a_Player) -{ - m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers - m_SlotAreas.push_back(new cSlotAreaArmor(*this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cCraftingWindow: - -cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : - cWindow(cWindow::Workbench, "MCS-Workbench") -{ - m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cChestWindow: - -cChestWindow::cChestWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cChestEntity * a_Chest) : - cWindow(cWindow::Chest, "MCS-Chest"), - m_World(a_Chest->GetWorld()), - m_BlockX(a_BlockX), - m_BlockY(a_BlockY), - m_BlockZ(a_BlockZ) -{ - m_SlotAreas.push_back(new cSlotAreaChest(a_Chest, *this)); - - // TODO: Double chests - - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); - - // Send out the chest-open packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 1, E_BLOCK_CHEST); -} - - - - - -cChestWindow::~cChestWindow() -{ - // Send out the chest-close packet: - m_World->BroadcastBlockAction(m_BlockX, m_BlockY, m_BlockZ, 1, 0, E_BLOCK_CHEST); -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cFurnaceWindow: - -cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : - cWindow(cWindow::Furnace, "MCS-Furnace") -{ - m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this)); - m_SlotAreas.push_back(new cSlotAreaInventory(*this)); - m_SlotAreas.push_back(new cSlotAreaHotBar(*this)); -} - - - - diff --git a/source/UI/cWindow.h b/source/UI/cWindow.h deleted file mode 100644 index 0fc368c9c..000000000 --- a/source/UI/cWindow.h +++ /dev/null @@ -1,181 +0,0 @@ - -// cWindow.h - -// Interfaces to the cWindow class representing a UI window for a specific block - - - - - -#pragma once - -#include "../cItem.h" - - - - - -class cPlayer; -class cWindowOwner; -class cClientHandle; -class cChestEntity; -class cFurnaceEntity; -class cSlotArea; -class cWorld; - -typedef std::list cPlayerList; -typedef std::vector cSlotAreas; - - - - - -/** -Represents a UI window. - -Each window has a list of players that are currently using it -When there's no player using a window, it is destroyed. -A window consists of several areas of slots with similar functionality - for example the crafting grid area, or -the inventory area. Each area knows what its slots are (GetSlot() function) and can handle mouse clicks. -The window acts only as a top-level container for those areas, redirecting the click events to the correct areas. -*/ -class cWindow -{ -public: - enum WindowType - { - Inventory = -1, // This value is never actually sent to a client - Chest = 0, - Workbench = 1, - Furnace = 2, - Dispenser = 3, - Enchantment = 4, - Brewery = 5 - }; - - static const int c_NumInventorySlots = 36; - - cWindow(WindowType a_WindowType, const AString & a_WindowTitle); - virtual ~cWindow(); - - char GetWindowID(void) const { return m_WindowID; } - int GetWindowType(void) const { return m_WindowType; } - - cWindowOwner * GetOwner() { return m_Owner; } - void SetOwner( cWindowOwner * a_Owner ) { m_Owner = a_Owner; } - - int GetNumSlots(void) const; - - /// Fills a_Slots with the slots read from m_SlotAreas[], for the specified player - void GetSlots(cPlayer & a_Player, cItems & a_Slots) const; - - void Clicked( - cPlayer & a_Player, int a_WindowID, - short a_SlotNum, bool a_IsRightClick, bool a_IsShiftPressed, - const cItem & a_ClickedItem - ); - - void OpenedByPlayer(cPlayer & a_Player); - void ClosedByPlayer(cPlayer & a_Player); - - void SendWholeWindow(cClientHandle & a_Client); - void BroadcastWholeWindow(void); - void BroadcastInventoryProgress(short a_Progressbar, short a_Value); - - const AString & GetWindowTitle() const { return m_WindowTitle; } - void SetWindowTitle(const AString & a_WindowTitle ) { m_WindowTitle = a_WindowTitle; } - - void OwnerDestroyed(void); - - /// Calls the callback safely for each player that has this window open; returns true if all players have been enumerated - bool ForEachPlayer(cItemCallback & a_Callback); - - /// Calls the callback safely for each client that has this window open; returns true if all clients have been enumerated - bool ForEachClient(cItemCallback & a_Callback); - - /** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed! - if a_ShouldApply is true, the changes are written into the slots; - if a_ShouldApply is false, only a_ItemStack is modified to reflect the number of fits (for fit-testing purposes) - */ - void DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, cSlotArea * a_ExcludeArea, bool a_ShouldApply); - - /// Used by cSlotAreas to send individual slots to clients, a_RelativeSlotNum is the slot number relative to a_SlotArea - void SendSlot(cPlayer & a_Player, cSlotArea * a_SlotArea, int a_RelativeSlotNum); - -protected: - cSlotAreas m_SlotAreas; - -private: - char m_WindowID; - int m_WindowType; - AString m_WindowTitle; - - cCriticalSection m_CS; - cPlayerList m_OpenedBy; - - bool m_IsDestroyed; - - cWindowOwner * m_Owner; - - static char m_WindowIDCounter; - - void Destroy(void); -} ; - - - - - -class cCraftingWindow : - public cWindow -{ -public: - cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ); -} ; - - - - - -class cFurnaceWindow : - public cWindow -{ -public: - cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace); -} ; - - - - - -class cChestWindow : - public cWindow -{ -public: - cChestWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cChestEntity * a_Chest); - ~cChestWindow(); - -protected: - cWorld * m_World; - int m_BlockX, m_BlockY, m_BlockZ; // Position of the chest, for the window-close packet -} ; - - - - - -class cInventoryWindow : - public cWindow -{ -public: - cInventoryWindow(cPlayer & a_Player); - -protected: - cPlayer & m_Player; - -} ; - - - - - diff --git a/source/UI/cWindowOwner.h b/source/UI/cWindowOwner.h deleted file mode 100644 index 1ce03ed30..000000000 --- a/source/UI/cWindowOwner.h +++ /dev/null @@ -1,125 +0,0 @@ - -#pragma once - -#include "../cBlockEntity.h" -#include "../cEntity.h" -#include "cWindow.h" - -/* -Being a descendant of cWindowOwner means that the class can own one window. That window can be -queried, opened by other players, closed by players and finally destroyed. -Also, a cWindowOwner can be queried for the block coords where the window is displayed. That will be used -for entities / players in motion to close their windows when they get too far away from the window "source". -*/ - - - - - -// class cWindow; - - - - - -/** -Base class for the window owning -*/ -class cWindowOwner -{ -public: - cWindowOwner() : - m_Window(NULL) - { - } - - void CloseWindow(void) - { - m_Window = NULL; - } - - void OpenWindow(cWindow * a_Window) - { - m_Window = a_Window; - m_Window->SetOwner(this); - } - - cWindow * GetWindow(void) const - { - return m_Window; - } - - /// Returns the block position at which the element owning the window is - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) = 0; - -private: - cWindow * m_Window; -} ; - - - - - -/** -Window owner that is associated with a block entity (chest, furnace, ...) -*/ -class cBlockEntityWindowOwner : - public cWindowOwner -{ -public: - cBlockEntityWindowOwner(void) : - m_BlockEntity(NULL) - { - } - - void SetBlockEntity(cBlockEntity * a_BlockEntity) - { - m_BlockEntity = a_BlockEntity; - } - - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override - { - a_BlockX = m_BlockEntity->GetPosX(); - a_BlockY = m_BlockEntity->GetPosY(); - a_BlockZ = m_BlockEntity->GetPosZ(); - } - -private: - cBlockEntity * m_BlockEntity; -} ; - - - - - -/** -Window owner that is associated with an entity (chest minecart) -*/ -class cEntityWindowOwner : - public cWindowOwner -{ -public: - cEntityWindowOwner(void) : - m_Entity(NULL) - { - } - - void SetEntity(cEntity * a_Entity) - { - m_Entity = a_Entity; - } - - virtual void GetBlockPos(int & a_BlockX, int & a_BlockY, int & a_BlockZ) override - { - a_BlockX = (int)(m_Entity->GetPosX()); - a_BlockY = (int)(m_Entity->GetPosY()); - a_BlockZ = (int)(m_Entity->GetPosZ()); - } - -private: - cEntity * m_Entity; -} ; - - - - diff --git a/source/blocks/BlockWorkbench.h b/source/blocks/BlockWorkbench.h index 998e07d9b..776628382 100644 --- a/source/blocks/BlockWorkbench.h +++ b/source/blocks/BlockWorkbench.h @@ -1,6 +1,6 @@ #pragma once #include "Block.h" -#include "../UI/cWindow.h" +#include "../UI/Window.h" #include "../cPlayer.h" diff --git a/source/cChestEntity.cpp b/source/cChestEntity.cpp index 8914f5f41..659bd7083 100644 --- a/source/cChestEntity.cpp +++ b/source/cChestEntity.cpp @@ -5,7 +5,7 @@ #include "cItem.h" #include "cClientHandle.h" #include "cPlayer.h" -#include "UI/cWindow.h" +#include "UI/Window.h" #include "cWorld.h" #include "cRoot.h" #include "cPickup.h" diff --git a/source/cChestEntity.h b/source/cChestEntity.h index 962e9f86d..2f6301479 100644 --- a/source/cChestEntity.h +++ b/source/cChestEntity.h @@ -2,7 +2,7 @@ #pragma once #include "cBlockEntity.h" -#include "UI/cWindowOwner.h" +#include "UI/WindowOwner.h" diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 5802fc1d1..5aa06eb36 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -10,7 +10,7 @@ #include "cInventory.h" #include "cChestEntity.h" #include "cSignEntity.h" -#include "UI/cWindow.h" +#include "UI/Window.h" #include "cItem.h" #include "cTorch.h" #include "cDoors.h" @@ -1067,7 +1067,7 @@ void cClientHandle::Tick(float a_Dt) void cClientHandle::SendDisconnect(const AString & a_Reason) { - LOGD("Sending a DC"); + LOGD("Sending a DC: \"%s\"", a_Reason.c_str()); m_Protocol->SendDisconnect(a_Reason); } diff --git a/source/cFurnaceEntity.cpp b/source/cFurnaceEntity.cpp index 7ad088586..07df83452 100644 --- a/source/cFurnaceEntity.cpp +++ b/source/cFurnaceEntity.cpp @@ -4,7 +4,7 @@ #include "cFurnaceEntity.h" #include "BlockID.h" #include "cItem.h" -#include "UI/cWindow.h" +#include "UI/Window.h" #include "cPlayer.h" #include "cWorld.h" #include "cClientHandle.h" diff --git a/source/cFurnaceEntity.h b/source/cFurnaceEntity.h index 43bf615a6..60aec47af 100644 --- a/source/cFurnaceEntity.h +++ b/source/cFurnaceEntity.h @@ -2,7 +2,7 @@ #pragma once #include "cBlockEntity.h" -#include "UI/cWindowOwner.h" +#include "UI/WindowOwner.h" #include "cItem.h" diff --git a/source/cInventory.cpp b/source/cInventory.cpp index 1e0b4f6ae..41d4c14fa 100644 --- a/source/cInventory.cpp +++ b/source/cInventory.cpp @@ -4,7 +4,7 @@ #include "cInventory.h" #include "cPlayer.h" #include "cClientHandle.h" -#include "UI/cWindow.h" +#include "UI/Window.h" #include "cItem.h" #include "cRoot.h" diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index e0d1eef6e..65132296f 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -4,8 +4,8 @@ #include "cPlayer.h" #include "cServer.h" #include "cClientHandle.h" -#include "UI/cWindow.h" -#include "UI/cWindowOwner.h" +#include "UI/Window.h" +#include "UI/WindowOwner.h" #include "cWorld.h" #include "cPickup.h" #include "cPluginManager.h" -- cgit v1.2.3