Start typing to search packages!
sapphire-ecr
By @mark-marks
Roblox
Mirroredsapphire-ecr
A lightweight scheduler + niceties (replication, etc.) for centau/ecr for Mark-Marks/sapphire
Installation
- Install it with wally
[dependencies]
sapphire_ecr = "mark-marks/sapphire-ecr@LATEST" # replace LATEST with the latest version
wally install- Extend sapphire with it
local sapphire_ecr = require("@pkg/sapphire_ecr")
sapphire
:use(sapphire_ecr)
API
Exports
.registry
type registry = ecr.Registry
.stepped_systems
Readonly!
type stepped_systems = { system }
.heartbeat_systems
Readonly!
type heartbeat_systems = { system }
.render_stepped_systems
Readonly!
type render_stepped_systems = { system }
.ecr
Reexport of ecr
SapphireEcr.ecr = ecr
Types
loop_type
type loop_type = "Stepped" | "Heartbeat" | "RenderStepped"
system
type system = {
--- Fires every `RunService.Stepped`
runner: (delta_time: number) -> (),
--- 1 = lowest priority
priority: number?,
--- Defaults to "Stepped"
loop_type: loop_type?,
}
spawner<T...>
type spawner<T...> = {
spawn: (T...) -> ecr.entity,
spawn_with_handle: (T...) -> ecr.Handle,
}
raw_data
map<component_id, map<entity_id, component_value>>
Migrated from map<entity_id, map<component_id, component_value>> to do SoA instead of AoS
type raw_data = {
[number]: { [ecr.entity]: unknown },
}
replicator
type replicator = {
get_full_data: () -> raw_data,
calculate_difference: () -> raw_data?,
apply_difference: (difference: raw_data) -> (),
}
entity
type entity = ecr.entity
Signal<T...>
type Signal<T...> = ecr.Signal<T...>
Connection
type Connection = ecr.Connection
Handle
type Handle = ecr.Handle
View<T...>
type View<T...> = ecr.View<T...>
Observer<T...>
type Observer<T...> = ecr.Observer<T...>
Group<T...>
type Group<T...> = ecr.Group<T...>
Registry
type Registry = ecr.Registry
Queue<T...>
type Queue<T...> = ecr.Queue<T...>
Registered methods
.system()
Registers a system.
(
singleton: sapphire.singleton
)
Singletons need to follow the following format:
type format = {
system: (registry: ecr.Registry) -> (delta_time: number) -> (),
--- Defaults to 1
priority: number?,
--- Defaults to `Stepped`
loop_type: loop_type?,
}
Systems on the server that use RenderStepped will be migrated to Heartbeat.
Functions
.spawn_entity()
Creates an entity and returns its id.
() -> ecr.entity
.spawn_entity_with_handle()
Creates an entity and returns a handle to it.
() -> ecr.Handle
.create_spawner()
Creates a spawner.
<T...>(
...: T...
) -> spawner<T...>
local spawner = sapphire_ecr.create_spawner(components.part, components.velocity, components.position)
for _ = 1, 1000 do
spawner.spawn(part_template:Clone(), Vector3.zero, Vector3.zero)
end
.create_replicator
Creates a "replicator"
(
...
) -> replicator
A replicator keeps track of all entities with the passed components and their values -
whenever a component is changed (add, change, remove) and the replicator listens to it, it's also changed within the contained raw data.
The developer can then calculate the difference on the server and send it to the client every time,
on which the difference is then applied to the registry.
Albeit it's called a replicator, it doesn't replicate the data by itself.
It allows the developer to use any networking libary to replicate the changes.
-- server
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
function singleton.system()
return function()
local difference = replicator.calculate_difference()
-- There might not be any difference
if not difference then
return
end
data_replication_event.send_to_all(difference)
end
end
-- client
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
function singleton.system()
return function()
for _, difference in data_replication_event.poll() do
replicator.apply_difference(difference)
end
end
end
spawner<T...>
.spawn()
Creates an entity with the given components.
(
T...
) -> ecr.entity
.spawn_with_handle()
Creates an entity with the given components and returns a handle to it.
(
T...
) -> ecr.Handle
replicator
A replicator keeps track of all entities with the passed components and their values -
whenever a component is changed (add, change, remove) and the replicator listens to it, it's also changed within the contained raw data.
The developer can then calculate the difference on the server and send it to the client every time,
on which the difference is then applied to the registry.
Albeit it's called a replicator, it doesn't replicate the data by itself.
It allows the developer to use any networking libary to replicate the changes.
-- server
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
function singleton.system()
return function()
local difference = replicator.calculate_difference()
-- There might not be any difference
if not difference then
return
end
data_replication_event.send_to_all(difference)
end
end
-- client
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
function singleton.system()
return function()
for _, difference in data_replication_event.poll() do
replicator.apply_difference(difference)
end
end
end
.get_full_data()
Gets the full data representing the entire registry. Useful for initial replication to every player.
() -> raw_data
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
Players.PlayerAdded:Connect(function(player)
data_replication_event.send_to(player, replicator.get_full_data())
end)
.calculate_difference()
Calculates the difference between last sent data and currently stored data.
() -> raw_data?
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
function singleton.system()
return function()
local difference = replicator.calculate_difference()
-- There might not be any difference
if not difference then
return
end
data_replication_event.send_to_all(difference)
end
end
.apply_difference()
Applies the difference to the current data.
(
difference: raw_data
) -> ()
local replicator = sapphire_ecr.create_replicator(component_a, component_b, ...)
function singleton.system()
return function()
for _, difference in data_replication_event.poll()
replicator.apply_difference(difference)
end
end
end
Package Details
Install command (Click to copy)
Version
0.1.5
License
MIT
Safe for commercial use
Automated license review — not legal advice.
