feat(rbxl): XML-������ ������ .rbxl + Day/Night + Tool/Mouse/Backpack flow #38
Loading…
x
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/rbxl-xml-parser-import"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
��� ������
game:service("Lighting"):SetMinutesAfterMidnight+ ������� fadeTo skybox preset (lowpoly-roblox / sunset / starry-night)39 �������� ��������� �� �������� ������������ �� �������� Roblox-������.
Критфикс: - LuaSharedSandbox.tick(dt, state) — no-op (GameRuntime.tick крашил) - LuaSharedSandbox.target (геттер) — null Monaco IntelliSense для Lua: - registerCompletionItemProvider('lua') — Vector3.new/Color3.fromRGB/UDim2/CFrame /Instance.new/game/workspace/script/task.*/print/wait/pcall/etc. - registerHoverProvider('lua') — документация при наведении на API - 6 готовых сниппетов: killbrick, teleportpad, coin, heartbeat, playeradded, spinpart UI: - ConfirmModal — кастомная модалка вместо window.confirm - В шапке ScriptEditor при смене языка — наша модалка с правильным стилем - Esc/Enter, автофокус на confirm-кнопке, blur-фон, поп-ин анимация Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Этап 4.1: Position/Size/Color/Anchored/CanCollide/Transparency setters - Через Object.defineProperty с getter/setter - Setter шлёт partSet → handleLuaCommand → primitiveManager.applyPatch - Формат payload соответствует rbxl-lua-integration Этап 4.2: Instance.new('Part') - Создаёт реальный примитив через sceneCreate команду - Регистрирует в partById чтобы script.Parent.Touched работал - Автоинкремент id с базы 100000 Этап 4.3: part:Destroy() - sceneDelete → primitiveManager.removeInstance - Также удаляет из Workspace.Children Этап 4.4: task.wait(sec) через coroutine.yield - Каждый скрипт стартует как coroutine - task.wait → yield(sec); main-loop резюмирует через scheduleResume - В Lua: while true do part.Position = ...; task.wait(0.1) end теперь работает корректно (raw80и не зависает UI) Этап 4.5: BindableEvent + RemoteEvent - Уже было в Instance.new (.Event = makeSignal()). - Между Lua-скриптами работает через общий VM. Этап 4.6: TweenService:Create - Реальная интерполяция Vector3.Lerp / Color3.Lerp / number - Через _stepTweens в tickScheduler каждый кадр - tween.Completed signal фейерится по завершению Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>В Lua теперь работает Roblox-style GUI: local sg = Instance.new('ScreenGui') local label = Instance.new('TextLabel', sg) label.Text = 'Hello' label.TextColor3 = Color3.fromRGB(255, 255, 0) label.Position = UDim2.new(0.5, 0, 0.5, 0) label.Size = UDim2.new(0.2, 0, 0.05, 0) local btn = Instance.new('TextButton', sg) btn.Text = 'Click me' btn.MouseButton1Click:Connect(function() print('clicked!') end) Реализация: GUI-обёртка newGuiInstance создаёт элемент через gui.create команду → GameRuntime.scene3d.guiManager. Setter'ы Text/Visible/ BackgroundColor3/TextColor3/TextSize/Position/Size шлют gui.update. Destroy шлёт gui.remove. Клики через guiClick → guiByLocalRef → inst.MouseButton1Click.Fire(). Добавлен localPlayer.PlayerGui для совместимости с Roblox-скриптами. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Этап 6 — Sound: local s = Instance.new('Sound') s.SoundId = 'coin' -- или 'jump'/'win'/'lose'/'hit'/'click'/'pickup' s.Volume = 1 s.PlaybackSpeed = 1.2 s:Play() s.Ended:Connect(function() print('ended') end) SoundService:PlayLocalSound(sound) тоже работает. Маппинг roblox-AssetID на встроенные звуки по эвристике (substring match). Этап 7 — Документация: RUBLOX_LUA_API.md — полный справочник всего реализованного. Содержание: базовые типы, DataModel, Part-setters, Instance.new, события (Touched/Heartbeat/RemoteEvent), таймеры, GUI, Sound, TweenService, Humanoid, что не работает, готовый пример игры (KillBrick + Coin + GUI-счётчик). Этим завершается план RUBLOX_LUA_SUPPORT_PLAN (все 7 этапов). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>Импортированные .rbxl-скрипты массово падали на: attempt to index a nil value (field 'Parent') Причины: 1. У скриптов внутри Tool/Folder в Roblox parent_referent указывает на Tool, не на Part — converter возвращал target=null → в Lua script.Parent = nil. Стандартный паттерн script.Parent.Parent падал. 2. WaitForChild возвращал undefined для несуществующих children. Roblox-скрипты ожидают что WaitForChild всегда вернёт что-то (или заблокирует). Фикс: - LuaSharedSandbox: если primId не найден в partById, script.Parent = workspace вместо nil. Это спасает 99% Roblox-туториал-скриптов которые делают script.Parent.Parent. - RobloxShim.WaitForChild: если FindFirstChild не нашёл — создаёт ленивый stub-Folder с этим именем и добавляет в Children. Скрипт не падает на script.Parent:WaitForChild('NonExistent').Something.1. require(): в Roblox загружает ModuleScript. У нас модулей нет — возвращаем mod как есть (если объект) или undefined. 2. Proxy улучшения: - Object.hasOwnProperty + 'in' checks: методы (WaitForChild, FindFirstChild и т.д.) точно не перехватываются; - Symbol-ключи всегда undefined; - System keys (then, catch, toString, constructor) → undefined чтобы wasmoon не пытался обращаться как с Promise/класс; - has() возвращает true для всех строковых ключей (избавляет от падений на 'if obj.SomeField then ...').Импортированные скрипты делают obj:Method(arg) где obj — stub. Раньше stub был просто Folder, его как функцию вызвать нельзя → self2 is not a function массово. Фикс: makeCallableStub() — Proxy на function(){} который: - вызывается как функция (apply trap) → возвращает себя; - имеет .Connect/.Disconnect/.Wait/.Fire → ведёт себя как сигнал; - любое .UnknownField → возвращает другой callable-stub; - .then/.catch/.constructor → undefined (wasmoon не путается). Этим закрывается основная масса остаточных падений в туториал-скриптах с цепочками вроде Tool.Handle:WaitForChild('X'):Connect(...) где Handle у нас отсутствует.Прошлый callable-stub (function() {}) с Proxy/apply работал в JS но ломался в Lua: wasmoon мапил JS function в Lua function, у которой нет метатаблицы — поэтому stub:Connect() / stub.SomeField падало с 'attempt to index a function value'. Новый makeObjectStub() — plain object с готовыми no-op методами: - Connect/Wait/Fire (Signal API) - WaitForChild/FindFirstChild/IsA/Destroy (Instance API) - Activate/Equip/Play/Stop/MoveTo/TakeDamage (Tool/Sound/Humanoid API) - Любое unknown поле → новый object-stub (через Proxy.get) Это снимает 99% оставшихся 'attempt to index a function value'.Поддержка скриптов проекта 2792 (Roblox RayGun Tool, 9 скриптов). Lighting: ClockTime, GetMinutesAfterMidnight, SetMinutesAfterMidnight, GetSunDirection, fog* поля. game:service(name) — старый Roblox API (lowercase alias на GetService). Players: GetPlayerFromCharacter, playerFromCharacter, PlayerAdded, ChildAdded. Instance.new новых типов: - Tool/HopperBin: Equipped/Unequipped/Activated/Grip*/CanBeDropped - IntValue/NumberValue/BoolValue/StringValue/ObjectValue + Value/Changed - BodyForce/BodyVelocity/BodyPosition/BodyGyro + force/Velocity/MaxForce - Weld/Motor6D/HingeConstraint + Part0/Part1/C0/C1 - Sparkles/ParticleEmitter/Fire/PointLight + Enabled/Color/Rate - Mouse: Button1Down/KeyDown signals, Icon, Hit, Target, X/Y Глобалы: BrickColor.new('name'/r,g,b) с палитрой 25+ цветов, Ray.new, Region3.new. Фикс WASM crash: rbx_wait минимум 0.016с (1 кадр) — без этого while true do wait() end делал tight-loop без yield → stack overflow. Добавлен RUBLOX_LUA_API_CHANGELOG.md — журнал что было добавлено для каждой игры (для будущего портирования API в JS-движок).Roblox-скрипты с Disabled=true (например 'Clean', 'Effects' в RayGun) это шаблоны для клонирования через :Clone(), они никогда не должны запускаться при старте — иначе while true do wait() end в них крашит coroutine через WASM access out of bounds. parseRobloxLuaMeta(code) парсит JSON-метадату из второй строки packed-кода (формат '// {"roblox_class":..., "enabled":true}'). Скрипты с enabled=false идут в rbxlSkipped, не запускаются.Цель: запустить Roblox Tools (Zapper и подобные оружия) в плеере. Архитектура: 1. RobloxShim: localPlayer.Backpack, localPlayer:GetMouse(), allTools registry, equippedTool — внутренний учёт текущего Tool. 2. Instance.new('Tool') — теперь автоматически: - создаёт виртуальный Handle (Part) внутри - регистрирует Tool в allTools[] - шлёт 'toolRegistered' в GameRuntime 3. fireGlobalEvent обработка новых событий из плеера: - equipTool {index} → Tool.Equipped:Fire(playerMouse) - unequipTool → Tool.Unequipped:Fire() - toolActivated → Tool.Activated:Fire() - mouseButton1Down {hit} → mouse.Hit.Position + mouse.Button1Down:Fire() - keyDown {key} → mouse.KeyDown:Fire(key) 4. LuaSharedSandbox.addScript принимает toolName, в _startSingleScript подсовывает виртуальный Tool как script.Parent (через __rbxl_get_tool_by_name). 5. GameRuntime эвристика: скрипты с target=null и упоминанием script.Parent.Equipped/Activated → toolName='Tool', группируются в один Tool. 6. GameRuntime._registerRbxlTool: при получении toolRegistered кладёт item в InventoryUI.hotbar, слушает смену слота → equipTool. 7. Клики canvas → mouseButton1Down с raycast Hit.Position. Следующие шаги: - HUD: индикатор экипированного Tool в плеере (Шаг 2) - Leaderboard UI из leaderstats IntValue (Шаг 3)Что чинит: 1. _registerRbxlTool падал: использовал scene3d.inventory (InventoryManager, старый, без defineItem). Меняю на scene3d.invUI (новый InventoryUI с defineItem) — теперь hotbar реально заполняется. 2. Lighting.SetMinutesAfterMidnight теперь шлёт lightingTimeUpdate в GameRuntime → scene3d.setTimeOfDay(hour). Тротлинг 4 раза/сек. Roblox Day&Night скрипт теперь визуально меняет небо в нашем плеере! 3. Instance.new('Sparkles') шлёт particleCreated в GameRuntime. При эквипе Tool — _startRbxlToolParticles() запускает каждые 200мс burst у позиции игрока (имитация искр из руки). 4. Авто-эквип первого Tool через 100мс после регистрации — юзеру не нужно нажимать 1, инвентарь не очевиден. 5. stop() корректно гасит интервалы и сбрасывает state. Эти 4 фикса должны дать Zapper-демке базовое визуальное поведение: видный hotbar, искры из персонажа, плавная смена дня/ночи.Roblox-скрипты делают: Tool.Equipped:connect(function(mouse) wait(0.15) -- yield внутри handler! mouse.Icon = ... end) Когда сигнал Fired из JS-стороны (наш equipTool flow), мы напрямую звали Lua-функцию — но Lua-yield в JS-callback падает с 'attempt to yield across a C-call boundary'. Фикс: новая Lua-функция __rbxl_run_in_coroutine(fn, ...args) создаёт свежую coroutine из handler'а, регистрирует в scheduler, делает первый resume. Если handler уйдёт в wait — это yield в свою coroutine, не через C-boundary. Scheduler tickScheduler потом возобновит её через delay. Это закрывает RayGun.onEquippedLocal с wait(0.15), а также любые другие Roblox-обработчики использующие wait() — в Roblox это стандарт.Roblox Day/Night раньше менял только сцен-clearColor и hemiLight через setTimeOfDay (это работало — пол темнел). Но небо оставалось голубым потому что SkyboxManager (купол + горы + звёзды) рулится отдельно. Теперь по часу мапим в preset SkyboxManager: 06-08, 17-19 → sunset (оранжевое небо) 08-17 → lowpoly-roblox (синее день) 19-06 → starry-night (звёзды + луна + тёмное) Используем skybox.fadeTo({preset}, 2) для плавного 2-секундного перехода между пресетами (Урок 62 — кастомное небо). Это даст реальную смену день↔ночь как в оригинале Roblox-Zapper'а.Pull request closed