RuneHive-Game
Loading...
Searching...
No Matches
ObjectDefinitionDecoder.java
Go to the documentation of this file.
1package com.runehive.fs.cache.decoder;
2
3import com.runehive.fs.cache.FileSystem;
4import com.runehive.fs.cache.archive.Archive;
5import com.runehive.fs.util.ByteBufferUtil;
6import com.runehive.game.world.object.GameObjectDefinition;
7import org.apache.logging.log4j.LogManager;
8import org.apache.logging.log4j.Logger;
9
10import java.nio.ByteBuffer;
11
12/**
13 * A class which parses object definitions.
14 *
15 * @author Ryley Kimmel <ryley.kimmel@live.com>
16 * @author Artem Batutin <artembatutin@gmail.com>
17 */
18public final class ObjectDefinitionDecoder implements Runnable {
19
20 /** The logger to log process output. */
21 private final static Logger LOGGER = LogManager.getLogger(ObjectDefinitionDecoder.class);
22
23 /** The IndexedFileSystem. */
24 private final FileSystem fs;
25
26 /**
27 * Creates the {@link ObjectDefinitionDecoder}.
28 *
29 * @param fs The {@link FileSystem}.
30 */
32 this.fs = fs;
33 }
34
35 @Override
36 public void run() {
37 LOGGER.info("Loading object definitions.");
39 ByteBuffer dat = archive.getData("loc.dat");
40 ByteBuffer idx = archive.getData("loc.idx");
41
42 int count = idx.getShort() & 0xFFFF;
43
44 // Allow dynamic object count to support different cache versions (Elvarg: 44934, osroyale: 47501)
46 LOGGER.warn("GameObjectDefinition count mismatch: cache has " + count + ", expected " +
47 GameObjectDefinition.MAX_DEFINITIONS + ". Using cache count.");
48 }
49
50 int pos = 0;
51 int loaded = 0;
52 for (int index = 0; index < count; index++) {
53 dat.position(pos);
54 decode(index, dat);
55 pos += idx.getShort() & 0xFFFF;
56 loaded++;
57 }
58 LOGGER.info("Loaded " + loaded + " object definitions.");
59 }
60
61 /**
62 * Parses a single game object definition by reading object info from a
63 * buffer.
64 *
65 * @param id The id of the object.
66 * @param buffer The buffer.
67 */
68 private static void decode(int id, ByteBuffer buffer) {
69 String name = "null";
70 String desc = "null";
71 int width = 1;
72 int length = 1;
73 boolean solid = true;
74 boolean impenetrable = true;
75 boolean hasActions = false;
76 boolean interactive = false;
77 boolean wall = false;
78 boolean decoration = false;
79 boolean removeClipping = false;
80 boolean models = false;
81 boolean is10 = true;
82 int walkingFlag = 0;
83
84 int lastOpcode = -1;
85 while (true) {
86 int opcode = buffer.get() & 0xff;
87 if (opcode == 0) {
88 break;
89 }
90
91 if (opcode == 1) {
92 int len = buffer.get();
93 if (len > 0 && !models) {
94 for (int idx = 0; idx < len; idx++) {
95 buffer.position(buffer.position() + Short.BYTES);
96 if (buffer.get() != 10 && idx == 0) {
97 is10 = false;
98 }
99 }
100 } else {
101 buffer.position(buffer.position() + len * (Byte.BYTES + Short.BYTES));
102 }
103 } else if (opcode == 2) {
105 } else if (opcode == 3) {
106
107 } else if (opcode == 5) {
108 int len = buffer.get();
109 if (len > 0) {
110 models = true;
111 buffer.position(buffer.position() + len * Short.BYTES);
112 }
113 } else if (opcode == 14) {
114 width = buffer.get();
115 } else if (opcode == 15) {
116 length = buffer.get();
117 } else if (opcode == 17) {
118 solid = false;
119 impenetrable = false;
120 } else if (opcode == 18) {
121 impenetrable = false;
122 } else if (opcode == 19) {
123 hasActions = (buffer.get() == 1);
124 } else if (opcode == 21) {
125
126 } else if (opcode == 22) {
127
128 } else if (opcode == 23) {
129
130 } else if (opcode == 24) {
131 buffer.getShort();
132 } else if (opcode == 27) {
133 // interact type = 1
134 } else if (opcode == 28) {
135 buffer.get();
136 } else if (opcode == 29) {
137 buffer.get();
138 } else if (opcode == 39) {
139 buffer.get();
140 } else if (opcode >= 30 && opcode < 35) {
142 interactive = true;
143 } else if (opcode == 40) {
144 int len = buffer.get();
145 for (int i = 0; i < len; i++) {
146 buffer.getShort();
147 buffer.getShort();
148 }
149 } else if (opcode == 41) {
150 int len = buffer.get();
151 for (int i = 0; i < len; i++) {
152 buffer.getShort();
153 buffer.getShort();
154 }
155 } else if (opcode == 61) {
156 buffer.getShort();
157 } else if (opcode == 62) {
158 wall = true;
159 } else if (opcode == 64) {
160
161 } else if (opcode == 65) {
162 buffer.getShort();
163 } else if (opcode == 66) {
164 buffer.getShort();
165 } else if (opcode == 67) {
166 buffer.getShort();
167 } else if (opcode == 68) {
168 buffer.getShort();
169 } else if (opcode == 69) {
170 walkingFlag = buffer.get();
171 } else if (opcode == 70) {
172 buffer.getShort();
173 } else if (opcode == 71) {
174 buffer.getShort();
175 } else if (opcode == 72) {
176 buffer.getShort();
177 } else if (opcode == 73) {
178 decoration = true;
179 } else if (opcode == 74) {
180 removeClipping = true;
181 } else if (opcode == 75) {
182 buffer.get();
183 } else if (opcode == 77) {
184 buffer.getShort();
185 buffer.getShort();
186
187 int len = buffer.get() & 0xFF;
188 for (int i = 0; i <= len; ++i) {
189 buffer.getShort();
190 }
191 } else if (opcode == 78) {
192 buffer.getShort();
193 buffer.get();
194 } else if (opcode == 79) {
195 buffer.getShort();
196 buffer.getShort();
197 buffer.get();
198
199 int len = buffer.get() & 0xFF;
200 for (int i = 0; i < len; ++i) {
201 buffer.getShort();
202 }
203 } else if (opcode == 81) {
204 buffer.get();
205 } else if (opcode == 82) {
206 buffer.getShort();
207 } else if (opcode == 89) {
208
209 } else if (opcode == 92) {
210 buffer.getShort();
211 buffer.getShort();
212 buffer.getShort();
213
214 int len = buffer.get() & 0xFF;
215 for (int i = 0; i <= len; ++i) {
216 buffer.getShort();
217 }
218 } else if (opcode == 249) {
219 int len = buffer.get();
220 for (int i = 0; i < len; i++) {
221 boolean isString = buffer.get() == 1;
223 if (isString) {
225 } else {
226 buffer.getInt();
227 }
228 }
229 } else {
230 // Unknown opcode - break to prevent infinite loop (for cache compatibility with different revisions)
231 LOGGER.warn("Unknown object opcode: {} (last: {}) for object id: {}. Skipping remaining opcodes for this object.",
232 opcode, lastOpcode, id);
233 break;
234 }
235 lastOpcode = opcode;
236 }
237
238 if (!name.equals("null")) {
239 hasActions = models && is10;
240 if (interactive) {
241 hasActions = true;
242 }
243 }
244
245 if (removeClipping) {
246 solid = false;
247 impenetrable = false;
248 }
249
250 int distance = 1;
251
252 switch(id) {
253 case 31561:
254 distance = 2;
255 break;
256 case 26254:
257 name = "Donator Box";
258 break;
259 }
260
261 GameObjectDefinition.addDefinition(new GameObjectDefinition(id, name, desc, width, length, distance, solid, impenetrable, hasActions, wall, decoration, walkingFlag));
262 }
263}
Represents a file system of Caches and Archives.
static final int CONFIG_ARCHIVE
Represents the id of the configurations archive.
Represents an archive within the Cache.
Definition Archive.java:25
static void decode(int id, ByteBuffer buffer)
Parses a single game object definition by reading object info from a buffer.
static final Logger LOGGER
The logger to log process output.
ObjectDefinitionDecoder(FileSystem fs)
Creates the ObjectDefinitionDecoder.
A static-utility class containing extension or helper methods for ByteBuffers.
static String readStringCp1252NullTerminated(ByteBuffer buffer)
static int getMedium(ByteBuffer buffer)
Gets a 24-bit medium integer from the specified ByteBuffer, this method does not mark the ByteBuffers...
static final int MAX_DEFINITIONS
The maximum number of object definitions.
static void addDefinition(GameObjectDefinition def)
Adds a definition.