Client Upload Part 2

RD Core / Commit #5

Commit Client Upload Part 2

Alex Alex committed 19/10/2026 00:06 main Patch
1,244 files +271,215 -0
A RD_Client/src/client/thingtype.h +323-0 View file
@@ -0,0 +1,323 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef THINGTYPE_H
24+#define THINGTYPE_H
25+
26+#include "declarations.h"
27+#include "animator.h"
28+
29+#include <framework/core/declarations.h>
30+#include <framework/otml/declarations.h>
31+#include <framework/graphics/texture.h>
32+#include <framework/graphics/coordsbuffer.h>
33+#include <framework/graphics/drawqueue.h>
34+#include <framework/luaengine/luaobject.h>
35+#include <framework/net/server.h>
36+
37+enum NewDrawType : uint8 {
38+ NewDrawNormal = 0,
39+ NewDrawMount = 5,
40+ NewDrawOutfit = 6,
41+ NewDrawOutfitLayers = 7,
42+ NewDrawMissle = 10
43+};
44+
45+enum FrameGroupType : uint8 {
46+ FrameGroupDefault = 0,
47+ FrameGroupIdle = FrameGroupDefault,
48+ FrameGroupMoving
49+};
50+
51+enum ThingCategory : uint8 {
52+ ThingCategoryItem = 0,
53+ ThingCategoryCreature,
54+ ThingCategoryEffect,
55+ ThingCategoryMissile,
56+ ThingInvalidCategory,
57+ ThingLastCategory = ThingInvalidCategory
58+};
59+
60+enum ThingAttr : uint8 {
61+ ThingAttrGround = 0,
62+ ThingAttrGroundBorder = 1,
63+ ThingAttrOnBottom = 2,
64+ ThingAttrOnTop = 3,
65+ ThingAttrContainer = 4,
66+ ThingAttrStackable = 5,
67+ ThingAttrForceUse = 6,
68+ ThingAttrMultiUse = 7,
69+ ThingAttrWritable = 8,
70+ ThingAttrWritableOnce = 9,
71+ ThingAttrFluidContainer = 10,
72+ ThingAttrSplash = 11,
73+ ThingAttrNotWalkable = 12,
74+ ThingAttrNotMoveable = 13,
75+ ThingAttrBlockProjectile = 14,
76+ ThingAttrNotPathable = 15,
77+ ThingAttrPickupable = 16,
78+ ThingAttrHangable = 17,
79+ ThingAttrHookSouth = 18,
80+ ThingAttrHookEast = 19,
81+ ThingAttrRotateable = 20,
82+ ThingAttrLight = 21,
83+ ThingAttrDontHide = 22,
84+ ThingAttrTranslucent = 23,
85+ ThingAttrDisplacement = 24,
86+ ThingAttrElevation = 25,
87+ ThingAttrLyingCorpse = 26,
88+ ThingAttrAnimateAlways = 27,
89+ ThingAttrMinimapColor = 28,
90+ ThingAttrLensHelp = 29,
91+ ThingAttrFullGround = 30,
92+ ThingAttrLook = 31,
93+ ThingAttrCloth = 32,
94+ ThingAttrMarket = 33,
95+ ThingAttrUsable = 34,
96+ ThingAttrWrapable = 35,
97+ ThingAttrUnwrapable = 36,
98+ ThingAttrTopEffect = 37,
99+ ThingAttrBones = 38,
100+
101+ // additional
102+ ThingAttrOpacity = 100,
103+ ThingAttrNotPreWalkable = 101,
104+
105+ ThingAttrFloorChange = 252,
106+ ThingAttrNoMoveAnimation = 253, // 10.10: real value is 16, but we need to do this for backwards compatibility
107+ ThingAttrChargeable = 254, // deprecated
108+ ThingLastAttr = 255
109+};
110+
111+enum SpriteMask {
112+ SpriteMask = 1,
113+};
114+
115+struct MarketData {
116+ std::string name;
117+ int category;
118+ uint16 requiredLevel;
119+ uint16 restrictVocation;
120+ uint16 showAs;
121+ uint16 tradeAs;
122+};
123+
124+struct StoreCategory {
125+ std::string name;
126+ std::string description;
127+ int state;
128+ std::string icon;
129+ std::string parent;
130+};
131+
132+struct StoreOffer {
133+ int id;
134+ std::string name;
135+ std::string description;
136+ int price;
137+ int state;
138+ std::string icon;
139+};
140+
141+struct Imbuement {
142+ int id;
143+ std::string name;
144+ std::string description;
145+ std::string group;
146+ int imageId;
147+ int duration;
148+ bool premiumOnly;
149+ std::vector<std::pair<ItemPtr, std::string>> sources;
150+ int cost;
151+ int successRate;
152+ int protectionCost;
153+};
154+
155+struct Light {
156+ Point pos;
157+ uint8_t color = 215;
158+ uint8_t intensity = 0;
159+};
160+
161+struct DrawOutfitParams {
162+ Rect dest;
163+ TexturePtr texture;
164+ Rect src;
165+ Point offset;
166+ Color color;
167+};
168+
169+class ThingType : public LuaObject
170+{
171+public:
172+ ThingType();
173+
174+ void unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr& fin);
175+ void unserializeOtml(const OTMLNodePtr& node);
176+ void unload();
177+
178+ void serialize(const FileStreamPtr& fin);
179+ void exportImage(std::string fileName);
180+ void replaceSprites(std::map<uint32_t, ImagePtr>& replacements, std::string fileName);
181+
182+ DrawQueueItem* draw(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color = Color::white, LightView* lightView = nullptr);
183+ DrawQueueItem* draw(const Rect& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color = Color::white);
184+ std::shared_ptr<DrawOutfitParams> drawOutfit(const Point& dest, int maskLayer, int xPattern, int yPattern, int zPattern, int animationPhase, Color color = Color::white, LightView* lightView = nullptr);
185+ Rect getDrawSize(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase);
186+ void drawWithShader(const Point& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, const std::string& shader, Color color = Color::white, LightView* lightView = nullptr);
187+ void drawWithShader(const Rect& dest, int layer, int xPattern, int yPattern, int zPattern, int animationPhase, const std::string& shader, Color color = Color::white);
188+
189+ uint16 getId() { return m_id; }
190+ ThingCategory getCategory() { return m_category; }
191+ bool isNull() { return m_null; }
192+ bool hasAttr(ThingAttr attr) { return m_attribs.has(attr); }
193+ bool isLoaded() { return m_loaded; }
194+ ticks_t getLastUsage() { return m_lastUsage; }
195+
196+ Size getSize() { return m_size; }
197+ int getWidth() { return m_size.width(); }
198+ int getHeight() { return m_size.height(); }
199+ int getExactSize(int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animationPhase = 0);
200+ int getRealSize() { return m_realSize; }
201+ int getLayers() { return m_layers; }
202+ int getNumPatternX() { return m_numPatternX; }
203+ int getNumPatternY() { return m_numPatternY; }
204+ int getNumPatternZ() { return m_numPatternZ; }
205+ int getAnimationPhases() { return m_animationPhases; }
206+ AnimatorPtr getAnimator() { return m_animator; }
207+ AnimatorPtr getIdleAnimator() { return m_idleAnimator; }
208+ Point getDisplacement() { return m_displacement; }
209+ int getDisplacementX() { return getDisplacement().x; }
210+ int getDisplacementY() { return getDisplacement().y; }
211+ int getElevation() { return m_elevation; }
212+ const Point& getBones(int direction) { return m_bones[direction]; }
213+
214+ int getGroundSpeed() { return m_attribs.get<uint16>(ThingAttrGround); }
215+ int getMaxTextLength() { return m_attribs.has(ThingAttrWritableOnce) ? m_attribs.get<uint16>(ThingAttrWritableOnce) : m_attribs.get<uint16>(ThingAttrWritable); }
216+ Light getLight() { return m_attribs.get<Light>(ThingAttrLight); }
217+ int getMinimapColor() { return m_attribs.get<uint16>(ThingAttrMinimapColor); }
218+ int getLensHelp() { return m_attribs.get<uint16>(ThingAttrLensHelp); }
219+ int getClothSlot() { return m_attribs.get<uint16>(ThingAttrCloth); }
220+ MarketData getMarketData() { return m_attribs.get<MarketData>(ThingAttrMarket); }
221+ bool isGround() { return m_attribs.has(ThingAttrGround); }
222+ bool isGroundBorder() { return m_attribs.has(ThingAttrGroundBorder); }
223+ bool isOnBottom() { return m_attribs.has(ThingAttrOnBottom); }
224+ bool isOnTop() { return m_attribs.has(ThingAttrOnTop); }
225+ bool isContainer() { return m_attribs.has(ThingAttrContainer); }
226+ bool isStackable() { return m_attribs.has(ThingAttrStackable); }
227+ bool isForceUse() { return m_attribs.has(ThingAttrForceUse); }
228+ bool isMultiUse() { return m_attribs.has(ThingAttrMultiUse); }
229+ bool isWritable() { return m_attribs.has(ThingAttrWritable); }
230+ bool isChargeable() { return m_attribs.has(ThingAttrChargeable); }
231+ bool isWritableOnce() { return m_attribs.has(ThingAttrWritableOnce); }
232+ bool isFluidContainer() { return m_attribs.has(ThingAttrFluidContainer); }
233+ bool isSplash() { return m_attribs.has(ThingAttrSplash); }
234+ bool isNotWalkable() { return m_attribs.has(ThingAttrNotWalkable); }
235+ bool isNotMoveable() { return m_attribs.has(ThingAttrNotMoveable); }
236+ bool blockProjectile() { return m_attribs.has(ThingAttrBlockProjectile); }
237+ bool isNotPathable() { return m_attribs.has(ThingAttrNotPathable); }
238+ bool isPickupable() { return m_attribs.has(ThingAttrPickupable); }
239+ bool isHangable() { return m_attribs.has(ThingAttrHangable); }
240+ bool isHookSouth() { return m_attribs.has(ThingAttrHookSouth); }
241+ bool isHookEast() { return m_attribs.has(ThingAttrHookEast); }
242+ bool isRotateable() { return m_attribs.has(ThingAttrRotateable); }
243+ bool hasLight() { return m_attribs.has(ThingAttrLight); }
244+ bool isDontHide() { return m_attribs.has(ThingAttrDontHide); }
245+ bool isTranslucent() { return m_attribs.has(ThingAttrTranslucent); }
246+ bool hasDisplacement() { return m_attribs.has(ThingAttrDisplacement); }
247+ bool hasElevation() { return m_attribs.has(ThingAttrElevation); }
248+ bool isLyingCorpse() { return m_attribs.has(ThingAttrLyingCorpse); }
249+ bool isAnimateAlways() { return m_attribs.has(ThingAttrAnimateAlways); }
250+ bool hasMiniMapColor() { return m_attribs.has(ThingAttrMinimapColor); }
251+ bool hasLensHelp() { return m_attribs.has(ThingAttrLensHelp); }
252+ bool isFullGround() { return m_attribs.has(ThingAttrFullGround); }
253+ bool isIgnoreLook() { return m_attribs.has(ThingAttrLook); }
254+ bool isCloth() { return m_attribs.has(ThingAttrCloth); }
255+ bool isMarketable() { return m_attribs.has(ThingAttrMarket); }
256+ bool isUsable() { return m_attribs.has(ThingAttrUsable); }
257+ bool isWrapable() { return m_attribs.has(ThingAttrWrapable); }
258+ bool isUnwrapable() { return m_attribs.has(ThingAttrUnwrapable); }
259+ bool isTopEffect() { return m_attribs.has(ThingAttrTopEffect); }
260+ bool hasBones() { return m_attribs.has(ThingAttrBones); }
261+
262+ std::vector<int> getSprites() { return m_spritesIndex; }
263+
264+ // additional
265+ float getOpacity() { return m_opacity; }
266+ bool isNotPreWalkable() { return m_attribs.has(ThingAttrNotPreWalkable); }
267+ void setPathable(bool var);
268+
269+private:
270+ const TexturePtr& getTexture(int animationPhase);
271+ Size getBestTextureDimension(int w, int h, int count);
272+ uint getSpriteIndex(int w, int h, int l, int x, int y, int z, int a);
273+ uint getTextureIndex(int l, int x, int y, int z);
274+
275+ ThingCategory m_category;
276+ uint16 m_id;
277+ bool m_null;
278+ stdext::dynamic_storage<uint8> m_attribs;
279+
280+ Size m_size;
281+ Point m_displacement;
282+ AnimatorPtr m_animator;
283+ AnimatorPtr m_idleAnimator;
284+ std::vector<Point> m_bones;
285+ int m_animationPhases;
286+ int m_exactSize;
287+ int m_realSize;
288+ int m_numPatternX, m_numPatternY, m_numPatternZ;
289+ int m_layers;
290+ int m_elevation;
291+ float m_opacity;
292+ std::string m_customImage;
293+
294+ std::vector<int> m_spritesIndex;
295+ std::vector<TexturePtr> m_textures;
296+ std::vector<std::vector<Rect>> m_texturesFramesRects;
297+ std::vector<std::vector<Rect>> m_texturesFramesOriginRects;
298+ std::vector<std::vector<Point>> m_texturesFramesOffsets;
299+
300+ bool m_loaded = false;
301+ time_t m_lastUsage;
302+};
303+
304+struct DrawQueueItemThingWithShader : public DrawQueueItemTexturedRect {
305+ DrawQueueItemThingWithShader(const Rect& rect, const TexturePtr& texture, const Rect& src, const Point& offset, const Point& center, int32_t colors, const std::string& shader) :
306+ DrawQueueItemTexturedRect(rect, texture, src, Color::white), m_offset(offset), m_center(center), m_colors(colors), m_shader(shader)
307+ {};
308+
309+ void draw() override;
310+ void draw(const Point& pos) override
311+ {}
312+ bool cache() override
313+ {
314+ return false;
315+ }
316+
317+ Point m_offset;
318+ Point m_center;
319+ int32_t m_colors;
320+ std::string m_shader;
321+};
322+
323+#endif
A RD_Client/src/client/thingtypemanager.cpp +497-0 View file
@@ -0,0 +1,497 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "thingtypemanager.h"
24+#include "spritemanager.h"
25+#include "thing.h"
26+#include "thingtype.h"
27+#include "itemtype.h"
28+#include "creature.h"
29+#include "creatures.h"
30+#include "game.h"
31+
32+#include <framework/core/resourcemanager.h>
33+#include <framework/core/filestream.h>
34+#include <framework/core/binarytree.h>
35+#include <framework/xml/tinyxml.h>
36+#include <framework/otml/otml.h>
37+#include <framework/util/stats.h>
38+
39+ThingTypeManager g_things;
40+
41+void ThingTypeManager::init()
42+{
43+ m_nullThingType = ThingTypePtr(new ThingType);
44+ m_nullItemType = ItemTypePtr(new ItemType);
45+ m_datSignature = 0;
46+ m_contentRevision = 0;
47+ m_otbMinorVersion = 0;
48+ m_otbMajorVersion = 0;
49+ m_datLoaded = false;
50+ m_xmlLoaded = false;
51+ m_otbLoaded = false;
52+ for (int i = 0; i < ThingLastCategory; ++i) {
53+ m_thingTypes[i].resize(1, m_nullThingType);
54+ m_checkIndex[i] = 0;
55+ }
56+ m_itemTypes.resize(1, m_nullItemType);
57+
58+ check();
59+}
60+
61+void ThingTypeManager::terminate()
62+{
63+ for(int i = 0; i < ThingLastCategory; ++i)
64+ m_thingTypes[i].clear();
65+ m_itemTypes.clear();
66+ m_reverseItemTypes.clear();
67+ m_marketCategories.clear();
68+ m_nullThingType = nullptr;
69+ m_nullItemType = nullptr;
70+
71+ if (m_checkEvent) {
72+ m_checkEvent->cancel();
73+ m_checkEvent = nullptr;
74+ }
75+}
76+
77+void ThingTypeManager::check()
78+{
79+ // removes unused textures from memory after 60s, 500 checks / s
80+ m_checkEvent = g_dispatcher.scheduleEvent(std::bind(&ThingTypeManager::check, &g_things), 1000);
81+
82+ for (size_t i = 0; i < ThingLastCategory; ++i) {
83+ size_t limit = std::min<size_t>(m_checkIndex[i] + 100, m_thingTypes[i].size());
84+ for (size_t j = m_checkIndex[i]; j < limit; ++j) {
85+ if (m_thingTypes[i][j]->isLoaded() && m_thingTypes[i][j]->getLastUsage() + 60 < g_clock.seconds()) {
86+ m_thingTypes[i][j]->unload();
87+ }
88+ }
89+ m_checkIndex[i] = limit;
90+ if (m_checkIndex[i] >= m_thingTypes[i].size()) {
91+ m_checkIndex[i] = 0;
92+ }
93+ }
94+}
95+
96+#ifdef WITH_ENCRYPTION
97+void ThingTypeManager::saveDat(std::string fileName)
98+{
99+ if(!m_datLoaded)
100+ stdext::throw_exception("failed to save, dat is not loaded");
101+
102+ try {
103+ FileStreamPtr fin = g_resources.createFile(fileName);
104+ if(!fin)
105+ stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
106+
107+ fin->addU32(m_datSignature);
108+
109+ for(int category = 0; category < ThingLastCategory; ++category)
110+ fin->addU16(m_thingTypes[category].size() - 1);
111+
112+ for(int category = 0; category < ThingLastCategory; ++category) {
113+ uint16 firstId = 1;
114+ if(category == ThingCategoryItem)
115+ firstId = 100;
116+
117+ for(uint16 id = firstId; id < m_thingTypes[category].size(); ++id)
118+ m_thingTypes[category][id]->serialize(fin);
119+ }
120+
121+
122+ fin->flush();
123+ fin->close();
124+ } catch(std::exception& e) {
125+ g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
126+ }
127+}
128+
129+void ThingTypeManager::dumpTextures(std::string dir)
130+{
131+ if (dir.empty()) {
132+ g_logger.error("Empty dir for sprites dump");
133+ return;
134+ }
135+ g_resources.makeDir(dir);
136+ for (int category = 0; category < ThingLastCategory; ++category) {
137+ g_resources.makeDir(dir + "/" + std::to_string((int)category));
138+
139+ uint16 firstId = 1;
140+ if (category == ThingCategoryItem)
141+ firstId = 100;
142+
143+ for (uint16 id = firstId; id < m_thingTypes[category].size(); ++id)
144+ m_thingTypes[category][id]->exportImage(dir + "/" + std::to_string((int)category) + "/" + std::to_string(id) + ".png");
145+ }
146+}
147+
148+void ThingTypeManager::replaceTextures(std::string dir) {
149+ if (dir.empty()) {
150+ g_logger.error("Empty dir for sprites dump");
151+ return;
152+ }
153+
154+ std::map<uint32_t, ImagePtr> replacements;
155+ for (int category = 0; category < ThingLastCategory; ++category) {
156+ uint16 firstId = 1;
157+ if (category == ThingCategoryItem)
158+ firstId = 100;
159+
160+ for (uint16 id = firstId; id < m_thingTypes[category].size(); ++id) {
161+ std::string fileName = dir + "/" + std::to_string((int)category) + "/" + std::to_string(id) + "_[][x2.000000].png";
162+ m_thingTypes[category][id]->replaceSprites(replacements, fileName);
163+ }
164+ }
165+ //g_sprites.saveReplacedSpr(dir + "/sprites.spr", replacements);
166+}
167+
168+#endif
169+
170+bool ThingTypeManager::loadDat(std::string file)
171+{
172+ m_datLoaded = false;
173+ m_datSignature = 0;
174+ m_contentRevision = 0;
175+ try {
176+ file = g_resources.guessFilePath(file, "dat");
177+
178+ FileStreamPtr fin = g_resources.openFile(file, g_game.getFeature(Otc::GameDontCacheFiles));
179+
180+ m_datSignature = fin->getU32();
181+ m_contentRevision = static_cast<uint16_t>(m_datSignature);
182+
183+ for(int category = 0; category < ThingLastCategory; ++category) {
184+ int count = fin->getU16() + 1;
185+ m_thingTypes[category].clear();
186+ m_thingTypes[category].resize(count, m_nullThingType);
187+ }
188+
189+ m_marketCategories.clear();
190+ for(int category = 0; category < ThingLastCategory; ++category) {
191+ uint16 firstId = 1;
192+ if(category == ThingCategoryItem)
193+ firstId = 100;
194+ for(uint16 id = firstId; id < m_thingTypes[category].size(); ++id) {
195+ ThingTypePtr type(new ThingType);
196+ type->unserialize(id, (ThingCategory)category, fin);
197+ m_thingTypes[category][id] = type;
198+ if (type->isMarketable()) {
199+ auto marketData = type->getMarketData();
200+ m_marketCategories.insert(marketData.category);
201+ }
202+ }
203+ }
204+
205+ m_datLoaded = true;
206+ g_lua.callGlobalField("g_things", "onLoadDat", file);
207+ return true;
208+ } catch(stdext::exception& e) {
209+ g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what()));
210+ return false;
211+ }
212+}
213+
214+bool ThingTypeManager::loadOtml(std::string file)
215+{
216+ try {
217+ file = g_resources.guessFilePath(file, "otml");
218+
219+ OTMLDocumentPtr doc = OTMLDocument::parse(file);
220+ for(const OTMLNodePtr& node : doc->children()) {
221+ ThingCategory category;
222+ if(node->tag() == "creatures")
223+ category = ThingCategoryCreature;
224+ else if(node->tag() == "items")
225+ category = ThingCategoryItem;
226+ else if(node->tag() == "effects")
227+ category = ThingCategoryEffect;
228+ else if(node->tag() == "missiles")
229+ category = ThingCategoryMissile;
230+ else {
231+ throw OTMLException(node, "not a valid thing category");
232+ }
233+
234+ for(const OTMLNodePtr& node2 : node->children()) {
235+ uint16 id = stdext::safe_cast<uint16>(node2->tag());
236+ ThingTypePtr type = getThingType(id, category);
237+ if(!type)
238+ throw OTMLException(node2, "thing not found");
239+ type->unserializeOtml(node2);
240+ }
241+ }
242+ return true;
243+ } catch(std::exception& e) {
244+ g_logger.error(stdext::format("Failed to read dat otml '%s': %s'", file, e.what()));
245+ return false;
246+ }
247+}
248+
249+void ThingTypeManager::loadOtb(const std::string& file)
250+{
251+ try {
252+ FileStreamPtr fin = g_resources.openFile(file, g_game.getFeature(Otc::GameDontCacheFiles));
253+
254+ uint signature = fin->getU32();
255+ if (signature != 0)
256+ stdext::throw_exception("invalid otb file");
257+
258+ BinaryTreePtr root = fin->getBinaryTree();
259+ root->skip(1); // otb first byte is always 0
260+
261+ signature = root->getU32();
262+ if (signature != 0)
263+ stdext::throw_exception("invalid otb file");
264+
265+ uint8 rootAttr = root->getU8();
266+ if (rootAttr == 0x01) { // OTB_ROOT_ATTR_VERSION
267+ uint16 size = root->getU16();
268+ if (size != 4 + 4 + 4 + 128)
269+ stdext::throw_exception("invalid otb root attr version size");
270+
271+ m_otbMajorVersion = root->getU32();
272+ m_otbMinorVersion = root->getU32();
273+ root->skip(4); // buildNumber
274+ root->skip(128); // description
275+ }
276+
277+ BinaryTreeVec children = root->getChildren();
278+ m_reverseItemTypes.clear();
279+ m_itemTypes.resize(children.size() + 1, m_nullItemType);
280+ m_reverseItemTypes.resize(children.size() + 1, m_nullItemType);
281+
282+ for (const BinaryTreePtr& node : children) {
283+ ItemTypePtr itemType(new ItemType);
284+ itemType->unserialize(node);
285+ addItemType(itemType);
286+
287+ uint16 clientId = itemType->getClientId();
288+ if (unlikely(clientId >= m_reverseItemTypes.size()))
289+ m_reverseItemTypes.resize(clientId + 1);
290+ m_reverseItemTypes[clientId] = itemType;
291+ }
292+
293+ m_otbLoaded = true;
294+ g_lua.callGlobalField("g_things", "onLoadOtb", file);
295+ } catch (std::exception& e) {
296+ g_logger.error(stdext::format("Failed to load '%s' (OTB file): %s", file, e.what()));
297+ }
298+}
299+
300+
301+void ThingTypeManager::loadXml(const std::string& file)
302+{
303+ try {
304+ if(!isOtbLoaded())
305+ stdext::throw_exception("OTB must be loaded before XML");
306+
307+ TiXmlDocument doc;
308+ doc.Parse(g_resources.readFileContents(file).c_str());
309+ if(doc.Error())
310+ stdext::throw_exception(stdext::format("failed to parse '%s': '%s'", file, doc.ErrorDesc()));
311+
312+ TiXmlElement* root = doc.FirstChildElement();
313+ if(!root || root->ValueTStr() != "items")
314+ stdext::throw_exception("invalid root tag name");
315+
316+ for(TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) {
317+ if(unlikely(element->ValueTStr() != "item"))
318+ continue;
319+
320+ uint16 id = element->readType<uint16>("id");
321+ if(id != 0) {
322+ std::vector<std::string> s_ids = stdext::split(element->Attribute("id"), ";");
323+ for(const std::string& s : s_ids) {
324+ std::vector<int32> ids = stdext::split<int32>(s, "-");
325+ if(ids.size() > 1) {
326+ int32 i = ids[0];
327+ while(i <= ids[1])
328+ parseItemType(i++, element);
329+ } else
330+ parseItemType(atoi(s.c_str()), element);
331+ }
332+ } else {
333+ std::vector<int32> begin = stdext::split<int32>(element->Attribute("fromid"), ";");
334+ std::vector<int32> end = stdext::split<int32>(element->Attribute("toid"), ";");
335+ if(begin[0] && begin.size() == end.size()) {
336+ size_t size = begin.size();
337+ for(size_t i = 0; i < size; ++i)
338+ while(begin[i] <= end[i])
339+ parseItemType(begin[i]++, element);
340+ }
341+ }
342+ }
343+
344+ doc.Clear();
345+ m_xmlLoaded = true;
346+ g_logger.debug("items.xml read successfully.");
347+ } catch(std::exception& e) {
348+ g_logger.error(stdext::format("Failed to load '%s' (XML file): %s", file, e.what()));
349+ }
350+}
351+
352+void ThingTypeManager::parseItemType(uint16 serverId, TiXmlElement* elem)
353+{
354+ ItemTypePtr itemType = nullptr;
355+
356+ bool s;
357+ int d;
358+
359+ if(g_game.getClientVersion() < 960) {
360+ s = serverId > 20000 && serverId < 20100;
361+ d = 20000;
362+ } else {
363+ s = serverId > 30000 && serverId < 30100;
364+ d = 30000;
365+ }
366+
367+ if(s) {
368+ serverId -= d;
369+ itemType = ItemTypePtr(new ItemType);
370+ itemType->setServerId(serverId);
371+ addItemType(itemType);
372+ } else
373+ itemType = getItemType(serverId);
374+
375+ itemType->setName(elem->Attribute("name"));
376+ for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
377+ std::string key = attrib->Attribute("key");
378+ if(key.empty())
379+ continue;
380+
381+ stdext::tolower(key);
382+ if(key == "description")
383+ itemType->setDesc(attrib->Attribute("value"));
384+ else if(key == "weapontype")
385+ itemType->setCategory(ItemCategoryWeapon);
386+ else if(key == "ammotype")
387+ itemType->setCategory(ItemCategoryAmmunition);
388+ else if(key == "armor")
389+ itemType->setCategory(ItemCategoryArmor);
390+ else if(key == "charges")
391+ itemType->setCategory(ItemCategoryCharges);
392+ else if(key == "type") {
393+ std::string value = attrib->Attribute("value");
394+ stdext::tolower(value);
395+
396+ if(value == "key")
397+ itemType->setCategory(ItemCategoryKey);
398+ else if(value == "magicfield")
399+ itemType->setCategory(ItemCategoryMagicField);
400+ else if(value == "teleport")
401+ itemType->setCategory(ItemCategoryTeleport);
402+ else if(value == "door")
403+ itemType->setCategory(ItemCategoryDoor);
404+ }
405+ }
406+}
407+
408+void ThingTypeManager::addItemType(const ItemTypePtr& itemType)
409+{
410+ uint16 id = itemType->getServerId();
411+ if(unlikely(id >= m_itemTypes.size()))
412+ m_itemTypes.resize(id + 1, m_nullItemType);
413+ m_itemTypes[id] = itemType;
414+}
415+
416+const ItemTypePtr& ThingTypeManager::findItemTypeByClientId(uint16 id)
417+{
418+ if(id == 0 || id >= m_reverseItemTypes.size())
419+ return m_nullItemType;
420+
421+ if(m_reverseItemTypes[id])
422+ return m_reverseItemTypes[id];
423+ else
424+ return m_nullItemType;
425+}
426+
427+const ItemTypePtr& ThingTypeManager::findItemTypeByName(std::string name)
428+{
429+ for(const ItemTypePtr& it : m_itemTypes)
430+ if(it->getName() == name)
431+ return it;
432+ return m_nullItemType;
433+}
434+
435+ItemTypeList ThingTypeManager::findItemTypesByName(std::string name)
436+{
437+ ItemTypeList ret;
438+ for(const ItemTypePtr& it : m_itemTypes)
439+ if(it->getName() == name)
440+ ret.push_back(it);
441+ return ret;
442+}
443+
444+ItemTypeList ThingTypeManager::findItemTypesByString(std::string name)
445+{
446+ ItemTypeList ret;
447+ for(const ItemTypePtr& it : m_itemTypes)
448+ if(it->getName().find(name) != std::string::npos)
449+ ret.push_back(it);
450+ return ret;
451+}
452+
453+const ThingTypePtr& ThingTypeManager::getThingType(uint16 id, ThingCategory category)
454+{
455+ if(category >= ThingLastCategory || id >= m_thingTypes[category].size()) {
456+ g_logger.error(stdext::format("invalid thing type client id %d in category %d", id, category));
457+ return m_nullThingType;
458+ }
459+ return m_thingTypes[category][id];
460+}
461+
462+const ItemTypePtr& ThingTypeManager::getItemType(uint16 id)
463+{
464+ if(id >= m_itemTypes.size() || m_itemTypes[id] == m_nullItemType) {
465+ g_logger.error(stdext::format("invalid thing type, server id: %d", id));
466+ return m_nullItemType;
467+ }
468+ return m_itemTypes[id];
469+}
470+
471+ThingTypeList ThingTypeManager::findThingTypeByAttr(ThingAttr attr, ThingCategory category)
472+{
473+ ThingTypeList ret;
474+ for(const ThingTypePtr& type : m_thingTypes[category])
475+ if(type->hasAttr(attr))
476+ ret.push_back(type);
477+ return ret;
478+}
479+
480+ItemTypeList ThingTypeManager::findItemTypeByCategory(ItemCategory category)
481+{
482+ ItemTypeList ret;
483+ for(const ItemTypePtr& type : m_itemTypes)
484+ if(type->getCategory() == category)
485+ ret.push_back(type);
486+ return ret;
487+}
488+
489+const ThingTypeList& ThingTypeManager::getThingTypes(ThingCategory category)
490+{
491+ ThingTypeList ret;
492+ if(category >= ThingLastCategory)
493+ stdext::throw_exception(stdext::format("invalid thing type category %d", category));
494+ return m_thingTypes[category];
495+}
496+
497+/* vim: set ts=4 sw=4 et: */
A RD_Client/src/client/thingtypemanager.h +119-0 View file
@@ -0,0 +1,119 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef THINGTYPEMANAGER_H
24+#define THINGTYPEMANAGER_H
25+
26+#include <framework/global.h>
27+#include <framework/core/declarations.h>
28+#include <framework/core/eventdispatcher.h>
29+
30+#include "thingtype.h"
31+#include "itemtype.h"
32+
33+class ThingTypeManager
34+{
35+public:
36+ void init();
37+ void terminate();
38+ void check();
39+
40+ bool loadDat(std::string file);
41+ bool loadOtml(std::string file);
42+ void loadOtb(const std::string& file);
43+ void loadXml(const std::string& file);
44+ void parseItemType(uint16 id, TiXmlElement *elem);
45+
46+#ifdef WITH_ENCRYPTION
47+ void saveDat(std::string fileName);
48+ void dumpTextures(std::string dir);
49+ void replaceTextures(std::string dir);
50+#endif
51+
52+ void addItemType(const ItemTypePtr& itemType);
53+ const ItemTypePtr& findItemTypeByClientId(uint16 id);
54+ const ItemTypePtr& findItemTypeByName(std::string name);
55+ ItemTypeList findItemTypesByName(std::string name);
56+ ItemTypeList findItemTypesByString(std::string str);
57+
58+ std::set<int> getMarketCategories()
59+ {
60+ return m_marketCategories;
61+ }
62+
63+ const ThingTypePtr& getNullThingType() { return m_nullThingType; }
64+ const ItemTypePtr& getNullItemType() { return m_nullItemType; }
65+
66+ const ThingTypePtr& getThingType(uint16 id, ThingCategory category);
67+ const ItemTypePtr& getItemType(uint16 id);
68+ ThingType* rawGetThingType(uint16 id, ThingCategory category) {
69+ VALIDATE(id < m_thingTypes[category].size());
70+ return m_thingTypes[category][id].get();
71+ }
72+ ItemType* rawGetItemType(uint16 id) {
73+ VALIDATE(id < m_itemTypes.size());
74+ return m_itemTypes[id].get();
75+ }
76+
77+ ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category);
78+ ItemTypeList findItemTypeByCategory(ItemCategory category);
79+
80+ const ThingTypeList& getThingTypes(ThingCategory category);
81+ const ItemTypeList& getItemTypes() { return m_itemTypes; }
82+
83+ uint32 getDatSignature() { return m_datSignature; }
84+ uint32 getOtbMajorVersion() { return m_otbMajorVersion; }
85+ uint32 getOtbMinorVersion() { return m_otbMinorVersion; }
86+ uint16 getContentRevision() { return m_contentRevision; }
87+
88+ bool isDatLoaded() { return m_datLoaded; }
89+ bool isXmlLoaded() { return m_xmlLoaded; }
90+ bool isOtbLoaded() { return m_otbLoaded; }
91+
92+ bool isValidDatId(uint16 id, ThingCategory category) { return id >= 1 && id < m_thingTypes[category].size(); }
93+ bool isValidOtbId(uint16 id) { return id >= 1 && id < m_itemTypes.size(); }
94+
95+private:
96+ ThingTypeList m_thingTypes[ThingLastCategory];
97+ ItemTypeList m_reverseItemTypes;
98+ ItemTypeList m_itemTypes;
99+ std::set<int> m_marketCategories;
100+
101+ ThingTypePtr m_nullThingType;
102+ ItemTypePtr m_nullItemType;
103+
104+ bool m_datLoaded;
105+ bool m_xmlLoaded;
106+ bool m_otbLoaded;
107+
108+ uint32 m_otbMinorVersion;
109+ uint32 m_otbMajorVersion;
110+ uint32 m_datSignature;
111+ uint16 m_contentRevision;
112+
113+ ScheduledEventPtr m_checkEvent;
114+ size_t m_checkIndex[ThingLastCategory];
115+};
116+
117+extern ThingTypeManager g_things;
118+
119+#endif
Top