implement INSTR_STATE in the qcvm
authorWolfgang Bumiller <wry.git@bumiller.com>
Tue, 8 Apr 2014 12:34:26 +0000 (14:34 +0200)
committerWolfgang Bumiller <wry.git@bumiller.com>
Tue, 8 Apr 2014 12:34:26 +0000 (14:34 +0200)
exec.c
gmqcc.h

diff --git a/exec.c b/exec.c
index 29a04a3fcc689f8faeabd40264e4876a9ce2acce..fde8196b2e4833ffebbd0f452b0c5517cf276916 100644 (file)
--- a/exec.c
+++ b/exec.c
@@ -55,8 +55,16 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
 {
     prog_header_t   header;
     qc_program_t   *prog;
+    size_t          i;
     fs_file_t      *file  = fs_file_open(filename, "rb");
 
+    /* we need all those in order to support INSTR_STATE: */
+    bool            has_self      = false,
+                    has_time      = false,
+                    has_think     = false,
+                    has_nextthink = false,
+                    has_frame     = false;
+
     if (!file)
         return NULL;
 
@@ -137,6 +145,36 @@ qc_program_t* prog_load(const char *filename, bool skipversion)
     memset(vec_add(prog->entitydata, prog->entityfields), 0, prog->entityfields * sizeof(prog->entitydata[0]));
     prog->entities = 1;
 
+    /* cache some globals and fields from names */
+    for (i = 0; i < vec_size(prog->defs); ++i) {
+        const char *name = prog_getstring(prog, prog->defs[i].name);
+        if      (!strcmp(name, "self")) {
+            prog->cached_globals.self = prog->defs[i].offset;
+            has_self = true;
+        }
+        else if (!strcmp(name, "time")) {
+            prog->cached_globals.time = prog->defs[i].offset;
+            has_time = true;
+        }
+    }
+    for (i = 0; i < vec_size(prog->fields); ++i) {
+        const char *name = prog_getstring(prog, prog->fields[i].name);
+        if      (!strcmp(name, "think")) {
+            prog->cached_fields.think     = prog->fields[i].offset;
+            has_think = true;
+        }
+        else if (!strcmp(name, "nextthink")) {
+            prog->cached_fields.nextthink = prog->fields[i].offset;
+            has_nextthink = true;
+        }
+        else if (!strcmp(name, "frame")) {
+            prog->cached_fields.frame     = prog->fields[i].offset;
+            has_frame = true;
+        }
+    }
+    if (has_self && has_time && has_think && has_nextthink && has_frame)
+        prog->supports_state = true;
+
     return prog;
 
 error:
@@ -1574,8 +1612,24 @@ while (prog->vmerror == 0) {
             break;
 
         case INSTR_STATE:
-            qcvmerror(prog, "`%s` tried to execute a STATE operation", prog->filename);
+        {
+            qcfloat_t *nextthink;
+            qcfloat_t *time;
+            qcfloat_t *frame;
+            if (!prog->supports_state) {
+                qcvmerror(prog, "`%s` tried to execute a STATE operation but misses its defs!", prog->filename);
+                goto cleanup;
+            }
+            ed = prog_getedict(prog, prog->globals[prog->cached_globals.self]);
+            ((qcint_t*)ed)[prog->cached_fields.think] = OPB->function;
+
+            frame     = (qcfloat_t*)&((qcint_t*)ed)[prog->cached_fields.frame];
+            *frame    = OPA->_float;
+            nextthink = (qcfloat_t*)&((qcint_t*)ed)[prog->cached_fields.nextthink];
+            time      = (qcfloat_t*)(prog->globals + prog->cached_globals.time);
+            *nextthink = *time + 0.1;
             break;
+        }
 
         case INSTR_GOTO:
             st += st->o1.s1 - 1;    /* offset the s++ */
diff --git a/gmqcc.h b/gmqcc.h
index 835931df990a5431399f463728053f652321ce72..7834a24fd59216b580d2a92c3ff8e78e105cb4e0 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
@@ -789,17 +789,17 @@ typedef struct {
 } qc_exec_stack_t;
 
 typedef struct qc_program_s {
-    char                    *filename;
+    char                     *filename;
     prog_section_statement_t *code;
     prog_section_def_t       *defs;
     prog_section_def_t       *fields;
     prog_section_function_t  *functions;
-    char                    *strings;
-    qcint_t                   *globals;
-    qcint_t                   *entitydata;
-    bool                    *entitypool;
+    char                     *strings;
+    qcint_t                  *globals;
+    qcint_t                  *entitydata;
+    bool                     *entitypool;
 
-    const char*             *function_stack;
+    const char*              *function_stack;
 
     uint16_t crc16;
 
@@ -825,6 +825,20 @@ typedef struct qc_program_s {
     size_t xflags;
 
     int    argc; /* current arg count for debugging */
+
+    /* cached fields */
+    struct {
+        qcint_t frame;
+        qcint_t nextthink;
+        qcint_t think;
+    } cached_fields;
+
+    struct {
+        qcint_t self;
+        qcint_t time;
+    } cached_globals;
+
+    bool supports_state; /* is INSTR_STATE supported? */
 } qc_program_t;
 
 qc_program_t*       prog_load      (const char *filename, bool ignoreversion);