From: Wolfgang Bumiller Date: Tue, 8 Apr 2014 12:34:26 +0000 (+0200) Subject: implement INSTR_STATE in the qcvm X-Git-Tag: xonotic-v0.8.1~9^2~33^2~4 X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=commitdiff_plain;h=0d8b0d419c0b33bc9471e90f0d92e41d17107f74 implement INSTR_STATE in the qcvm --- diff --git a/exec.c b/exec.c index 29a04a3..fde8196 100644 --- 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 835931d..7834a24 100644 --- 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);