diff --git a/src/editor/ScriptEditor.jsx b/src/editor/ScriptEditor.jsx index 83da9de..cc7adec 100644 --- a/src/editor/ScriptEditor.jsx +++ b/src/editor/ScriptEditor.jsx @@ -40,16 +40,22 @@ import ConfirmModal from './ConfirmModal'; // Используется при смене языка JS→Lua когда текущий код выглядит «пустым». export const LUA_TEMPLATE_PART = `-- Скрипт привязан к Part. script.Parent = эта часть. local part = script.Parent +print("Скрипт детали", part.Name, "запущен") part.Touched:Connect(function(hit) print("Касание:", hit.Name) end) `; -export const LUA_TEMPLATE_GLOBAL = `-- Глобальный Lua-скрипт. Работает на стороне сервера/клиента. +export const LUA_TEMPLATE_GLOBAL = `-- Глобальный Lua-скрипт. Доступ к game.* API через Roblox-обёртку. local Players = game:GetService("Players") +print("Привет, Рублокс! Lua-скрипты работают.") +-- Здороваемся со всеми кто уже в игре + кто заходит позже +for _, player in ipairs(Players:GetPlayers()) do + print("Игрок в игре:", player.Name) +end Players.PlayerAdded:Connect(function(player) - print("Игрок зашёл:", player.Name) + print("Зашёл игрок:", player.Name) end) `; export const JS_TEMPLATE_GLOBAL = `// Глобальный JS-скрипт. Подробнее: см. game.* API в /справочник. diff --git a/src/editor/engine/lua/LuaSharedSandbox.js b/src/editor/engine/lua/LuaSharedSandbox.js index 7883bbd..c06a72d 100644 --- a/src/editor/engine/lua/LuaSharedSandbox.js +++ b/src/editor/engine/lua/LuaSharedSandbox.js @@ -134,6 +134,21 @@ export class LuaSharedSandbox { } else { // eslint-disable-next-line no-console console.log(`[LuaSharedSandbox] all ${pending.length} scripts kicked off`); + // После того как все скрипты подключили хендлеры — фейрим + // events для уже существующих сущностей. Roblox-конвенция: + // если игрок уже на сервере когда скрипт подключается, + // Players.PlayerAdded не сработает повторно. Юзеру нужно + // делать ручной обход GetPlayers() — но это редко кто помнит. + // Мы дублируем событие через короткую задержку. + setTimeout(() => { + try { + if (this.api?.fireExistingPlayers) { + this.api.fireExistingPlayers(); + } + } catch (e) { + console.warn('[LuaSharedSandbox] fireExistingPlayers failed:', e); + } + }, 100); } }; setTimeout(initBatch, 0); diff --git a/src/editor/engine/lua/RobloxShim.js b/src/editor/engine/lua/RobloxShim.js index 5cc004c..9663929 100644 --- a/src/editor/engine/lua/RobloxShim.js +++ b/src/editor/engine/lua/RobloxShim.js @@ -828,6 +828,9 @@ export function registerRobloxShim(lua, opts) { character.Parent = localPlayer; localPlayer.Children.push(character); localPlayer.Character = character; + localPlayer.CharacterAdded = makeSignal(); + localPlayer.CharacterRemoving = makeSignal(); + localPlayer.CharacterAppearanceLoaded = makeSignal(); const humanoid = newInstance('Humanoid', 'Humanoid'); humanoid.Parent = character; @@ -1730,6 +1733,23 @@ export function registerRobloxShim(lua, opts) { onGuiSnapshot() {}, onDataSnapshot() {}, + /** Фейр PlayerAdded для уже существующих игроков после того как + * скрипты успели подключить хендлеры. Roblox-конвенция: + * Players.PlayerAdded не срабатывает для игроков уже на сервере. + * Мы дублируем чтобы простые скрипты вроде + * Players.PlayerAdded:Connect(...) работали из коробки. */ + fireExistingPlayers() { + try { + if (players?.PlayerAdded?.Fire) { + players.PlayerAdded.Fire(localPlayer); + } + // CharacterAdded — то же самое + if (localPlayer?.CharacterAdded?.Fire && character) { + localPlayer.CharacterAdded.Fire(character); + } + } catch (_) {} + }, + tickScheduler(_dt) { // 0a. Lua-handlers из очереди (signal.Fire отложил их сюда). // Запускаем каждый в своей coroutine — wait() внутри безопасен.