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;
++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();
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)
- {
- j = search_getsize(fd);
- for(int i = 0; i < j; ++i)
- s = strcat(s, " ", search_getfilename(fd, i));
- search_end(fd);
- }
- fd = search_begin("*.serverpackage", 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);
}
- 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
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));