Cuberite
A lightweight, fast and extensible game server for Minecraft
LuaWindow.cpp
Go to the documentation of this file.
1 // LuaWindow.cpp
2 
3 // Implements the cLuaWindow class representing a virtual window that plugins may create and open for the player
4 
5 #include "Globals.h"
6 #include "LuaWindow.h"
7 #include "../Entities/Player.h"
8 #include "../UI/SlotArea.h"
9 #include "PluginLua.h"
10 extern "C"
11 {
12  #include "lua/src/lauxlib.h" // Needed for LUA_REFNIL
13 }
14 #include "../Root.h"
15 #include "../ClientHandle.h"
16 
17 
18 
19 
21 // cLuaWindow:
22 
23 cLuaWindow::cLuaWindow(cLuaState & a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString & a_Title) :
24  Super(a_WindowType, a_Title),
25  m_Contents(a_SlotsX, a_SlotsY),
26  m_LuaState(a_LuaState.QueryCanonLuaState())
27 {
28  ASSERT(m_LuaState != nullptr); // We must have a valid Lua state; this assert fails only if there was no Canon Lua state
29 
30  m_Contents.AddListener(*this);
31  m_SlotAreas.push_back(new cSlotAreaItemGrid(m_Contents, *this));
32 
33  // If appropriate, add an Armor slot area:
34  switch (a_WindowType)
35  {
38  {
39  m_SlotAreas.push_back(new cSlotAreaArmor(*this));
40  break;
41  }
42  default:
43  {
44  break;
45  }
46  }
47  m_SlotAreas.push_back(new cSlotAreaInventory(*this));
48  m_SlotAreas.push_back(new cSlotAreaHotBar(*this));
49 }
50 
51 
52 
53 
54 
56 {
58 
59  // Close open lua window from players, to avoid dangling pointers
60  cRoot::Get()->ForEachPlayer([this](cPlayer & a_Player)
61  {
62  if (a_Player.GetWindow() == this)
63  {
64  a_Player.CloseWindow(false);
65  }
66  return false;
67  }
68  );
69 
70  // Must delete slot areas now, because they are referencing this->m_Contents and would try to access it in cWindow's
71  // destructor, when the member is already gone.
72  for (cSlotAreas::iterator itr = m_SlotAreas.begin(), end = m_SlotAreas.end(); itr != end; ++itr)
73  {
74  delete *itr;
75  }
76  m_SlotAreas.clear();
77 
78  ASSERT(m_OpenedBy.empty());
79 }
80 
81 
82 
83 
84 
86 {
87  // Only one Lua state can be a cLuaWindow object callback:
88  ASSERT(a_OnClicked->IsSameLuaState(*m_LuaState));
89 
90  // Store the new reference, releasing the old one if appropriate:
91  m_OnClicked = std::move(a_OnClicked);
92 }
93 
94 
95 
96 
97 
99 {
100  // Only one Lua state can be a cLuaWindow object callback:
101  ASSERT(a_OnClosing->IsSameLuaState(*m_LuaState));
102 
103  // Store the new reference, releasing the old one if appropriate:
104  m_OnClosing = std::move(a_OnClosing);
105 }
106 
107 
108 
109 
110 
112 {
113  // Only one Lua state can be a cLuaWindow object callback:
114  ASSERT(a_OnSlotChanged->IsSameLuaState(*m_LuaState));
115 
116  // Store the new reference, releasing the old one if appropriate:
117  m_OnSlotChanged = std::move(a_OnSlotChanged);
118 }
119 
120 
121 
122 
123 
125 {
126  // If the first player is opening the window, create a Lua Reference to the window object so that Lua will not GC it until the last player closes the window:
127  if (m_PlayerCount == 0)
128  {
130  }
131 
132  ++m_PlayerCount;
133  Super::OpenedByPlayer(a_Player);
134 }
135 
136 
137 
138 
139 
140 bool cLuaWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse)
141 {
142  // First notify the plugin through the registered callback:
143  if (m_OnClosing != nullptr)
144  {
145  bool res;
146  if (
147  m_OnClosing->Call(this, &a_Player, a_CanRefuse, cLuaState::Return, res) && // The callback succeeded
148  res // The callback says not to close the window
149  )
150  {
151  // The callback disagrees (the higher levels check the CanRefuse flag compliance)
152  return false;
153  }
154  }
155 
156  // If the last player has closed the window, release the Lua reference, so that Lua may GC the object:
157  --m_PlayerCount;
158  if (m_PlayerCount == 0)
159  {
160  m_LuaRef.UnRef();
161  }
162 
163  return Super::ClosedByPlayer(a_Player, a_CanRefuse);
164 }
165 
166 
167 
168 
169 
171 {
172  Super::Destroy();
173 
174  // Lua will take care of this object, it will garbage-collect it, so we must not delete it!
175  m_IsDestroyed = false;
176 }
177 
178 
179 
180 
181 
182 void cLuaWindow::DistributeStack(cItem & a_ItemStack, int a_Slot, cPlayer & a_Player, cSlotArea * a_ClickedArea, bool a_ShouldApply)
183 {
184  cSlotAreas Areas;
185  for (auto && Area : m_SlotAreas)
186  {
187  if (Area != a_ClickedArea)
188  {
189  Areas.push_back(Area);
190  }
191  }
192 
193  Super::DistributeStackToAreas(a_ItemStack, a_Player, Areas, a_ShouldApply, false);
194 }
195 
196 
197 
198 
199 
200 void cLuaWindow::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
201 {
202  ASSERT(a_ItemGrid == &m_Contents);
203 
204  // If an OnSlotChanged callback has been registered, call it:
205  if (m_OnSlotChanged != nullptr)
206  {
207  m_OnSlotChanged->Call(this, a_SlotNum);
208  }
209 }
210 
211 
212 
213 
214 
215 void cLuaWindow::Clicked(cPlayer & a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem)
216 {
217  if (m_OnClicked != nullptr)
218  {
219  // Plugin can stop a click
220  bool res;
221  if (m_OnClicked->Call(this, &a_Player, a_SlotNum, a_ClickAction, a_ClickedItem, cLuaState::Return, res) && res)
222  {
223  // Tell the client the actual state of the window
224  a_Player.GetClientHandle()->SendInventorySlot(-1, -1, a_Player.GetDraggingItem());
226  return;
227  }
228  }
229 
230  cWindow::Clicked(a_Player, a_WindowID, a_SlotNum, a_ClickAction, a_ClickedItem);
231 }
232 
233 
234 
235 
eClickAction
Individual actions sent in the WindowClick packet.
Definition: Defines.h:82
#define ASSERT(x)
Definition: Globals.h:276
std::string AString
Definition: StringUtils.h:11
std::vector< cSlotArea * > cSlotAreas
Definition: Window.h:34
Encapsulates a Lua state and provides some syntactic sugar for common operations.
Definition: LuaState.h:56
std::unique_ptr< cCallback > cCallbackPtr
Definition: LuaState.h:326
static const cRet Return
Definition: LuaState.h:445
void CreateFromObject(cLuaState &a_LuaState, T &&a_Object)
Creates a Lua reference to the specified object instance in the specified Lua state.
Definition: LuaState.h:192
void UnRef(void)
Removes the bound reference, resets the object to Unbound state.
Definition: LuaState.cpp:2650
std::atomic< int > m_PlayerCount
Number of players that are currently using the window.
Definition: LuaWindow.h:81
virtual void OnSlotChanged(cItemGrid *a_ItemGrid, int a_SlotNum) override
Called whenever a slot changes.
Definition: LuaWindow.cpp:200
void SetOnClicked(cLuaState::cCallbackPtr &&a_OnClicked)
Sets the Lua callback to call when the player clicks on the window.
Definition: LuaWindow.cpp:85
cLuaWindow(cLuaState &a_LuaState, cWindow::WindowType a_WindowType, int a_SlotsX, int a_SlotsY, const AString &a_Title)
Create a window of the specified type, with a slot grid of a_SlotsX * a_SlotsY size.
Definition: LuaWindow.cpp:23
void SetOnClosing(cLuaState::cCallbackPtr &&a_OnClosing)
Sets the Lua callback function to call when the window is about to close.
Definition: LuaWindow.cpp:98
virtual void Clicked(cPlayer &a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem) override
Handles a click event from a player.
Definition: LuaWindow.cpp:215
virtual ~cLuaWindow() override
Definition: LuaWindow.cpp:55
void SetOnSlotChanged(cLuaState::cCallbackPtr &&a_OnSlotChanged)
Sets the Lua callback function to call when a slot is changed.
Definition: LuaWindow.cpp:111
cItemGrid m_Contents
Contents of the non-inventory part.
Definition: LuaWindow.h:65
virtual bool ClosedByPlayer(cPlayer &a_Player, bool a_CanRefuse) override
Called when a player closes this window; notifies all slot areas.
Definition: LuaWindow.cpp:140
virtual void Destroy(void) override
Sets the internal flag as "destroyed"; notifies the owner that the window is destroying.
Definition: LuaWindow.cpp:170
cLuaState::cCallbackPtr m_OnSlotChanged
The Lua callback to call when a slot has changed.
Definition: LuaWindow.h:77
cLuaState::cCallbackPtr m_OnClicked
The Lua callback to call when the player clicked on a slot.
Definition: LuaWindow.h:71
virtual void OpenedByPlayer(cPlayer &a_Player) override
Definition: LuaWindow.cpp:124
cLuaState::cRef m_LuaRef
Reference to self, to keep Lua from GCing the object while a player is still using it.
Definition: LuaWindow.h:85
cLuaState * m_LuaState
The canon Lua state that has opened the window and owns the m_LuaRef.
Definition: LuaWindow.h:68
cLuaState::cCallbackPtr m_OnClosing
The Lua callback to call when the window is closing for any player.
Definition: LuaWindow.h:74
virtual void DistributeStack(cItem &a_ItemStack, int a_Slot, cPlayer &a_Player, cSlotArea *a_ClickedArea, bool a_ShouldApply) override
Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is dist...
Definition: LuaWindow.cpp:182
void SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem &a_Item)
Definition: Player.h:29
cClientHandle * GetClientHandle(void) const
Definition: Player.h:276
cItem & GetDraggingItem(void)
In UI windows, get the item that the player is dragging.
Definition: Player.h:448
cWindow * GetWindow(void)
Definition: Player.h:262
Definition: Item.h:37
void AddListener(cListener &a_Listener)
Adds a callback that gets called whenever a slot changes.
Definition: ItemGrid.cpp:809
void RemoveListener(cListener &a_Listener)
Removes a slot-change-callback.
Definition: ItemGrid.cpp:820
static cRoot * Get()
Definition: Root.h:52
bool ForEachPlayer(cPlayerListCallback a_Callback)
Calls the callback for each player in all worlds.
Definition: Root.cpp:681
Handles the main inventory of each player, excluding the armor and hotbar.
Definition: SlotArea.h:120
Handles the hotbar of each player.
Definition: SlotArea.h:138
Handles the armor area of the player's inventory.
Definition: SlotArea.h:173
Handles any slot area that is representing a cItemGrid; same items for all the players.
Definition: SlotArea.h:200
Represents a UI window.
Definition: Window.h:54
virtual void OpenedByPlayer(cPlayer &a_Player)
Definition: Window.cpp:284
bool m_IsDestroyed
Definition: Window.h:188
virtual bool ClosedByPlayer(cPlayer &a_Player, bool a_CanRefuse)
Called when a player closes this window; notifies all slot areas.
Definition: Window.cpp:306
void BroadcastWholeWindow(void)
Sends the contents of the whole window to all clients of this window.
Definition: Window.cpp:393
WindowType
Definition: Window.h:57
@ wtWorkbench
Definition: Window.h:60
@ wtInventory
Definition: Window.h:58
cPlayerList m_OpenedBy
Definition: Window.h:186
virtual void Destroy(void)
Sets the internal flag as "destroyed"; notifies the owner that the window is destroying.
Definition: Window.cpp:536
virtual void Clicked(cPlayer &a_Player, int a_WindowID, short a_SlotNum, eClickAction a_ClickAction, const cItem &a_ClickedItem)
Handles a click event from a player.
Definition: Window.cpp:197
void DistributeStackToAreas(cItem &a_ItemStack, cPlayer &a_Player, cSlotAreas &a_AreasInOrder, bool a_ShouldApply, bool a_BackFill)
Called from DistributeStack() to distribute the stack into a_AreasInOrder; Modifies a_ItemStack as it...
Definition: Window.cpp:467
cSlotAreas m_SlotAreas
Definition: Window.h:179