X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Frace.qc;h=715d00d46921df81756e1d6209d4b3a91bc5930c;hb=5dc828e3b59c65f75c870d4a57e34c023cdbdb86;hp=183da23f9a6944ce0c5424ee1e17ff94086c5edf;hpb=60b0e81cdaed847a7aac9d234f219937ab9462b2;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/race.qc b/qcsrc/server/race.qc index 183da23f9..715d00d46 100644 --- a/qcsrc/server/race.qc +++ b/qcsrc/server/race.qc @@ -1,27 +1,71 @@ #include "race.qh" -#include -#include -#include "client.qh" -#include "portals.qh" -#include "scores.qh" -#include "spawnpoints.qh" -#include "bot/api.qh" -#include "command/getreplies.qh" -#include "../common/deathtypes/all.qh" -#include "../common/notifications/all.qh" -#include "../common/mapinfo.qh" +#include +#include #include +#include +#include +#include #include +#include #include -#include "../common/mapobjects/subs.qh" -#include -#include "../lib/warpzone/util_server.qh" -#include "../lib/warpzone/common.qh" -#include "../common/mutators/mutator/waypoints/waypointsprites.qh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +.string stored_netname; // TODO: store this information independently of race-based gamemodes + +string uid2name(string myuid) +{ + string s = db_get(ServerProgsDB, strcat("/uid2name/", myuid)); + + // FIXME remove this later after 0.6 release + // convert old style broken records to correct style + if(s == "") + { + s = db_get(ServerProgsDB, strcat("uid2name", myuid)); + if(s != "") + { + db_put(ServerProgsDB, strcat("/uid2name/", myuid), s); + db_remove(ServerProgsDB, strcat("uid2name", myuid)); + } + } + + if(s == "") + s = "^1Unregistered Player"; + return s; +} + +void write_recordmarker(entity pl, float tstart, float dt) +{ + GameLogEcho(strcat(":recordset:", ftos(pl.playerid), ":", ftos(dt))); + + // also write a marker into demo files for demotc-race-record-extractor to find + stuffcmd(pl, + strcat( + strcat("//", strconv(2, 0, 0, GetGametype()), " RECORD SET ", TIME_ENCODED_TOSTRING(TIME_ENCODE(dt))), + " ", ftos(tstart), " ", ftos(dt), "\n")); +} IntrusiveList g_race_targets; -STATIC_INIT(g_race_targets) { g_race_targets = IL_NEW(); } +IntrusiveList g_racecheckpoints; void race_InitSpectator() { @@ -30,20 +74,14 @@ void race_InitSpectator() race_SendNextCheckpoint(msg_entity.enemy, 1); } -void W_Porto_Fail(entity this, float failhard); - float race_readTime(string map, float pos) { - string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD)); - - return stof(db_get(ServerProgsDB, strcat(map, rr, "time", ftos(pos)))); + return stof(db_get(ServerProgsDB, strcat(map, record_type, "time", ftos(pos)))); } string race_readUID(string map, float pos) { - string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD)); - - return db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos))); + return db_get(ServerProgsDB, strcat(map, record_type, "crypto_idfp", ftos(pos))); } float race_readPos(string map, float t) @@ -60,8 +98,6 @@ float race_readPos(string map, float t) void race_writeTime(string map, float t, string myuid) { - string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD)); - float newpos; newpos = race_readPos(map, t); @@ -76,8 +112,8 @@ void race_writeTime(string map, float t, string myuid) // player improved his existing record, only have to iterate on ranks between new and old recs for (i = prevpos; i > newpos; --i) { - db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1))); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1)); + db_put(ServerProgsDB, strcat(map, record_type, "time", ftos(i)), ftos(race_readTime(map, i - 1))); + db_put(ServerProgsDB, strcat(map, record_type, "crypto_idfp", ftos(i)), race_readUID(map, i - 1)); } } else @@ -85,28 +121,41 @@ void race_writeTime(string map, float t, string myuid) // player has no ranked record yet for (i = RANKINGS_CNT; i > newpos; --i) { - db_put(ServerProgsDB, strcat(map, rr, "time", ftos(i)), ftos(race_readTime(map, i - 1))); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(i)), race_readUID(map, i - 1)); + float other_time = race_readTime(map, i - 1); + if (other_time) { + db_put(ServerProgsDB, strcat(map, record_type, "time", ftos(i)), ftos(other_time)); + db_put(ServerProgsDB, strcat(map, record_type, "crypto_idfp", ftos(i)), race_readUID(map, i - 1)); + } } } // store new time itself - db_put(ServerProgsDB, strcat(map, rr, "time", ftos(newpos)), ftos(t)); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(newpos)), myuid); + db_put(ServerProgsDB, strcat(map, record_type, "time", ftos(newpos)), ftos(t)); + db_put(ServerProgsDB, strcat(map, record_type, "crypto_idfp", ftos(newpos)), myuid); } string race_readName(string map, float pos) { - string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD)); + return uid2name(db_get(ServerProgsDB, strcat(map, record_type, "crypto_idfp", ftos(pos)))); +} - return uid2name(db_get(ServerProgsDB, strcat(map, rr, "crypto_idfp", ftos(pos)))); +void race_checkAndWriteName(entity player) +{ + if(CS_CVAR(player).cvar_cl_allow_uidtracking == 1 && CS_CVAR(player).cvar_cl_allow_uid2name == 1) + { + if (!player.stored_netname) + player.stored_netname = strzone(uid2name(player.crypto_idfp)); + if(player.stored_netname != player.netname) + { + db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname); + strcpy(player.stored_netname, player.netname); + } + } } const float MAX_CHECKPOINTS = 255; -spawnfunc(target_checkpoint); - .float race_penalty; .float race_penalty_accumulator; .string race_penalty_reason; @@ -206,7 +255,6 @@ void race_send_recordtime(float msg) WriteInt24_t(msg, race_readTime(GetMapname(), 1)); } - void race_send_speedaward(float msg) { // send the best speed of the round @@ -233,7 +281,7 @@ void race_send_rankings_cnt(float msg) WriteByte(msg, m); } -void race_SendRankings(float pos, float prevpos, float del, float msg) +void race_SendRanking(float pos, float prevpos, float del, float msg) { WriteHeader(msg, TE_CSQC_RACE); WriteByte(msg, RACE_NET_SERVER_RANKINGS); @@ -244,6 +292,56 @@ void race_SendRankings(float pos, float prevpos, float del, float msg) WriteInt24_t(msg, race_readTime(GetMapname(), pos)); } +void race_SpeedAwardFrame(entity player) +{ + if (IS_OBSERVER(player)) + return; + + if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed)) + { + speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1'); + speedaward_holder = player.netname; + speedaward_uid = player.crypto_idfp; + speedaward_lastupdate = time; + } + if (speedaward_speed > speedaward_lastsent && (time - speedaward_lastupdate > 1 || intermission_running)) + { + race_send_speedaward(MSG_ALL); + speedaward_lastsent = speedaward_speed; + if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "") + { + speedaward_alltimebest = speedaward_speed; + speedaward_alltimebest_holder = speedaward_holder; + speedaward_alltimebest_uid = speedaward_uid; + db_put(ServerProgsDB, strcat(GetMapname(), record_type, "speed/speed"), ftos(speedaward_alltimebest)); + db_put(ServerProgsDB, strcat(GetMapname(), record_type, "speed/crypto_idfp"), speedaward_alltimebest_uid); + race_send_speedaward_alltimebest(MSG_ALL); + } + } +} + +void race_SendAll(entity player, bool only_rankings) +{ + if(!IS_REAL_CLIENT(player)) + return; + + msg_entity = player; + if (!only_rankings) + { + race_send_recordtime(MSG_ONE); + race_send_speedaward(MSG_ONE); + + speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), record_type, "speed/speed"))); + speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), record_type, "speed/crypto_idfp"))); + race_send_speedaward_alltimebest(MSG_ONE); + } + + int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt); + race_send_rankings_cnt(MSG_ONE); + for (int i = 1; i <= m; ++i) + race_SendRanking(i, 0, 0, MSG_ONE); +} + void race_SendStatus(float id, entity e) { if(!IS_REAL_CLIENT(e)) @@ -324,7 +422,7 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e, race_send_recordtime(MSG_ALL); } - race_SendRankings(newpos, player_prevpos, 0, MSG_ALL); + race_SendRanking(newpos, player_prevpos, 0, MSG_ALL); strcpy(rankings_reply, getrankings()); if(newpos == player_prevpos) @@ -352,24 +450,22 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e, void race_deleteTime(string map, float pos) { - string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD)); - for(int i = pos; i <= RANKINGS_CNT; ++i) { string therank = ftos(i); if (i == RANKINGS_CNT) { - db_remove(ServerProgsDB, strcat(map, rr, "time", therank)); - db_remove(ServerProgsDB, strcat(map, rr, "crypto_idfp", therank)); + db_remove(ServerProgsDB, strcat(map, record_type, "time", therank)); + db_remove(ServerProgsDB, strcat(map, record_type, "crypto_idfp", therank)); } else { - db_put(ServerProgsDB, strcat(map, rr, "time", therank), ftos(race_readTime(GetMapname(), i+1))); - db_put(ServerProgsDB, strcat(map, rr, "crypto_idfp", therank), race_readUID(GetMapname(), i+1)); + db_put(ServerProgsDB, strcat(map, record_type, "time", therank), ftos(race_readTime(GetMapname(), i+1))); + db_put(ServerProgsDB, strcat(map, record_type, "crypto_idfp", therank), race_readUID(GetMapname(), i+1)); } } - race_SendRankings(pos, 0, 1, MSG_ALL); + race_SendRanking(pos, 0, 1, MSG_ALL); if(pos == 1) race_send_recordtime(MSG_ALL); @@ -566,6 +662,9 @@ void race_ClearTime(entity e) void checkpoint_passed(entity this, entity player) { + if(IS_VEHICLE(player) && player.owner) + player = player.owner; + if(player.personal && autocvar_g_allow_checkpoints) return; // practice mode! @@ -740,9 +839,35 @@ bool race_waypointsprite_visible_for_player(entity this, entity player, entity v return false; } +void defrag_waypointsprites(entity targeted, entity checkpoint) +{ + for(entity t = findchain(target, targeted.targetname); t; t = t.chain) + { + if(t.modelindex) + { + entity s = WP_RaceStart; + + if(checkpoint.classname == "target_checkpoint") + s = WP_RaceCheckpoint; + else if(checkpoint.classname == "target_stopTimer") + s = WP_RaceFinish; + + vector o = (t.absmin + t.absmax) * 0.5; + + WaypointSprite_SpawnFixed(s, o, t, sprite, RADARICON_NONE); + + t.sprite.realowner = checkpoint; + t.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player; + } + + if(t.targetname) + defrag_waypointsprites(t, checkpoint); + } +} + void trigger_race_checkpoint_verify(entity this) { - static bool have_verified; + static bool have_verified; if (have_verified) return; have_verified = true; @@ -758,25 +883,25 @@ void trigger_race_checkpoint_verify(entity this) // race only (middle of the race) g_race_qualifying = false; pl_race_place = 0; - if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) { + if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) { error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for respawning in race) - bailing out")); - } + } if (i == 0) { // qualifying only g_race_qualifying = 1; pl_race_place = race_lowest_place_spawn; - if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) { + if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) { error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for qualifying) - bailing out")); - } + } // race only (initial spawn) g_race_qualifying = 0; for (int p = 1; p <= race_highest_place_spawn; ++p) { pl_race_place = p; - if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) { + if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) { error(strcat("Checkpoint ", ftos(i), " misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for initially spawning in race) - bailing out")); - } + } } } } @@ -785,9 +910,9 @@ void trigger_race_checkpoint_verify(entity this) pl_race_checkpoint = race_NextCheckpoint(0); g_race_qualifying = 1; pl_race_place = race_lowest_place_spawn; - if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false)) { + if (!Spawn_FilterOutBadSpots(this, findchain(classname, "info_player_deathmatch"), 0, false, true)) { error(strcat("Checkpoint 0 misses a spawnpoint with race_place==", ftos(pl_race_place), " (used for qualifying) - bailing out")); - } + } } else { pl_race_checkpoint = race_NextCheckpoint(0); g_race_qualifying = 1; @@ -809,8 +934,8 @@ void trigger_race_checkpoint_verify(entity this) for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) { if (argv(0) == cp.targetname) { cp.race_checkpoint = stof(argv(1)); - } - } + } + } } fclose(fh); } @@ -818,37 +943,12 @@ void trigger_race_checkpoint_verify(entity this) g_race_qualifying = qual; - IL_EACH(g_race_targets, it.classname == "target_checkpoint" || it.classname == "target_startTimer" || it.classname == "target_stopTimer", - { - if(it.targetname == "" || !it.targetname) // somehow this is a case... - continue; - entity cpt = it; - FOREACH_ENTITY_STRING(target, cpt.targetname, - { - vector org = (it.absmin + it.absmax) * 0.5; - if(cpt.race_checkpoint == 0) - WaypointSprite_SpawnFixed(WP_RaceStart, org, it, sprite, RADARICON_NONE); - else - WaypointSprite_SpawnFixed(WP_RaceCheckpoint, org, it, sprite, RADARICON_NONE); - - it.sprite.realowner = cpt; - it.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player; - }); - }); - if (race_timed_checkpoint) { if (defrag_ents) { IL_EACH(g_race_targets, it.classname == "target_checkpoint" || it.classname == "target_startTimer" || it.classname == "target_stopTimer", { - entity cpt = it; - if(it.classname == "target_startTimer" || it.classname == "target_stopTimer") { - if(it.targetname == "" || !it.targetname) // somehow this is a case... - continue; - FOREACH_ENTITY_STRING(target, cpt.targetname, { - if(it.sprite) - WaypointSprite_UpdateSprites(it.sprite, ((cpt.classname == "target_startTimer") ? WP_RaceStart : WP_RaceFinish), WP_Null, WP_Null); - }); - } + defrag_waypointsprites(it, it); + if(it.classname == "target_checkpoint") { if(it.race_checkpoint == -2) defragcpexists = -1; // something's wrong with the defrag cp file or it has not been written yet, set defragcpexists to -1 so that it will be rewritten when someone finishes @@ -859,17 +959,17 @@ void trigger_race_checkpoint_verify(entity this) for (entity cp = NULL; (cp = find(cp, classname, "target_checkpoint"));) { if (cp.race_checkpoint > largest_cp_id) { largest_cp_id = cp.race_checkpoint; - } - } + } + } for (entity cp = NULL; (cp = find(cp, classname, "target_stopTimer"));) { cp.race_checkpoint = largest_cp_id + 1; // finish line - } + } race_highest_checkpoint = largest_cp_id + 1; race_timed_checkpoint = largest_cp_id + 1; } else { for (entity cp = NULL; (cp = find(cp, classname, "target_stopTimer"));) { cp.race_checkpoint = 255; // finish line - } + } race_highest_checkpoint = 255; race_timed_checkpoint = 255; } @@ -878,14 +978,14 @@ void trigger_race_checkpoint_verify(entity this) { if (it.race_checkpoint == 0) { WaypointSprite_UpdateSprites(it.sprite, WP_RaceStart, WP_Null, WP_Null); - } else if (it.race_checkpoint == race_timed_checkpoint) { + } else if (it.race_checkpoint == race_timed_checkpoint) { WaypointSprite_UpdateSprites(it.sprite, WP_RaceFinish, WP_Null, WP_Null); } - }); + }); } } - if (defrag_ents) { + if (defrag_ents) { /* The following hack shall be removed when per-player trigger_multiple.wait is implemented for cts */ for (entity trigger = NULL; (trigger = find(trigger, classname, "trigger_multiple")); ) { for (entity targ = NULL; (targ = find(targ, targetname, trigger.target)); ) { if (targ.classname == "target_checkpoint" || targ.classname == "target_startTimer" || targ.classname == "target_stopTimer") { @@ -987,12 +1087,18 @@ spawnfunc(trigger_race_checkpoint) this.sprite.waypointsprite_visible_for_player = race_waypointsprite_visible_for_player; this.spawn_evalfunc = trigger_race_checkpoint_spawn_evalfunc; + if (!g_racecheckpoints) + g_racecheckpoints = IL_NEW(); IL_PUSH(g_racecheckpoints, this); + // trigger_race_checkpoint_verify checks this list too + if (!g_race_targets) + g_race_targets = IL_NEW(); + InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET); } -spawnfunc(target_checkpoint) // defrag entity +void target_checkpoint_setup(entity this) { if(!g_race && !g_cts) { delete(this); return; } defrag_ents = 1; @@ -1032,13 +1138,26 @@ spawnfunc(target_checkpoint) // defrag entity race_timed_checkpoint = 1; + if (!g_race_targets) + g_race_targets = IL_NEW(); IL_PUSH(g_race_targets, this); + // trigger_race_checkpoint_verify checks this list too + if (!g_racecheckpoints) + g_racecheckpoints = IL_NEW(); + InitializeEntity(this, trigger_race_checkpoint_verify, INITPRIO_FINDTARGET); } -spawnfunc(target_startTimer) { spawnfunc_target_checkpoint(this); } -spawnfunc(target_stopTimer) { spawnfunc_target_checkpoint(this); } +spawnfunc(target_checkpoint) +{ + // xonotic defrag entity + target_checkpoint_setup(this); +} + +// compatibility entity names +spawnfunc(target_startTimer) { target_checkpoint_setup(this); } +spawnfunc(target_stopTimer) { target_checkpoint_setup(this); } void race_AbandonRaceCheck(entity p) {