mirror of
https://github.com/Ukendio/jecs.git
synced 2025-04-24 17:10:03 +00:00
Rework demo
This commit is contained in:
parent
2e29046770
commit
97fe91387f
17 changed files with 296 additions and 454 deletions
|
@ -2,18 +2,16 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|||
local RunService = game:GetService("RunService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local jabby = require(ReplicatedStorage.Packages.jabby)
|
||||
local std = require(ReplicatedStorage.std)
|
||||
local Scheduler = std.Scheduler
|
||||
local world = std.world
|
||||
local std = ReplicatedStorage.std
|
||||
local scheduler = require(std.scheduler)
|
||||
local world = require(std.world)
|
||||
|
||||
local function start(modules)
|
||||
local scheduler = Scheduler.new(world, require(ReplicatedStorage.std.components))
|
||||
for _, module in modules do
|
||||
require(module)(scheduler)
|
||||
require(module)
|
||||
end
|
||||
local events = scheduler.collect.all()
|
||||
scheduler.systems.begin(events)
|
||||
|
||||
local events = scheduler.COLLECT()
|
||||
scheduler.BEGIN(events)
|
||||
jabby.set_check_function(function(player)
|
||||
return true
|
||||
end)
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
|
||||
-- original author @centau
|
||||
|
||||
local SUCCESS = 0
|
||||
local FAILURE = 1
|
||||
local RUNNING = 2
|
||||
local FAILURE = -1
|
||||
local RUNNING = 0
|
||||
local SUCCESS = 1
|
||||
|
||||
local function SEQUENCE(nodes)
|
||||
return function(...)
|
||||
for _, node in nodes do
|
||||
local status = node(...)
|
||||
if status == FAILURE or status == RUNNING then
|
||||
if status <= RUNNING then
|
||||
return status
|
||||
end
|
||||
end
|
||||
|
@ -23,7 +23,7 @@ local function FALLBACK(nodes)
|
|||
return function(...)
|
||||
for _, node in nodes do
|
||||
local status = node(...)
|
||||
if status == SUCCESS or status == RUNNING then
|
||||
if status > FAILURE then
|
||||
return status
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ local components: {
|
|||
Model: Entity<Model>,
|
||||
Player: Entity,
|
||||
Target: Entity,
|
||||
Transform: Entity<CFrame>,
|
||||
Transform: Entity<{ new: CFrame, old: CFrame }>,
|
||||
Velocity: Entity<number>,
|
||||
Previous: Entity,
|
||||
} =
|
||||
|
@ -23,4 +23,8 @@ local components: {
|
|||
Previous = world:component(),
|
||||
}
|
||||
|
||||
for name, component in components :: {[string]: jecs.Entity} do
|
||||
world:set(component, jecs.Name, name)
|
||||
end
|
||||
|
||||
return table.freeze(components)
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
local handle = require(script.Parent.handle)
|
||||
local world = require(script.Parent.world)
|
||||
|
||||
local singleton = world:entity()
|
||||
|
||||
local function ctx()
|
||||
-- Cannot cache handles because they will get invalidated
|
||||
return handle(singleton)
|
||||
end
|
||||
|
||||
return ctx
|
|
@ -1,56 +0,0 @@
|
|||
local jecs = require(game:GetService("ReplicatedStorage").ecs)
|
||||
local world = require(script.Parent.world)
|
||||
|
||||
type Handle = {
|
||||
has: (self: Handle, id: jecs.Entity) -> boolean,
|
||||
get: <T>(self: Handle, id: jecs.Entity<T>) -> T?,
|
||||
add: <T>(self: Handle, id: jecs.Entity<T>) -> Handle,
|
||||
set: <T>(self: Handle, id: jecs.Entity<T>, value: T) -> Handle,
|
||||
id: (self: Handle?) -> jecs.Entity,
|
||||
}
|
||||
|
||||
local handle: (e: jecs.Entity) -> Handle
|
||||
|
||||
do
|
||||
local e
|
||||
local function has(_, id)
|
||||
return world:has(e, id)
|
||||
end
|
||||
local function get(_, id)
|
||||
return world:get(e, id)
|
||||
end
|
||||
local function set(self, id, value)
|
||||
world:set(e, id, value)
|
||||
return self
|
||||
end
|
||||
local function add(self, id)
|
||||
world:add(e, id)
|
||||
return self
|
||||
end
|
||||
local function clear(self)
|
||||
world:clear(e)
|
||||
return self
|
||||
end
|
||||
local function delete(self)
|
||||
world:delete(e)
|
||||
end
|
||||
local function id()
|
||||
return e
|
||||
end
|
||||
|
||||
local entity = {
|
||||
has = has,
|
||||
get = get,
|
||||
set = set,
|
||||
add = add,
|
||||
clear = clear,
|
||||
id = id,
|
||||
}
|
||||
|
||||
function handle(id)
|
||||
e = id
|
||||
return entity
|
||||
end
|
||||
end
|
||||
|
||||
return handle
|
|
@ -1,32 +0,0 @@
|
|||
--!native
|
||||
--!optimize 2
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local jecs = require(ReplicatedStorage.ecs)
|
||||
|
||||
local function create_cache(hook)
|
||||
local columns = setmetatable({}, {
|
||||
__index = function(self, component)
|
||||
local column = {}
|
||||
self[component] = column
|
||||
return column
|
||||
end,
|
||||
})
|
||||
|
||||
return function(world, component, fn)
|
||||
local column = columns[component]
|
||||
table.insert(column, fn)
|
||||
world:set(component, hook, function(entity, value)
|
||||
for _, callback in column do
|
||||
callback(entity, value)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
local hooks = {
|
||||
OnSet = create_cache(jecs.OnSet),
|
||||
OnAdd = create_cache(jecs.OnAdd),
|
||||
OnRemove = create_cache(jecs.OnRemove),
|
||||
}
|
||||
|
||||
return hooks
|
|
@ -1,25 +0,0 @@
|
|||
local jecs = require(game:GetService("ReplicatedStorage").ecs)
|
||||
|
||||
local world = require(script.world) :: jecs.World
|
||||
export type World = jecs.World
|
||||
|
||||
local Scheduler = require(script.scheduler)
|
||||
export type Scheduler = Scheduler.Scheduler
|
||||
|
||||
local std = {
|
||||
ChangeTracker = require(script.changetracker),
|
||||
Scheduler = Scheduler,
|
||||
bt = require(script.bt),
|
||||
collect = require(script.collect),
|
||||
components = require(script.components),
|
||||
ctx = require(script.ctx),
|
||||
handle = require(script.handle),
|
||||
interval = require(script.interval),
|
||||
ref = require(script.ref),
|
||||
world = world :: World,
|
||||
pair = jecs.pair,
|
||||
__ = jecs.w,
|
||||
hooks = require(script.hooks),
|
||||
}
|
||||
|
||||
return std
|
|
@ -16,4 +16,4 @@ local function interval(s)
|
|||
return throttle
|
||||
end
|
||||
|
||||
return interval
|
||||
return interval
|
14
demo/src/ReplicatedStorage/std/phases.luau
Normal file
14
demo/src/ReplicatedStorage/std/phases.luau
Normal file
|
@ -0,0 +1,14 @@
|
|||
local std = game:GetService("ReplicatedStorage").std
|
||||
local Players = game:GetService("Players")
|
||||
|
||||
local scheduler = require(std.scheduler)
|
||||
local PHASE = scheduler.PHASE
|
||||
|
||||
return {
|
||||
PlayerAdded = PHASE({
|
||||
event = Players.PlayerAdded
|
||||
}),
|
||||
PlayerRemoved = PHASE({
|
||||
event = Players.PlayerRemoving
|
||||
})
|
||||
}
|
|
@ -1,16 +1,18 @@
|
|||
local handle = require(script.Parent.handle)
|
||||
local world = require(script.Parent.world)
|
||||
local refs = {}
|
||||
local jecs = require(game:GetService("ReplicatedStorage").ecs)
|
||||
local refs: {[any]: jecs.Entity} = {}
|
||||
|
||||
local function fini(key)
|
||||
local function fini(key): () -> ()
|
||||
return function()
|
||||
refs[key] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function ref(key): (handle.Handle, (() -> ())?)
|
||||
local function noop() end
|
||||
|
||||
local function ref(key): (jecs.Entity, () -> ())
|
||||
if not key then
|
||||
return handle(world:entity())
|
||||
return world:entity(), noop
|
||||
end
|
||||
local e = refs[key]
|
||||
if not e then
|
||||
|
@ -18,7 +20,7 @@ local function ref(key): (handle.Handle, (() -> ())?)
|
|||
refs[key] = e
|
||||
end
|
||||
-- Cannot cache handles because they will get invalidated
|
||||
return handle(e), fini(key)
|
||||
return e, fini(key)
|
||||
end
|
||||
|
||||
return ref
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
local reserved = 0
|
||||
|
||||
local function reserve()
|
||||
reserved += 1
|
||||
return reserved
|
||||
end
|
||||
|
||||
-- If you don't like passing around a world singleton
|
||||
-- and you need to register component IDs, just register them.
|
||||
-- I dont use this because I like adding component traits
|
||||
--[[
|
||||
local components = {
|
||||
Model = registry.reserve(),
|
||||
Transform = registry.reserve(),
|
||||
}
|
||||
|
||||
local world = registry.register(jecs.World.new())
|
||||
local e = world:entity()
|
||||
world:set(e, components.Transform, CFrame)
|
||||
]]
|
||||
local function register(world)
|
||||
for _ = 1, reserved do
|
||||
world:component()
|
||||
end
|
||||
return world
|
||||
end
|
||||
|
||||
return {
|
||||
reserve = reserve,
|
||||
register = register,
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
--!native
|
||||
--!optimize 2
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local RunService = game:GetService("RunService")
|
||||
local jabby = require(ReplicatedStorage.Packages.jabby)
|
||||
local jecs = require(ReplicatedStorage.ecs)
|
||||
local pair = jecs.pair
|
||||
|
@ -8,6 +9,7 @@ local Name = jecs.Name
|
|||
|
||||
type World = jecs.World
|
||||
type Entity<T = nil> = jecs.Entity<T>
|
||||
type Id<T = unknown> = jecs.Id<T>
|
||||
|
||||
type System = {
|
||||
callback: (world: World) -> (),
|
||||
|
@ -21,226 +23,145 @@ type Events = {
|
|||
Heartbeat: Systems,
|
||||
}
|
||||
|
||||
export type Scheduler = {
|
||||
components: {
|
||||
Disabled: Entity,
|
||||
System: Entity<System>,
|
||||
Phase: Entity,
|
||||
DependsOn: Entity,
|
||||
},
|
||||
local world = require(script.Parent.world)
|
||||
local Disabled = world:entity()
|
||||
local System = world:component() :: Id<{ callback: (any) -> (), name: string}>
|
||||
local DependsOn = world:entity()
|
||||
local Event = world:component() :: Id<RBXScriptSignal>
|
||||
local Phase = world:entity()
|
||||
|
||||
collect: {
|
||||
under_event: (event: Entity) -> Systems,
|
||||
all: () -> Events,
|
||||
},
|
||||
local PreRender = world:entity()
|
||||
local Heartbeat = world:entity()
|
||||
local PreAnimation = world:entity()
|
||||
local PreSimulation = world:entity()
|
||||
|
||||
systems: {
|
||||
begin: (events: Events) -> { [Entity]: thread },
|
||||
new: (callback: (dt: number) -> (), phase: Entity) -> Entity,
|
||||
},
|
||||
local sys: System
|
||||
local dt: number
|
||||
|
||||
phases: {
|
||||
RenderStepped: Entity,
|
||||
Heartbeat: Entity,
|
||||
},
|
||||
local jabby_scheduler = jabby.scheduler.create("Scheduler")
|
||||
|
||||
phase: (after: Entity) -> Entity,
|
||||
local a, b, c, d
|
||||
local function run()
|
||||
local id = sys.id
|
||||
jabby_scheduler:run(id, sys.callback, a, b, c, d)
|
||||
return nil
|
||||
end
|
||||
|
||||
debugging: boolean,
|
||||
}
|
||||
world:add(Heartbeat, Phase)
|
||||
world:set(Heartbeat, Event, RunService.Heartbeat)
|
||||
|
||||
local scheduler_new: (w: World, components: { [string]: Entity }) -> Scheduler
|
||||
world:add(PreSimulation, Phase)
|
||||
world:set(PreSimulation, Event, RunService.PreSimulation)
|
||||
|
||||
do
|
||||
local world: World
|
||||
local Disabled: Entity
|
||||
local System: Entity<System>
|
||||
local DependsOn: Entity
|
||||
local Phase: Entity
|
||||
local Event: Entity<RBXScriptSignal>
|
||||
world:add(PreAnimation, Phase)
|
||||
world:set(PreAnimation, Event, RunService.PreAnimation)
|
||||
|
||||
local scheduler
|
||||
table.insert(jabby.public, {
|
||||
class_name = "World",
|
||||
name = "MyWorld",
|
||||
world = world,
|
||||
debug = Name,
|
||||
entities = {},
|
||||
})
|
||||
|
||||
local RenderStepped
|
||||
local Heartbeat
|
||||
local PreAnimation
|
||||
local PreSimulation
|
||||
jabby.public.updated = true
|
||||
|
||||
local sys: System
|
||||
local dt
|
||||
table.insert(jabby.public, jabby_scheduler)
|
||||
|
||||
local function run()
|
||||
local id = sys.id
|
||||
scheduler:run(id, sys.callback, dt)
|
||||
end
|
||||
if RunService:IsClient() then
|
||||
world:add(PreRender, Phase)
|
||||
world:set(PreRender, Event, (RunService :: RunService).PreRender)
|
||||
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 connections = {}
|
||||
for event, systems in events do
|
||||
if not event then
|
||||
continue
|
||||
end
|
||||
local event_name = tostring(event)
|
||||
connections[event] = event:Connect(function(delta)
|
||||
debug.profilebegin(event_name)
|
||||
for _, s in systems do
|
||||
sys = s
|
||||
dt = delta
|
||||
local didNotYield, why = xpcall(function()
|
||||
for _ in run do
|
||||
break
|
||||
end
|
||||
end, debug.traceback)
|
||||
local function begin(events: { [RBXScriptSignal]: Systems })
|
||||
local connections = {}
|
||||
for event, systems in events do
|
||||
if not event then
|
||||
continue
|
||||
end
|
||||
local event_name = tostring(event)
|
||||
connections[event] = event:Connect(function(...)
|
||||
debug.profilebegin(event_name)
|
||||
for _, s in systems do
|
||||
sys = s
|
||||
a, b, c, d = ...
|
||||
|
||||
if didNotYield then
|
||||
continue
|
||||
end
|
||||
|
||||
if string.find(why, "thread is not yieldable") then
|
||||
panic(
|
||||
"Not allowed to yield in the systems."
|
||||
.. "\n"
|
||||
.. "System: "
|
||||
.. debug.info(s.callback, "n")
|
||||
.. " has been ejected"
|
||||
)
|
||||
continue
|
||||
end
|
||||
panic(why)
|
||||
for _ in run do
|
||||
break
|
||||
end
|
||||
debug.profileend()
|
||||
end)
|
||||
end
|
||||
return threads
|
||||
|
||||
end
|
||||
debug.profileend()
|
||||
end)
|
||||
end
|
||||
return connections
|
||||
end
|
||||
|
||||
local function scheduler_collect_systems_under_phase_recursive(systems, phase)
|
||||
local phase_name = world:get(phase, Name)
|
||||
for _, s in world:query(System):with(pair(DependsOn, phase)) do
|
||||
table.insert(systems, {
|
||||
id = scheduler:register_system({
|
||||
name = s.name,
|
||||
phase = phase_name,
|
||||
}),
|
||||
callback = s.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, components: { [string]: Entity })
|
||||
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
|
||||
|
||||
world:add(Heartbeat, Phase)
|
||||
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)
|
||||
|
||||
for name, component in components do
|
||||
world:set(component, Name, name)
|
||||
end
|
||||
|
||||
table.insert(jabby.public, {
|
||||
class_name = "World",
|
||||
name = "MyWorld",
|
||||
world = world,
|
||||
debug = Name,
|
||||
entities = {},
|
||||
local function scheduler_collect_systems_under_phase_recursive(systems, phase: Entity)
|
||||
local phase_name = world:get(phase, Name)
|
||||
for _, s in world:query(System):with(pair(DependsOn, phase)) do
|
||||
table.insert(systems, {
|
||||
id = jabby_scheduler:register_system({
|
||||
name = s.name,
|
||||
phase = phase_name,
|
||||
} :: any),
|
||||
callback = s.callback,
|
||||
})
|
||||
|
||||
jabby.public.updated = true
|
||||
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
|
||||
for after in world:query(Phase):with(pair(DependsOn, phase)):iter() 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(d: { after: Entity?, event: RBXScriptSignal? })
|
||||
local phase = world:entity()
|
||||
world:add(phase, Phase)
|
||||
local after = d.after
|
||||
if after then
|
||||
local dependency = pair(DependsOn, after :: Entity)
|
||||
world:add(phase, dependency)
|
||||
end
|
||||
|
||||
local event = d.event
|
||||
if event then
|
||||
world:set(phase, Event, event)
|
||||
end
|
||||
return phase
|
||||
end
|
||||
|
||||
local function scheduler_systems_new(callback: (any) -> (), phase: Entity?)
|
||||
local system = world:entity()
|
||||
world:set(system, System, { callback = callback, name = debug.info(callback, "n") })
|
||||
local depends_on = DependsOn :: jecs.Entity
|
||||
local p: Entity = phase or Heartbeat
|
||||
world:add(system, pair(depends_on, p))
|
||||
|
||||
return system
|
||||
end
|
||||
|
||||
return {
|
||||
new = scheduler_new,
|
||||
SYSTEM = scheduler_systems_new,
|
||||
BEGIN = begin,
|
||||
PHASE = scheduler_phase_new,
|
||||
COLLECT = scheduler_collect_systems_all,
|
||||
phases = {
|
||||
Heartbeat = Heartbeat,
|
||||
PreSimulation = PreSimulation,
|
||||
PreAnimation = PreAnimation,
|
||||
PreRender = PreRender
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,12 @@ local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|||
local blink = require(game:GetService("ServerScriptService").net)
|
||||
local jecs = require(ReplicatedStorage.ecs)
|
||||
local __ = jecs.Wildcard
|
||||
local std = ReplicatedStorage.std
|
||||
local ref = require(std.ref)
|
||||
local interval = require(std.interval)
|
||||
|
||||
local std = require(ReplicatedStorage.std)
|
||||
local ref = std.ref
|
||||
local interval = std.interval
|
||||
|
||||
local world: std.World = std.world
|
||||
local cts = std.components
|
||||
local world = require(std.world)
|
||||
local cts = require(std.components)
|
||||
|
||||
local Mob = cts.Mob
|
||||
local Transform = cts.Transform
|
||||
|
@ -20,13 +19,26 @@ local Velocity = cts.Velocity
|
|||
local Player = cts.Player
|
||||
local Character = cts.Character
|
||||
|
||||
local characters = world
|
||||
:query(Character)
|
||||
:with(Player)
|
||||
:cached()
|
||||
|
||||
|
||||
local moving_mobs = world
|
||||
:query(Transform, Velocity)
|
||||
:with(Mob)
|
||||
:cached()
|
||||
|
||||
|
||||
local function mobsMove(dt: number)
|
||||
local targets = {}
|
||||
for _, character in world:query(Character):with(Player):iter() do
|
||||
|
||||
for _, character in characters:iter() do
|
||||
table.insert(targets, (character.PrimaryPart :: Part).Position)
|
||||
end
|
||||
|
||||
for mob, transform, v in world:query(Transform, Velocity):with(Mob):iter() do
|
||||
for mob, transform, v in moving_mobs:iter() do
|
||||
local cf = transform.new
|
||||
local p = cf.Position
|
||||
|
||||
|
@ -53,21 +65,24 @@ end
|
|||
|
||||
local throttle = interval(5)
|
||||
|
||||
local function spawnMobs()
|
||||
local function spawnMobs()
|
||||
if throttle() then
|
||||
local p = Vector3.new(0, 5, 0)
|
||||
local cf = CFrame.new(p)
|
||||
local v = 5
|
||||
|
||||
local id = ref():set(Velocity, v):set(Transform, { new = cf }):add(Mob).id()
|
||||
local e = world:entity()
|
||||
world:set(e, Velocity, v)
|
||||
world:set(e, Transform, { new = cf })
|
||||
world:add(e, Mob)
|
||||
|
||||
blink.SpawnMob.FireAll(id, cf, v)
|
||||
blink.SpawnMob.FireAll(e, cf, v)
|
||||
end
|
||||
end
|
||||
|
||||
return function(scheduler: std.Scheduler)
|
||||
local phases = scheduler.phases
|
||||
local system_new = scheduler.systems.new
|
||||
system_new(mobsMove, phases.Heartbeat)
|
||||
system_new(spawnMobs, phases.Heartbeat)
|
||||
end
|
||||
local scheduler = require(std.scheduler)
|
||||
|
||||
scheduler.SYSTEM(spawnMobs)
|
||||
scheduler.SYSTEM(mobsMove)
|
||||
|
||||
return 0
|
|
@ -1,43 +1,40 @@
|
|||
local Players = game:GetService("Players")
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
|
||||
local std = require(ReplicatedStorage.std)
|
||||
local ref = std.ref
|
||||
local collect = std.collect
|
||||
local std = ReplicatedStorage.std
|
||||
local ref = require(std.ref)
|
||||
local collect = require(std.collect)
|
||||
|
||||
local cts = std.components
|
||||
local cts = require(std.components)
|
||||
local world = require(std.world)
|
||||
local Player = cts.Player
|
||||
local Character = cts.Character
|
||||
|
||||
local playersAdded = collect(Players.PlayerAdded)
|
||||
local playersRemoved = collect(Players.PlayerRemoving)
|
||||
local world: std.World = std.world
|
||||
|
||||
local conn = {}
|
||||
|
||||
local function players()
|
||||
for _, player in playersAdded do
|
||||
world:set(std.world:entity(), cts.Transform)
|
||||
|
||||
local e = ref(player.UserId):set(Player, player)
|
||||
local characterAdd = player.CharacterAdded
|
||||
conn[e.id()] = characterAdd:Connect(function(rig)
|
||||
while rig.Parent ~= workspace do
|
||||
task.wait()
|
||||
end
|
||||
e:set(Character, rig)
|
||||
end)
|
||||
end
|
||||
|
||||
for _, player in playersRemoved do
|
||||
local id = ref(player.UserId):clear().id()
|
||||
conn[id]:Disconnect()
|
||||
conn[id] = nil
|
||||
end
|
||||
local function playersAdded(player: Player)
|
||||
local e = ref(player.UserId)
|
||||
world:set(e, Player, player)
|
||||
local characterAdd = player.CharacterAdded
|
||||
conn[e] = characterAdd:Connect(function(rig)
|
||||
while rig.Parent ~= workspace do
|
||||
task.wait()
|
||||
end
|
||||
world:set(e, Character, rig)
|
||||
end)
|
||||
end
|
||||
|
||||
return function(scheduler: std.Scheduler)
|
||||
local phases = scheduler.phases
|
||||
local system_new = scheduler.systems.new
|
||||
system_new(players, phases.Heartbeat)
|
||||
local function playersRemoved(player: Player)
|
||||
local e = ref(player.UserId)
|
||||
world:clear(e)
|
||||
local connection = conn[e]
|
||||
connection:Disconnect()
|
||||
conn[e] = nil
|
||||
end
|
||||
|
||||
local scheduler = require(std.scheduler)
|
||||
local phases = require(std.phases)
|
||||
scheduler.SYSTEM(playersAdded, phases.PlayerAdded)
|
||||
scheduler.SYSTEM(playersRemoved, phases.PlayerRemoved)
|
||||
|
||||
return 0
|
|
@ -1,20 +1,22 @@
|
|||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local blink = require(ReplicatedStorage.net)
|
||||
local std = require(ReplicatedStorage.std)
|
||||
local world = std.world
|
||||
local ref = std.ref
|
||||
local std = ReplicatedStorage.std
|
||||
local world = require(std.world)
|
||||
local ref = require(std.ref)
|
||||
|
||||
local cts = std.components
|
||||
local cts = require(std.components)
|
||||
|
||||
local Model = cts.Model
|
||||
local Transform = cts.Transform
|
||||
|
||||
local moving_models = world:query(Transform, Model):cached()
|
||||
local function move(dt: number)
|
||||
for _, transform, model in world:query(Transform, Model):iter() do
|
||||
for _, transform, model in moving_models:iter() do
|
||||
local cf = transform.new
|
||||
if cf ~= transform.old then
|
||||
local origo = model.PrimaryPart.CFrame
|
||||
model.PrimaryPart.CFrame = origo:Lerp(cf, 1)
|
||||
local part = model.PrimaryPart :: BasePart
|
||||
local origo = part.CFrame
|
||||
part.CFrame = origo:Lerp(cf, 1)
|
||||
transform.old = cf
|
||||
end
|
||||
end
|
||||
|
@ -22,8 +24,8 @@ end
|
|||
|
||||
local function syncTransforms()
|
||||
for _, id, cf in blink.UpdateTransform.Iter() do
|
||||
local e = ref("server-" .. id)
|
||||
local transform = e:get(cts.Transform)
|
||||
local e = ref("server-" .. tostring(id))
|
||||
local transform = world:get(e, Transform)
|
||||
if not transform then
|
||||
continue
|
||||
end
|
||||
|
@ -31,9 +33,9 @@ local function syncTransforms()
|
|||
end
|
||||
end
|
||||
|
||||
return function(scheduler: std.Scheduler)
|
||||
local phases = scheduler.phases
|
||||
local system_new = scheduler.systems.new
|
||||
system_new(move, phases.Heartbeat)
|
||||
system_new(syncTransforms, phases.RenderStepped)
|
||||
end
|
||||
local scheduler = require(std.scheduler)
|
||||
|
||||
scheduler.SYSTEM(move)
|
||||
scheduler.SYSTEM(syncTransforms)
|
||||
|
||||
return 0
|
|
@ -1,9 +1,9 @@
|
|||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local blink = require(ReplicatedStorage.net)
|
||||
local std = require(ReplicatedStorage.std)
|
||||
local ref = std.ref
|
||||
local world = std.world
|
||||
local cts = std.components
|
||||
local std = ReplicatedStorage.std
|
||||
local ref = require(std.ref)
|
||||
local world = require(std.world)
|
||||
local cts = require(std.components)
|
||||
|
||||
local function syncMobs()
|
||||
for _, id, cf, vel in blink.SpawnMob.Iter() do
|
||||
|
@ -16,16 +16,16 @@ local function syncMobs()
|
|||
part.Parent = model
|
||||
model.Parent = workspace
|
||||
|
||||
ref("server-" .. id)
|
||||
:set(cts.Transform, { new = cf, old = cf })
|
||||
:set(cts.Velocity, vel)
|
||||
:set(cts.Model, model)
|
||||
:add(cts.Mob)
|
||||
local e = ref("server-" .. tostring(id))
|
||||
world:set(e, cts.Transform, { new = cf, old = cf })
|
||||
world:set(e, cts.Velocity, vel)
|
||||
world:set(e, cts.Model, model)
|
||||
world:add(e, cts.Mob)
|
||||
end
|
||||
end
|
||||
|
||||
return function(scheduler: std.Scheduler)
|
||||
local phases = scheduler.phases
|
||||
local system_new = scheduler.systems.new
|
||||
system_new(syncMobs, phases.RenderStepped)
|
||||
end
|
||||
local scheduler = require(std.scheduler)
|
||||
scheduler.SYSTEM(syncMobs)
|
||||
|
||||
return 0
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local std = ReplicatedStorage.std
|
||||
local world = require(std.world)
|
||||
|
||||
local A = world:component()
|
||||
local B = world:component()
|
||||
local C = world:component()
|
||||
local D = world:component()
|
||||
|
||||
local function flip()
|
||||
return math.random() >= 0.15
|
||||
end
|
||||
|
||||
for i = 1, 2^8 do
|
||||
local e = world:entity()
|
||||
if flip() then
|
||||
world:set(e, A, true)
|
||||
end
|
||||
if flip() then
|
||||
world:set(e, B, true)
|
||||
end
|
||||
if flip() then
|
||||
world:set(e, C, true)
|
||||
end
|
||||
if flip() then
|
||||
world:set(e, D, true)
|
||||
end
|
||||
end
|
||||
|
||||
local function uncached()
|
||||
for _ in world:query(A, B, C, D) do
|
||||
end
|
||||
end
|
||||
|
||||
local q = world:query(A, B, C, D):cached()
|
||||
local function cached()
|
||||
for _ in q:iter() do
|
||||
end
|
||||
end
|
||||
|
||||
local scheduler = require(std.scheduler)
|
||||
scheduler.SYSTEM(uncached)
|
||||
scheduler.SYSTEM(cached)
|
||||
return 0
|
Loading…
Reference in a new issue