C#:
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("PlayerAntiHack", "TimMorse", "0.0.1")]
public class PlayerAntiHack : RustPlugin
{
[PluginReference] Plugin VKBot;
#region Config
private static ConfigData config;
private class ConfigData
{
public class VKBotLog
{
[JsonProperty("Включить логирование в беседу")]
public bool Enabled;
[JsonProperty("ID беседы")]
public string ChatID;
}
[JsonProperty("VKBot logger")]
public VKBotLog vKBotLog;
}
private ConfigData GetDefaultConfig()
{
return new ConfigData
{
vKBotLog = new ConfigData.VKBotLog
{
Enabled = true,
ChatID = "2"
}
};
}
protected override void LoadDefaultConfig()
{
PrintWarning("Файл конфигурации поврежден (или не существует), создаем новый...");
config = GetDefaultConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<ConfigData>();
if (config == null)
LoadDefaultConfig();
}
catch
{
LoadDefaultConfig();
}
SaveConfig();
}
#endregion
#region Variables
private class PlayerInfo
{
public double SpeedGatherLastTime;
public int SpeedGatherDetections;
}
Dictionary<ulong, PlayerInfo> playerInfo = new Dictionary<ulong, PlayerInfo>();
static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0);
static double CurrentTimeSec()
{
return DateTime.UtcNow.Subtract(epoch).TotalSeconds;
}
#endregion
#region Hooks
[HookMethod("OnPlayerInit")]
private void OnPlayerInit(BasePlayer player)
{
if (!playerInfo.ContainsKey(player.userID))
{
playerInfo.Add(player.userID, new PlayerInfo()
{
SpeedGatherLastTime = CurrentTimeSec(),
SpeedGatherDetections = 0,
});
}
}
[HookMethod("OnPlayerDisconnected")]
private void OnPlayerDisconnected(BasePlayer player)
{
if (playerInfo.ContainsKey(player.userID))
{
playerInfo.Remove(player.userID);
}
}
[HookMethod("Unload")]
private void Unload()
{
playerInfo.Clear();
}
[HookMethod("OnServerInitialized")]
void OnServerInitialized()
{
foreach(var player in BasePlayer.activePlayerList) OnPlayerInit(player);
}
[HookMethod("OnPlayerHealthChange")]
object OnPlayerHealthChange(BasePlayer player, float oldValue, float newValue)
{
if (player.health.ToString().Contains("NaN") || player.health > 100)
{
Log($"[GODMOD] {player.displayName} ({player.userID}): был обнаружен GodMod", 2);
ConsoleSystem.Run.Server.Normal($"player.ban {player.net.connection.ipaddress.Split(':')[0]} \"GodMod\"");
player.Kill(global::BaseNetworkable.DestroyMode.Gib);
player.Kick("GodMod detected");
}
return null;
}
[HookMethod("OnPlayerAntiHackKicked")]
private void OnPlayerAntiHackKicked(BasePlayer player, string reason)
{
Log($"[ANTIHACK] {player.displayName} ({player.userID}): был кикнут за {reason}", 1);
ConsoleSystem.Run.Server.Normal($"player.ban {player.userID} \"{reason}\"");
}
[HookMethod("OnPlayerAttack")]
private void OnPlayerAttack(BasePlayer attacker, HitInfo info)
{
BasePlayer target = info?.HitEntity as BasePlayer;
if (target != null)
{
string weapon = info.Weapon.ShortPrefabName.Replace(".entity", "");
string damage = info.damageTypes.Total() > 0 ? $"{info.damageTypes.Total()}" : "";
var distance = Vector3.Distance(attacker.transform.position, target.transform.position);
attacker.SendConsoleCommand($"echo " +
$"<color=green>[Урон игроку]</color> " +
$"<color=silver>{attacker.displayName} -> {target.displayName}</color> " +
$"<color=orange>({weapon})</color> " +
$"<color=white>({info.boneName})</color> {distance}m.{damage}");
target.SendConsoleCommand($"echo " +
$"<color=red>[Урон от игрока]</color> " +
$"<color=silver>{target.displayName} <- {attacker.displayName}</color> " +
$"<color=orange>({weapon})</color> " +
$"<color=white>({info.boneName})</color> {distance}m.{damage}");
return;
}
if (attacker == null || info.Weapon == null || info.Weapon.GetComponent<BaseMelee>() == null) return;
BaseMelee component = info.Weapon.GetComponent<BaseMelee>();
double currentTime = CurrentTimeSec();
if (currentTime - playerInfo[attacker.userID].SpeedGatherLastTime < component.repeatDelay - 0.2)
{
info.damageTypes = new DamageTypeList();
info.HitEntity = null;
if (playerInfo[attacker.userID].SpeedGatherDetections > 2)
{
int ping = Network.Net.sv.GetAveragePing(attacker.net.connection);
Log($"[SPEED GATHER] {attacker.displayName} ({attacker.userID}) PING({ping}): возможно использует Speed Gather", 1);
if(ping < 200) ConsoleSystem.Run.Server.Normal($"player.ban {attacker.net.connection.ipaddress.Split(':')[0]} \"Speed Gather\"");
}
playerInfo[attacker.userID].SpeedGatherDetections += 1;
playerInfo[attacker.userID].SpeedGatherLastTime = currentTime;
}
else
{
playerInfo[attacker.userID].SpeedGatherDetections = 0;
playerInfo[attacker.userID].SpeedGatherLastTime = currentTime;
}
}
#endregion
#region Helper
private void Log(string message, int type = 0)
{
switch (type)
{
case 0:
Puts(message);
break;
case 1:
PrintWarning(message);
break;
case 2:
PrintError(message);
break;
}
if (config.vKBotLog.Enabled && type > 0) SendChatMessage(config.vKBotLog.ChatID, message);
ConVar.Server.Log("player_antihack_log.txt", message);
}
private void SendChatMessage(string chatid, string msg) => VKBot.CallHook("SendChatMessage", chatid, msg);
#endregion
}
}