{"id":25940700,"url":"https://github.com/2003scape/rsc-landscape","last_synced_at":"2025-03-04T05:18:33.835Z","repository":{"id":36463691,"uuid":"225511439","full_name":"2003scape/rsc-landscape","owner":"2003scape","description":"🗺️ (de)serialize runescape classic landscape files","archived":false,"fork":false,"pushed_at":"2024-12-27T23:52:40.000Z","size":1821,"stargazers_count":13,"open_issues_count":3,"forks_count":9,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-02-19T18:40:08.735Z","etag":null,"topics":["bzip2","jagex","json","landscape","maps","rsc","runescape","tiles"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/2003scape.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-03T02:19:49.000Z","updated_at":"2024-12-27T23:52:43.000Z","dependencies_parsed_at":"2024-10-24T21:21:30.698Z","dependency_job_id":"984378ca-f5f3-484d-ba01-8a55319b8cdb","html_url":"https://github.com/2003scape/rsc-landscape","commit_stats":{"total_commits":4,"total_committers":1,"mean_commits":4.0,"dds":0.0,"last_synced_commit":"1331d895e50a0383cb5b117aee0d70fde8b9b1d0"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2003scape%2Frsc-landscape","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2003scape%2Frsc-landscape/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2003scape%2Frsc-landscape/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/2003scape%2Frsc-landscape/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/2003scape","download_url":"https://codeload.github.com/2003scape/rsc-landscape/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241507753,"owners_count":19973881,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bzip2","jagex","json","landscape","maps","rsc","runescape","tiles"],"created_at":"2025-03-04T05:18:33.239Z","updated_at":"2025-03-04T05:18:33.814Z","avatar_url":"https://github.com/2003scape.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# rsc-landscape\n(de)serialize runescape classic landscape files. parse the original `land` and\n`maps` archives into a tile objects, dump PNGs, make changes and encode +\ncompress them back to an original archive.\n\n![](./doc/worldmap-final.png?raw=true)\n\n*a world map generated with rsc-landscape*\n\n![](./doc/map-comparison.gif?raw=true)\n![](./doc/map-comparison2.gif?raw=true)\n![](./doc/map-comparison3.gif?raw=true)\n\n*comparison with jagex's world map*\n\nthe official world map generated by jagex contains less detail due to GIF\npalette compression, as well as clipped object symbols between sectors. it's\nalso missing some areas compared to the latest revision (gertrude's house,\ndigsite, shilo village, etc.).\n\n## install\n\n    $ npm install @2003scape/rsc-landscape # -g for CLI program\n\n## cli usage\n```\nrsc-landscape \u003ccommand\u003e\n\nCommands:\n  rsc-landscape generate-map \u003carchives..\u003e  generate world map png\n  rsc-landscape dump-json \u003carchives..\u003e     dump JSON files of each sector\n  rsc-landscape pack-json \u003cdirectory\u003e      generate land and maps archives from\n                                           directory of JSON files\n  rsc-landscape print-sector \u003carchives..\u003e  print coloured sector to terminal\n\nOptions:\n  --help     Show help                                                 [boolean]\n  --version  Show version number                                       [boolean]\n```\n\n    $ rsc-landscape generate-map land* maps* -O object-locs.json \\\n        -p map-points.json -l map-labels.json # generate worldmap.png\n    $ rsc-landscape generate-map land* maps* --plane 3 -o dungeons.png\n    $ rsc-landscape print-sector land* maps* -x 50 -y 50 -z 0 -c 2 # lumbridge\n\n## example\n```javascript\nconst fs = require('fs');\nconst { Landscape } = require('./src');\n\nconst landscape = new Landscape();\n\nlandscape.loadJag(fs.readFileSync('./land63.jag'),\n    fs.readFileSync('./maps63.jag'));\nlandscape.loadMem(fs.readFileSync('./land63.mem'),\n    fs.readFileSync('./maps63.mem'));\n\nlandscape.parseArchives();\n\nconst lumbridge = landscape.sectors[50][50][0];\n\nconst tile = lumbridge.tiles[0][0];\nconsole.log(tile.colour, tile.getGameCoords());\n\nconst tile2 = landscape.getTileAtGameCoords(126, 1468);\nconsole.log(tile2.getTileDef());\n\nprocess.stdout.write(lumbridge.toString(true));\nfs.writeFileSync(`./sector-lumbridge.png`, lumbridge.toCanvas().toBuffer());\n\n(async () =\u003e {\n    fs.writeFileSync('./worldmap.png', (await landscape.toCanvas({\n        points: require('./map-points.json'),\n        objects: require('./object-locs.json'),\n        labels: require('./map-labels.json')\n    })).toBuffer());\n})();\n```\n\n## file formats\nthe runescape classic world is separated into sectors, each containing 48x48\n(2304) tiles.\noverworld and dungeon sectors contain both a `.hei` and `.dat` file, sectors\nupstairs only contain `.dat` files, and any sector with object locations will\nhave a `.loc` file.\n* `.hei` file in *land* archive which stores elevation and colour of tiles\n* `.dat` file in *maps* archive which stores walls and object direction of tiles\n* `.loc` file in *maps* archive which stores object IDs (used for the login\nscreen previews)\n\n## api\n### .terrainColours.integer\narray of original, undarkened 256 colours client uses to colour tiles.\n\n### .terrainColours.rgb\narray of 256 map colours used for each tile, darkened by 50% and converted to\n`rgb(r, g, b)` format.\n\n### .tileOverlays\nmap of IDs to tile overlay information.\n\n### tile = new Tile({ sector, x, y, ... })\ncreate new sector tile. accepts all of the properties listed below.\n\n### tile.colour\nnumber from 0-255 corresponding to colour in `.terrainColours`.\n\n### tile.elevation\nnumber from 0-255 describing height of tile.\n\n### tile.direction\nnumber from 0-6 describing direction objects should face on tile.\n\n### tile.overlay\noverlay type index. corresponding names are stored in `.overlays`.\n\n### tile.wall\nobject with following potential properties:\n\n```javascript\n{\n    diagonal: {\n        direction: '/' || '\\\\',\n        overlay: overlay\n    } || null,\n    vertical: overlay || 0,\n    horizontal: overlay || 0,\n    roof: roofOverlay || 0\n}\n```\n\n### tile.objectId\nstore object here for login screen previews.\n\n### tile.populate()\nread buffers from tile's sector and populate its properties.\n\n### tile.getTerrainColour()\nreturn base colour of this tile for maps.\n\n### tile.getTileDef()\nreturn  object describing attributes of tile's overlay (from\n`./res/tile-overlays.json`):\n```javascript\n{\n    name: 'road',\n    blocked: false,\n    bridge: false,\n    indoors: false,\n    antialias: true,\n    colour: 'rgb(64, 64, 64)'\n}\n```\n\n### tile.getGameCoords()\nreturn `{ x, y }` game uses for this tile.\n\n### sector = new Sector({ x, y, plane, members?, tiles? })\ncreate new sector instance.\n\n### sector.members\nstore in `.jag` or `.mem` file?\n\n### sector.width\namount of tiles on x axis (48).\n\n### sector.height\namount of tiles on y axis (48).\n\n### sector.terrainHeight\n### sector.terrainColour\n### sector.wallsVertical\n### sector.wallsHorizontal\n### sector.wallsRoof\n### sector.tileDecoration\n### sector.tileDirection\nInt8Array buffers populated from archive files with `sector.parse*` or from\nsector's tile objects with `sector.populateBuffers()`. these buffers are\nencoded + compressed into archives.\n\n### sector.wallsDiagonal\nInt32Array buffer, similar to above but 32-bit to store values \u003e 255 (\npotentially larger than 48000 if objects are stored).\n\n### sector.tiles\\[width\\]\\[height\\]\n2d array of tile objects. populate this field from the archive buffers with\n`sector.populateTiles()`, or populate the future archive buffers with\n`sector.populateBuffers()`.\n\n### sector.parseHei(buffer)\npopulate `sector.terrainHeight` and `sector.terrainColour` from a `.hei` file.\n\n### sector.parseDat(buffer)\npopulate `sector.walls*`, `sector.tileDecoration` and `sector.tileDirection`\nfrom a `.dat` file.\n\n### sector.parseLoc(buffer)\npopulate `sector.wallsDiagonal` with object IDs from a `.loc` file.\n\n### sector.populateTiles()\npopulate `sector.tiles` with a 2d array (48x48) of tile objects based on buffers\nwe parsed from archived files.\n\n### sector.populateBuffers()\npopulate future archive buffers (`sector.terrain*`, `sector.wall*`, etc.) with\n`sector.tiles`.\n\n### sector.getEntryName()\nget the main portion of a landscape archive filename.\n\n### sector.toHei()\nget a `.hei` file buffer for this sector.\n\n### sector.toDat()\nget a `.dat` file buffer for this sector.\n\n### sector.toLoc()\nget a `.loc` file buffer for this sector (or null if no objects ID are stored).\n\n### sector.toCanvas(options, [ north, east, south, west ])\nrender an individual sector to a canvas. the second argument is optional if you\nwant to antialias the edges properly using the neighbouring sectors (world map\ngeneration does this automatically).\n\nin node, you can turn this into a PNG\nwith [`.toBuffer()`](https://github.com/Automattic/node-canvas#canvastobuffer).\n\n### sector.toString(terminal = false, colourLevel = -1)\nif `terminal` is true, return a nethack-esque terminal rendering of the sector:\n\n![](./doc/terminal.png?raw=true)\n\n`colourLevel` describes the\n[chalk level of colours to use](https://github.com/chalk/chalk#chalklevel).\n`-1` automatically detects the maximum support.\n\n...otherwise just return the name and size of the sector.\n\n### landscape = new Landscape()\ncreate new landscape (de)serializer instance.\n\n### landscape.loadJag(landBuffer, mapBuffer)\n### landscape.loadMem(landBuffer, mapBuffer)\nprepare `.jag` and `.mem` buffers to be parsed. any sectors loaded with\n`landscape.loadMem` will have `sector.members = true`.\n\n### landscape.parseArchives()\npopulate `landscape.sectors` with loaded buffers.\n\n### \\*landscape.getPopulatedSectors()\nreturn iterator of all the non-empty sectors.\n\n### landscape.getSectorNeighbours(x, y, plane)\nreturn neighbours to a sector position as `[north, east, south, west]`.\n\n### landscape.getTileAtGameCoords(x, y)\nget the tile at coordinates used in game.\n\n### async landscape.toCanvas({ objects, points, labels })\ncreate a world map image from all of the non-empty sectors.\n\n* `objects` is an optional array of the following:\n```javascript\n{\n    id: 1,\n    position: [x, y]\n}\n```\n\nits `x` and `y` are multipled by the tile size.\n\n* `points` is an optional array of the following:\n```javascript\n{\n    type: 'altar', // 'general-shop', 'dungeon' etc. see ./res/key/\n    x, y\n}\n```\n\neach point image is 15x15.\n\n* `labels` is an optional array of the following:\n```javascript\n{\n    text: 'label\\nfor\\nsomething',\n    x, y,\n    size: 10, // 8 is the smallest in use, while 14 is the largest\n    align: 'center' || 'left',\n    bold: true || undefined,\n    colour: 'rgb(254, 165, 0)' || '#ff00ff' || undefined\n}\n```\n\n## license\nCopyright 2019  2003Scape Team\n\nThis program is free software: you can redistribute it and/or modify it under\nthe terms of the GNU Affero General Public License as published by the\nFree Software Foundation, either version 3 of the License, or (at your option)\nany later version.\n\nThis program is distributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A\nPARTICULAR PURPOSE. See the GNU Affero General Public License for more details.\n\nYou should have received a copy of the GNU Affero General Public License along\nwith this program. If not, see http://www.gnu.org/licenses/.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2003scape%2Frsc-landscape","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F2003scape%2Frsc-landscape","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F2003scape%2Frsc-landscape/lists"}