revival time

This commit is contained in:
sample-text-here 2021-11-17 16:28:06 -08:00
parent 66f9254429
commit 8ace3266f3
11 changed files with 675 additions and 624 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.pnpm-debug.log

View file

@ -104,3 +104,15 @@ the content type
the content's name
# roadmap
- currently, only a small subset of the features are
supported.
- version 1 will be released when all features are
supported and there are no major bugs
- version 2 will be released when i implement map io
- more versions will be released when the schematic/map
system changes signifigantly

View file

@ -1,332 +1,378 @@
const { err, capitalize } = require("../util/misc.js");
const ContentType = [
"item",
"block",
"mech_UNUSED",
"bullet",
"liquid",
"status",
"unit",
"weather",
"effect_UNUSED",
"sector",
"loadout_UNUSED",
"typeid_UNUSED",
"error",
"planet",
"ammo",
"item",
"block",
"mech_UNUSED",
"bullet",
"liquid",
"status",
"unit",
"weather",
"effect_UNUSED",
"sector",
"loadout_UNUSED",
"typeid_UNUSED",
"error",
"planet",
"ammo",
];
const content = {
Block: [
"air",
"spawn",
"cliff",
"deepwater",
"water",
"taintedWater",
"tar",
"slag",
"stone",
"craters",
"charr",
"sand",
"darksand",
"dirt",
"mud",
"ice",
"snow",
"darksandTaintedWater",
"space",
"dacite",
"stoneWall",
"dirtWall",
"sporeWall",
"iceWall",
"daciteWall",
"sporePine",
"snowPine",
"pine",
"shrubs",
"whiteTree",
"whiteTreeDead",
"sporeCluster",
"iceSnow",
"sandWater",
"darksandWater",
"duneWall",
"sandWall",
"moss",
"sporeMoss",
"shale",
"shaleWall",
"shaleBoulder",
"sandBoulder",
"daciteBoulder",
"boulder",
"snowBoulder",
"basaltBoulder",
"grass",
"salt",
"metalFloor",
"metalFloorDamaged",
"metalFloor2",
"metalFloor3",
"metalFloor5",
"basalt",
"magmarock",
"hotrock",
"snowWall",
"saltWall",
"darkPanel1",
"darkPanel2",
"darkPanel3",
"darkPanel4",
"darkPanel5",
"darkPanel6",
"darkMetal",
"pebbles",
"tendrils",
"oreCopper",
"oreLead",
"oreScrap",
"oreCoal",
"oreTitanium",
"oreThorium",
"siliconSmelter",
"siliconCrucible",
"kiln",
"graphitePress",
"plastaniumCompressor",
"multiPress",
"phaseWeaver",
"surgeSmelter",
"pyratiteMixer",
"blastMixer",
"cryofluidMixer",
"melter",
"separator",
"disassembler",
"sporePress",
"pulverizer",
"incinerator",
"coalCentrifuge",
"powerSource",
"powerVoid",
"itemSource",
"itemVoid",
"liquidSource",
"liquidVoid",
"illuminator",
"copperWall",
"copperWallLarge",
"titaniumWall",
"titaniumWallLarge",
"plastaniumWall",
"plastaniumWallLarge",
"thoriumWall",
"thoriumWallLarge",
"door",
"doorLarge",
"phaseWall",
"phaseWallLarge",
"surgeWall",
"surgeWallLarge",
"mender",
"mendProjector",
"overdriveProjector",
"overdriveDome",
"forceProjector",
"shockMine",
"scrapWall",
"scrapWallLarge",
"scrapWallHuge",
"scrapWallGigantic",
"thruster",
"conveyor",
"titaniumConveyor",
"plastaniumConveyor",
"armoredConveyor",
"distributor",
"junction",
"itemBridge",
"phaseConveyor",
"sorter",
"invertedSorter",
"router",
"overflowGate",
"underflowGate",
"massDriver",
"payloadConveyor",
"payloadRouter",
"mechanicalPump",
"rotaryPump",
"thermalPump",
"conduit",
"pulseConduit",
"platedConduit",
"liquidRouter",
"liquidTank",
"liquidJunction",
"bridgeConduit",
"phaseConduit",
"combustionGenerator",
"thermalGenerator",
"steamGenerator",
"differentialGenerator",
"rtgGenerator",
"solarPanel",
"largeSolarPanel",
"thoriumReactor",
"impactReactor",
"battery",
"batteryLarge",
"powerNode",
"powerNodeLarge",
"surgeTower",
"diode",
"mechanicalDrill",
"pneumaticDrill",
"laserDrill",
"blastDrill",
"waterExtractor",
"oilExtractor",
"cultivator",
"coreShard",
"coreFoundation",
"coreNucleus",
"vault",
"container",
"unloader",
"duo",
"scatter",
"scorch",
"hail",
"arc",
"wave",
"lancer",
"swarmer",
"salvo",
"fuse",
"ripple",
"cyclone",
"foreshadow",
"spectre",
"meltdown",
"segment",
"parallax",
"tsunami",
"commandCenter",
"groundFactory",
"airFactory",
"navalFactory",
"additiveReconstructor",
"multiplicativeReconstructor",
"exponentialReconstructor",
"tetrativeReconstructor",
"repairPoint",
"resupplyPoint",
"message",
"switchBlock",
"microProcessor",
"logicProcessor",
"hyperProcessor",
"largeLogicDisplay",
"logicDisplay",
"memoryCell",
"memoryBank",
"launchPad",
"launchPadLarge",
"interplanetaryAccelerator",
"blockForge",
"blockLoader",
"blockUnloader",
],
Block: [
"air",
"spawn",
"cliff",
"deepwater",
"water",
"taintedWater",
"tar",
"slag",
"stone",
"craters",
"charr",
"sand",
"darksand",
"dirt",
"mud",
"ice",
"snow",
"darksandTaintedWater",
"space",
"dacite",
"stoneWall",
"dirtWall",
"sporeWall",
"iceWall",
"daciteWall",
"sporePine",
"snowPine",
"pine",
"shrubs",
"whiteTree",
"whiteTreeDead",
"sporeCluster",
"iceSnow",
"sandWater",
"darksandWater",
"duneWall",
"sandWall",
"moss",
"sporeMoss",
"shale",
"shaleWall",
"shaleBoulder",
"sandBoulder",
"daciteBoulder",
"boulder",
"snowBoulder",
"basaltBoulder",
"grass",
"salt",
"metalFloor",
"metalFloorDamaged",
"metalFloor2",
"metalFloor3",
"metalFloor5",
"basalt",
"magmarock",
"hotrock",
"snowWall",
"saltWall",
"darkPanel1",
"darkPanel2",
"darkPanel3",
"darkPanel4",
"darkPanel5",
"darkPanel6",
"darkMetal",
"pebbles",
"tendrils",
"oreCopper",
"oreLead",
"oreScrap",
"oreCoal",
"oreTitanium",
"oreThorium",
"siliconSmelter",
"siliconCrucible",
"kiln",
"graphitePress",
"plastaniumCompressor",
"multiPress",
"phaseWeaver",
"surgeSmelter",
"pyratiteMixer",
"blastMixer",
"cryofluidMixer",
"melter",
"separator",
"disassembler",
"sporePress",
"pulverizer",
"incinerator",
"coalCentrifuge",
"powerSource",
"powerVoid",
"itemSource",
"itemVoid",
"liquidSource",
"liquidVoid",
"illuminator",
"copperWall",
"copperWallLarge",
"titaniumWall",
"titaniumWallLarge",
"plastaniumWall",
"plastaniumWallLarge",
"thoriumWall",
"thoriumWallLarge",
"door",
"doorLarge",
"phaseWall",
"phaseWallLarge",
"surgeWall",
"surgeWallLarge",
"mender",
"mendProjector",
"overdriveProjector",
"overdriveDome",
"forceProjector",
"shockMine",
"scrapWall",
"scrapWallLarge",
"scrapWallHuge",
"scrapWallGigantic",
"thruster",
"conveyor",
"titaniumConveyor",
"plastaniumConveyor",
"armoredConveyor",
"distributor",
"junction",
"itemBridge",
"phaseConveyor",
"sorter",
"invertedSorter",
"router",
"overflowGate",
"underflowGate",
"massDriver",
"payloadConveyor",
"payloadRouter",
"mechanicalPump",
"rotaryPump",
"thermalPump",
"conduit",
"pulseConduit",
"platedConduit",
"liquidRouter",
"liquidTank",
"liquidJunction",
"bridgeConduit",
"phaseConduit",
"combustionGenerator",
"thermalGenerator",
"steamGenerator",
"differentialGenerator",
"rtgGenerator",
"solarPanel",
"largeSolarPanel",
"thoriumReactor",
"impactReactor",
"battery",
"batteryLarge",
"powerNode",
"powerNodeLarge",
"surgeTower",
"diode",
"mechanicalDrill",
"pneumaticDrill",
"laserDrill",
"blastDrill",
"waterExtractor",
"oilExtractor",
"cultivator",
"coreShard",
"coreFoundation",
"coreNucleus",
"vault",
"container",
"unloader",
"duo",
"scatter",
"scorch",
"hail",
"arc",
"wave",
"lancer",
"swarmer",
"salvo",
"fuse",
"ripple",
"cyclone",
"foreshadow",
"spectre",
"meltdown",
"segment",
"parallax",
"tsunami",
"commandCenter",
"groundFactory",
"airFactory",
"navalFactory",
"additiveReconstructor",
"multiplicativeReconstructor",
"exponentialReconstructor",
"tetrativeReconstructor",
"repairPoint",
"resupplyPoint",
"message",
"switchBlock",
"microProcessor",
"logicProcessor",
"hyperProcessor",
"largeLogicDisplay",
"logicDisplay",
"memoryCell",
"memoryBank",
"launchPad",
"launchPadLarge",
"interplanetaryAccelerator",
"blockForge",
"blockLoader",
"blockUnloader",
],
Item: [
"scrap",
"copper",
"lead",
"graphite",
"coal",
"titanium",
"thorium",
"silicon",
"plastanium",
"phaseFabric",
"surgeAlloy",
"sporePod",
"sand",
"blastCompound",
"pyratite",
"metaglass",
],
Item: [
"scrap",
"copper",
"lead",
"graphite",
"coal",
"titanium",
"thorium",
"silicon",
"plastanium",
"phaseFabric",
"surgeAlloy",
"sporePod",
"sand",
"blastCompound",
"pyratite",
"metaglass",
],
Liquid: ["water", "slag", "oil", "cryofluid"],
Liquid: ["water", "slag", "oil", "cryofluid"],
Unit: [
"mace",
"dagger",
"crawler",
"fortress",
"scepter",
"reign",
"nova",
"pulsar",
"quasar",
"vela",
"corvus",
"atrax",
"spiroct",
"arkyid",
"toxopid",
"flare",
"eclipse",
"horizon",
"zenith",
"antumbra",
"mono",
"poly",
"mega",
"quad",
"oct",
"alpha",
"beta",
"gamma",
"risso",
"minke",
"bryde",
"sei",
"omura",
"block",
],
Unit: [
"mace",
"dagger",
"crawler",
"fortress",
"scepter",
"reign",
"nova",
"pulsar",
"quasar",
"vela",
"corvus",
"atrax",
"spiroct",
"arkyid",
"toxopid",
"flare",
"eclipse",
"horizon",
"zenith",
"antumbra",
"mono",
"poly",
"mega",
"quad",
"oct",
"alpha",
"beta",
"gamma",
"risso",
"minke",
"bryde",
"sei",
"omura",
"block",
],
Bullet: [
"artilleryDense",
"artilleryPlastic",
"artilleryPlasticFrag",
"artilleryHoming",
"artilleryIncendiary",
"artilleryExplosive",
"flakScrap",
"flakLead",
"flakGlass",
"flakGlassFrag",
"fragGlass",
"fragExplosive",
"fragPlastic",
"fragSurge",
"fragGlassFrag",
"fragPlasticFrag",
"missileExplosive",
"missileIncendiary",
"missileSurge",
"standardCopper",
"standardDense",
"standardThorium",
"standardHoming",
"standardIncendiary",
"standardDenseBig",
"standardThoriumBig",
"standardIncendiaryBig",
"waterShot",
"cryoShot",
"slagShot",
"oilShot",
"heavyWaterShot",
"heavyCryoShot",
"heavySlagShot",
"heavyOilShot",
"damageLightning",
"damageLightningGround",
"fireball",
"basicFlame",
"pyraFlame",
"driverBolt",
],
};
class Content {
constructor(type, name) {
this.type = type;
this.name = name;
}
constructor(type, name) {
this.type = type;
this.name = name;
}
get typeId() {
return ContentType.indexOf(this.type.toLowerCase());
}
get typeId() {
return ContentType.indexOf(this.type.toLowerCase());
}
get id() {
return content[this.type].indexOf(this.name);
}
get id() {
return content[this.type].indexOf(this.name);
}
}
function getByName(kind, id) {
if (typeof kind === "number" && !isNaN(kind)) kind = ContentType[kind];
const selected = content[capitalize(kind)];
if (!selected) err("content doesnt exist");
return selected[id] ? new Content(capitalize(kind), selected[id]) : null;
if (typeof kind === "number" && !isNaN(kind)) kind = ContentType[kind];
const selected = content[capitalize(kind)];
if (!selected) throw "content doesnt exist";
return selected[id] ? new Content(capitalize(kind), selected[id]) : null;
}
module.exports = {
ContentType,
Content,
content,
getByName,
ContentType,
Content,
content,
getByName,
};

