diff options
author | rodri <rgl@antares-labs.eu> | 2021-07-21 05:05:07 +0000 |
---|---|---|
committer | rodri <rgl@antares-labs.eu> | 2021-07-21 05:05:07 +0000 |
commit | d276cd9961e05c184d4fd653bb9e92a288a09ec3 (patch) | |
tree | bb9de32f3e21af254f0fa447ba3f7d5759417ab5 | |
download | musw-d276cd9961e05c184d4fd653bb9e92a288a09ec3.tar.gz musw-d276cd9961e05c184d4fd653bb9e92a288a09ec3.tar.bz2 musw-d276cd9961e05c184d4fd653bb9e92a288a09ec3.zip |
initial commit.
implemented basic server loop, with separate threads to handle connections and run the simulations.
-rw-r--r-- | dat.h | 25 | ||||
-rw-r--r-- | fns.h | 1 | ||||
-rw-r--r-- | mkfile | 14 | ||||
-rw-r--r-- | musw.c | 0 | ||||
-rw-r--r-- | muswd.c | 118 | ||||
-rw-r--r-- | nanosec.c | 109 | ||||
-rw-r--r-- | physics.c | 100 | ||||
-rw-r--r-- | readme.md | 0 | ||||
-rw-r--r-- | stats.c | 18 |
9 files changed, 385 insertions, 0 deletions
@@ -0,0 +1,25 @@ +typedef struct GameState GameState; +typedef struct Derivative Derivative; +typedef struct Stats Stats; +typedef struct Sprite Sprite; + +struct Stats +{ + double cur; + double total; + double min, avg, max; + uvlong nupdates; + + void (*update)(Stats*, double); +}; + +struct GameState +{ + double x, v; + Stats stats; +}; + +struct Derivative +{ + double dx, dv; +}; @@ -0,0 +1 @@ +uvlong nanosec(void); @@ -0,0 +1,14 @@ +</$objtype/mkfile + +BIN=/$objtype/bin/games +TARG=\ + musw\ + muswd\ + +OFILES= + +HFILES=\ + dat.h\ + fns.h\ + +</sys/src/cmd/mkmany @@ -0,0 +1,118 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include "dat.h" +#include "fns.h" + +int debug; + +double t, Δt; + +static long +_iolisten(va_list *arg) +{ + char *adir, *ldir; + + adir = va_arg(*arg, char*); + ldir = va_arg(*arg, char*); + + return listen(adir, ldir); +} + +long +iolisten(Ioproc *io, char *adir, char *ldir) +{ + return iocall(io, _iolisten, adir, ldir); +} + +void +threadlisten(void *arg) +{ + int lcfd; + char *adir, ldir[40]; + Ioproc *io; + + adir = arg; + io = ioproc(); + + for(;;){ + lcfd = iolisten(io, adir, ldir); + if(lcfd < 0){ + fprint(2, "iolisten: %r\n"); + continue; + } + /* + * handle connection and allocate user on a seat, ready + * to play + */ + } +} + +void +resetsim(void) +{ + memset(&state, 0, sizeof(GameState)); + state.x = 100; + state.stats.update = statsupdate; + t = 0; +} + +void +threadsim(void *) +{ + uvlong then, now; + double frametime, timeacc; + + Δt = 0.01; + then = nanosec(); + timeacc = 0; + + resetsim(); + + for(;;){ + now = nanosec(); + frametime = now - then; + then = now; + timeacc += frametime/1e9; + + while(timeacc >= Δt){ + integrate(&state, t, Δt); + timeacc -= Δt; + t += Δt; + } + + sleep(66); + } +} + +void +usage(void) +{ + fprint(2, "usage: %s [-d]\n", argv0); + threadexitsall("usage"); +} + +void +threadmain(int argc, char *argv[]) +{ + int acfd; + char adir[40]; + + ARGBEGIN{ + case 'd': + debug++; + break; + default: + usage(); + }ARGEND; + if(argc != 0) + usage(); + + acfd = announce("tcp!*!112", adir); + if(acfd < 0) + sysfatal("announce: %r"); + + threadcreate(threadlisten, adir, 1024); + threadcreate(threadsim, nil, 8192); + threadexits(nil); +} diff --git a/nanosec.c b/nanosec.c new file mode 100644 index 0000000..f82d47a --- /dev/null +++ b/nanosec.c @@ -0,0 +1,109 @@ +#include <u.h> +#include <libc.h> +#include <tos.h> + +/* + * This code is a mixture of cpuid(1) and the nanosec() found in vmx, + * in order to force the use of nsec(2) in case we are running in a + * virtualized environment where the clock is mis-bhyve-ing. + */ + +typedef struct Res { + ulong ax, bx, cx, dx; +} Res; + +static uchar _cpuid[] = { + 0x5E, /* POP SI (PC) */ + 0x5D, /* POP BP (Res&) */ + 0x58, /* POP AX */ + 0x59, /* POP CX */ + + 0x51, /* PUSH CX */ + 0x50, /* PUSH AX */ + 0x55, /* PUSH BP */ + 0x56, /* PUSH SI */ + + 0x31, 0xDB, /* XOR BX, BX */ + 0x31, 0xD2, /* XOR DX, DX */ + + 0x0F, 0xA2, /* CPUID */ + + 0x89, 0x45, 0x00, /* MOV AX, 0(BP) */ + 0x89, 0x5d, 0x04, /* MOV BX, 4(BP) */ + 0x89, 0x4d, 0x08, /* MOV CX, 8(BP) */ + 0x89, 0x55, 0x0C, /* MOV DX, 12(BP) */ + 0xC3, /* RET */ +}; + +static Res (*cpuid)(ulong ax, ulong cx) = (Res(*)(ulong, ulong)) _cpuid; + +/* + * nsec() is wallclock and can be adjusted by timesync + * so need to use cycles() instead, but fall back to + * nsec() in case we can't + */ +uvlong +nanosec(void) +{ + static uvlong fasthz, xstart; + char buf[13], path[128]; + ulong w; + uvlong x, div; + int fd; + Res r; + + if(fasthz == ~0ULL) + return nsec() - xstart; + + if(fasthz == 0){ + /* first long in a.out header */ + snprint(path, sizeof path, "/proc/%d/text", getpid()); + fd = open(path, OREAD); + if(fd < 0) + goto Wallclock; + if(read(fd, buf, 4) != 4){ + close(fd); + goto Wallclock; + } + close(fd); + + w = ((ulong *) buf)[0]; + + switch(w){ + default: + goto Wallclock; + case 0x978a0000: /* amd64 */ + /* patch out POP BP -> POP AX */ + _cpuid[1] = 0x58; + case 0xeb010000: /* 386 */ + break; + } + segflush(_cpuid, sizeof(_cpuid)); + + r = cpuid(0x40000000, 0); + ((ulong *) buf)[0] = r.bx; + ((ulong *) buf)[1] = r.cx; + ((ulong *) buf)[2] = r.dx; + buf[12] = 0; + + if(strstr(buf, "bhyve") != nil) + goto Wallclock; + + if(_tos->cyclefreq){ + fasthz = _tos->cyclefreq; + cycles(&xstart); + } else { +Wallclock: + fasthz = ~0ULL; + xstart = nsec(); + } + return 0; + } + cycles(&x); + x -= xstart; + + /* this is ugly */ + for(div = 1000000000ULL; x < 0x1999999999999999ULL && div > 1 ; div /= 10ULL, x *= 10ULL); + + return x / (fasthz / div); +} diff --git a/physics.c b/physics.c new file mode 100644 index 0000000..5f45fd9 --- /dev/null +++ b/physics.c @@ -0,0 +1,100 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include "dat.h" +#include "fns.h" + +//enum { DYNTIME, RENTIME, NSTATS }; +//Stats simstats[NSTATS]; + + +/* + * Dynamics stepper + * + * Currently set to a basic spring-damper system. + */ +static double +accel(GameState *s, double t) +{ + static double k = 15, b = 0.1; + + USED(t); + return -k*s->x - b*s->v; +} + +static Derivative +eval(GameState *s0, double t, double Δt, Derivative *d) +{ + GameState s; + Derivative res; + + s.x = s0->x + d->dx*Δt; + s.v = s0->v + d->dv*Δt; + + res.dx = s.v; + res.dv = accel(&s, t+Δt); + return res; +} + +/* + * Explicit Euler Integrator + */ +static void +euler0(GameState *s, double t, double Δt) +{ + static Derivative ZD = {0,0}; + Derivative d; + + d = eval(s, t, Δt, &ZD); + + s->x += d.dx*Δt; + s->v += d.dv*Δt; +} + +/* + * Semi-implicit Euler Integrator + */ +static void +euler1(GameState *s, double t, double Δt) +{ + static Derivative ZD = {0,0}; + Derivative d; + + d = eval(s, t, Δt, &ZD); + + s->v += d.dv*Δt; + s->x += s->v*Δt; +} + +/* + * RK4 Integrator + */ +static void +rk4(GameState *s, double t, double Δt) +{ + static Derivative ZD = {0,0}; + Derivative a, b, c, d; + double dxdt, dvdt; + + a = eval(s, t, 0, &ZD); + b = eval(s, t, Δt/2, &a); + c = eval(s, t, Δt/2, &b); + d = eval(s, t, Δt, &c); + + dxdt = 1.0/6 * (a.dx + 2*(b.dx + c.dx) + d.dx); + dvdt = 1.0/6 * (a.dv + 2*(b.dv + c.dv) + d.dv); + + s->x += dxdt*Δt; + s->v += dvdt*Δt; +} + +/* + * The Integrator + */ +void +integrate(GameState *s, double t, double Δt) +{ + //euler0(s, t, Δt); + //euler1(s, t, Δt); + rk4(s, t, Δt); +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/readme.md @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> +#include <draw.h> +#include "dat.h" +#include "fns.h" + +static double min(double a, double b) { return a < b? a: b; } +static double max(double a, double b) { return a > b? a: b; } + +void +statsupdate(Stats *s, double n) +{ + s->cur = n; + s->total += s->cur; + s->avg = s->total/++s->nupdates; + s->min = min(s->cur, s->min); + s->max = max(s->cur, s->max); +} |