fix(lua): __rbxl_player_pos возвращает реальную позицию игрока

Проблема: __rbxl_player_pos() возвращал (0,8,0) — нач. позицию hrp._position,
которая не обновлялась. Конфетти всегда вылетали из стартовой точки.

Фикс:
- api._realPlayerPos обновляется в GameRuntime tick (каждый кадр)
  через api.updatePlayerPos(x, y, z) из player.body.position.
- __rbxl_player_pos() в Lua возвращает api._realPlayerPos если есть.

Убраны debug-логи.
This commit is contained in:
min 2026-06-09 13:01:45 +03:00
parent 6fe249033e
commit 8321a526cd
3 changed files with 27 additions and 11 deletions

View File

@ -170,7 +170,7 @@ finishEvent.Event:Connect(function()
won = true
winSound:Play()
__rbxl_show_text("Победа! Ты дошёл до финиша!", 5)
-- Конфетти над игроком (как JS game.scene.spawnParticles)
-- Конфетти над игроком (паритет с JS game.scene.spawnParticles)
local pos = __rbxl_player_pos()
__rbxl_spawn_particles("confetti", pos.x, pos.y + 3, pos.z, 3, 3)
end)`,

View File

@ -326,10 +326,6 @@ export class GameRuntime {
}
} catch (_) {}
} else {
if (cmd === 'scene.particles' || cmd === 'ui.showText') {
// eslint-disable-next-line no-console
console.warn('[Lua onCommand]', cmd, JSON.stringify(payload));
}
this._handleCommand(null, cmd, payload);
}
});
@ -960,7 +956,20 @@ export class GameRuntime {
this._syncPhysicsToScene();
}
const state = this._collectState();
// Реальная позиция игрока для Lua __rbxl_player_pos()
const player = this.scene3d?.player;
let realPos = null;
if (player?.body?.position) {
const p = player.body.position;
realPos = { x: p.x, y: p.y, z: p.z };
} else if (state?.player) {
realPos = { x: state.player.x, y: state.player.y, z: state.player.z };
}
for (const sb of this.sandboxes) {
// Обновляем реальную позицию игрока для Lua-shim
if (realPos && sb.api?.updatePlayerPos) {
try { sb.api.updatePlayerPos(realPos.x, realPos.y, realPos.z); } catch (_) {}
}
// Для скриптов с target — добавляем актуальную позицию self
const stateForSb = sb.target
? { ...state, selfPosition: this._collectSelfPosition(sb.target) }
@ -4872,8 +4881,6 @@ export class GameRuntime {
* Делегирует в BabylonScene._spawnParticleEffect, который знает о Babylon.
*/
_spawnParticles(payload) {
// eslint-disable-next-line no-console
console.warn('[_spawnParticles] called with:', JSON.stringify(payload), 'scene3d=', !!this.scene3d, 'fn=', !!this.scene3d?._spawnParticleEffect);
if (!payload || !this.scene3d?._spawnParticleEffect) return;
try {
this.scene3d._spawnParticleEffect(payload);

View File

@ -1827,10 +1827,11 @@ export function registerRobloxShim(lua, opts) {
});
});
// Позиция игрока для удобства (для confetti над головой и т.п.)
// Берётся из api.updatePlayerPos который GameRuntime обновляет каждый кадр.
global.set('__rbxl_player_pos', () => {
try {
const p = hrp._position || { X: 0, Y: 0, Z: 0 };
return { x: p.X, y: p.Y, z: p.Z };
const p = api._realPlayerPos || hrp._position || { X: 0, Y: 0, Z: 0 };
return { x: p.x ?? p.X, y: p.y ?? p.Y, z: p.z ?? p.Z };
} catch (_) { return { x: 0, y: 0, z: 0 }; }
});
// Достаём ссылку на Lua-функцию один раз; вызовы безопасны (не doStringSync)
@ -1845,8 +1846,10 @@ export function registerRobloxShim(lua, opts) {
// Для Этапа 3 сделаем proxy через явный метод. В Этапе 4 — введём
// metatable на Lua-стороне (более чистый путь).
// Возвращаем api для main-loop
return {
// Возвращаем api для main-loop. api объявляется заранее, чтобы closures
// вроде __rbxl_player_pos и updatePlayerPos могли его видеть.
const api = {
_realPlayerPos: null,
onSceneSnapshot(snap) {
try {
const prims = snap?.primitives || [];
@ -2076,7 +2079,13 @@ export function registerRobloxShim(lua, opts) {
return allTools.find(t => t.Name === name);
},
getAllTools() { return allTools.slice(); },
// GameRuntime каждый кадр шлёт реальную позицию игрока сюда.
// __rbxl_player_pos() её возвращает Lua-скриптам.
updatePlayerPos(x, y, z) {
api._realPlayerPos = { x: +x, y: +y, z: +z };
},
// Доступ к ключевым объектам (для тестов и отладки)
partById, localPlayer, humanoid, character, workspace, players, game,
};
return api;
}