@2003scape/rsc-landscape 中文文档教程

发布于 4年前 浏览 20 项目主页 更新于 3年前

rsc-landscape

(反)序列化 runescape 经典景观文件。 解析原始的 landmaps 归档到 tile 对象,转储 PNG,进行更改和编码 + 将它们压缩回原始档案。

用 rsc-landscape 生成的世界地图

与 jagex 的世界地图比较

由于 GIF,jagex 生成的官方世界地图包含的细节较少 调色板压缩,以及扇区之间的剪切对象符号。 它是 与最新版本相比也缺少一些区域(格特鲁德的房子, digsite、shilo 村等)。

install

$ npm install @2003scape/rsc-landscape # -g for CLI program

cli usage

rsc-landscape <command>

Commands:
  rsc-landscape generate-map <archives..>  generate world map png
  rsc-landscape dump-json <archives..>     dump JSON files of each sector
  rsc-landscape pack-json <directory>      generate land and maps archives from
                                           directory of JSON files
  rsc-landscape print-sector <archives..>  print coloured sector to terminal

Options:
  --help     Show help                                                 [boolean]
  --version  Show version number                                       [boolean]
$ rsc-landscape generate-map land* maps* -O object-locs.json \
    -p map-points.json -l map-labels.json # generate worldmap.png
$ rsc-landscape generate-map land* maps* --plane 3 -o dungeons.png
$ rsc-landscape print-sector land* maps* -x 50 -y 50 -z 0 -c 2 # lumbridge

example

const fs = require('fs');
const { Landscape } = require('./src');

const landscape = new Landscape();

landscape.loadJag(fs.readFileSync('./land63.jag'),
    fs.readFileSync('./maps63.jag'));
landscape.loadMem(fs.readFileSync('./land63.mem'),
    fs.readFileSync('./maps63.mem'));

landscape.parseArchives();

const lumbridge = landscape.sectors[50][50][0];

const tile = lumbridge.tiles[0][0];
console.log(tile.colour, tile.getGameCoords());

const tile2 = landscape.getTileAtGameCoords(126, 1468);
console.log(tile2.getTileDef());

process.stdout.write(lumbridge.toString(true));
fs.writeFileSync(`./sector-lumbridge.png`, lumbridge.toCanvas().toBuffer());

(async () => {
    fs.writeFileSync('./worldmap.png', (await landscape.toCanvas({
        points: require('./map-points.json'),
        objects: require('./object-locs.json'),
        labels: require('./map-labels.json')
    })).toBuffer());
})();

file formats

runescape classic 世界被分成扇区,每个扇区包含 48x48 (2304) 瓷砖。 overworld 和 dungeon 扇区包含一个 .hei.dat 文件,扇区 楼上只包含.dat文件,任何有对象位置的扇区都会 有一个 .loc 文件。

  • .hei file in land archive which stores elevation and colour of tiles
  • .dat file in maps archive which stores walls and object direction of tiles
  • .loc file in maps archive which stores object IDs (used for the login screen previews)

api

.terrainColours.integer

一组原始的、未加深的 256 种颜色,客户使用这些颜色来为瓷砖着色。

.terrainColours.rgb

用于每个图块的 256 种地图颜色的数组,变暗 50% 并转换为 rgb(r, g, b) 格式。

.tileOverlays

ID 到图块覆盖信息的映射。

tile = new Tile({ sector, x, y, … })

创建新的部门瓷砖。 接受下面列出的所有属性。

tile.colour

0-255 中的数字对应于 .terrainColours 中的颜色。

tile.elevation

0-255 之间的数字描述了 tile 的高度。

tile.direction

0-6 中的数字描述对象在图块上应面对的方向。

tile.overlay

叠加类型索引。 相应的名称存储在 .overlays 中。

tile.wall

具有以下潜在属性的对象:

{
    diagonal: {
        direction: '/' || '\\',
        overlay: overlay
    } || null,
    vertical: overlay || 0,
    horizontal: overlay || 0,
    roof: roofOverlay || 0
}

tile.objectId

在此处存储对象以供登录屏幕预览。

tile.populate()

从 tile 的扇区读取缓冲区并填充其属性。

tile.getTerrainColour()

