itemdef.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. /*
  2. Minetest
  3. Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. Copyright (C) 2013 Kahrl <kahrl@gmx.net>
  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. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include "itemdef.h"
  18. #include "nodedef.h"
  19. #include "tool.h"
  20. #include "inventory.h"
  21. #ifndef SERVER
  22. #include "mapblock_mesh.h"
  23. #include "mesh.h"
  24. #include "wieldmesh.h"
  25. #include "client/tile.h"
  26. #include "client.h"
  27. #endif
  28. #include "log.h"
  29. #include "settings.h"
  30. #include "util/serialize.h"
  31. #include "util/container.h"
  32. #include "util/thread.h"
  33. #include <map>
  34. #include <set>
  35. #ifdef __ANDROID__
  36. #include <GLES/gl.h>
  37. #endif
  38. /*
  39. ItemDefinition
  40. */
  41. ItemDefinition::ItemDefinition()
  42. {
  43. resetInitial();
  44. }
  45. ItemDefinition::ItemDefinition(const ItemDefinition &def)
  46. {
  47. resetInitial();
  48. *this = def;
  49. }
  50. ItemDefinition& ItemDefinition::operator=(const ItemDefinition &def)
  51. {
  52. if(this == &def)
  53. return *this;
  54. reset();
  55. type = def.type;
  56. name = def.name;
  57. description = def.description;
  58. inventory_image = def.inventory_image;
  59. wield_image = def.wield_image;
  60. wield_scale = def.wield_scale;
  61. stack_max = def.stack_max;
  62. usable = def.usable;
  63. liquids_pointable = def.liquids_pointable;
  64. if(def.tool_capabilities)
  65. {
  66. tool_capabilities = new ToolCapabilities(
  67. *def.tool_capabilities);
  68. }
  69. groups = def.groups;
  70. node_placement_prediction = def.node_placement_prediction;
  71. sound_place = def.sound_place;
  72. sound_place_failed = def.sound_place_failed;
  73. range = def.range;
  74. palette_image = def.palette_image;
  75. color = def.color;
  76. return *this;
  77. }
  78. ItemDefinition::~ItemDefinition()
  79. {
  80. reset();
  81. }
  82. void ItemDefinition::resetInitial()
  83. {
  84. // Initialize pointers to NULL so reset() does not delete undefined pointers
  85. tool_capabilities = NULL;
  86. reset();
  87. }
  88. void ItemDefinition::reset()
  89. {
  90. type = ITEM_NONE;
  91. name = "";
  92. description = "";
  93. inventory_image = "";
  94. wield_image = "";
  95. palette_image = "";
  96. color = video::SColor(0xFFFFFFFF);
  97. wield_scale = v3f(1.0, 1.0, 1.0);
  98. stack_max = 99;
  99. usable = false;
  100. liquids_pointable = false;
  101. delete tool_capabilities;
  102. tool_capabilities = NULL;
  103. groups.clear();
  104. sound_place = SimpleSoundSpec();
  105. sound_place_failed = SimpleSoundSpec();
  106. range = -1;
  107. node_placement_prediction = "";
  108. }
  109. void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const
  110. {
  111. u8 version = (protocol_version >= 34) ? 4 : 3;
  112. writeU8(os, version);
  113. writeU8(os, type);
  114. os << serializeString(name);
  115. os << serializeString(description);
  116. os << serializeString(inventory_image);
  117. os << serializeString(wield_image);
  118. writeV3F1000(os, wield_scale);
  119. writeS16(os, stack_max);
  120. writeU8(os, usable);
  121. writeU8(os, liquids_pointable);
  122. std::string tool_capabilities_s;
  123. if(tool_capabilities){
  124. std::ostringstream tmp_os(std::ios::binary);
  125. tool_capabilities->serialize(tmp_os, protocol_version);
  126. tool_capabilities_s = tmp_os.str();
  127. }
  128. os << serializeString(tool_capabilities_s);
  129. writeU16(os, groups.size());
  130. for (const auto &group : groups) {
  131. os << serializeString(group.first);
  132. writeS16(os, group.second);
  133. }
  134. os << serializeString(node_placement_prediction);
  135. os << serializeString(sound_place.name);
  136. writeF1000(os, sound_place.gain);
  137. writeF1000(os, range);
  138. os << serializeString(sound_place_failed.name);
  139. writeF1000(os, sound_place_failed.gain);
  140. os << serializeString(palette_image);
  141. writeU32(os, color.color);
  142. if (version >= 4) {
  143. writeF1000(os, sound_place.pitch);
  144. writeF1000(os, sound_place_failed.pitch);
  145. }
  146. }
  147. void ItemDefinition::deSerialize(std::istream &is)
  148. {
  149. // Reset everything
  150. reset();
  151. // Deserialize
  152. int version = readU8(is);
  153. if (version < 1 || version > 4)
  154. throw SerializationError("unsupported ItemDefinition version");
  155. type = (enum ItemType)readU8(is);
  156. name = deSerializeString(is);
  157. description = deSerializeString(is);
  158. inventory_image = deSerializeString(is);
  159. wield_image = deSerializeString(is);
  160. wield_scale = readV3F1000(is);
  161. stack_max = readS16(is);
  162. usable = readU8(is);
  163. liquids_pointable = readU8(is);
  164. std::string tool_capabilities_s = deSerializeString(is);
  165. if(!tool_capabilities_s.empty())
  166. {
  167. std::istringstream tmp_is(tool_capabilities_s, std::ios::binary);
  168. tool_capabilities = new ToolCapabilities;
  169. tool_capabilities->deSerialize(tmp_is);
  170. }
  171. groups.clear();
  172. u32 groups_size = readU16(is);
  173. for(u32 i=0; i<groups_size; i++){
  174. std::string name = deSerializeString(is);
  175. int value = readS16(is);
  176. groups[name] = value;
  177. }
  178. if(version == 1){
  179. // We cant be sure that node_placement_prediction is send in version 1
  180. try{
  181. node_placement_prediction = deSerializeString(is);
  182. }catch(SerializationError &e) {};
  183. // Set the old default sound
  184. sound_place.name = "default_place_node";
  185. sound_place.gain = 0.5;
  186. } else if(version >= 2) {
  187. node_placement_prediction = deSerializeString(is);
  188. //deserializeSimpleSoundSpec(sound_place, is);
  189. sound_place.name = deSerializeString(is);
  190. sound_place.gain = readF1000(is);
  191. }
  192. if(version >= 3) {
  193. range = readF1000(is);
  194. }
  195. // If you add anything here, insert it primarily inside the try-catch
  196. // block to not need to increase the version.
  197. try {
  198. sound_place_failed.name = deSerializeString(is);
  199. sound_place_failed.gain = readF1000(is);
  200. palette_image = deSerializeString(is);
  201. color.set(readU32(is));
  202. if (version >= 4) {
  203. sound_place.pitch = readF1000(is);
  204. sound_place_failed.pitch = readF1000(is);
  205. }
  206. } catch(SerializationError &e) {};
  207. }
  208. /*
  209. CItemDefManager
  210. */
  211. // SUGG: Support chains of aliases?
  212. class CItemDefManager: public IWritableItemDefManager
  213. {
  214. #ifndef SERVER
  215. struct ClientCached
  216. {
  217. video::ITexture *inventory_texture;
  218. ItemMesh wield_mesh;
  219. Palette *palette;
  220. ClientCached():
  221. inventory_texture(NULL),
  222. palette(NULL)
  223. {}
  224. };
  225. #endif
  226. public:
  227. CItemDefManager()
  228. {
  229. #ifndef SERVER
  230. m_main_thread = std::this_thread::get_id();
  231. #endif
  232. clear();
  233. }
  234. virtual ~CItemDefManager()
  235. {
  236. #ifndef SERVER
  237. const std::vector<ClientCached*> &values = m_clientcached.getValues();
  238. for (ClientCached *cc : values) {
  239. if (cc->wield_mesh.mesh)
  240. cc->wield_mesh.mesh->drop();
  241. delete cc;
  242. }
  243. #endif
  244. for (auto &item_definition : m_item_definitions) {
  245. delete item_definition.second;
  246. }
  247. m_item_definitions.clear();
  248. }
  249. virtual const ItemDefinition& get(const std::string &name_) const
  250. {
  251. // Convert name according to possible alias
  252. std::string name = getAlias(name_);
  253. // Get the definition
  254. std::map<std::string, ItemDefinition*>::const_iterator i;
  255. i = m_item_definitions.find(name);
  256. if(i == m_item_definitions.end())
  257. i = m_item_definitions.find("unknown");
  258. assert(i != m_item_definitions.end());
  259. return *(i->second);
  260. }
  261. virtual const std::string &getAlias(const std::string &name) const
  262. {
  263. StringMap::const_iterator it = m_aliases.find(name);
  264. if (it != m_aliases.end())
  265. return it->second;
  266. return name;
  267. }
  268. virtual void getAll(std::set<std::string> &result) const
  269. {
  270. result.clear();
  271. for (const auto &item_definition : m_item_definitions) {
  272. result.insert(item_definition.first);
  273. }
  274. for (const auto &alias : m_aliases) {
  275. result.insert(alias.first);
  276. }
  277. }
  278. virtual bool isKnown(const std::string &name_) const
  279. {
  280. // Convert name according to possible alias
  281. std::string name = getAlias(name_);
  282. // Get the definition
  283. std::map<std::string, ItemDefinition*>::const_iterator i;
  284. return m_item_definitions.find(name) != m_item_definitions.end();
  285. }
  286. #ifndef SERVER
  287. public:
  288. ClientCached* createClientCachedDirect(const std::string &name,
  289. Client *client) const
  290. {
  291. infostream<<"Lazily creating item texture and mesh for \""
  292. <<name<<"\""<<std::endl;
  293. // This is not thread-safe
  294. sanity_check(std::this_thread::get_id() == m_main_thread);
  295. // Skip if already in cache
  296. ClientCached *cc = NULL;
  297. m_clientcached.get(name, &cc);
  298. if(cc)
  299. return cc;
  300. ITextureSource *tsrc = client->getTextureSource();
  301. const ItemDefinition &def = get(name);
  302. // Create new ClientCached
  303. cc = new ClientCached();
  304. // Create an inventory texture
  305. cc->inventory_texture = NULL;
  306. if (!def.inventory_image.empty())
  307. cc->inventory_texture = tsrc->getTexture(def.inventory_image);
  308. ItemStack item = ItemStack();
  309. item.name = def.name;
  310. getItemMesh(client, item, &(cc->wield_mesh));
  311. cc->palette = tsrc->getPalette(def.palette_image);
  312. // Put in cache
  313. m_clientcached.set(name, cc);
  314. return cc;
  315. }
  316. ClientCached* getClientCached(const std::string &name,
  317. Client *client) const
  318. {
  319. ClientCached *cc = NULL;
  320. m_clientcached.get(name, &cc);
  321. if (cc)
  322. return cc;
  323. if (std::this_thread::get_id() == m_main_thread) {
  324. return createClientCachedDirect(name, client);
  325. }
  326. // We're gonna ask the result to be put into here
  327. static ResultQueue<std::string, ClientCached*, u8, u8> result_queue;
  328. // Throw a request in
  329. m_get_clientcached_queue.add(name, 0, 0, &result_queue);
  330. try {
  331. while(true) {
  332. // Wait result for a second
  333. GetResult<std::string, ClientCached*, u8, u8>
  334. result = result_queue.pop_front(1000);
  335. if (result.key == name) {
  336. return result.item;
  337. }
  338. }
  339. } catch(ItemNotFoundException &e) {
  340. errorstream << "Waiting for clientcached " << name
  341. << " timed out." << std::endl;
  342. return &m_dummy_clientcached;
  343. }
  344. }
  345. // Get item inventory texture
  346. virtual video::ITexture* getInventoryTexture(const std::string &name,
  347. Client *client) const
  348. {
  349. ClientCached *cc = getClientCached(name, client);
  350. if(!cc)
  351. return NULL;
  352. return cc->inventory_texture;
  353. }
  354. // Get item wield mesh
  355. virtual ItemMesh* getWieldMesh(const std::string &name,
  356. Client *client) const
  357. {
  358. ClientCached *cc = getClientCached(name, client);
  359. if(!cc)
  360. return NULL;
  361. return &(cc->wield_mesh);
  362. }
  363. // Get item palette
  364. virtual Palette* getPalette(const std::string &name,
  365. Client *client) const
  366. {
  367. ClientCached *cc = getClientCached(name, client);
  368. if(!cc)
  369. return NULL;
  370. return cc->palette;
  371. }
  372. virtual video::SColor getItemstackColor(const ItemStack &stack,
  373. Client *client) const
  374. {
  375. // Look for direct color definition
  376. const std::string &colorstring = stack.metadata.getString("color", 0);
  377. video::SColor directcolor;
  378. if (!colorstring.empty() && parseColorString(colorstring, directcolor, true))
  379. return directcolor;
  380. // See if there is a palette
  381. Palette *palette = getPalette(stack.name, client);
  382. const std::string &index = stack.metadata.getString("palette_index", 0);
  383. if (palette && !index.empty())
  384. return (*palette)[mystoi(index, 0, 255)];
  385. // Fallback color
  386. return get(stack.name).color;
  387. }
  388. #endif
  389. void clear()
  390. {
  391. for(std::map<std::string, ItemDefinition*>::const_iterator
  392. i = m_item_definitions.begin();
  393. i != m_item_definitions.end(); ++i)
  394. {
  395. delete i->second;
  396. }
  397. m_item_definitions.clear();
  398. m_aliases.clear();
  399. // Add the four builtin items:
  400. // "" is the hand
  401. // "unknown" is returned whenever an undefined item
  402. // is accessed (is also the unknown node)
  403. // "air" is the air node
  404. // "ignore" is the ignore node
  405. ItemDefinition* hand_def = new ItemDefinition;
  406. hand_def->name = "";
  407. hand_def->wield_image = "wieldhand.png";
  408. hand_def->tool_capabilities = new ToolCapabilities;
  409. m_item_definitions.insert(std::make_pair("", hand_def));
  410. ItemDefinition* unknown_def = new ItemDefinition;
  411. unknown_def->type = ITEM_NODE;
  412. unknown_def->name = "unknown";
  413. m_item_definitions.insert(std::make_pair("unknown", unknown_def));
  414. ItemDefinition* air_def = new ItemDefinition;
  415. air_def->type = ITEM_NODE;
  416. air_def->name = "air";
  417. m_item_definitions.insert(std::make_pair("air", air_def));
  418. ItemDefinition* ignore_def = new ItemDefinition;
  419. ignore_def->type = ITEM_NODE;
  420. ignore_def->name = "ignore";
  421. m_item_definitions.insert(std::make_pair("ignore", ignore_def));
  422. }
  423. virtual void registerItem(const ItemDefinition &def)
  424. {
  425. verbosestream<<"ItemDefManager: registering \""<<def.name<<"\""<<std::endl;
  426. // Ensure that the "" item (the hand) always has ToolCapabilities
  427. if (def.name.empty())
  428. FATAL_ERROR_IF(!def.tool_capabilities, "Hand does not have ToolCapabilities");
  429. if(m_item_definitions.count(def.name) == 0)
  430. m_item_definitions[def.name] = new ItemDefinition(def);
  431. else
  432. *(m_item_definitions[def.name]) = def;
  433. // Remove conflicting alias if it exists
  434. bool alias_removed = (m_aliases.erase(def.name) != 0);
  435. if(alias_removed)
  436. infostream<<"ItemDefManager: erased alias "<<def.name
  437. <<" because item was defined"<<std::endl;
  438. }
  439. virtual void unregisterItem(const std::string &name)
  440. {
  441. verbosestream<<"ItemDefManager: unregistering \""<<name<<"\""<<std::endl;
  442. delete m_item_definitions[name];
  443. m_item_definitions.erase(name);
  444. }
  445. virtual void registerAlias(const std::string &name,
  446. const std::string &convert_to)
  447. {
  448. if (m_item_definitions.find(name) == m_item_definitions.end()) {
  449. verbosestream<<"ItemDefManager: setting alias "<<name
  450. <<" -> "<<convert_to<<std::endl;
  451. m_aliases[name] = convert_to;
  452. }
  453. }
  454. void serialize(std::ostream &os, u16 protocol_version)
  455. {
  456. writeU8(os, 0); // version
  457. u16 count = m_item_definitions.size();
  458. writeU16(os, count);
  459. for (std::map<std::string, ItemDefinition *>::const_iterator
  460. it = m_item_definitions.begin();
  461. it != m_item_definitions.end(); ++it) {
  462. ItemDefinition *def = it->second;
  463. // Serialize ItemDefinition and write wrapped in a string
  464. std::ostringstream tmp_os(std::ios::binary);
  465. def->serialize(tmp_os, protocol_version);
  466. os << serializeString(tmp_os.str());
  467. }
  468. writeU16(os, m_aliases.size());
  469. for (StringMap::const_iterator
  470. it = m_aliases.begin();
  471. it != m_aliases.end(); ++it) {
  472. os << serializeString(it->first);
  473. os << serializeString(it->second);
  474. }
  475. }
  476. void deSerialize(std::istream &is)
  477. {
  478. // Clear everything
  479. clear();
  480. // Deserialize
  481. int version = readU8(is);
  482. if(version != 0)
  483. throw SerializationError("unsupported ItemDefManager version");
  484. u16 count = readU16(is);
  485. for(u16 i=0; i<count; i++)
  486. {
  487. // Deserialize a string and grab an ItemDefinition from it
  488. std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
  489. ItemDefinition def;
  490. def.deSerialize(tmp_is);
  491. // Register
  492. registerItem(def);
  493. }
  494. u16 num_aliases = readU16(is);
  495. for(u16 i=0; i<num_aliases; i++)
  496. {
  497. std::string name = deSerializeString(is);
  498. std::string convert_to = deSerializeString(is);
  499. registerAlias(name, convert_to);
  500. }
  501. }
  502. void processQueue(IGameDef *gamedef)
  503. {
  504. #ifndef SERVER
  505. //NOTE this is only thread safe for ONE consumer thread!
  506. while(!m_get_clientcached_queue.empty())
  507. {
  508. GetRequest<std::string, ClientCached*, u8, u8>
  509. request = m_get_clientcached_queue.pop();
  510. m_get_clientcached_queue.pushResult(request,
  511. createClientCachedDirect(request.key, (Client *)gamedef));
  512. }
  513. #endif
  514. }
  515. private:
  516. // Key is name
  517. std::map<std::string, ItemDefinition*> m_item_definitions;
  518. // Aliases
  519. StringMap m_aliases;
  520. #ifndef SERVER
  521. // The id of the thread that is allowed to use irrlicht directly
  522. std::thread::id m_main_thread;
  523. // A reference to this can be returned when nothing is found, to avoid NULLs
  524. mutable ClientCached m_dummy_clientcached;
  525. // Cached textures and meshes
  526. mutable MutexedMap<std::string, ClientCached*> m_clientcached;
  527. // Queued clientcached fetches (to be processed by the main thread)
  528. mutable RequestQueue<std::string, ClientCached*, u8, u8> m_get_clientcached_queue;
  529. #endif
  530. };
  531. IWritableItemDefManager* createItemDefManager()
  532. {
  533. return new CItemDefManager();
  534. }