From 8f04c35701fab23cf21732a4f69c02a78507dd62 Mon Sep 17 00:00:00 2001 From: TimePath Date: Sun, 19 Jun 2016 21:57:54 +1000 Subject: [PATCH] ECS framework --- qcsrc/.editorconfig | 7 ++++ qcsrc/client/progs.inc | 2 ++ qcsrc/ecs/README.md | 48 ++++++++++++++++++++++++++ qcsrc/ecs/_lib.inc | 60 +++++++++++++++++++++++++++++++++ qcsrc/ecs/_mod.inc | 2 ++ qcsrc/ecs/_mod.qh | 2 ++ qcsrc/ecs/components/_mod.inc | 3 ++ qcsrc/ecs/components/_mod.qh | 3 ++ qcsrc/ecs/components/input.qc | 3 ++ qcsrc/ecs/components/input.qh | 6 ++++ qcsrc/ecs/components/physics.qc | 10 ++++++ qcsrc/ecs/components/physics.qh | 7 ++++ qcsrc/ecs/events/_mod.inc | 1 + qcsrc/ecs/events/_mod.qh | 1 + qcsrc/ecs/main.qc | 12 +++++++ qcsrc/ecs/main.qh | 3 ++ qcsrc/ecs/systems/_mod.inc | 2 ++ qcsrc/ecs/systems/_mod.qh | 2 ++ qcsrc/ecs/systems/physics.qc | 6 ++++ qcsrc/ecs/systems/physics.qh | 3 ++ qcsrc/server/progs.inc | 2 ++ qcsrc/tools/genmod.sh | 5 +-- 22 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 qcsrc/.editorconfig create mode 100644 qcsrc/ecs/README.md create mode 100644 qcsrc/ecs/_lib.inc create mode 100644 qcsrc/ecs/_mod.inc create mode 100644 qcsrc/ecs/_mod.qh create mode 100644 qcsrc/ecs/components/_mod.inc create mode 100644 qcsrc/ecs/components/_mod.qh create mode 100644 qcsrc/ecs/components/input.qc create mode 100644 qcsrc/ecs/components/input.qh create mode 100644 qcsrc/ecs/components/physics.qc create mode 100644 qcsrc/ecs/components/physics.qh create mode 100644 qcsrc/ecs/events/_mod.inc create mode 100644 qcsrc/ecs/events/_mod.qh create mode 100644 qcsrc/ecs/main.qc create mode 100644 qcsrc/ecs/main.qh create mode 100644 qcsrc/ecs/systems/_mod.inc create mode 100644 qcsrc/ecs/systems/_mod.qh create mode 100644 qcsrc/ecs/systems/physics.qc create mode 100644 qcsrc/ecs/systems/physics.qh diff --git a/qcsrc/.editorconfig b/qcsrc/.editorconfig new file mode 100644 index 000000000..013c331e8 --- /dev/null +++ b/qcsrc/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*.{qc,qh,inc}] +end_of_line = lf +insert_final_newline = true +indent_style = tab +charset = utf-8 diff --git a/qcsrc/client/progs.inc b/qcsrc/client/progs.inc index 8952f058f..48579ecbb 100644 --- a/qcsrc/client/progs.inc +++ b/qcsrc/client/progs.inc @@ -25,6 +25,8 @@ #endif +#include + #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 index 000000000..9fd6ad694 --- /dev/null +++ b/qcsrc/ecs/README.md @@ -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 index 000000000..32db1f3d3 --- /dev/null +++ b/qcsrc/ecs/_lib.inc @@ -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 index 000000000..683c3a91d --- /dev/null +++ b/qcsrc/ecs/_mod.inc @@ -0,0 +1,2 @@ +// generated file; do not modify +#include diff --git a/qcsrc/ecs/_mod.qh b/qcsrc/ecs/_mod.qh new file mode 100644 index 000000000..4d8bc34da --- /dev/null +++ b/qcsrc/ecs/_mod.qh @@ -0,0 +1,2 @@ +// generated file; do not modify +#include diff --git a/qcsrc/ecs/components/_mod.inc b/qcsrc/ecs/components/_mod.inc new file mode 100644 index 000000000..097587129 --- /dev/null +++ b/qcsrc/ecs/components/_mod.inc @@ -0,0 +1,3 @@ +// generated file; do not modify +#include +#include diff --git a/qcsrc/ecs/components/_mod.qh b/qcsrc/ecs/components/_mod.qh new file mode 100644 index 000000000..64fad31b3 --- /dev/null +++ b/qcsrc/ecs/components/_mod.qh @@ -0,0 +1,3 @@ +// generated file; do not modify +#include +#include diff --git a/qcsrc/ecs/components/input.qc b/qcsrc/ecs/components/input.qc new file mode 100644 index 000000000..13b341367 --- /dev/null +++ b/qcsrc/ecs/components/input.qc @@ -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 index 000000000..37944ca5c --- /dev/null +++ b/qcsrc/ecs/components/input.qh @@ -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 index 000000000..5094ad17a --- /dev/null +++ b/qcsrc/ecs/components/physics.qc @@ -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 index 000000000..502657e4b --- /dev/null +++ b/qcsrc/ecs/components/physics.qh @@ -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 index 000000000..98fb4815c --- /dev/null +++ b/qcsrc/ecs/events/_mod.inc @@ -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 index 000000000..98fb4815c --- /dev/null +++ b/qcsrc/ecs/events/_mod.qh @@ -0,0 +1 @@ +// generated file; do not modify diff --git a/qcsrc/ecs/main.qc b/qcsrc/ecs/main.qc new file mode 100644 index 000000000..29be3f367 --- /dev/null +++ b/qcsrc/ecs/main.qc @@ -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 index 000000000..9b7bf3523 --- /dev/null +++ b/qcsrc/ecs/main.qh @@ -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 index 000000000..f79d7f065 --- /dev/null +++ b/qcsrc/ecs/systems/_mod.inc @@ -0,0 +1,2 @@ +// generated file; do not modify +#include diff --git a/qcsrc/ecs/systems/_mod.qh b/qcsrc/ecs/systems/_mod.qh new file mode 100644 index 000000000..e71e0591c --- /dev/null +++ b/qcsrc/ecs/systems/_mod.qh @@ -0,0 +1,2 @@ +// generated file; do not modify +#include diff --git a/qcsrc/ecs/systems/physics.qc b/qcsrc/ecs/systems/physics.qc new file mode 100644 index 000000000..8348b8785 --- /dev/null +++ b/qcsrc/ecs/systems/physics.qc @@ -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 index 000000000..38d4e55e5 --- /dev/null +++ b/qcsrc/ecs/systems/physics.qh @@ -0,0 +1,3 @@ +#pragma once + +SYSTEM(phys, 30, 10); diff --git a/qcsrc/server/progs.inc b/qcsrc/server/progs.inc index ed005dfad..163b16674 100644 --- a/qcsrc/server/progs.inc +++ b/qcsrc/server/progs.inc @@ -28,6 +28,8 @@ #endif +#include + #if BUILD_MOD #include "../../mod/server/progs.inc" #endif diff --git a/qcsrc/tools/genmod.sh b/qcsrc/tools/genmod.sh index b4c4fc304..2c34e6713 100755 --- a/qcsrc/tools/genmod.sh +++ b/qcsrc/tools/genmod.sh @@ -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) -- 2.39.2