first commit
This commit is contained in:
commit
5302ecc6cc
43 changed files with 2530 additions and 0 deletions
8
src/ReplicatedStorage/ecs/systems/client/test.ts
Normal file
8
src/ReplicatedStorage/ecs/systems/client/test.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
/**
|
||||
* A test system that does nothing.
|
||||
*/
|
||||
function test(): void {
|
||||
// A test system.
|
||||
}
|
||||
|
||||
export = test
|
108
src/ReplicatedStorage/ecs/systems/index.ts
Normal file
108
src/ReplicatedStorage/ecs/systems/index.ts
Normal file
|
@ -0,0 +1,108 @@
|
|||
import { AnySystem, Debugger, Loop } from "@rbxts/matter"
|
||||
import { Context, HotReloader } from "@rbxts/rewire"
|
||||
import { ServerScriptService } from "@rbxts/services"
|
||||
import { Host } from "ReplicatedStorage/hosts"
|
||||
|
||||
const ERROR_CONTAINER = "%s container not found"
|
||||
|
||||
const shared = script.FindFirstChild("shared")
|
||||
const client = script.FindFirstChild("client")
|
||||
const server = ServerScriptService.FindFirstChild("goopler")
|
||||
?.FindFirstChild("ecs")
|
||||
?.FindFirstChild("systems")
|
||||
?.FindFirstChild("server")
|
||||
|
||||
let firstRunSystems: AnySystem[] | undefined = []
|
||||
let hotReloader: HotReloader | undefined
|
||||
|
||||
/**
|
||||
* Starts the system loader.
|
||||
*
|
||||
* Loads systems for the specified container into the provided loop and
|
||||
* debugger. Systems are hot reloaded as they are changed.
|
||||
*
|
||||
* @param container - The container to load
|
||||
* @param loop - The ECS loop to load systems into
|
||||
* @param debug - The debugger to load systems into
|
||||
*
|
||||
* @throws "[container] container not found"
|
||||
* This is thrown when a container necessary for the provided host doesn't
|
||||
* exist.
|
||||
*/
|
||||
export function start<T extends unknown[]>(container: Host, loop: Loop<T>, debug: Debugger): void {
|
||||
if (!firstRunSystems) return
|
||||
|
||||
const containers: Instance[] = []
|
||||
if (!shared) throw string.format(ERROR_CONTAINER, "Shared")
|
||||
containers.push(shared)
|
||||
|
||||
if (container === Host.All || container === Host.Client) {
|
||||
if (!client) throw string.format(ERROR_CONTAINER, "Client")
|
||||
containers.push(client)
|
||||
}
|
||||
if (container === Host.All || container === Host.Server) {
|
||||
if (!server) throw string.format(ERROR_CONTAINER, "Server")
|
||||
containers.push(server)
|
||||
}
|
||||
|
||||
const systemsByModule: Map<ModuleScript, AnySystem> = new Map()
|
||||
|
||||
function load(module: ModuleScript, context: Context): void {
|
||||
if (
|
||||
module.Name.match("%.spec$")[0] !== undefined ||
|
||||
module.Name.match("%.dev$")[0] !== undefined
|
||||
)
|
||||
return
|
||||
const original = context.originalModule
|
||||
const previous = systemsByModule.get(original)
|
||||
const [ok, required] = pcall(require, module)
|
||||
|
||||
if (!ok) {
|
||||
warn("Error when hot-reloading system", module.Name, required)
|
||||
return
|
||||
}
|
||||
|
||||
// Here we don't know that this is necessarily a system, but we let matter
|
||||
// handle this at runtime.
|
||||
const system = required as AnySystem
|
||||
|
||||
if (firstRunSystems) {
|
||||
firstRunSystems.push(system)
|
||||
} else if (previous) {
|
||||
loop.replaceSystem(previous, system)
|
||||
debug.replaceSystem(previous, system)
|
||||
} else {
|
||||
loop.scheduleSystem(system)
|
||||
}
|
||||
|
||||
systemsByModule.set(original, system)
|
||||
}
|
||||
|
||||
function unload(_: ModuleScript, context: Context): void {
|
||||
if (context.isReloading) return
|
||||
|
||||
const original = context.originalModule
|
||||
const previous = systemsByModule.get(original)
|
||||
if (previous) {
|
||||
loop.evictSystem(previous)
|
||||
systemsByModule.delete(original)
|
||||
}
|
||||
}
|
||||
|
||||
hotReloader = new HotReloader()
|
||||
for (const container of containers) {
|
||||
hotReloader.scan(container, load, unload)
|
||||
}
|
||||
|
||||
loop.scheduleSystems(firstRunSystems)
|
||||
firstRunSystems = undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops loading systems.
|
||||
*/
|
||||
export function stop(): void {
|
||||
if (firstRunSystems) return
|
||||
firstRunSystems = []
|
||||
hotReloader?.destroy()
|
||||
}
|
19
src/ReplicatedStorage/ecs/systems/shared/lifetimesExpire.ts
Normal file
19
src/ReplicatedStorage/ecs/systems/shared/lifetimesExpire.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { World, useDeltaTime } from "@rbxts/matter"
|
||||
import { Lifetime } from "ReplicatedStorage/ecs/components"
|
||||
|
||||
/**
|
||||
* @todo
|
||||
*/
|
||||
function updateIdAttribute(world: World): void {
|
||||
for (const [id, lifetime] of world.query(Lifetime)) {
|
||||
const newLifetime = lifetime.patch({ elapsed: lifetime.elapsed + useDeltaTime() })
|
||||
|
||||
if (os.clock() > lifetime.spawnedAt + lifetime.length) {
|
||||
world.despawn(id)
|
||||
} else {
|
||||
world.insert(id, newLifetime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export = updateIdAttribute
|
25
src/ReplicatedStorage/ecs/systems/shared/trackMemory.ts
Normal file
25
src/ReplicatedStorage/ecs/systems/shared/trackMemory.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
import { DebugWidgets, World } from "@rbxts/matter"
|
||||
import { Stats } from "@rbxts/services"
|
||||
|
||||
const startInstanceCount = Stats.InstanceCount
|
||||
const startMemory = Stats.GetTotalMemoryUsageMb()
|
||||
const startTime = os.clock()
|
||||
|
||||
function trackMemory(world: World, state: object, ui: DebugWidgets): void {
|
||||
const currentInstanceCount = Stats.InstanceCount
|
||||
const currentMemory = Stats.GetTotalMemoryUsageMb()
|
||||
|
||||
ui.window("Memory Stats", () => {
|
||||
ui.label(`Instances: ${currentInstanceCount}`)
|
||||
|
||||
ui.label(`Gained Instances: ${currentInstanceCount - startInstanceCount}`)
|
||||
|
||||
ui.label(`Memory: ${string.format("%.1f", currentMemory)}`)
|
||||
|
||||
ui.label(`Gained Memory: ${string.format("%.1f", currentMemory - startMemory)}`)
|
||||
|
||||
ui.label(`Time: ${string.format("%.1f", os.clock() - startTime)}`)
|
||||
})
|
||||
}
|
||||
|
||||
export = trackMemory
|
|
@ -0,0 +1,16 @@
|
|||
import { World } from "@rbxts/matter"
|
||||
import { Model } from "ReplicatedStorage/ecs/components"
|
||||
import { getIdAttribute } from "ReplicatedStorage/idAttribute"
|
||||
|
||||
/**
|
||||
* A system that updates the ID of {@link Model | Models}.
|
||||
*
|
||||
* @param world - The {@link World} the system operates on
|
||||
*/
|
||||
function updateIdAttribute(world: World): void {
|
||||
for (const [id, record] of world.queryChanged(Model)) {
|
||||
record.new?.model?.SetAttribute(getIdAttribute(), id)
|
||||
}
|
||||
}
|
||||
|
||||
export = updateIdAttribute
|
Loading…
Add table
Add a link
Reference in a new issue