1 /* ResidualVM - A 3D game interpreter
2 *
3 * ResidualVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the AUTHORS
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #ifndef STARK_RESOURCES_RESOURCE_H
24 #define STARK_RESOURCES_RESOURCE_H
25
26 #include "common/array.h"
27 #include "common/str.h"
28
29 namespace Stark {
30
31 namespace Formats {
32 class XRCReadStream;
33 }
34 class ResourceSerializer;
35
36 namespace Resources {
37
38 class Type {
39 public:
40 enum ResourceType {
41 kInvalid = 0,
42 kRoot = 1,
43 kLevel = 2,
44 kLocation = 3,
45 kLayer = 4,
46 kCamera = 5,
47 kFloor = 6,
48 kFloorFace = 7,
49 kItem = 8,
50 kScript = 9,
51 kAnimHierarchy = 10,
52 kAnim = 11,
53 kDirection = 12,
54 kImage = 13,
55 kAnimScript = 14,
56 kAnimScriptItem = 15,
57 kSoundItem = 16,
58 kPath = 17,
59 kFloorField = 18,
60 kBookmark = 19,
61 kKnowledgeSet = 20,
62 kKnowledge = 21,
63 kCommand = 22,
64 kPATTable = 23,
65 kContainer = 26,
66 kDialog = 27,
67 kSpeech = 29,
68 kLight = 30,
69 kCursor = 31, // Not sure about this one
70 kBonesMesh = 32,
71 kScroll = 33,
72 kFMV = 34,
73 kLipSync = 35,
74 kAnimSoundTrigger = 36,
75 kString = 37,
76 kTextureSet = 38
77 };
78
79 Type();
80 Type(ResourceType type);
81
82 ResourceType get() const;
83 const char *getName() const;
84
85 bool operator==(const Type &other) const {
86 return other._type == _type;
87 }
88
89 bool operator!=(const Type &other) const {
90 return other._type != _type;
91 }
92
93 bool operator==(const Type::ResourceType other) const {
94 return other == _type;
95 }
96
97 bool operator!=(const Type::ResourceType other) const {
98 return other != _type;
99 }
100
101 private:
102 ResourceType _type;
103 };
104
105 /**
106 * Game resource base object
107 *
108 * The in-game objects are represented using subclasses of this class.
109 *
110 * The game world is made of a tree of resources, with each level further down
111 * the tree adding further details. An instance of this class is a node in that
112 * tree.
113 *
114 * The first few tree levels are as follow:
115 * - Root
116 * - Level
117 * - Location
118 * - Layer
119 *
120 * The actual world tree is cut off in several sub-trees. There is one sub-tree
121 * per xarc archive. For resource management reasons the sub-trees are not merged
122 * in memory, the sub-trees are loaded and unloaded as needed, according to the
123 * current level / location.
124 *
125 * The xarc archives contain each an xrc file, which is a serialized version
126 * of the initial state of a resource sub-tree. The readData method is called for
127 * each resource by the archive loader when a resource tree is loaded to set up
128 * its initial state.
129 *
130 * As the game plays, modifications are made to the resources to reflect
131 * the game's state. When the resource sub-trees are loaded or unloaded their
132 * state is restored or persisted by the state provider. The saveLoad method
133 * is called to perform the serialization / deserialization of a resource.
134 * The saveLoadCurrent method is additionally called when loading or saving
135 * a sub-tree corresponding to the current level / location. This allows to
136 * persist additional data needed when restoring an active location.
137 *
138 * The OnEnterLocation and OnExitLocation methods are called by the resource
139 * provider when entering or leaving a level / location.
140 *
141 * The OnGameLoop method is called during the game loop.
142 *
143 */
144 class Object {
145 public:
146 virtual ~Object();
147
148 /** Get the resource type */
getType()149 Type getType() const { return _type; }
150
151 /** Get the resource sub type */
getSubType()152 byte getSubType() const { return _subType; }
153
154 /** Get the resource index */
getIndex()155 uint16 getIndex() const { return _index; }
156
157 /** Get the resource index as a string */
getIndexAsString()158 Common::String getIndexAsString() const { return Common::String::format("%02x", _index); }
159
160 /** Get the name of the resource */
getName()161 Common::String getName() const { return _name; }
162
163 /**
164 * Deserialize the resource static data and initial state.
165 */
166 virtual void readData(Formats::XRCReadStream *stream);
167
168 /**
169 * Persist / restore the resource state
170 */
171 virtual void saveLoad(ResourceSerializer *serializer);
172
173 /**
174 * Persist / restore the resource state
175 *
176 * Called only for active locations
177 */
178 virtual void saveLoadCurrent(ResourceSerializer *serializer);
179
180 /**
181 * Called when the node's initialization is complete.
182 *
183 * Allows to load additional data from file.
184 */
185 virtual void onPostRead();
186
187 /**
188 * Called when the resource sub-tree is entirely loaded.
189 *
190 * Allows to load data from other nodes.
191 */
192 virtual void onAllLoaded();
193
194 /**
195 * Called when entering a location
196 */
197 virtual void onEnterLocation();
198
199 /**
200 * Called once per game loop
201 */
202 virtual void onGameLoop();
203
204 /**
205 * Called when ScummVM pauses or resumes the engine
206 */
207 virtual void onEnginePause(bool pause);
208
209 /**
210 * Called when exiting a location
211 */
212 virtual void onExitLocation();
213
214 /**
215 * Called before a resource sub-tree is unloaded.
216 */
217 virtual void onPreDestroy();
218
219 /**
220 * Cast a resource, performing a type check
221 */
222 template<class T>
223 static T *cast(Object *resource);
224
225 /** Find the first parent resource with the specified type */
226 template<class T>
227 T *findParent();
228
229 /** Find a child resource matching the specified type, index and subtype */
230 Object *findChildWithIndex(Type type, uint16 index, int subType = -1) const;
231
232 /** Find a child resource matching the specified type, order in the children list and subtype */
233 Object *findChildWithOrder(Type type, uint16 order, int subType = -1) const;
234
235 /** Find a child resource matching the specified type, name and subtype */
236 Object *findChildWithName(Type type, const Common::String &name, int subType = -1) const;
237
238 /** Find a child matching the template parameter type */
239 template<class T>
240 T *findChild(bool mustBeUnique = true) const;
241
242 /** Find a child matching the template parameter type and the specified subtype */
243 template<class T>
244 T *findChildWithSubtype(int subType, bool mustBeUnique = true) const;
245
246 /** Find a child matching the template parameter type and the specified index */
247 template<class T>
248 T *findChildWithIndex(uint16 index, int subType = -1) const;
249
250 /** Find a child matching the template parameter type, order in the children list and subtype */
251 template<class T>
252 T *findChildWithOrder(uint16 order, int subType = -1) const;
253
254 /** Find a child matching the template parameter type, name and subtype */
255 template<class T>
256 T *findChildWithName(const Common::String &name, int subType = -1) const;
257
258 /** List children matching the template parameter type and the specified subtype */
259 template<class T>
260 Common::Array<T *> listChildren(int subType = -1) const;
261
262 /** List children recursively matching the template parameter type and the specified subtype */
263 template<class T>
264 Common::Array<T *> listChildrenRecursive(int subType = -1);
265
266 /** Add a resource to the children list */
267 void addChild(Object *child);
268
269 /** Print debug information for the resource */
270 virtual void print(uint depth = 0);
271
272 protected:
273 Object(Object *parent, byte subType, uint16 index, const Common::String &name);
274
275 void printWithDepth(uint depth, const Common::String &string) const;
276 void printDescription(uint depth) const;
277 virtual void printData();
278
279 Type _type;
280 byte _subType;
281 uint16 _index;
282 Common::String _name;
283
284 Object *_parent;
285 Common::Array<Object *> _children;
286 };
287
288 /**
289 * An unimplemented resource type.
290 *
291 * Used to display the raw resource data when dumping a resource tree.
292 * To be removed once all the resource types are implemented.
293 */
294 class UnimplementedResource : public Object {
295 public:
296 UnimplementedResource(Object *parent, Type type, byte subType, uint16 index, const Common::String &name);
297 virtual ~UnimplementedResource();
298
299 protected:
300 void readData(Formats::XRCReadStream *stream) override;
301 void printData() override;
302
303 uint32 _dataLength;
304 byte *_data;
305 };
306
307 template <class T>
cast(Object * resource)308 T* Object::cast(Object *resource) {
309 if (resource && resource->_type != T::TYPE) {
310 error("Unexpected resource type when casting resource %s instead of %s",
311 resource->_type.getName(), Type(T::TYPE).getName());
312 }
313
314 return (T *) resource;
315 }
316
317 template<>
318 Object *Object::cast<Object>(Object *resource);
319
320 template<class T>
findParent()321 T *Object::findParent() {
322 if (getType() == T::TYPE) {
323 return cast<T>(this);
324 } else if (!_parent) {
325 return nullptr;
326 } else {
327 return _parent->findParent<T>();
328 }
329 }
330
331 template<>
332 Object *Object::findParent();
333
334 template <class T>
listChildren(int subType)335 Common::Array<T *> Object::listChildren(int subType) const {
336 Common::Array<T *> list;
337
338 for (uint i = 0; i < _children.size(); i++) {
339 if (_children[i]->getType() == T::TYPE
340 && (_children[i]->getSubType() == subType || subType == -1)) {
341 // Found a matching child
342 list.push_back(Object::cast<T>(_children[i]));
343 }
344 }
345
346 return list;
347 }
348
349 template<class T>
listChildrenRecursive(int subType)350 Common::Array<T *> Object::listChildrenRecursive(int subType) {
351 Common::Array<T *> list;
352
353 for (uint i = 0; i < _children.size(); i++) {
354 if (_children[i]->getType() == T::TYPE
355 && (_children[i]->getSubType() == subType || subType == -1)) {
356 // Found a matching child
357 list.push_back(Object::cast<T>(_children[i]));
358 }
359
360 // Look for matching resources in the child's children
361 list.push_back(_children[i]->listChildrenRecursive<T>(subType));
362 }
363
364 return list;
365 }
366
367 template<>
368 Common::Array<Object *> Object::listChildren<Object>(int subType) const;
369
370 template<class T>
findChild(bool mustBeUnique)371 T *Object::findChild(bool mustBeUnique) const {
372 return findChildWithSubtype<T>(-1, mustBeUnique);
373 }
374
375 template <class T>
findChildWithSubtype(int subType,bool mustBeUnique)376 T *Object::findChildWithSubtype(int subType, bool mustBeUnique) const {
377 Common::Array<T *> list = listChildren<T>(subType);
378
379 if (list.empty()) {
380 return nullptr;
381 }
382
383 if (list.size() > 1 && mustBeUnique) {
384 error("Several children resources matching criteria type = %s, subtype = %d", Type(T::TYPE).getName(), subType);
385 }
386
387 return list.front();
388 }
389
390 template <class T>
findChildWithIndex(uint16 index,int subType)391 T *Object::findChildWithIndex(uint16 index, int subType) const {
392 return Object::cast<T>(findChildWithIndex(T::TYPE, index, subType));
393 }
394
395 template <class T>
findChildWithOrder(uint16 order,int subType)396 T *Object::findChildWithOrder(uint16 order, int subType) const {
397 return Object::cast<T>(findChildWithOrder(T::TYPE, order, subType));
398 }
399
400 template<class T>
findChildWithName(const Common::String & name,int subType)401 T *Object::findChildWithName(const Common::String &name, int subType) const {
402 return Object::cast<T>(findChildWithName(T::TYPE, name, subType));
403 }
404
405 } // End of namespace Resources
406 } // End of namespace Stark
407
408 #endif // STARK_RESOURCES_RESOURCE_H
409