View file

@ -2,157 +2,152 @@ const zlib = require("zlib");
const { Reader, Writer, TypeIO, Position, capitalize } = require("../util");
const header = Buffer.from("msch");
class Block {
constructor(data = {}) {
this.block = "air";
this.position = new Position(0);
this.config = null;
this.rotation = 0;
Object.assign(this, data);
const me = this;
["block", "position", "config", "rotation"].forEach((i) => {
const fmt = capitalize(i);
this["get" + fmt] = () => {
return me[i];
};
this["set" + fmt] = (val) => {
me[i] = val;
return me;
};
});
}
class Stile {
constructor(data = {}) {
this.block = "air";
this.position = new Position(0);
this.config = null;
this.rotation = 0;
Object.assign(this, data);
const me = this;
for(let i of ["block", "position", "config", "rotation"]) {
const fmt = capitalize(i);
this["get" + fmt] = () => me[i];
this["set" + fmt] = (val) => me[i] = val;
}
}
}
class Schematic {
// load or make a new Schematic
constructor(buffer) {
// create a blank slate
this.reset();
if (!buffer) return this;
// load or make a new Schematic
constructor(buffer) {
// create a blank slate
this.reset();
if (!buffer) return this;
// make sure the header exists
const rawReader = new Reader(buffer);
if (!rawReader.raw(4).equals(header)) err("Incorrect header");
if (rawReader.byte() !== 1) err("Unsupported schematic version");
// make sure the header exists
const rawReader = new Reader(buffer);
if (!rawReader.raw(4).equals(header)) throw "Incorrect header";
if (rawReader.byte() !== 1) throw "Unsupported schematic version";
// create a reader and grab width/height
const reader = new Reader(zlib.inflateSync(buffer.slice(5)));
this.width = reader.short();
this.height = reader.short();
// create a reader and grab width/height
const reader = new Reader(zlib.inflateSync(buffer.slice(5)));
this.width = reader.short();
this.height = reader.short();
// get tags (eg. name)
const tagLen = reader.byte();
for (let i = 0; i < tagLen; i++) {
this.tags[reader.string()] = reader.string();
}
// get tags (eg. name)
const tagLen = reader.byte();
for (let i = 0; i < tagLen; i++) {
this.tags[reader.string()] = reader.string();
}
// block dictionary, each id is mapped to a block
const dictionary = [],
dictLen = reader.byte();
for (let i = 0; i < dictLen; i++) {
dictionary.push(reader.string());
}
// block dictionary, each id is mapped to a block
const dictionary = [],
dictLen = reader.byte();
for (let i = 0; i < dictLen; i++) {
dictionary.push(reader.string());
}
// actually read the blocks
const totalBlocks = reader.int();
for (let i = 0; i < totalBlocks; i++) {
const block = dictionary[reader.byte()];
const position = new Position(reader.int());
const config = TypeIO.read(reader);
const rotation = reader.byte();
if (block === "air") continue;
this.blocks.push(
new Block({
block,
position,
config,
rotation,
})
);
}
}
// actually read the blocks
const totalBlocks = reader.int();
for (let i = 0; i < totalBlocks; i++) {
const block = dictionary[reader.byte()];
const position = new Position(reader.int());
const config = TypeIO.read(reader);
const rotation = reader.byte();
if (block === "air") continue;
const tile = new Stile({ block, position, config, rotation });
this.tiles.push(new Stile(tile));
}
}
// resize the schematic
resize(height, width) {
this.height = height;
this.width = width;
}
// resize the schematic
resize(height, width) {
this.height = height;
this.width = width;
}
// get a block at a x and y position
// creates it if it doesn't exist
block(x, y) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height)
err("out of bounds, resize schematic first!");
for (let i of this.blocks) {
if (i.position.x === x && i.position.y === y) return i;
}
// get a block at a x and y position
// creates it if it doesn't exist
tile(x, y) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height)
throw "out of bounds, resize schematic first!";
for (let i of this.tiles) {
if (i.position.x === x && i.position.y === y) return i;
}
const block = new Block({
position: new Position({ x, y }),
});
const block = new Stile({
position: new Position({ x, y }),
});
this.blocks.push(block);
return block;
}
this.tiles.push(block);
return block;
}
// delete a block at the x and y position
delete(x, y) {
let index = -1;
for (let i = 0; i < this.blocks.length; i++) {
const pos = this.blocks[i].position;
if (pos.x === x && pos.y === y) index = i;
}
if (index >= 0) this.blocks.splice(index, 1);
}
// delete a block at the x and y position
delete(x, y) {
let index = -1;
for (let i = 0; i < this.tiles.length; i++) {
const pos = this.tiles[i].position;
if (pos.x === x && pos.y === y) index = i;
}
if (index >= 0) this.tiles.splice(index, 1);
}
// loop through the blocks
each(callback) {
this.blocks.forEach(callback);
}
// loop through the blocks
each(callback) {
this.tiles.forEach(callback);
}
toBuffer() {
// the constructor, but it's opposite day
toBuffer() {
// the constructor, but it's opposite day
const writer = new Writer();
writer.short(this.width);
writer.short(this.height);
const writer = new Writer();
writer.short(this.width);
writer.short(this.height);
writer.byte(Object.keys(this.tags).length);
for (let i in this.tags) {
writer.string(i);
writer.string(this.tags[i]);
}
writer.byte(Object.keys(this.tags).length);
for (let i in this.tags) {
writer.string(i);
writer.string(this.tags[i]);
}
const dictionary = this.blocks.reduce((acc, i) => {
if (!acc.includes(i.block)) acc.push(i.block);
return acc;
}, []);
const dictionary = this.tiles.reduce((acc, i) => {
if (!acc.includes(i.block)) acc.push(i.block);
return acc;
}, []);
writer.byte(dictionary.length);
dictionary.forEach((i) => writer.string(i));
writer.byte(dictionary.length);
dictionary.forEach((i) => writer.string(i));
writer.int(this.blocks.length);
for (let i of this.blocks) {
writer.byte(dictionary.indexOf(i.block));
writer.int(i.position.pack());
TypeIO.write(writer, i.config);
writer.byte(i.rotation);
}
writer.int(this.tiles.length);
for (let i of this.tiles) {
writer.byte(dictionary.indexOf(i.block));
writer.int(i.position.pack());
TypeIO.write(writer, i.config);
writer.byte(i.rotation);
}
return Buffer.concat([
header,
Buffer.from("\u0001"),
zlib.deflateSync(writer.toBuffer()),
]);
}
return Buffer.concat([
header,
Buffer.from("\u0001"),
zlib.deflateSync(writer.toBuffer()),
]);
}
// reset the schematic
reset() {
this.width = 0;
this.height = 0;
this.tags = {};
this.blocks = [];
}
toString() {
let str = `Schematic "${this.tags.name}" {\n`;
}
// reset the schematic
reset() {
this.width = 0;
this.height = 0;
this.tags = {};
this.tiles= [];
}
}
module.exports = Schematic;