为地图返回此图块的基色。

tile.getTileDef()

返回描述图块覆盖属性的对象(来自 ./res/tile-overlays.json):

{
    name: 'road',
    blocked: false,
    bridge: false,
    indoors: false,
    antialias: true,
    colour: 'rgb(64, 64, 64)'
}

tile.getGameCoords()

返回 { x, y } 游戏用于此图块。

sector = new Sector({ x, y, plane, members?, tiles? })

创建新的扇区实例。

sector.members

存储在 .jag.mem 文件中?

sector.width

x 轴 (48) 上的瓷砖数量。

sector.height

y 轴上的瓷砖数量 (48)。

sector.terrainHeight

sector.terrainColour

sector.wallsVertical

sector.wallsHorizontal

sector.wallsRoof

sector.tileDecoration

sector.tileDirection

使用 sector.parse* 或从存档文件填充的 Int8Array 缓冲区 使用 sector.populateBuffers() 的扇区磁贴对象。 这些缓冲器是 编码+压缩成档案。

sector.wallsDiagonal

Int32Array 缓冲区,与上面类似但 32 位存储值 > 255 ( 如果存储对象,则可能大于 48000)。

sector.tiles[width][height]

二维图块对象数组。 从存档缓冲区填充此字段 sector.populateTiles(),或者用 sector.populateBuffers()

sector.parseHei(buffer)

.hei 文件填充 sector.terrainHeightsector.terrainColour

sector.parseDat(buffer)

填充 sector.walls*sector.tileDecorationsector.tileDirection 来自 .dat 文件。

sector.parseLoc(buffer)

使用 .loc 文件中的对象 ID 填充 sector.wallsDiagonal

sector.populateTiles()

使用基于缓冲区的 tile 对象的二维数组 (48x48) 填充 sector.tiles 我们从存档文件中解析。

sector.populateBuffers()

填充未来的存档缓冲区(sector.terrain*sector.wall* 等) 扇区.tiles

sector.getEntryName()

获取横向存档文件名的主要部分。

sector.toHei()

为该扇区获取一个 .hei 文件缓冲区。

sector.toDat()

获取此扇区的 .dat 文件缓冲区。

sector.toLoc()

获取此扇区的 .loc 文件缓冲区(如果未存储对象 ID,则为 null)。

sector.toCanvas(options, [ north, east, south, west ])

将单个扇区渲染到画布上。 第二个参数是可选的,如果你 想要使用相邻扇区(世界地图 生成会自动执行此操作)。

在节点中,您可以将其转换为 PNG 使用 .toBuffer()

sector.toString(terminal = false, colourLevel = -1)

如果 terminal 为真,则返回该扇区的 nethack 式终端渲染:

colourLevel< /code> 描述了 要使用的粉笔颜色级别-1 自动检测最大支持度。

…否则只返回扇区的名称和大小。

landscape = new Landscape()

创建新的景观(反)序列化器实例。

landscape.loadJag(landBuffer, mapBuffer)

landscape.loadMem(landBuffer, mapBuffer)

准备要解析的 .jag.mem 缓冲区。 任何部门加载 landscape.loadMem 将有 sector.members = true

landscape.parseArchives()

用加载的缓冲区填充 landscape.sectors

*landscape.getPopulatedSectors()

返回所有非空扇区的迭代器。

landscape.getSectorNeighbours(x, y, plane)

将邻居返回到扇区位置作为 [north, east, south, west]

landscape.getTileAtGameCoords(x, y)

在游戏中使用的坐标处获取图块。

async landscape.toCanvas({ objects, points, labels })

从所有非空扇区创建世界地图图像。

  • objects is an optional array of the following:
{
    id: 1,
    position: [x, y]
}

它的 xy 乘以图块大小。

  • points is an optional array of the following:
{
    type: 'altar', // 'general-shop', 'dungeon' etc. see ./res/key/
    x, y
}

每个点图像是 15x15。

  • labels is an optional array of the following:
{
    text: 'label\nfor\nsomething',
    x, y,
    size: 10, // 8 is the smallest in use, while 14 is the largest
    align: 'center' || 'left',
    bold: true || undefined,
    colour: 'rgb(254, 165, 0)' || '#ff00ff' || undefined
}

