1
-----------------------------
2
THE MANA WORLD PACKAGE SYSTEM
3
-----------------------------
4
5
1. INTRODUCTION
6
2. LOCATION OF DATA
7
3. CONTENTS OF DATA PACKAGE
8
4. TYPES OF DATA
9
5. INITIALIZING PACKAGE MANAGEMENT
10
6. LOADING A REQUESTED RESOURCE
11
7. RESOURCE MANAGEMENT DETAILS
12
13
14
1. INTRODUCTION
15
16
The Mana World is expected to grow continuously with updates to the game world
17
occurring relatively frequently. More often so than for example new releases
18
of the game client. To make sure players don't have to update their data
19
manually all the time, by for example downloading the latest from the website,
20
the TMW client should be able to automatically obtain new data packages from
21
the server.
22
23
 Note: To reduce the load on the server (which isn't expected to have huge
24
 free uploading resources), the idea is that the server will only send a
25
 torrent file to the client and that the file is subsequently downloaded from
26
 several locations that have volunteered to spread TMW data files. Ultimately
27
 a simple option on the client will even allow players to contribute their
28
 excess bandwidth to help other players get the updates faster.
29
30
31
2. LOCATION OF DATA
32
33
There are two locations where TMW can look for game data. The install data
34
directory and the data directory in the user's home directory. The latter one
35
doesn't have to be used for Windows users, but is required for dynamic updates
36
for UNIX users, who generally won't have write permissions to the install
37
data directory. So for UNIX the two locations are:
38
39
 /usr/local/share/manaworld/data/*
40
41
 ~/.manaworld/data/*
42
43
While for Windows all the data will be located at:
44
45
 C:\Program Files\The Mana World\data\*
46
47
In the UNIX case it doesn't matter in which order the data directories are
48
examined.
49
50
51
3. CONTENTS OF DATA PACKAGE
52
53
The contents of the data packages are strictly categorized and all packages
54
share a single root, similar to the paths on a UNIX system. The name of the
55
package is irrelevant. An example of the contents is given by:
56
57
 /graphics/sprites/forest/pinetree.png
58
 /graphics/sprites/furniture/bed.png
59
 /graphics/tiles/dark_forest.png
60
 /graphics/tiles/city.png
61
 /music/eagles_are_watching.xm
62
 /music/silent_rose.xm
63
 /sound/battle/sword1.ogg
64
 /sound/battle/sword2.ogg
65
 /maps/deep_desert.tmx
66
 /maps/desert_town.tmx
67
 /tilesets/dark_forest.tsx
68
 /tilesets/city.tsx
69
 /scripts/Portal.rb
70
 /scripts/PawnShop.rb
71
 /scripts/Fountain.rb
72
73
74
4. TYPES OF DATA
75
76
 png - The preferred format for images
77
 xm  - The preferred format for music (or other kinds of module formats)
78
 ogg - The preferred format for sound effects
79
 tmx - The map format (to be implemented)
80
 tsx - The tile set format (to be implemented)
81
 rb  - A Ruby script file (application to be discussed)
82
83
84
5. INITIALIZING PACKAGE MANAGEMENT
85
86
When TMW starts it will scan its data directories for both packages (archives)
87
and directories. When a directory is found with the same name as a package, the
88
directory is the preferred location to load data from as it is assumed to be
89
more up to date.
90
91
Each package will have an ID and a file listing associated with it. Having made
92
a list of all packages they are processed in the order of their IDs. A mapping
93
is made from file to package, as follows:
94
95
 /music/eagles_are_watching.xm  -> /usr/local/share/manaworld/data/musicpack
96
 /music/silent_rose.xm          -> /usr/local/share/manaworld/data/musicpack
97
 /sound/battle/sword1.ogg       -> ~/.manaworld/data/patch1
98
 /sound/battle/sword2.ogg       -> ~/.manaworld/data/patch1
99
 ...
100
101
Because the packages are loaded in the order of their IDs, it is made sure that
102
each file will always point to the package in which is was last updated. The
103
package IDs make sure that there is an absolute ordering of the packages.
104
105
To allow the client to get rid of old packages, a package can declare an
106
arbitrary amount of packages with a lower ID than itself as obsolete. These
107
packages will then be ignored by the client, and optionally they can be
108
automatically deleted.
109
110
111
6. LOADING A REQUESTED RESOURCE
112
113
When the game starts and during the game, resources will continuously be asked
114
for. A resource manager will take care that each resource is only loaded once.
115
It also makes sure that the resources are loaded from the right package using
116
the constructed mapping.
117
118
As noted above, the resource manager makes sure directories are preferred
119
to package files when resources are loaded. The presence of directories is
120
only expected in the case of developers that will relatively frequently update
121
the data while working on the next package to be released.
122
123
124
7. RESOURCE MANAGEMENT DETAILS
125
126
The resource management technique is critical to the overall success of the
127
package management system as a whole.  Resources are loaded at runtime as they
128
are needed, and unloaded as they become unused.  In order to ensure the
129
autonomous functioning of this process reference counting is the agreed upon
130
technique for managing loaded resources in TMW.
131
132
For those unfamiliar with the practice of reference counting, it involves
133
every resource object having a variable containing the number of references to
134
the object. When a reference is added the function addRef() is called and when
135
it is removed the function release() is called. When the reference count
136
reaches zero the object will automatically delete itself, thus handling the
137
cleanup of resources.
138
139
Reference counting will form the core of the resource management system.  Each
140
resource object will have the functionality of a reference counted object. The
141
resource manager will hold ResourceEntry objects.  The resource entry object
142
contains a pointer to the resource as well as the location of the path of the
143
file the resource was loaded from.  This would look something like:
144
145
  /**
146
   * A generic reference counted resource object.
147
   */
148
  class Resource {
149
      public:
150
          /**
151
           * Loads the resource from the specified path.
152
           * @param filePath The path to the file to be loaded.
153
           * @return <code>true</code> if loaded <code>false</code> otherwise.
154
           */
155
          virtual bool Load(std::string filePath) = 0;
156
          ...
157
          /**
158
           * Increments the reference counted of this object.
159
           */
160
          void addRef() { ++referenceCount; }
161
162
          /**
163
           * Decrements the reference count and deletes the object
164
           * if no references are left.
165
           * @return <code>true</code> if the object was deleted
166
           * <code>false</code> otherwise.
167
           */
168
          void release() {
169
              --referenceCount;
170
171
              if (!referenceCount)
172
              {
173
                  delete this;
174
                  return true;
175
              }
176
177
              return false;
178
          }
179
      private:
180
          unsigned int referenceCount;
181
  };
182
  ...
183
  /**
184
   * A resource entry descriptor.
185
   */
186
  struct ResourceEntry {
187
      Resource*   resource;
188
      std::string filePath;
189
  };
190
  ...
191
192
The resource manager would then hold a mapping containing the resource entry as
193
well as the string defining its resource identification path. The resource
194
manager would thus look something like this:
195
196
  /**
197
   * A class for loading and managing resources.
198
   */
199
  class ResourceManager {
200
      public:
201
          ...
202
      private:
203
          std::map<std::string, ResourceEntry> resources;
204
  };
205
  ...
206
207
This will allow the game to load resources with little awareness of the actual
208
path from which they were loaded.  The resource manager will also act as a
209
resource object factory.  A factory object is an object that creates an
210
instance of an object derived from a common base class.  In this case it will
211
create Resource objects. This would make the ResourceManager object look like
212
this:
213
214
  /**
215
   * A class for loading and managing resources.
216
   */
217
  class ResourceManager {
218
      public:
219
          enum E_RESOURCE_TYPE
220
          {
221
             MAP,
222
             MUSIC,
223
             IMAGE,
224
             SCRIPT,
225
             TILESET,
226
             SOUND_EFFECT
227
          };
228
229
          /**
230
           * Creates a resource and adds it to the resource map.
231
           * The idPath is converted into the appropriate path
232
           * for the current operating system and the resource
233
           * is loaded.
234
           * @param type The type of resource to load.
235
           * @param idPath The resource identifier path.
236
           * @return A valid resource or <code>NULL</code> if
237
           * the resource could not be loaded.
238
           */
239
          Resource* Create(const E_RESOURCE_TYPE& type,
240
                                            std::string idPath);
241
          ...
242
      private:
243
          std::map<std::string, ResourceEntry> resources;
244
  };
245
  ...
246
247
Loading a resource would then look something like:
248
249
  Image* img = (Image*) ResourceManager.Create(ResourceManager::IMAGE,
250
                                         "/graphics/tiles/dark_forest.png");