diff --git a/patches/anticheat.patch b/patches/anticheat.patch index fb5c41b..2c114b1 100644 --- a/patches/anticheat.patch +++ b/patches/anticheat.patch @@ -1,23 +1,3 @@ -Subject: [PATCH] add anticheat.patch, clean up Makefile, use Zig to - cross-compile - ---- - src/anticheat/anticheat.cpp | 637 +++++++++++++++++++++++++++ - src/engine/engine.h | 6 + - src/engine/main.cpp | 17 + - src/engine/movie.cpp | 4 + - src/engine/server.cpp | 17 + - src/engine/sound.cpp | 4 + - src/engine/texture.cpp | 5 +- - src/fpsgame/client.cpp | 19 + - src/fpsgame/game.h | 35 +- - src/fpsgame/server.cpp | 60 ++- - src/p1xbraten/capability_probing.cpp | 3 + - src/shared/cube.h | 2 +- - src/shared/igame.h | 14 +- - 13 files changed, 817 insertions(+), 6 deletions(-) - create mode 100644 src/anticheat/anticheat.cpp - diff --git src/anticheat/anticheat.cpp src/anticheat/anticheat.cpp new file mode 100644 index 0000000..2fe07ee @@ -846,10 +826,10 @@ index c5ae27e..6b87170 100644 if(remote) stopfollowing(); ignores.setsize(0); connected = remote = false; -@@ -2076,7 +2079,23 @@ namespace game - managedgamedemonextmatch = val!=0; +@@ -2091,7 +2094,23 @@ namespace game + } + else enddemorecord(true); break; - } +#ifdef ANTICHEAT + case N_P1X_ANTICHEAT_BEGINSESSION: + triggeranticheatsession(); @@ -877,18 +857,15 @@ index 0a4c901..4e9fe3a 100644 @@ -215,6 +215,7 @@ enum // protocol extensions - static const char * const CAP_PROBE_CLIENT_DEMO_UPLOAD = "capability_probe_protocol_extension_p1x_client_demo_upload"; + static const char * const CAP_PROBE_CLIENT_DEMO_UPLOAD = "capability_probe_protocol_extension_p1x_client_demo_upload_v2"; +static const char * const CAP_PROBE_ANTICHEAT = "capability_probe_protocol_extension_p1x_anticheat"; // network messages codes, c2s, c2c, s2c -@@ -245,8 +246,11 @@ enum - N_INITTOKENS, N_TAKETOKEN, N_EXPIRETOKENS, N_DROPTOKENS, N_DEPOSITTOKENS, N_STEALTOKENS, - N_SERVCMD, - N_DEMOPACKET, -- N_P1X_SETIP = 900, // only from proxy to server -+ N_P1X_SETIP = 900, // only from proxy to server (see addtrustedproxyip cmd) - N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD +@@ -248,6 +248,9 @@ enum + N_P1X_SETIP = 900, // only from proxy to server (see addtrustedproxyip cmd) + // N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // legacy + N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1002, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD +#ifdef ANTICHEAT + N_P1X_ANTICHEAT_SUPPORTED = 2000, N_P1X_ANTICHEAT_BEGINSESSION, N_P1X_ANTICHEAT_MESSAGE, N_P1X_ANTICHEAT_VIOLATION, N_P1X_ANTICHEAT_ENDSESSION, // guarded by CAP_PROBE_ANTICHEAT +#endif @@ -906,9 +883,9 @@ index 0a4c901..4e9fe3a 100644 }; @@ -886,6 +893,14 @@ namespace game - extern bool managedgamedemonextmatch; - extern string managedgamedemofname; - extern void sendclientdemo(); + // managed games + extern void handlecapprobe(const char *msg); + extern void sendclientdemo(stream *demo); + +#ifdef ANTICHEAT + // anticheat @@ -1081,6 +1058,20 @@ index 232c554..286bdfa 100644 } } +diff --git src/p1xbraten/clientdemo.cpp src/p1xbraten/clientdemo.cpp +index 4272bd7..8b407e5 100644 +--- src/p1xbraten/clientdemo.cpp ++++ src/p1xbraten/clientdemo.cpp +@@ -55,6 +55,9 @@ namespace game { + case N_AUTHTRY: case N_AUTHCHAL: case N_AUTHANS: case N_REQAUTH: + case N_P1X_SETIP: + case N_P1X_RECORDDEMO: ++#ifdef ANTICHEAT ++ case N_P1X_ANTICHEAT_BEGINSESSION: case N_P1X_ANTICHEAT_MESSAGE: case N_P1X_ANTICHEAT_ENDSESSION: ++#endif + return; + } + int stamp[3] = { totalmillis-demostartmillis, chan, len }; diff --git src/shared/cube.h src/shared/cube.h index be7755c..c153591 100644 --- src/shared/cube.h diff --git a/patches/clientdemo.patch b/patches/clientdemo.patch index e82c4c3..4c07279 100644 --- a/patches/clientdemo.patch +++ b/patches/clientdemo.patch @@ -30,7 +30,7 @@ index f6f7555..59b8c54 100644 + } + } }; - + extern captureclientmode capturemode; diff --git src/fpsgame/client.cpp src/fpsgame/client.cpp index 522d32a..b0cc1c8 100644 @@ -45,7 +45,7 @@ index 522d32a..b0cc1c8 100644 void printname() { @@ -568,6 +569,7 @@ namespace game - + void changemapserv(const char *name, int mode) // forced map change from the server { + if(demorecord) enddemorecord(); @@ -63,14 +63,14 @@ index 522d32a..b0cc1c8 100644 @@ -980,7 +983,7 @@ namespace game VARP(teamcolorchat, 0, 1, 1); const char *chatcolorname(fpsent *d) { return teamcolorchat ? teamcolorname(d, NULL) : colorname(d); } - + - void toserver(char *text) { conoutf(CON_CHAT, "%s:\f0 %s", chatcolorname(player1), text); addmsg(N_TEXT, "rcs", player1, text); } + void toserver(char *text) { conoutf(CON_CHAT, "%s:\f0 %s", chatcolorname(player1), text); addmsg(N_TEXT, "rcs", player1, text); if(demorecord) recordmsg(N_TEXT, "rcs", player1, text); } COMMANDN(say, toserver, "C"); - + void sayteam(char *text) { conoutf(CON_TEAMCHAT, "\fs\f8[team]\fr %s: \f8%s", chatcolorname(player1), text); addmsg(N_SAYTEAM, "rcs", player1, text); } @@ -994,6 +997,7 @@ namespace game - + static void sendposition(fpsent *d, packetbuf &q) { + int offset = q.length(); @@ -83,7 +83,7 @@ index 522d32a..b0cc1c8 100644 } + if(demorecord && (d==player1 || d->ai)) recordpacket(0, q.buf+offset, q.length()); } - + void sendposition(fpsent *d, bool reliable) @@ -1115,9 +1120,21 @@ namespace game void c2sinfo(bool force) // send update to the server @@ -110,13 +110,13 @@ index 522d32a..b0cc1c8 100644 } @@ -1826,7 +1843,9 @@ namespace game } - + case N_PONG: + if(demopacket) { getint(p); break; } addmsg(N_CLIENTPING, "i", player1->ping = (player1->ping*5+totalmillis-getint(p))/6); + if(demorecord) recordmsg(N_CLIENTPING, "i", player1->ping); break; - + case N_CLIENTPING: @@ -2101,6 +2120,7 @@ namespace game void parsepacketclient(int chan, packetbuf &p) // processes any updates from the server @@ -132,7 +132,7 @@ index a3d4ea8..1e6b8b0 100644 +++ src/fpsgame/ctf.h @@ -447,6 +447,9 @@ struct ctfclientmode : clientmode } - + void initclient(clientinfo *ci, packetbuf &p, bool connecting) +#else + void initdemoclient(packetbuf &p) @@ -159,7 +159,7 @@ index a3d4ea8..1e6b8b0 100644 @@ -480,6 +489,7 @@ struct ctfclientmode : clientmode } } - + +#ifdef SERVMODE void parseflags(ucharbuf &p, bool commit) { @@ -191,11 +191,11 @@ index 7dc7de0..f5328cb 100644 @@ -688,6 +688,7 @@ namespace game disablezoom(); lasthit = 0; - + + if(remote && demonextmatch) setupdemorecord(); execident("mapstart"); } - + @@ -743,12 +744,16 @@ namespace game if(!d || d==player1) { @@ -223,11 +223,11 @@ index b59407a..64a92ad 100644 virtual bool aipursue(fpsent *d, ai::aistate &b) { return false; } + virtual void initdemoclient(packetbuf &p) {} }; - + extern clientmode *cmode; @@ -752,8 +753,10 @@ namespace game const char *mastermodeicon(int n, const char *unknown); - + // client - extern bool connected, remote, demoplayback; + extern bool connected, remote, demoplayback, gamepaused; @@ -235,7 +235,7 @@ index b59407a..64a92ad 100644 + extern int mastermode, gamespeed; + extern hashset teaminfos; extern vector messages; - + extern int parseplayer(const char *arg); @@ -860,6 +863,14 @@ namespace game extern int chooserandomplayermodel(int seed); @@ -246,11 +246,11 @@ index b59407a..64a92ad 100644 + extern bool demonextmatch; + extern stream *demorecord; + extern void setupdemorecord(); -+ extern void recordpacket(int chan, void *data, int len); ++ extern void recordpacket(int chan, uchar *data, int len); + extern bool recordmsg(int type, const char *fmt = NULL, ...); + extern void enddemorecord(); } - + #include "fragmessages.h" diff --git src/fpsgame/scoreboard.cpp src/fpsgame/scoreboard.cpp index 1833375..6433a9b 100644 @@ -259,10 +259,10 @@ index 1833375..6433a9b 100644 @@ -22,7 +22,7 @@ namespace game MOD(VARP, showdamage, 0, 0, 2); MOD(VARP, showdamagereceived, 0, 0, 1); - + - static hashset teaminfos; + hashset teaminfos; - + void clearteaminfo() { diff --git src/fpsgame/weapon.cpp src/fpsgame/weapon.cpp @@ -286,14 +286,14 @@ index f495ed6..4810e0d 100644 + int(from.x*DMF), int(from.y*DMF), int(from.z*DMF), + int(to.x*DMF), int(to.y*DMF), int(to.z*DMF)); } - + d->gunwait = guns[d->gunselect].attackdelay; diff --git src/p1xbraten/clientdemo.cpp src/p1xbraten/clientdemo.cpp new file mode 100644 index 0000000..839b0a9 --- /dev/null +++ src/p1xbraten/clientdemo.cpp -@@ -0,0 +1,300 @@ +@@ -0,0 +1,317 @@ +#include "game.h" + +// client-side demo recording works mostly the same as server-side: @@ -321,15 +321,36 @@ index 0000000..839b0a9 + { + if(!demorecord) return; + DELETEP(demorecord); ++ conoutf("stopped client demo recording"); + if(!demo) return; + DELETEP(demo); -+ conoutf("stopped client demo recording"); + } + -+ void recordpacket(int chan, void *data, int len) ++ ++ void recordpacket(int chan, uchar *data, int len) + { -+ if(!demorecord) return; -+ int stamp[3] = { totalmillis-demostartmillis, chan, len }; ++ if(!demorecord || !len) return; ++ // peek message type ++ int type = (schar)data[0]; ++ if(type==-128 && len > 3) ++ { ++ type = data[1]; ++ type |= ((schar)data[2])<<8; ++ } ++ else if(type==-127 && len > 5) ++ { ++ type = data[1]; ++ type |= ((schar)data[2])<<8; ++ type |= ((schar)data[3])<<16; ++ type |= ((schar)data[4])<<24; ++ } ++ // skip certain packets ++ switch (type) { ++ case N_SENDDEMOLIST: ++ case N_AUTHTRY: case N_AUTHCHAL: case N_AUTHANS: case N_REQAUTH: ++ return; ++ } ++ int stamp[3] = { lastmillis-demostartmillis, chan, len }; + lilswap(stamp, 3); + demorecord->write(stamp, sizeof(stamp)); + demorecord->write(data, len); @@ -390,7 +411,7 @@ index 0000000..839b0a9 + putint(p, gamemode); + putint(p, 0); // notgotitems = false + putint(p, N_TIMEUP); -+ putint(p, lastmillis < maplimit && !intermission ? max((maplimit - totalmillis)/1000, 1) : 0); ++ putint(p, intermission ? 0 : max((maplimit - lastmillis)/1000, 1)); + putint(p, N_ITEMLIST); + loopv(entities::ents) if(entities::ents[i]->spawned()) + { @@ -458,7 +479,7 @@ index 0000000..839b0a9 + + void setupdemorecord() + { -+ if(!m_mp(gamemode) || m_edit || m_collect || demo || demorecord) return; ++ if(!m_mp(gamemode) || m_collect || demoplayback || demorecord) return; // todo: collect init packet + + string tname; + tname[0] = '\0'; @@ -490,7 +511,7 @@ index 0000000..839b0a9 + lilswap(&hdr.version, 2); + demorecord->write(&hdr, sizeof(demoheader)); + -+ demostartmillis = totalmillis; ++ demostartmillis = lastmillis; + + packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); + welcomepacket(p); @@ -501,17 +522,13 @@ index 0000000..839b0a9 + { + switch (val) + { -+ case 0: case 1: // (un)schedule for next match -+ { -+ demonextmatch = val==1; -+ conoutf("client demo recording is %s for next match", demonextmatch ? "enabled" : "disabled"); ++ case 0: // stop recording ++ enddemorecord(); + break; -+ } ++ // case 1: // unused, legacy + case 2: // start immediately -+ { + setupdemorecord(); + break; -+ } + } + } + ICOMMAND(recordclientdemo, "i", (int *val), recordclientdemo(*val)); diff --git a/patches/managed_games.patch b/patches/managed_games.patch index 4fd54fd..cf6a8a0 100644 --- a/patches/managed_games.patch +++ b/patches/managed_games.patch @@ -2,7 +2,7 @@ diff --git src/fpsgame/client.cpp src/fpsgame/client.cpp index b0cc1c8..1e3163e 100644 --- src/fpsgame/client.cpp +++ src/fpsgame/client.cpp -@@ -2043,8 +2043,19 @@ namespace game +@@ -2060,8 +2060,18 @@ namespace game case N_SERVCMD: getstring(text, p); @@ -10,31 +10,17 @@ index b0cc1c8..1e3163e 100644 break; + case N_P1X_RECORDDEMO: -+ { -+ int val = getint(p); -+ if(val) conoutf("server requested client demo recording for the next match"); -+ else if(managedgamedemonextmatch) conoutf("server canceled client demo recording for the next match"); -+ else if(managedgamedemofname[0]) enddemorecord(); -+ managedgamedemonextmatch = val!=0; ++ if(!getint(p)) enddemorecord(true); ++ else if(!demorecord) ++ { ++ conoutf("server triggered client demo recording"); ++ setupdemorecord(); ++ } + break; -+ } + default: neterr("type", cn < 0); return; -diff --git src/fpsgame/fps.cpp src/fpsgame/fps.cpp -index 24d623f..1f6919b 100644 ---- src/fpsgame/fps.cpp -+++ src/fpsgame/fps.cpp -@@ -688,7 +688,7 @@ namespace game - disablezoom(); - lasthit = 0; - -- if(remote && demonextmatch) setupdemorecord(); -+ if(remote && (demonextmatch || managedgamedemonextmatch)) setupdemorecord(); - execident("mapstart"); - } - diff --git src/fpsgame/game.h src/fpsgame/game.h index 02277f9..b37ef32 100644 --- src/fpsgame/game.h @@ -44,16 +30,17 @@ index 02277f9..b37ef32 100644 }; +// protocol extensions -+static const char * const CAP_PROBE_CLIENT_DEMO_UPLOAD = "capability_probe_protocol_extension_p1x_client_demo_upload"; ++static const char * const CAP_PROBE_CLIENT_DEMO_UPLOAD = "capability_probe_protocol_extension_p1x_client_demo_upload_v2"; + // network messages codes, c2s, c2c, s2c enum -@@ -242,6 +245,7 @@ enum +@@ -242,6 +245,8 @@ enum N_INITTOKENS, N_TAKETOKEN, N_EXPIRETOKENS, N_DROPTOKENS, N_DEPOSITTOKENS, N_STEALTOKENS, N_SERVCMD, N_DEMOPACKET, -+ N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD ++ // N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // legacy ++ N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1002, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD NUMMSG }; @@ -65,16 +52,15 @@ index 02277f9..b37ef32 100644 -1 }; -@@ -871,6 +876,12 @@ namespace game +@@ -871,6 +876,10 @@ namespace game extern void recordpacket(int chan, void *data, int len); extern bool recordmsg(int type, const char *fmt = NULL, ...); - extern void enddemorecord(); +- extern void enddemorecord(); ++ extern void enddemorecord(bool send = false); + + // managed games + extern void handlecapprobe(const char *msg); -+ extern bool managedgamedemonextmatch; -+ extern string managedgamedemofname; -+ extern void sendclientdemo(); ++ extern void sendclientdemo(stream *demo); } #include "fragmessages.h" @@ -373,58 +359,47 @@ diff --git src/p1xbraten/clientdemo.cpp src/p1xbraten/clientdemo.cpp index 839b0a9..48e29ec 100644 --- src/p1xbraten/clientdemo.cpp +++ src/p1xbraten/clientdemo.cpp -@@ -28,6 +28,7 @@ namespace game { +@@ -22,11 +22,12 @@ namespace game { + int demostartmillis = 0; + +- void enddemorecord() ++ void enddemorecord(bool send) + { + if(!demorecord) return; + DELETEP(demorecord); + conoutf("stopped client demo recording"); if(!demo) return; ++ if(send) sendclientdemo(demo); DELETEP(demo); - conoutf("stopped client demo recording"); -+ if(intermission && managedgamedemofname[0]) sendclientdemo(); } - void recordpacket(int chan, void *data, int len) -@@ -174,6 +175,7 @@ namespace game { - filtertext(fname, fname, false); - len = strlen(fname); - if(len < 4 || strcasecmp(&fname[len-4], ".dmo")) concatstring(fname, ".dmo"); -+ if(managedgamedemonextmatch) copystring(managedgamedemofname, fname); - - if(const char *buf = server::getdemofile(fname, true)) demo = openrawfile(buf, "w+b"); - if(!demo) demo = openrawfile(fname, "w+b"); -@@ -185,6 +187,7 @@ namespace game { - conoutf("recording client demo"); - - demonextmatch = false; -+ managedgamedemonextmatch = false; - demorecord = f; - - demoheader hdr; +@@ -52,6 +52,7 @@ namespace game { + switch (type) { + case N_SENDDEMOLIST: + case N_AUTHTRY: case N_AUTHCHAL: case N_AUTHANS: case N_REQAUTH: ++ case N_P1X_RECORDDEMO: + return; + } + int stamp[3] = { totalmillis-demostartmillis, chan, len }; diff --git src/p1xbraten/managed_games.cpp src/p1xbraten/managed_games.cpp new file mode 100644 index 0000000..1c1b1d7 --- /dev/null +++ src/p1xbraten/managed_games.cpp -@@ -0,0 +1,267 @@ +@@ -0,0 +1,262 @@ +#include "game.h" + +#ifndef STANDALONE +namespace game { + -+ bool managedgamedemonextmatch = false; -+ string managedgamedemofname; -+ -+ void sendclientdemo() ++ void sendclientdemo(stream *demo) + { -+ if(!managedgamedemofname[0]) { conoutf(CON_ERROR, "client demo requested, but demo file name unknown!"); return; }; -+ conoutf("sending demo %s to server...", managedgamedemofname); -+ stream *demo = NULL; -+ if(const char *buf = server::getdemofile(managedgamedemofname, true)) demo = openrawfile(buf, "rb"); -+ if(!demo) demo = openrawfile(managedgamedemofname, "rb"); -+ managedgamedemofname[0] = '\0'; -+ if(!demo) { conoutf("failed to open demo file"); return; } ++ conoutf("sending demo to server..."); ++ if(!demo) return; + stream::offset len = demo->size(); + if(len > 16*1024*1024) conoutf(CON_ERROR, "demo is too large"); // todo: is 16 MB enough? + else if(len <= 0) conoutf(CON_ERROR, "could not read demo"); + else sendfile(-1, 3, demo); -+ DELETEP(demo); + conoutf("client demo sent"); + } +} @@ -468,7 +443,6 @@ index 0000000..1c1b1d7 + { + clientinfo *ci = clients[i]; + if(ci->state.state==CS_SPECTATOR) continue; -+ if(ci->supportsclientdemoupload) sendf(ci->clientnum, 1, "rii", N_P1X_RECORDDEMO, 1); + } + + managedgamenextmatch = true; @@ -604,7 +578,12 @@ index 0000000..1c1b1d7 + void onspawn(clientinfo *ci) + { + if(!notyetspawned.length()) return; -+ loopv(notyetspawned) if(notyetspawned[i]==ci) notyetspawned.remove(i); ++ loopv(notyetspawned) if(notyetspawned[i]==ci) ++ { ++ notyetspawned.remove(i); ++ if(ci->supportsclientdemoupload) sendf(ci->clientnum, 1, "rii", N_P1X_RECORDDEMO, 2); ++ break; ++ } + if(!notyetspawned.length()) + { + sendf(-1, 1, "ris", N_SERVMSG, "all players ready, game starts in 3"); diff --git a/patches/proxy_setip.patch b/patches/proxy_setip.patch index f5fa39f..a2e5da7 100644 --- a/patches/proxy_setip.patch +++ b/patches/proxy_setip.patch @@ -8,7 +8,7 @@ index 3017f57..4aa8d18 100644 void *info; + ENetAddress real; // set by proxy via setip remote command }; - + vector clients; @@ -187,7 +188,18 @@ int getservermtu() { return serverhost ? serverhost->mtu : -1; } void *getclientinfo(int i) { return !clients.inrange(i) || clients[i]->type==ST_EMPTY ? NULL : clients[i]->info; } @@ -27,7 +27,7 @@ index 3017f57..4aa8d18 100644 + return enet_address_get_host_ip(&clients[n]->real, clients[n]->hostname, strlen("xxx.xxx.xxx.xxx")); +} +const char *getclienthostname(int n) { return clients.inrange(n) && clients[n]->type==ST_TCPIP ? clients[n]->hostname : NULL; } - + void sendpacket(int n, int chan, ENetPacket *packet, int exclude) { diff --git src/fpsgame/game.h src/fpsgame/game.h @@ -38,9 +38,9 @@ index 392b59c..a0af230 100644 N_INITTOKENS, N_TAKETOKEN, N_EXPIRETOKENS, N_DROPTOKENS, N_DEPOSITTOKENS, N_STEALTOKENS, N_SERVCMD, N_DEMOPACKET, -+ N_P1X_SETIP = 900, // only from proxy to server - N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD - NUMMSG ++ N_P1X_SETIP = 900, // only from proxy to server (see addtrustedproxyip cmd) + // N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // legacy + N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1002, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD }; @@ -276,6 +277,7 @@ static const int msgsizes[] = // size inclusive message token, 0 f N_INITTOKENS, 0, N_TAKETOKEN, 2, N_EXPIRETOKENS, 0, N_DROPTOKENS, 0, N_DEPOSITTOKENS, 2, N_STEALTOKENS, 0, @@ -58,25 +58,25 @@ index 392b59c..a0af230 100644 + // proxy support + extern void setip(clientinfo *sender, uint ip); } - + // additional colors diff --git src/fpsgame/server.cpp src/fpsgame/server.cpp index 4272bd7..8b407e5 100644 --- src/fpsgame/server.cpp +++ src/fpsgame/server.cpp @@ -1301,7 +1301,7 @@ namespace server - + uchar operator[](int msg) const { return msg >= 0 && msg < NUMMSG ? msgmask[msg] : 0; } } msgfilter(-1, N_CONNECT, N_SERVINFO, N_INITCLIENT, N_WELCOME, N_MAPCHANGE, N_SERVMSG, N_DAMAGE, N_HITPUSH, N_SHOTFX, N_EXPLODEFX, N_DIED, N_SPAWNSTATE, N_FORCEDEATH, N_TEAMINFO, N_ITEMACC, N_ITEMSPAWN, N_TIMEUP, N_CDIS, N_CURRENTMASTER, N_PONG, N_RESUME, N_BASESCORE, N_BASEINFO, N_BASEREGEN, N_ANNOUNCE, N_SENDDEMOLIST, N_SENDDEMO, N_DEMOPLAYBACK, N_SENDMAP, N_DROPFLAG, N_SCOREFLAG, N_RETURNFLAG, N_RESETFLAG, N_INVISFLAG, N_CLIENT, N_AUTHCHAL, N_INITAI, N_EXPIRETOKENS, N_DROPTOKENS, N_STEALTOKENS, N_DEMOPACKET, N_P1X_RECORDDEMO, -2, N_REMIP, N_NEWMAP, N_GETMAP, N_SENDMAP, N_CLIPBOARD, -3, N_EDITENT, N_EDITF, N_EDITT, N_EDITM, N_FLIP, N_COPY, N_PASTE, N_ROTATE, N_REPLACE, N_DELCUBE, N_EDITVAR, N_EDITVSLOT, N_UNDO, N_REDO, -4, N_POS, NUMMSG), - connectfilter(-1, N_CONNECT, -2, N_AUTHANS, -3, N_PING, NUMMSG); + connectfilter(-1, N_CONNECT, -2, N_AUTHANS, -3, N_PING, N_P1X_SETIP, NUMMSG); - + int checktype(int type, clientinfo *ci) { @@ -2785,6 +2785,10 @@ namespace server getint(p); break; - + + case N_P1X_SETIP: + setip(ci, getint(p)); + break; @@ -84,6 +84,18 @@ index 4272bd7..8b407e5 100644 default: disconnect_client(sender, DISC_MSGERR); return; +diff --git src/p1xbraten/clientdemo.cpp src/p1xbraten/clientdemo.cpp +index 4272bd7..8b407e5 100644 +--- src/p1xbraten/clientdemo.cpp ++++ src/p1xbraten/clientdemo.cpp +@@ -53,6 +53,7 @@ namespace game { + switch (type) { + case N_SENDDEMOLIST: + case N_AUTHTRY: case N_AUTHCHAL: case N_AUTHANS: case N_REQAUTH: ++ case N_P1X_SETIP: + case N_P1X_RECORDDEMO: + return; + } diff --git src/p1xbraten/proxy_real_ip.cpp src/p1xbraten/proxy_real_ip.cpp new file mode 100644 index 0000000..bd130e3 diff --git a/src/Makefile b/src/Makefile index 71f7b6d..a36a986 100644 --- a/src/Makefile +++ b/src/Makefile @@ -23,9 +23,11 @@ else endif CFLAGS= --target=$(TARGET) -CXXFLAGS= --target=$(TARGET) -O3 -fomit-frame-pointer -ffast-math +CXXFLAGS= --target=$(TARGET) -fomit-frame-pointer -ffast-math ifdef DEBUG override CXXFLAGS+= -DDEBUG=$$DEBUG +else + override CXXFLAGS+= -O3 endif LINKERFLAGS= diff --git a/src/fpsgame/client.cpp b/src/fpsgame/client.cpp index 9e1a88a..8700785 100644 --- a/src/fpsgame/client.cpp +++ b/src/fpsgame/client.cpp @@ -2071,14 +2071,13 @@ namespace game break; case N_P1X_RECORDDEMO: - { - int val = getint(p); - if(val) conoutf("server requested client demo recording for the next match"); - else if(managedgamedemonextmatch) conoutf("server canceled client demo recording for the next match"); - else if(managedgamedemofname[0]) enddemorecord(); - managedgamedemonextmatch = val!=0; + if(!getint(p)) enddemorecord(true); + else if(!demorecord) + { + conoutf("server triggered client demo recording"); + setupdemorecord(); + } break; - } #ifdef ANTICHEAT case N_P1X_ANTICHEAT_BEGINSESSION: triggeranticheatsession(); diff --git a/src/fpsgame/fps.cpp b/src/fpsgame/fps.cpp index b47873d..141739f 100644 --- a/src/fpsgame/fps.cpp +++ b/src/fpsgame/fps.cpp @@ -725,7 +725,7 @@ namespace game disablezoom(); lasthit = 0; - if(remote && (demonextmatch || managedgamedemonextmatch)) setupdemorecord(); + if(remote && demonextmatch) setupdemorecord(); execident("mapstart"); } diff --git a/src/fpsgame/game.h b/src/fpsgame/game.h index 7a53450..f479b73 100644 --- a/src/fpsgame/game.h +++ b/src/fpsgame/game.h @@ -214,7 +214,7 @@ enum }; // protocol extensions -static const char * const CAP_PROBE_CLIENT_DEMO_UPLOAD = "capability_probe_protocol_extension_p1x_client_demo_upload"; +static const char * const CAP_PROBE_CLIENT_DEMO_UPLOAD = "capability_probe_protocol_extension_p1x_client_demo_upload_v2"; static const char * const CAP_PROBE_ANTICHEAT = "capability_probe_protocol_extension_p1x_anticheat"; // network messages codes, c2s, c2c, s2c @@ -247,7 +247,8 @@ enum N_SERVCMD, N_DEMOPACKET, N_P1X_SETIP = 900, // only from proxy to server (see addtrustedproxyip cmd) - N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD + // N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1000, N_P1X_RECORDDEMO, // legacy + N_P1X_CLIENT_DEMO_UPLOAD_SUPPORTED = 1002, N_P1X_RECORDDEMO, // guarded by CAP_PROBE_CLIENT_DEMO_UPLOAD #ifdef ANTICHEAT N_P1X_ANTICHEAT_SUPPORTED = 2000, N_P1X_ANTICHEAT_BEGINSESSION, N_P1X_ANTICHEAT_MESSAGE, N_P1X_ANTICHEAT_VIOLATION, N_P1X_ANTICHEAT_ENDSESSION, // guarded by CAP_PROBE_ANTICHEAT #endif @@ -884,15 +885,13 @@ namespace game extern bool demonextmatch; extern stream *demorecord; extern void setupdemorecord(); - extern void recordpacket(int chan, void *data, int len); + extern void recordpacket(int chan, uchar *data, int len); extern bool recordmsg(int type, const char *fmt = NULL, ...); - extern void enddemorecord(); + extern void enddemorecord(bool send = false); // managed games extern void handlecapprobe(const char *msg); - extern bool managedgamedemonextmatch; - extern string managedgamedemofname; - extern void sendclientdemo(); + extern void sendclientdemo(stream *demo); #ifdef ANTICHEAT // anticheat diff --git a/src/p1xbraten/clientdemo.cpp b/src/p1xbraten/clientdemo.cpp index e5c44f7..20eee68 100644 --- a/src/p1xbraten/clientdemo.cpp +++ b/src/p1xbraten/clientdemo.cpp @@ -21,20 +21,46 @@ namespace game { stream *demo = NULL, *demorecord = NULL; int demostartmillis = 0; - void enddemorecord() + void enddemorecord(bool send) { if(!demorecord) return; DELETEP(demorecord); + conoutf("stopped client demo recording"); if(!demo) return; + if(send) sendclientdemo(demo); DELETEP(demo); - conoutf("stopped client demo recording"); - if(intermission && managedgamedemofname[0]) sendclientdemo(); } - void recordpacket(int chan, void *data, int len) + + void recordpacket(int chan, uchar *data, int len) { - if(!demorecord) return; - int stamp[3] = { totalmillis-demostartmillis, chan, len }; + if(!demorecord || !len) return; + // peek message type + int type = (schar)data[0]; + if(type==-128 && len > 3) + { + type = data[1]; + type |= ((schar)data[2])<<8; + } + else if(type==-127 && len > 5) + { + type = data[1]; + type |= ((schar)data[2])<<8; + type |= ((schar)data[3])<<16; + type |= ((schar)data[4])<<24; + } + // skip certain packets + switch (type) { + case N_SENDDEMOLIST: + case N_AUTHTRY: case N_AUTHCHAL: case N_AUTHANS: case N_REQAUTH: + case N_P1X_SETIP: + case N_P1X_RECORDDEMO: +#ifdef ANTICHEAT + case N_P1X_ANTICHEAT_BEGINSESSION: case N_P1X_ANTICHEAT_MESSAGE: case N_P1X_ANTICHEAT_ENDSESSION: +#endif + return; + } + int stamp[3] = { lastmillis-demostartmillis, chan, len }; lilswap(stamp, 3); demorecord->write(stamp, sizeof(stamp)); demorecord->write(data, len); @@ -95,7 +121,7 @@ namespace game { putint(p, gamemode); putint(p, 0); // notgotitems = false putint(p, N_TIMEUP); - putint(p, lastmillis < maplimit && !intermission ? max((maplimit - totalmillis)/1000, 1) : 0); + putint(p, intermission ? 0 : max((maplimit - lastmillis)/1000, 1)); putint(p, N_ITEMLIST); loopv(entities::ents) if(entities::ents[i]->spawned()) { @@ -165,7 +191,7 @@ namespace game { void setupdemorecord() { - if(!m_mp(gamemode) || m_edit || m_collect || demo || demorecord) return; + if(!m_mp(gamemode) || m_collect || demoplayback || demorecord) return; // todo: collect init packet string tname; tname[0] = '\0'; @@ -177,7 +203,6 @@ namespace game { filtertext(fname, fname, false); len = strlen(fname); if(len < 4 || strcasecmp(&fname[len-4], ".dmo")) concatstring(fname, ".dmo"); - if(managedgamedemonextmatch) copystring(managedgamedemofname, fname); if(const char *buf = server::getdemofile(fname, true)) demo = openrawfile(buf, "w+b"); if(!demo) demo = openrawfile(fname, "w+b"); @@ -189,7 +214,6 @@ namespace game { conoutf("recording client demo"); demonextmatch = false; - managedgamedemonextmatch = false; demorecord = f; demoheader hdr; @@ -199,7 +223,7 @@ namespace game { lilswap(&hdr.version, 2); demorecord->write(&hdr, sizeof(demoheader)); - demostartmillis = totalmillis; + demostartmillis = lastmillis; packetbuf p(MAXTRANS, ENET_PACKET_FLAG_RELIABLE); welcomepacket(p); @@ -211,17 +235,13 @@ namespace game { { switch (val) { - case 0: case 1: // (un)schedule for next match - { - demonextmatch = val==1; - conoutf("client demo recording is %s for next match", demonextmatch ? "enabled" : "disabled"); + case 0: // stop recording + enddemorecord(); break; - } + // case 1: // unused, legacy case 2: // start immediately - { setupdemorecord(); break; - } } } ICOMMAND(recordclientdemo, "i", (int *val), recordclientdemo(*val)); diff --git a/src/p1xbraten/managed_games.cpp b/src/p1xbraten/managed_games.cpp index b9be233..c014fd3 100644 --- a/src/p1xbraten/managed_games.cpp +++ b/src/p1xbraten/managed_games.cpp @@ -3,23 +3,14 @@ #ifndef STANDALONE namespace game { - bool managedgamedemonextmatch = false; - string managedgamedemofname; - - void sendclientdemo() + void sendclientdemo(stream *demo) { - if(!managedgamedemofname[0]) { conoutf(CON_ERROR, "client demo requested, but demo file name unknown!"); return; }; - conoutf("sending demo %s to server...", managedgamedemofname); - stream *demo = NULL; - if(const char *buf = server::getdemofile(managedgamedemofname, true)) demo = openrawfile(buf, "rb"); - if(!demo) demo = openrawfile(managedgamedemofname, "rb"); - managedgamedemofname[0] = '\0'; - if(!demo) { conoutf("failed to open demo file"); return; } + conoutf("sending demo to server..."); + if(!demo) return; stream::offset len = demo->size(); if(len > 16*1024*1024) conoutf(CON_ERROR, "demo is too large"); // todo: is 16 MB enough? else if(len <= 0) conoutf(CON_ERROR, "could not read demo"); else sendfile(-1, 3, demo); - DELETEP(demo); conoutf("client demo sent"); } } @@ -63,7 +54,6 @@ namespace server { { clientinfo *ci = clients[i]; if(ci->state.state==CS_SPECTATOR) continue; - if(ci->supportsclientdemoupload) sendf(ci->clientnum, 1, "rii", N_P1X_RECORDDEMO, 1); } managedgamenextmatch = true; @@ -199,7 +189,12 @@ namespace server { void onspawn(clientinfo *ci) { if(!notyetspawned.length()) return; - loopv(notyetspawned) if(notyetspawned[i]==ci) notyetspawned.remove(i); + loopv(notyetspawned) if(notyetspawned[i]==ci) + { + notyetspawned.remove(i); + if(ci->supportsclientdemoupload) sendf(ci->clientnum, 1, "rii", N_P1X_RECORDDEMO, 2); + break; + } if(!notyetspawned.length()) { sendf(-1, 1, "ris", N_SERVMSG, "all players ready, game starts in 3");