feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39

Merged
min merged 215 commits from feat/lua-50-games-bundle into main 2026-06-09 21:59:25 +00:00
4 changed files with 40 additions and 22 deletions
Showing only changes of commit 936f93a42c - Show all commits

View File

@ -185,7 +185,12 @@ export class GameRuntime {
sb.setOnCommand(({ cmd, payload }) => { sb.setOnCommand(({ cmd, payload }) => {
if (cmd === 'partSet' || cmd === 'partVel' || if (cmd === 'partSet' || cmd === 'partVel' ||
cmd === 'sceneCreate' || cmd === 'sceneDelete') { cmd === 'sceneCreate' || cmd === 'sceneDelete') {
try { handleLuaCommand(null, cmd, payload, this); } catch (_) {} try {
handleLuaCommand(null, cmd, payload, this);
} catch (e) {
// eslint-disable-next-line no-console
console.error('[GameRuntime] handleLuaCommand failed:', cmd, payload, e);
}
} else { } else {
this._handleCommand(null, cmd, payload); this._handleCommand(null, cmd, payload);
} }

View File

@ -689,7 +689,16 @@ export class PrimitiveManager {
const data = this.instances.get(id); const data = this.instances.get(id);
if (!data) return; if (!data) return;
// Позиция // Позиция / поворот / размер — нужно расфризить world matrix,
// иначе freezeStaticPrimitives() сделает mesh.position.set бессмысленным.
const positionChanged = patch.x !== undefined || patch.y !== undefined || patch.z !== undefined;
const transformChanged = positionChanged
|| patch.rotationX !== undefined || patch.rotationY !== undefined || patch.rotationZ !== undefined
|| patch.sx !== undefined || patch.sy !== undefined || patch.sz !== undefined;
if (transformChanged && data._worldMatrixFrozen) {
try { data.mesh.unfreezeWorldMatrix?.(); } catch (_) {}
data._worldMatrixFrozen = false;
}
if (patch.x !== undefined) data.x = patch.x; if (patch.x !== undefined) data.x = patch.x;
if (patch.y !== undefined) data.y = patch.y; if (patch.y !== undefined) data.y = patch.y;
if (patch.z !== undefined) data.z = patch.z; if (patch.z !== undefined) data.z = patch.z;

View File

@ -279,7 +279,6 @@ function newPart(primData, sendFn) {
}; };
// Setter'ы шлют partSet → BabylonScene.primitiveManager через handleLuaCommand. // Setter'ы шлют partSet → BabylonScene.primitiveManager через handleLuaCommand.
// Формат payload должен соответствовать rbxl-lua-integration.js#handleLuaCommand.
const send = (prop, value) => { const send = (prop, value) => {
try { sendFn('partSet', { primId: p.__primId, prop, value }); } catch (_) {} try { sendFn('partSet', { primId: p.__primId, prop, value }); } catch (_) {}
}; };

View File

@ -122,29 +122,34 @@ export function handleLuaCommand(_scriptId, cmd, payload, runtime) {
return; return;
} }
if (cmd === 'partSet') { if (cmd === 'partSet') {
const pm = runtime.scene3d?.primitiveManager;
if (!pm) {
console.warn('[partSet] no primitiveManager. scene3d=', !!runtime.scene3d);
return;
}
const primId = payload?.primId;
const prop = payload?.prop;
const value = payload?.value;
const patch = {};
if (prop === 'position' && value) {
patch.x = value.x; patch.y = value.y; patch.z = value.z;
} else if (prop === 'cframe' && value) {
patch.x = value.x; patch.y = value.y; patch.z = value.z;
patch.rotationX = value.rx; patch.rotationY = value.ry; patch.rotationZ = value.rz;
} else if (prop === 'size' && value) {
patch.sx = value.sx; patch.sy = value.sy; patch.sz = value.sz;
} else if (prop === 'color') patch.color = value;
else if (prop === 'material') patch.material = value;
else if (prop === 'anchored') patch.anchored = value;
else if (prop === 'canCollide') patch.canCollide = value;
else if (prop === 'opacity') patch.opacity = value;
try { try {
const pm = runtime.scene3d?.primitiveManager;
if (!pm) return;
const primId = payload?.primId;
const prop = payload?.prop;
const value = payload?.value;
const patch = {};
if (prop === 'position' && value) {
patch.x = value.x; patch.y = value.y; patch.z = value.z;
} else if (prop === 'cframe' && value) {
patch.x = value.x; patch.y = value.y; patch.z = value.z;
patch.rotationX = value.rx; patch.rotationY = value.ry; patch.rotationZ = value.rz;
} else if (prop === 'size' && value) {
patch.sx = value.sx; patch.sy = value.sy; patch.sz = value.sz;
} else if (prop === 'color') patch.color = value;
else if (prop === 'material') patch.material = value;
else if (prop === 'anchored') patch.anchored = value;
else if (prop === 'canCollide') patch.canCollide = value;
else if (prop === 'opacity') patch.opacity = value;
if (typeof pm.updateInstance === 'function') pm.updateInstance(primId, patch); if (typeof pm.updateInstance === 'function') pm.updateInstance(primId, patch);
else if (typeof pm.applyPatch === 'function') pm.applyPatch(primId, patch); else if (typeof pm.applyPatch === 'function') pm.applyPatch(primId, patch);
else if (typeof pm.update === 'function') pm.update(primId, patch); else if (typeof pm.update === 'function') pm.update(primId, patch);
} catch (e) {} } catch (e) {
console.error('[partSet] updateInstance failed:', e);
}
return; return;
} }
if (cmd === 'sceneCreate') { if (cmd === 'sceneCreate') {