ECS framework
authorTimePath <andrew.hardaker1995@gmail.com>
Sun, 19 Jun 2016 11:57:54 +0000 (21:57 +1000)
committerTimePath <andrew.hardaker1995@gmail.com>
Sun, 19 Jun 2016 11:59:27 +0000 (21:59 +1000)
22 files changed:
qcsrc/.editorconfig [new file with mode: 0644]
qcsrc/client/progs.inc
qcsrc/ecs/README.md [new file with mode: 0644]
qcsrc/ecs/_lib.inc [new file with mode: 0644]
qcsrc/ecs/_mod.inc [new file with mode: 0644]
qcsrc/ecs/_mod.qh [new file with mode: 0644]
qcsrc/ecs/components/_mod.inc [new file with mode: 0644]
qcsrc/ecs/components/_mod.qh [new file with mode: 0644]
qcsrc/ecs/components/input.qc [new file with mode: 0644]
qcsrc/ecs/components/input.qh [new file with mode: 0644]
qcsrc/ecs/components/physics.qc [new file with mode: 0644]
qcsrc/ecs/components/physics.qh [new file with mode: 0644]
qcsrc/ecs/events/_mod.inc [new file with mode: 0644]
qcsrc/ecs/events/_mod.qh [new file with mode: 0644]
qcsrc/ecs/main.qc [new file with mode: 0644]
qcsrc/ecs/main.qh [new file with mode: 0644]
qcsrc/ecs/systems/_mod.inc [new file with mode: 0644]
qcsrc/ecs/systems/_mod.qh [new file with mode: 0644]
qcsrc/ecs/systems/physics.qc [new file with mode: 0644]
qcsrc/ecs/systems/physics.qh [new file with mode: 0644]
qcsrc/server/progs.inc
qcsrc/tools/genmod.sh

diff --git a/qcsrc/.editorconfig b/qcsrc/.editorconfig
new file mode 100644 (file)
index 0000000..013c331
--- /dev/null
@@ -0,0 +1,7 @@
+root = true
+
+[*.{qc,qh,inc}]
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+charset = utf-8
index 8952f05..48579ec 100644 (file)
@@ -25,6 +25,8 @@
 
 #endif
 
+#include <ecs/_lib.inc>
+
 #if BUILD_MOD
 #include "../../mod/client/progs.inc"
 #endif
