X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmain.qc;h=40e14c906bf858e544c321cf475cada1526a9024;hb=297a8c4a5b3580f26234fb70333c742088cfc069;hp=8a2da54aa4a721c2312017b0bd30ae52bd72e561;hpb=13fa6801efb4383d705cb81001aeff75402609f3;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/main.qc b/qcsrc/server/main.qc index 8a2da54aa..40e14c906 100644 --- a/qcsrc/server/main.qc +++ b/qcsrc/server/main.qc @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -32,6 +33,7 @@ void dropclient_do(entity this) dropclient(this.owner); delete(this); } + /** * Schedules dropclient for a player and returns true; * if dropclient is already scheduled (for that player) it does nothing and returns false. @@ -142,12 +144,12 @@ void CreatureFrame_FallDamage(entity this) bool have_hook = false; for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot) { - .entity weaponentity = weaponentities[slot]; - if(this.(weaponentity).hook && this.(weaponentity).hook.state) - { - have_hook = true; - break; - } + .entity weaponentity = weaponentities[slot]; + if(this.(weaponentity).hook && this.(weaponentity).hook.state) + { + have_hook = true; + break; + } } if(!have_hook) { @@ -186,12 +188,14 @@ void CreatureFrame_All() }); } +// called shortly after map change in dedicated void Pause_TryPause_Dedicated(entity this) { - if (player_count == 0) + if (player_count == 0 && !intermission_running && !autocvar__endmatch) setpause(1); } +// called every normal frame in singleplayer/listen void Pause_TryPause() { int n = 0, p = 0; @@ -206,9 +210,12 @@ void Pause_TryPause() setpause(0); } +// called every paused frame by DP void SV_PausedTic(float elapsedtime) { - if (!server_is_dedicated) + if (autocvar__endmatch) // `endmatch` while paused + setpause(0); // proceed to intermission + else if (!server_is_dedicated) { if (autocvar_sv_autopause) Pause_TryPause(); @@ -224,33 +231,33 @@ void dedicated_print(string input) void make_safe_for_remove(entity e) { - if (e.initialize_entity) - { - entity ent, prev = NULL; - for (ent = initialize_entity_first; ent; ) - { - if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e))) - { - //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n"); - // skip it in linked list - if (prev) - { - prev.initialize_entity_next = ent.initialize_entity_next; - ent = prev.initialize_entity_next; - } - else - { - initialize_entity_first = ent.initialize_entity_next; - ent = initialize_entity_first; - } - } - else - { - prev = ent; - ent = ent.initialize_entity_next; - } - } - } + if (e.initialize_entity) + { + entity ent, prev = NULL; + for (ent = initialize_entity_first; ent; ) + { + if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e))) + { + //print("make_safe_for_remove: getting rid of initializer ", etos(ent), "\n"); + // skip it in linked list + if (prev) + { + prev.initialize_entity_next = ent.initialize_entity_next; + ent = prev.initialize_entity_next; + } + else + { + initialize_entity_first = ent.initialize_entity_next; + ent = initialize_entity_first; + } + } + else + { + prev = ent; + ent = ent.initialize_entity_next; + } + } + } } void remove_except_protected(entity e) @@ -262,15 +269,15 @@ void remove_except_protected(entity e) void remove_unsafely(entity e) { - if(e.classname == "spike") - error("Removing spikes is forbidden (crylink bug), please report"); - builtin_remove(e); + if(e.classname == "spike") + error("Removing spikes is forbidden (crylink bug), please report"); + builtin_remove(e); } void remove_safely(entity e) { - make_safe_for_remove(e); - builtin_remove(e); + make_safe_for_remove(e); + builtin_remove(e); } /* @@ -287,12 +294,14 @@ void systems_update(); void sys_phys_update(entity this, float dt); void StartFrame() { - // TODO: if move is more than 50ms, split it into two moves (this matches QWSV behavior and the client prediction) - IL_EACH(g_players, IS_FAKE_CLIENT(it), sys_phys_update(it, frametime)); - IL_EACH(g_players, IS_FAKE_CLIENT(it), PlayerPreThink(it)); + FOREACH_CLIENT(IS_FAKE_CLIENT(it), + { + // DP calls these for real clients only + sys_phys_update(it, frametime); // called by SV_PlayerPhysics for players + PlayerPreThink(it); + }); execute_next_frame(); - if (autocvar_sv_autopause && !server_is_dedicated) Pause_TryPause(); delete_fn = remove_unsafely; // not during spawning! serverprevtime = servertime; @@ -312,10 +321,10 @@ void StartFrame() ++c_seen; }); LOG_INFO( - "CEFC time: ", ftos(t * 1000), "ms; ", - "CEFC calls per second: ", ftos(c_seeing * (c_seen - 1) / t), "; ", - "CEFC 100% load at: ", ftos(solve_quadratic(t, -t, -1) * '0 1 0') - ); + "CEFC time: ", ftos(t * 1000), "ms; ", + "CEFC calls per second: ", ftos(c_seeing * (c_seen - 1) / t), "; ", + "CEFC 100% load at: ", ftos(solve_quadratic(t, -t, -1) * '0 1 0') + ); client_cefc_accumulatortime = time; client_cefc_accumulator = 0; } @@ -345,6 +354,10 @@ void StartFrame() CreatureFrame_All(); CheckRules_World(); + // after CheckRules_World() as it may set intermission_running, and after RedirectionThink() in case listen server is closing + if (autocvar_sv_autopause && !server_is_dedicated && !intermission_running) + Pause_TryPause(); + if (warmup_stage && !game_stopped && warmup_limit > 0 && time - game_starttime >= warmup_limit) { ReadyRestart(true); return; @@ -355,8 +368,13 @@ void StartFrame() MUTATOR_CALLHOOK(SV_StartFrame); GlobalStats_updateglobal(); - FOREACH_CLIENT(true, GlobalStats_update(it)); - IL_EACH(g_players, IS_FAKE_CLIENT(it), PlayerPostThink(it)); + FOREACH_CLIENT(true, + { + GlobalStats_update(it); + if (IS_FAKE_CLIENT(it)) + PlayerPostThink(it); // DP calls this for real clients only + PlayerFrame(it); + }); } .vector originjitter; @@ -388,22 +406,22 @@ void SV_OnEntityPreSpawnFunction(entity this) if (this.monster_attack) { IL_PUSH(g_monster_targets, this); - } + } // support special -1 and -2 angle from radiant if (this.angles == '0 -1 0') { this.angles = '-90 0 0'; } else if (this.angles == '0 -2 0') { this.angles = '+90 0 0'; - } + } - #define X(out, in) MACRO_BEGIN \ - if (in != 0) { out = out + (random() * 2 - 1) * in; } \ - MACRO_END - X(this.origin.x, this.originjitter.x); X(this.origin.y, this.originjitter.y); X(this.origin.z, this.originjitter.z); - X(this.angles.x, this.anglesjitter.x); X(this.angles.y, this.anglesjitter.y); X(this.angles.z, this.anglesjitter.z); - X(this.angles.y, this.anglejitter); - #undef X + #define X(out, in) MACRO_BEGIN \ + if (in != 0) { out = out + (random() * 2 - 1) * in; } \ + MACRO_END + X(this.origin.x, this.originjitter.x); X(this.origin.y, this.originjitter.y); X(this.origin.z, this.originjitter.z); + X(this.angles.x, this.anglesjitter.x); X(this.angles.y, this.anglesjitter.y); X(this.angles.z, this.anglesjitter.z); + X(this.angles.y, this.anglejitter); + #undef X if (MUTATOR_CALLHOOK(OnEntityPreSpawn, this)) { delete(this); @@ -467,6 +485,32 @@ string GetField_fullspawndata(entity e, string f, ...) return v; } +/* +============= +FindFileInMapPack + +Returns the first matching VFS file path that exists in the current map's pack. +Returns string_null if no files match or the map isn't packaged. +============= +*/ +string FindFileInMapPack(string pattern) +{ + if (!checkextension("DP_QC_FS_SEARCH_PACKFILE")) + return string_null; + + string base_pack = whichpack(strcat("maps/", mapname, ".bsp")); + if (base_pack == "" || !base_pack) // this map isn't packaged or there was an error + return string_null; + + int glob = search_packfile_begin(pattern, true, true, base_pack); + if (glob < 0) + return string_null; + + string file = search_getfilename(glob, 0); + search_end(glob); + return file; +} + void WarpZone_PostInitialize_Callback() { // create waypoint links for warpzones