X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fg_world.qc;h=054e19d7466589c9ae0b3146843b9329d21157b9;hb=669311cae7c93d70ff08fa2e3dd30cabdd2da8fa;hp=b49b2160ed0a2860f2d98b81d90c0f473760fed9;hpb=692cb758fe8f25fa078bfd5885333ee031885600;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/g_world.qc b/qcsrc/server/g_world.qc index b49b2160e..054e19d74 100644 --- a/qcsrc/server/g_world.qc +++ b/qcsrc/server/g_world.qc @@ -24,7 +24,7 @@ #include "../common/monsters/all.qh" #include "../common/monsters/sv_monsters.qh" #include "../common/vehicles/all.qh" -#include "../common/notifications.qh" +#include "../common/notifications/all.qh" #include "../common/physics/player.qh" #include "../common/playerstats.qh" #include "../common/stats.qh" @@ -34,6 +34,7 @@ #include "../common/util.qh" #include "../common/items/all.qh" #include "../common/weapons/all.qh" +#include "../common/state.qh" const float LATENCY_THINKRATE = 10; .float latency_sum; @@ -48,13 +49,13 @@ void PingPLReport_Think() delta = 3 / maxclients; if(delta < sys_frametime) delta = 0; - self.nextthink = time + delta; + this.nextthink = time + delta; - e = edict_num(self.cnt + 1); + e = edict_num(this.cnt + 1); if(IS_REAL_CLIENT(e)) { WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); - WriteByte(MSG_BROADCAST, self.cnt); + WriteByte(MSG_BROADCAST, this.cnt); WriteShort(MSG_BROADCAST, max(1, e.ping)); WriteByte(MSG_BROADCAST, ceil(e.ping_packetloss * 255)); WriteByte(MSG_BROADCAST, ceil(e.ping_movementloss * 255)); @@ -71,17 +72,16 @@ void PingPLReport_Think() else { WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT); - WriteByte(MSG_BROADCAST, self.cnt); + WriteByte(MSG_BROADCAST, this.cnt); WriteShort(MSG_BROADCAST, 0); WriteByte(MSG_BROADCAST, 0); WriteByte(MSG_BROADCAST, 0); } - self.cnt = (self.cnt + 1) % maxclients; + this.cnt = (this.cnt + 1) % maxclients; } void PingPLReport_Spawn() { - pingplreport = new(pingplreport); - make_pure(pingplreport); + pingplreport = new_pure(pingplreport); pingplreport.think = PingPLReport_Think; pingplreport.nextthink = time; } @@ -232,7 +232,6 @@ void cvar_changes_init() BADPREFIX("g_chat_flood_"); BADPREFIX("g_ghost_items"); BADPREFIX("g_playerstats_"); - BADPREFIX("g_respawn_ghosts"); BADPREFIX("g_voice_flood_"); BADPREFIX("log_file"); BADPREFIX("rcon_"); @@ -269,7 +268,9 @@ void cvar_changes_init() BADCVAR("g_nexball"); BADCVAR("g_onslaught"); BADCVAR("g_race"); + BADCVAR("g_race_laps_limit"); BADCVAR("g_race_qualifying_timelimit"); + BADCVAR("g_race_qualifying_timelimit_override"); BADCVAR("g_tdm"); BADCVAR("g_tdm_teams"); BADCVAR("leadlimit"); @@ -300,47 +301,53 @@ void cvar_changes_init() // now check if the changes are actually gameplay relevant - // does nothing visible + // does nothing gameplay relevant BADCVAR("captureleadlimit_override"); + BADCVAR("gameversion"); + BADCVAR("g_allow_oldvortexbeam"); BADCVAR("g_balance_kill_delay"); - BADCVAR("g_ca_point_limit"); + BADCVAR("g_campcheck_distance"); BADCVAR("g_ca_point_leadlimit"); + BADCVAR("g_ca_point_limit"); BADCVAR("g_ctf_captimerecord_always"); BADCVAR("g_ctf_flag_glowtrails"); BADCVAR("g_ctf_flag_pickup_verbosename"); BADCVAR("g_domination_point_leadlimit"); BADCVAR("g_forced_respawn"); - BADCVAR("g_freezetag_point_limit"); BADCVAR("g_freezetag_point_leadlimit"); - BADCVAR("g_keyhunt_point_leadlimit"); - BADPREFIX("g_mod_"); + BADCVAR("g_freezetag_point_limit"); + BADCVAR("g_hats"); BADCVAR("g_invasion_point_limit"); + BADCVAR("g_keyhunt_point_leadlimit"); BADCVAR("g_nexball_goalleadlimit"); - BADCVAR("g_tdm_point_limit"); BADCVAR("g_tdm_point_leadlimit"); + BADCVAR("g_tdm_point_limit"); BADCVAR("leadlimit_and_fraglimit"); BADCVAR("leadlimit_override"); BADCVAR("pausable"); BADCVAR("sv_allow_fullbright"); BADCVAR("sv_checkforpacketsduringsleep"); + BADCVAR("sv_intermission_cdtrack"); + BADCVAR("sv_minigames"); + BADCVAR("sv_namechangetimer"); + BADCVAR("sv_precacheplayermodels"); BADCVAR("sv_timeout"); - BADPREFIX("sv_timeout_"); BADPREFIX("crypto_"); + BADPREFIX("gameversion_"); BADPREFIX("g_chat_"); BADPREFIX("g_ctf_captimerecord_"); BADPREFIX("g_maplist_votable_"); + BADPREFIX("g_mod_"); + BADPREFIX("g_respawn_"); BADPREFIX("net_"); BADPREFIX("prvm_"); BADPREFIX("skill_"); BADPREFIX("sv_cullentities_"); BADPREFIX("sv_maxidle_"); + BADPREFIX("sv_minigames_"); + BADPREFIX("sv_timeout_"); BADPREFIX("sv_vote_"); BADPREFIX("timelimit_"); - BADCVAR("gameversion"); - BADPREFIX("gameversion_"); - BADCVAR("sv_minigames"); - BADPREFIX("sv_minigames_"); - BADCVAR("sv_namechangetimer"); // allowed changes to server admins (please sync this to server.cfg) // vi commands: @@ -385,7 +392,9 @@ void cvar_changes_init() BADCVAR("g_mirrordamage"); BADCVAR("g_nexball_goallimit"); BADCVAR("g_powerups"); + BADCVAR("g_spawnshieldtime"); BADCVAR("g_start_delay"); + BADCVAR("g_superspectate"); BADCVAR("g_tdm_teams_override"); BADCVAR("g_warmup"); BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay"); @@ -404,6 +413,7 @@ void cvar_changes_init() BADCVAR("sv_autotaunt"); BADCVAR("sv_curl_defaulturl"); BADCVAR("sv_defaultcharacter"); + BADCVAR("sv_defaultcharacterskin"); BADCVAR("sv_defaultplayercolors"); BADCVAR("sv_defaultplayermodel"); BADCVAR("sv_defaultplayerskin"); @@ -423,7 +433,6 @@ void cvar_changes_init() BADCVAR("sv_vote_simple_majority_factor"); BADCVAR("teamplay_mode"); BADCVAR("timelimit_override"); - BADCVAR("g_spawnshieldtime"); BADPREFIX("g_warmup_"); BADPREFIX("sv_ready_restart_"); @@ -503,24 +512,23 @@ entity randomseed; bool RandomSeed_Send(entity this, entity to, int sf) { WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED); - WriteShort(MSG_ENTITY, self.cnt); + WriteShort(MSG_ENTITY, this.cnt); return true; } void RandomSeed_Think() {SELFPARAM(); - self.cnt = bound(0, floor(random() * 65536), 65535); - self.nextthink = time + 5; + this.cnt = bound(0, floor(random() * 65536), 65535); + this.nextthink = time + 5; - self.SendFlags |= 1; + this.SendFlags |= 1; } void RandomSeed_Spawn() {SELFPARAM(); - randomseed = new(randomseed); - make_pure(randomseed); + randomseed = new_pure(randomseed); randomseed.think = RandomSeed_Think; Net_LinkEntity(randomseed, false, 0, RandomSeed_Send); - WITH(entity, self, randomseed, randomseed.think()); // sets random seed and nextthink + WITHSELF(randomseed, randomseed.think()); // sets random seed and nextthink } spawnfunc(__init_dedicated_server) @@ -555,6 +563,18 @@ void __init_dedicated_server_shutdown() { MapInfo_Shutdown(); } +void SetLimits(int fraglimit_override, int leadlimit_override, float timelimit_override, float qualifying_override) +{ + if(!autocvar_g_campaign) + { + if(fraglimit_override >= 0) cvar_set("fraglimit", ftos(fraglimit_override)); + if(timelimit_override >= 0) cvar_set("timelimit", ftos(timelimit_override)); + if(leadlimit_override >= 0) cvar_set("leadlimit", ftos(leadlimit_override)); + if(qualifying_override >= 0) cvar_set("g_race_qualifying_timelimit", ftos(qualifying_override)); + } + limits_are_set = true; +} + void Map_MarkAsRecent(string m); float world_already_spawned; void Nagger_Init(); @@ -563,7 +583,70 @@ void WeaponStats_Init(); void WeaponStats_Shutdown(); spawnfunc(worldspawn) { - float fd, l, j, n; + server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated"))); + + bool wantrestart = false; + { + if (!server_is_dedicated) + { + // force unloading of server pk3 files when starting a listen server + // localcmd("\nfs_rescan\n"); // FIXME: does more harm than good, has unintended side effects. What we really want is to unload temporary pk3s only + // restore csqc_progname too + string expect = "csprogs.dat"; + wantrestart = cvar_string_normal("csqc_progname") != expect; + cvar_set_normal("csqc_progname", expect); + } + else + { + // Try to use versioned csprogs from pk3 + // Only ever use versioned csprogs.dat files on dedicated servers; + // we need to reset csqc_progname on clients ourselves, and it's easier if the client's release name is constant + string pk3csprogs = "csprogs-" WATERMARK ".dat"; + // This always works; fall back to it if a versioned csprogs.dat is suddenly missing + string select = "csprogs.dat"; + if (fexists(pk3csprogs)) select = pk3csprogs; + if (cvar_string_normal("csqc_progname") != select) + { + cvar_set_normal("csqc_progname", select); + wantrestart = true; + } + // Check for updates on startup + // We do it this way for atomicity so that connecting clients still match the server progs and don't disconnect + int sentinel = fopen("progs.txt", FILE_READ); + if (sentinel >= 0) + { + string switchversion = fgets(sentinel); + fclose(sentinel); + if (switchversion != "" && switchversion != WATERMARK) + { + LOG_INFOF("Switching progs: " WATERMARK " -> %s\n", switchversion); + // if it doesn't exist, assume either: + // a) the current program was overwritten + // b) this is a client only update + string newprogs = sprintf("progs-%s.dat", switchversion); + if (fexists(newprogs)) + { + cvar_set_normal("sv_progs", newprogs); + wantrestart = true; + } + string newcsprogs = sprintf("csprogs-%s.dat", switchversion); + if (fexists(newcsprogs)) + { + cvar_set_normal("csqc_progname", newcsprogs); + wantrestart = true; + } + } + } + } + if (wantrestart) + { + LOG_INFOF("Restart requested\n"); + changelevel(mapname); + // let initialization continue, shutdown depends on it + } + } + + float fd, l; string s; cvar = cvar_normal; @@ -586,8 +669,6 @@ spawnfunc(worldspawn) ++maxclients; } - server_is_dedicated = (stof(cvar_defstring("is_dedicated")) ? true : false); - // needs to be done so early because of the constants they create static_init(); @@ -649,6 +730,12 @@ spawnfunc(worldspawn) readlevelcvars(); GrappleHookInit(); + if(!limits_are_set) + SetLimits(autocvar_fraglimit_override, autocvar_leadlimit_override, autocvar_timelimit_override, -1); + + if(warmup_limit == 0) + warmup_limit = (autocvar_timelimit > 0) ? autocvar_timelimit * 60 : autocvar_timelimit; + player_count = 0; bot_waypoints_for_items = autocvar_g_waypoints_for_items; if(bot_waypoints_for_items == 1) @@ -780,34 +867,37 @@ spawnfunc(worldspawn) CheatInit(); - localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n"); + if (!wantrestart) localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n"); // fill sv_curl_serverpackages from .serverpackage files - if(autocvar_sv_curl_serverpackages_auto) + if (autocvar_sv_curl_serverpackages_auto) { - s = ""; - n = tokenize_console(cvar_string("sv_curl_serverpackages")); - for(int i = 0; i < n; ++i) - if(substring(argv(i), -18, -1) != "-serverpackage.txt") - if(substring(argv(i), -14, -1) != ".serverpackage") // OLD legacy - s = strcat(s, " ", argv(i)); - fd = search_begin("*-serverpackage.txt", true, false); - if(fd >= 0) + s = "csprogs-" WATERMARK ".txt"; + // remove automatically managed files from the list to prevent duplicates + for (int i = 0, n = tokenize_console(cvar_string("sv_curl_serverpackages")); i < n; ++i) { - j = search_getsize(fd); - for(int i = 0; i < j; ++i) - s = strcat(s, " ", search_getfilename(fd, i)); - search_end(fd); + string pkg = argv(i); + if (startsWith(pkg, "csprogs-")) continue; + if (endsWith(pkg, "-serverpackage.txt")) continue; + if (endsWith(pkg, ".serverpackage")) continue; // OLD legacy + s = cons(s, pkg); } - fd = search_begin("*.serverpackage", true, false); - if(fd >= 0) - { - j = search_getsize(fd); - for(int i = 0; i < j; ++i) - s = strcat(s, " ", search_getfilename(fd, i)); - search_end(fd); - } - cvar_set("sv_curl_serverpackages", substring(s, 1, -1)); + // add automatically managed files to the list + #define X(match) MACRO_BEGIN { \ + fd = search_begin(match, true, false); \ + if (fd >= 0) \ + { \ + for (int i = 0, j = search_getsize(fd); i < j; ++i) \ + { \ + s = cons(s, search_getfilename(fd, i)); \ + } \ + search_end(fd); \ + } \ + } MACRO_END + X("*-serverpackage.txt"); + X("*.serverpackage"); + #undef X + cvar_set("sv_curl_serverpackages", s); } // MOD AUTHORS: change this, and possibly remove a few of the blocks below to ignore certain changes @@ -1225,7 +1315,7 @@ void IntermissionThink() return; if(!mapvote_initialized) - if (time < intermission_exittime + 10 && !(self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE)) + if (time < intermission_exittime + 10 && !(PHYS_INPUT_BUTTON_ATCK(self) || PHYS_INPUT_BUTTON_JUMP(self) || PHYS_INPUT_BUTTON_ATCK2(self) || PHYS_INPUT_BUTTON_HOOK(self) || PHYS_INPUT_BUTTON_USE(self))) return; MapVote_Start(); @@ -1432,6 +1522,7 @@ only called if a time or frag limit has expired */ void NextLevel() { + SELFPARAM(); gameover = true; intermission_running = 1; @@ -1459,7 +1550,7 @@ void NextLevel() PlayerStats_GameReport(true); WeaponStats_Shutdown(); - Kill_Notification(NOTIF_ALL, world, MSG_CENTER, 0); // kill all centerprints now + Kill_Notification(NOTIF_ALL, world, MSG_CENTER, CPID_Null); // kill all centerprints now if(autocvar_sv_eventlog) GameLogEcho(":gameover"); @@ -1472,9 +1563,7 @@ void NextLevel() bprint(it.netname, " ^7wins.\n"); )); - entity oldself = self; - target_music_kill(); - self = oldself; + WITHSELF(NULL, target_music_kill()); if(autocvar_g_campaign) CampaignPreIntermission(); @@ -1496,8 +1585,8 @@ void CheckRules_Player() if (gameover) // someone else quit the game already return; - if(!IS_DEAD(self)) - self.play_time += frametime; + if(!IS_DEAD(this)) + this.play_time += frametime; // fixme: don't check players; instead check spawnfunc_dom_team and spawnfunc_ctf_team entities // (div0: and that in CheckRules_World please) @@ -1583,51 +1672,6 @@ void ClearWinners() FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(it.winning = 0)); } -// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives) -// they win. Otherwise the defending team wins once the timelimit passes. -void assault_new_round(); -float WinningCondition_Assault() -{SELFPARAM(); - float status; - - WinningConditionHelper(); // set worldstatus - - status = WINNING_NO; - // as the timelimit has not yet passed just assume the defending team will win - if(assault_attacker_team == NUM_TEAM_1) - { - SetWinners(team, NUM_TEAM_2); - } - else - { - SetWinners(team, NUM_TEAM_1); - } - - entity ent; - ent = find(world, classname, "target_assault_roundend"); - if(ent) - { - if(ent.winning) // round end has been triggered by attacking team - { - bprint("ASSAULT: round completed...\n"); - SetWinners(team, assault_attacker_team); - - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0)); - - if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round - { - status = WINNING_YES; - } - else - { - WITH(entity, self, ent, assault_new_round()); - } - } - } - - return status; -} - void ShuffleMaplist() { cvar_set("g_maplist", shufflewords(autocvar_g_maplist)); @@ -1942,40 +1986,36 @@ string GotoMap(string m) void EndFrame() -{SELFPARAM(); +{ anticheat_endframe(); - float altime; - FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA( + FOREACH_CLIENT(IS_REAL_CLIENT(it), { entity e = IS_SPEC(it) ? it.enemy : it; - if(e.typehitsound) + if (e.typehitsound) { it.typehit_time = time; - else if(e.damage_dealt) - { + } else if (e.damage_dealt) { it.hit_time = time; it.damage_dealt_total += ceil(e.damage_dealt); } - )); - altime = time + frametime * (1 + autocvar_g_antilag_nudge); + }); // add 1 frametime because after this, engine SV_Physics // increases time by a frametime and then networks the frame // add another frametime because client shows everything with // 1 frame of lag (cl_nolerp 0). The last +1 however should not be // needed! - FOREACH_CLIENT(true, LAMBDA( + float altime = time + frametime * (1 + autocvar_g_antilag_nudge); + FOREACH_CLIENT(true, { it.typehitsound = false; it.damage_dealt = 0; - setself(it); - antilag_record(it, altime); - )); - FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, LAMBDA( - setself(it); - antilag_record(it, altime); - )); - FOREACH_CLIENT(PS(it), LAMBDA( + antilag_record(it, CS(it), altime); + }); + FOREACH_ENTITY_FLAGS(flags, FL_MONSTER, { + antilag_record(it, it, altime); + }); + FOREACH_CLIENT(PS(it), { PlayerState s = PS(it); s.ps_push(s, it); - )); + }); }