Anti-cheatы для Source

Обсуждаем все, что относится к выделенным серверам *NIX (Unix, Linux) и Windows
Сообщение
Автор
putnik1591
Нович0к
Нович0к
Сообщения: 29
Зарегистрирован: 10.01.2009
Откуда: Волгоград
Контактная информация:

#61 Сообщение 07.07.2009, 10:53

Dirt, такого плагина пока не наблюдается...

Dirt
Сержант
Сержант
Сообщения: 50
Зарегистрирован: 22.09.2008

#62 Сообщение 09.07.2009, 19:35

putnik1591
Ну дык, есть же серваки на CSS с MyAC, что они тогда пользуют? :/
Изображение
Изображение
Изображение
Изображение

putnik1591
Нович0к
Нович0к
Сообщения: 29
Зарегистрирован: 10.01.2009
Откуда: Волгоград
Контактная информация:

#63 Сообщение 09.07.2009, 21:15

Dirt, никаких дополнительных плагинов не стоит. Все так и работает. =\
Сам бы хотел такое найти,чтобы у лицензий не требовало...

Аватара пользователя
kykysha
Лейтенант
Лейтенант
Сообщения: 123
Зарегистрирован: 08.09.2008

#64 Сообщение 11.07.2009, 13:42

2. MyAC - основной минус конечно платность и второй немаловажный 64-бита ОС.
пишут что обновляется первый пост но как скачать то его пробывали ?? ссылка битая
Изображение

kadet89
Майор
Майор
Сообщения: 557
Зарегистрирован: 26.12.2006

#65 Сообщение 24.07.2009, 02:08

Народ, кому удалось всётаки натаскать DeToCs Anti-cheat на спидхак, поделитесь конфигом плз.
Мне что-то кажется что этот античит вообще не способен детектить спидхак...
Detox Anti Cheat - установлен, но реально беспомощен перед подрубами.
...
Вот чтобы не говорили, а он лучше всех справляется с этим читом и главное не банит, а просто тормозит игрока. Правда проверено, из-за него сервер частенько падает...

Аватара пользователя
leha---83
Капитан
Капитан
Сообщения: 275
Зарегистрирован: 24.11.2008
Откуда: Perm (Chernushka)
Контактная информация:

#66 Сообщение 25.07.2009, 19:11

Ниразу не падал за 3 месяца (Linux ubuntu server 9.04)
Изображение

kadet89
Майор
Майор
Сообщения: 557
Зарегистрирован: 26.12.2006

#67 Сообщение 26.07.2009, 20:10

leha---83, ну значит тебе повезло. У меня много скриптов и конфликты неизбежны.

kadet89
Майор
Майор
Сообщения: 557
Зарегистрирован: 26.12.2006

#68 Сообщение 27.07.2009, 16:33

Как я понял, проблема Kigen's Anti-Cheat в том, что он банит по steam-id
IMPORTANT: KAC will NOT work with non-Steam (cracked) servers!
И получается он не будет работать в локалке?

Аватара пользователя
[»Twilight«]
Капитан
Капитан
Сообщения: 277
Зарегистрирован: 22.05.2007
Откуда: "Heaven's Night" Club, 2121 Carroll Street, Silent Hill, ME [Ukraine]
Контактная информация:

#69 Сообщение 27.07.2009, 17:17

Если ставить эмуль, который будет женерить steam_id - будет.
If you are the Receiver of Wisdom, you will understand my words...
Изображение

kadet89
Майор
Майор
Сообщения: 557
Зарегистрирован: 26.12.2006

#70 Сообщение 27.07.2009, 18:50

[»Twilight«], можешь сказать, этот эмуль со стороны клиента не требует установки доп. софта?

Я просто думаю может быстро переписать античит, чтоб он с ипом работал

Аватара пользователя
[»Twilight«]
Капитан
Капитан
Сообщения: 277
Зарегистрирован: 22.05.2007
Откуда: "Heaven's Night" Club, 2121 Carroll Street, Silent Hill, ME [Ukraine]
Контактная информация:

#71 Сообщение 27.07.2009, 19:02

Серверный емуль (eSTEAMATiON, RevEmu...)
If you are the Receiver of Wisdom, you will understand my words...
Изображение

kadet89
Майор
Майор
Сообщения: 557
Зарегистрирован: 26.12.2006

#72 Сообщение 27.07.2009, 21:54

Он со спидхаком борется также как Detox Anti Cheat?
Всмысле не банит, а просто притормаживает игрока?

Аватара пользователя
U#0
Майор
Майор
Сообщения: 529
Зарегистрирован: 25.10.2007
Поблагодарили: 1 раз
Контактная информация:

#73 Сообщение 27.07.2009, 22:01

kadet89 писал(а):Я просто думаю может быстро переписать античит, чтоб он с ипом работал
Прально!
Если секс - то только стоя и в гамаке! )))

kadet89
Майор
Майор
Сообщения: 557
Зарегистрирован: 26.12.2006

#74 Сообщение 28.07.2009, 00:25

Detocs провалил детектирование спидхака.
Kigen's Anti-Cheat походу тоже провалит...но может ещё я его неправильно настроил или эти оба античита борятся с другим типом спидхака.

Походу альтернативы detox'у в плане борьбы со спидхаком нет
Последний раз редактировалось kadet89 28.07.2009, 15:38, всего редактировалось 2 раза.

Аватара пользователя
[»Twilight«]
Капитан
Капитан
Сообщения: 277
Зарегистрирован: 22.05.2007
Откуда: "Heaven's Night" Club, 2121 Carroll Street, Silent Hill, ME [Ukraine]
Контактная информация:

#75 Сообщение 28.07.2009, 12:16

kadet89 писал(а):Detox провалил детектирование спидхака.
В server.cfg допиши

Код: Выделить всё

detox_sh 1
kadet89 писал(а):Kigen's Anti-Cheat походу тоже провалит...
kadet89 писал(а):Походу альтернативы detocs'у в плане борьбы со спидхаком нет
Покажи мне, где тут борьба со спидхаком?
detocs.py

Код: Выделить всё

# -*- coding:Utf-8 -*-

import es, playerlib, os, time, repeat, random, gamethread, langlib, urllib2

########NE PAS EDITER CE FICHIER########
########DON'T EDIT THIS FILE########

info = es.AddonInfo()
info.name = "DeToCs Anti-Cheat" 
info.version = "1.2"
info.author = "MegaMan" 
info.url = "www.team-tocs.com"

es.ServerVar('DeToCs', info.version, 'AntiCheat: Check cheating variables (by MegaMan)').makepublic()

action_on_cheatR = es.ServerVar("action_on_cheat")
ban_durationR = es.ServerVar("ban_duration")
ban_typeR = es.ServerVar("ban_type")
advert_on_cheatR = es.ServerVar("advert_on_cheat")
advert_on_nocheatR = es.ServerVar("advert_on_nocheat")
check_on_fragR = es.ServerVar("check_on_frag")
check_repeatR = es.ServerVar("check_repeat")
check_secondsR = es.ServerVar("check_seconds")
detocs_langR = es.ServerVar("detocs_lang")
ban_with_gbR = es.ServerVar("ban_with_gb")
idreason_gbR = es.ServerVar("idreason_gb")
steamid_gbR = es.ServerVar("steamid_gb")
detect = False
on_connect = False
messages = langlib.Strings(es.getAddonPath("detocs") + "/language.ini")

def load():
	es.log("[DeToCs] Load")
	es.server.cmd("es_xmexec ../addons/eventscripts/detocs/detocs.cfg")
	if int(check_repeatR) == 1:
		repeat.create("CheckCheat", check_variable_seconds)
		repeat.start("CheckCheat", int(check_secondsR), 0)

def unload():
	es.log("[DeToCs] Unload")
	if int(check_repeatR) == 1:
		repeat.stop("CheckCheat")
		repeat.delete("CheckCheat")

def player_activate(event_var):
	global on_connect
	if int(es.ServerVar("sv_cheats")) == 0:
		on_connect = True
		if int(check_on_fragR) == 0 and int(check_repeatR) == 0:
			check_variable_connect(event_var['userid'])
			gamethread.delayed(random.randint(40,100), check_variable, event_var['userid'])
		else:
			check_variable(event_var['userid'])

def check_variable(userid):
	global on_connect
	if int(es.ServerVar("sv_cheats")) == 0:
		if int(userid) in es.getUseridList():
			es.queryclientvar(userid, "sv_cheats")
			es.queryclientvar(userid, "mat_wireframe")
			es.queryclientvar(userid, "r_drawothermodels")
			es.queryclientvar(userid, "mat_fillrate")
			es.queryclientvar(userid, "snd_show")
			es.queryclientvar(userid, "snd_visualize")
			es.queryclientvar(userid, "r_partition_level")
			es.queryclientvar(userid, "r_drawbrushmodels")
			es.queryclientvar(userid, "mem_force_flush")
			es.queryclientvar(userid, "r_drawmodelstatsoverlay")
			es.queryclientvar(userid, "cl_leveloverview")
			es.queryclientvar(userid, "r_shadowwireframe")
			es.queryclientvar(userid, "r_visualizetraces")
			es.queryclientvar(userid, "r_rainspeed")
			es.queryclientvar(userid, "r_visualizelighttraces")
			es.queryclientvar(userid, "cl_particles_show_bbox")
			es.queryclientvar(userid, "r_drawparticles")
			es.queryclientvar(userid, "r_drawlights")
			es.queryclientvar(userid, "r_drawrenderboxes")
			es.queryclientvar(userid, "vcollide_wireframe")
			es.queryclientvar(userid, "fog_enable")
			es.queryclientvar(userid, "mat_normalmaps")
			es.queryclientvar(userid, "mat_luxels")
			es.queryclientvar(userid, "cl_pitchup")
			es.queryclientvar(userid, "cl_pitchdown")
			es.queryclientvar(userid, "cl_bobcycle")
			es.queryclientvar(userid, "r_modelwireframedecal")
			es.queryclientvar(userid, "sv_showplayerhitboxes")
			es.queryclientvar(userid, "vgui_drawtree")
			if int(es.ServerVar("sv_consistency")) == 1:
				es.queryclientvar(userid, "sv_consistency")
			es.queryclientvar(userid, "mat_showlowresimage")
			on_connect = False
			es.queryclientvar(userid, "host_framerate")


def check_variable_connect(userid):
	es.queryclientvar(userid, "sv_cheats")
	es.queryclientvar(userid, "mat_wireframe")
	es.queryclientvar(userid, "r_drawothermodels")
	es.queryclientvar(userid, "mat_fillrate")
	es.queryclientvar(userid, "snd_show")
	es.queryclientvar(userid, "snd_visualize")
	es.queryclientvar(userid, "r_partition_level")
	es.queryclientvar(userid, "r_drawbrushmodels")
	es.queryclientvar(userid, "mem_force_flush")
	es.queryclientvar(userid, "r_drawmodelstatsoverlay")
	es.queryclientvar(userid, "cl_leveloverview")
	es.queryclientvar(userid, "r_shadowwireframe")
	es.queryclientvar(userid, "r_visualizetraces")
	es.queryclientvar(userid, "r_rainspeed")
	es.queryclientvar(userid, "r_visualizelighttraces")
	es.queryclientvar(userid, "cl_particles_show_bbox")
	es.queryclientvar(userid, "r_drawparticles")
	es.queryclientvar(userid, "r_drawlights")
	es.queryclientvar(userid, "r_drawrenderboxes")
	es.queryclientvar(userid, "vcollide_wireframe")
	es.queryclientvar(userid, "fog_enable")
	es.queryclientvar(userid, "mat_normalmaps")
	es.queryclientvar(userid, "mat_luxels")
	es.queryclientvar(userid, "cl_pitchup")
	es.queryclientvar(userid, "cl_pitchdown")
	es.queryclientvar(userid, "cl_bobcycle")
	es.queryclientvar(userid, "r_modelwireframedecal")
	es.queryclientvar(userid, "sv_showplayerhitboxes")
	es.queryclientvar(userid, "vgui_drawtree")
	es.queryclientvar(userid, "mat_showlowresimage")
	if int(es.ServerVar("sv_consistency")) == 1:
		es.queryclientvar(userid, "sv_consistency")
	es.queryclientvar(userid, "host_framerate")

def check_variable_seconds():
	global on_connect
	if int(es.ServerVar("sv_cheats")) == 0:
		for userid in es.getUseridList():
			es.queryclientvar(userid, "sv_cheats")
			es.queryclientvar(userid, "mat_wireframe")
			es.queryclientvar(userid, "r_drawothermodels")
			es.queryclientvar(userid, "mat_fillrate")
			es.queryclientvar(userid, "snd_show")
			es.queryclientvar(userid, "snd_visualize")
			es.queryclientvar(userid, "r_partition_level")
			es.queryclientvar(userid, "r_drawbrushmodels")
			es.queryclientvar(userid, "mem_force_flush")
			es.queryclientvar(userid, "r_drawmodelstatsoverlay")
			es.queryclientvar(userid, "cl_leveloverview")
			es.queryclientvar(userid, "r_shadowwireframe")
			es.queryclientvar(userid, "r_visualizetraces")
			es.queryclientvar(userid, "r_rainspeed")
			es.queryclientvar(userid, "r_visualizelighttraces")
			es.queryclientvar(userid, "cl_particles_show_bbox")
			es.queryclientvar(userid, "r_drawparticles")
			es.queryclientvar(userid, "r_drawlights")
			es.queryclientvar(userid, "r_drawrenderboxes")
			es.queryclientvar(userid, "vcollide_wireframe")
			es.queryclientvar(userid, "fog_enable")
			es.queryclientvar(userid, "mat_normalmaps")
			es.queryclientvar(userid, "mat_luxels")
			es.queryclientvar(userid, "cl_pitchup")
			es.queryclientvar(userid, "cl_pitchdown")
			es.queryclientvar(userid, "cl_bobcycle")
			es.queryclientvar(userid, "r_modelwireframedecal")
			es.queryclientvar(userid, "sv_showplayerhitboxes")
			es.queryclientvar(userid, "vgui_drawtree")
			es.queryclientvar(userid, "mat_showlowresimage")
			if int(es.ServerVar("sv_consistency")) == 1:
				es.queryclientvar(userid, "sv_consistency")
			on_connect = False
			es.queryclientvar(userid, "host_framerate")

def player_death(event_var):
	if int(check_on_fragR) == 1 and int(es.ServerVar("sv_cheats")) == 0:
		check_variable(event_var['attacker'])

def player_disconnect(event_var):
	global detect
	detect = False

def es_player_variable(event_var):
	global detect
	global on_connect
	variable_offense = False
	tokens = {}
	if (not detect) and (event_var['variable'] != "rate"):
		if (event_var['variable'] in "sv_cheats mat_wireframe mat_fillrate snd_show snd_visualize mem_force_flush r_drawmodelstatsoverlay cl_leveloverview r_shadowwireframe r_visualizetraces r_visualizelighttraces cl_particles_show_bbox r_drawlights r_drawrenderboxes vcollide_wireframe mat_normalmaps mat_luxels r_modelwireframedecal sv_showplayerhitboxes vgui_drawtree mat_showlowresimage") and (str(event_var['value']) != '0'):
			variable_offense = True
		elif (event_var['variable'] in "sv_consistency r_drawothermodels r_drawbrushmodels r_drawparticles fog_enable") and (str(event_var['value']) != '1'):
			variable_offense = True
		elif (event_var['variable'] == "cl_pitchup cl_pitchdown") and (str(event_var['value']) != '89'):
			variable_offense = True
		elif (event_var['variable'] == "r_partition_level") and (str(event_var['value']) != '-1'):
			variable_offense = True
		elif (event_var['variable'] == "cl_bobcycle") and (str(event_var['value']) != '0.8'):
			variable_offense = True
		elif (event_var['variable'] == "r_rainspeed") and (str(event_var['value']) != '600.0f'):
			variable_offense = True
		elif (event_var['variable'] == "host_framerate") and (str(event_var['value']) != '0'):
			joueur = playerlib.getPlayer(event_var['userid'])
			es.server.queuecmd("kickid %s [DeToCs] %s"%(event_var['userid'], messages("host_framerate",lang=joueur.get("lang"))))
			on_connect = False
		if variable_offense:
			tokens["variablecl"] = event_var['variable']
			tokens["userid"] = event_var['userid']
			tokens["username"] = es.getplayername(event_var['userid'])
			tokens["steamid"] = es.getplayersteamid(event_var['userid'])
			player = playerlib.getPlayer(event_var['userid'])
			userIp = player.attributes["address"]
			ipAddy, port = userIp.split(":")
			if int(action_on_cheatR) == 0:
				es.msg("#multi", messages("advert_cheat",opts=tokens,lang=detocs_langR))
				detect = True
			if int(action_on_cheatR) == 1:
				es.server.queuecmd("kickid %s [DeToCs] Kick (%s bypass)" % (event_var['userid'], event_var['variable']))
				detect = True
			elif int(action_on_cheatR) == 2:
				es.server.queuecmd("kickid %s [DeToCs] Ban (%s bypass)" % (event_var['userid'], event_var['variable']))
				if int(ban_with_gbR) == 1:
					es.server.queuecmd('es gb_externalBanUser "%s" "%s" %s %s minutes %s'%(str(steamid_gbR), es.getplayersteamid(event_var['userid']), str(idreason_gbR), str(ban_durationR), urllib2.quote(es.getplayername(event_var['userid']))))
					es.log("COMMANDE: es gb_externalBanUser %s %s %s %s minutes %s"%(str(steamid_gbR), es.getplayersteamid(event_var['userid']), str(idreason_gbR), str(ban_durationR), urllib2.quote(es.getplayername(event_var['userid']))))
				else:
					if int(ban_typeR) == 0:
						es.server.queuecmd("banid %s %s" % (int(es.ServerVar('ban_duration')), es.getplayersteamid(event_var['userid'])))
						es.server.queuecmd("writeid")
					elif int(ban_typeR) == 1:
						es.server.queuecmd("addip %s %s" % (int(es.ServerVar('ban_duration')), ipAddy))
						es.server.queuecmd("writeip")
					elif int(ban_typeR) == 2:
						es.server.queuecmd("addip %s %s" % (int(es.ServerVar('ban_duration')), ipAddy))
						es.server.queuecmd("banid %s %s" % (int(es.ServerVar('ban_duration')), es.getplayersteamid(event_var['userid'])))
						es.server.queuecmd("writeid")
						es.server.queuecmd("writeip")
				detect = True
			if (int(advert_on_cheatR) == 1) and (int(action_on_cheatR) == 1):
				es.msg ("#multi", messages("advert_kick",opts=tokens,lang=detocs_langR))
			elif (int(advert_on_cheatR) == 1) and (int(action_on_cheatR) == 2):
 				es.msg ("#multi", messages("advert_ban",opts=tokens,lang=detocs_langR))
			if os.path.isfile(os.getcwd() + "/cstrike/addons/eventscripts/detocs/detocs_logs.txt"):
				fichier = open(os.getcwd() + "/cstrike/addons/eventscripts/detocs/detocs_logs.txt", "a")
			else:
				fichier = open(os.getcwd() + "/cstrike/addons/eventscripts/detocs/detocs_logs.txt", "w")
			fichier.write("Date: %s %s\n"%(time.strftime("%d/%m/%y", time.localtime()), time.strftime("%H:%M", time.localtime())))
        		fichier.write("Username: %s\n"%es.getplayername(event_var['userid']))
        		fichier.write("SteamID: %s\n"%es.getplayersteamid(event_var['userid']))
        		fichier.write("IP: %s\n"%ipAddy)
			fichier.write("Variable: %s\n"%event_var['variable'])
			fichier.write("-----------------------------------\n")
       			fichier.close()
		elif (int(advert_on_nocheatR) == 1) and (event_var['variable'] == "host_framerate") and on_connect:
			tokens["username"] = es.getplayername(event_var['userid'])
			tokens["steamid"] = es.getplayersteamid(event_var['userid'])
			es.msg ("#multi", messages("advert_nocheat",opts=tokens,lang=detocs_langR))
			on_connect = False
kigen-ac-pub.sp

Код: Выделить всё

/************************************************
 *		Kigen's Anti-Cheat		*
 *----------------------------------------------*
 * Author: Kigen @ codingdirect.com 		*
 * Thanks to: SourceMod Team for covering a lot *
 * of the grunt work. :P			*
 ************************************************
 *		Copyright Notice		*
 *----------------------------------------------*
 * Copyright (c) 2008-09 Max Krivanek aka Kigen	*
 ************************************************
 *		Websites to Visit		*
 *----------------------------------------------*
 * http://www.kigenac.com/ - KAC's home.	*
 * http://www.codingdirect.com/	- My website	*
 * http://www.n00bsalad.net/ - Best servers on  *
 * the west coast. Users of KAC private version.*
 ************************************************
 * 		 Version History		*
 * ---------------------------------------------*
 * 1.0 Public - Initial Released Public Version *
 * 1.0.1 Pub - Removed useless dependencies.	*
 * 1.0.2 Pub - Fixed round_freeze_end for 	*
 * servers that don't have it. :P		*
 * 1.1 Pub - Added Cafe banning and using KAC	*
 * global banlist.  Added blocking names with	*
 * multibyte characters.  Fixed possible error	*
 * with format.					*
 * 1.1.1 Pub - Fixed problem with replication. 	*
 * 1.1.2 Pub - Replaced bobcycle cvar check.	*
 * 1.1.3 Pub - Fixed problems relating to mis-	*
 * documented/used functions in SourceMod.	*
 * 1.1.4 Pub - Fixed various bugs.  Reworked 	*
 * some of the code. Added logging to separate 	*
 * file. Now requires Sockets for use.  Added 	*
 * support for MySQL bans.			*
 * 1.1.5 Pub - Some new things, probably more 	*
 * than needed but shouldn't affect KAC's 	*
 * performance.  Added check for mat_dxlevel. 	*
 * 1.1.6 Pub - Fixed an error preventing a ban. *
 * 1.1.7 Pub - Updated various things.  Added	*
 * update checker to check for updates. 	*
 * Optimizations have been done as well.	*
 * 1.1.8 Pub - Added Spam Checking.  More	*
 * optimizations to the code.  Added define to	*
 * exclude Sockets at will.			*
 ************************************************
 * 		     License			*
 *----------------------------------------------*
 * All below code is to be covered under the 	*
 * GPL v3 or a later version.			*
 * http://www.gnu.org/licenses/gpl-3.0.txt	*
 ************************************************
 *		      Notes			*
 *----------------------------------------------*
 * This is a public version of the plugin.  It  *
 * is indeed pretty much KAC as it stands now,  *
 * however, it will not recieve all the future  *
 * features that maybe added to my own private  *
 * version of the plugin.  What made me decide  *
 * to go ahead and release a public version of  *
 * this plugin is the release of other similar  *
 * plugins such as ES Anti-Cheat and VBAC.	*
 * Since they currently use the Query ConVar	*
 * feature present in the Source engine they're *
 * likely to get bypassed or dodged due to the  *
 * releases.  Because of this I decided to go   *
 * ahead and give the community something 	*
 * useful instead of just these little plugins  *
 * that only detect sv_cheats and in the case   *
 * of VBAC mat_wireframe.			*
 * Also note that this was originally built  	*
 * before the releases of both above said ACs.	*
 ************************************************

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    **** DO NOT MODIFY THE ABOVE NOTICES PLEASE! (Unless just to note additions.) ****

*/

#define SOCKET_ENABLED  // Comment this line out to disable Sockets.

#pragma semicolon 1
#include <sourcemod>
#if defined SOCKET_ENABLED
#include <socket>
#endif

// Defined Native here rather than including the larger IRC include.
#if defined SOCKET_ENABLED // No Sockets, no IRC.
native IRC_PrivMsg(const String:destination[], const String:message[], any:...);
#endif

#define PLUGIN_VERSION "1.1.8"
#define MAX_HACKCVAR 33 // !!!!!!! If you add mat_dxlevel back make sure you change this!!!!!!!!!!!!!!!!!
#define MAX_WEAPONS 24

// Connection States
#define CS_NOTCONN 	0
#define CS_CONNING 	1
#define CS_AUTHED 	2
#define CS_VALIDATED 	3
#define CS_BOT 		4
#define CS_BANNING	5

// Action Types
#define ACTION_BAN 	0
#define ACTION_KICK	1
#define ACTION_WARN	2

// Compare Types
#define COMP_EQUAL	0
#define COMP_LESS	1
#define COMP_GREATER	2

new const String:g_CompareString[3][] = { "equal to", "less than or equal to", "greater than or equal to" };

// Booleans
#if defined SOCKET_ENABLED
new bool:HasIRC = false;
new bool:Locked = false;
new bool:Checked = false;
#endif
new bool:Enabled = true;
new ConnState[MAXPLAYERS+1] = {CS_NOTCONN, ...};
new count[MAXPLAYERS+1] = {0,...};

// CVAR Handles
new Handle:CVar_BlockNameCopy = INVALID_HANDLE;
new Handle:CVar_Cheats = INVALID_HANDLE;
new Handle:CVar_IRCChan = INVALID_HANDLE;
new Handle:CVar_BanCafe = INVALID_HANDLE;
new Handle:CVar_BlockMultiByte = INVALID_HANDLE;
new Handle:CVar_Enable = INVALID_HANDLE;

// Timer handles.
new Handle:PTimer[MAXPLAYERS+1] = {INVALID_HANDLE, ...};

// Socket
#if defined SOCKET_ENABLED
new Handle:TSocket = INVALID_HANDLE;
#endif

// Reason Strings
new String:g_Reason[MAXPLAYERS+1][512];
new String:g_Reason2[MAXPLAYERS+1][512];

// Arrays
new Handle:CacheAuthArray = INVALID_HANDLE;
new Handle:CacheReasonArray = INVALID_HANDLE;
#if defined SOCKET_ENABLED
new Handle:AllowArray = INVALID_HANDLE;
#endif
new Handle:IPBlockArray = INVALID_HANDLE;

/* Cvars to protect
 * If you wish to add more CVars then please make sure they are replicated properly on normal clients
 * and that you add at the end of this list and add the proper value for that CVar at the end of 
 * g_HackCVarValues.  You will also need to add one to MAX_HACKCVAR.
 */
