RSMap - How I mapped oldschool runescape with leaflet

This one might get abit lengthy, but my goal is to avoid too many ‘cut and paste code snippets’ and just talk more about how this method could be applied in any project. Which should make it adaptable to anyone else’s work and also help show the amount of work that went into the creation of it. So don’t expect any react.js explanations hhere.

What is RSMap

For those not hip enough to be playing a game from 2007, Old School Runescape is a re-relase of the popular MMORPG Runescape as it was in 2007, with constant updates and a growing community, I recommend it to anyone to this day.

RSMap is a website I created: rsmap.uk. With the goal being to make a world map for the web browser that could be just as powerful as the in game one developed by Mod Ash

The tools used

This project is based of a few key base tools, to build the map and process the data.

The Basic Tiles (Overworld)

My initial investigations were into coming up with a way to break down the world map image into tiles, which could then be displayed on leaflet. Thankfully, someone much smarter than me is way ahead, with gdal2tiles-leaflet. This is a python script that will take an image, then based off a zoom level and an original image file would generate the leaflet tiles.

1
2
3
4
5
6
./gdal2tiles-leaflet/gdal2tiles.py -l \ 
-p raster \
-z 0-9 \
-w none \
./public/map/original/*.png \
./public/map/generated

This command is basically just taking the downloaded osrsmap in public/map/original, -z 0-9 just means do all renderings between zoom level 0-9, -p raster says to use the raster cutting profile, -w none is just saying generate no webview. The result of this command is a series of broken up tiles stored in public/map/genderated/{zoomLevel}/{x}/{y}.png.

These tiles are fed into leaflet and hey preseto you have a map of Runescape!

The Basic Tiles (Dungeons)

Here is where things get more dicey, I wanted to apply the same logic as above, but couldn’t find a reliable source for a map containing all dungeons, that was until I found Explv’s Map. I do not promote botting or any other uses this map may have, but I will say the data it supplied openly was invaluable.

From this map I was able to write the following hacky bash script, that would get all the tiles generated from Exply’s Map and store them locally for futher processing, I did this at the highest level zoom level possible.

1
2
3
4
5
6
7
8
9
10
11
12
13
#Create a folder for each dungeon level (Basically runescape has map layers under the overall layers
for ((z=0;z<=3;z++)); do
# Loop through the entire y axis where the dungeons are
for ((y=188;y<=579;y++)); do
# Ignore this massive black area in the middle
if [ "$y" -ge 310 -a "$y" -le 470 ]; then continue; fi
mkdir -p "./outputz$z/$y"
for ((x=0;x<=195;x++)); do
#Download each style and store it somewhere that makes sense to us
curl https://raw.githubusercontent.com/Explv/osrs_map_full_2019_02_09/master/$z/10/$x/$y.png > "./outputz$z/$y/$x-$y.png"
done
done
done

Now I had my sources tiles I had to stitch together. This tool by far the longest time, but the resulting script looks like this essentially taking 5 parameters, an x y for the top left corner, an x y for the bottom right corner a label to name the map and a z index we need:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Xstart=$1
Ystart=$3
Xend=$2
Yend=$4
name=$5
zIndex=$6

mkdir $name
rm $name/* -f
echo "==> Start: $name"
for x in $(seq $Xstart $Xend); do
for y in $(seq $Ystart $Yend); do
cp outputz$zIndex/$x/$y-$x.png $name/$(printf "%04d" $y)-$(printf "%04d" $x).png
done
done

for x in $(seq $Xstart $Xend); do
convert $name/*-$(printf "%04d" $x).png +append $name/row-$x.png
done

convert $(ls $name/row-*.png | tac) -append locations/$name.png

rm $name -rf
echo "==> End: $name"

Below is a sample of what this looks like in the final file, see the full script here: known_spots.sh

1
2
3
./get_tiles.sh 196 203 76 84 zanaris 0
./get_tiles.sh 216 219 76 79 viyeldi_caves 0
./get_tiles.sh 212 215 84 86 lighthouse_dungeon 0

There is a script between this and the next that I won’t go into detail about but essentially it processes all the images to have a consistent black background and center the dungeon inside of it, ensure all dungeons are too the same scale in the final result.

The result of all of this means I have high resolution, blank images of every dungeon in Runescape. If you want to skip all the steps above, these are available here.

These are then all passed back through gdal2tiles-leaflet, which creates scaled tiles, these ensure that we can work with them in leaflet. See the script for regening the dungeon tiles here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
rm ./public/map/dungeons/generated/* -rf
#./gdal2tiles-leaflet/gdal2tiles.py -l -p raster -z 0-9 -w none ../static/map/original/osrs_world_map.png ../static/map/generated
for filename in ./public/map/dungeons/originals/*/*.png ; do
original_filename=$(echo $filename | sed -e "s/\.png$//")
convert $original_filename.png $original_filename.jpg

filename=$(echo $original_filename | sed -e "s/\.\/public\/map\/dungeons\/originals\/.*\///")
mkdir -p ./public/map/dungeons/generated/$filename
if [ ! -f ./public/map/dungeons/overrides/$filename/$filename.jpg ]; then
./gdal2tiles-leaflet/gdal2tiles.py -l -p raster -z 1-4 -w none $original_filename.jpg ./public/map/dungeons/generated/$filename
else

./gdal2tiles-leaflet/gdal2tiles.py -l -p raster -z 1-4 -w none ./public/map/dungeons/overrides/$filename/$filename.jpg ./public/map/dungeons/generated/$filename
fi
echo $filename
done

Now we have everything we need to render a runescape map, obviously there is a lot more work on the react side to piece this all together but the base idea is here. You can always view the full source for RSMap here