aboutsummaryrefslogtreecommitdiff
path: root/src/ecs
diff options
context:
space:
mode:
authorAlex Pickering <alex@cogarr.net>2026-02-01 13:14:32 -0600
committerAlexander M Pickering <alex@cogarr.net>2026-02-01 13:14:32 -0600
commit3a975db66a3711f34e8b64bb27a8eaca79fdeca9 (patch)
treefcc12f8f9d638ff575c1963796de76b7628854b4 /src/ecs
downloadggj26-3a975db66a3711f34e8b64bb27a8eaca79fdeca9.tar.gz
ggj26-3a975db66a3711f34e8b64bb27a8eaca79fdeca9.tar.bz2
ggj26-3a975db66a3711f34e8b64bb27a8eaca79fdeca9.zip
Initial commitHEADmaster
Diffstat (limited to 'src/ecs')
-rw-r--r--src/ecs/char_controller.moon70
-rw-r--r--src/ecs/client_networked.moon19
-rw-r--r--src/ecs/component.moon16
-rw-r--r--src/ecs/graphics.moon67
-rw-r--r--src/ecs/networked.moon71
-rw-r--r--src/ecs/player_graphic.moon66
-rw-r--r--src/ecs/predicted.moon25
-rw-r--r--src/ecs/script.moon16
8 files changed, 350 insertions, 0 deletions
diff --git a/src/ecs/char_controller.moon b/src/ecs/char_controller.moon
new file mode 100644
index 0000000..e5e3db7
--- /dev/null
+++ b/src/ecs/char_controller.moon
@@ -0,0 +1,70 @@
+ScriptComponent = require("ecs.script")
+win = require("window")
+log = require("log")
+world = require("world")
+
+class CharacterControllerComponent extends ScriptComponent
+ new: (name, properties, netc_name) =>
+ log.info("Creating new character controller", {"ecs"})
+ properties.script = () ->
+ --log.info("Character controller running", {"ecs"})
+ any_change = false
+ assert(@net.__class.__name == "ClientNetworkedComponent", "Wrong net component, was a " .. @net.__class.__name)
+ assert(@pred,"No predicted component")
+ assert(world.network, "Network must be created before CharacterControllerComponent starts running")
+ if win\key_pressed("w")
+ log.info("Key down w",{"net","ecs","client","player"})
+ @net.properties.acc[2] = 1
+ any_change = true
+ elseif win\key_released("w")
+ log.info("Key up w",{"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[2] = 0
+ if win\key_pressed("s")
+ log.info("Key down s",{"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[2] = -1
+ elseif win\key_released("s")
+ log.info("Key up s",{"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[2] = 0
+ if win\key_pressed("a")
+ log.info("Key down a", {"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[1] = -1
+ elseif win\key_released("a")
+ log.info("Key up a", {"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[1] = 0
+ if win\key_pressed("d")
+ log.info("Key down d", {"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[1] = 1
+ elseif win\key_released("d")
+ log.info("Key up d", {"net","ecs","client","player"})
+ any_change = true
+ @net.properties.acc[1] = 0
+
+ -- We can't actually update the network on the client,
+ -- but we still want to do predicted movement
+ if any_change
+ @net.properties.last_update = am.eval_js("Date.now();")
+ @net.properties.pos = @pred.properties.pos
+ --@net.properties.vel = @pred.properties.vel
+ world.network\send("SuggestPlayerUpdate",{
+ acc: @net.properties.acc
+ vel: @net.properties.vel
+ pos: @pred.properties.pos
+ })
+ return false
+ --print("Running character controller",win\key_pressed("w"))
+ @netc_name = netc_name
+ super(name, properties)
+ join: (entity) =>
+ log.debug("Components was:" .. tostring(entity.components), {"ecs"})
+ @net = entity\get(@netc_name)
+ @pred = entity\get("pred")
+ assert(@net, "Must have added network component: " .. @netc_name .. ".")
+ super(entity)
+
+CharacterControllerComponent
diff --git a/src/ecs/client_networked.moon b/src/ecs/client_networked.moon
new file mode 100644
index 0000000..fc70dc2
--- /dev/null
+++ b/src/ecs/client_networked.moon
@@ -0,0 +1,19 @@
+world = require("world")
+log = require("log")
+NetworkedComponent = require("ecs.networked")
+Component = require("ecs.component")
+
+class ClientNetworkedComponent extends Component
+ new: (name, properties) =>
+ log.info("Creating client networked info", {"client"})
+ super(name, properties)
+ listen_events: () ->
+ assert(wold.network, "world.network needs to be set before hooking events")
+ world.network\listen("create","client_network_component",(hubid, data) ->
+ error("ClientNetworkComponent create received:".. tostring(data))
+ )
+ world.network\listen("update","client_network_component",(hubid, data) ->
+ error("ClientNetworkComponent update received:".. tostring(data))
+ )
+
+ClientNetworkedComponent
diff --git a/src/ecs/component.moon b/src/ecs/component.moon
new file mode 100644
index 0000000..6ce16bd
--- /dev/null
+++ b/src/ecs/component.moon
@@ -0,0 +1,16 @@
+-- Base component class of the ECS
+class Component
+ depends: {}
+ new: (name, properties) =>
+ @name = name
+ @properties = properties or {}
+ join: (e, cid) =>
+ @
+ post_join: (e, cid) =>
+ @
+ leave: (e) =>
+ @
+ __tostring: () =>
+ return string.format("%s<%s> {\n%s\n}",@@__name,@name or "no name given",tostring(@properties))
+
+Component
diff --git a/src/ecs/graphics.moon b/src/ecs/graphics.moon
new file mode 100644
index 0000000..66e5e80
--- /dev/null
+++ b/src/ecs/graphics.moon
@@ -0,0 +1,67 @@
+Component = require("ecs.component")
+sprites = require("sprites")
+gworld = require("shaders.world")
+world = require("world")
+log = require("log")
+
+sd = sprites.floor
+w1 = sprites.wall1_diffuse
+
+panel = {
+ vec3(0, 1, 0.4),
+ vec3(1, 1, 0.4),
+ vec3(1, 0, 0.4),
+ vec3(1, 0, 0.4),
+ vec3(0, 0, 0.4),
+ vec3(0, 1, 0.4)
+}
+
+class GraphicsComponent extends Component
+ new: (name, properties) =>
+ --assert(properties and properties.node , "Failed to find node for graphics component")
+ --assert(@@node, ".node not set for GraphicsComponent")
+ assert(world.geom_view,".geom_view not set for world")
+ assert(world.uv_view, ".uv_view not set for world")
+ --@node = properties.node
+ super(name, properties)
+ static: () =>
+ @@static
+ join: () =>
+ --log.info("Joining with graphics component" .. tostring(@node), {"graphics"})
+ --@@node\append(@node)
+ gworld.add(@)
+ leave: () =>
+ gworld.remove(@)
+ --@@node\remove(@node)
+ node: () =>
+ error("Tried to access graphic component's .node")
+ --@properties.node
+ tris: () =>
+ 2
+ populate_buf: (geom_view, uv_view, offset) =>
+ assert(@properties.graphic, "Graphics component needs a graphic")
+ assert(offset == 1, "Offset was " .. tostring(offset))
+ log.info("Populating:" .. tostring(offset) .. ":" .. tostring(@properties.graphic), {"graphic","ecs"})
+ log.info(debug.traceback(), {"graphic","ecs"})
+ log.info("Populating with:" .. tostring(panel),{"graphic","ecs"})
+ geom_view\set(panel, offset, @tris! * 3)
+ @geom_view = geom_view
+ @uv_view = uv_view
+ @offset = offset
+ uv = @properties.graphic
+ uv_view[1] = vec4(uv.s1,uv.t1,1,1)
+ uv_view[2] = vec4(uv.s1,uv.t2,1,1)
+ uv_view[3] = vec4(uv.s2,uv.t2,1,1)
+ uv_view[4] = vec4(uv.s2,uv.t2,1,1)
+ uv_view[5] = vec4(uv.s2,uv.t1,1,1)
+ uv_view[6] = vec4(uv.s1,uv.t1,1,1)
+ --error("Graphics components must override .populate_buf()")
+ move: (move_off) =>
+ for i, set in ipairs(panel)
+ @geom_view[@offset + i - 1] = @geom_view[@offset + i - 1] + move_off
+ moveto: (loc) =>
+ assert(@offset, "Moveto called before populate_buf")
+ for i, set in ipairs(panel)
+ @geom_view[@offset + i - 1] = loc + set
+
+GraphicsComponent
diff --git a/src/ecs/networked.moon b/src/ecs/networked.moon
new file mode 100644
index 0000000..6673a7d
--- /dev/null
+++ b/src/ecs/networked.moon
@@ -0,0 +1,71 @@
+Component = require("ecs.component")
+world = require("world")
+log = require("log")
+
+network_log = {}
+
+class NetworkedComponent extends Component
+ @q: {}
+
+ new: (name, properties) =>
+ assert(properties.id == nil, "networked component's id needs to be nil")
+ assert(properties.name == nil, "network component's name needs to be nil")
+ properties.id = world.level_sync.entid
+ world.level_sync.entid += 1
+ nwc = @
+ update = (key, value) =>
+ if not world.hub
+ error("Tried to update network on the client")
+ return
+ if not properties[key]
+ error("Trying to set key not defined in properties:" .. key)
+ properties[key] = value
+ properties.last_update = am.eval_js("Date.now();")
+ nwc.__class.q[nwc] = true
+ -- Broadcast update to other peers through client
+ --world.hub\broadcast("update", properties)
+ --actually, we only want to update each network component *at most* once per frame.
+
+ proxy = {}
+ setmetatable(proxy, {
+ __index: properties,
+ __newindex: update
+ })
+ super(name, proxy)
+ @net_properties = properties
+ join: (e, cid) =>
+ @@node\action("Send Updates", ()->
+ @@update_dirty!
+ )
+ @net_properties.id = e.id
+ @net_properties.name = cid
+ log.info("Added networked componenet name " .. @name .. " to entity id " .. e.id, {"net","server","ecs"})
+ -- Send initial create message through client
+ --if world.hub -- Actually, entity creation is hard, just sync each entity individually.
+ --world.hub\broadcast("create", properties)
+ super(e)
+
+ pack: () =>
+ assert(@entity, "Tried to pack on a NetworkedComponent without an Entity")
+ log.info("Packing data from proxy:" .. tostring(@proxy), {"net","ecs"})
+ return am.to_json({
+ id: @entity.id
+ data: @net_properties
+ time: am.current_time!
+ })
+
+ unpack: () ->
+ assert(@entity, "Tried to unpack on a NEtworkedComponent without an Entity")
+
+ @update_dirty: () =>
+ for component, _ in pairs(@q)
+ world.hub\broadcast("update", component.net_properties)
+ @q = {}
+
+ -- Each different kind of entity needs to have it's own create and listen network
+ -- hooks, it's way too complicated and heavy to push every entity with every componenet
+ -- over the network.
+
+assert(NetworkedComponent.q, "No queue found!")
+
+NetworkedComponent
diff --git a/src/ecs/player_graphic.moon b/src/ecs/player_graphic.moon
new file mode 100644
index 0000000..5ad9cab
--- /dev/null
+++ b/src/ecs/player_graphic.moon
@@ -0,0 +1,66 @@
+GraphicsComponent = require("ecs.graphics")
+sprites = require("sprites")
+
+geom_fac = {
+ {-1, -1, 1},
+ {-1, 1, 1},
+ {-1, -1, 1},
+ {1, 1, 1},
+ {1, -1, 1},
+ {-1, -1, 1}
+}
+
+class PlayerGraphicComponent extends GraphicsComponent
+ @player_size = 0.25
+ @static = false
+ --new: (name, properties) =>
+ --print("New PlayerGraphicsComponenet, super is", @@__init)
+ --print("But graphicsComponent's __init is:", GraphicsComponent.__init)
+ --GraphicsComponent.__init(@, name, properties)
+ --super(name, properties)
+ tris: () ->
+ 2
+ populate_buf: (geom_view, uv_view, offset) =>
+ @playerbuf = geom_view
+ h = @@player_size / 2
+ for i, set in ipairs(geom_fac)
+ geom_view[i] = vec3(h*set[1], h*set[2], h*set[3])
+ uv = sprites.player_normal
+ uv_view[1] = vec2(uv.s1,uv.t1)
+ uv_view[2] = vec2(uv.s1,uv.t2)
+ uv_view[3] = vec2(uv.s2,uv.t2)
+ uv_view[4] = vec2(uv.s2,uv.t2)
+ uv_view[5] = vec2(uv.s2,uv.t1)
+ uv_view[6] = vec2(uv.s1,uv.t1)
+ join: (entity) =>
+ super(entity)
+ aspect = win.width / win.height
+ -- inject nodes into the scene graph
+ program = @.node("use_program")
+ pred_component = entity\get("pred")
+ graphic = entity\get("graphic")
+ @node\remove(program)
+ @node\append(am.blend("alpha")\append(am.depth_test("less", true)\append(program)))
+ @node\action(() =>
+ pred_loc = pred_component.properties.pos
+ graphic\move(pred_loc.x, pred_loc.y)
+ )
+ --@.node("bind").highlight = color.am_color.black
+ move: (x,y) =>
+ assert(x, "x required")
+ assert(y, "y required")
+ world.level.move_lamp(@lamp, x + @lamp_offset.x, y + @lamp_offset.y)
+ h = @@player_size / 2
+ z = 0.5
+ @playerbuf[1] = vec3(x-h,y-h,z)
+ @playerbuf[2] = vec3(x-h,y+h,z)
+ @playerbuf[3] = vec3(x+h,y+h,z)
+ @playerbuf[4] = vec3(x+h,y+h,z)
+ @playerbuf[5] = vec3(x+h,y-h,z)
+ @playerbuf[6] = vec3(x-h,y-h,z)
+ --print("Move called", @playerbuf[1])
+ face: (direction) =>
+ --print("direction",direction)
+ @.node("bind").rot = (direction ) % (math.pi * 2)
+
+PlayerGraphicComponent
diff --git a/src/ecs/predicted.moon b/src/ecs/predicted.moon
new file mode 100644
index 0000000..b8bdd28
--- /dev/null
+++ b/src/ecs/predicted.moon
@@ -0,0 +1,25 @@
+Component = require("ecs.component")
+
+class PredictedComponent extends Component
+ new: (name, properties, netc_name, calculate) =>
+ super(name, properties)
+ @netc_name = netc_name
+ assert(calculate and type(calculate) == "table", "Calculate must be a table, was " .. type(calculate))
+ @calculate = calculate
+ join: (entity) =>
+ @net = @entity\get(@netc_name)
+ @node = am.group!
+ @node\action(() ->
+ @forward!
+ )
+ @@node\append(@node)
+ super(entity)
+ leave: (entity) =>
+ @@node\remove(@node)
+ forward: () =>
+ for property, calculation in pairs(@calculate)
+ @properties[property] = calculation(@)
+
+
+
+PredictedComponent
diff --git a/src/ecs/script.moon b/src/ecs/script.moon
new file mode 100644
index 0000000..05869c0
--- /dev/null
+++ b/src/ecs/script.moon
@@ -0,0 +1,16 @@
+Component = require("ecs.component")
+
+class ScriptComponent extends Component
+ new: (name, properties) =>
+ print("Creating new script component")
+ assert(properties and properties.script, "Failed to find script name for script component")
+ super(name, properties)
+ join: (e) =>
+ print("Script component is joining an entity")
+ @node = am.group!
+ @@node\append(@node)
+ @node\action(@properties.script)
+
+ leave: (e) =>
+ print("Script component is leaving an entity")
+ @@node\remove(@node)