The purpose on this thread, is to shed light on map regions and some really usefull information that comes with those. Alot of people don't know some things I'm gonna lay out here, and I know that simply because of the fact I have never seen anyone use them. Also this information could be used by people that want to get 570+ login.
If you don't feel like reading this from top to bottom you might as well fuck off now, because I don't like replies like the first two below my post
.
We do have a few variables in our servers, that everyone has, that are related to the location of a player or npc. For example everyone has these in their server:
Code:
private int regionX;
private int regionY;
private int absX;
private int absY;
private int localX;
private int localY;
We are gonna ditch this list and make some new variables named after their real meanings. RegionX and regionY, represent a coordinate for a region you would suppose. In fact they represent coordinates for 8 x 8 pieces of map, and not coordinates for complete regions. Regions are 64 x 64 map pieces. Out of this we can conclude that the name regionX and regionY are inapropriate as a name for the variable that represents 8 x 8 pieces of map. To give an example:
RegionX = 400 and regionY = 400, represent the coords for a piece of map from 8 x 8, with its absolute base coordinates being (3200, 3200). The coordinates for the regions where this 8 x 8 piece of map is found are (50, 50).
If a region exists out of 64 x 64 tiles, then there are 64 map pieces with the size of 8 x 8 tiles in one region. Conclusion: the variables called regionX and regionY should have another name as they do not represent region coordinates but 8 x 8 pieces of map. We will call these variables region sections. Those region sections can be of great use, but that will come later. First we will gather our other variables with their correct names.
So we have:
Code:
private int regionSectionX = getAbsX >> 3; // Represents an x coordinate for 8 x 8 tiles map pieces
private int regionSectionY = getAbsX >> 3; // Represents an y coordinate for 8 x 8 tiles map pieces
We got rid of the names regionX and regionY, but of course we have coordinates for our regions. Those coordinates are not used in any server yet, so let's get an idea of how to retrieve them:
Code:
private int regionX = getRegionSectionX() / 8; // Represents an x coordinate for a region, bare in mind those are not absolute coords
private int regionY = getRegionSectionY() / 8; // // Represents an x coordinate for a region, bare in mind those are not absolute coords
So right now we have coordinates for our regions, being blocks of 64 x 64 tiles, and coordinates for the sections within the regions, being blocks of 8 x 8 tiles. It could be usefull to know how to calculate the relative positions within these blocks, and for that we need to be able to calculate the absolute coordinates of the bases of those blocks.
Code:
private int absX; // Represents an x coordinate for the absolute position
private int absY; // Represents an y coordinate for the absolute position
private int regionSectionX = getRegionSectionX() << 3; // Represents an absolute x coordinate for the position of the region section block
private int regionSectionY = getRegionSectionY() << 3; // Represents an absolute y coordinate for the position of the region section block
private int regionSectionLocalX = getAbsX() - getRegionSectionsBaseX(); // Represents the relative position within the particle
private int regionSectionLocalY = getAbsY() - getRegionSectionsBaseY(); // Represents the relative position within the particle
private int regionBaseX = (getRegionX() << 3) * 8; // Represents the absolute position of the base of the region
private int regionBaseY = (getRegionY() << 3) * 8; // Represents the absolute position of the base of the region
private int regionLocalX = getAbsX() - 8 * (getRegionX() - 6); // Represents the relative position within the region
private int regionLocalY = getAbsY() - 8 * (getRegionY() - 6); // Represents the relative position within the region
Now we have all those new and renamed variables, we might as well put them to use in our servers. Let's put down my Location class:
Code:
package net.maximemeire.rs2pro.world.entities;
/**
* Represent a location in the world.
*
* @author Maxime Meire
*
*/
public class Location implements Cloneable {
private int absX;
private int absY;
private int z;
private boolean isNewInRegion = true;
public Location(int x, int y, int z) {
setAbsX(x);
setAbsY(y);
setZ(z);
}
public void setAbsX(int absX) {
this.absX = absX;
}
public int getAbsX() {
return absX;
}
public void setAbsY(int absY) {
this.absY = absY;
}
public int getAbsY() {
return absY;
}
public void setZ(int z) {
this.z = z;
}
public int getZ() {
return z;
}
public int getRegionLocalX() {
return getAbsX() - 8 * (getPaletteX() - 6);
}
public int getRegionLocalY() {
return getAbsY() - 8 * (getPaletteY() - 6);
}
public int getPaletteX() {
return getAbsX() >> 3;
}
public int getPaletteY() {
return getAbsY() >> 3;
}
public int getPaletteBaseX() {
return getPaletteX() << 3;
}
public int getPaletteBaseY() {
return getPaletteY() << 3;
}
public int getPaletteLocalX() {
return getAbsX() - getPaletteBaseX();
}
public int getPaletteLocalY() {
return getAbsY() - getPaletteBaseY();
}
public int getRegionX() {
return getPaletteX() / 8;
}
public int getRegionY() {
return getPaletteY() / 8;
}
public int getRegionBaseX() {
return (getRegionX() << 3) * 8;
}
public int getRegionBaseY() {
return (getRegionY() << 3) * 8;
}
public int getPaletteId(int x, int y) {
return ((((getRegionY() + y) * 8) - 6) / 8)
+ ((((getRegionX() + x) - 6) / 8) << 8);
}
public void setNewInRegion(boolean isNewInRegion) {
this.isNewInRegion = isNewInRegion;
}
public boolean isNewInRegion() {
return isNewInRegion;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Location))
return false;
Location loc = (Location) other;
return loc.absX == absX && loc.absY == absY && loc.z == z;
}
@Override
public String toString() {
return "[" + absX + "," + absY + "," + z + "]";
}
}
The reason why I renamed the previously called variable regionX and regionY, is because I wanted to have the real regionX and regionY. Why? Because this gives me the oppertunity to select the regions I want to select. You see that method getRegionId(int x, int y);? That method allows me to grab the id of a region that is x regions west or east and y regions north or south away from the current region. This allows you to select 4 regions, that might contain data you need to load for player updating, but only those 4 that you really need. Example:
Code:
private static Region[] getRegionsToLoad(Player p, Region r) {
Region[] regions = new Region[4];
regions[0] = r;
if (p.getLocation().getAbsX() < 32) {
regions[1] = getRegion(p.getLocation().getRegionId(-1, 0)); // Region to the west from current region
if (p.getLocation().getAbsY() < 32) {
regions[2] = getRegion(p.getLocation().getRegionId(0, -1)); // Region to the south from current region
regions[3] = getRegion(p.getLocation().getRegionId(-1, -1)); // Region to the south west from current region
} else {
regions[2] = getRegion(p.getLocation().getRegionId(0, 1)); // Region to the north from current region
regions[3] = getRegion(p.getLocation().getRegionId(-1, 1)); // Region to the north west from current region
}
} else {
regions[1] = getRegion(p.getLocation().getRegionId(1, 0)); // Region to the east from the current region
if (p.getLocation().getAbsY() < 32) {
regions[2] = getRegion(p.getLocation().getRegionId(0, -1)); // Region to the south from current region
regions[3] = getRegion(p.getLocation().getRegionId(1, -1)); // Region to the south east from current region
} else {
regions[2] = getRegion(p.getLocation().getRegionId(0, 1)); // Region to the north from current region
regions[3] = getRegion(p.getLocation().getRegionId(1, 1)); // Region to the north east from current region
}
}
return regions;
}
We also had our region section blocks. Those variables would gives us the oppertunity to select 64 of those block to form a block the size of one region. If a player is in the middle of that, it is more than big enough to load every region property (players, npc's, ground items and objects) that would be within sight on the client, but reduces loading data size by aproxemately 75%.
Example:
Code:
# PART OF METHOD #
Queue<Player> players = new LinkedList<Player>();
int startX = getStartingX(p);
int startY = getStartingY(p);
for (Region r : regionsToLoad) {
for (Player pl : r.getPlayers()) {
if ((p.getLocation().getAbsX() >= startX || (startX + 64) >= p.getLocation().getAbsX())
&& (p.getLocation().getAbsY() >= startY || (startY + 64) >= p.getLocation().getAbsY())) {
players.add(pl);
}
}
}
# PART OF METHOD #
private static int getStartingX(Player p) {
int regionSectionX = p.getLocation().getRegionSectionX();
int nRegionsBack = p.getLocation().getRegionSectionsLocalX() < 4) ? 4 : 3;
return p.getLocation().getRegionSectionsBaseX(regionSectionX - nRegionsBack);
}
private static int getStartingY(Player p) {
int regionSectionY = p.getLocation().getRegionSectionY();
int nRegionsBack = p.getLocation().getRegionSectionsLocalY() < 4) ? 4 : 3;
return p.getLocation().getRegionSectionsBaseY(regionSectionY - nRegionsBack);
}
That would load 64 particles of players, npcs and whatever you include in your regions, the size of one ordinary region.
I want to conclude this thread with saying that the example code I used is based on two maps, one with active and one with idle region objects. Every region object holds tea data for the region, id for the region, players, npcs, grounditems and objects information.
I hope I wrote it down fairly understandable, any questions and I'll answer them.