@pixelvibing/cli 0.71.0 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pixel-vibing-cli.js +211 -5
- package/package.json +1 -1
package/dist/pixel-vibing-cli.js
CHANGED
|
@@ -3456,6 +3456,11 @@ function numbers(args, names) {
|
|
|
3456
3456
|
return read;
|
|
3457
3457
|
}
|
|
3458
3458
|
const mapShow = reading("map show", "Print the linked project's map outline: its revision, size, levels and the sectors they hold", "/map");
|
|
3459
|
+
const mapObjects = reading(
|
|
3460
|
+
"map objects",
|
|
3461
|
+
"Print the linked project's map's named points and areas, with their types and properties (specs/ide-map-editor/ R2.1)",
|
|
3462
|
+
"/map/objects"
|
|
3463
|
+
);
|
|
3459
3464
|
const mapVersions = reading(
|
|
3460
3465
|
"map versions",
|
|
3461
3466
|
"Print the version of each sector a level of the linked project's map holds",
|
|
@@ -4080,6 +4085,188 @@ function packSheets(items, side = SHEET_SIDE, gap = SHEET_GAP) {
|
|
|
4080
4085
|
placements: placements.sort(byName$1)
|
|
4081
4086
|
};
|
|
4082
4087
|
}
|
|
4088
|
+
const TILED_MAP = "map.tiled.json";
|
|
4089
|
+
const TILES_IMAGE = "tiles.png";
|
|
4090
|
+
const BLOCKING_IMAGE = "blocking.png";
|
|
4091
|
+
const propertyOf = (name, value) => ({
|
|
4092
|
+
name,
|
|
4093
|
+
type: typeof value === "boolean" ? "bool" : typeof value === "number" ? Number.isInteger(value) ? "int" : "float" : "string",
|
|
4094
|
+
value
|
|
4095
|
+
});
|
|
4096
|
+
const plainTile = (sprite) => sprite.width === TILE_SIZE && sprite.height === TILE_SIZE && sprite.animation === null && sprite.x === sprite.tile[0] * TILE_SIZE && sprite.y === sprite.tile[1] * TILE_SIZE;
|
|
4097
|
+
function tiledMap(input, codec2) {
|
|
4098
|
+
const { width, height } = input;
|
|
4099
|
+
const tileNames = [...new Set(input.sprites.filter(plainTile).map((sprite) => sprite.frame))].filter((name) => input.rasters.has(name)).sort();
|
|
4100
|
+
const columns = Math.max(1, Math.ceil(Math.sqrt(tileNames.length)));
|
|
4101
|
+
const rows = Math.max(1, Math.ceil(tileNames.length / columns));
|
|
4102
|
+
const sheet = blank(columns * TILE_SIZE, rows * TILE_SIZE);
|
|
4103
|
+
tileNames.forEach((name, index) => {
|
|
4104
|
+
const raster = input.rasters.get(name);
|
|
4105
|
+
const left = index % columns * TILE_SIZE;
|
|
4106
|
+
const top = Math.floor(index / columns) * TILE_SIZE;
|
|
4107
|
+
for (let y = 0; y < TILE_SIZE; y += 1)
|
|
4108
|
+
sheet.data.set(raster.data.subarray(y * TILE_SIZE * 4, (y + 1) * TILE_SIZE * 4), ((top + y) * sheet.width + left) * 4);
|
|
4109
|
+
});
|
|
4110
|
+
const gidOf = new Map(tileNames.map((name, index) => [name, index + 1]));
|
|
4111
|
+
const blockingGid = tileNames.length + 1;
|
|
4112
|
+
const mark = blank(TILE_SIZE, TILE_SIZE);
|
|
4113
|
+
for (let at = 0; at < mark.data.length; at += 4) mark.data.set([220, 40, 40, 128], at);
|
|
4114
|
+
const levels = [
|
|
4115
|
+
.../* @__PURE__ */ new Set([...input.sprites.map((each) => each.level), ...input.blocking.map((each) => each.level), ...input.places.map((each) => each.level)])
|
|
4116
|
+
].sort((a, b) => a - b);
|
|
4117
|
+
let nextLayer = 1;
|
|
4118
|
+
let nextObject = 1;
|
|
4119
|
+
const layerPaths = [];
|
|
4120
|
+
const groups = levels.map((level) => {
|
|
4121
|
+
const group = `level-${level}`;
|
|
4122
|
+
const bands = /* @__PURE__ */ new Map();
|
|
4123
|
+
for (const sprite of input.sprites) {
|
|
4124
|
+
if (sprite.level !== level || !plainTile(sprite) || !gidOf.has(sprite.frame)) continue;
|
|
4125
|
+
const [x, y] = sprite.tile;
|
|
4126
|
+
if (x < 0 || y < 0 || x >= width || y >= height) continue;
|
|
4127
|
+
const stack = bands.get(sprite.layer) ?? [];
|
|
4128
|
+
bands.set(sprite.layer, stack);
|
|
4129
|
+
const index = y * width + x;
|
|
4130
|
+
let data = stack.find((layer) => layer[index] === 0);
|
|
4131
|
+
if (data === void 0) {
|
|
4132
|
+
data = new Array(width * height).fill(0);
|
|
4133
|
+
stack.push(data);
|
|
4134
|
+
}
|
|
4135
|
+
data[index] = gidOf.get(sprite.frame);
|
|
4136
|
+
}
|
|
4137
|
+
const tileLayers = [...bands].flatMap(
|
|
4138
|
+
([band, stack]) => stack.map((data, index) => {
|
|
4139
|
+
const name = index === 0 ? band : `${band}-${index + 1}`;
|
|
4140
|
+
layerPaths.push(`${group}/${name}`);
|
|
4141
|
+
return { id: nextLayer++, name, type: "tilelayer", x: 0, y: 0, width, height, opacity: 1, visible: true, data };
|
|
4142
|
+
})
|
|
4143
|
+
);
|
|
4144
|
+
const blocking = new Array(width * height).fill(0);
|
|
4145
|
+
for (const cell of input.blocking)
|
|
4146
|
+
if (cell.level === level && cell.x >= 0 && cell.y >= 0 && cell.x < width && cell.y < height) blocking[cell.y * width + cell.x] = blockingGid;
|
|
4147
|
+
layerPaths.push(`${group}/blocking`);
|
|
4148
|
+
const objects = [
|
|
4149
|
+
...input.sprites.filter((sprite) => sprite.level === level && !plainTile(sprite)).map((sprite) => ({
|
|
4150
|
+
id: nextObject++,
|
|
4151
|
+
name: sprite.frame,
|
|
4152
|
+
type: "sprite",
|
|
4153
|
+
x: sprite.x,
|
|
4154
|
+
y: sprite.y,
|
|
4155
|
+
width: 0,
|
|
4156
|
+
height: 0,
|
|
4157
|
+
rotation: 0,
|
|
4158
|
+
visible: true,
|
|
4159
|
+
point: true,
|
|
4160
|
+
properties: [
|
|
4161
|
+
propertyOf("frame", sprite.frame),
|
|
4162
|
+
...sprite.animation === null ? [] : [propertyOf("animation", sprite.animation)],
|
|
4163
|
+
propertyOf("width", sprite.width),
|
|
4164
|
+
propertyOf("height", sprite.height),
|
|
4165
|
+
propertyOf("band", sprite.layer)
|
|
4166
|
+
]
|
|
4167
|
+
})),
|
|
4168
|
+
...input.places.filter((place) => place.level === level).map((place) => ({
|
|
4169
|
+
id: nextObject++,
|
|
4170
|
+
name: place.name,
|
|
4171
|
+
type: place.type,
|
|
4172
|
+
x: place.x,
|
|
4173
|
+
y: place.y,
|
|
4174
|
+
width: place.kind === "area" ? place.width : 0,
|
|
4175
|
+
height: place.kind === "area" ? place.height : 0,
|
|
4176
|
+
rotation: 0,
|
|
4177
|
+
visible: true,
|
|
4178
|
+
...place.kind === "point" ? { point: true } : {},
|
|
4179
|
+
properties: Object.entries(place.properties).map(([name, value]) => propertyOf(name, value))
|
|
4180
|
+
}))
|
|
4181
|
+
];
|
|
4182
|
+
layerPaths.push(`${group}/objects`);
|
|
4183
|
+
return {
|
|
4184
|
+
id: nextLayer++,
|
|
4185
|
+
name: group,
|
|
4186
|
+
type: "group",
|
|
4187
|
+
x: 0,
|
|
4188
|
+
y: 0,
|
|
4189
|
+
opacity: 1,
|
|
4190
|
+
visible: true,
|
|
4191
|
+
layers: [
|
|
4192
|
+
...tileLayers,
|
|
4193
|
+
{ id: nextLayer++, name: "blocking", type: "tilelayer", x: 0, y: 0, width, height, opacity: 0.5, visible: false, data: blocking },
|
|
4194
|
+
{ id: nextLayer++, name: "objects", type: "objectgroup", x: 0, y: 0, opacity: 1, visible: true, draworder: "topdown", objects }
|
|
4195
|
+
]
|
|
4196
|
+
};
|
|
4197
|
+
});
|
|
4198
|
+
const map = {
|
|
4199
|
+
type: "map",
|
|
4200
|
+
version: "1.10",
|
|
4201
|
+
tiledversion: "1.12.0",
|
|
4202
|
+
orientation: "orthogonal",
|
|
4203
|
+
renderorder: "right-down",
|
|
4204
|
+
infinite: false,
|
|
4205
|
+
compressionlevel: -1,
|
|
4206
|
+
width,
|
|
4207
|
+
height,
|
|
4208
|
+
tilewidth: TILE_SIZE,
|
|
4209
|
+
tileheight: TILE_SIZE,
|
|
4210
|
+
nextlayerid: nextLayer,
|
|
4211
|
+
nextobjectid: nextObject,
|
|
4212
|
+
layers: groups,
|
|
4213
|
+
tilesets: [
|
|
4214
|
+
{
|
|
4215
|
+
firstgid: 1,
|
|
4216
|
+
name: "tiles",
|
|
4217
|
+
image: TILES_IMAGE,
|
|
4218
|
+
imagewidth: sheet.width,
|
|
4219
|
+
imageheight: sheet.height,
|
|
4220
|
+
tilewidth: TILE_SIZE,
|
|
4221
|
+
tileheight: TILE_SIZE,
|
|
4222
|
+
tilecount: tileNames.length,
|
|
4223
|
+
columns,
|
|
4224
|
+
margin: 0,
|
|
4225
|
+
spacing: 0,
|
|
4226
|
+
// Each tile's asset name, so the game and Tiled both say what a tile is.
|
|
4227
|
+
tiles: tileNames.map((name, id2) => ({ id: id2, properties: [propertyOf("asset", name)] }))
|
|
4228
|
+
},
|
|
4229
|
+
{
|
|
4230
|
+
firstgid: blockingGid,
|
|
4231
|
+
name: "blocking",
|
|
4232
|
+
image: BLOCKING_IMAGE,
|
|
4233
|
+
imagewidth: TILE_SIZE,
|
|
4234
|
+
imageheight: TILE_SIZE,
|
|
4235
|
+
tilewidth: TILE_SIZE,
|
|
4236
|
+
tileheight: TILE_SIZE,
|
|
4237
|
+
tilecount: 1,
|
|
4238
|
+
columns: 1,
|
|
4239
|
+
margin: 0,
|
|
4240
|
+
spacing: 0
|
|
4241
|
+
}
|
|
4242
|
+
]
|
|
4243
|
+
};
|
|
4244
|
+
const typesOf = (kind) => [...new Set(input.places.filter((place) => place.kind === kind).map((place) => place.type))].sort();
|
|
4245
|
+
return {
|
|
4246
|
+
files: [
|
|
4247
|
+
{ path: TILED_MAP, bytes: new TextEncoder().encode(`${JSON.stringify(map, null, 2)}
|
|
4248
|
+
`) },
|
|
4249
|
+
{ path: TILES_IMAGE, bytes: codec2.encodePng(sheet) },
|
|
4250
|
+
{ path: BLOCKING_IMAGE, bytes: codec2.encodePng(mark) }
|
|
4251
|
+
],
|
|
4252
|
+
layers: layerPaths,
|
|
4253
|
+
pointTypes: typesOf("point"),
|
|
4254
|
+
areaTypes: typesOf("area")
|
|
4255
|
+
};
|
|
4256
|
+
}
|
|
4257
|
+
function mapNames(output) {
|
|
4258
|
+
const list2 = (values) => `[${values.map((value) => JSON.stringify(value)).join(", ")}]`;
|
|
4259
|
+
return [
|
|
4260
|
+
"// Written by PixelVibing's export with the map: the names its layers, points and areas have.",
|
|
4261
|
+
`export const MAP_LAYERS = ${list2(output.layers)} as const;`,
|
|
4262
|
+
"export type MapLayer = (typeof MAP_LAYERS)[number];",
|
|
4263
|
+
`export const POINT_TYPES = ${list2(output.pointTypes)} as const;`,
|
|
4264
|
+
"export type PointType = (typeof POINT_TYPES)[number];",
|
|
4265
|
+
`export const AREA_TYPES = ${list2(output.areaTypes)} as const;`,
|
|
4266
|
+
"export type AreaType = (typeof AREA_TYPES)[number];",
|
|
4267
|
+
""
|
|
4268
|
+
].join("\n");
|
|
4269
|
+
}
|
|
4083
4270
|
const ENGINES = ["default", "pixi", "phaser", "godot"];
|
|
4084
4271
|
const EXPORT_FORMAT = 1;
|
|
4085
4272
|
const DEFAULT_GODOT_ROOT = "res://pixelvibing/";
|
|
@@ -4302,10 +4489,27 @@ function phaserFiles(made) {
|
|
|
4302
4489
|
return [
|
|
4303
4490
|
json("atlas.json", atlas),
|
|
4304
4491
|
json("animations.json", anims),
|
|
4492
|
+
// The placed sprites, for a game written before the Tiled map (specs/ide-map-editor/ R3.5).
|
|
4305
4493
|
json("map.json", defaultMap(made)),
|
|
4306
|
-
...made.nineGrids.size === 0 ? [] : [json("nine-slices.json", { format: EXPORT_FORMAT, atlas: PHASER_ATLAS_KEY, frames: nineSlices })]
|
|
4494
|
+
...made.nineGrids.size === 0 ? [] : [json("nine-slices.json", { format: EXPORT_FORMAT, atlas: PHASER_ATLAS_KEY, frames: nineSlices })],
|
|
4495
|
+
...tiledFiles(made)
|
|
4307
4496
|
];
|
|
4308
4497
|
}
|
|
4498
|
+
function tiledFiles(made) {
|
|
4499
|
+
if (made.map === null) return [];
|
|
4500
|
+
const output = tiledMap(
|
|
4501
|
+
{
|
|
4502
|
+
width: made.map.width,
|
|
4503
|
+
height: made.map.height,
|
|
4504
|
+
sprites: made.sprites,
|
|
4505
|
+
blocking: made.map.tiles.filter((tile) => tile.blocking !== 0).map((tile) => ({ x: tile.x, y: tile.y, level: tile.z })),
|
|
4506
|
+
rasters: made.rasters,
|
|
4507
|
+
places: made.places
|
|
4508
|
+
},
|
|
4509
|
+
made.codec
|
|
4510
|
+
);
|
|
4511
|
+
return [...output.files, text("map-names.ts", mapNames(output))];
|
|
4512
|
+
}
|
|
4309
4513
|
const godotString = (value) => JSON.stringify(value);
|
|
4310
4514
|
const number = (value) => Number.isInteger(value) ? `${value}` : `${Number(value.toFixed(6))}`;
|
|
4311
4515
|
const rect = (placed) => `Rect2(${placed.x}, ${placed.y}, ${placed.width}, ${placed.height})`;
|
|
@@ -4457,7 +4661,7 @@ function exportProject(input, engine, codec2, options = {}) {
|
|
|
4457
4661
|
const animations = animationsOf(metadata, rasters, omitted);
|
|
4458
4662
|
const sprites = placedSprites(input, metadata, rasters, omitted);
|
|
4459
4663
|
const sheets = sheetsOf(rasters, codec2);
|
|
4460
|
-
const made = { sheets, animations, sprites, map: input.map, nineGrids: nineGridsOf(metadata, rasters) };
|
|
4664
|
+
const made = { sheets, animations, sprites, map: input.map, nineGrids: nineGridsOf(metadata, rasters), rasters, places: input.places ?? [], codec: codec2 };
|
|
4461
4665
|
const godotRoot = options.godotRoot ?? DEFAULT_GODOT_ROOT;
|
|
4462
4666
|
const described = engine === "default" ? defaultFiles(made) : engine === "pixi" ? pixiFiles(made) : engine === "phaser" ? phaserFiles(made) : godotFiles(made, godotRoot.endsWith("/") ? godotRoot : `${godotRoot}/`);
|
|
4463
4667
|
return {
|
|
@@ -4642,7 +4846,7 @@ async function exportFolder(art, engine, options = {}) {
|
|
|
4642
4846
|
try {
|
|
4643
4847
|
const boundary = new Boundary([art]);
|
|
4644
4848
|
const read = await readProjectArt(boundary, art);
|
|
4645
|
-
const mirrored2 = await readMirroredProjectMap(boundary, art);
|
|
4849
|
+
const mirrored2 = options.map ?? await readMirroredProjectMap(boundary, art);
|
|
4646
4850
|
const mapText = mirrored2 === null ? await readProjectMap(boundary, art) : null;
|
|
4647
4851
|
checkExportable(
|
|
4648
4852
|
read.pictures.map((picture) => {
|
|
@@ -4662,7 +4866,8 @@ async function exportFolder(art, engine, options = {}) {
|
|
|
4662
4866
|
pictures,
|
|
4663
4867
|
entries: read.entries,
|
|
4664
4868
|
map: mirrored2 ?? (mapText === null ? null : parseMapText(mapText, "pixelvibing/map.json").document),
|
|
4665
|
-
idMap: read.idMap === null ? null : parseIdMap(JSON.parse(read.idMap))
|
|
4869
|
+
idMap: read.idMap === null ? null : parseIdMap(JSON.parse(read.idMap)),
|
|
4870
|
+
...options.places === void 0 ? {} : { places: options.places }
|
|
4666
4871
|
},
|
|
4667
4872
|
engine,
|
|
4668
4873
|
codec$1,
|
|
@@ -7506,7 +7711,7 @@ function terminalOf(streams) {
|
|
|
7506
7711
|
step: (title, at = "step") => drawStep(streams.stderr, title, at)
|
|
7507
7712
|
};
|
|
7508
7713
|
}
|
|
7509
|
-
const version = "0.
|
|
7714
|
+
const version = "0.73.0";
|
|
7510
7715
|
const manifest = {
|
|
7511
7716
|
version
|
|
7512
7717
|
};
|
|
@@ -7562,6 +7767,7 @@ const COMMANDS = [
|
|
|
7562
7767
|
artTileset,
|
|
7563
7768
|
artDraft,
|
|
7564
7769
|
mapShow,
|
|
7770
|
+
mapObjects,
|
|
7565
7771
|
mapVersions,
|
|
7566
7772
|
mapSectors,
|
|
7567
7773
|
mapWrite,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelvibing/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.73.0",
|
|
4
4
|
"description": "PixelVibing: pixel art game assets from the command line, and the Skills that teach coding assistants to make them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://pixelvibing.com",
|