View file

@ -1,3 +1,4 @@
module.exports = {
Schematic: require("./content/schematic.js"),
Schematic: require("./content/schematic.js"),
};

View file

@ -1,19 +1,19 @@
{
"name": "mindustryio",
"version": "0.0.6",
"description": "tools for interacting with mindustry",
"main": "index.js",
"scripts": {
"test": "node ./test/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sample-text-here/mindustryio.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/sample-text-here/mindustryio/issues"
},
"homepage": "https://github.com/sample-text-here/mindustryio#readme"
"name": "mindustryio",
"version": "0.1.0",
"description": "tools for interacting with mindustry",
"main": "index.js",
"scripts": {
"test": "node ./test/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sample-text-here/mindustryio.git"
},
"author": "tezlm",
"license": "ISC",
"bugs": {
"url": "https://github.com/sample-text-here/mindustryio/issues"
},
"homepage": "https://github.com/sample-text-here/mindustryio#readme"
}

BIN
test/10_diffs.msch Normal file

Binary file not shown.

View file

@ -4,23 +4,29 @@ const { Schematic } = require("../index.js");
const buffer = fs.readFileSync(__dirname + "/sample.msch");
const schem = new Schematic(buffer);
// reading basic schematics
assert(schem.width, 4);
assert(schem.height, 8);
assert(schem.tags.name, "Silicon/Blast/Phase/Kiln");
assert(schem.block(2, 2).block, "phase-weaver");
assert(schem.block(3, 4).block, "inverted-sorter");
assert(schem.tile(2, 2).block, "phase-weaver");
assert(schem.tile(3, 4).block, "inverted-sorter");
schem.delete(3, 4);
assert(schem.block(3, 4).block, "air");
schem.block(3, 4).setBlock("copper-wall");
assert(schem.block(3, 4).block, "copper-wall");
// if it crashes, something's wrong
assert(schem.tile(3, 4).block, "air");
schem.tile(3, 4).setBlock("copper-wall");
assert(schem.tile(3, 4).block, "copper-wall");
new Schematic(schem.toBuffer());
// creating schematics
const schem2 = new Schematic();
schem2.resize(5, 5);
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
schem2.block(x, y).block = "copper-wall";
}
for (let y = 0; y < 5; y++) {
schem2.tile(x, y).block = "copper-wall";
}
}
assert(schem2.block(3, 3).block, "copper-wall");
assert(schem2.tile(3, 3).block, "copper-wall");
// schematics
const schem3 = new Schematic(fs.readFileSync(__dirname + "/10_diffs.msch"));
schem3.toBuffer();

