Optimize string (mis)handling (#8128)
[oweals/minetest.git] / src / inventorymanager.h
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #pragma once
21
22 #include "inventory.h"
23 #include <iostream>
24 #include <string>
25 class ServerActiveObject;
26
27 struct InventoryLocation
28 {
29         enum Type{
30                 UNDEFINED,
31                 CURRENT_PLAYER,
32                 PLAYER,
33                 NODEMETA,
34         DETACHED,
35         } type;
36
37         std::string name; // PLAYER, DETACHED
38         v3s16 p; // NODEMETA
39
40         InventoryLocation()
41         {
42                 setUndefined();
43         }
44         void setUndefined()
45         {
46                 type = UNDEFINED;
47         }
48         void setCurrentPlayer()
49         {
50                 type = CURRENT_PLAYER;
51         }
52         void setPlayer(const std::string &name_)
53         {
54                 type = PLAYER;
55                 name = name_;
56         }
57         void setNodeMeta(const v3s16 &p_)
58         {
59                 type = NODEMETA;
60                 p = p_;
61         }
62         void setDetached(const std::string &name_)
63         {
64                 type = DETACHED;
65                 name = name_;
66         }
67
68         bool operator==(const InventoryLocation &other) const
69         {
70                 if(type != other.type)
71                         return false;
72                 switch(type){
73                 case UNDEFINED:
74                         return false;
75                 case CURRENT_PLAYER:
76                         return true;
77                 case PLAYER:
78                         return (name == other.name);
79                 case NODEMETA:
80                         return (p == other.p);
81                 case DETACHED:
82                         return (name == other.name);
83                 }
84                 return false;
85         }
86         bool operator!=(const InventoryLocation &other) const
87         {
88                 return !(*this == other);
89         }
90
91         void applyCurrentPlayer(const std::string &name_)
92         {
93                 if(type == CURRENT_PLAYER)
94                         setPlayer(name_);
95         }
96
97         std::string dump() const;
98         void serialize(std::ostream &os) const;
99         void deSerialize(std::istream &is);
100         void deSerialize(const std::string &s);
101 };
102
103 struct InventoryAction;
104
105 class InventoryManager
106 {
107 public:
108         InventoryManager() = default;
109         virtual ~InventoryManager() = default;
110
111         // Get an inventory (server and client)
112         virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
113     // Set modified (will be saved and sent over network; only on server)
114         virtual void setInventoryModified(const InventoryLocation &loc, bool playerSend = true){}
115     // Send inventory action to server (only on client)
116         virtual void inventoryAction(InventoryAction *a){}
117 };
118
119 enum class IAction : u16 {
120         Move,
121         Drop,
122         Craft
123 };
124
125 struct InventoryAction
126 {
127         static InventoryAction *deSerialize(std::istream &is);
128
129         virtual IAction getType() const = 0;
130         virtual void serialize(std::ostream &os) const = 0;
131         virtual void apply(InventoryManager *mgr, ServerActiveObject *player,
132                         IGameDef *gamedef) = 0;
133         virtual void clientApply(InventoryManager *mgr, IGameDef *gamedef) = 0;
134         virtual ~InventoryAction() = default;;
135 };
136
137 struct MoveAction
138 {
139         InventoryLocation from_inv;
140         std::string from_list;
141         s16 from_i = -1;
142         InventoryLocation to_inv;
143         std::string to_list;
144         s16 to_i = -1;
145 };
146
147 struct IMoveAction : public InventoryAction, public MoveAction
148 {
149         // count=0 means "everything"
150         u16 count = 0;
151         bool move_somewhere = false;
152
153         // treat these as private
154         // related to movement to somewhere
155         bool caused_by_move_somewhere = false;
156         u32 move_count = 0;
157
158         IMoveAction() = default;
159
160         IMoveAction(std::istream &is, bool somewhere);
161
162         IAction getType() const
163         {
164                 return IAction::Move;
165         }
166
167         void serialize(std::ostream &os) const
168         {
169                 if (!move_somewhere)
170                         os << "Move ";
171                 else
172                         os << "MoveSomewhere ";
173                 os << count << " ";
174                 os << from_inv.dump() << " ";
175                 os << from_list << " ";
176                 os << from_i << " ";
177                 os << to_inv.dump() << " ";
178                 os << to_list;
179                 if (!move_somewhere)
180                         os << " " << to_i;
181         }
182
183         void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
184
185         void clientApply(InventoryManager *mgr, IGameDef *gamedef);
186 };
187
188 struct IDropAction : public InventoryAction, public MoveAction
189 {
190         // count=0 means "everything"
191         u16 count = 0;
192
193         IDropAction() = default;
194
195         IDropAction(std::istream &is);
196
197         IAction getType() const
198         {
199                 return IAction::Drop;
200         }
201
202         void serialize(std::ostream &os) const
203         {
204                 os<<"Drop ";
205                 os<<count<<" ";
206                 os<<from_inv.dump()<<" ";
207                 os<<from_list<<" ";
208                 os<<from_i;
209         }
210
211         void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
212
213         void clientApply(InventoryManager *mgr, IGameDef *gamedef);
214 };
215
216 struct ICraftAction : public InventoryAction
217 {
218         // count=0 means "everything"
219         u16 count = 0;
220         InventoryLocation craft_inv;
221
222         ICraftAction() = default;
223
224         ICraftAction(std::istream &is);
225
226         IAction getType() const
227         {
228                 return IAction::Craft;
229         }
230
231         void serialize(std::ostream &os) const
232         {
233                 os<<"Craft ";
234                 os<<count<<" ";
235                 os<<craft_inv.dump()<<" ";
236         }
237
238         void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
239
240         void clientApply(InventoryManager *mgr, IGameDef *gamedef);
241 };
242
243 // Crafting helper
244 bool getCraftingResult(Inventory *inv, ItemStack &result,
245                 std::vector<ItemStack> &output_replacements,
246                 bool decrementInput, IGameDef *gamedef);