X-Git-Url: https://git.xonotic.org/?p=xonotic%2Fgmqcc.git;a=blobdiff_plain;f=exec.c;h=8ec97e4302d38f7d5099fee6b0a9622bf565de74;hp=43d1980ed1a12895b516a2c29cbf776def1ff710;hb=b5ac2745d678a3cf7d7275864a0aabe9a52d8f08;hpb=8e8b3608fbf1e9627e79c5f8d4ec894ccbde0e4f diff --git a/exec.c b/exec.c index 43d1980..8ec97e4 100644 --- a/exec.c +++ b/exec.c @@ -1,26 +1,3 @@ -/* - * Copyright (C) 2012, 2013 - * Wolfgang Bumiller - * Dale Weiler - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is furnished to do - * so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ #ifndef QCVM_LOOP #include #include @@ -55,26 +32,36 @@ qc_program_t* prog_load(const char *filename, bool skipversion) { prog_header_t header; qc_program_t *prog; - fs_file_t *file = fs_file_open(filename, "rb"); + size_t i; + FILE *file = fopen(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; - if (fs_file_read(&header, sizeof(header), 1, file) != 1) { + if (fread(&header, sizeof(header), 1, file) != 1) { loaderror("failed to read header from '%s'", filename); - fs_file_close(file); + fclose(file); return NULL; } + util_swap_header(&header); + if (!skipversion && header.version != 6) { loaderror("header says this is a version %i progs, we need version 6\n", header.version); - fs_file_close(file); + fclose(file); return NULL; } prog = (qc_program_t*)mem_a(sizeof(qc_program_t)); if (!prog) { - fs_file_close(file); + fclose(file); fprintf(stderr, "failed to allocate program data\n"); return NULL; } @@ -90,11 +77,11 @@ qc_program_t* prog_load(const char *filename, bool skipversion) } #define read_data(hdrvar, progvar, reserved) \ - if (fs_file_seek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ + if (fseek(file, header.hdrvar.offset, SEEK_SET) != 0) { \ loaderror("seek failed"); \ goto error; \ } \ - if (fs_file_read ( \ + if (fread( \ vec_add(prog->progvar, header.hdrvar.length + reserved), \ sizeof(*prog->progvar), \ header.hdrvar.length, \ @@ -114,7 +101,13 @@ qc_program_t* prog_load(const char *filename, bool skipversion) read_data1(strings); read_data2(globals, 2); /* reserve more in case a RETURN using with the global at "the end" exists */ - fs_file_close(file); + util_swap_statements (prog->code); + util_swap_defs_fields(prog->defs); + util_swap_defs_fields(prog->fields); + util_swap_functions (prog->functions); + util_swap_globals (prog->globals); + + fclose(file); /* profile counters */ memset(vec_add(prog->profile, vec_size(prog->code)), 0, sizeof(prog->profile[0]) * vec_size(prog->code)); @@ -129,6 +122,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: @@ -144,7 +167,7 @@ error: vec_free(prog->entitypool); mem_d(prog); - fs_file_close(file); + fclose(file); return NULL; } @@ -351,7 +374,7 @@ static void trace_print_global(qc_program_t *prog, unsigned int glob, int vtype) done: if (len < (int)sizeof(spaces)-1) { spaces[sizeof(spaces)-1-len] = 0; - fs_file_puts((fs_file_t*)stdout, spaces); + fputs(spaces, stdout); spaces[sizeof(spaces)-1-len] = ' '; } } @@ -814,6 +837,16 @@ static int qc_floor(qc_program_t *prog) { return 0; } +static int qc_pow(qc_program_t *prog) { + qcany_t *base, *exp, out; + CheckArgs(2); + base = GetArg(0); + exp = GetArg(1); + out._float = powf(base->_float, exp->_float); + Return(out); + return 0; +} + static prog_builtin_t qc_builtins[] = { NULL, &qc_print, /* 1 */ @@ -829,7 +862,8 @@ static prog_builtin_t qc_builtins[] = { &qc_strcmp, /* 11 */ &qc_normalize, /* 12 */ &qc_sqrt, /* 13 */ - &qc_floor /* 14 */ + &qc_floor, /* 14 */ + &qc_pow /* 15 */ }; static const char *arg0 = NULL; @@ -893,7 +927,7 @@ static void prog_main_setparams(qc_program_t *prog) { } } -void prog_disasm_function(qc_program_t *prog, size_t id); +static void prog_disasm_function(qc_program_t *prog, size_t id); int main(int argc, char **argv) { size_t i; @@ -1208,7 +1242,7 @@ int main(int argc, char **argv) { return 0; } -void prog_disasm_function(qc_program_t *prog, size_t id) { +static void prog_disasm_function(qc_program_t *prog, size_t id) { prog_section_function_t *fdef = prog->functions + id; prog_section_statement_t *st; @@ -1555,8 +1589,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++ */