Table of Contents

Intro

Everyone knows that a coordinate system is in place to navigate through the Runescape world. That coordinate system is based off upon three variables, the Absolute X, Y Z coordinates. Before we continue to talk about how these three variables are used in calculations lets set down some vocabulary:

Definitions

Tile

A tile is a representation of an absolute coordinate.

Example: Varrock Coordinates [3211,] represents one tile.

Tile Chunk

A chunk of tiles, 8 x 8 in size. Also known as a region before the scope of a region was understood. The chunk is considered a point so it has X and Y coordinates. There are two forms of a Chunk, formatted and non; a formatted chunks equation is:

 int chunkX = (getAbsoluteX() >> 3) - 6;
 int chunkY = (getAbsoluteY() >> 3) - 6;

This centers the chunk on the map, more on that later.

The normal chunk equation is:

 int chunkX = (getAbsoluteX() >> 3);
 int chunkY = (getAbsoluteY() >> 3);

Example: The Coordinates [3211,] Chunk X (formatted) is 395 and the Chunk Y (un-formatted) is 428.

Region

A region is 64 x 64 in size, or 8 x 8 in chunks. The region is considered a point so it has X and Y coordinates. The equation for finding the region the coordinates is within is:

 int regionx = (getUnformattedRegionX() >> 3); //getUnformatedRegionX()/8;
 int regiony = (getUnformattedRegionY() >> 3); //getUnformatedRegionY()/8;

Example: The Coordinates [3211,] Region X is 50 and the Region Y is 53.

Note: The Region X and Region Y coordinates are traditionally not used in server location calculations; but practical region systems should use this calculation for many purposes.

Map

There is no calculation for a map, and there is no Map X or Map Y. A Map is, however, a 104 x 104 area made up of 13 x 13 chunks. Why is the number not even you may ask? Because it has a center. The [7,] map chunk of the map is the center, and is also the formatted chunk. When a region update is called by the server, a new map is called, but you must understand that the formatted chunk never changes; the tiles in the map, however, are updated and trimmed. When the player moves out of the formatted chunk, the map is re-positioned to make that chunk the center yet again. As I said, a new update is not needed every time the player enters a new region, but when the range of +- 32 from the point in the center of the chunk is reached, an update is required to update the map to the new objects so that the 'black space' or fog is not reached. Confused?

Diagram

External Image

The active chunk is the chunk in which the player resides. The definite rendering chunks are the chunks in which will be rendered on the players screen no matter where they are in the active chunk. The indefinite rendering chunks are the chunks in which depending on where the player is within the active chunk they may be rendered or not. Remember this depends on the +- distance of 32 from the players absolute position. The queue chunks are pre-loaded chunks in which after the active chunk is moved may be disposed of or activated depending upon the direction in which the active chunk changes.

Loading

These were the regions loaded for the coordinates [3183,]:

External Image

If you can imagine a puzzle, a 64 x 64 piece does not fit equally within the 104 x 104 area. So bits of each region are taken that are within the 104 x 104 map area.

The amount of regions that are to be loaded can be calculated this way:

Please note that Region X and Region Y are not formatted.

 int amt = 0;
 for(int i21 = (player.getLocation().getRegionX() - 6) / 8; i21 <= (player.getLocation().getRegionX() + 6) / 8; i21++) {
    for(int k23 = (player.getLocation().getRegionY() - 6) / 8; k23 <= (player.getLocation().getRegionY() + 6) / 8; k23++)
         amt++;
 }

Along with this, the base X and base Y of each of the region can be calculated:

 for(int i21 = (player.getLocation().getRegionX() - 6) / 8; i21 <= (player.getLocation().getRegionX() + 6) / 8; i21++) {
    for(int k23 = (player.getLocation().getRegionY() - 6) / 8; k23 <= (player.getLocation().getRegionY() + 6) / 8; k23++)
         System.out.println(i21+" X "+(i21 << 6)+","+k23+" Y "+(k23 << 6));;;
 }

The 'X' and 'Y' coordinates represents the coordinates of the region as depicted in the diagram. After the regions are loaded they are trimmed to the tiles that are necessary.

Well hope this gave you some idea of how regions are loaded and such, tell me if you need explanation on anything.

Heres an example of a location class that I wrote, sorry for the lack of comments. If you read everything then this should make sense:

    /**
     * The Tile X and Y coordinates.
     */
    private int tilex = 0, 
                tiley = 0;
    
    /**
     * The Height of the location.
     */
    private int height = 0;
    
    /**
     * The asynchronous Chunk X and Y coordinates; used in region updating. 
     */
    private int chunkx = 0,
                chunky = 0;
    
    /**
     * 
     * @param tilex 
     */
    public void setTileX(int tilex) {
        this.tilex = (tilex & 0xFFFF);
    }
    
    /**
     * 
     * @return 
     */
    public int getTileX() {
        return tilex;
    }
    
    /**
     * 
     * @param tilex 
     */
    public void setTileY(int tiley) {
        this.tiley = (tiley & 0xFFFF);
    }
    
    /**
     * 
     * @return 
     */
    public int getTileY() {
        return tiley;
    }
    
    /**
     * 
     * @param formated If the chunk is formatted for map positioning or
     *                 other formatted chunk comparison.    
     * @return 
     */
    public int calculateChunkX(boolean formated) {
        return formated ? (getTileX() >> 3) - 6 : (getTileX() >> 3);
    }
    
    /**
     * 
     * @param formated If the chunk is formatted for map positioning or
     *                 other formatted chunk comparison.                
     * @return 
     */
    public int calculateChunkY(boolean formated) {
        return formated ? (getTileY() >> 3) - 6 : (getTileY() >> 3);
    }
    
    /**
     * 
     */
    public void updateChunkX() {
        this.chunkx = calculateChunkX(true);
    }
    
    /**
     * 
     */
    public void updateChunkY() {
        this.chunkx = calculateChunkY(true);
    }
    
    /**
     * 
     * @return 
     */
    public int getChunkX() {
        return chunkx;
    }
    
    /**
     * 
     * @return 
     */
    public int getMapLocalX() {
        return getTileX() - (getChunkX() << 3);
    }
    
    /**
     * 
     * @return 
     */
    public int getChunkY() {
        return chunky;
    }
    
    /**
     * 
     * @return 
     */
    public int getMapLocalY() {
        return getTileX() - (getChunkY() << 3);
    }
    
    /**
     * 
     * @param height 
     */
    public void setHeight(int height) {
        this.height = (height & 0x3);
    }
    
    /**
     * 
     * @return 
     */
    public int getHeight() {
        return height;
    }
    
    /**
     * 
     * @return 
     */
    public int getRegionX() {
        return calculateChunkX(false) >> 3;
    }
    
    /**
     * 
     * @return 
     */
    public int getRegionLocalX() {
        return getTileX() - (getRegionX() << 6);
    }
    
    /**
     * 
     * @return 
     */
    public int getRegionY() {
        return calculateChunkY(false) >> 3;
    }
    
    /**
     * 
     * @return 
     */
    public int getRegionLocalY() {
        return getTileY() - (getRegionY() << 6);
    }
    
    /**
     * 
     * @param tilex
     * @param tiley
     * @param height 
     */
    public void set(int tilex, int tiley, int height) {
        setTileX(tilex);
        setTileY(tiley);
        setHeight(height);
    }
    
    /**
     * 
     * @param tilex
     * @param tiley
     * @param height 
     */
    public Location(int tilex, int tiley, int height) {
        set(tilex, tiley, height);
        updateChunkX();
        updateChunkY();
    }
 }