updated
This commit is contained in:
parent
94571943cf
commit
8ee6a87d44
7 changed files with 2317 additions and 560 deletions
|
|
@ -168,8 +168,20 @@
|
|||
return out;
|
||||
}
|
||||
|
||||
function normalizeEncodedPlane(value, size, emptyChar = '.') {
|
||||
const total = Math.max(1, Number(size) || 1) ** 2;
|
||||
function assetWidth(asset) {
|
||||
const size = Math.max(1, Number(asset?.size) || 16);
|
||||
return Math.max(1, Number(asset?.width ?? asset?.w ?? size) || size);
|
||||
}
|
||||
|
||||
function assetHeight(asset) {
|
||||
const size = Math.max(1, Number(asset?.size) || 16);
|
||||
return Math.max(1, Number(asset?.height ?? asset?.ht ?? size) || size);
|
||||
}
|
||||
|
||||
function normalizeEncodedPlane(value, width, emptyChar = '.', height = width) {
|
||||
const w = Math.max(1, Number(width) || 1);
|
||||
const h = Math.max(1, Number(height) || w);
|
||||
const total = w * h;
|
||||
const source = typeof value === 'string' ? value : Array.isArray(value) ? value.map((v) => v || emptyChar).join('') : '';
|
||||
return (source + emptyChar.repeat(total)).slice(0, total);
|
||||
}
|
||||
|
|
@ -184,15 +196,17 @@
|
|||
return best;
|
||||
}
|
||||
|
||||
function cropPlane(encoded, size, emptyChar = '.', options = {}) {
|
||||
const text = normalizeEncodedPlane(encoded, size, emptyChar);
|
||||
let minX = size;
|
||||
let minY = size;
|
||||
function cropPlane(encoded, width, emptyChar = '.', options = {}, height = width) {
|
||||
const w0 = Math.max(1, Number(width) || 1);
|
||||
const h0 = Math.max(1, Number(height) || w0);
|
||||
const text = normalizeEncodedPlane(encoded, w0, emptyChar, h0);
|
||||
let minX = w0;
|
||||
let minY = h0;
|
||||
let maxX = -1;
|
||||
let maxY = -1;
|
||||
for (let y = 0; y < size; y++) {
|
||||
for (let x = 0; x < size; x++) {
|
||||
if (text[y * size + x] !== emptyChar) {
|
||||
for (let y = 0; y < h0; y++) {
|
||||
for (let x = 0; x < w0; x++) {
|
||||
if (text[y * w0 + x] !== emptyChar) {
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x);
|
||||
|
|
@ -204,7 +218,7 @@
|
|||
const w = maxX - minX + 1;
|
||||
const h = maxY - minY + 1;
|
||||
let cropped = '';
|
||||
for (let y = minY; y <= maxY; y++) cropped += text.slice(y * size + minX, y * size + minX + w);
|
||||
for (let y = minY; y <= maxY; y++) cropped += text.slice(y * w0 + minX, y * w0 + minX + w);
|
||||
const candidates = [
|
||||
{ b: [minX, minY, w, h], e: 'raw', v: cropped },
|
||||
{ b: [minX, minY, w, h], e: 'rle', v: rleEncode(cropped) }
|
||||
|
|
@ -213,9 +227,15 @@
|
|||
return chooseSmallest(candidates);
|
||||
}
|
||||
|
||||
function expandPlane(packed, size, emptyChar = '.', baseEncoded = null) {
|
||||
const total = Math.max(1, Number(size) || 1) ** 2;
|
||||
function expandPlane(packed, width, emptyChar = '.', baseEncoded = null, height = width) {
|
||||
const w0 = Math.max(1, Number(width) || 1);
|
||||
const h0 = Math.max(1, Number(height) || w0);
|
||||
const total = w0 * h0;
|
||||
const out = Array(total).fill(emptyChar);
|
||||
if (baseEncoded) {
|
||||
const base = normalizeEncodedPlane(baseEncoded, w0, emptyChar, h0);
|
||||
for (let i = 0; i < Math.min(out.length, base.length); i++) out[i] = base[i] || emptyChar;
|
||||
}
|
||||
if (!packed || !packed.b) return out.join('');
|
||||
const [x0, y0, w, h] = packed.b.map((v) => Math.max(0, Number(v) || 0));
|
||||
let value = '';
|
||||
|
|
@ -227,27 +247,31 @@
|
|||
const src = y * w + x;
|
||||
const dx = x0 + x;
|
||||
const dy = y0 + y;
|
||||
if (dx >= 0 && dy >= 0 && dx < size && dy < size && src < value.length) out[dy * size + dx] = value[src] || emptyChar;
|
||||
if (dx >= 0 && dy >= 0 && dx < w0 && dy < h0 && src < value.length) out[dy * w0 + dx] = value[src] || emptyChar;
|
||||
}
|
||||
}
|
||||
return out.join('');
|
||||
}
|
||||
|
||||
function planeForAsset(asset) {
|
||||
const size = Math.max(1, Number(asset?.size) || 16);
|
||||
return normalizeEncodedPlane(asset?.faces?.right || asset?.pixels || '', size, '.');
|
||||
const w = assetWidth(asset);
|
||||
const h = assetHeight(asset);
|
||||
return normalizeEncodedPlane(asset?.faces?.right || asset?.pixels || '', w, '.', h);
|
||||
}
|
||||
|
||||
function selectPixelPlanePack(asset, assetMap) {
|
||||
const size = Math.max(1, Number(asset.size) || 16);
|
||||
const w = assetWidth(asset);
|
||||
const h = assetHeight(asset);
|
||||
const right = planeForAsset(asset);
|
||||
return cropPlane(right, size, '.', { bitPack: true });
|
||||
return cropPlane(right, w, '.', { bitPack: true }, h);
|
||||
}
|
||||
|
||||
function packAsset(asset, assetMap = null) {
|
||||
const size = Math.max(1, Number(asset.size) || 16);
|
||||
const width = assetWidth(asset);
|
||||
const height = assetHeight(asset);
|
||||
const size = Math.max(width, height, Math.max(1, Number(asset.size) || 16));
|
||||
const category = asset.category === 'dynamic' ? 'dynamic' : 'static';
|
||||
const depth = asset.meta?.depthPixels ? normalizeEncodedPlane(asset.meta.depthPixels, size, '.') : '';
|
||||
const depth = asset.meta?.depthPixels ? normalizeEncodedPlane(asset.meta.depthPixels, width, '.', height) : '';
|
||||
const lights = Array.isArray(asset.meta?.lightPixels)
|
||||
? asset.meta.lightPixels.map((p) => [Number(p.x) || 0, Number(p.y) || 0, p.c || asset.meta?.lightColor || '']).filter((p) => p[2])
|
||||
: [];
|
||||
|
|
@ -255,7 +279,7 @@
|
|||
? asset.meta.particlePixels.map((p) => [Number(p.x) || 0, Number(p.y) || 0, p.c || '', p.dir || 'up']).filter((p) => p[2])
|
||||
: [];
|
||||
const meta = {};
|
||||
if (depth && /[1\-]/.test(depth)) meta.d = cropPlane(depth, size, '.');
|
||||
if (depth && /[1\-]/.test(depth)) meta.d = cropPlane(depth, width, '.', {}, height);
|
||||
if (lights.length) meta.l = lights;
|
||||
if (particles.length) meta.pt = particles;
|
||||
if (asset.meta?.lightColor) meta.lc = asset.meta.lightColor;
|
||||
|
|
@ -272,6 +296,8 @@
|
|||
c: category,
|
||||
t: asset.subtype || (category === 'dynamic' ? 'human' : 'other'),
|
||||
s: size,
|
||||
w: width !== size ? width : undefined,
|
||||
ht: height !== size ? height : undefined,
|
||||
p: selectPixelPlanePack(asset, assetMap),
|
||||
f: category === 'dynamic' ? { l: 'mirror' } : null,
|
||||
pa: asset.parentAssetId || null,
|
||||
|
|
@ -279,6 +305,8 @@
|
|||
ca: asset.createdAt || Date.now(),
|
||||
ua: asset.updatedAt || asset.createdAt || Date.now(),
|
||||
au: asset.author || 'Local Artist',
|
||||
ow: asset.ownerAccountId || null,
|
||||
v: Number(asset.version) || 1,
|
||||
m: Object.keys(meta).length ? meta : null
|
||||
};
|
||||
}
|
||||
|
|
@ -286,8 +314,10 @@
|
|||
function unpackAsset(packed, assetById = null) {
|
||||
if (!packed || !packed.id) return null;
|
||||
const size = Math.max(1, Number(packed.s || packed.size) || 16);
|
||||
const width = Math.max(1, Number(packed.w || packed.width || size) || size);
|
||||
const height = Math.max(1, Number(packed.ht || packed.height || size) || size);
|
||||
const category = packed.c === 'dynamic' || packed.category === 'dynamic' ? 'dynamic' : 'static';
|
||||
const pixels = expandPlane(packed.p, size, '.');
|
||||
const pixels = expandPlane(packed.p, width, '.', null, height);
|
||||
if (pixels == null) return null;
|
||||
const metaPacked = packed.m || {};
|
||||
const lightPixels = Array.isArray(metaPacked.l)
|
||||
|
|
@ -306,7 +336,7 @@
|
|||
hasParticles: Boolean(particleConfig) || particlePixels.length > 0,
|
||||
particlePixels,
|
||||
particleConfig,
|
||||
depthPixels: metaPacked.d ? expandPlane(metaPacked.d, size, '.') : null,
|
||||
depthPixels: metaPacked.d ? expandPlane(metaPacked.d, width, '.', null, height) : null,
|
||||
door: Array.isArray(metaPacked.dr) ? { x: Number(metaPacked.dr[0]) || 0, y: Number(metaPacked.dr[1]) || 0 } : null
|
||||
};
|
||||
return {
|
||||
|
|
@ -315,6 +345,8 @@
|
|||
category,
|
||||
subtype: packed.t || (category === 'dynamic' ? 'human' : 'other'),
|
||||
size,
|
||||
width,
|
||||
height,
|
||||
pixels,
|
||||
faces: category === 'dynamic' ? { right: pixels, left: 'mirror' } : null,
|
||||
parentAssetId: packed.pa || null,
|
||||
|
|
@ -322,6 +354,8 @@
|
|||
createdAt: packed.ca || Date.now(),
|
||||
updatedAt: packed.ua || packed.ca || Date.now(),
|
||||
author: packed.au || 'Local Artist',
|
||||
ownerAccountId: packed.ow || packed.ownerAccountId || '',
|
||||
version: Number(packed.v || packed.version) || 1,
|
||||
meta,
|
||||
contentHash: packed.h || null
|
||||
};
|
||||
|
|
@ -335,26 +369,28 @@
|
|||
const meta = {};
|
||||
if (item.publishedAt) meta.pu = item.publishedAt;
|
||||
if (item.status && item.status !== 'active') meta.st = item.status;
|
||||
if (item.ownerAccountId) meta.ow = item.ownerAccountId;
|
||||
return [item.id, item.assetId, Number(item.x) || 0, Number(item.y) || 0, item.placedAt || Date.now(), Number(item.version) || 1, Object.keys(meta).length ? meta : null];
|
||||
}
|
||||
|
||||
function unpackPlacement(row) {
|
||||
if (!Array.isArray(row)) return row;
|
||||
const meta = row[6] || {};
|
||||
return { id: row[0], assetId: row[1], x: row[2], y: row[3], placedAt: row[4], version: row[5] || 1, publishedAt: meta.pu || row[4], status: meta.st || 'active' };
|
||||
return { id: row[0], assetId: row[1], x: row[2], y: row[3], placedAt: row[4], version: row[5] || 1, publishedAt: meta.pu || row[4], status: meta.st || 'active', ownerAccountId: meta.ow || '' };
|
||||
}
|
||||
|
||||
function packDynamic(item) {
|
||||
const meta = {};
|
||||
if (item.publishedAt) meta.pu = item.publishedAt;
|
||||
if (item.status && item.status !== 'active') meta.st = item.status;
|
||||
if (item.ownerAccountId) meta.ow = item.ownerAccountId;
|
||||
return [item.id, item.assetId, Number(item.homeX) || 0, Number(item.homeY) || 0, item.createdAt || Date.now(), Number(item.version) || 1, Object.keys(meta).length ? meta : null];
|
||||
}
|
||||
|
||||
function unpackDynamic(row) {
|
||||
if (!Array.isArray(row)) return row;
|
||||
const meta = row[6] || {};
|
||||
return { id: row[0], assetId: row[1], homeX: row[2], homeY: row[3], createdAt: row[4], version: row[5] || 1, publishedAt: meta.pu || row[4], status: meta.st || 'active' };
|
||||
return { id: row[0], assetId: row[1], homeX: row[2], homeY: row[3], createdAt: row[4], version: row[5] || 1, publishedAt: meta.pu || row[4], status: meta.st || 'active', ownerAccountId: meta.ow || '' };
|
||||
}
|
||||
|
||||
function assetMapFor(assets) {
|
||||
|
|
@ -381,7 +417,10 @@
|
|||
account: state.account || null,
|
||||
publishLog: Array.isArray(state.publishLog) ? state.publishLog.slice(-300) : [],
|
||||
eventLog: Array.isArray(state.eventLog) ? state.eventLog.slice(-EVENT_LOG_LIMIT) : [],
|
||||
sync: state.sync || { lastEventId: null }
|
||||
sync: state.sync || { lastEventId: null },
|
||||
worldMode: state.worldMode === 'shared' ? 'shared' : 'local',
|
||||
serverSync: state.serverSync || { lastServerEventId: null, pendingCommands: [] },
|
||||
tombstones: state.tombstones || { assets: {}, objects: {} }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -403,7 +442,10 @@
|
|||
account: input.account || null,
|
||||
publishLog: Array.isArray(input.publishLog) ? input.publishLog.slice(-300) : [],
|
||||
eventLog: Array.isArray(input.eventLog) ? input.eventLog.slice(-EVENT_LOG_LIMIT) : [],
|
||||
sync: input.sync || { lastEventId: null }
|
||||
sync: input.sync || { lastEventId: null },
|
||||
worldMode: input.worldMode === 'shared' ? 'shared' : 'local',
|
||||
serverSync: input.serverSync || { lastServerEventId: null, pendingCommands: [] },
|
||||
tombstones: input.tombstones || { assets: {}, objects: {} }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -421,7 +463,7 @@
|
|||
}
|
||||
|
||||
function assetManifest(state) {
|
||||
return (state.assets || []).map((asset) => ({ id: asset.id, h: asset.contentHash || null, s: asset.size, c: asset.category, t: asset.subtype, pa: asset.parentAssetId || null, oa: asset.originalAssetId || null }));
|
||||
return (state.assets || []).map((asset) => ({ id: asset.id, h: asset.contentHash || null, s: asset.size, w: asset.width || null, ht: asset.height || null, c: asset.category, t: asset.subtype, pa: asset.parentAssetId || null, oa: asset.originalAssetId || null }));
|
||||
}
|
||||
|
||||
function makeSnapshot(state, worldId = 'local-main') {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue