HLMOD.HU Forrás Megtekintés - www.hlmod.hu
  1. /*================================================================================
  2.  
  3. ----------------------
  4. -*- Ping Faker 1.5 -*-
  5. ----------------------
  6.  
  7. ~~~~~~~~~~~~~~~
  8. - Description -
  9. ~~~~~~~~~~~~~~~
  10.  
  11. This plugin can fake the display of a player's latency (ping) shown on
  12. the scoreboard. Unlike the "fakelag" command, it does not affect the
  13. player's real latency in any way.
  14.  
  15. You can have all players report the same ping, or only fake it for those
  16. having a specific IP/SteamID. This last feature is especially useful
  17. when running a dedicated server from your own computer, when you don't
  18. want people to guess you're an admin/owner by looking at your low ping.
  19.  
  20. ~~~~~~~~~
  21. - CVARS -
  22. ~~~~~~~~~
  23.  
  24. * pingfake_enable [0/1] - Enable/disable ping faking
  25. * pingfake_ping [1337] - The ping you want displayed (min: 0 // max: 4095)
  26. * pingfake_flux [0] - Fake ping fluctuation amount (0 = none)
  27. * pingfake_target [0/1] - Whether to display fake ping to its target too
  28. * pingfake_bots [0/1/2] - Affect bots too (set to 2 for bots ONLY setting)
  29. * pingfake_multiplier [0.0] - Set this to have the fake ping be a multiple
  30. of the player's real ping instead of fixed values (0.0 = disabled)
  31. * pingfake_fileonly [0/1] - Enable this to fake pings ONLY for players
  32. listed on the .INI file
  33.  
  34. Note: changes to these will take effect after a new round.
  35.  
  36. ~~~~~~~~~~~~
  37. - Commands -
  38. ~~~~~~~~~~~~
  39.  
  40. * amx_fakeping <target> <ping>
  41. - Toggle fake ping override for player (use -1 to disable)
  42.  
  43. You can also have players automatically get fake pings according to IP/SteamID
  44. by editing the "fakepings.ini" file in your configs folder.
  45.  
  46. ~~~~~~~~
  47. - ToDo -
  48. ~~~~~~~~
  49.  
  50. * Fix this to send a single SVC_PINGS message, using the real
  51. arguments used by the HL engine, which can be found here:
  52. http://wiki.amxmodx.org/Half-Life_1_Engine_Messages#SVC_PINGS
  53.  
  54. ~~~~~~~~~~~~~~~~~~~
  55. - Developer Notes -
  56. ~~~~~~~~~~~~~~~~~~~
  57.  
  58. The SVC_PINGS message can't be intercepted by Metamod/AMXX (it is purely
  59. handled by the engine) so the only way to supercede it is to send our own
  60. custom message right after the original is fired. This works as long as
  61. the custom message is parsed AFTER the original. To achieve this here, we
  62. send it as an unreliable message (cl_messages 1 helps see arrival order).
  63.  
  64. The next difficulty is in figuring out what the message arguments are.
  65. For this I did some trial and error until I finally got it working, though
  66. in a really odd way. I also can't seem to send all of the pings in a single
  67. message without getting weird results or triggering heaps of message
  68. parsing errors (namely svc_bad).
  69.  
  70. A final consideration is bandwidth usage. I found out (with cl_shownet 1)
  71. the packet size increases by 102 bytes when the original SVC_PINGS message
  72. is sent for 32 players. Sending our own message right after means the size
  73. will grow even larger, so we should only send the message when absolutely
  74. needed. In this case that's once every client data update (any less often
  75. than that and the ping wasn't properly overridden sometimes).
  76.  
  77. ~~~~~~~~~~~~~
  78. - Changelog -
  79. ~~~~~~~~~~~~~
  80.  
  81. * v1.0: (Feb 23, 2009)
  82. - Public release
  83.  
  84. * v1.1: (Feb 23, 2009)
  85. - Managed to send up to 3 pings on a single message,
  86. thus reducing bandwidth usage by 26%
  87.  
  88. * v1.2: (Feb 23, 2009)
  89. - Added fake ping fluctuation and affect bots settings
  90.  
  91. * v1.2a: (Feb 24, 2009)
  92. - Fixed is_user_bot flag not being reset on disconnect
  93.  
  94. * v1.3: (Feb 24, 2009)
  95. - Added admin command to manually toggle fake ping for players
  96. - Added feature to automatically load fake pings from file
  97.  
  98. * v1.4: (Mar 15, 2009)
  99. - Added feature (+CVAR) to have the fake ping be a multiple
  100. of the player's real ping
  101.  
  102. * v1.5: (Jun 06, 2011)
  103. - Fixed plugin so that it works on all HL mods
  104. - Removed CVAR pingfake_flags (not really needed anymore)
  105. - Added feature (+CVAR) to have the plugin fake pings ONLY for
  106. players listed on the .INI file
  107. - Fixed fake pings overriden after DeathMsg/TeamInfo events in CS
  108.  
  109.  
  110. Fordította: BBk - Death of Legend
  111. =================================================================================*/
  112.  
  113. #include <amxmodx>
  114. #include <amxmisc>
  115. #include <fakemeta>
  116.  
  117. new const FAKEPINGS_FILE[] = "fakepings.ini"
  118. const TASK_ARGUMENTS = 100
  119.  
  120. new cvar_enable, cvar_ping, cvar_flux, cvar_target, cvar_bots, cvar_multiplier, cvar_fileonly, cvar_showactivity
  121. new g_maxplayers, g_connected[33], g_isbot[33], g_offset[33][2], g_argping[33][3]
  122. new g_loaded_counter, g_pingoverride[33] = { -1, ... }
  123. new Array:g_loaded_authid, Array:g_loaded_ping
  124.  
  125. public plugin_init()
  126. {
  127. register_plugin("Ping Faker", "1.5", "MeRcyLeZZ")
  128.  
  129. cvar_enable = register_cvar("pingfake_enable", "1")
  130. cvar_ping = register_cvar("pingfake_ping", "1337")
  131. cvar_flux = register_cvar("pingfake_flux", "0")
  132. cvar_target = register_cvar("pingfake_target", "1")
  133. cvar_bots = register_cvar("pingfake_bots", "0")
  134. cvar_multiplier = register_cvar("pingfake_multiplier", "0.0")
  135. cvar_fileonly = register_cvar("pingfake_fileonly", "0")
  136. cvar_showactivity = get_cvar_pointer("amx_show_activity")
  137.  
  138. g_maxplayers = get_maxplayers()
  139.  
  140. // If mod is CS, register some additional events to fix a bug
  141. new mymod[16]
  142. get_modname(mymod, charsmax(mymod))
  143. if (equal(mymod, "cstrike"))
  144. {
  145. register_event("DeathMsg", "fix_fake_pings", "a")
  146. register_event("TeamInfo", "fix_fake_pings", "a")
  147. }
  148.  
  149. register_forward(FM_UpdateClientData, "fw_UpdateClientData")
  150.  
  151. register_concmd("amx_fakeping", "cmd_fakeping", ADMIN_KICK, "<target> <ping> - hamis ping feluliras a jatekosokon (-1 kikapcsolas)")
  152.  
  153. g_loaded_authid = ArrayCreate(32, 1)
  154. g_loaded_ping = ArrayCreate(1, 1)
  155.  
  156. // Load list of IP/SteamIDs to fake pings for
  157. load_pings_from_file()
  158.  
  159. // Calculate weird argument values regularly in case we are faking ping fluctuations or a multiple of the real ping
  160. set_task(2.0, "calculate_arguments", TASK_ARGUMENTS, _, _, "b")
  161. }
  162.  
  163. // After some events in CS, the fake pings are overriden for some reason, so we have to send them again...
  164. public fix_fake_pings()
  165. {
  166. static player
  167. for (player = 1; player <= g_maxplayers; player++)
  168. {
  169. // Player not in game?
  170. if (!g_connected[player])
  171. continue;
  172.  
  173. // Resend fake pings
  174. fw_UpdateClientData(player)
  175. }
  176. }
  177.  
  178. public client_authorized(id)
  179. {
  180. check_for_loaded_pings(id)
  181. }
  182.  
  183. public client_putinserver(id)
  184. {
  185. g_connected[id] = true
  186. if (is_user_bot(id)) g_isbot[id] = true
  187. check_for_loaded_pings(id)
  188. }
  189.  
  190. public client_disconnect(id)
  191. {
  192. g_connected[id] = false
  193. g_isbot[id] = false
  194. g_pingoverride[id] = -1
  195. }
  196.  
  197. public fw_UpdateClientData(id)
  198. {
  199. // Ping faking disabled?
  200. if (!get_pcvar_num(cvar_enable)) return;
  201.  
  202. // Scoreboard key being pressed?
  203. if (!(pev(id, pev_button) & IN_SCORE) && !(pev(id, pev_oldbuttons) & IN_SCORE))
  204. return;
  205.  
  206. // Send fake player's pings
  207. static player, sending
  208. sending = 0
  209. for (player = 1; player <= g_maxplayers; player++)
  210. {
  211. // Player not in game?
  212. if (!g_connected[player])
  213. continue;
  214.  
  215. // Fake latency for its target too?
  216. if (!get_pcvar_num(cvar_target) && id == player)
  217. continue;
  218.  
  219. // Fake pings enabled for players on .INI file ONLY and this guy is not listed
  220. if (get_pcvar_num(cvar_fileonly) && g_pingoverride[player] < 0)
  221. continue;
  222.  
  223. // Only do these checks if not overriding ping for player
  224. if (g_pingoverride[player] < 0)
  225. {
  226. // Is this a bot?
  227. if (g_isbot[player])
  228. {
  229. // Bots setting disabled?
  230. if (!get_pcvar_num(cvar_bots)) continue;
  231. }
  232. else
  233. {
  234. // Bots only setting?
  235. if (get_pcvar_num(cvar_bots) == 2) continue;
  236. }
  237. }
  238.  
  239. // Send message with the weird arguments
  240. switch (sending)
  241. {
  242. case 0:
  243. {
  244. // Start a new message
  245. message_begin(MSG_ONE_UNRELIABLE, SVC_PINGS, _, id)
  246. write_byte((g_offset[player][0] * 64) + (1 + 2 * (player - 1)))
  247. write_short(g_argping[player][0])
  248. sending++
  249. }
  250. case 1:
  251. {
  252. // Append additional data
  253. write_byte((g_offset[player][1] * 128) + (2 + 4 * (player - 1)))
  254. write_short(g_argping[player][1])
  255. sending++
  256. }
  257. case 2:
  258. {
  259. // Append additional data and end message
  260. write_byte((4 + 8 * (player - 1)))
  261. write_short(g_argping[player][2])
  262. write_byte(0)
  263. message_end()
  264. sending = 0
  265. }
  266. }
  267. }
  268.  
  269. // End message if not yet sent
  270. if (sending)
  271. {
  272. write_byte(0)
  273. message_end()
  274. }
  275. }
  276.  
  277. public cmd_fakeping(id, level, cid)
  278. {
  279. // Check for access flag
  280. if (!cmd_access(id, level, cid, 3))
  281. return PLUGIN_HANDLED;
  282.  
  283. // Retrieve arguments
  284. static arg[32], player, ping
  285. read_argv(1, arg, sizeof arg - 1)
  286. player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
  287. read_argv(2, arg, sizeof arg - 1)
  288. ping = str_to_num(arg)
  289.  
  290. // Invalid target
  291. if (!player) return PLUGIN_HANDLED;
  292.  
  293. // Update ping overrides for player
  294. g_pingoverride[player] = min(ping, 4095)
  295.  
  296. // Get player's name for displaying/logging activity
  297. static name1[32], name2[32]
  298. get_user_name(id, name1, sizeof name1 - 1)
  299. get_user_name(player, name2, sizeof name2 - 1)
  300.  
  301. // Negative value means disable fakeping
  302. if (ping < 0)
  303. {
  304. // Show activity?
  305. switch (get_pcvar_num(cvar_showactivity))
  306. {
  307. case 1: client_print(0, print_chat, "ADMIN - hamis ping feluliras tiltva rajta: %s", name2)
  308. case 2: client_print(0, print_chat, "ADMIN %s - hamis ping feluliras tiltva rajta: %s", name1, name2)
  309. }
  310.  
  311. // Log activity
  312. static logdata[100], authid[32], ip[16]
  313. get_user_authid(id, authid, sizeof authid - 1)
  314. get_user_ip(id, ip, sizeof ip - 1, 1)
  315. formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - hamis ping feluliras tiltva rajta: %s", name1, authid, ip, name2)
  316. log_amx(logdata)
  317. }
  318. else
  319. {
  320. // Show activity?
  321. switch (get_pcvar_num(cvar_showactivity))
  322. {
  323. case 1: client_print(0, print_chat, "ADMIN - hamis ping feluliras (%d) engedelyezve rajta: %s", ping, name2)
  324. case 2: client_print(0, print_chat, "ADMIN %s - hamis ping feluliras (%d) engedelyezve rajta: %s", name1, ping, name2)
  325. }
  326.  
  327. // Log activity
  328. static logdata[100], authid[32], ip[16]
  329. get_user_authid(id, authid, sizeof authid - 1)
  330. get_user_ip(id, ip, sizeof ip - 1, 1)
  331. formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - hamis ping feluliras (%d) engedelyezve rajta: %s", name1, authid, ip, ping, name2)
  332. log_amx(logdata)
  333. }
  334.  
  335. return PLUGIN_HANDLED;
  336. }
  337.  
  338. // Calculate weird argument values based on target ping
  339. public calculate_arguments()
  340. {
  341. static player, ping, loss
  342. for (player = 1; player <= g_maxplayers; player++)
  343. {
  344. // Calculate target ping (clamp if out of bounds)
  345. if (g_pingoverride[player] < 0)
  346. {
  347. if (get_pcvar_float(cvar_multiplier) > 0.0)
  348. {
  349. get_user_ping(player, ping, loss)
  350. ping = clamp(floatround(ping * get_pcvar_float(cvar_multiplier)), 0, 4095)
  351. }
  352. else
  353. ping = clamp(get_pcvar_num(cvar_ping) + random_num(-abs(get_pcvar_num(cvar_flux)), abs(get_pcvar_num(cvar_flux))), 0, 4095)
  354. }
  355. else
  356. ping = g_pingoverride[player]
  357.  
  358. // First argument's ping
  359. for (g_offset[player][0] = 0; g_offset[player][0] < 4; g_offset[player][0]++)
  360. {
  361. if ((ping - g_offset[player][0]) % 4 == 0)
  362. {
  363. g_argping[player][0] = (ping - g_offset[player][0]) / 4
  364. break;
  365. }
  366. }
  367. // Second argument's ping
  368. for (g_offset[player][1] = 0; g_offset[player][1] < 2; g_offset[player][1]++)
  369. {
  370. if ((ping - g_offset[player][1]) % 2 == 0)
  371. {
  372. g_argping[player][1] = (ping - g_offset[player][1]) / 2
  373. break;
  374. }
  375. }
  376. // Third argument's ping
  377. g_argping[player][2] = ping
  378. }
  379. }
  380.  
  381. load_pings_from_file()
  382. {
  383. // Build file path
  384. new path[64]
  385. get_configsdir(path, sizeof path - 1)
  386. format(path, sizeof path - 1, "%s/%s", path, FAKEPINGS_FILE)
  387.  
  388. // File not present, skip loading
  389. if (!file_exists(path)) return;
  390.  
  391. // Open file for reading
  392. new linedata[40], authid[32], ping[8], file = fopen(path, "rt")
  393.  
  394. while (file && !feof(file))
  395. {
  396. // Read one line at a time
  397. fgets(file, linedata, sizeof linedata - 1)
  398.  
  399. // Replace newlines with a null character to prevent headaches
  400. replace(linedata, sizeof linedata - 1, "^n", "")
  401.  
  402. // Blank line or comment
  403. if (!linedata[0] || linedata[0] == ';') continue;
  404.  
  405. // Get authid and ping
  406. strbreak(linedata, authid, sizeof authid - 1, ping, sizeof ping -1)
  407. remove_quotes(ping)
  408.  
  409. // Store data into global arrays
  410. ArrayPushString(g_loaded_authid, authid)
  411. ArrayPushCell(g_loaded_ping, clamp(str_to_num(ping), 0, 4095))
  412.  
  413. // Increase loaded data counter
  414. g_loaded_counter++
  415. }
  416. if (file) fclose(file)
  417. }
  418.  
  419. check_for_loaded_pings(id)
  420. {
  421. // Nothing to check for
  422. if (g_loaded_counter <= 0) return;
  423.  
  424. // Get steamid and ip
  425. static authid[32], ip[16], i, buffer[32]
  426. get_user_authid(id, authid, sizeof authid - 1)
  427. get_user_ip(id, ip, sizeof ip - 1, 1)
  428.  
  429. for (i = 0; i < g_loaded_counter; i++)
  430. {
  431. // Retrieve authid
  432. ArrayGetString(g_loaded_authid, i, buffer, sizeof buffer - 1)
  433.  
  434. // Compare it with this player's steamid and ip
  435. if (equali(buffer, authid) || equal(buffer, ip))
  436. {
  437. // We've got a match!
  438. g_pingoverride[id] = ArrayGetCell(g_loaded_ping, i)
  439. break;
  440. }
  441. }
  442. }
  443.