@underpostnet/underpost 2.98.0 → 2.98.3
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/.vscode/settings.json +7 -8
- package/README.md +2 -2
- package/bin/build.js +21 -5
- package/bin/deploy.js +10 -0
- package/bin/file.js +2 -1
- package/bin/util.js +0 -17
- package/cli.md +2 -2
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +2 -2
- package/package.json +2 -4
- package/scripts/rocky-setup.sh +12 -39
- package/src/api/document/document.service.js +1 -1
- package/src/cli/cluster.js +5 -9
- package/src/cli/repository.js +9 -9
- package/src/cli/run.js +108 -106
- package/src/client/components/core/Content.js +54 -4
- package/src/client/components/core/FullScreen.js +202 -9
- package/src/client/components/core/Panel.js +91 -22
- package/src/client/components/core/PanelForm.js +5 -2
- package/src/client/components/core/Translate.js +8 -0
- package/src/client/components/core/VanillaJs.js +80 -29
- package/src/client/services/default/default.management.js +324 -136
- package/src/index.js +58 -20
- package/src/client/components/core/ObjectLayerEngine.js +0 -1520
- package/src/client/components/core/ObjectLayerEngineModal.js +0 -1245
- package/src/client/components/core/ObjectLayerEngineViewer.js +0 -880
- package/src/server/object-layer.js +0 -335
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Provides utilities and engine logic for processing and managing Cyberia Online's object layer assets (skins, floors, weapons, etc.).
|
|
3
|
-
* @module src/server/object-layer.js
|
|
4
|
-
* @namespace CyberiaObjectLayer
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import fs from 'fs-extra';
|
|
8
|
-
import { PNG } from 'pngjs';
|
|
9
|
-
import sharp from 'sharp';
|
|
10
|
-
import { Jimp, intToRGBA, rgbaToInt } from 'jimp';
|
|
11
|
-
|
|
12
|
-
import { range } from '../client/components/core/CommonJs.js';
|
|
13
|
-
import { random } from '../client/components/core/CommonJs.js';
|
|
14
|
-
import { loggerFactory } from '../server/logger.js';
|
|
15
|
-
|
|
16
|
-
const logger = loggerFactory(import.meta);
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @typedef {Object} ObjectLayerCallbackPayload
|
|
20
|
-
* @property {string} path - The full file path to the image.
|
|
21
|
-
* @property {string} objectLayerType - The type of object layer (e.g., 'skin', 'floor').
|
|
22
|
-
* @property {string} objectLayerId - The unique ID of the object layer asset.
|
|
23
|
-
* @property {string} direction - The direction folder name (e.g., '08', '12').
|
|
24
|
-
* @memberof CyberiaObjectLayer
|
|
25
|
-
* @property {string} frame - The frame file name.
|
|
26
|
-
*/
|
|
27
|
-
|
|
28
|
-
export class ObjectLayerEngine {
|
|
29
|
-
/**
|
|
30
|
-
* @memberof CyberiaObjectLayer
|
|
31
|
-
* @static
|
|
32
|
-
* @description Iterates through the directory structure of object layer PNG assets for a given type.
|
|
33
|
-
* @param {string} [objectLayerType='skin'] - The type of object layer to iterate over (e.g., 'skin', 'floor').
|
|
34
|
-
* @param {function(ObjectLayerCallbackPayload): Promise<void>} [callback=() => {}] - The async function to execute for each image file found.
|
|
35
|
-
* @returns {Promise<void>}
|
|
36
|
-
* @memberof CyberiaObjectLayer
|
|
37
|
-
*/
|
|
38
|
-
static async pngDirectoryIteratorByObjectLayerType(
|
|
39
|
-
objectLayerType = 'skin',
|
|
40
|
-
callback = ({ path, objectLayerType, objectLayerId, direction, frame }) => {},
|
|
41
|
-
) {
|
|
42
|
-
const assetRoot = `./src/client/public/cyberia/assets/${objectLayerType}`;
|
|
43
|
-
if (!fs.existsSync(assetRoot)) {
|
|
44
|
-
logger.warn(`Asset root not found for type: ${objectLayerType}`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
for (const objectLayerId of await fs.readdir(assetRoot)) {
|
|
49
|
-
const idPath = `${assetRoot}/${objectLayerId}`;
|
|
50
|
-
if (!fs.statSync(idPath).isDirectory()) continue;
|
|
51
|
-
|
|
52
|
-
for (const direction of await fs.readdir(idPath)) {
|
|
53
|
-
const dirFolder = `${idPath}/${direction}`;
|
|
54
|
-
if (!fs.statSync(dirFolder).isDirectory()) continue;
|
|
55
|
-
|
|
56
|
-
for (const frame of await fs.readdir(dirFolder)) {
|
|
57
|
-
const imageFilePath = `${dirFolder}/${frame}`;
|
|
58
|
-
await callback({ path: imageFilePath, objectLayerType, objectLayerId, direction, frame });
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @memberof CyberiaObjectLayer
|
|
66
|
-
* @static
|
|
67
|
-
* @description Asynchronously reads a PNG file and resolves with its raw bitmap data, width, and height.
|
|
68
|
-
* @param {string} filePath - The path to the PNG file.
|
|
69
|
-
* @returns {Promise<{width: number, height: number, data: Buffer} | {error: true, message: string}>} - The image data or an error object.
|
|
70
|
-
* @memberof CyberiaObjectLayer
|
|
71
|
-
*/
|
|
72
|
-
static readPngAsync(filePath) {
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
fs.createReadStream(filePath)
|
|
75
|
-
.pipe(new PNG())
|
|
76
|
-
.on('parsed', function () {
|
|
77
|
-
resolve({
|
|
78
|
-
width: this.width,
|
|
79
|
-
height: this.height,
|
|
80
|
-
data: Buffer.from(this.data),
|
|
81
|
-
});
|
|
82
|
-
})
|
|
83
|
-
.on('error', (error) => {
|
|
84
|
-
logger.error(`Error reading PNG file: ${filePath}`, error);
|
|
85
|
-
// Resolve with a specific error indicator instead of rejecting
|
|
86
|
-
resolve({ error: true, message: error.message });
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @memberof CyberiaObjectLayer
|
|
93
|
-
* @static
|
|
94
|
-
* @description Processes an image file (PNG or GIF) to generate a frame matrix and a color palette (map_color).
|
|
95
|
-
* It quantizes the image based on a factor derived from image height (mazeFactor).
|
|
96
|
-
* @param {string} path - The path to the image file.
|
|
97
|
-
* @param {Array<number[]>} [colors=[]] - The existing color palette array to append new colors to.
|
|
98
|
-
* @returns {Promise<{frame: number[][], colors: Array<number[]>}>} - The frame matrix and the updated color palette.
|
|
99
|
-
* @memberof CyberiaObjectLayer
|
|
100
|
-
*/
|
|
101
|
-
static async frameFactory(path, colors = []) {
|
|
102
|
-
const frame = [];
|
|
103
|
-
try {
|
|
104
|
-
let image;
|
|
105
|
-
|
|
106
|
-
if (path.endsWith('.gif')) {
|
|
107
|
-
image = await Jimp.read(path);
|
|
108
|
-
// remove gif file
|
|
109
|
-
fs.removeSync(path);
|
|
110
|
-
// save image replacing gif for png
|
|
111
|
-
const pngPath = path.replace('.gif', '.png');
|
|
112
|
-
await image.write(pngPath);
|
|
113
|
-
} else {
|
|
114
|
-
const png = await ObjectLayerEngine.readPngAsync(path);
|
|
115
|
-
if (png.error) {
|
|
116
|
-
throw new Error(`Failed to read PNG: ${png.message}`);
|
|
117
|
-
}
|
|
118
|
-
image = new Jimp(png);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const mazeFactor = parseInt(image.bitmap.height / 24);
|
|
122
|
-
let _y = -1;
|
|
123
|
-
for (const y of range(0, image.bitmap.height - 1)) {
|
|
124
|
-
if (y % mazeFactor === 0) {
|
|
125
|
-
_y++;
|
|
126
|
-
if (!frame[_y]) frame[_y] = [];
|
|
127
|
-
}
|
|
128
|
-
let _x = -1;
|
|
129
|
-
for (const x of range(0, image.bitmap.width - 1)) {
|
|
130
|
-
const rgba = Object.values(intToRGBA(image.getPixelColor(x, y)));
|
|
131
|
-
if (y % mazeFactor === 0 && x % mazeFactor === 0) {
|
|
132
|
-
_x++;
|
|
133
|
-
const indexColor = colors.findIndex(
|
|
134
|
-
(c) => c[0] === rgba[0] && c[1] === rgba[1] && c[2] === rgba[2] && c[3] === rgba[3],
|
|
135
|
-
);
|
|
136
|
-
if (indexColor === -1) {
|
|
137
|
-
colors.push(rgba);
|
|
138
|
-
frame[_y][_x] = colors.length - 1;
|
|
139
|
-
} else {
|
|
140
|
-
frame[_y][_x] = indexColor;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
} catch (error) {
|
|
146
|
-
logger.error(`Failed to process image ${path}:`, error);
|
|
147
|
-
}
|
|
148
|
-
return { frame, colors };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* @memberof CyberiaObjectLayer
|
|
153
|
-
* @static
|
|
154
|
-
* @description Converts a numerical folder direction (e.g., '08', '14') into an array of corresponding keyframe names (e.g., 'down_idle', 'left_walking').
|
|
155
|
-
* @param {string} direction - The numerical direction string.
|
|
156
|
-
* @returns {string[]} - An array of keyframe direction names.
|
|
157
|
-
* @memberof CyberiaObjectLayer
|
|
158
|
-
*/
|
|
159
|
-
static getKeyFramesDirectionsFromNumberFolderDirection(direction) {
|
|
160
|
-
let objectLayerFrameDirections = [];
|
|
161
|
-
|
|
162
|
-
switch (direction) {
|
|
163
|
-
case '08':
|
|
164
|
-
objectLayerFrameDirections = ['down_idle', 'none_idle', 'default_idle'];
|
|
165
|
-
break;
|
|
166
|
-
case '18':
|
|
167
|
-
objectLayerFrameDirections = ['down_walking'];
|
|
168
|
-
break;
|
|
169
|
-
case '02':
|
|
170
|
-
objectLayerFrameDirections = ['up_idle'];
|
|
171
|
-
break;
|
|
172
|
-
case '12':
|
|
173
|
-
objectLayerFrameDirections = ['up_walking'];
|
|
174
|
-
break;
|
|
175
|
-
case '04':
|
|
176
|
-
objectLayerFrameDirections = ['left_idle', 'up_left_idle', 'down_left_idle'];
|
|
177
|
-
break;
|
|
178
|
-
case '14':
|
|
179
|
-
objectLayerFrameDirections = ['left_walking', 'up_left_walking', 'down_left_walking'];
|
|
180
|
-
break;
|
|
181
|
-
case '06':
|
|
182
|
-
objectLayerFrameDirections = ['right_idle', 'up_right_idle', 'down_right_idle'];
|
|
183
|
-
break;
|
|
184
|
-
case '16':
|
|
185
|
-
objectLayerFrameDirections = ['right_walking', 'up_right_walking', 'down_right_walking'];
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return objectLayerFrameDirections;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* @memberof CyberiaObjectLayer
|
|
194
|
-
* @static
|
|
195
|
-
* @description Processes an image file through frameFactory and adds the resulting frame to the render data structure.
|
|
196
|
-
* Updates the color palette and pushes the frame to all keyframe directions corresponding to the given direction code.
|
|
197
|
-
* Initializes colors array, frames object, and direction arrays if they don't exist.
|
|
198
|
-
* @param {Object} renderData - The render data object containing frames and colors.
|
|
199
|
-
* @param {string} imagePath - The path to the image file to process.
|
|
200
|
-
* @param {string} directionCode - The numerical direction code (e.g., '08', '14').
|
|
201
|
-
* @returns {Promise<Object>} - The updated render data object.
|
|
202
|
-
* @memberof CyberiaObjectLayer
|
|
203
|
-
*/
|
|
204
|
-
static async processAndPushFrame(renderData, imagePath, directionCode) {
|
|
205
|
-
// Initialize colors array if it doesn't exist
|
|
206
|
-
if (!renderData.colors) {
|
|
207
|
-
renderData.colors = [];
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Initialize frames object if it doesn't exist
|
|
211
|
-
if (!renderData.frames) {
|
|
212
|
-
renderData.frames = {};
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Process the image and extract frame matrix and updated colors
|
|
216
|
-
const frameFactoryResult = await ObjectLayerEngine.frameFactory(imagePath, renderData.colors);
|
|
217
|
-
|
|
218
|
-
// Update the colors palette
|
|
219
|
-
renderData.colors = frameFactoryResult.colors;
|
|
220
|
-
|
|
221
|
-
// Get all keyframe directions for this direction code
|
|
222
|
-
const keyframeDirections = ObjectLayerEngine.getKeyFramesDirectionsFromNumberFolderDirection(directionCode);
|
|
223
|
-
|
|
224
|
-
// Push the frame to all corresponding directions
|
|
225
|
-
for (const keyframeDirection of keyframeDirections) {
|
|
226
|
-
if (!renderData.frames[keyframeDirection]) {
|
|
227
|
-
renderData.frames[keyframeDirection] = [];
|
|
228
|
-
}
|
|
229
|
-
renderData.frames[keyframeDirection].push(frameFactoryResult.frame);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return renderData;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* @memberof CyberiaObjectLayer
|
|
237
|
-
* @static
|
|
238
|
-
* @description Builds a PNG image file from a tile matrix and color map using Jimp and Sharp.
|
|
239
|
-
* @param {Object} options - Options object.
|
|
240
|
-
* @param {Object} options.tile - The tile data.
|
|
241
|
-
* @param {Array<number[]>} options.tile.map_color - The color palette.
|
|
242
|
-
* @param {number[][]} options.tile.frame_matrix - The matrix of color indices.
|
|
243
|
-
* @param {string} options.imagePath - The output path for the generated image.
|
|
244
|
-
* @param {number} [options.cellPixelDim=20] - The pixel dimension of each cell in the matrix.
|
|
245
|
-
* @param {function(number, number, number[]): number} [options.opacityFilter] - Function to filter opacity (ignored in this implementation).
|
|
246
|
-
* @returns {Promise<void>}
|
|
247
|
-
* @memberof CyberiaObjectLayer
|
|
248
|
-
*/
|
|
249
|
-
static async buildImgFromTile(
|
|
250
|
-
options = {
|
|
251
|
-
tile: { map_color: null, frame_matrix: null },
|
|
252
|
-
imagePath: '',
|
|
253
|
-
cellPixelDim: 20,
|
|
254
|
-
opacityFilter: (x, y, color) => 255,
|
|
255
|
-
},
|
|
256
|
-
) {
|
|
257
|
-
const { tile, imagePath, cellPixelDim } = options;
|
|
258
|
-
const mainMatrix = tile.frame_matrix;
|
|
259
|
-
if (!mainMatrix || mainMatrix.length === 0 || mainMatrix[0].length === 0) {
|
|
260
|
-
logger.error(`Cannot build image from empty or invalid frame_matrix for path: ${imagePath}`);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const sharpOptions = {
|
|
265
|
-
create: {
|
|
266
|
-
width: cellPixelDim * mainMatrix[0].length,
|
|
267
|
-
height: cellPixelDim * mainMatrix.length,
|
|
268
|
-
channels: 4,
|
|
269
|
-
background: { r: 0, g: 0, b: 0, alpha: 0 }, // transparent background
|
|
270
|
-
},
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
let image = await sharp(sharpOptions).png().toBuffer();
|
|
274
|
-
fs.writeFileSync(imagePath, image);
|
|
275
|
-
image = await Jimp.read(imagePath);
|
|
276
|
-
|
|
277
|
-
for (let y = 0; y < mainMatrix.length; y++) {
|
|
278
|
-
for (let x = 0; x < mainMatrix[y].length; x++) {
|
|
279
|
-
const colorIndex = mainMatrix[y][x];
|
|
280
|
-
if (colorIndex === null || colorIndex === undefined) continue;
|
|
281
|
-
|
|
282
|
-
const color = tile.map_color[colorIndex];
|
|
283
|
-
if (!color) continue;
|
|
284
|
-
|
|
285
|
-
const rgbaColor = color.length === 4 ? color : [...color, 255]; // Ensure alpha channel
|
|
286
|
-
|
|
287
|
-
for (let dy = 0; dy < cellPixelDim; dy++) {
|
|
288
|
-
for (let dx = 0; dx < cellPixelDim; dx++) {
|
|
289
|
-
const pixelX = x * cellPixelDim + dx;
|
|
290
|
-
const pixelY = y * cellPixelDim + dy;
|
|
291
|
-
image.setPixelColor(rgbaToInt(...rgbaColor), pixelX, pixelY);
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
await image.write(imagePath);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* @memberof CyberiaObjectLayer
|
|
302
|
-
* @static
|
|
303
|
-
* @description Generates a random set of character statistics for an item, with values between 0 and 10.
|
|
304
|
-
* @returns {{effect: number, resistance: number, agility: number, range: number, intelligence: number, utility: number}} - The random stats object.
|
|
305
|
-
* @memberof CyberiaObjectLayer
|
|
306
|
-
*/
|
|
307
|
-
static generateRandomStats() {
|
|
308
|
-
return {
|
|
309
|
-
effect: random(0, 10),
|
|
310
|
-
resistance: random(0, 10),
|
|
311
|
-
agility: random(0, 10),
|
|
312
|
-
range: random(0, 10),
|
|
313
|
-
intelligence: random(0, 10),
|
|
314
|
-
utility: random(0, 10),
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* @memberof CyberiaObjectLayer
|
|
321
|
-
* @constant
|
|
322
|
-
* @description Mapping of item type names to numerical IDs.
|
|
323
|
-
* @type {{floor: number, skin: number, weapon: number, skill: number, coin: number}}
|
|
324
|
-
*/
|
|
325
|
-
export const itemTypes = { floor: 0, skin: 1, weapon: 2, skill: 3, coin: 4 };
|
|
326
|
-
|
|
327
|
-
// Export equivalent for backward compatibility with existing destructured imports.
|
|
328
|
-
export const pngDirectoryIteratorByObjectLayerType = ObjectLayerEngine.pngDirectoryIteratorByObjectLayerType;
|
|
329
|
-
export const readPngAsync = ObjectLayerEngine.readPngAsync;
|
|
330
|
-
export const frameFactory = ObjectLayerEngine.frameFactory;
|
|
331
|
-
export const getKeyFramesDirectionsFromNumberFolderDirection =
|
|
332
|
-
ObjectLayerEngine.getKeyFramesDirectionsFromNumberFolderDirection;
|
|
333
|
-
export const processAndPushFrame = ObjectLayerEngine.processAndPushFrame;
|
|
334
|
-
export const buildImgFromTile = ObjectLayerEngine.buildImgFromTile;
|
|
335
|
-
export const generateRandomStats = ObjectLayerEngine.generateRandomStats;
|