new String:g_HackCVars[][] = {
	"cl_clock_correction", 	// 15	0
	"cl_leveloverview",	// 9 	1
	"cl_overdraw_test",	//	2
	"cl_particles_show_bbox", // 11	3
	"cl_phys_timescale",	//	4
	"cl_showevents",	//	5
	"fog_enable",		// 7	6
	"host_timescale",	// 2	7
	"mat_fillrate",		// 8	8
	"mat_proxy",		// 5	9
	"mat_wireframe",	//	10
	"mem_force_flush",	// 10	11
	"snd_show",		// 17	12
	"snd_visualize",	// 18	13
	"sv_cheats",		// 0	14
	"sv_consistency",	// 3	15
	"sv_gravity",		// 1	16
	"r_aspectratio",	// 14	17
	"r_colorstaticprops",	// 19	18
	"r_DispWalkable",	// 20	19
	"r_DrawBeams",		// 21	20
	"r_drawbrushmodels",	// 22	21
	"r_drawclipbrushes",	// 23	22
	"r_drawdecals",		// 24	23
	"r_drawentities",	//	24
	"r_drawopaqueworld",	//	25
	"r_drawothermodels",	// 16	26
	"r_drawparticles",	// 4	27
	"r_drawrenderboxes",	// 12	28
	"r_drawtranslucentworld", //	29
	"r_shadowwireframe",	// 6	30
	"r_skybox",		//	31
	"r_visocclusion",	//	32
	"vcollide_wireframe"	// 13	33
//	"cl_bobcycle"		//	34
//	"mat_dxlevel"		//	35
};
new Float:g_HackCVarValues[] = {
	1.0, // cl_clock_correction	15	0
	0.0, // cl_leveloverview	9	1
	0.0, // cl_overdraw_test		2
	0.0, // cl_particles_show_bbox	11	3
	1.0, // cl_phys_timescale		4
	0.0, // cl_showevents			5
	1.0, // fog_enable		7	6
	1.0, // host_timescale		2	7
	0.0, // mat_fillrate		8	8
	0.0, // mat_proxy		5	9
	0.0, // mat_wireframe			10
	0.0, // mem_force_flush		10	11
	0.0, // snd_show		17	12
	0.0, // snd_visualize		18	13
	0.0, // sv_cheats		0	14
	1.0, // sv_consistency		3	15
	800.0, // sv_gravity		1	16
	0.0, // r_aspectratio		14	17
	0.0, // r_colorstaticprops	19	18
	0.0, // r_DispWalkable		20	19
	1.0, // r_DrawBeams		21	20
	1.0, // r_drawbrushmodels	22	21
	0.0, // r_drawclipbrushes	23	22
	1.0, // r_drawdecals		24	23
	1.0, // r_drawentities			24
	1.0, // r_drawopaqueworld		25
	1.0, // r_drawothermodels	16	26
	1.0, // r_drawparticles		4	27
	0.0, // r_drawrenderboxes	12	28
	1.0, // r_drawtranslucentworld		29
	0.0, // r_shadowwireframe	6	30
	1.0, // r_skybox			31
	0.0, // r_visocclusion			32
	0.0  // vcollide_wireframe	13	33
//	0.8  // cl_bobcycle			34
//	80.0 // mat_dxlevel			35
};
new g_HackCVarsComp[] = {
	COMP_EQUAL, // cl_clock_correction	15	0
	COMP_EQUAL, // cl_leveloverview	9	1
	COMP_EQUAL, // cl_overdraw_test		2
	COMP_EQUAL, // cl_particles_show_bbox	11	3
	COMP_EQUAL, // cl_phys_timescale		4
	COMP_EQUAL, // cl_showevents			5
	COMP_EQUAL, // fog_enable		7	6
	COMP_EQUAL, // host_timescale		2	7
	COMP_EQUAL, // mat_fillrate		8	8
	COMP_EQUAL, // mat_proxy		5	9
	COMP_EQUAL, // mat_wireframe			10
	COMP_EQUAL, // mem_force_flush		10	11
	COMP_EQUAL, // snd_show		17	12
	COMP_EQUAL, // snd_visualize		18	13
	COMP_EQUAL, // sv_cheats		0	14
	COMP_EQUAL, // sv_consistency		3	15
	COMP_EQUAL, // sv_gravity		1	16
	COMP_EQUAL, // r_aspectratio		14	17
	COMP_EQUAL, // r_colorstaticprops	19	18
	COMP_EQUAL, // r_DispWalkable		20	19
	COMP_EQUAL, // r_DrawBeams		21	20
	COMP_EQUAL, // r_drawbrushmodels	22	21
	COMP_EQUAL, // r_drawclipbrushes	23	22
	COMP_EQUAL, // r_drawdecals		24	23
	COMP_EQUAL, // r_drawentities			24
	COMP_EQUAL, // r_drawopaqueworld		25
	COMP_EQUAL, // r_drawothermodels	16	26
	COMP_EQUAL, // r_drawparticles		4	27
	COMP_EQUAL, // r_drawrenderboxes	12	28
	COMP_EQUAL, // r_drawtranslucentworld		29
	COMP_EQUAL, // r_shadowwireframe	6	30
	COMP_EQUAL, // r_skybox			31
	COMP_EQUAL, // r_visocclusion			32
	COMP_EQUAL  // vcollide_wireframe	13	33
//	COMP_EQUAL  // cl_bobcycle			34
//	COMP_GREATER // mat_dxlevel			35
};
new g_HackCVarsAction[] = {
	ACTION_BAN, // cl_clock_correction	15	0
	ACTION_BAN, // cl_leveloverview	9	1
	ACTION_BAN, // cl_overdraw_test		2
	ACTION_BAN, // cl_particles_show_bbox	11	3
	ACTION_BAN, // cl_phys_timescale		4
	ACTION_BAN, // cl_showevents			5
	ACTION_BAN, // fog_enable		7	6
	ACTION_BAN, // host_timescale		2	7
	ACTION_BAN, // mat_fillrate		8	8
	ACTION_BAN, // mat_proxy		5	9
	ACTION_BAN, // mat_wireframe			10
	ACTION_BAN, // mem_force_flush		10	11
	ACTION_BAN, // snd_show		17	12
	ACTION_BAN, // snd_visualize		18	13
	ACTION_BAN, // sv_cheats		0	14
	ACTION_BAN, // sv_consistency		3	15
	ACTION_BAN, // sv_gravity		1	16
	ACTION_KICK, // r_aspectratio		14	17
	ACTION_BAN, // r_colorstaticprops	19	18
	ACTION_BAN, // r_DispWalkable		20	19
	ACTION_BAN, // r_DrawBeams		21	20
	ACTION_BAN, // r_drawbrushmodels	22	21
	ACTION_BAN, // r_drawclipbrushes	23	22
	ACTION_BAN, // r_drawdecals		24	23
	ACTION_BAN, // r_drawentities			24
	ACTION_BAN, // r_drawopaqueworld		25
	ACTION_BAN, // r_drawothermodels	16	26
	ACTION_BAN, // r_drawparticles		4	27
	ACTION_BAN, // r_drawrenderboxes	12	28
	ACTION_BAN, // r_drawtranslucentworld		29
	ACTION_BAN, // r_shadowwireframe	6	30
	ACTION_BAN, // r_skybox			31
	ACTION_BAN, // r_visocclusion			32
	ACTION_BAN  // vcollide_wireframe	13	33
//	ACTION_KICK // cl_bobcycle			34
//	ACTION_KICK // mat_dxlevel			35
};

new Handle:g_HackCVarHandles[MAX_HACKCVAR+1] = {INVALID_HANDLE, ...};
new g_HackCheckOrder[MAX_HACKCVAR*2+2] = {0, ...};
new CVarI[MAXPLAYERS+1];

public Plugin:myinfo =
{
    name = "Kigen's Anti-Cheat", 
    author = "Kigen", 
    description = "The cheats stop here!", 
    version = PLUGIN_VERSION, 
    url = "http://www.kigenac.com/"
};

#if defined SOCKET_ENABLED
public bool:AskPluginLoad(Handle:myself, bool:late, String:error[], err_max)
{
	// Mark Native
	MarkNativeAsOptional("IRC_PrivMsg");
	return true;
}
#endif

