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