View file

@ -1,84 +1,58 @@
class Reader {
constructor(buffer) {
this.buffer = buffer;
this.offset = 0;
}
constructor(buffer) {
this.buffer = buffer;
this.offset = 0;
}
raw(bytes) {
this.offset += bytes;
return this.buffer.slice(this.offset - bytes, this.offset);
}
raw(bytes) {
const old = this.offset;
this.offset += bytes;
return this.buffer.slice(old, this.offset);
}
byte() {
return this.raw(1).readInt8();
}
byte() { return this.raw(1).readInt8() }
short() { return this.raw(2).readInt16BE() }
int() { return this.raw(4).readInt32BE() }
long() { return this.raw(8).readBigInt64BE() }
float() { return this.raw(4).readFloatBE() }
short() {
return this.raw(2).readInt16BE();
}
int() {
return this.raw(4).readInt32BE();
}
long() {
return this.raw(8).readBigInt64BE();
}
float() {
return this.raw(4).readFloatBE();
}
string() {
const len = this.short();
const str = this.raw(len).toString();
return str;
}
string() {
const len = this.short();
return this.raw(len).toString("utf8");
}
}
class Writer {
constructor(buffer) {
this.parts = [];
}
constructor() {
this.parts = [];
}
write(size, kind, value) {
const buf = Buffer.alloc(size);
buf[kind](value);
this.parts.push(buf);
}
write(size, kind, value) {
const buf = Buffer.alloc(size);
buf[kind](value);
this.parts.push(buf);
}
raw(bytes) {
this.parts.push(Buffer.from(bytes));
}
raw(bytes) {
const buf = Buffer.from(bytes);
this.parts.push(buf);
}
byte(val) {
this.write(1, "writeInt8", val);
}
byte(val) { this.write(1, "writeInt8", val) }
short(val) { this.write(2, "writeInt16BE", val) }
int(val) { this.write(4, "writeInt32BE", val) }
long(val) { this.write(8, "writeBigInt64BE", val) }
float(val) { this.write(4, "writeFloatBE", val) }
string(str) {
this.short(str.length);
this.raw(str);
}
short(val) {
this.write(2, "writeInt16BE", val);
}
int(val) {
this.write(4, "writeInt32BE", val);
}
long(val) {
this.write(8, "writeBigInt64BE", val);
}
float(val) {
this.write(4, "writeFloatBE", val);
}
string(str) {
this.short(str.length);
this.raw(str);
}
toBuffer() {
return Buffer.concat(this.parts);
}
toBuffer() {
return Buffer.concat(this.parts);
}
}
module.exports = { Reader, Writer };