license

版权所有 2019 2003Scape Team

本程序是免费软件:您可以重新分发它和/或修改它 GNU Affero 通用公共许可证的条款由 自由软件基金会,许可证的第 3 版,或(由您选择) 任何更高版本。

分发该程序是希望它有用,但没有任何 保修单; 甚至没有适销性或适用性的默示保证 特殊用途。 有关详细信息,请参阅 GNU Affero 通用公共许可证。

您应该已经收到 GNU Affero 通用公共许可证的副本 有了这个程序。 如果没有,请参阅 http://www.gnu.org/licenses/。

rsc-landscape

(de)serialize runescape classic landscape files. parse the original land and maps archives into a tile objects, dump PNGs, make changes and encode + compress them back to an original archive.

a world map generated with rsc-landscape

comparison with jagex's world map

the official world map generated by jagex contains less detail due to GIF palette compression, as well as clipped object symbols between sectors. it's also missing some areas compared to the latest revision (gertrude's house, digsite, shilo village, etc.).

install

$ npm install @2003scape/rsc-landscape # -g for CLI program

cli usage

rsc-landscape <command>

Commands:
  rsc-landscape generate-map <archives..>  generate world map png
  rsc-landscape dump-json <archives..>     dump JSON files of each sector
  rsc-landscape pack-json <directory>      generate land and maps archives from
                                           directory of JSON files
  rsc-landscape print-sector <archives..>  print coloured sector to terminal

Options:
  --help     Show help                                                 [boolean]
  --version  Show version number                                       [boolean]
$ rsc-landscape generate-map land* maps* -O object-locs.json \
    -p map-points.json -l map-labels.json # generate worldmap.png
$ rsc-landscape generate-map land* maps* --plane 3 -o dungeons.png
$ rsc-landscape print-sector land* maps* -x 50 -y 50 -z 0 -c 2 # lumbridge

example

const fs = require('fs');
const { Landscape } = require('./src');

const landscape = new Landscape();

landscape.loadJag(fs.readFileSync('./land63.jag'),
    fs.readFileSync('./maps63.jag'));
landscape.loadMem(fs.readFileSync('./land63.mem'),
    fs.readFileSync('./maps63.mem'));

landscape.parseArchives();

const lumbridge = landscape.sectors[50][50][0];

const tile = lumbridge.tiles[0][0];
console.log(tile.colour, tile.getGameCoords());

const tile2 = landscape.getTileAtGameCoords(126, 1468);
console.log(tile2.getTileDef());

process.stdout.write(lumbridge.toString(true));
fs.writeFileSync(`./sector-lumbridge.png`, lumbridge.toCanvas().toBuffer());

(async () => {
    fs.writeFileSync('./worldmap.png', (await landscape.toCanvas({
        points: require('./map-points.json'),
        objects: require('./object-locs.json'),
        labels: require('./map-labels.json')
    })).toBuffer());
})();

file formats

the runescape classic world is separated into sectors, each containing 48x48 (2304) tiles. overworld and dungeon sectors contain both a .hei and .dat file, sectors upstairs only contain .dat files, and any sector with object locations will have a .loc file.

  • .hei file in land archive which stores elevation and colour of tiles
  • .dat file in maps archive which stores walls and object direction of tiles
  • .loc file in maps archive which stores object IDs (used for the login screen previews)

api

.terrainColours.integer

array of original, undarkened 256 colours client uses to colour tiles.

.terrainColours.rgb

array of 256 map colours used for each tile, darkened by 50% and converted to rgb(r, g, b) format.

.tileOverlays

map of IDs to tile overlay information.

tile = new Tile({ sector, x, y, … })

create new sector tile. accepts all of the properties listed below.

tile.colour

number from 0-255 corresponding to colour in .terrainColours.

tile.elevation

number from 0-255 describing height of tile.

tile.direction

number from 0-6 describing direction objects should face on tile.

tile.overlay

overlay type index. corresponding names are stored in .overlays.

tile.wall

object with following potential properties:

{
    diagonal: {
        direction: '/' || '\\',
        overlay: overlay
    } || null,
    vertical: overlay || 0,
    horizontal: overlay || 0,
    roof: roofOverlay || 0
}

