]> git.lizzy.rs Git - minetest.git/blob - src/craftdef.cpp
Implement minetest.register_on_dieplayer()
[minetest.git] / src / craftdef.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2011 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 General Public License as published by
7 the Free Software Foundation; either version 2 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 General Public License for more details.
14
15 You should have received a copy of the GNU 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 #include "craftdef.h"
21
22 #include "irrlichttypes.h"
23 #include "log.h"
24 #include <sstream>
25 #include "utility.h"
26 #include "gamedef.h"
27 #include "inventory.h"
28 #include "inventorymanager.h" // checkItemCombination
29
30 CraftPointerInput::~CraftPointerInput()
31 {
32         for(u32 i=0; i<items.size(); i++)
33                 delete items[i];
34 }
35
36 CraftPointerInput createPointerInput(const CraftInput &ci, IGameDef *gamedef)
37 {
38         std::vector<InventoryItem*> items;
39         for(u32 i=0; i<ci.items.size(); i++){
40                 InventoryItem *item = NULL;
41                 if(ci.items[i] != ""){
42                         std::istringstream iss(ci.items[i], std::ios::binary);
43                         item = InventoryItem::deSerialize(iss, gamedef);
44                 }
45                 items.push_back(item);
46         }
47         return CraftPointerInput(ci.width, items);
48 }
49
50 CraftInput createInput(const CraftPointerInput &cpi)
51 {
52         std::vector<std::string> items;
53         for(u32 i=0; i<cpi.items.size(); i++){
54                 if(cpi.items[i] == NULL)
55                         items.push_back("");
56                 else{
57                         std::ostringstream oss(std::ios::binary);
58                         cpi.items[i]->serialize(oss);
59                         items.push_back(oss.str());
60                 }
61         }
62         return CraftInput(cpi.width, items);
63 }
64
65 std::string CraftInput::dump() const
66 {
67         std::ostringstream os(std::ios::binary);
68         os<<"(width="<<width<<"){";
69         for(u32 i=0; i<items.size(); i++)
70                 os<<"\""<<items[i]<<"\",";
71         os<<"}";
72         return os.str();
73 }
74
75 std::string CraftDefinition::dump() const
76 {
77         std::ostringstream os(std::ios::binary);
78         os<<"{output=\""<<output<<"\", input={";
79         for(u32 i=0; i<input.items.size(); i++)
80                 os<<"\""<<input.items[i]<<"\",";
81         os<<"}, (input.width="<<input.width<<")}";
82         return os.str();
83 }
84
85 void CraftDefinition::serialize(std::ostream &os) const
86 {
87         writeU8(os, 0); // version
88         os<<serializeString(output);
89         writeU8(os, input.width);
90         writeU16(os, input.items.size());
91         for(u32 i=0; i<input.items.size(); i++)
92                 os<<serializeString(input.items[i]);
93 }
94
95 void CraftDefinition::deSerialize(std::istream &is)
96 {
97         int version = readU8(is);
98         if(version != 0) throw SerializationError(
99                         "unsupported CraftDefinition version");
100         output = deSerializeString(is);
101         input.width = readU8(is);
102         u32 count = readU16(is);
103         for(u32 i=0; i<count; i++)
104                 input.items.push_back(deSerializeString(is));
105 }
106
107 class CCraftDefManager: public IWritableCraftDefManager
108 {
109 public:
110         virtual ~CCraftDefManager()
111         {
112                 clear();
113         }
114         virtual InventoryItem* getCraftResult(const CraftPointerInput &input_cpi,
115                         IGameDef *gamedef) const
116         {
117                 if(input_cpi.width > 3){
118                         errorstream<<"getCraftResult(): ERROR: "
119                                         <<"input_cpi.width > 3; Failing to craft."<<std::endl;
120                         return NULL;
121                 }
122                 InventoryItem *input_items[9];
123                 for(u32 y=0; y<3; y++)
124                 for(u32 x=0; x<3; x++)
125                 {
126                         u32 i=y*3+x;
127                         if(x >= input_cpi.width || y >= input_cpi.height())
128                                 input_items[i] = NULL;
129                         else
130                                 input_items[i] = input_cpi.items[y*input_cpi.width+x];
131                 }
132                 for(core::list<CraftDefinition*>::ConstIterator
133                                 i = m_craft_definitions.begin();
134                                 i != m_craft_definitions.end(); i++)
135                 {
136                         CraftDefinition *def = *i;
137
138                         /*infostream<<"Checking "<<createInput(input_cpi).dump()<<std::endl
139                                         <<" against "<<def->input.dump()
140                                         <<" (output=\""<<def->output<<"\")"<<std::endl;*/
141
142                         try {
143                                 CraftPointerInput spec_cpi = createPointerInput(def->input, gamedef);
144                                 if(spec_cpi.width > 3){
145                                         errorstream<<"getCraftResult: ERROR: "
146                                                         <<"spec_cpi.width > 3 in recipe "
147                                                         <<def->dump()<<std::endl;
148                                         continue;
149                                 }
150                                 InventoryItem *spec_items[9];
151                                 for(u32 y=0; y<3; y++)
152                                 for(u32 x=0; x<3; x++)
153                                 {
154                                         u32 i=y*3+x;
155                                         if(x >= spec_cpi.width || y >= spec_cpi.height())
156                                                 spec_items[i] = NULL;
157                                         else
158                                                 spec_items[i] = spec_cpi.items[y*spec_cpi.width+x];
159                                 }
160
161                                 bool match = checkItemCombination(input_items, spec_items);
162
163                                 if(match){
164                                         std::istringstream iss(def->output, std::ios::binary);
165                                         return InventoryItem::deSerialize(iss, gamedef);
166                                 }
167                         }
168                         catch(SerializationError &e)
169                         {
170                                 errorstream<<"getCraftResult: ERROR: "
171                                                 <<"Serialization error in recipe "
172                                                 <<def->dump()<<std::endl;
173                                 // then go on with the next craft definition
174                         }
175                 }
176                 return NULL;
177         }
178         virtual void registerCraft(const CraftDefinition &def)
179         {
180                 infostream<<"registerCraft: registering craft definition: "
181                                 <<def.dump()<<std::endl;
182                 if(def.input.width > 3 || def.input.height() > 3){
183                         errorstream<<"registerCraft: input size is larger than 3x3,"
184                                         <<" ignoring"<<std::endl;
185                         return;
186                 }
187                 m_craft_definitions.push_back(new CraftDefinition(def));
188         }
189         virtual void clear()
190         {
191                 for(core::list<CraftDefinition*>::Iterator
192                                 i = m_craft_definitions.begin();
193                                 i != m_craft_definitions.end(); i++){
194                         delete *i;
195                 }
196                 m_craft_definitions.clear();
197         }
198         virtual void serialize(std::ostream &os)
199         {
200                 writeU8(os, 0); // version
201                 u16 count = m_craft_definitions.size();
202                 writeU16(os, count);
203                 for(core::list<CraftDefinition*>::Iterator
204                                 i = m_craft_definitions.begin();
205                                 i != m_craft_definitions.end(); i++){
206                         CraftDefinition *def = *i;
207                         // Serialize wrapped in a string
208                         std::ostringstream tmp_os(std::ios::binary);
209                         def->serialize(tmp_os);
210                         os<<serializeString(tmp_os.str());
211                 }
212         }
213         virtual void deSerialize(std::istream &is)
214         {
215                 // Clear everything
216                 clear();
217                 // Deserialize
218                 int version = readU8(is);
219                 if(version != 0) throw SerializationError(
220                                 "unsupported CraftDefManager version");
221                 u16 count = readU16(is);
222                 for(u16 i=0; i<count; i++){
223                         // Deserialize a string and grab a CraftDefinition from it
224                         std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
225                         CraftDefinition def;
226                         def.deSerialize(tmp_is);
227                         // Register
228                         registerCraft(def);
229                 }
230         }
231 private:
232         core::list<CraftDefinition*> m_craft_definitions;
233 };
234
235 IWritableCraftDefManager* createCraftDefManager()
236 {
237         return new CCraftDefManager();
238 }
239