View file

@ -1,26 +1,26 @@
const overflow = 65536;
class Position {
constructor(pos = 0) {
if (typeof pos === "object" && pos) {
this.x = pos.x;
this.y = pos.y;
} else {
this.y = pos % overflow;
this.x = Math.floor(pos / overflow);
}
}
constructor(pos = 0) {
if (typeof pos === "object" && pos) {
this.x = pos.x;
this.y = pos.y;
} else {
this.x = Math.floor(pos / overflow);
this.y = pos % overflow;
}
}
pack() {
return this.x * overflow + this.y;
}
pack() {
return this.x * overflow + this.y;
}
}
function capitalize(str) {
return str[0].toUpperCase() + str.slice(1).toLowerCase();
return str[0].toUpperCase() + str.slice(1).toLowerCase();
}
function err(why) {
throw new Error(why);
throw new Error(why);
}
module.exports = { Position, overflow, err, capitalize };

View file

@ -1,73 +1,88 @@
const { err, overflow, Position } = require("./misc.js");
const { getByName, Content } = require("../content/content.js");
module.exports = {
read(stream) {
const type = stream.byte();
switch (type) {
case 0:
return null;
case 1:
return stream.int();
case 2:
return stream.long();
case 3:
return stream.float();
case 4:
return stream.string();
case 5:
return getByName(stream.byte(), stream.short());
case 6:
const length = stream.short();
const arr = [];
for (let i = 0; i < length; i++) arr.push(stream.int());
return arr;
case 7:
return new Position({ x: stream.int(), y: stream.int() });
// case 8: byte len = read.b(); Point2[] out = new Point2[len]; for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i()); return out;
// case 9: return TechTree.getNotNull(content.getByID(ContentType.all[read.b()], read.s()));
// case 10: return read.bool();
// case 11: return read.d();
// case 12: return world.build(read.i());
// case 13: return LAccess.all[read.s()];
// case 14: int blen = read.i(); byte[] bytes = new byte[blen]; read.b(bytes); return bytes;
// case 15: return UnitCommand.all[read.b()];
default:
err(
`Unknown object type: ${type} (WIP, don't expect everything to work!)`
);
}
},
write(stream, thing) {
if (thing === null) {
stream.byte(0);
} else if (typeof thing === "number" && !isNaN(thing)) {
if (!Number.isInteger(thing)) {
stream.byte(3);
stream.float(thing);
} else if (thing > overflow) {
stream.byte(2);
stream.long(thing);
} else {
stream.byte(1);
stream.int(thing);
}
} else if (typeof thing === "string") {
stream.byte(4);
stream.string(thing);
} else if (thing instanceof Content) {
stream.byte(5);
stream.byte(thing.typeId);
stream.short(thing.id);
} else if (thing instanceof Array) {
stream.byte(6);
stream.short(thing.length);
for (let i of thing) stream.int(i);
} else if (thing instanceof Position) {
stream.byte(7);
stream.int(thing.x);
stream.int(thing.y);
} else {
err("can't pack");
}
},
};
function read(reader) {
const type = reader.byte();
switch (type) {
case 0: return null;
case 1: return reader.int();
case 2: return reader.long();
case 3: return reader.float();
case 4:
const exists = reader.byte();
if(exists === 0) return null;
return reader.string();
case 5:
return getByName(reader.byte(), reader.short());
case 6:
const len = reader.short();
const arr = [];
for (let i = 0; i < len; i++) arr.push(reader.int());
return arr;
case 7:
return new Position({ x: reader.int(), y: reader.int() });
case 8:
const plen = reader.byte();
const points = [];
for (let i = 0; i < plen; i++)
points.push(new Position(reader.int()));
return points;
case 14:
const blen = reader.int();
const slice = reader.raw(blen);
return slice;
case 15:
return ["attack", "rally", "idle"][reader.byte()];
default:
throw `Unknown object type: ${type}`;
}
}
function write(stream, thing) {
if (thing === null) {
stream.byte(0);
} else if (typeof thing === "number" && !isNaN(thing)) {
if (!Number.isInteger(thing)) {
stream.byte(3);
stream.float(thing);
} else if (thing > overflow) {
stream.byte(2);
stream.long(thing);
} else {
stream.byte(1);
stream.int(thing);
}
} else if (typeof thing === "string") {
stream.byte(4);
if(!thing.length) return stream.byte(0);
stream.byte(1);
stream.string(thing);
} else if (thing instanceof Content) {
stream.byte(5);
stream.byte(thing.typeId);
stream.short(thing.id);
} else if (thing instanceof Array) {
if (thing[0] instanceof Position) {
stream.byte(8);
stream.byte(thing.length);
for (let i of thing) stream.int(i.pack());
} else {
stream.byte(6);
stream.short(thing.length);
for (let i of thing) stream.int(i);
}
} else if (thing instanceof Position) {
stream.byte(7);
stream.int(thing.x);
stream.int(thing.y);
} else if (thing instanceof Buffer) {
stream.byte(14);
stream.int(thing.length);
stream.raw(thing);
} else {
throw "can't pack";
}
}
module.exports = { read, write };