tile.objectId

store object here for login screen previews.

tile.populate()

read buffers from tile's sector and populate its properties.

tile.getTerrainColour()

return base colour of this tile for maps.

tile.getTileDef()

return object describing attributes of tile's overlay (from ./res/tile-overlays.json):

{
    name: 'road',
    blocked: false,
    bridge: false,
    indoors: false,
    antialias: true,
    colour: 'rgb(64, 64, 64)'
}

tile.getGameCoords()

return { x, y } game uses for this tile.

sector = new Sector({ x, y, plane, members?, tiles? })

create new sector instance.

sector.members

store in .jag or .mem file?

sector.width

amount of tiles on x axis (48).

sector.height

amount of tiles on y axis (48).

sector.terrainHeight

sector.terrainColour

sector.wallsVertical

sector.wallsHorizontal

sector.wallsRoof

sector.tileDecoration

sector.tileDirection

Int8Array buffers populated from archive files with sector.parse* or from sector's tile objects with sector.populateBuffers(). these buffers are encoded + compressed into archives.

sector.wallsDiagonal

Int32Array buffer, similar to above but 32-bit to store values > 255 ( potentially larger than 48000 if objects are stored).

sector.tiles[width][height]

2d array of tile objects. populate this field from the archive buffers with sector.populateTiles(), or populate the future archive buffers with sector.populateBuffers().

sector.parseHei(buffer)

populate sector.terrainHeight and sector.terrainColour from a .hei file.

sector.parseDat(buffer)

populate sector.walls*, sector.tileDecoration and sector.tileDirection from a .dat file.

sector.parseLoc(buffer)

populate sector.wallsDiagonal with object IDs from a .loc file.

sector.populateTiles()

populate sector.tiles with a 2d array (48x48) of tile objects based on buffers we parsed from archived files.

sector.populateBuffers()

populate future archive buffers (sector.terrain*, sector.wall*, etc.) with sector.tiles.

sector.getEntryName()

get the main portion of a landscape archive filename.

sector.toHei()

get a .hei file buffer for this sector.

sector.toDat()

get a .dat file buffer for this sector.

sector.toLoc()

get a .loc file buffer for this sector (or null if no objects ID are stored).

sector.toCanvas(options, [ north, east, south, west ])

render an individual sector to a canvas. the second argument is optional if you want to antialias the edges properly using the neighbouring sectors (world map generation does this automatically).

in node, you can turn this into a PNG with .toBuffer().

sector.toString(terminal = false, colourLevel = -1)

if terminal is true, return a nethack-esque terminal rendering of the sector:

colourLevel describes the chalk level of colours to use. -1 automatically detects the maximum support.

…otherwise just return the name and size of the sector.

landscape = new Landscape()

create new landscape (de)serializer instance.

landscape.loadJag(landBuffer, mapBuffer)

landscape.loadMem(landBuffer, mapBuffer)

prepare .jag and .mem buffers to be parsed. any sectors loaded with landscape.loadMem will have sector.members = true.

landscape.parseArchives()

populate landscape.sectors with loaded buffers.

*landscape.getPopulatedSectors()

return iterator of all the non-empty sectors.

landscape.getSectorNeighbours(x, y, plane)

return neighbours to a sector position as [north, east, south, west].

landscape.getTileAtGameCoords(x, y)

get the tile at coordinates used in game.

async landscape.toCanvas({ objects, points, labels })

create a world map image from all of the non-empty sectors.

  • objects is an optional array of the following:
{
    id: 1,
    position: [x, y]
}

its x and y are multipled by the tile size.

  • points is an optional array of the following:
{
    type: 'altar', // 'general-shop', 'dungeon' etc. see ./res/key/
    x, y
}

each point image is 15x15.

  • labels is an optional array of the following:
{
    text: 'label\nfor\nsomething',
    x, y,
    size: 10, // 8 is the smallest in use, while 14 is the largest
    align: 'center' || 'left',
    bold: true || undefined,
    colour: 'rgb(254, 165, 0)' || '#ff00ff' || undefined
}

license

Copyright 2019 2003Scape Team

This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses/.

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文