From 2eac09b1656b518dc804bb0882c4faddedec15e8 Mon Sep 17 00:00:00 2001 From: TimePath Date: Mon, 21 Dec 2015 16:50:19 +1100 Subject: [PATCH] Client commands: register Weapons: weapon_find command to show waypoints --- qcsrc/client/commands/cl_cmd.qc | 60 +++++++++++++------------------ qcsrc/client/commands/cl_cmd.qh | 22 +++++++++--- qcsrc/client/main.qc | 4 +-- qcsrc/common/animdecide.qh | 4 +-- qcsrc/common/weapons/all.qc | 54 ++++++++++++++++++++++++++++ qcsrc/lib/net.qh | 12 +++---- qcsrc/server/command/cmd.qc | 2 +- qcsrc/server/weapons/selection.qc | 44 ++++++++++++----------- 8 files changed, 130 insertions(+), 72 deletions(-) diff --git a/qcsrc/client/commands/cl_cmd.qc b/qcsrc/client/commands/cl_cmd.qc index 63e0c5612..be3ac5645 100644 --- a/qcsrc/client/commands/cl_cmd.qc +++ b/qcsrc/client/commands/cl_cmd.qc @@ -493,57 +493,45 @@ void LocalCommand_(int request) // ================================== // Normally do not hard code aliases for these, instead create them in commands.cfg... also: keep in alphabetical order, please ;) -#define CLIENT_COMMANDS(request, arguments) \ - CLIENT_COMMAND("blurtest", LocalCommand_blurtest(request), "Feature for testing blur postprocessing") \ - CLIENT_COMMAND("boxparticles", LocalCommand_boxparticles(request, arguments), "Spawn particles manually") \ - CLIENT_COMMAND("create_scrshot_ent", LocalCommand_create_scrshot_ent(request), "Create an entity at this location for automatic screenshots") \ - CLIENT_COMMAND("debugmodel", LocalCommand_debugmodel(request, arguments), "Spawn a debug model manually") \ - CLIENT_COMMAND("handlevote", LocalCommand_handlevote(request, arguments), "System to handle selecting a vote or option") \ - CLIENT_COMMAND("hud", LocalCommand_hud(request, arguments), "Commands regarding/controlling the HUD system") \ - CLIENT_COMMAND("localprint", LocalCommand_localprint(request, arguments), "Create your own centerprint sent to yourself") \ - CLIENT_COMMAND("find", LocalCommand_find(request, arguments), "Search through entities for matching classname") \ - CLIENT_COMMAND("mv_download", LocalCommand_mv_download(request, arguments), "Retrieve mapshot picture from the server") \ - CLIENT_COMMAND("sendcvar", LocalCommand_sendcvar(request, arguments), "Send a cvar to the server (like weaponpriority)") \ - /* nothing */ +CLIENT_COMMAND(blurtest, "Feature for testing blur postprocessing") { LocalCommand_blurtest(request); } +CLIENT_COMMAND(boxparticles, "Spawn particles manually") { LocalCommand_boxparticles(request, arguments); } +CLIENT_COMMAND(create_scrshot_ent, "Create an entity at this location for automatic screenshots") { LocalCommand_create_scrshot_ent(request); } +CLIENT_COMMAND(debugmodel, "Spawn a debug model manually") { LocalCommand_debugmodel(request, arguments); } +CLIENT_COMMAND(handlevote, "System to handle selecting a vote or option") { LocalCommand_handlevote(request, arguments); } +CLIENT_COMMAND(hud, "Commands regarding/controlling the HUD system") { LocalCommand_hud(request, arguments); } +CLIENT_COMMAND(localprint, "Create your own centerprint sent to yourself") { LocalCommand_localprint(request, arguments); } +CLIENT_COMMAND(find, "Search through entities for matching classname") { LocalCommand_find(request, arguments); } +CLIENT_COMMAND(mv_download, "Retrieve mapshot picture from the server") { LocalCommand_mv_download(request, arguments); } +CLIENT_COMMAND(sendcvar, "Send a cvar to the server (like weaponpriority)") { LocalCommand_sendcvar(request, arguments); } void LocalCommand_macro_help() { - #define CLIENT_COMMAND(name, function, description) \ - { if (strtolower(description) != "") { LOG_INFO(" ^2", name, "^7: ", description, "\n"); } } - - CLIENT_COMMANDS(0, 0); - #undef CLIENT_COMMAND + FOREACH(CLIENT_COMMANDS, true, LAMBDA(LOG_INFOF(" ^2%s^7: %s\n", it.m_name, it.m_description))); } -bool LocalCommand_macro_command(int argc) +bool LocalCommand_macro_command(int argc, string command) { - #define CLIENT_COMMAND(name, function, description) \ - { if (name == strtolower(argv(0))) { function; return true; } } - - CLIENT_COMMANDS(CMD_REQUEST_COMMAND, argc); - #undef CLIENT_COMMAND - + string c = strtolower(argv(0)); + FOREACH(CLIENT_COMMANDS, it.m_name == c, LAMBDA( + it.m_invokecmd(CMD_REQUEST_COMMAND, NULL, argc, command); + return true; + )); return false; } bool LocalCommand_macro_usage(int argc) { - #define CLIENT_COMMAND(name, function, description) \ - { if (name == strtolower(argv(1))) { function; return true; } } - - CLIENT_COMMANDS(CMD_REQUEST_USAGE, argc); - #undef CLIENT_COMMAND - + string c = strtolower(argv(1)); + FOREACH(CLIENT_COMMANDS, it.m_name == c, LAMBDA( + it.m_invokecmd(CMD_REQUEST_USAGE, NULL, argc, ""); + return true; + )); return false; } void LocalCommand_macro_write_aliases(int fh) { - #define CLIENT_COMMAND(name, function, description) \ - { if (strtolower(description) != "") { CMD_Write_Alias("qc_cmd_cl", name, description); } } - - CLIENT_COMMANDS(0, 0); - #undef CLIENT_COMMAND + FOREACH(CLIENT_COMMANDS, true, LAMBDA(CMD_Write_Alias("qc_cmd_cl", it.m_name, it.m_description))); } @@ -587,7 +575,7 @@ void GameCommand(string command) } // continue as usual and scan for normal commands if (GenericCommand(command) // handled by common/command/generic.qc - || LocalCommand_macro_command(argc) // handled by one of the above LocalCommand_* functions + || LocalCommand_macro_command(argc, command) // handled by one of the above LocalCommand_* functions || MUTATOR_CALLHOOK(CSQC_ConsoleCommand, s, argc, command) // handled by a mutator ) return; diff --git a/qcsrc/client/commands/cl_cmd.qh b/qcsrc/client/commands/cl_cmd.qh index ba3151c43..23d72ff60 100644 --- a/qcsrc/client/commands/cl_cmd.qh +++ b/qcsrc/client/commands/cl_cmd.qh @@ -1,13 +1,27 @@ #ifndef CLIENT_COMMANDS_CL_CMD_H #define CLIENT_COMMANDS_CL_CMD_H -// ============================================== -// CSQC client commands code, written by Samual -// Last updated: December 17th, 2011 -// ============================================== void Cmd_HUD_SetFields(int); void Cmd_HUD_Help(); // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file void LocalCommand_macro_write_aliases(int fh); + +REGISTRY(CLIENT_COMMANDS, BITS(7)) +#define CLIENT_COMMANDS_from(i) _CLIENT_COMMANDS_from(i, NULL) +REGISTER_REGISTRY(CLIENT_COMMANDS) +REGISTRY_SORT(CLIENT_COMMANDS) + +#define CLIENT_COMMAND(id, description) \ + CLASS(clientcommand_##id, Command) \ + ATTRIB(clientcommand_##id, m_name, string, #id); \ + ATTRIB(clientcommand_##id, m_description, string, description); \ + ENDCLASS(clientcommand_##id) \ + REGISTER(CLIENT_COMMANDS, CMD_CL, id, m_id, NEW(clientcommand_##id)); \ + METHOD(clientcommand_##id, m_invokecmd, void(int request, entity caller, int arguments, string command)) + +STATIC_INIT(CLIENT_COMMANDS_aliases) { + FOREACH(CLIENT_COMMANDS, true, LAMBDA(localcmd(sprintf("alias %1$s \"%2$s %1$s ${* ?}\"\n", it.m_name, "qc_cmd_cl")))); +} + #endif diff --git a/qcsrc/client/main.qc b/qcsrc/client/main.qc index 6b5cf6463..05a11080b 100644 --- a/qcsrc/client/main.qc +++ b/qcsrc/client/main.qc @@ -759,7 +759,7 @@ void CSQC_Ent_Update(bool isnew) if (isnew) this.classname = it.netname; if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Ent_Update(%d) at %f with this=%i {.entnum=%d, .enttype=%d} t=%s (%d)\n", isnew, savetime, this, this.entnum, this.enttype, this.classname, t); - done = it.m_read(this, isnew); + done = it.m_read(this, NULL, isnew); break; )); time = savetime; @@ -849,7 +849,7 @@ bool CSQC_Parse_TempEntity() FOREACH(TempEntities, it.m_id == nTEID, LAMBDA( if (autocvar_developer_csqcentities) LOG_INFOF("CSQC_Parse_TempEntity() nTEID=%s (%d)\n", it.netname, nTEID); - return it.m_read(NULL, true); + return it.m_read(NULL, NULL, true); )); if (autocvar_developer_csqcentities) diff --git a/qcsrc/common/animdecide.qh b/qcsrc/common/animdecide.qh index 578a30f68..39ca54ff2 100644 --- a/qcsrc/common/animdecide.qh +++ b/qcsrc/common/animdecide.qh @@ -26,8 +26,8 @@ ENDCLASS(Animation) REGISTRY(Animations, BITS(8)) REGISTER_REGISTRY(Animations) #define Animations_from(id) _Animations_from(id, NULL) -#define WriteAnimation(to, it) WriteRegistry(Animations, to, it) -#define ReadAnimation() ReadRegistry(Animations) +#define WriteAnimation(to, it) WriteRegistered(Animations, to, it) +#define ReadAnimation() ReadRegistered(Animations) #define REGISTER_ANIMATION(id, framenames) \ .vector anim_##id; \ REGISTER(Animations, ANIM_##id, m_id, NEW(Animation)) { \ diff --git a/qcsrc/common/weapons/all.qc b/qcsrc/common/weapons/all.qc index 7d107fd61..07ae75851 100644 --- a/qcsrc/common/weapons/all.qc +++ b/qcsrc/common/weapons/all.qc @@ -588,6 +588,60 @@ void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim) } #endif +REGISTER_NET_C2S(w_whereis) +#ifdef SVQC +void Weapon_whereis(Weapon this, entity cl); +NET_HANDLE(w_whereis, bool) +{ + Weapon wpn = ReadRegistered(Weapons); + if (wpn != WEP_Null) Weapon_whereis(wpn, sender); + return true; +} +#else +void w_whereis(Weapon this) +{ + int channel = MSG_C2S; + WriteHeader(channel, w_whereis); + WriteRegistered(Weapons, channel, this); +} +CLIENT_COMMAND(weapon_find, "Show spawn locations of a weapon") +{ + switch (request) + { + case CMD_REQUEST_COMMAND: + { + string s = argv(1); + if (s == "all") + { + FOREACH(Weapons, it != WEP_Null, w_whereis(it)); + return; + } + if (s == "unowned") + { + FOREACH(Weapons, it != WEP_Null && !(STAT(WEAPONS) & it.m_wepset), w_whereis(it)); + return; + } + FOREACH(Weapons, it != WEP_Null && it.netname == s, + { + w_whereis(it); + return; + }); + } + default: + { + LOG_INFOF("Incorrect parameters for ^2%s^7\n", "weapon_find"); + } + case CMD_REQUEST_USAGE: + { + LOG_INFO("\nUsage:^3 cl_cmd weapon_find weapon\n"); + LOG_INFO(" Where 'weapon' is the lowercase weapon name, 'all' or 'unowned'.\n"); + return; + } + } +} +#endif + + #endif #endif diff --git a/qcsrc/lib/net.qh b/qcsrc/lib/net.qh index 0c0f814e8..9782ba313 100644 --- a/qcsrc/lib/net.qh +++ b/qcsrc/lib/net.qh @@ -7,8 +7,8 @@ .string netname; .int m_id; -.bool(entity this, bool isNew) m_read; -#define NET_HANDLE(id, param) bool Net_Handle_##id(entity this, param) +.bool(entity this, entity sender, bool isNew) m_read; +#define NET_HANDLE(id, param) bool Net_Handle_##id(entity this, entity sender, param) #ifdef CSQC @@ -155,7 +155,7 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); } int ReadByte(); - void Net_ClientCommand(string command) + void Net_ClientCommand(entity sender, string command) { // command matches `c2s "(.+)"` string buf = substring(command, argv_start_index(1) + 1, -2); @@ -164,7 +164,7 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); } for (int C2S; (C2S = ReadByte()) >= 0; ) { entity reader = C2S_Protocol_from(C2S); - if (reader && reader.m_read && reader.m_read(NULL, true)) continue; + if (reader && reader.m_read && reader.m_read(NULL, sender, true)) continue; LOG_SEVEREF("Net_ClientCommand() with malformed C2S=%d\n", C2S); return; } @@ -212,8 +212,8 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); } } MACRO_END #endif -#define ReadRegistry(r) r##_from(Read_byte()) -#define WriteRegistry(r, to, it) Write_byte(to, it.m_id) +#define ReadRegistered(r) r##_from(Read_byte()) +#define WriteRegistered(r, to, it) Write_byte(to, it.m_id) #define Read_byte() ReadByte() #define Write_byte(to, f) WriteByte(to, f) diff --git a/qcsrc/server/command/cmd.qc b/qcsrc/server/command/cmd.qc index a454ff947..319c20488 100644 --- a/qcsrc/server/command/cmd.qc +++ b/qcsrc/server/command/cmd.qc @@ -752,7 +752,7 @@ void SV_ParseClientCommand(string command) case "prespawn": break; // handled by engine in host_cmd.c case "sentcvar": break; // handled by server in this file case "spawn": break; // handled by engine in host_cmd.c - case "c2s": Net_ClientCommand(command); return; // handled by net.qh + case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh default: if (SV_ParseClientCommand_floodcheck()) break; // "true": continue, as we're not flooding yet diff --git a/qcsrc/server/weapons/selection.qc b/qcsrc/server/weapons/selection.qc index abd1d9f31..4b96e1f9d 100644 --- a/qcsrc/server/weapons/selection.qc +++ b/qcsrc/server/weapons/selection.qc @@ -17,6 +17,28 @@ void Send_WeaponComplain(entity e, float wpn, float type) WriteByte(MSG_ONE, type); } +void Weapon_whereis(Weapon this, entity cl) +{ + if (!autocvar_g_showweaponspawns) return; + for (entity it = NULL; (it = findfloat(it, weapon, this.m_id)); ) + { + if (it.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2) + continue; + if (!(it.flags & FL_ITEM)) + continue; + entity wp = WaypointSprite_Spawn( + WP_Weapon, + 1, 0, + NULL, it.origin + ('0 0 1' * it.maxs.z) * 1.2, + cl, 0, + NULL, enemy, + 0, + RADARICON_NONE + ); + wp.wp_extra = this.m_id; + } +} + bool client_hasweapon(entity cl, Weapon wpn, float andammo, bool complain) { float f = 0; @@ -77,27 +99,7 @@ bool client_hasweapon(entity cl, Weapon wpn, float andammo, bool complain) if (weaponsInMap & WepSet_FromWeapon(wpn)) { Send_WeaponComplain(cl, wpn.m_id, 1); - - if(autocvar_g_showweaponspawns) - { - for(entity e = world; (e = findfloat(e, weapon, wpn.m_id)); ) - { - if(e.classname == "droppedweapon" && autocvar_g_showweaponspawns < 2) - continue; - if(!(e.flags & FL_ITEM)) - continue; - entity wp = WaypointSprite_Spawn( - WP_Weapon, - 1, 0, - world, e.origin + ('0 0 1' * e.maxs.z) * 1.2, - cl, 0, - world, enemy, - 0, - RADARICON_NONE - ); - wp.wp_extra = wpn.m_id; - } - } + Weapon_whereis(wpn, cl); } else { -- 2.39.2