ImmortalWhite

Untitled

Nov 28th, 2025
249
0
13 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 3.91 KB | None | 0 0
  1. --!strict
  2. --!optimize 2
  3.  
  4. export type SystemPhase = "pre" | "update" | "post"
  5. export type SystemFn = (world: World, dt: number) -> ()
  6. export type ComponentTable = { [number]: any }
  7.  
  8. export type World = {
  9.     _nextEntityId: number,
  10.     _alive: { [number]: boolean },
  11.     _components: { [string]: ComponentTable },
  12.     _systemsPre: { SystemFn },
  13.     _systemsUpdate: { SystemFn },
  14.     _systemsPost: { SystemFn },
  15.  
  16.     Spawn: (self: World) -> number,
  17.     Despawn: (self: World, entityId: number) -> (),
  18.  
  19.     HasEntity: (self: World, entityId: number) -> boolean,
  20.  
  21.     GetComponentTable: (self: World, name: string) -> ComponentTable,
  22.     AddComponent: (self: World, entityId: number, name: string, data: any) -> (),
  23.     GetComponent: (self: World, entityId: number, name: string) -> any?,
  24.     RemoveComponent: (self: World, entityId: number, name: string) -> (),
  25.  
  26.     RegisterSystem: (self: World, phase: SystemPhase, system: SystemFn) -> (),
  27.     Step: (self: World, dt: number) -> (),
  28.  
  29.     ForEach: (self: World, name: string, fn: (entityId: number, data: any) -> ()) -> (),
  30. }
  31.  
  32. local ECSWorld = {}
  33.  
  34. local function runSystems(list: { SystemFn }, world: World, dt: number)
  35.     local count = #list
  36.     for i = 1, count do
  37.         list[i](world, dt)
  38.     end
  39. end
  40.  
  41. local function spawnEntity(self: World): number
  42.     local id = self._nextEntityId + 1
  43.     self._nextEntityId = id
  44.     self._alive[id] = true
  45.     return id
  46. end
  47.  
  48. local function despawnEntity(self: World, entityId: number)
  49.     if not self._alive[entityId] then
  50.         return
  51.     end
  52.     self._alive[entityId] = nil
  53.     local components = self._components
  54.     for _, tableForComponent in pairs(components) do
  55.         tableForComponent[entityId] = nil
  56.     end
  57. end
  58.  
  59. local function hasEntity(self: World, entityId: number): boolean
  60.     return self._alive[entityId] == true
  61. end
  62.  
  63. local function getComponentTable(self: World, name: string): ComponentTable
  64.     local components = self._components
  65.     local tbl = components[name]
  66.     if tbl ~= nil then
  67.         return tbl
  68.     end
  69.     local newTbl: ComponentTable = {}
  70.     components[name] = newTbl
  71.     return newTbl
  72. end
  73.  
  74. local function addComponent(self: World, entityId: number, name: string, data: any)
  75.     if not self._alive[entityId] then
  76.         return
  77.     end
  78.     local tbl = getComponentTable(self, name)
  79.     tbl[entityId] = data
  80. end
  81.  
  82. local function getComponent(self: World, entityId: number, name: string): any?
  83.     local tbl = self._components[name]
  84.     if tbl == nil then
  85.         return nil
  86.     end
  87.     return tbl[entityId]
  88. end
  89.  
  90. local function removeComponent(self: World, entityId: number, name: string)
  91.     local tbl = self._components[name]
  92.     if tbl == nil then
  93.         return
  94.     end
  95.     tbl[entityId] = nil
  96. end
  97.  
  98. local function registerSystem(self: World, phase: SystemPhase, system: SystemFn)
  99.     if phase == "pre" then
  100.         local list = self._systemsPre
  101.         list[#list + 1] = system
  102.     elseif phase == "update" then
  103.         local list = self._systemsUpdate
  104.         list[#list + 1] = system
  105.     else
  106.         local list = self._systemsPost
  107.         list[#list + 1] = system
  108.     end
  109. end
  110.  
  111. local function step(self: World, dt: number)
  112.     if dt <= 0 then
  113.         return
  114.     end
  115.     runSystems(self._systemsPre, self, dt)
  116.     runSystems(self._systemsUpdate, self, dt)
  117.     runSystems(self._systemsPost, self, dt)
  118. end
  119.  
  120. local function forEach(self: World, name: string, fn: (entityId: number, data: any) -> ())
  121.     local tbl = self._components[name]
  122.     if tbl == nil then
  123.         return
  124.     end
  125.     for entityId, data in tbl do
  126.         if self._alive[entityId] then
  127.             fn(entityId, data)
  128.         end
  129.     end
  130. end
  131.  
  132. function ECSWorld.new(): World
  133.     local world: World = {
  134.         _nextEntityId = 0,
  135.         _alive = {},
  136.         _components = {},
  137.         _systemsPre = {},
  138.         _systemsUpdate = {},
  139.         _systemsPost = {},
  140.  
  141.         Spawn = spawnEntity,
  142.         Despawn = despawnEntity,
  143.         HasEntity = hasEntity,
  144.  
  145.         GetComponentTable = getComponentTable,
  146.         AddComponent = addComponent,
  147.         GetComponent = getComponent,
  148.         RemoveComponent = removeComponent,
  149.  
  150.         RegisterSystem = registerSystem,
  151.         Step = step,
  152.  
  153.         ForEach = forEach,
  154.     }
  155.  
  156.     return world
  157. end
  158.  
  159. return ECSWorld
  160.  
Advertisement
Add Comment
Please, Sign In to add comment