mirror of
				https://github.com/Ukendio/jecs.git
				synced 2025-11-04 10:59:18 +00:00 
			
		
		
		
	Add scheduler to demo (#106)
* Add example to make scheduler with phases * Add more builtin phases
This commit is contained in:
		
							parent
							
								
									3d8d71b48d
								
							
						
					
					
						commit
						f220b95d2f
					
				
					 12 changed files with 279 additions and 101 deletions
				
			
		
							
								
								
									
										
											BIN
										
									
								
								demo.rbxl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								demo.rbxl
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
					@ -1,9 +1,14 @@
 | 
				
			||||||
local jecs = require(game:GetService("ReplicatedStorage").ecs)
 | 
					local jecs = require(game:GetService("ReplicatedStorage").ecs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local world = require(script.world) :: jecs.World
 | 
					local world = require(script.world) :: jecs.World
 | 
				
			||||||
export type World = jecs.World
 | 
					export type World = jecs.World
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local scheduler = require(script.scheduler)
 | 
				
			||||||
 | 
					export type Scheduler = scheduler.Scheduler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local std = {
 | 
					local std = {
 | 
				
			||||||
    ChangeTracker = require(script.changetracker),
 | 
					    ChangeTracker = require(script.changetracker),
 | 
				
			||||||
    Scheduler = require(script.scheduler),
 | 
					    Scheduler = scheduler.new(world),
 | 
				
			||||||
    bt = require(script.bt),
 | 
					    bt = require(script.bt),
 | 
				
			||||||
    collect = require(script.collect),
 | 
					    collect = require(script.collect),
 | 
				
			||||||
    components = require(script.components),
 | 
					    components = require(script.components),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,64 +1,207 @@
 | 
				
			||||||
local function panic(str)
 | 
					--!native
 | 
				
			||||||
    -- We don't want to interrupt the loop when we error
 | 
					--!optimize 2
 | 
				
			||||||
    task.spawn(error, str)
 | 
					local jecs = require(game:GetService("ReplicatedStorage").ecs)
 | 
				
			||||||
end
 | 
					local pair = jecs.pair
 | 
				
			||||||
 | 
					type World = jecs.World
 | 
				
			||||||
 | 
					type Entity<T=nil> = jecs.Entity<T>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type System = {
 | 
				
			||||||
 | 
					    callback: (world: World) -> ()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Systems = { System }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Events = {
 | 
				
			||||||
 | 
					    RenderStepped: Systems,
 | 
				
			||||||
 | 
					    Heartbeat: Systems
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type Scheduler = {
 | 
				
			||||||
 | 
					    components: {
 | 
				
			||||||
 | 
					        Disabled: Entity,
 | 
				
			||||||
 | 
					        System: Entity<System>,
 | 
				
			||||||
 | 
					        Phase: Entity,
 | 
				
			||||||
 | 
					        DependsOn: Entity
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    collect: {
 | 
				
			||||||
 | 
					        under_event: (event: Entity) -> Systems,
 | 
				
			||||||
 | 
					        all: () -> Events
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    systems: {
 | 
				
			||||||
 | 
					        begin: (events: Events) -> (),
 | 
				
			||||||
 | 
					        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 RenderStepped
 | 
				
			||||||
 | 
					    local Heartbeat
 | 
				
			||||||
 | 
					    local PreAnimation
 | 
				
			||||||
 | 
					    local PreSimulation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function Scheduler(...)
 | 
					 | 
				
			||||||
    local systems = { ... }
 | 
					 | 
				
			||||||
    local systemsNames = {}
 | 
					 | 
				
			||||||
    local N = #systems
 | 
					 | 
				
			||||||
    local system
 | 
					    local system
 | 
				
			||||||
    local dt
 | 
					    local dt
 | 
				
			||||||
 | 
					 | 
				
			||||||
    for i, module in systems do
 | 
					 | 
				
			||||||
        local sys = require(module)
 | 
					 | 
				
			||||||
        systems[i] = sys
 | 
					 | 
				
			||||||
        local file, line = debug.info(2, "sl")
 | 
					 | 
				
			||||||
        systemsNames[sys] = `{file}->::{line}::->{debug.info(sys, "n")}`
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    local function run()
 | 
					    local function run()
 | 
				
			||||||
        local name = systemsNames[system]
 | 
					        debug.profilebegin(system.name)
 | 
				
			||||||
 | 
					        system.callback(dt)
 | 
				
			||||||
        debug.profilebegin(name)
 | 
					 | 
				
			||||||
        debug.setmemorycategory(name)
 | 
					 | 
				
			||||||
        system(dt)
 | 
					 | 
				
			||||||
        debug.profileend()
 | 
					        debug.profileend()
 | 
				
			||||||
    end
 | 
					    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)
 | 
				
			||||||
 | 
					        local connections = {}
 | 
				
			||||||
 | 
					        for event, systems in events do
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    local function loop(sinceLastFrame)
 | 
					            if not event then continue end
 | 
				
			||||||
        debug.profilebegin("loop()")
 | 
					            local event_name = tostring(event)
 | 
				
			||||||
 | 
					            connections[event] = event:Connect(function(last)
 | 
				
			||||||
 | 
					                debug.profilebegin(event_name)
 | 
				
			||||||
 | 
					                for _, sys in systems do
 | 
				
			||||||
 | 
					                    system = sys
 | 
				
			||||||
 | 
					                    dt = last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for i = N, 1, -1 do
 | 
					                    local didNotYield, why = xpcall(function()
 | 
				
			||||||
            system = systems[i]
 | 
					                        for _ in run do end
 | 
				
			||||||
 | 
					                    end, debug.traceback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            dt = sinceLastFrame
 | 
					                    if didNotYield then
 | 
				
			||||||
 | 
					             			continue
 | 
				
			||||||
 | 
					              		end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            local didNotYield, why = xpcall(function()
 | 
					              		if string.find(why, "thread is not yieldable") then
 | 
				
			||||||
                for _ in run do end
 | 
					             			panic("Not allowed to yield in the systems.")
 | 
				
			||||||
            end, debug.traceback)
 | 
					              		else
 | 
				
			||||||
 | 
					              		    panic(why)
 | 
				
			||||||
 | 
					              		end
 | 
				
			||||||
 | 
					                end
 | 
				
			||||||
 | 
					                debug.profileend()
 | 
				
			||||||
 | 
					            end)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        return connections
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if didNotYield then
 | 
					    local function scheduler_collect_systems_under_phase_recursive(systems, phase)
 | 
				
			||||||
				continue
 | 
					        for _, system in world:query(System):with(pair(DependsOn, phase)) do
 | 
				
			||||||
			end
 | 
					            table.insert(systems, system)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        for dependant in world:query(Phase):with(pair(DependsOn, phase)) do
 | 
				
			||||||
 | 
					            scheduler_collect_systems_under_phase_recursive(systems, dependant)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if string.find(why, "thread is not yieldable") then
 | 
					    local function scheduler_collect_systems_under_event(event)
 | 
				
			||||||
				N -= 1
 | 
					        local systems = {}
 | 
				
			||||||
				local name = table.remove(systems, i)
 | 
					        scheduler_collect_systems_under_phase_recursive(systems, event)
 | 
				
			||||||
				panic("Not allowed to yield in the systems."
 | 
					        return systems
 | 
				
			||||||
    				.. "\n"
 | 
					    end
 | 
				
			||||||
    				.. `System: {name} has been ejected`
 | 
					
 | 
				
			||||||
				)
 | 
					    local function scheduler_collect_systems_all()
 | 
				
			||||||
			else
 | 
					        local systems = {}
 | 
				
			||||||
			    panic(why)
 | 
					        for phase, event in world:query(Event):with(Phase) do
 | 
				
			||||||
			end
 | 
					            systems[event] = scheduler_collect_systems_under_event(phase)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					        return systems
 | 
				
			||||||
 | 
					    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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        debug.profileend()
 | 
					        world:add(Heartbeat, Phase)
 | 
				
			||||||
        debug.resetmemorycategory()
 | 
					        world:set(Heartbeat, Event, RunService.Heartbeat)
 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return loop
 | 
					        world:add(PreSimulation, Phase)
 | 
				
			||||||
 | 
					        world:set(PreSimulation, Event, RunService.PreSimulation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        world:add(PreAnimation, Phase)
 | 
				
			||||||
 | 
					        world:set(PreAnimation, Event, RunService.PreAnimation)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return Scheduler
 | 
					
 | 
				
			||||||
 | 
					return {
 | 
				
			||||||
 | 
					    new = scheduler_new
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,8 @@
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local std = require(ReplicatedStorage.std)
 | 
					local std = require(ReplicatedStorage.std)
 | 
				
			||||||
local loop = std.Scheduler(unpack(script.Parent.systems:GetChildren()))
 | 
					local scheduler = std.Scheduler
 | 
				
			||||||
game:GetService("RunService").Heartbeat:Connect(loop)
 | 
					for _, module in script.Parent.systems:GetChildren() do
 | 
				
			||||||
 | 
					    require(module)(scheduler)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					local events = scheduler.collect.all()
 | 
				
			||||||
 | 
					scheduler.systems.begin(events)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,7 @@
 | 
				
			||||||
 | 
					--!optimize 2
 | 
				
			||||||
 | 
					--!native
 | 
				
			||||||
--!strict
 | 
					--!strict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local blink = require(game:GetService("ServerScriptService").net)
 | 
					local blink = require(game:GetService("ServerScriptService").net)
 | 
				
			||||||
local jecs = require(ReplicatedStorage.ecs)
 | 
					local jecs = require(ReplicatedStorage.ecs)
 | 
				
			||||||
| 
						 | 
					@ -15,25 +18,22 @@ local Player = cts.Player
 | 
				
			||||||
local Character = cts.Character
 | 
					local Character = cts.Character
 | 
				
			||||||
 | 
					
 | 
				
			||||||
local function mobsMove(dt: number)
 | 
					local function mobsMove(dt: number)
 | 
				
			||||||
    local players = world:query(Character):with(Player)
 | 
					    local targets = {}
 | 
				
			||||||
 | 
					    for _, character in world:query(Character):with(Player):iter() do
 | 
				
			||||||
 | 
					        table.insert(targets, (character.PrimaryPart :: Part).Position)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for mob, cf, v in world:query(Transform, Velocity):with(Mob):iter() do
 | 
					    for mob, cf, v in world:query(Transform, Velocity):with(Mob):iter() do
 | 
				
			||||||
        local p = cf.Position
 | 
					        local p = cf.Position
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        local target
 | 
					        local target
 | 
				
			||||||
 | 
					        local closest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for playerId, character in players:iter() do
 | 
					        for _, pos in targets do
 | 
				
			||||||
            local pos = (character.PrimaryPart::Part).Position
 | 
					            local distance = (p - pos).Magnitude
 | 
				
			||||||
            if true then
 | 
					            if not target or distance < closest then
 | 
				
			||||||
                target = pos
 | 
					 | 
				
			||||||
                break
 | 
					 | 
				
			||||||
            end
 | 
					 | 
				
			||||||
            if not target then
 | 
					 | 
				
			||||||
                target = pos
 | 
					 | 
				
			||||||
            elseif (p - pos).Magnitude
 | 
					 | 
				
			||||||
                < (p - target).Magnitude
 | 
					 | 
				
			||||||
            then
 | 
					 | 
				
			||||||
                target = pos
 | 
					                target = pos
 | 
				
			||||||
 | 
					                closest = distance
 | 
				
			||||||
            end
 | 
					            end
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,4 +47,7 @@ local function mobsMove(dt: number)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return mobsMove
 | 
					return function(scheduler: std.Scheduler)
 | 
				
			||||||
 | 
					    return scheduler.systems.new(mobsMove,
 | 
				
			||||||
 | 
					        scheduler.phases.Heartbeat)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,4 +39,7 @@ local function players()
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return players
 | 
					return function(scheduler: std.Scheduler)
 | 
				
			||||||
 | 
					    return scheduler.systems.new(players,
 | 
				
			||||||
 | 
					        scheduler.phases.Heartbeat)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,4 +27,7 @@ local function spawnMobs()
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return spawnMobs
 | 
					return function(scheduler: std.Scheduler)
 | 
				
			||||||
 | 
					    return scheduler.systems.new(spawnMobs,
 | 
				
			||||||
 | 
					        scheduler.phases.Heartbeat)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,9 @@
 | 
				
			||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
					local ReplicatedStorage = game:GetService("ReplicatedStorage")
 | 
				
			||||||
local std = require(ReplicatedStorage.std)
 | 
					local std = require(ReplicatedStorage.std)
 | 
				
			||||||
 | 
					local scheduler = std.Scheduler
 | 
				
			||||||
 | 
					for _, module in script.Parent:WaitForChild("systems"):GetChildren() do
 | 
				
			||||||
 | 
					    require(module)(scheduler)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					local events = scheduler.collect.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
print(script.Parent:WaitForChild("systems"):GetChildren())
 | 
					scheduler.systems.begin(events)
 | 
				
			||||||
local loop = std.Scheduler(unpack(script.Parent:WaitForChild("systems"):GetChildren()))
 | 
					 | 
				
			||||||
game:GetService("RunService").Heartbeat:Connect(loop)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,4 +14,7 @@ local function move(dt: number)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return move
 | 
					return function(scheduler: std.Scheduler)
 | 
				
			||||||
 | 
					    return scheduler.systems.new(move,
 | 
				
			||||||
 | 
					        scheduler.phases.RenderStepped)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,9 @@ local function syncMobs()
 | 
				
			||||||
            :set(cts.Model, model)
 | 
					            :set(cts.Model, model)
 | 
				
			||||||
            :add(cts.Mob)
 | 
					            :add(cts.Mob)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return syncMobs
 | 
					return function(scheduler: std.Scheduler)
 | 
				
			||||||
 | 
					    return scheduler.systems.new(syncMobs,
 | 
				
			||||||
 | 
					        scheduler.phases.RenderStepped)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,4 +13,7 @@ local function syncTransforms()
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
return syncTransforms
 | 
					return function(scheduler: std.Scheduler)
 | 
				
			||||||
 | 
					    return scheduler.systems.new(syncTransforms,
 | 
				
			||||||
 | 
					        scheduler.phases.RenderStepped)
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1264,11 +1264,12 @@ TEST("scheduler", function()
 | 
				
			||||||
            DependsOn: Entity
 | 
					            DependsOn: Entity
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        collect: {
 | 
				
			||||||
 | 
					            under_event: (event: Entity) -> Systems,
 | 
				
			||||||
 | 
					            all: () -> Events
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        systems: {
 | 
					        systems: {
 | 
				
			||||||
            collect: {
 | 
					 | 
				
			||||||
                under_event: (event: Entity) -> Systems,
 | 
					 | 
				
			||||||
                all: () -> Events
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            run: (events: Events) -> (),
 | 
					            run: (events: Events) -> (),
 | 
				
			||||||
            new: (callback: (world: World) -> (), phase: Entity) -> Entity
 | 
					            new: (callback: (world: World) -> (), phase: Entity) -> Entity
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -1287,8 +1288,20 @@ TEST("scheduler", function()
 | 
				
			||||||
        local System
 | 
					        local System
 | 
				
			||||||
        local DependsOn
 | 
					        local DependsOn
 | 
				
			||||||
        local Phase
 | 
					        local Phase
 | 
				
			||||||
 | 
					        local Event
 | 
				
			||||||
        local RenderStepped
 | 
					        local RenderStepped
 | 
				
			||||||
        local Heartbeat
 | 
					        local Heartbeat
 | 
				
			||||||
 | 
					        local Name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        local function scheduler_systems_run(events)
 | 
				
			||||||
 | 
					            for _, system in events[RenderStepped] do
 | 
				
			||||||
 | 
					                system.callback()
 | 
				
			||||||
 | 
					            end
 | 
				
			||||||
 | 
					            print(Heartbeat, events[Heartbeat])
 | 
				
			||||||
 | 
					            for _, system in events[Heartbeat] do
 | 
				
			||||||
 | 
					                system.callback()
 | 
				
			||||||
 | 
					            end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        local function scheduler_collect_systems_under_phase_recursive(systems, phase)
 | 
					        local function scheduler_collect_systems_under_phase_recursive(systems, phase)
 | 
				
			||||||
            for _, system in world:query(System):with(pair(DependsOn, phase)) do
 | 
					            for _, system in world:query(System):with(pair(DependsOn, phase)) do
 | 
				
			||||||
| 
						 | 
					@ -1306,24 +1319,13 @@ TEST("scheduler", function()
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        local function scheduler_collect_systems_all()
 | 
					        local function scheduler_collect_systems_all()
 | 
				
			||||||
            local systems = {
 | 
					            local systems = {}
 | 
				
			||||||
                RenderStepped = scheduler_collect_systems_under_event(
 | 
					            for phase in world:query(Phase, Event) do
 | 
				
			||||||
                    RenderStepped),
 | 
					                systems[phase] = scheduler_collect_systems_under_event(phase)
 | 
				
			||||||
                Heartbeat = scheduler_collect_systems_under_event(
 | 
					            end
 | 
				
			||||||
                    Heartbeat)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            return systems
 | 
					            return systems
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        local function scheduler_run_systems(events)
 | 
					 | 
				
			||||||
            for _, system in events.RenderStepped do
 | 
					 | 
				
			||||||
                system.callback(world)
 | 
					 | 
				
			||||||
            end
 | 
					 | 
				
			||||||
            for _, system in events.Heartbeat do
 | 
					 | 
				
			||||||
                system.callback(world)
 | 
					 | 
				
			||||||
            end
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        local function scheduler_phase_new(after)
 | 
					        local function scheduler_phase_new(after)
 | 
				
			||||||
            local phase = world:entity()
 | 
					            local phase = world:entity()
 | 
				
			||||||
            world:add(phase, Phase)
 | 
					            world:add(phase, Phase)
 | 
				
			||||||
| 
						 | 
					@ -1345,12 +1347,15 @@ TEST("scheduler", function()
 | 
				
			||||||
            System = world:component()
 | 
					            System = world:component()
 | 
				
			||||||
            Phase = world:component()
 | 
					            Phase = world:component()
 | 
				
			||||||
            DependsOn = world:component()
 | 
					            DependsOn = world:component()
 | 
				
			||||||
 | 
					            Event = world:component()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            RenderStepped = world:component()
 | 
					            RenderStepped = world:component()
 | 
				
			||||||
            Heartbeat = world:component()
 | 
					            Heartbeat = world:component()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            world:add(RenderStepped, Phase)
 | 
					            world:add(RenderStepped, Phase)
 | 
				
			||||||
 | 
					            world:add(RenderStepped, Event)
 | 
				
			||||||
            world:add(Heartbeat, Phase)
 | 
					            world:add(Heartbeat, Phase)
 | 
				
			||||||
 | 
					            world:add(Heartbeat, Event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return {
 | 
					            return {
 | 
				
			||||||
                phase = scheduler_phase_new,
 | 
					                phase = scheduler_phase_new,
 | 
				
			||||||
| 
						 | 
					@ -1371,13 +1376,14 @@ TEST("scheduler", function()
 | 
				
			||||||
                    System = System,
 | 
					                    System = System,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                collect = {
 | 
				
			||||||
 | 
					                    under_event = scheduler_collect_systems_under_event,
 | 
				
			||||||
 | 
					                    all = scheduler_collect_systems_all
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                systems = {
 | 
					                systems = {
 | 
				
			||||||
                    run = scheduler_run_systems,
 | 
					 | 
				
			||||||
                    collect = {
 | 
					 | 
				
			||||||
                        under_event = scheduler_collect_systems_under_event,
 | 
					 | 
				
			||||||
                        all = scheduler_collect_systems_all
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    new = scheduler_systems_new,
 | 
					                    new = scheduler_systems_new,
 | 
				
			||||||
 | 
					                    run = scheduler_systems_run
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
| 
						 | 
					@ -1432,7 +1438,7 @@ TEST("scheduler", function()
 | 
				
			||||||
        createSystem(hit, Collisions)
 | 
					        createSystem(hit, Collisions)
 | 
				
			||||||
        createSystem(move, Physics)
 | 
					        createSystem(move, Physics)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        local events = scheduler.systems.collect.all()
 | 
					        local events = scheduler.collect.all()
 | 
				
			||||||
        scheduler.systems.run(events)
 | 
					        scheduler.systems.run(events)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        order ..= "->END"
 | 
					        order ..= "->END"
 | 
				
			||||||
| 
						 | 
					@ -1465,20 +1471,20 @@ TEST("scheduler", function()
 | 
				
			||||||
        createSystem(move, Physics)
 | 
					        createSystem(move, Physics)
 | 
				
			||||||
        createSystem(camera, Render)
 | 
					        createSystem(camera, Render)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        local systems = scheduler.systems.collect.under_event(Collisions)
 | 
					        local systems = scheduler.collect.under_event(Collisions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CHECK(#systems == 1)
 | 
					        CHECK(#systems == 1)
 | 
				
			||||||
        CHECK(systems[1].callback == hit)
 | 
					        CHECK(systems[1].callback == hit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        systems = scheduler.systems.collect.under_event(Physics)
 | 
					        systems = scheduler.collect.under_event(Physics)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CHECK(#systems == 2)
 | 
					        CHECK(#systems == 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        systems = scheduler.systems.collect.under_event(Heartbeat)
 | 
					        systems = scheduler.collect.under_event(Heartbeat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CHECK(#systems == 2)
 | 
					        CHECK(#systems == 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        systems = scheduler.systems.collect.under_event(Render)
 | 
					        systems = scheduler.collect.under_event(Render)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        CHECK(#systems == 1)
 | 
					        CHECK(#systems == 1)
 | 
				
			||||||
        CHECK(systems[1].callback == camera)
 | 
					        CHECK(systems[1].callback == camera)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue