3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
20 #include "inventorymanager.h"
21 #include "serverremoteplayer.h"
23 #include "mapblock.h" // getNodeBlockPos
29 // Wrapper for old code
30 Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id)
32 if(id == "current_player")
34 assert(c->current_player);
35 InventoryLocation loc;
36 loc.setPlayer(c->current_player->getName());
37 return getInventory(loc);
41 std::string id0 = fn.next(":");
46 p.X = stoi(fn.next(","));
47 p.Y = stoi(fn.next(","));
48 p.Z = stoi(fn.next(","));
50 InventoryLocation loc;
52 return getInventory(loc);
55 errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
58 // Wrapper for old code
59 void InventoryManager::inventoryModified(InventoryContext *c, std::string id)
61 if(id == "current_player")
63 assert(c->current_player);
64 InventoryLocation loc;
65 loc.setPlayer(c->current_player->getName());
66 setInventoryModified(loc);
71 std::string id0 = fn.next(":");
76 p.X = stoi(fn.next(","));
77 p.Y = stoi(fn.next(","));
78 p.Z = stoi(fn.next(","));
79 v3s16 blockpos = getNodeBlockPos(p);
81 InventoryLocation loc;
83 setInventoryModified(loc);
87 errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
94 InventoryAction * InventoryAction::deSerialize(std::istream &is)
97 std::getline(is, type, ' ');
99 InventoryAction *a = NULL;
103 a = new IMoveAction(is);
105 else if(type == "Drop")
107 a = new IDropAction(is);
113 static std::string describeC(const struct InventoryContext *c)
115 if(c->current_player == NULL)
116 return "current_player=NULL";
118 return std::string("current_player=") + c->current_player->getName();
121 IMoveAction::IMoveAction(std::istream &is)
125 std::getline(is, ts, ' ');
128 std::getline(is, from_inv, ' ');
130 std::getline(is, from_list, ' ');
132 std::getline(is, ts, ' ');
135 std::getline(is, to_inv, ' ');
137 std::getline(is, to_list, ' ');
139 std::getline(is, ts, ' ');
143 void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
144 ServerEnvironment *env)
146 Inventory *inv_from = mgr->getInventory(c, from_inv);
147 Inventory *inv_to = mgr->getInventory(c, to_inv);
150 infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
151 <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
152 <<", to_inv=\""<<to_inv<<"\""<<std::endl;
156 infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
157 "context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
158 <<", to_inv=\""<<to_inv<<"\""<<std::endl;
162 InventoryList *list_from = inv_from->getList(from_list);
163 InventoryList *list_to = inv_to->getList(to_list);
166 If a list doesn't exist or the source item doesn't exist
169 infostream<<"IMoveAction::apply(): FAIL: source list not found: "
170 <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
171 <<", from_list=\""<<from_list<<"\""<<std::endl;
175 infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
176 <<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
177 <<", to_list=\""<<to_list<<"\""<<std::endl;
180 if(list_from->getItem(from_i) == NULL)
182 infostream<<"IMoveAction::apply(): FAIL: source item not found: "
183 <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
184 <<", from_list=\""<<from_list<<"\""
185 <<" from_i="<<from_i<<std::endl;
189 If the source and the destination slots are the same
191 if(inv_from == inv_to && list_from == list_to && from_i == to_i)
193 infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
194 <<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
195 <<"\" i="<<from_i<<std::endl;
199 // Take item from source list
200 InventoryItem *item1 = NULL;
202 item1 = list_from->changeItem(from_i, NULL);
204 item1 = list_from->takeItem(from_i, count);
206 // Try to add the item to destination list
207 InventoryItem *olditem = item1;
208 item1 = list_to->addItem(to_i, item1);
210 // If something is returned, the item was not fully added
213 // If olditem is returned, nothing was added.
214 bool nothing_added = (item1 == olditem);
216 // If something else is returned, part of the item was left unadded.
217 // Add the other part back to the source item
218 list_from->addItem(from_i, item1);
220 // If olditem is returned, nothing was added.
224 // Take item from source list
225 item1 = list_from->changeItem(from_i, NULL);
226 // Adding was not possible, swap the items.
227 InventoryItem *item2 = list_to->changeItem(to_i, item1);
228 // Put item from destination list to the source list
229 list_from->changeItem(from_i, item2);
233 mgr->inventoryModified(c, from_inv);
234 if(from_inv != to_inv)
235 mgr->inventoryModified(c, to_inv);
237 infostream<<"IMoveAction::apply(): moved at "
238 <<"["<<describeC(c)<<"]"
239 <<" from inv=\""<<from_inv<<"\""
240 <<" list=\""<<from_list<<"\""
242 <<" to inv=\""<<to_inv<<"\""
243 <<" list=\""<<to_list<<"\""
248 IDropAction::IDropAction(std::istream &is)
252 std::getline(is, ts, ' ');
255 std::getline(is, from_inv, ' ');
257 std::getline(is, from_list, ' ');
259 std::getline(is, ts, ' ');
263 void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
264 ServerEnvironment *env)
266 if(c->current_player == NULL){
267 infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
271 // Do NOT cast directly to ServerActiveObject*, it breaks
272 // because of multiple inheritance.
273 ServerActiveObject *dropper =
274 static_cast<ServerActiveObject*>(
275 static_cast<ServerRemotePlayer*>(
279 Inventory *inv_from = mgr->getInventory(c, from_inv);
282 infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
283 <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
287 InventoryList *list_from = inv_from->getList(from_list);
290 If a list doesn't exist or the source item doesn't exist
293 infostream<<"IDropAction::apply(): FAIL: source list not found: "
294 <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
295 <<", from_list=\""<<from_list<<"\""<<std::endl;
298 InventoryItem *item = list_from->getItem(from_i);
301 infostream<<"IDropAction::apply(): FAIL: source item not found: "
302 <<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
303 <<", from_list=\""<<from_list<<"\""
304 <<" from_i="<<from_i<<std::endl;
308 v3f pos = dropper->getBasePosition();
318 bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
320 list_from->deleteItem(from_i);
322 mgr->inventoryModified(c, from_inv);
324 infostream<<"IDropAction::apply(): dropped "
325 <<"["<<describeC(c)<<"]"
326 <<" from inv=\""<<from_inv<<"\""
327 <<" list=\""<<from_list<<"\""
333 Craft checking system
336 bool ItemSpec::checkItem(const InventoryItem *item) const
338 if(type == ITEM_NONE)
346 // There should be an item
350 std::string itemname = item->getName();
352 if(type == ITEM_MATERIAL)
354 if(itemname != "MaterialItem")
356 MaterialItem *mitem = (MaterialItem*)item;
358 if(mitem->getMaterial() != num)
361 if(mitem->getNodeName() != name)
365 else if(type == ITEM_CRAFT)
367 if(itemname != "CraftItem")
369 CraftItem *mitem = (CraftItem*)item;
370 if(mitem->getSubName() != name)
373 else if(type == ITEM_TOOL)
378 else if(type == ITEM_MBO)
391 bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
393 u16 items_min_x = 100;
394 u16 items_max_x = 100;
395 u16 items_min_y = 100;
396 u16 items_max_y = 100;
397 for(u16 y=0; y<3; y++)
398 for(u16 x=0; x<3; x++)
400 if(items[y*3 + x] == NULL)
402 if(items_min_x == 100 || x < items_min_x)
404 if(items_min_y == 100 || y < items_min_y)
406 if(items_max_x == 100 || x > items_max_x)
408 if(items_max_y == 100 || y > items_max_y)
411 // No items at all, just return false
412 if(items_min_x == 100)
415 u16 items_w = items_max_x - items_min_x + 1;
416 u16 items_h = items_max_y - items_min_y + 1;
418 u16 specs_min_x = 100;
419 u16 specs_max_x = 100;
420 u16 specs_min_y = 100;
421 u16 specs_max_y = 100;
422 for(u16 y=0; y<3; y++)
423 for(u16 x=0; x<3; x++)
425 if(specs[y*3 + x].type == ITEM_NONE)
427 if(specs_min_x == 100 || x < specs_min_x)
429 if(specs_min_y == 100 || y < specs_min_y)
431 if(specs_max_x == 100 || x > specs_max_x)
433 if(specs_max_y == 100 || y > specs_max_y)
436 // No specs at all, just return false
437 if(specs_min_x == 100)
440 u16 specs_w = specs_max_x - specs_min_x + 1;
441 u16 specs_h = specs_max_y - specs_min_y + 1;
444 if(items_w != specs_w || items_h != specs_h)
447 for(u16 y=0; y<specs_h; y++)
448 for(u16 x=0; x<specs_w; x++)
450 u16 items_x = items_min_x + x;
451 u16 items_y = items_min_y + y;
452 u16 specs_x = specs_min_x + x;
453 u16 specs_y = specs_min_y + y;
454 const InventoryItem *item = items[items_y * 3 + items_x];
455 const ItemSpec &spec = specs[specs_y * 3 + specs_x];
457 if(spec.checkItem(item) == false)
464 bool checkItemCombination(const InventoryItem * const * items,
465 const InventoryItem * const * specs)
467 u16 items_min_x = 100;
468 u16 items_max_x = 100;
469 u16 items_min_y = 100;
470 u16 items_max_y = 100;
471 for(u16 y=0; y<3; y++)
472 for(u16 x=0; x<3; x++)
474 if(items[y*3 + x] == NULL)
476 if(items_min_x == 100 || x < items_min_x)
478 if(items_min_y == 100 || y < items_min_y)
480 if(items_max_x == 100 || x > items_max_x)
482 if(items_max_y == 100 || y > items_max_y)
485 // No items at all, just return false
486 if(items_min_x == 100)
489 u16 items_w = items_max_x - items_min_x + 1;
490 u16 items_h = items_max_y - items_min_y + 1;
492 u16 specs_min_x = 100;
493 u16 specs_max_x = 100;
494 u16 specs_min_y = 100;
495 u16 specs_max_y = 100;
496 for(u16 y=0; y<3; y++)
497 for(u16 x=0; x<3; x++)
499 if(specs[y*3 + x] == NULL)
501 if(specs_min_x == 100 || x < specs_min_x)
503 if(specs_min_y == 100 || y < specs_min_y)
505 if(specs_max_x == 100 || x > specs_max_x)
507 if(specs_max_y == 100 || y > specs_max_y)
510 // No specs at all, just return false
511 if(specs_min_x == 100)
514 u16 specs_w = specs_max_x - specs_min_x + 1;
515 u16 specs_h = specs_max_y - specs_min_y + 1;
518 if(items_w != specs_w || items_h != specs_h)
521 for(u16 y=0; y<specs_h; y++)
522 for(u16 x=0; x<specs_w; x++)
524 u16 items_x = items_min_x + x;
525 u16 items_y = items_min_y + y;
526 u16 specs_x = specs_min_x + x;
527 u16 specs_y = specs_min_y + y;
528 const InventoryItem *item = items[items_y * 3 + items_x];
529 const InventoryItem *spec = specs[specs_y * 3 + specs_x];
531 if(item == NULL && spec == NULL)
533 if(item == NULL && spec != NULL)
535 if(item != NULL && spec == NULL)
537 if(!spec->isSubsetOf(item))