RuneHive-Game
Loading...
Searching...
No Matches
RegionDecoder.java
Go to the documentation of this file.
1package com.runehive.fs.cache.decoder;
2
3import com.runehive.fs.cache.Cache;
4import com.runehive.fs.cache.FileSystem;
5import com.runehive.fs.util.ByteBufferUtil;
6import com.runehive.fs.util.CompressionUtil;
7import com.runehive.game.world.World;
8import com.runehive.game.world.object.*;
9import com.runehive.game.world.pathfinding.TraversalMap;
10import com.runehive.game.world.position.Position;
11import com.runehive.game.world.region.Region;
12import com.runehive.game.world.region.RegionDefinition;
13import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
14import it.unimi.dsi.fastutil.ints.IntSet;
15import org.apache.logging.log4j.LogManager;
16import org.apache.logging.log4j.Logger;
17
18import java.nio.ByteBuffer;
19import java.util.Optional;
20import java.util.concurrent.atomic.AtomicInteger;
21
22/**
23 * A class which parses static object definitions, which include tool.mapviewer
24 * tiles and landscapes.
25 *
26 * @author Ryley Kimmel <ryley.kimmel@live.com>
27 * @author Artem Batutin <artembatutin@gmail.com>
28 */
29public final class RegionDecoder implements Runnable {
30
31 private static final Logger LOGGER = LogManager.getLogger(RegionDecoder.class);
32
33 /**
34 * The FileSystem.
35 */
36 private final FileSystem fs;
37
38 /**
39 * Amount of regions correctly decoded.
40 */
41 private final AtomicInteger decoded = new AtomicInteger();
42
43 /**
44 * Amount of regions incorrectly decoded.
45 */
46 private final AtomicInteger errors = new AtomicInteger();
47
48 /**
49 * Creates the {@link ObjectDefinitionDecoder}.
50 *
51 * @param fs The {@link FileSystem}.
52 */
54 this.fs = fs;
55 }
56
57 @Override
58 public void run() {
59 LOGGER.info("Loading regional map data.");
60 final Cache mapIndex = fs.getCache(FileSystem.MAP_INDEX);
62 .values()
63 .forEach(def -> load(mapIndex, def));
64 LOGGER.info("Loaded " + decoded + " regions, skipped " + errors + " maps.");
65 }
66
67 public void load(final Cache mapIndex, final RegionDefinition def) {
68 final int hash = def.getHash();
69 final int x = (hash >> 8 & 0xFF) << 6;
70 final int y = (hash & 0xFF) << 6;
71 try {
72 final Region region = World.getRegions().getRegion(x, y);
73
74 ByteBuffer terrainData = mapIndex.get(def.getTerrainFile());
75 if (terrainData == null) {
76 errors.getAndIncrement();
77 return;
78 }
79 ByteBuffer terrainBuffer = ByteBuffer.wrap(CompressionUtil.gunzip(terrainData.array()));
80
81 final IntSet downHeights = new IntOpenHashSet();
82
83 parseTerrain(region, terrainBuffer, downHeights);
84
85 ByteBuffer gameObjectData = mapIndex.get(def.getObjectFile());
86 if (gameObjectData == null) {
87 errors.getAndIncrement();
88 return;
89 }
90 ByteBuffer gameObjectBuffer = ByteBuffer.wrap(CompressionUtil.gunzip(gameObjectData.array()));
91 parseGameObject(region, gameObjectBuffer, x, y, downHeights);
92
93 decoded.getAndIncrement();
94 } catch (Exception e) {
95 e.printStackTrace();
96 errors.getAndIncrement();
97 }
98 }
99
100 /**
101 * Parses a {@link GameObject} on the specified coordinates.
102 *
103 * @param buf The uncompressed game object data buffer.
104 * @param x The x coordinate this object is on.
105 * @param y The y coordinate this object is on.
106 */
107 private void parseGameObject(Region region, ByteBuffer buf, int x, int y, IntSet downHeights) {
108 int objId = -1;
109 while (true) {
110 int objIdOffset = ByteBufferUtil.getSmart(buf);
111 if (objIdOffset == 0) break;
112
113 objId += objIdOffset;
114 int objPosInfo = 0;
115
116 while (true) {
117 int objPosInfoOffset = ByteBufferUtil.getSmart(buf);
118 if (objPosInfoOffset == 0) break;
119 objPosInfo += objPosInfoOffset - 1;
120
121 int objOtherInfo = buf.get() & 0xFF;
122 int localY = objPosInfo & 0x3f;
123 int localX = objPosInfo >> 6 & 0x3f;
124 int height = objPosInfo >> 12 & 0x3;
125
126 Optional<ObjectType> type = ObjectType.valueOf(objOtherInfo >> 2);
127 Optional<ObjectDirection> face = ObjectDirection.valueOf(objOtherInfo & 0x3);
128
129 if (downHeights.contains(Position.hash(localX, localY, 1))) {
130 if (--height < 0) continue;
131 } else if (downHeights.contains(Position.hash(localX, localY, height))) {
132 height--;
133 }
134
135 if (!type.isPresent() || !face.isPresent()) {
136 continue;
137 }
138
139 Position pos = new Position(localX + x, localY + y, height);
141
142 if (def == null)
143 continue;
144
145 StaticGameObject staticObject = new StaticGameObject(def, pos, type.get(), face.get());
146
147 if (Region.SKIPPED_OBJECTS.contains(pos)) {
148 region.skip(staticObject);
149 } else {
150 TraversalMap.markObject(region, staticObject, true, true);
151 }
152 }
153 }
154 }
155
156 /**
157 * Loads all of the tool.mapviewer indexes entries and decodes each.
158 *
159 * @param mapBuffer The uncompressed tool.mapviewer entry data buffer.
160 */
161 private void parseTerrain(Region region, ByteBuffer mapBuffer, IntSet downHeights) {
162 int[][][] attributes = new int[4][64][64];
163
164 for (int height = 0; height < 4; height++) {
165 for (int localX = 0; localX < 64; localX++) {
166 for (int localY = 0; localY < 64; localY++) {
167 while (true) {
168 int attributeId = mapBuffer.getShort() & 0xFFFF;
169 if (attributeId == 0) {
170 break;
171 }
172 if (attributeId == 1) {
173 int tileHeight = mapBuffer.get() & 0xFF;
174 break;
175 }
176 if (attributeId <= 49) {
177 int overlayId = mapBuffer.getShort() & 0xFFFF;
178 } else if (attributeId <= 81) {
179 attributes[height][localX][localY] = attributeId - 49;
180 }
181 }
182 }
183 }
184 }
185
186 for (int height = 0; height < 4; height++) {
187 for (int localX = 0; localX < 64; localX++) {
188 for (int localY = 0; localY < 64; localY++) {
189
190 if ((attributes[height][localX][localY] & 2) == 2) {
191 downHeights.add(Position.hash(localX, localY, height));
192 }
193
194 if ((attributes[height][localX][localY] & 1) == 1) {
195 int plane = height;
196
197 if ((attributes[1][localX][localY] & 2) == 2) {
198 downHeights.add(Position.hash(localX, localY, 1));
199 plane--;
200 }
201
202 if (plane >= 0) {
203 TraversalMap.block(region, plane, localX, localY);
204 }
205 }
206 }
207 }
208 }
209 }
210
211}
Represents a Sector and Index cache.
Definition Cache.java:14
ByteBuffer get(final int indexId)
Gets a ByteBuffer of data within this cache for the specified index id.
Definition Cache.java:81
Represents a file system of Caches and Archives.
static final int MAP_INDEX
Represents the id of the tool.mapviewer and landscape cache.
final FileSystem fs
The FileSystem.
RegionDecoder(FileSystem fs)
Creates the ObjectDefinitionDecoder.
void load(final Cache mapIndex, final RegionDefinition def)
final AtomicInteger errors
Amount of regions incorrectly decoded.
void parseTerrain(Region region, ByteBuffer mapBuffer, IntSet downHeights)
Loads all of the tool.mapviewer indexes entries and decodes each.
void parseGameObject(Region region, ByteBuffer buf, int x, int y, IntSet downHeights)
Parses a GameObject on the specified coordinates.
final AtomicInteger decoded
Amount of regions correctly decoded.
A static-utility class containing extension or helper methods for ByteBuffers.
static int getSmart(final ByteBuffer buffer)
Reads a 'smart' (either a byte or short depending on the value) from the specified buffer.
A static-utility class containing containing extension or helper methods for compressor-deccompressor...
static byte[] gunzip(byte[] data)
Uncompresses a byte array of g-zipped data.
Represents the game world.
Definition World.java:46
static RegionManager getRegions()
Definition World.java:552
static GameObjectDefinition forId(int id)
Gets an object definition by its id.
Represents a static game object loaded from the map fs.
Contains traversal data for a set of regions.
static void block(Region region, int height, int localX, int localY)
Marks the specified set of coordinates blocked, unable to be passed through.
static void markObject(Region region, GameObject object, boolean add, boolean list)
Marks a GameObject with the specified attributes on the specified Position to the TraversalMap.
Represents a single tile on the game world.
Definition Position.java:14
static int hash(int x, int y, int z)
Represents a single region definition.
static Int2ObjectMap< RegionDefinition > getDefinitions()
Gets the regional definitions.
Represents a single region.
Definition Region.java:21
static final Set< Position > SKIPPED_OBJECTS
Definition Region.java:26
Region getRegion(Position position)
Gets a region by position.
The enumerated type whose elements represent the directions for objects.
static Optional< ObjectDirection > valueOf(final int id)
Returns a ObjectDirection wrapped in an Optional for the specified id.
The enumerated type whose elements represent all of the object types.
static Optional< ObjectType > valueOf(final int id)
Returns a ObjectType wrapped in an Optional for the specified id.