Creating an Interactive Online Map for a 15-Year-Old Oblivion Mod

Full screen version

Ever since I started playing computer games, The Elder Scrolls series has held a special place in my heart. What draws me in every time is the incredible sense of freedom—the ability to go anywhere, do anything, and truly make the world my own. Whether it’s uncovering hidden caves, or exploring vast open landscapes.
But what I like even more than Bethesda's games are the total conversions created by the small german studio SureAI that use the Elderscroll's engine to build totally new games with awesome handcrafted worlds and hooking stories.
Out of all their creations, Nehrim is my personal favorite—the blend of its stunning landscapes and a hefty dose of nostalgia fills me with a warm, comforting feeling every time I dive back into it.
For Oblivion, there exists a fan made Google Earth like map which I really liked when playing the game. Out of boredom, I decided to build something similar for Nehrim as well.

Tile Extraction

Luckily for me, Oblivion's official modding tool, the TES Construction Set, Comes with a functionality called "Create Local Maps"

TES CS Local Map tool

The output is a pile of DDS files which contain worldspace name (in my case "NehrimWorldpace") and x+y coordinates in the file name. In a first step, I converted them to PNG files using Imagemagick's "mogrify" command. I also cropped them, since I found out they were overlapping a few pixels:

mogrify -path png -format png -crop 241x241+14+14  dds/*.dds

The results look like this:

Zooming

Nehrim's world is approx. 300x300 tiles large which would cause a very poor rendering performance and high load on my server. So my idea was to combine multiple tiles together for lower zoom-levels:

I did this using a quick-and-dirty python script. The results look like this:

The Software

To bring everything to the web, I use a fairly standard technology stack built around the Leaflet framework. Instead of an OSM tileserver, I point the tile server endpoint to the server delivering the game's tiles. I only had to invert the y-coordinate since Oblivions coordinate system is different than Leaflet's.

var map = L.map(
    'map',
    { crs: L.CRS.Simple }
).setView([0, 0], 0);

L.TileLayer.Ntilelayer = L.TileLayer.extend({
    getTileUrl: function(coords) {
        coords.y = - coords.y;
        return L.TileLayer.prototype.getTileUrl.call(this, coords);
    }
});

L.tileLayer.ntilelayer = function(templateUrl, options) {
    return new L.TileLayer.Ntilelayer(templateUrl, options);
}

L.tileLayer.ntilelayer('{x}/{y}/{z}.png', {
    tms: false,
    continuousWorld: 'false',
    noWrap: false,
    defaultRadius:1,
    maxNativeZoom: 0,
    minNativeZoom: -5,
    minZoom: -5,
    maxZoom: 5
}).addTo(map);

Closing Remarks

Building this little project was super fun and I love exploring the map to this day.
I'd also really like to add map markers and more interactive elements to it but haven't yet found out how to extract more data out of the *.esm file.
If you have any ideas or like to help, I'd love if you contact me.