From 6085111d7cdd20264c32c9622ac7859db252f036 Mon Sep 17 00:00:00 2001 From: Damion Date: Wed, 17 Jun 2020 11:43:41 +1000 Subject: [PATCH] Region factory (#404) * Split region loading and object population to factory class * Implement changes, disable CommandConsole * You guys don't omit /build/ --- .../main/java/com/rebotted/GameEngine.java | 11 +- .../java/com/rebotted/world/clip/Region.java | 325 ++++++------------ .../rebotted/world/clip/RegionFactory.java | 196 +++++++++++ 3 files changed, 303 insertions(+), 229 deletions(-) create mode 100644 2006Redone Server/src/main/java/com/rebotted/world/clip/RegionFactory.java diff --git a/2006Redone Server/src/main/java/com/rebotted/GameEngine.java b/2006Redone Server/src/main/java/com/rebotted/GameEngine.java index e421e63f..3ee69e09 100644 --- a/2006Redone Server/src/main/java/com/rebotted/GameEngine.java +++ b/2006Redone Server/src/main/java/com/rebotted/GameEngine.java @@ -16,7 +16,6 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.mina.common.IoAcceptor; import org.apache.mina.transport.socket.nio.SocketAcceptor; import org.apache.mina.transport.socket.nio.SocketAcceptorConfig; -import com.rebotted.console.CommandConsole; import com.rebotted.event.CycleEventHandler; import com.rebotted.game.content.minigames.FightCaves; import com.rebotted.game.content.minigames.FightPits; @@ -47,7 +46,7 @@ import com.rebotted.world.ItemHandler; import com.rebotted.world.ObjectHandler; import com.rebotted.world.ObjectManager; import com.rebotted.world.clip.ObjectDefinition; -import com.rebotted.world.clip.Region; +import com.rebotted.world.clip.RegionFactory; /** * Server.java @@ -189,7 +188,7 @@ public class GameEngine { * Initialise Handlers */ ObjectDefinition.loadConfig(); - Region.load(); + RegionFactory.load(); Doors.getSingleton().load(); DoubleDoors.getSingleton().load(); ItemDefinition.read(); @@ -265,7 +264,11 @@ public class GameEngine { } }, 0, GameConstants.CYCLE_TIME, TimeUnit.MILLISECONDS); - CommandConsole.getInstance(); + /* + * I'd recommend disabling this until I can be bothered to implement it + * properly. + */ + // CommandConsole.getInstance(); try { while (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) { diff --git a/2006Redone Server/src/main/java/com/rebotted/world/clip/Region.java b/2006Redone Server/src/main/java/com/rebotted/world/clip/Region.java index ba8b0a1f..17b042bd 100644 --- a/2006Redone Server/src/main/java/com/rebotted/world/clip/Region.java +++ b/2006Redone Server/src/main/java/com/rebotted/world/clip/Region.java @@ -1,29 +1,70 @@ package com.rebotted.world.clip; -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; import java.util.ArrayList; -import java.util.zip.GZIPInputStream; import com.rebotted.game.objects.Objects; public class Region { private ArrayList realObjects = new ArrayList(); - + private final int id; + private final int[][][] clips = new int[4][][]; + private final int[][][] projectileClips = new int[4][][]; + private boolean members = false; + + public Region(int id, boolean members) { + this.id = id; + this.members = members; + } + + public int id() { + return id; + } + + public boolean members() { + return members; + } + + public static boolean isMembers(int x, int y) { + if (x >= 3272 && x <= 3320 && y >= 2752 && y <= 2809) { + return false; + } + if (x >= 2640 && x <= 2677 && y >= 2638 && y <= 2679) { + return false; + } + return getRegion(x, y).members(); + } + + /** + * Takes X Y coordinates, gives a region object + * + * @param x coordinate X + * @param y coordinate Y + * @return Region object + */ public static Region getRegion(int x, int y) { - int regionX = x >> 3; - int regionY = y >> 3; - int regionId = (regionX / 8 << 8) + regionY / 8; - for (Region region : regions) { + int regionId = getRegionId(x,y); + for (Region region : RegionFactory.getRegions()) { if (region.id() == regionId) { return region; } } return null; } + + /** + * Calculates regionId from X Y coordinates + * + * @param x coordinate X + * @param y coordinate Y + * @return ID of target region + */ + public static int getRegionId(int x, int y) { + int regionX = x >> 3; + int regionY = y >> 3; + int regionId = (regionX / 8 << 8) + regionY / 8; + return regionId; + } public static Objects getObject(int id, int x, int y, int z) { Region r = getRegion(x, y); @@ -71,12 +112,16 @@ public class Region { clips[height][x - regionAbsX][y - regionAbsY] = 0; } - public static void removeClipping(int x, int y, int height) { - final int regionX = x >> 3; - final int regionY = y >> 3; - final int regionId = ((regionX / 8) << 8) + (regionY / 8); - for (Region r : regions) { - if (r.id() == regionId) { + /** + * Nothing calls this... + * + * @param x + * @param y + * @param height + */ + public void removeClipping(int x, int y, int height) { + for (Region r : RegionFactory.getRegions()) { + if (r.id() == getRegionId(x,y)) { r.removeClip(x, y, height); break; } @@ -142,21 +187,25 @@ public class Region { public static boolean canShoot(int x, int y, int z, int direction) { if (direction == 0) { - return !projectileBlockedNorthWest(x, y, z) && !projectileBlockedNorth(x, y, z) && !projectileBlockedWest(x, y, z); + return !projectileBlockedNorthWest(x, y, z) && !projectileBlockedNorth(x, y, z) + && !projectileBlockedWest(x, y, z); } else if (direction == 1) { return !projectileBlockedNorth(x, y, z); } else if (direction == 2) { - return !projectileBlockedNorthEast(x, y, z) && !projectileBlockedNorth(x, y, z) && !projectileBlockedEast(x, y, z); + return !projectileBlockedNorthEast(x, y, z) && !projectileBlockedNorth(x, y, z) + && !projectileBlockedEast(x, y, z); } else if (direction == 3) { return !projectileBlockedWest(x, y, z); } else if (direction == 4) { return !projectileBlockedEast(x, y, z); } else if (direction == 5) { - return !projectileBlockedSouthWest(x, y, z) && !projectileBlockedSouth(x, y, z) && !projectileBlockedWest(x, y, z); + return !projectileBlockedSouthWest(x, y, z) && !projectileBlockedSouth(x, y, z) + && !projectileBlockedWest(x, y, z); } else if (direction == 6) { return !projectileBlockedSouth(x, y, z); } else if (direction == 7) { - return !projectileBlockedSouthEast(x, y, z) && !projectileBlockedSouth(x, y, z) && !projectileBlockedEast(x, y, z); + return !projectileBlockedSouthEast(x, y, z) && !projectileBlockedSouth(x, y, z) + && !projectileBlockedEast(x, y, z); } return false; } @@ -285,12 +334,17 @@ public class Region { return projectileClips[height][x - regionAbsX][y - regionAbsY]; } + /** + * Adds clipping to whichever region matches provided XYZ. + * + * @param x coordinate X + * @param y coordinate Y + * @param height coordinate Z + * @param shift uuuuh shift? + */ public static void addClipping(int x, int y, int height, int shift) { - int regionX = x >> 3; - int regionY = y >> 3; - int regionId = (regionX / 8 << 8) + regionY / 8; - for (Region r : regions) { - if (r.id() == regionId) { + for (Region r : RegionFactory.getRegions()) { + if (r.id() == getRegionId(x, y)) { r.addClip(x, y, height, shift); break; } @@ -298,55 +352,14 @@ public class Region { } private static void addProjectileClipping(int x, int y, int height, int shift) { - int regionX = x >> 3; - int regionY = y >> 3; - int regionId = (regionX / 8 << 8) + regionY / 8; - for (Region r : regions) { - if (r.id() == regionId) { + for (Region r : RegionFactory.getRegions()) { + if (r.id() == getRegionId(x,y)) { r.addProjectileClip(x, y, height, shift); break; } } } - - private static Region[] regions; - private final int id; - private final int[][][] clips = new int[4][][]; - private final int[][][] projectileClips = new int[4][][]; - private boolean members = false; - - public Region(int id, boolean members) { - this.id = id; - this.members = members; - } - - public int id() { - return id; - } - - public boolean members() { - return members; - } - - public static boolean isMembers(int x, int y, int height) { - if (x >= 3272 && x <= 3320 && y >= 2752 && y <= 2809) { - return false; - } - if (x >= 2640 && x <= 2677 && y >= 2638 && y <= 2679) { - return false; - } - int regionX = x >> 3; - int regionY = y >> 3; - int regionId = (regionX / 8 << 8) + regionY / 8; - for (Region r : regions) { - if (r.id() == regionId) { - return r.members(); - } - } - return false; - } - private static void addClippingForVariableObject(int x, int y, int height, int type, int direction, boolean flag) { if (type == 0) { @@ -575,6 +588,18 @@ public class Region { } } + /** + * + * Adds object to region + * + * @param objectId + * @param x + * @param y + * @param height + * @param type + * @param direction + * @param startUp + */ public static void addObject(int objectId, int x, int y, int height, int type, int direction, boolean startUp) { if (ObjectDefinition.getObjectDef(objectId) == null) { } @@ -624,13 +649,10 @@ public class Region { public static int getClipping(int x, int y, int height) { if (height > 3) { - height = 0; + height = 0; //this doesn't seem good } - int regionX = x >> 3; - int regionY = y >> 3; - int regionId = (regionX / 8 << 8) + regionY / 8; - for (Region r : regions) { - if (r.id() == regionId) { + for (Region r : RegionFactory.getRegions()) { + if (r.id() == getRegionId(x,y)) { return r.getClip(x, y, height); } } @@ -641,18 +663,16 @@ public class Region { if (height > 3) { height = 0; } - int regionX = x >> 3; - int regionY = y >> 3; - int regionId = (regionX / 8 << 8) + regionY / 8; - for (Region r : regions) { - if (r.id() == regionId) { + for (Region r : RegionFactory.getRegions()) { + if (r.id() == getRegionId(x,y)) { return r.getProjectileClip(x, y, height); } } return 0; } - public static boolean getClipping(int x, int y, int height, int moveTypeX, int moveTypeY) { + public static boolean getClipping(int x, int y, int height, int moveTypeX, + int moveTypeY) { try { if (height > 3) { height = 0; @@ -694,149 +714,4 @@ public class Region { } } - public static void load() { - try { - File f = new File("./data/world/map_index"); - byte[] buffer = new byte[(int) f.length()]; - DataInputStream dis = new DataInputStream(new FileInputStream(f)); - dis.readFully(buffer); - dis.close(); - ByteStream in = new ByteStream(buffer); - int size = in.length() / 7; - regions = new Region[size]; - int[] regionIds = new int[size]; - int[] mapGroundFileIds = new int[size]; - int[] mapObjectsFileIds = new int[size]; - boolean[] isMembers = new boolean[size]; - for (int i = 0; i < size; i++) { - regionIds[i] = in.getUShort(); - mapGroundFileIds[i] = in.getUShort(); - mapObjectsFileIds[i] = in.getUShort(); - isMembers[i] = in.getUByte() == 0; - } - for (int i = 0; i < size; i++) { - regions[i] = new Region(regionIds[i], isMembers[i]); - } - for (int i = 0; i < size; i++) { - byte[] file1 = getBuffer(new File("./data/world/map/" - + mapObjectsFileIds[i] + ".gz")); - byte[] file2 = getBuffer(new File("./data/world/map/" - + mapGroundFileIds[i] + ".gz")); - if (file1 == null || file2 == null) { - continue; - } - try { - loadMaps(regionIds[i], new ByteStream(file1), - new ByteStream(file2)); - } catch (Exception e) { - System.out.println("Error loading map region: " - + regionIds[i]); - } - } - System.out.println("[Region] DONE LOADING REGION CONFIGURATIONS"); - } catch (Exception e) { - e.printStackTrace(); - } - } - - private static void loadMaps(int regionId, ByteStream str1, ByteStream str2) { - int absX = (regionId >> 8) * 64; - int absY = (regionId & 0xff) * 64; - int[][][] someArray = new int[4][64][64]; - for (int i = 0; i < 4; i++) { - for (int i2 = 0; i2 < 64; i2++) { - for (int i3 = 0; i3 < 64; i3++) { - while (true) { - int v = str2.getUByte(); - if (v == 0) { - break; - } else if (v == 1) { - str2.skip(1); - break; - } else if (v <= 49) { - str2.skip(1); - } else if (v <= 81) { - someArray[i][i2][i3] = v - 49; - } - } - } - } - } - for (int i = 0; i < 4; i++) { - for (int i2 = 0; i2 < 64; i2++) { - for (int i3 = 0; i3 < 64; i3++) { - if ((someArray[i][i2][i3] & 1) == 1) { - int height = i; - if ((someArray[1][i2][i3] & 2) == 2) { - height--; - } - if (height >= 0 && height <= 3) { - addClipping(absX + i2, absY + i3, height, 0x200000); - } - } - } - } - } - int objectId = -1; - int incr; - while ((incr = str1.getUSmart()) != 0) { - objectId += incr; - int location = 0; - int incr2; - while ((incr2 = str1.getUSmart()) != 0) { - location += incr2 - 1; - int localX = location >> 6 & 0x3f; - int localY = location & 0x3f; - int height = location >> 12; - int objectData = str1.getUByte(); - int type = objectData >> 2; - int direction = objectData & 0x3; - if (localX < 0 || localX >= 64 || localY < 0 || localY >= 64) { - continue; - } - if ((someArray[1][localX][localY] & 2) == 2) { - height--; - } - if (height >= 0 && height <= 3) { - addObject(objectId, absX + localX, absY + localY, height, - type, direction, false); - } - } - } - } - - public static byte[] getBuffer(File f) throws Exception { - if (!f.exists()) { - return null; - } - byte[] buffer = new byte[(int) f.length()]; - DataInputStream dis = new DataInputStream(new FileInputStream(f)); - dis.readFully(buffer); - dis.close(); - byte[] gzipInputBuffer = new byte[999999]; - int bufferlength = 0; - GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream( - buffer)); - do { - if (bufferlength == gzipInputBuffer.length) { - System.out - .println("Error inflating data.\nGZIP buffer overflow."); - break; - } - int readByte = gzip.read(gzipInputBuffer, bufferlength, - gzipInputBuffer.length - bufferlength); - if (readByte == -1) { - break; - } - bufferlength += readByte; - } while (true); - byte[] inflated = new byte[bufferlength]; - System.arraycopy(gzipInputBuffer, 0, inflated, 0, bufferlength); - buffer = inflated; - if (buffer.length < 10) { - return null; - } - return buffer; - } - } diff --git a/2006Redone Server/src/main/java/com/rebotted/world/clip/RegionFactory.java b/2006Redone Server/src/main/java/com/rebotted/world/clip/RegionFactory.java new file mode 100644 index 00000000..9caf7392 --- /dev/null +++ b/2006Redone Server/src/main/java/com/rebotted/world/clip/RegionFactory.java @@ -0,0 +1,196 @@ +package com.rebotted.world.clip; + +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.util.zip.GZIPInputStream; + +public class RegionFactory { + + private static Region[] regions; + + public static Region[] getRegions() { + return regions; + } + + public static void load() { + //GameEngine.getLogger(Region.class).info("Loading region configurations..."); + try { + File f = new File("./data/world/map_index"); + byte[] buffer = new byte[(int) f.length()]; + DataInputStream dis = new DataInputStream(new FileInputStream(f)); + dis.readFully(buffer); + dis.close(); + ByteStream in = new ByteStream(buffer); + int size = in.length() / 7; + regions = new Region[size]; + int[] regionIds = new int[size]; + int[] mapGroundFileIds = new int[size]; + int[] mapObjectsFileIds = new int[size]; + boolean[] isMembers = new boolean[size]; + /** + * Seems to be that regions consist of + * regionIds (16 bits) + * groundFileIds (16 bits) + * objectsFileIds (16 bits) + * isMembers (8 bits) + */ + for (int i = 0; i < size; i++) { + regionIds[i] = in.getUShort(); + mapGroundFileIds[i] = in.getUShort(); + mapObjectsFileIds[i] = in.getUShort(); + isMembers[i] = in.getUByte() == 0; + } + for (int i = 0; i < size; i++) { + regions[i] = new Region(regionIds[i], isMembers[i]); + } + //GameEngine.getLogger(Region.class).info(size + " Regions created."); + //GameEngine.getLogger(Region.class).info("Populating regions..."); + for (int i = 0; i < size; i++) { + //GameEngine.getLogger(Region.class).info("Region: " + i + " RegionId: " + regionIds[i] + " ObjectsId: " + mapObjectsFileIds[i] + // + " ClippingsId: " + mapGroundFileIds[i]); + byte[] file1 = getBuffer(new File("./data/world/map/" + + mapObjectsFileIds[i] + ".gz")); + byte[] file2 = getBuffer(new File("./data/world/map/" + + mapGroundFileIds[i] + ".gz")); + if (file1 == null || file2 == null) { + continue; + } + try { + loadMaps(regionIds[i], new ByteStream(file1), + new ByteStream(file2)); + } catch (Exception e) { + System.out.println("Error loading map region: " + + regionIds[i]); + } + } + //GameEngine.getLogger(Region.class).info("Region configuration done."); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Regions in runescape are chunks of the map. + * They are comprised of 64x64 blocks of x,y positions on 4 possibly height levels (z). + * + * This code populates those positions. + * + * @param regionId + * @param str1 + * @param str2 + */ + private static void loadMaps(int regionId, ByteStream str1, ByteStream str2) { + int regionX = (regionId >> 8) * 64; // Region ID is bitshifted to get X position + int regionY = (regionId & 0xff) * 64; // Region ID is bitshifted and AND'd against 0xff to get Y position + int[][][] positionArray = new int[4][64][64]; + /** + * z seems to be the height (map level?) (0 through 3) (I'm told these loop for additional levels) + * x seems to be X position (of 64 possible positions) + * y seems to be Y position (of 64 possible positions) + */ + for (int localz = 0; localz < 4; localz++) { // height (z coord) + for (int localx = 0; localx < 64; localx++) { // x coord + for (int localy = 0; localy < 64; localy++) { // y coord + while (true) { // we loop through each position x,y,z + int v = str2.getUByte(); //Reading the bytestream, I guess the map is read and loaded bottom to top, left to right. + if (v == 0) { + break; + } else if (v == 1) { + str2.skip(1); + break; + } else if (v <= 49) { + str2.skip(1); + } else if (v <= 81) { + positionArray[localz][localx][localy] = v - 49; // Clipping data is gathered. + } + } + } + } + } + /** + * Clipping data is validated and added. + */ + for (int localz = 0; localz < 4; localz++) { + for (int localx = 0; localx < 64; localx++) { + for (int localy = 0; localy < 64; localy++) { + if ((positionArray[localz][localx][localy] & 1) == 1) { + int height = localz; + if ((positionArray[1][localx][localy] & 2) == 2) { + height--; + } + if (height >= 0 && height <= 3) { + //GameEngine.getLogger(Region.class).debug("Adding clipping at x,y " + (regionX + localx) + "," + (regionY + localy) + " at height: " + localz); + Region.addClipping(regionX + localx, regionY + localy, height, 0x200000); + } + } + } + } + } + /** + * Object data. + */ + int objectId = -1; + int incr; + while ((incr = str1.getUSmart()) != 0) { + objectId += incr; + int location = 0; + int incr2; + while ((incr2 = str1.getUSmart()) != 0) { + location += incr2 - 1; + int objectX = location >> 6 & 0x3f; + int objectY = location & 0x3f; + int objectHeight = location >> 12; + int objectData = str1.getUByte(); + int type = objectData >> 2; + int direction = objectData & 0x3; + if (objectX < 0 || objectX >= 64 || objectY < 0 || objectY >= 64) { + continue; //Checks the object position is not outside the bounds of a region (0-64) + } + if ((positionArray[1][objectX][objectY] & 2) == 2) { + objectHeight--; + } + if (objectHeight >= 0 && objectHeight <= 3) { + Region.addObject(objectId, regionX + objectX, regionY + objectY, objectHeight, + type, direction, false); + } + } + } + } + + public static byte[] getBuffer(File f) throws Exception { + if (!f.exists()) { + return null; + } + byte[] buffer = new byte[(int) f.length()]; + DataInputStream dis = new DataInputStream(new FileInputStream(f)); + dis.readFully(buffer); + dis.close(); + byte[] gzipInputBuffer = new byte[999999]; + int bufferlength = 0; + GZIPInputStream gzip = new GZIPInputStream(new ByteArrayInputStream( + buffer)); + do { + if (bufferlength == gzipInputBuffer.length) { + System.out + .println("Error inflating data.\nGZIP buffer overflow."); + break; + } + int readByte = gzip.read(gzipInputBuffer, bufferlength, + gzipInputBuffer.length - bufferlength); + if (readByte == -1) { + break; + } + bufferlength += readByte; + } while (true); + byte[] inflated = new byte[bufferlength]; + System.arraycopy(gzipInputBuffer, 0, inflated, 0, bufferlength); + buffer = inflated; + if (buffer.length < 10) { + return null; + } + return buffer; + } + +}