public OnPluginStart()
{
	decl Handle:cvar, String:name[64], bool:comm, flags, Handle:t_ConVar, String:t_String[256], bool:isRPG;

	isRPG = false;
	CacheAuthArray = CreateArray(64);
	CacheReasonArray = CreateArray(256);
#if defined SOCKET_ENABLED
	AllowArray = CreateArray(64);
#endif
	IPBlockArray = CreateArray(64);

	if ( !HookEventEx("player_changename", EventNameChange) )
		LogError("Unable to hook player_changename");

	CreateConVar("kac_version", PLUGIN_VERSION, "KAC version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY);
	CVar_BlockNameCopy = CreateConVar("kac_block_namecopy", "0", "Blocks name copying and short names (name < 3)");
	CVar_IRCChan = CreateConVar("kac_irc_channel", "", "Channel to broadcast KAC messages on.  Set to nothing to disable.");
	CVar_BanCafe = CreateConVar("kac_block_cafe", "0", "Blocks all Cafe accounts from entering the server.");
	CVar_BlockMultiByte = CreateConVar("kac_block_multibyte_names", "0", "Blocks the usage of multibyte characters in a name.");
	CVar_Enable = CreateConVar("kac_enable", "1", "Enables/Disables KAC's cheat detection. (Does not affect other features.)");
	CVar_Cheats = FindConVar("sv_cheats");
	SetConVarInt(CVar_Cheats, 0, true);

	if ( CVar_BlockNameCopy == INVALID_HANDLE || CVar_IRCChan == INVALID_HANDLE
	  || CVar_BanCafe == INVALID_HANDLE || CVar_BlockMultiByte == INVALID_HANDLE || CVar_Cheats == INVALID_HANDLE )
		SetFailState("Unable to create/hook needed convars.");

	// Hook sv_cheats if server is not RPG.
	t_ConVar = FindConVar("cssrpg_enable");
	if ( t_ConVar != INVALID_HANDLE )
	{
		isRPG = true;
		CloseHandle(t_ConVar);
	}
	else
		HookConVarChange(CVar_Cheats, CheatsChange);
	HookConVarChange(CVar_Enable, EnableChange);
	
	// Hook replicated convars and cheat commands.
	cvar = FindFirstConCommand(name, sizeof(name), comm, flags);
	if (cvar == INVALID_HANDLE)
		SetFailState("Failed getting first command/convar.");
	do
	{
		if (!comm && (flags & FCVAR_REPLICATED) && ( !StrEqual(name, "sv_cheats") ) ) // RPG is funky.
		{
			t_ConVar = FindConVar(name);
			if ( t_ConVar == INVALID_HANDLE ) // wtf protection
				continue;
			GetConVarString(t_ConVar, t_String, sizeof(t_String));
			ReplicateConVar(t_ConVar, "", t_String); // Replicate it now for idoit protection.
			HookConVarChange(t_ConVar, ReplicateConVar);
		}
		else if (comm && (flags & FCVAR_CHEAT) && !isRPG)
			RegConsoleCmd(name, BlockCheat);
		
	} while (FindNextConCommand(cvar, name, sizeof(name), comm, flags));

	// Exploit
	RegConsoleCmd("changelevel", BlockExploit);
	RegConsoleCmd("ent_fire", BlockExploit); // Exploit that cheaters can do.

	// Cheat
	RegConsoleCmd("snd_restart", BlockCheat);

	// Crash
	RegConsoleCmd("ai_test_los", BlockCrash);
	RegConsoleCmd("sv_benchmark_force_start", BlockCrash);
	RegConsoleCmd("sv_findsoundname", BlockCrash);
	RegConsoleCmd("sv_soundemitter_filecheck", BlockCrash);
	RegConsoleCmd("sv_soundemitter_flush", BlockCrash);
	RegConsoleCmd("sv_soundscape_printdebuginfo", BlockCrash);

	// Spam Check
	RegConsoleCmd("timeleft", SpamCheck);
	RegConsoleCmd("nextmap", SpamCheck);

	// KAC commands
#if defined SOCKET_ENABLED
	RegAdminCmd("kac_allow", KACAllow, ADMFLAG_ROOT);
#endif
	RegAdminCmd("kac_allowip", KACAllowIP, ADMFLAG_ROOT);
	RegAdminCmd("kac_blockip", KACBlockIP, ADMFLAG_ROOT);

	for(new i=0;i<MAX_HACKCVAR;i++)
	{
		t_ConVar = FindConVar(g_HackCVars[i]);
		if ( t_ConVar != INVALID_HANDLE && (GetConVarFlags(t_ConVar) & FCVAR_REPLICATED) )
			g_HackCVarHandles[i] = t_ConVar;
	}

	// Stuff for if we're late.
	for(new i=1;i<MaxClients;i++)
	{
		if ( IsClientInGame(i) &&  !IsFakeClient(i) )
		{
			CVarI[i] = 0;
			PTimer[i] = CreateTimer(GetRandomFloat(10.5, 123.8), PeriodicTimer, i, TIMER_FLAG_NO_MAPCHANGE);
		}
	}

#if defined SOCKET_ENABLED
	CreateTimer(10.0, CheckVersion);
#endif
	CreateTimer(1.0, Clear, _, TIMER_REPEAT);
}

// SourceMod likes to crash the server if we don't kill all the timers before unload. - Kigen
public OnPluginEnd()
{
	for(new i=1;i<MaxClients;i++)
		KillTimers(i);
}

#if defined SOCKET_ENABLED
public Action:KACAllow(client, args)
{
	if ( args != 1 )
	{
		ReplyToCommand(client, "Usage: kac_allow <steam ID>");
		return Plugin_Handled;
	}

	new index, String:authString[64];
	GetCmdArg(1, authString, sizeof(authString));

	if ( strncmp(authString, "STEAM_0:", 8) != 0 )
	{
		ReplyToCommand(client, "You must use a properly formatted STEAM ID.");
		return Plugin_Handled;
	} 
	
	index = FindStringInArray(CacheAuthArray, authString);
	if ( index != -1 )
	{
		RemoveFromArray(CacheAuthArray, index);
		RemoveFromArray(CacheReasonArray, index);
	}
	index = FindStringInArray(AllowArray, authString);
	if ( index == -1 )
		PushArrayString(AllowArray, authString);
	ReplyToCommand(client, "Steam ID '%s' added to exceptions list.", authString);
	return Plugin_Handled;
}
#endif

public Action:KACBlockIP(client, args)
{
	if ( args != 1 )
	{
		ReplyToCommand(client, "Usage: kac_blockip <ip>");
		return Plugin_Handled;
	}
	
	new index, String:ip[64];
	GetCmdArg(1, ip, sizeof(ip));
	
	index = FindStringInArray(IPBlockArray, ip);
	if ( index == -1 )
	{
		PushArrayString(IPBlockArray, ip);
		ReplyToCommand(client, "IP '%s' added to block list.", ip);
	}
	else
		ReplyToCommand(client, "IP '%s' already in block list.", ip);
	return Plugin_Handled;
}

public Action:KACAllowIP(client, args)
{
	if ( args != 1 )
	{
		ReplyToCommand(client, "Usage: kac_allowip <ip>");
		return Plugin_Handled;
	}
	
	new index, String:ip[64];
	GetCmdArg(1, ip, sizeof(ip));
	
	index = FindStringInArray(IPBlockArray, ip);
	if ( index != -1 )
	{
		RemoveFromArray(IPBlockArray, index);
		ReplyToCommand(client, "IP '%s' removed from block list.", ip);
	}
	else
		ReplyToCommand(client, "IP '%s' not found.", ip);
	return Plugin_Handled;
}

#if defined SOCKET_ENABLED
public OnConfigsExecuted()
{
	decl Handle:t_ConVar;
	t_ConVar = FindConVar("irc_version");
	if ( t_ConVar != INVALID_HANDLE )
	{
		HasIRC = true;
		CloseHandle(t_ConVar);
	}
}
#endif

// This apparently gets called whenever the plugin is loaded.
public OnMapStart()
{
	CreateNewCheckOrder();
	ClearArray(CacheAuthArray);
	ClearArray(CacheReasonArray);
}

public OnMapEnd()
{
	for(new i=1;i<MaxClients;i++)
	{
		CVarI[i] = 0;
		PTimer[i] = INVALID_HANDLE;
	}
}

public bool:OnClientConnect(client, String:rejectmsg[], maxlen)
{
	if ( IsFakeClient(client) )
	{
		ConnState[client] = CS_BOT;
		return true;
	}

	decl String:ip[64], index;
	GetClientIP(client, ip, sizeof(ip));
	index = FindStringInArray(IPBlockArray, ip);
	if ( index != -1 )
	{
		Format(rejectmsg, maxlen, "You are not allowed to connect to this server.");
		return false;
	}

	decl String:name[64], len;
	GetClientName(client, name, 64);
	len = strlen(name);
	if ( len <= 0 )
	{
		Format(rejectmsg, maxlen, "Don't even think about it.");
		return false;
	}

	if ( GetConVarBool(CVar_BlockNameCopy) )
	{
		decl String:PlayerName[64], diff;
		if ( len <= 3 )
		{
			Format(rejectmsg, maxlen, "You need a longer name to play in this server.");
			return false;
		}
		for(new i=1;i<MaxClients;i++)
		{
			if (IsClientConnected(i) && client != i)
			{
				GetClientName(i, PlayerName, 64);
				diff = CmpString(PlayerName, name);
				if ( strlen(PlayerName) > 3 && diff < 2 )
				{
					decl String:authString[64], String:reason[255];
					if ( !GetClientAuthString(i, authString, 64) )
						strcopy(authString, 64, "STEAM_ID_PENDING");
					Format(reason, 255, "%s was blocked from entering the server for having a similar name to %s (%s). KAC ID:1 Diff: %d", name, PlayerName, authString, diff);
					KACLog(reason);
					PrintToAdmins(reason);
					Format(rejectmsg, maxlen, "You were blocked from entering the server for having a name similar to %s", PlayerName);
					// CreateTimer(0.1, KickThem, client);
					return false;
				}
			}
		}
	}
	if ( GetConVarBool(CVar_BlockMultiByte) )
	{
		for(new i=0;i<len;i++)
		{
			if ( IsCharMB(name[i]) )
			{
				decl String:reason[255];
				Format(reason, 255, "%s was blocked from entering the server for having a multibyte character (UTF) in their name.", name);
				KACLog(reason);
				PrintToAdmins(reason);
				Format(rejectmsg, maxlen, "You were blocked from entering this server for having a multibyte character (UTF) in your name");
				return false;
			}
		}
	}

	ConnState[client] = CS_CONNING;
	return true;
}

public Action:KickThem(Handle:timer, any:client)
{
	if ( IsClientConnected(client) && !IsClientInKickQueue(client) && !IsFakeClient(client) )
		KickClient(client, "%s", g_Reason[client]);
	return Plugin_Stop;
}

public OnClientAuthorized(client, const String:auth[])
{
	if ( IsFakeClient(client) )
		return;
	
#if defined SOCKET_ENABLED
	decl index;
	index = FindStringInArray(CacheAuthArray, auth);
	if ( index != -1 )
	{
		GetArrayString(CacheReasonArray, index, g_Reason[client], 512);
		CreateTimer(0.1, KickThem, client);
		return;
	}

	index = FindStringInArray(AllowArray, auth);
	if ( index != -1 )
		ConnState[client] = CS_VALIDATED;
	else
		ConnState[client] = CS_AUTHED;
#else
	ConnState[client] = CS_VALIDATED;
#endif

	decl  Handle:t_PTimer;
	t_PTimer = PTimer[client]; 

	CVarI[client] = 0;
	PTimer[client] = CreateTimer(GetRandomFloat(5.5, 17.8), PeriodicTimer, client, TIMER_FLAG_NO_MAPCHANGE);

	if ( t_PTimer != INVALID_HANDLE ) // Kill an already existing PTimer to prevent over-checking.
		CloseHandle(t_PTimer);
}

public OnClientDisconnect_Post(client)
{
	ConnState[client] = CS_NOTCONN;
	strcopy(g_Reason[client], 255, "");
	strcopy(g_Reason2[client], 255, "");
	KillTimers(client);
}

public Action:BlockCheat(client, args)
{
	if ( !client )
		return Plugin_Continue; // Server operation.
	new String:log[256], String:cmd[255], String:name[64], String:authString[64];
	GetCmdArgString(cmd, 255);
	GetClientName(client, name, 64);
	GetClientAuthString(client, authString, 64);
	FormatEx(log, 256, "Player %s (%s) tried to execute cheat command: %s", name, authString, cmd);
	KACLog(log);
	return Plugin_Stop;
}

public Action:BlockCrash(client, args)
{
	if ( !client )
		return Plugin_Stop; // Server operation.  Don't allow server to crash itself.
	if ( ConnState[client] == CS_BANNING )
		return Plugin_Stop;
	new String:log[256], String:cmd[255], String:name[64], String:authString[64];
	GetCmdArg(0, cmd, 255);
	GetClientName(client, name, 64);
	GetClientAuthString(client, authString, 64);
	FormatEx(log, 256, "%s (%s) attempted to crash this server with %s.", name, authString, cmd);
	KACLog(log);
	KACBan(client, 0, "Attempting to crash server", "You fail, goodbye.");
	return Plugin_Stop;
}

public Action:BlockExploit(client, args)
{
	if ( !client )
		return Plugin_Continue; // Server operation.
	if ( ConnState[client] == CS_BANNING )
		return Plugin_Stop;
	new String:log[256], String:cmd[255], String:cmd2[255], String:name[64], String:authString[64];
	GetCmdArg(0, cmd, 255);
	GetCmdArgString(cmd2, 255);
	GetClientName(client, name, 64);
	GetClientAuthString(client, authString, 64);
	FormatEx(log, 256, "%s (%s) attempted to exploit this server with: %s %s.", name, authString, cmd, cmd2);
	KACLog(log);
	KACBan(client, 0, "Attempting to exploit server", "You fail, goodbye.");
	return Plugin_Stop;
}

public Action:SpamCheck(client, args)
{
	if ( !client )
		return Plugin_Continue;
	if ( ConnState[client] == CS_BANNING )
		return Plugin_Stop;
	count[client]++;
	if ( count[client] > 10 )
	{
		new String:log[256], String:cmd[255], String:cmd2[255], String:name[64], String:authString[64];
		GetCmdArg(0, cmd, 255);
		GetCmdArgString(cmd2, 255);
		GetClientName(client, name, 64);
		GetClientAuthString(client, authString, 64);
		FormatEx(log, 256, "%s (%s) attempted to spam crash this server with: %s %s.", name, authString, cmd, cmd2);
		KACLog(log);
		KACBan(client, 0, "Attempting to spam crash server", "You fail, goodbye.");
		return Plugin_Stop;
	}
	return Plugin_Continue;
}

public Action:Clear(Handle:timer, any:arg)
{
	for(new i=1;i<MaxClients;i++)
		count[i] = 0;
	return Plugin_Continue;
}

public Action:PeriodicTimer(Handle:timer, any:client)
{
	if ( PTimer[client] == INVALID_HANDLE )
		return Plugin_Stop;
	PTimer[client] = INVALID_HANDLE;
	if ( !IsClientConnected(client) || IsClientInKickQueue(client) )
		return Plugin_Stop;

	decl String:name[64];
	if ( GetClientName(client, name, 64) && strlen(name) < 1 )
	{
		decl String:authString[64], String:reason[255];
		GetClientAuthString(client, authString, 64);
		FormatEx(reason, 255, "%s (%s) was banned for attempting to name hack. KAC ID:2", name, authString);
		KACLog(reason);
		PrintToAdmins(reason);
		KACBan(client, 0, "Banned for name exploit. KAC ID:2", "You have been banned for name exploiting.");
		return Plugin_Stop;
	}
	if ( CVarI[client] > MAX_HACKCVAR*2 )
		CVarI[client] = 0;
	if ( Enabled )
		QueryClientConVar(client, g_HackCVars[g_HackCheckOrder[CVarI[client]]], ClientCVarCallback, client);
	else
		PTimer[client] = CreateTimer(GetRandomFloat(11.5, 25.8), PeriodicTimer, client, TIMER_FLAG_NO_MAPCHANGE);
	return Plugin_Stop;
}

#if defined SOCKET_ENABLED
public Action:CheckVersion(Handle:timer, any:we)
{
	new Handle:socket = SocketCreate(SOCKET_TCP, OnSockErrVer);
	SocketConnect(socket, OnSockConnVer, OnSockRecvVer, OnSockDiscVer, "kigen.ath.cx", 9652);
}

public Action:Warn(Handle:timer, any:we)
{
	PrintToAdmins("Your KAC version is out-of-date! You need to update!");
	PrintToAdmins("KAC is disabled.");
}

public OnSockDiscVer(Handle:socket, any:we)
{
	CreateTimer(0.1, TKills, socket);
	if ( !Checked )
		CreateTimer(60.0, CheckVersion);
}

public OnSockErrVer(Handle:socket, const errorType, const errorNum, any:we)
{
	CreateTimer(0.1, TKills, socket);
	if ( !Checked )
		CreateTimer(60.0, CheckVersion);
}

public OnSockConnVer(Handle:socket, any:we)
{
	if ( !SocketIsConnected(socket) )
	{
		CreateTimer(0.1, TKills, socket);
		CreateTimer(60.0, CheckVersion);
		return;
	}
	new String:version[15];
	Format(version, sizeof(version), "_VERSION %s", PLUGIN_VERSION);
	SocketSend(socket, version, strlen(version)+1); // Send that \0!
	return;
}

public OnSockRecvVer(Handle:socket, String:data[], const size, any:we)
{
	Checked = true;
	if ( StrEqual(data, "_UPTODATE") )
	{
		CreateTimer(10.0, CheckPlayers, INVALID_HANDLE, TIMER_REPEAT);
		// PrintToAdmins("Your KAC version is up-to-date.");
	} 
	else if ( StrEqual(data, "_OLDFINE") )
	{
		CreateTimer(20.0, CheckPlayers, INVALID_HANDLE, TIMER_REPEAT);
		PrintToAdmins("Your KAC version is out-to-date.  You should update.");
	}
	else if ( StrEqual(data, "_OLDBAD") )
	{
		SetConVarBool(CVar_Enable, false);
		Locked = true;
		Enabled = false;
		CreateTimer(60.0, Warn, _, TIMER_REPEAT);
	}
	else
		Checked = false;
}

public Action:CheckPlayers(Handle:timer, any:dsocket)
{
	if ( TSocket != INVALID_HANDLE )
	{
		CreateTimer(0.1, TKills, TSocket);
		if ( SocketIsConnected(TSocket) )
			SocketDisconnect(TSocket);
		return Plugin_Continue;
	}
 	for(new client=1;client<MaxClients;client++)
	{
		if ( ConnState[client] != CS_AUTHED )
			continue;
	
		new Handle:socket = SocketCreate(SOCKET_TCP, OnSocketError);
		if ( socket == INVALID_HANDLE )
		{
			LogError("Unable to create socket.");
			return Plugin_Continue;
		}
		TSocket = socket;
		SocketSetArg(socket, client);
		SocketConnect(socket, OnSocketConnect, OnSocketReceive, OnSocketDisconnect, "kigenac.ath.cx", 9652);
		return Plugin_Continue;
	}
	return Plugin_Continue;
}

public OnSocketConnect(Handle:socket, any:client)
{
	if ( !SocketIsConnected(socket) )
	{
		CreateTimer(0.1, TKills, socket);
		return;
	}
	decl String:authString[64];
	if ( ConnState[client] != CS_AUTHED || !GetClientAuthString(client, authString, 64) )
	{
		SocketDisconnect(socket);
		CreateTimer(0.1, TKills, socket);
		return;
	}
	SocketSend(socket, authString, strlen(authString)+1); // Send that \0! - Kigen
	return;
}

public Action:TKills(Handle:timer, any:socket)
{
	if ( socket == TSocket )
		TSocket = INVALID_HANDLE;
	if ( socket != INVALID_HANDLE )
		CloseHandle(socket);
	return Plugin_Stop;
}

public OnSocketDisconnect(Handle:socket, any:client)
{
	if ( socket == INVALID_HANDLE )
		return;

	if ( SocketIsConnected(socket) ) // Why it would be like this is beyond me.  But there isn't threading safety.
		SocketDisconnect(socket);

	CreateTimer(0.1, TKills, socket);
	return;
}

public OnSocketReceive(Handle:socket, String:data[], const size, any:client) 
{
	if ( socket == INVALID_HANDLE || ConnState[client] != CS_AUTHED )
		return;

	decl String:authString[64], String:name[64], String:buff[256];
	GetClientAuthString(client, authString, 64);
	GetClientName(client, name, 64);
	ConnState[client] = CS_VALIDATED;
	if ( StrEqual(data, "_BAN") )
	{
		FormatEx(buff, 256, "%s (%s) is on the KAC global banlist.", name, authString);
		PrintToAdmins(buff);
		KACLog(buff);
		strcopy(g_Reason[client], 512, "You have been banned from all KAC secured servers for a cheating infraction.  See http://www.kigenac.com/ for more information");
		PushArrayString(CacheAuthArray, authString);
		PushArrayString(CacheReasonArray, g_Reason[client]);
		CreateTimer(0.1, KickThem, client);
	} 
	else if ( StrEqual(data, "_CAFE") )
	{
		if ( !GetConVarBool(CVar_BanCafe) )
			return;
		FormatEx(buff, 256, "%s (%s) is on the KAC Cafe List.", name, authString);
		PrintToAdmins(buff);
		KACLog(buff);
		strcopy(g_Reason[client], 512, "This KAC protected server does not allow Cafe Accounts.  See http://www.kigenac.com/ for more information and possible whitelisting.");
		PushArrayString(CacheAuthArray, authString);
		PushArrayString(CacheReasonArray, g_Reason[client]);
		CreateTimer(0.1, KickThem, client);
	}
	else if ( StrEqual(data, "_OK") )
	{
		// sigh here.
	}
	else
	{
		ConnState[client] = CS_AUTHED;
		FormatEx(buff, 256, "%s (%s) got unknown reply from KAC master server. Data: %s", name, authString, data);
		PrintToAdmins(buff);
		KACLog(buff);
	}
}

public OnSocketError(Handle:socket, const errorType, const errorNum, any:client)
{
	if ( socket == INVALID_HANDLE )
		return;

	// LogError("Socket Error: eT: %d, eN, %d, c, %d", errorType, errorNum, client);
	CreateTimer(0.1, TKills, socket);
}
#endif

public Action:TimedBan(Handle:timer, any:userid)
{
	new client = GetClientOfUserId(userid);
	if (!client || !IsClientConnected(client) || IsClientInKickQueue(client))
		return Plugin_Stop;

	decl String:name[64];
	GetClientName(client, name, 64);
	PrintToChatAll("%s was banned by KAC for a cheating infraction.", name);
	PrintToAdmins(g_Reason2[client]);
	KACBan(client, 0, g_Reason[client], "You have been banned for a cheating infraction.");
	CreateTimer(GetRandomFloat(4.5, 30.4), TimedBan2, userid, TIMER_FLAG_NO_MAPCHANGE); // Make sure they're gone.
	return Plugin_Stop;
}

public Action:TimedBan2(Handle:timer, any:userid)
{
	new client = GetClientOfUserId(userid);
	if (!client || !IsClientConnected(client) || IsClientInKickQueue(client))
		return Plugin_Stop;

	BanClient(client, 0, BANFLAG_AUTO, g_Reason2[client], "You have been banned for a cheating infraction.");
	CreateTimer(GetRandomFloat(4.5, 30.4), TimedBan2, userid, TIMER_FLAG_NO_MAPCHANGE);
	return Plugin_Stop;
}

public CheatsChange(Handle:convar, const String:oldValue[], const String:newValue[])
{
	if ( Enabled && StringToInt(newValue) != 0 )
		SetConVarInt(convar, 0, true, false); // Force sv_cheats off at all times.
}

public EnableChange(Handle:convar, const String:oldValue[], const String:newValue[])
{
#if defined SOCKET_ENABLED
	if ( Locked )
	{
		if ( GetConVarBool(convar) != Enabled )
			SetConVarBool(convar, Enabled);
		return;
	}
#endif
	if ( GetConVarBool(convar) )
	{
		if ( Enabled )
			return;
		Enabled = true;
		PrintToAdmins("KAC has been enabled.");
		SetConVarInt(CVar_Cheats, 0, true);
	}
	else
	{
		if ( !Enabled )
			return;
		Enabled = false;
		PrintToAdmins("KAC has been disabled.");
	}
}

// Base Fun Votes (sm_votegravity) and other things like it don't properly replicated values like they should. -.-
public ReplicateConVar(Handle:convar, String:oldValue[], String:newValue[])
{
	for(new i=1;i<MaxClients;i++)
		if ( IsClientConnected(i) && !IsFakeClient(i) )
			SendConVarValue(i, convar, newValue);
}

// param 2 (client) is always passing the client that returned the cookie, does not pass anything else
public ClientCVarCallback(QueryCookie:cookie, client, ConVarQueryResult:result, const String:cvarName[], const String:cvarValue[])
{
	if ( !client || !IsClientConnected(client) || IsFakeClient(client) )
		return;
	decl String:name[64], Handle:cvar, cvarid, bool:continuechecks, String:authString[64], ComparisonID, CompTest, Float:clientValue, Float:serverValue;
	ComparisonID = 0;
	continuechecks = true;
	cvarid = g_HackCheckOrder[CVarI[client]];
	GetClientName(client, name, 64);
	if ( strcmp(g_HackCVars[cvarid], cvarName) != 0 ) // Lets go ahead and make use of this call.
	{
		decl String:buff[256];
		GetClientAuthString(client, authString, 64);
		FormatEx(buff, 256, "Cvar out of sync: %s (%s) on %s (%s) is %s", g_HackCVars[cvarid], cvarName, name, authString, cvarValue);
		KACLog(buff);
		for(new i=0;i<MAX_HACKCVAR;i++)
		{
			if ( StrEqual(g_HackCVars[i], cvarName) )
			{
				cvarid = i;
				continuechecks = false;
				break;
			}
		}
		if ( continuechecks ) // CVar not found, weird.
			return;
	}
	cvar = g_HackCVarHandles[cvarid];
	if ( Enabled )
	{
		CompTest = g_HackCVarsComp[cvarid];
		if ( cvar != INVALID_HANDLE )
			serverValue = GetConVarFloat(cvar);
		else
			serverValue = g_HackCVarValues[cvarid];
		clientValue = StringToFloat(cvarValue);
		if ( result == ConVarQuery_Okay )
		{
			// if ( ( CompTest == COMP_EQUAL && clientValue != serverValue )
			//   || ( CompTest == COMP_GREATER &&  clientValue < serverValue )
			//   || ( CompTest == COMP_LESS && clientValue > serverValue ) )
			// 	ComparisonID = 5;
			switch (CompTest) // This is actually more efficent. - Kigen
			{
				case COMP_EQUAL:
				{
					if ( clientValue != serverValue )
						ComparisonID = 5;
					// break;
				}
				case COMP_LESS:
				{
					if ( clientValue > serverValue )
						ComparisonID = 5;
					// break;
				}
				case COMP_GREATER:
				{
					if ( clientValue < serverValue )
						ComparisonID = 5;
					// break;
				}
			}
		}
		else
			ComparisonID = 4;
	}
	if ( ComparisonID )
	{
		if ( ComparisonID == 5 && cvar == INVALID_HANDLE )
			ComparisonID++;
		decl String:reason[255], String:buff[256];
		GetClientAuthString(client, authString, 64);
		if ( ComparisonID == 4 )
			FormatEx(buff, sizeof(buff), "Bad CVar response! Client %s (%s) failed to reply properly to convar query!  %s (%s) set to %s", name, authString, cvarName, g_HackCVars[cvarid], cvarValue);
		else
			FormatEx(buff, sizeof(buff), "Bad CVar response! %s (%s) has %s (%s) set to %s", name, authString, cvarName, g_HackCVars[cvarid], cvarValue);
		KACLog(buff);
		if ( g_HackCVarsAction[cvarid] == ACTION_BAN || ComparisonID == 4 )
		{
			FormatEx(reason, 255, "%s (%s) was banned for cheating. KAC ID:%d.%d", name, authString, ComparisonID, cvarid);
			KACLog(reason);
			FormatEx(g_Reason[client], 512, "Cheating. KAC ID:%d.%d", ComparisonID, cvarid);
			CreateTimer(GetRandomFloat(2.5, 11.4), TimedBan, GetClientUserId(client), TIMER_FLAG_NO_MAPCHANGE);
		}
		else if ( g_HackCVarsAction[cvarid] == ACTION_KICK )
		{
			decl String:value[64];
			if ( cvar != INVALID_HANDLE )
				GetConVarString(cvar, value, 64);
			else
				FloatToString(g_HackCVarValues[cvarid], value, 64);
			FormatEx(g_Reason[client], 512, "The cvar %s needs to be %s %s.", g_HackCVars[cvarid], g_CompareString[CompTest], value);
			FormatEx(reason, 255, "%s (%s) was kicked for having a bad value on %s (had %s).", name, authString, g_HackCVars[cvarid], cvarValue);
			KACLog(reason);
			CreateTimer(0.1, KickThem, client);
		}
		strcopy(g_Reason2[client], 255, reason);
	}
	if ( continuechecks || PTimer[client] == INVALID_HANDLE )
	{
		if ( continuechecks )
			CVarI[client]++;
		if ( CVarI[client] > MAX_HACKCVAR*2 )
		{
			CVarI[client] = 0;
			PTimer[client] = CreateTimer(GetRandomFloat(43.5, 65.8), PeriodicTimer, client, TIMER_FLAG_NO_MAPCHANGE);
			return;
		}
		PTimer[client] = CreateTimer(GetRandomFloat(2.5, 7.8), PeriodicTimer, client, TIMER_FLAG_NO_MAPCHANGE);
	}
}

public EventNameChange(Handle:event, const String:name[], bool:dontBroadcast)
{
	new client = GetClientOfUserId(GetEventInt(event, "userid"));
	if ( !client || !IsClientConnected(client) || IsClientInKickQueue(client) || IsFakeClient(client) )
		return;

	decl String:oldName[64], String:newName[64], String:PlayerName[64], String:authString[64];
	GetEventString(event, "oldname", oldName, sizeof(oldName));
	GetEventString(event, "newname", newName, sizeof(newName));
	if ( !GetClientAuthString(client, authString, 64) )
		strcopy(authString, 64, "STEAM_ID_PENDING");
	if ( strlen(newName) < 1 )
	{
		decl String:reason[255]; // String:authString[64], 
		// GetClientAuthString(client, authString, 64);
		FormatEx(reason, sizeof(reason), "%s (%s) was banned for attempting to name hack. KAC ID:2", oldName, authString);
		KACLog(reason);
		KACBan(client, 0, "Banned for name exploit. KAC ID:2", "You have been banned for name exploiting.");
		PrintToAdmins(reason);
		return;
	}

	if ( GetConVarBool(CVar_BlockMultiByte) )
	{
		decl len;
		len = strlen(newName);
		for(new i=0;i<len;i++)
		{
			if ( IsCharMB(newName[i]) )
			{
				decl String:reason[255];
				FormatEx(reason, 255, "%s was kicked from the server for having a multibyte character (UTF) in their name.", name);
				KACLog(reason);
				PrintToAdmins(reason);
				strcopy(g_Reason[client], 512, "You were kicked from this server for having a multibyte character (UTF) in your name.");
				CreateTimer(0.1, KickThem, client);
				return;
			}
		}
	}

	if ( !GetConVarBool(CVar_BlockNameCopy) )
		return;

	// Why the kick/ban?  Why not block?  Answer: Cheats mess up the way things are handled, thus not always promising that a return Plugin_Handled will do the job.
	if ( strlen(newName) <= 3 )
	{
		strcopy(g_Reason[client], 512, "Your name is too short, please come back with a longer name");
		CreateTimer(0.1, KickThem, client);
	}
	else
	{
		for(new i=1;i<MaxClients;i++)
		{
			if (IsClientConnected(i) && client != i)
			{
				decl diff;
				GetClientName(i, PlayerName, 64);
				diff = CmpString(PlayerName, newName);
				if ( strlen(PlayerName) > 3 && diff < 2 )
				{
					decl String:authString2[64], String:reason[255];
					if ( !GetClientAuthString(i, authString2, 64) )
						strcopy(authString2, 64, "STEAM_ID_PENDING");
					FormatEx(reason, 255, "%s (%s) was banned for attempting to name copy on %s (%s). KAC ID:1 Diff: %d NewName: %s", oldName, authString, PlayerName, authString2, diff, newName);
					KACLog(reason);
					PrintToAdmins(reason);
					KACBan(client, 5, "Banned for name copying. KAC ID:1", "You have been banned for name copying.");
					return;
				}
			}
		}
	}
}


/* Private KAC functions */

/*
 * CreateNewCheckOrder()
 * Description: Creates a new convar checking order.  Used to prevent guessing when a check on a specific convar is going to happen.
 */
CreateNewCheckOrder()
{
	new temp, bool:done = false, test;
	for(new i=0;i<MAX_HACKCVAR+1;i++)
	{
		done = false;
		while (!done)
		{
			if ( i < 4 ) // 0 1 2 3
				temp = GetRandomInt(13, 16); // Check sv_cheats and sv_consistency first.  They're common to be on the blatant cheaters.
			else
				temp = GetRandomInt(0, MAX_HACKCVAR);
			done = true;
			for(new t=0;t<i;t++)
				if ( g_HackCheckOrder[t] == temp )
					done = false;
		}
		g_HackCheckOrder[i] = temp;
	}
	test = MAX_HACKCVAR*2+1;
	for(new i=MAX_HACKCVAR+1;i<test;i++)
	{
		done = false;
		while (!done)
		{
			temp = GetRandomInt(0, MAX_HACKCVAR);
			done = true;
			for(new t=MAX_HACKCVAR+1;t<i;t++)
				if ( g_HackCheckOrder[t] == temp )
					done = false;
		}
		g_HackCheckOrder[i] = temp;
	}
}

/*
 * KACLog(String:log[])
 * log: String to log.
 * Description: Logs actions to KAC log and SourceMod logs.
 */
KACLog(String:log[])
{
	LogMessage("%s", log);
	decl String:path[256];
	BuildPath(Path_SM, path, 256, "logs/KAC.log");
	LogToFileEx(path, "%s", log); // Use Ex since we should be the only ones logging.
}

KACBan(client, time, String:IReason[], String:EReason[])
{
	if ( ConnState[client] == CS_BANNING || !IsClientConnected(client) || IsFakeClient(client) || IsClientInKickQueue(client) )
		return;
	ConnState[client] = CS_BANNING;
	decl String:authString[64], Handle:t_ConVar, bool:test;
	test = GetClientAuthString(client, authString, 64);
	if ( !test || StrEqual(authString, "STEAM_ID_LAN") )
	{
		BanClient(client, time, BANFLAG_IP, IReason, EReason);
		return;
	}
	else
	{
		t_ConVar = FindConVar("sb_version");
		if ( t_ConVar != INVALID_HANDLE )
		{
			ServerCommand("sm_ban #%d %d \"%s\"", GetClientUserId(client), time, IReason);
			CloseHandle(t_ConVar);
			return;
		}
		t_ConVar = FindConVar("mysql_bans_version");
		if ( t_ConVar != INVALID_HANDLE )
		{
			ServerCommand("mysql_ban #%d %d %s", GetClientUserId(client), time, IReason);
			CloseHandle(t_ConVar);
			return;
		}
		BanClient(client, time, BANFLAG_AUTO, IReason, EReason);
	}
	return;
	
}

/*
 * PrintToAdmins(String:text[])
 * text: String to display to all admins.
 * Description: Prints text to all admins on the server.
 */
PrintToAdmins(String:text[])
{
	for(new i=1;i<MaxClients;i++)
		if ( IsClientInGame(i) && GetUserAdmin(i) != INVALID_ADMIN_ID )
			PrintToChat(i, "KAC: %s", text);
#if defined SOCKET_ENABLED
	if ( HasIRC )
	{
		decl String:ircChan[64];
		GetConVarString(CVar_IRCChan, ircChan, 64);
		if ( strlen(ircChan) > 0 )
			IRC_PrivMsg(ircChan, "KAC: %s", text);
	}
#endif
}

/*
 * CmpString(String:str1[], String:str2[])
 * str1: First String to Compare.
 * str2: Second String to Compare.
 * Returns difference.
 * Counts the number of differences between two strings.
 */
CmpString(String:str1[], String:str2[])
{
	decl len, diff;
	diff = 0;
	len = strlen(str1);
	if ( len > strlen(str2) )
		len = strlen(str2);

	for(new i=0;i<len;i++)
	{
		if ( str1[i] != str2[i] )
			diff++;
	}
	return diff;
}

/*
 * KillTimers(client)
 * client: Client Index number.
 * Description: Kills all active KAC timers on client.
 */
KillTimers(client)
{
	decl Handle:t_PTimer;
	t_PTimer = PTimer[client];
	PTimer[client] = INVALID_HANDLE;

	if ( t_PTimer != INVALID_HANDLE )
		CloseHandle(t_PTimer);
}

Последний раз редактировалось [»Twilight«] 28.07.2009, 16:16, всего редактировалось 1 раз.
If you are the Receiver of Wisdom, you will understand my words...
Изображение

Ответить Вложения 2