--!native --!optimize 2 local ReplicatedStorage = game:GetService("ReplicatedStorage") local jabby = require(ReplicatedStorage.Packages.jabby) local jecs = require(ReplicatedStorage.ecs) local components = require(ReplicatedStorage.std.components) local pair = jecs.pair type World = jecs.World type Entity = jecs.Entity type System = { callback: (world: World) -> (), name: string, rate: number?, interval: number? } type Systems = { System } type Events = { RenderStepped: Systems, Heartbeat: Systems } export type Scheduler = { components: { Disabled: Entity, System: Entity, Phase: Entity, DependsOn: Entity }, collect: { under_event: (event: Entity) -> Systems, all: () -> Events }, systems: { begin: (events: Events) -> { [Entity]: thread }, new: (callback: (dt: number) -> (), phase: Entity) -> Entity }, phases: { RenderStepped: Entity, Heartbeat: Entity }, phase: (after: Entity) -> Entity } local scheduler_new: (w: World) -> Scheduler do local world local Disabled local System local DependsOn local Phase local Event local Name local scheduler local RenderStepped local Heartbeat local PreAnimation local PreSimulation local system: System local dt local function run() debug.profilebegin(system.name) system.callback(dt) debug.profileend() end local function panic(str) -- We don't want to interrupt the loop when we error task.spawn(error, str) end local function begin(events: { Systems }) local threads = {} for event, systems in events do if not event then continue end local event_name = tostring(event) threads[event] = task.spawn(function() while true do dt = event:Wait() debug.profilebegin(event_name) for _, sys in systems do scheduler:run(sys.id, sys.system, dt) end debug.profileend() end end) end return threads end local function scheduler_collect_systems_under_phase_recursive(systems, phase) local phase_name = world:get(phase, Name) for _, system in world:query(System):with(pair(DependsOn, phase)) do table.insert(systems, { id = scheduler:register_system({ name = system.name, phase = phase_name }), system = system.callback }) end for after in world:query(Phase):with(pair(DependsOn, phase)) do scheduler_collect_systems_under_phase_recursive(systems, after) end end local function scheduler_collect_systems_under_event(event) local systems = {} scheduler_collect_systems_under_phase_recursive(systems, event) return systems end local function scheduler_collect_systems_all() local events = {} for phase, event in world:query(Event):with(Phase) do events[event] = scheduler_collect_systems_under_event(phase) end return events end local function scheduler_phase_new(after) local phase = world:entity() world:add(phase, Phase) local dependency = pair(DependsOn, after) world:add(phase, dependency) return phase end local function scheduler_systems_new(callback, phase) local system = world:entity() local name = debug.info(callback, "n") world:set(system, System, { callback = callback, name = name }) world:add(system, pair(DependsOn, phase)) return system end function scheduler_new(w) world = w Disabled = world:component() System = world:component() Phase = world:component() DependsOn = world:component() Event = world:component() Name = world:component() RenderStepped = world:component() Heartbeat = world:component() PreSimulation = world:component() PreAnimation = world:component() local RunService = game:GetService("RunService") if RunService:IsClient() then world:add(RenderStepped, Phase) world:set(RenderStepped, Event, RunService.RenderStepped) end world:add(Heartbeat, Phase) world:set(Heartbeat, Name) world:set(Heartbeat, Event, RunService.Heartbeat) world:add(PreSimulation, Phase) world:set(PreSimulation, Event, RunService.PreSimulation) world:add(PreAnimation, Phase) world:set(PreAnimation, Event, RunService.PreAnimation) jabby.public.updated = true table.insert(jabby.public, { class_name = "World", name = "MyWorld", world = world, debug = Name, entities = {} }) for name, component in components do world:set(component, Name, name) print(Name, name) end scheduler = jabby.scheduler.create("scheduler") table.insert(jabby.public, scheduler) return { phase = scheduler_phase_new, phases = { RenderStepped = RenderStepped, PreSimulation = PreSimulation, Heartbeat = Heartbeat, PreAnimation = PreAnimation }, world = world, components = { DependsOn = DependsOn, Disabled = Disabled, Phase = Phase, System = System, }, collect = { under_event = scheduler_collect_systems_under_event, all = scheduler_collect_systems_all }, systems = { new = scheduler_systems_new, begin = begin } } end end return { new = scheduler_new }