diff --git a/qcsrc/ecs/README.md b/qcsrc/ecs/README.md
new file mode 100644 (file)
index 0000000..9fd6ad6
--- /dev/null
@@ -0,0 +1,48 @@
+# Xonotic entity component system
+
+## guidelines
+
+* avoid #if and #ifdef
+* avoid string
+* avoid declaring entity fields outside of components
+* uncrustify relentlessly
+* shared code in $file, prog specific code uses prefix: { client: cl_, server: sv_, menu: ui_ }. $file must exist
+* component naming =~ com_$component_$name
+* system naming =~ sys_$system_$name
+* event naming =~ evt_$component_$name
+* global naming =~ g_$name
+* cvar naming =~ xon_$name
+
+## components
+
+    COMPONENT($component);
+    .int com_$component_$property;
+
+## entities
+
+    entity e = new(foo);
+    e.com_$component = true;
+    e.com_$component_$property = 42;
+
+## systems
+
+    SYSTEM($system, 30, 10);
+    sys_$system_update(entity this, float dt) {
+        code;
+    }
+
+## events
+
+### declaring
+
+    EVENT($component_$name, (entity this));
+
+### emitting
+
+    emit($event, it);
+
+### listening
+
+    entity listener = new_pure(someListener);
+    listener.evt_$event = void(entity this) { code; };
+    subscribe(listener, $event);
diff --git a/qcsrc/ecs/_lib.inc b/qcsrc/ecs/_lib.inc
new file mode 100644 (file)
index 0000000..32db1f3
--- /dev/null
@@ -0,0 +1,60 @@
+/** Components always interpolate from the previous state */
+#define COMPONENT(com) \
+       void com_##com##_interpolate(entity it, float a); \
+       .bool com_##com
+
+#define FOREACH_COMPONENT(com, body) FOREACH_ENTITY_FLOAT(com_##com, true, body)
+
+
+#define EVENT(T, args) .bool evt_##T##_listener; .void args evt_##T
+
+#define emit(T, ...) \
+       MACRO_BEGIN \
+       FOREACH_ENTITY_FLOAT_ORDERED(evt_##T##_listener, true, it.evt_##T(__VA_ARGS__)); \
+       MACRO_END
+
+#define subscribe(listener, T) \
+       MACRO_BEGIN \
+       listener.evt_##T##_listener = true; \
+       MACRO_END
+
+
+/**
+ * framelimit 0 is no limit, interpolation does not apply
+ * framerate below minfps will result in less than 100% speed
+ */
+#define SYSTEM(sys, frameLimit, minfps) \
+       void sys_##sys##_update(entity this, float dt); \
+       float autocvar_xon_sys_##sys##_dt = ((frameLimit) ? (1 / (frameLimit)) : 0); \
+       float autocvar_xon_sys_##sys##_minfps = (1 / (1 / (minfps)))
+
+#define SYSTEM_UPDATE(sys) \
+       MACRO_BEGIN \
+       static float t = 0; \
+       float dt = autocvar_xon_sys_##sys##_dt; \
+       float minfps = autocvar_xon_sys_##sys##_minfps; \
+       static float accumulator = 0; \
+       float a = 0; \
+       if (dt) { \
+               accumulator += min(frametime, 1 / (minfps)); \
+       } else { \
+               accumulator += frametime; \
+               dt = accumulator; \
+               a = 1; \
+       } \
+       while (accumulator >= dt) \
+       { \
+               time = t; \
+               FOREACH_COMPONENT(sys, sys_##sys##_update(it, dt)); \
+               t += dt; \
+               accumulator -= dt; \
+       } \
+       if (!a) a = accumulator / dt; \
+       FOREACH_COMPONENT(sys, com_##sys##_interpolate(it, a)); \
+       MACRO_END
+
+
+#include "_mod.inc"
+#include "components/_mod.inc"
+#include "events/_mod.inc"
+#include "systems/_mod.inc"
diff --git a/qcsrc/ecs/_mod.inc b/qcsrc/ecs/_mod.inc
new file mode 100644 (file)
index 0000000..683c3a9
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <ecs/main.qc>
diff --git a/qcsrc/ecs/_mod.qh b/qcsrc/ecs/_mod.qh
new file mode 100644 (file)
index 0000000..4d8bc34
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <ecs/main.qh>
diff --git a/qcsrc/ecs/components/_mod.inc b/qcsrc/ecs/components/_mod.inc
new file mode 100644 (file)
index 0000000..0975871
--- /dev/null
@@ -0,0 +1,3 @@
+// generated file; do not modify
+#include <ecs/components/input.qc>
+#include <ecs/components/physics.qc>
diff --git a/qcsrc/ecs/components/_mod.qh b/qcsrc/ecs/components/_mod.qh
new file mode 100644 (file)
index 0000000..64fad31
--- /dev/null
@@ -0,0 +1,3 @@
+// generated file; do not modify
+#include <ecs/components/input.qh>
+#include <ecs/components/physics.qh>
diff --git a/qcsrc/ecs/components/input.qc b/qcsrc/ecs/components/input.qc
new file mode 100644 (file)
index 0000000..13b3413
--- /dev/null
@@ -0,0 +1,3 @@
+#include "input.qh"
+
+void com_in_interpolate(entity it, float a) { }
diff --git a/qcsrc/ecs/components/input.qh b/qcsrc/ecs/components/input.qh
new file mode 100644 (file)
index 0000000..37944ca
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+COMPONENT(in);
+.vector com_in_move;
+.vector com_in_angles;
+.bool   com_in_jump;
diff --git a/qcsrc/ecs/components/physics.qc b/qcsrc/ecs/components/physics.qc
new file mode 100644 (file)
index 0000000..5094ad1
--- /dev/null
@@ -0,0 +1,10 @@
+#include "physics.qh"
+
+bool autocvar_xon_com_phys_interpolate = true;
+
+void com_phys_interpolate(entity it, float a)
+{
+       if (!autocvar_xon_com_phys_interpolate) a = 1;
+       it.origin = it.com_phys_pos_prev * (1 - a) + it.com_phys_pos * a;
+       it.angles = it.com_phys_ang_prev * (1 - a) + it.com_phys_ang * a;  // TODO: slerp, not lerp
+}
diff --git a/qcsrc/ecs/components/physics.qh b/qcsrc/ecs/components/physics.qh
new file mode 100644 (file)
index 0000000..502657e
--- /dev/null
@@ -0,0 +1,7 @@
+#pragma once
+
+COMPONENT(phys);
+.vector com_phys_pos, com_phys_pos_prev;
+.vector com_phys_ang, com_phys_ang_prev;
+.vector com_phys_vel;
+.vector com_phys_acc;
diff --git a/qcsrc/ecs/events/_mod.inc b/qcsrc/ecs/events/_mod.inc
new file mode 100644 (file)
index 0000000..98fb481
--- /dev/null
@@ -0,0 +1 @@
+// generated file; do not modify
diff --git a/qcsrc/ecs/events/_mod.qh b/qcsrc/ecs/events/_mod.qh
new file mode 100644 (file)
index 0000000..98fb481
--- /dev/null
@@ -0,0 +1 @@
+// generated file; do not modify
diff --git a/qcsrc/ecs/main.qc b/qcsrc/ecs/main.qc
new file mode 100644 (file)
index 0000000..29be3f3
--- /dev/null
@@ -0,0 +1,12 @@
+#include "main.qh"
+
+#include "components/_mod.qh"
+#include "events/_mod.qh"
+#include "systems/_mod.qh"
+
+void systems_update()
+{
+       float realtime = time;
+       SYSTEM_UPDATE(phys);
+       time = realtime;
+}
diff --git a/qcsrc/ecs/main.qh b/qcsrc/ecs/main.qh
new file mode 100644 (file)
index 0000000..9b7bf35
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+void systems_update();
diff --git a/qcsrc/ecs/systems/_mod.inc b/qcsrc/ecs/systems/_mod.inc
new file mode 100644 (file)
index 0000000..f79d7f0
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <ecs/systems/physics.qc>
diff --git a/qcsrc/ecs/systems/_mod.qh b/qcsrc/ecs/systems/_mod.qh
new file mode 100644 (file)
index 0000000..e71e059
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <ecs/systems/physics.qh>
diff --git a/qcsrc/ecs/systems/physics.qc b/qcsrc/ecs/systems/physics.qc
new file mode 100644 (file)
index 0000000..8348b87
--- /dev/null
@@ -0,0 +1,6 @@
+#include "physics.qh"
+
+void sys_phys_update(entity this, float dt)
+{
+       PM_Main(this);
+}
diff --git a/qcsrc/ecs/systems/physics.qh b/qcsrc/ecs/systems/physics.qh
new file mode 100644 (file)
index 0000000..38d4e55
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+SYSTEM(phys, 30, 10);
index ed005df..163b166 100644 (file)
@@ -28,6 +28,8 @@
 
 #endif
 
+#include <ecs/_lib.inc>
+
 #if BUILD_MOD
 #include "../../mod/server/progs.inc"
 #endif
index b4c4fc3..2c34e67 100755 (executable)
@@ -1,6 +1,6 @@
-#!/bin/bash
+#!/usr/bin/env bash
 set -eu
-cd "$(dirname "$0")"
+cd ${0%/*}
 cd ..
 ROOT=$PWD/
 
@@ -32,6 +32,7 @@ function genmod() {
 
 (cd lib; genmod)
 (cd common; genmod)
+(cd ecs; genmod)
 (cd client; genmod)
 (cd server; genmod)
 (cd menu; genmod)