C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Rust;
using Oxide.Core;
using System.Collections.Generic;
using UnityEngine;
using System.Text.RegularExpressions;
using ConVar;
using Oxide.Core.Libraries.Covalence;
using System;
using Object = System.Object;
using Oxide.Core.Libraries;
using System.Text;
using Oxide.Core.Plugins;
using Oxide.Core.Database;
using Newtonsoft.Json.Linq;
using System.Linq;
using Newtonsoft.Json;
namespace Oxide.Plugins {
[Info("IQBanSystem", "Mercury", "1.12.19")]
[Description("IQBanSystem")]
public class IQBanSystem : RustPlugin {
private String SQL_Query_CreatedDatabase() {
return $"CREATE TABLE IF NOT EXISTS `{config.mysqlConnected.dbTableName}`(" + "`id` INT(11) NOT NULL AUTO_INCREMENT," + "`steamid` VARCHAR(17) NOT NULL," + "`ipAdress` VARCHAR(30) NOT NULL," + "`permanent` VARCHAR(1) NOT NULL," + "`timeUnbanned` VARCHAR(70) NOT NULL," + "`reason` VARCHAR(70) NOT NULL," + "`serverName` VARCHAR(70) NOT NULL," + "`serverAdress` VARCHAR(70) NOT NULL," + "`owner` VARCHAR(70) NOT NULL," + "`nameHistory` TEXT NOT NULL," + "`ipHistory` TEXT NOT NULL," + "`steamIdHistory` TEXT NOT NULL," + " PRIMARY KEY(`id`))" + " CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;";
}
object OnTeamKick(RelationshipManager.PlayerTeam team, BasePlayer player, UInt64 target) {
LeaveTeamPlayer(target);
return null;
}
[ChatCommand("ban")]
private void ChatBanCommand(BasePlayer ownerCommand, String cmd, String[] arg) => BanCommand(ownerCommand, arg);
/// <summary>
/// - Корректировка работы с хуком : OnUserConnected
///
/// </summary>
private static IQBanSystem _;
private class TeamLocalMemory {
public Double firstJoin;
public Double lastRemoved;
}
void OnTeamCreated(BasePlayer player, RelationshipManager.PlayerTeam team) => TeamAdded(team);
public class Footer {
public String text {
get;
set;
}
public String icon_url {
get;
set;
}
public String proxy_icon_url {
get;
set;
}
public Footer(String text, String icon_url, String proxy_icon_url) {
this.text = text;
this.icon_url = icon_url;
this.proxy_icon_url = proxy_icon_url;
}
}
protected override void SaveConfig() => Config.WriteObject(config);
private class ProcessCheckVPN {
public Int32 detectedVpn;
public Boolean isCompleteProxyCheck;
public Boolean isCompleteVpnApi;
public Boolean isCompleteIPHub;
}
private List<String> ipListGods = new List<String>();
private Timer timerCheckVpn;
private Dictionary<Vector3, String> GetAuthCupboardPlayer(UInt64 playerID) {
Dictionary<Vector3, String> resultData = new Dictionary<Vector3, String>();
List<BaseNetworkable> listEntity = Facepunch.Pool.Get<List<BaseNetworkable>>();
listEntity.AddRange(BaseNetworkable.serverEntities.entityList.Get().Values.Where(x => x.ShortPrefabName.Contains("cupboard") && x is BuildingPrivlidge));
foreach (BaseNetworkable cupboards in listEntity) {
BuildingPrivlidge cupboard = cupboards as BuildingPrivlidge;
if (cupboard == null) continue;
if (cupboard.IsAuthed(playerID) || cupboard.OwnerID == playerID) resultData.Add(cupboard.transform.position, MapHelper.PositionToString(cupboard.transform.position));
}
Facepunch.Pool.FreeUnmanaged(ref listEntity);
return resultData;
}
private void OnServerInitialized() {
permission.RegisterPermission(permissionsBan, this);
permission.RegisterPermission(permissionsUnBan, this);
permission.RegisterPermission(permissionsKick, this);
permission.RegisterPermission(permissionsIgnoreVPN, this);
permission.RegisterPermission(permissionIgnoreBan, this);
Configuration.BannedSetting.DestroyedAfterBannedSetting configDestroyed = config.bannedSetting.destroyedAfterBannedSetting;
Boolean isMarkerUse = configDestroyed.mapMarkerDestroyedObjectSetting.useMapMarkerDestroyedObjectPlayer && config.generalSetting.additionalSetting.useAlertAllPlayers && configDestroyed.useAlertGridHomes && configDestroyed.useDestroyObjects;
if (isMarkerUse) timerUpdateMarkers = timer.Every(60f, MarkerUpdate);
useIpHub = !String.IsNullOrWhiteSpace(config.vpnSetting.iPHubToken);
useVpnApi = !String.IsNullOrWhiteSpace(config.vpnSetting.vpnApiIoToken);
useProxyCheck = !String.IsNullOrWhiteSpace(config.vpnSetting.proxyCheckIo);
maxDetectedVpn = (config.vpnSetting.countDetectedToKickInVPN <= 0 ? 1 : config.vpnSetting.countDetectedToKickInVPN);
if(RustApp) if (RustApp.Version < new VersionNumber(1, 9, 2)) {
PrintWarning(LanguageEn ? "" : "У вас установлен RustApp версии ниже 1.9.2 - плагины не смогут взаимодействовать! Обновите плагин RustApp..");
}
}
private const String VendingPrefab = "assets/prefabs/deployable/vendingmachine/vending_mapmarker.prefab";
private Boolean TryParseTimeSpan(String source, out Double timeSpan) {
Int32 seconds = 0, minutes = 0, hours = 0, days = 0;
MatchCollection matches = Regex.Matches(source, @"(\d+)([smhd])", RegexOptions.IgnoreCase);
foreach (Match match in matches) {
Int32 value = int.Parse(match.Groups[1].Value);
Char unit = match.Groups[2].Value.ToLower()[0];
switch (unit) {
case 's' : seconds += value;
break;
case 'm' : minutes += value;
break;
case 'h' : hours += value;
break;
case 'd' : days += value;
break;
}
}
source = Regex.Replace(source, @"(\d+)[smhd]", String.Empty, RegexOptions.IgnoreCase);
if (!String.IsNullOrEmpty(source) || (seconds == 0 && minutes == 0 && hours == 0 && days == 0)) {
timeSpan = 0;
return false;
}
timeSpan = new TimeSpan(days, hours, minutes, seconds).TotalSeconds;
return true;
}
private const String permissionsUnBan = "iqbansystem.unban";
private Dictionary<UInt64, Dictionary<UInt64, TeamLocalMemory>> teamLocalMemory = new();
private void PullOutTeamsInfo(BasePlayer player) {
RelationshipManager.PlayerTeam team = player.Team;
if (team == null) return;
//PrintToChat("Pull Out Teams");
TeamAdded(team);
}
private Boolean IsIpAdress(String mbIP) => Regex.IsMatch(mbIP, patternIP);
private void KickCommand(BasePlayer ownerCommand, String[] arg) {
if (arg == null) {
SendInfo(ownerCommand, LanguageEn ? "Use syntax: kick SteamID/IP/Name* Reason\nItems marked with * are mandatory" : "Используйте синтаксис : kick SteamID/IP/Name* Причина\nПункты помеченные `*` - это обязательные пункты");
return;
}
if (ownerCommand != null) if (!permission.UserHasPermission(ownerCommand.UserIDString, permissionsKick)) return;
if (arg.Length < 1) {
SendInfo(ownerCommand, LanguageEn ? "Use syntax: kick SteamID/IP/Name* Reason\nItems marked with * are mandatory" : "Используйте синтаксис : kick SteamID/IP/Name* Причина\nПункты помеченные `*` - это обязательные пункты");
return;
}
String userParams = arg[0];
IPlayer iPlayer = GetIPlayer(userParams);
if (iPlayer == null) {
SendInfo(ownerCommand, LanguageEn ? "Couldn't find a player" : "Не удалось найти игрока");
return;
}
String reasonArg = String.Empty;
if (arg.Length >= 2) {
if (!String.IsNullOrWhiteSpace(arg[1])) reasonArg = arg[1];
}
KickUser(iPlayer, reasonArg, ownerCommand);
}
private Connection sqlConnection = null;
/// <summary>
/// Returned unbanTime.-1 = permanent
/// </summary>
/// <param name="idOrIP"></param>
/// <returns></returns>
private Double GetUnbanTime(String idOrIP) {
TypeAction typeAction = TypeAction.BannedSteamID;
if (IsIpAdress(idOrIP)) typeAction = TypeAction.BannedIP;
PlayerInfo pInfo = PlayerInfo.Get(idOrIP, typeAction);
if (pInfo == null) return 0;
if (pInfo.permanent) return -1;
return pInfo.GetUnbanTime;
}
private void BanUserOrIp(String idPlayer, String displayName, String ipAdress, String reason, Double banTime, TypeAction type, BasePlayer ownerAction = null, Boolean skipTeam = false) {
if (permission.UserHasPermission(idPlayer, permissionIgnoreBan)) return;
Boolean isBannedIP = type == TypeAction.BannedIP;
String valueImported = isBannedIP ? ipAdress : idPlayer;
PlayerInfo PlayerBanned = PlayerInfo.Get(valueImported, type);
if (PlayerBanned != null && PlayerBanned.IsBanned()) return;
Configuration.BannedSetting.DestroyedAfterBannedSetting configDestroyed = config.bannedSetting.destroyedAfterBannedSetting;
String ownerBanned = ownerAction == null ? "Console" : $"{ownerAction.displayName}({ownerAction.userID})";
Boolean isPermanent = banTime <= 0;
String banReason = String.IsNullOrWhiteSpace(reason) ? "Banned" : reason;
String kickReason = isPermanent ? GetLang("BANNED_DEFAULT_REASON_PERMANENT", idPlayer) : GetLang("BANNED_DEFAULT_REASON", idPlayer, FormatTime(banTime, idPlayer));
if (!String.IsNullOrWhiteSpace(reason)) {
kickReason = isPermanent ? GetLang("BANNED_ALERT_PERMANENT", idPlayer, reason) : GetLang("BANNED_ALERT_TIME", idPlayer, reason, FormatTime(banTime, idPlayer));
}
String formatTime = DateTime.Now.ToString("HH:mm dd:MM:yyyy");
List<PlayerInfo.History> nameHistory = String.IsNullOrWhiteSpace(displayName) ? new List<PlayerInfo.History>() : new List<PlayerInfo.History> {
new() {
value = displayName, time = formatTime
}
}
;
List<PlayerInfo.History> ipHistory = String.IsNullOrWhiteSpace(ipAdress) ? new List<PlayerInfo.History>() : new List<PlayerInfo.History> {
new() {
value = ipAdress, time = formatTime
}
}
;
List<PlayerInfo.History> steamIdHistory = String.IsNullOrWhiteSpace(idPlayer) ? new List<PlayerInfo.History>() : new List<PlayerInfo.History> {
new() {
value = idPlayer, time = formatTime
}
}
;
PlayerInfo.Import(valueImported, new PlayerInfo {
permanent = isPermanent, timeUnbanned = banTime + CurrentTime, reason = banReason, nameHistory = nameHistory, ipHistory = ipHistory, steamIdHistory = steamIdHistory, serverName = config.generalSetting.serverName, serverAdress = config.generalSetting.serverAdress, owner = ownerBanned,
}
, type);
IPlayer bannedPlayer = GetIPlayer(valueImported);
UInt64 userID = 0;
if(bannedPlayer != null) userID = UInt64.Parse(bannedPlayer.Id);
else if(valueImported.IsSteamId()) userID = UInt64.Parse(valueImported);
Boolean isValidID = userID.IsSteamId();
if (IsOpenMySQL()) InserOrUpdateDatabase(valueImported, type, bannedPlayer);
if (isBannedIP) Interface.CallHook("OnBannedPlayerIP", ipAdress, reason, banTime, ownerAction);
else Interface.CallHook("OnBannedPlayerID", userID, reason, banTime, ownerAction);
List<String> posInGridDestroyed = Facepunch.Pool.Get<List<String>>();
List<IPlayer> teamsBanneds = Facepunch.Pool.Get<List<IPlayer>>();
if(bannedPlayer != null) if (config.bannedSetting.teamBannedSetting.useBlockTeam && !skipTeam && isValidID) teamsBanneds = BannedTeams(userID, ownerAction);
String playerBannedName = type == TypeAction.BannedIP ? ipAdress : !String.IsNullOrWhiteSpace(displayName) ? displayName : "Unknown";
String playerBannedNameAlert = type == TypeAction.BannedIP ? ipAdress : !String.IsNullOrWhiteSpace(displayName) ? $"{displayName}({(String.IsNullOrWhiteSpace(idPlayer) ? "Unknown" : idPlayer)})" : "Unknown";
if (config.bannedSetting.useKilledPlayer && bannedPlayer != null && isValidID) {
BasePlayer bPlayer = BasePlayer.FindAwakeOrSleepingByID(userID);
if (bPlayer != null) bPlayer.Hurt(1000f, DamageType.Suicide);
}
if (configDestroyed.useDestroyObjects) {
if (bannedPlayer != null) posInGridDestroyed = DestroyObjectBanned(bannedPlayer, playerBannedName);
}
if (config.generalSetting.additionalSetting.useAlertAllPlayers) {
foreach (BasePlayer basePlayer in BasePlayer.activePlayerList) {
String banTimeFormat = isPermanent ? GetLang("ALERT_ALL_TITILE_PERMANENT", basePlayer.UserIDString) : FormatTime(banTime, basePlayer.UserIDString);
String reasonAlert = GetLang(banReason, basePlayer.UserIDString);
String ownerBannedAlert = ownerAction == null ? GetLang("ALERT_ALL_TITILE_ADMIN_BANNED", basePlayer.UserIDString) : ownerAction.displayName;
String playerNameAlert = GetLang(playerBannedName, basePlayer.UserIDString);
String messagePlayers = GetLang("ALERT_ALL_PLAYER_BANNED", basePlayer.UserIDString, playerNameAlert, reasonAlert, banTimeFormat, ownerBannedAlert);
if (config.bannedSetting.teamBannedSetting.useBlockTeam && config.generalSetting.additionalSetting.useAlertBlockTeam && teamsBanneds != null && teamsBanneds.Count != 0) messagePlayers += GetLang("ALERT_ALL_BANNED_TEAMS", basePlayer.UserIDString, String.Join(", ", teamsBanneds.Select(player => player.Name)));
if (configDestroyed.useDestroyObjects && configDestroyed.useAlertGridHomes && posInGridDestroyed != null && posInGridDestroyed.Count != 0) {
String alertMessage = configDestroyed.typeDestroyed switch {
TypeDestroy.AllObjectsAndDropInStorage => "ALERT_ALL_ADDITIONAL_DESTROY", TypeDestroy.OnlyLocks => "ALERT_ALL_ADDITIONAL_DESTROY_ONLY_CODE_LOCK", TypeDestroy.AllObjects => "ALERT_ALL_ADDITIONAL_DESTROY_CLEAR_STORAGE", TypeDestroy.OnlyStorageAndDropInStorage => "ALERT_ALL_ADDITIONAL_DESTROY_ONLY_STORAGE", _ => "ALERT_ALL_ADDITIONAL_DESTROY_ONLY_STORAGE_CLEAR"
}
;
messagePlayers += GetLang(alertMessage, basePlayer.UserIDString, String.Join(", ", posInGridDestroyed));
if (configDestroyed.mapMarkerDestroyedObjectSetting.useMapMarkerDestroyedObjectPlayer) if (TryParseTimeSpan(configDestroyed.mapMarkerDestroyedObjectSetting.markerLifeTime, out Double markerLife)) messagePlayers += GetLang("ALERT_ALL_USE_MARKER", basePlayer.UserIDString, FormatTime(markerLife, idPlayer));
}
SendChat(messagePlayers, basePlayer);
if (skipTeam) continue;
String soundPath = config.generalSetting.additionalSetting.effectAlertAllPlayers;
if (soundPath != null && !String.IsNullOrWhiteSpace(soundPath)) RunEffect(basePlayer, soundPath);
}
}
if (bannedPlayer is {
IsConnected : true
}
) bannedPlayer.Kick(banReason);
if(isValidID && isPermanent) SetTirifyBan(userID.ToString(), reason);
String messageAlert = LanguageEn ? $"Player {playerBannedNameAlert} has been banned.\nBan Time: {(isPermanent ? "permanent" : FormatTime(banTime, null))}.\nReason: {banReason}.\nIssued by: {ownerBanned}" : $"Игрок {playerBannedNameAlert} заблокирован.\nВремя блокировки : {(isPermanent ? "навсегда" : FormatTime(banTime, null))}.\nПричина : {banReason}.\nВыдал блокировку : {ownerBanned}";
Puts(messageAlert);
String webhookBanned = config.generalSetting.discordSetting.alertBanned.webHookBanned;
if (!String.IsNullOrWhiteSpace(webhookBanned)) {
List<Fields> fieldsBanned = new List<Fields> {
new Fields(type == TypeAction.BannedIP ? "IP" : LanguageEn ? "Player" : "Игрок", playerBannedNameAlert, true), new Fields(LanguageEn ? "Issued by" : "Выдал блокировку", ownerBanned, true), new Fields("", "", false), new Fields(LanguageEn ? "Ban Time" : "Время блокировки", (isPermanent ? (LanguageEn ? "permanent" : "навсегда") : FormatTime(banTime, null)), true), new Fields(LanguageEn ? "Reason" : "Причина", banReason, true), new Fields("", "", false),
}
;
if (config.bannedSetting.teamBannedSetting.useBlockTeam && config.generalSetting.additionalSetting.useAlertBlockTeam && teamsBanneds != null && teamsBanneds.Count != 0) {
fieldsBanned.Add(new Fields(LanguageEn ? "Banneds teams" : "Заблокированные тиммейты", String.Join(", ", teamsBanneds.Select(player => player.Name)), false));
fieldsBanned.Add(new Fields("", "", false));
}
if(posInGridDestroyed != null && posInGridDestroyed.Count != 0) {
fieldsBanned.Add(new Fields(LanguageEn ? "Destroyed buildings of the player in squares" : "Разрушенные строения игрока в квадратах", String.Join(", ", posInGridDestroyed), false));
fieldsBanned.Add(new Fields("", "", false));
}
if (config.generalSetting.discordSetting.alertBanned.cupboardAuthInfo) {
if (isValidID) {
Dictionary<Vector3, String> infoCupboards = GetAuthCupboardPlayer(userID);
fieldsBanned.Add(new Fields(LanguageEn ? "Houses where the player is logged in" : "Дома в которых авторизован игрок", infoCupboards.Count == 0 ? (LanguageEn ? "Empty" : "Пусто") : String.Join("\n", infoCupboards.Select(kv => $"{kv.Value} - {kv.Key}")), false));
fieldsBanned.Add(new Fields("", "", false));
}
}
if (config.generalSetting.discordSetting.alertBanned.teamsAlert.saveInfoTeams) {
if (isValidID) {
String timePlayeingInConfig = config.generalSetting.discordSetting.alertBanned.teamsAlert.formatTimePlaying;
if (TryParseTimeSpan(timePlayeingInConfig, out Double timePlaying)) {
Dictionary<UInt64, Double> teamMemory = GetTeamsBannedPlayer(userID);
String resultTeams = teamMemory == null || teamMemory.Count == 0 ? (LanguageEn ? "Empty" : "Пусто") : String.Join("\n", teamMemory.Where(memory => memory.Value > timePlaying && memory.Key != userID).Select(memory => {
IPlayer iPlayer = GetIPlayer($"{memory.Key}");
return iPlayer != null ? $"{iPlayer.Name} - {memory.Key}" : $"Unknown - {memory.Key}";
}
));
resultTeams = String.IsNullOrWhiteSpace(resultTeams) ? (LanguageEn ? "Empty" : "Пусто") : resultTeams;
fieldsBanned.Add(new Fields(LanguageEn ? $"Players who have been blocked for more than {GetFormatTimeDiscord(timePlayeingInConfig)}" : $"Игроки с которым играл заблокированный более {GetFormatTimeDiscord(timePlayeingInConfig)}", resultTeams, false));
fieldsBanned.Add(new Fields("", "", false));
}
}
}
fieldsBanned.Add(new Fields(LanguageEn ? "History nick" : "История ников", nameHistory == null || nameHistory.Count == 0? (LanguageEn ? "Empty" : "Пусто") : String.Join("\n", nameHistory.Select(ph => $"{ph.time} - {ph.value}")), false));
fieldsBanned.Add(new Fields(LanguageEn ? "History Steam64ID" : "История Steam64ID", steamIdHistory == null || steamIdHistory.Count == 0 ? (LanguageEn ? "Empty" : "Пусто") : String.Join("\n", steamIdHistory.Select(ph => $"{ph.time} - {ph.value}")), false));
fieldsBanned.Add(new Fields(LanguageEn ? "History IPs" : "История IP", ipHistory == null || ipHistory.Count == 0 ? (LanguageEn ? "Empty" : "Пусто") : String.Join("\n", ipHistory.Select(ph => $"{ph.time} - {ph.value}")), false));
fieldsBanned.Add(new Fields("", "", false));
SendDiscord(fieldsBanned, TypeAlertDiscord.Banned, webhookBanned);
}
Facepunch.Pool.FreeUnmanaged(ref posInGridDestroyed);
Facepunch.Pool.FreeUnmanaged(ref teamsBanneds);
if (IQTeleportation && isValidID) IQTeleportation.CallHook("ClearHomesPlayer", userID, "IQBanSystem");
}
private const String permissionsBan = "iqbansystem.ban";
void WriteData() {
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQBanSystem/ListGodIps", ipListGods);
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQBanSystem/TeamsMemory", teamLocalMemory);
}
private static Double CurrentTime => DateTime.UtcNow.Subtract(epoch).TotalSeconds;
private IPlayer GetIPlayer(String userParams) {
if (UInt64.TryParse(userParams, out UInt64 userID)) {
BasePlayer basePlayerByID = BasePlayer.FindByID(userID);
if (basePlayerByID) return basePlayerByID.IPlayer;
BasePlayer sleepingPlayer = BasePlayer.sleepingPlayerList.FirstOrDefault(p => p.userID == userID);
if (sleepingPlayer) return sleepingPlayer.IPlayer;
IPlayer iPlayer = covalence.Players.FindPlayerById(userParams);
if (iPlayer != null) return iPlayer;
}
if (IsIpAdress(userParams)) {
foreach (BasePlayer player in BasePlayer.activePlayerList) {
if (player.net?.connection?.ipaddress != null && player.net.connection.ipaddress.StartsWith(userParams)) return player.IPlayer;
}
foreach (BasePlayer player in BasePlayer.sleepingPlayerList) {
if (player.net?.connection?.ipaddress != null && player.net.connection.ipaddress.StartsWith(userParams)) return player.IPlayer;
}
}
BasePlayer activePlayer = BasePlayer.activePlayerList.FirstOrDefault(p => String.Equals(p.displayName, userParams, StringComparison.OrdinalIgnoreCase));
if (activePlayer != null) return activePlayer.IPlayer;
BasePlayer sleepingPlayerByName = BasePlayer.sleepingPlayerList.FirstOrDefault(p => String.Equals(p.displayName, userParams, StringComparison.OrdinalIgnoreCase));
if (sleepingPlayerByName != null) return sleepingPlayerByName.IPlayer;
List<BasePlayer> matchingPlayers = new List<BasePlayer>();
foreach (BasePlayer player in BasePlayer.activePlayerList) {
if (player.displayName.IndexOf(userParams, StringComparison.OrdinalIgnoreCase) >= 0) matchingPlayers.Add(player);
}
foreach (BasePlayer player in BasePlayer.sleepingPlayerList) {
if (player.displayName.IndexOf(userParams, StringComparison.OrdinalIgnoreCase) >= 0) matchingPlayers.Add(player);
}
switch (matchingPlayers.Count) {
case 1 : return matchingPlayers[0].IPlayer;
case > 1 : {
String playerNames = "";
for (Int32 i = 0; i < matchingPlayers.Count; i++) {
playerNames += matchingPlayers[i].displayName;
if (i < matchingPlayers.Count - 1) playerNames += ", ";
}
Puts(LanguageEn ? $"Specify the nickname or use the ID.\nPossible players with a similar nickname : {playerNames}" : $"Уточните ник или используйте ID.\nВозможные игроки с похожим ником : {playerNames}");
return null;
}
}
IPlayer covalencePlayer = covalence.Players.FindPlayer(userParams);
return covalencePlayer ?? null;
}
private class PlayerInfo : SplitDatafile<PlayerInfo> {
private const String BaseFolder = "IQSystem" + "/" + "IQBanSystem" + "/";
private const String UserFolder = "UserBanned" + "/";
private const String IpFolder = "IPBanned" + "/";
private static String GetFolder(TypeAction typeBanned) => typeBanned == TypeAction.BannedIP ? BaseFolder + IpFolder : BaseFolder + UserFolder;
public static PlayerInfo Save(String idOrIp, TypeAction type) => Save(type, GetFolder(type), idOrIp);
public static void Import(String idOrIp, PlayerInfo data, TypeAction type) => Import(type, GetFolder(type), idOrIp, data);
public static void Remove(String idOrIp, TypeAction type) => Remove(type, GetFolder(type), idOrIp);
public static PlayerInfo Get(String idOrIp, TypeAction type) => Get(type, GetFolder(type), idOrIp);
public static PlayerInfo Load(String idOrIp, TypeAction type) => Load(type, GetFolder(type), idOrIp);
public static PlayerInfo Clear(String idOrIp, TypeAction type) => ClearAndSave(type, GetFolder(type), idOrIp);
public static PlayerInfo GetOrLoad(String idOrIp, TypeAction type) => GetOrLoad(type, GetFolder(type), idOrIp);
public static PlayerInfo GetOrCreate(String idOrIp, TypeAction type) => GetOrCreate(type, GetFolder(type), idOrIp);
public static String[] GetFiles(TypeAction type) => GetFiles(GetFolder(type));
public Boolean permanent = false;
public Double timeUnbanned;
public String reason;
public String serverName;
public String serverAdress;
public String owner;
public List<History> nameHistory = new();
public List<History> ipHistory = new();
public List<History> steamIdHistory = new();
internal class History {
public String value;
public String time;
}
[JsonIgnore]
public Double GetUnbanTime => timeUnbanned - CurrentTime;
public Boolean IsBanned() {
if (permanent) return true;
return GetUnbanTime > 0;
}
public void UpdateHistory(TypeHistoryInfo typeInfo, String value) {
List<History> historyList = GetHistoryList(typeInfo);
if (IsExistsValueHistory(historyList, value)) return;
historyList.Insert(0, new History {
time = DateTime.Now.ToString("HH:mm dd:MM:yyyy"), value = value,
}
);
}
private List<History> GetHistoryList(TypeHistoryInfo typeInfo) {
return typeInfo switch {
TypeHistoryInfo.Name => nameHistory, TypeHistoryInfo.IP => ipHistory, TypeHistoryInfo.SteamID => steamIdHistory, _ => throw new ArgumentOutOfRangeException(nameof(typeInfo), typeInfo, null),
}
;
}
private Boolean IsExistsValueHistory(List<History> histories, String value) {
foreach (History history in histories) {
if (!history.value.Equals(value)) continue;
history.time = DateTime.Now.ToString("HH:mm dd:MM:yyyy");
return true;
}
return false;
}
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
}
catch {
PrintWarning(LanguageEn ? $"Error reading #54327 configuration 'oxide/config/{Name}', creating a new configuration!!" : $"Ошибка чтения #54327 конфигурации 'oxide/config/{Name}', создаём новую конфигурацию!!");
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
private abstract class SplitDatafile<T> where T : SplitDatafile<T>, new() {
public static Dictionary<String, T> _players = new();
public static Dictionary<String, T> _ipAdresses = new();
public static Dictionary<String, T> _savedItems = new();
private static Dictionary<String, T> GetRepository(TypeAction type) => type switch {
TypeAction.BannedIP => _ipAdresses, TypeAction.BannedSteamID => _players, _ => _savedItems
}
;
protected static void Import(TypeAction type, String baseFolder, String userId, T data) {
Dictionary<String, T> repository = GetRepository(type);
repository[userId] = data;
Save(type, baseFolder, userId);
}
protected static String[] GetFiles(String baseFolder) {
try {
Int32 json = ".json".Length;
String[] paths = Interface.Oxide.DataFileSystem.GetFiles(baseFolder, "*.json");
for (Int32 i = 0; i < paths.Length; i++) {
String path = paths[i];
Int32 separatorIndex = path.LastIndexOf("/", StringComparison.Ordinal);
paths[i] = path.Substring(separatorIndex + 1, path.Length - separatorIndex - 1 - json);
}
return paths;
}
catch {
return Array.Empty<string>();
}
}
protected static T Save(TypeAction type, string baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
T data;
if (!repository.TryGetValue(userId, out data)) return null;
Interface.Oxide.DataFileSystem.WriteObject(baseFolder + userId, data);
return data;
}
protected static void Remove(TypeAction type, string baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
if (!repository.ContainsKey(userId)) return;
repository.Remove(userId);
Interface.Oxide.DataFileSystem.DeleteDataFile(baseFolder + userId);
}
protected static T Get(TypeAction type, string baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
T data;
if (repository.TryGetValue(userId, out data)) return data;
return null;
}
protected static T Load(TypeAction type, String baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
T data = null;
try {
data = Interface.Oxide.DataFileSystem.ReadObject<T>(baseFolder + userId);
}
catch (Exception e) {
Interface.Oxide.LogError(e.ToString());
}
return repository[userId] = data;
}
protected static T GetOrLoad(TypeAction type, String baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
T data;
if (repository.TryGetValue(userId, out data)) return data;
return Load(type, baseFolder, userId);
}
protected static T GetOrCreate(TypeAction type, String baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
return GetOrLoad(type, baseFolder, userId) ?? (repository[userId] = new T());
}
protected static T ClearAndSave(TypeAction type, String baseFolder, String userId) {
Dictionary<String, T> repository = GetRepository(type);
T data;
if (repository.TryGetValue(userId, out data)) {
data = new T();
Interface.Oxide.DataFileSystem.WriteObject(baseFolder + userId, data);
return data;
}
return null;
}
}
private void BanIp(String IpAdress, IPlayer iPlayer = null, String reason = default, Double banTime = 0, BasePlayer ownerCommand = null, Boolean skipTeam = false) {
String displayName = iPlayer?.Name ?? String.Empty;
String idPlayer = iPlayer?.Id ?? String.Empty;
BanUserOrIp(idPlayer, displayName, IpAdress, reason, banTime, TypeAction.BannedIP, ownerCommand, skipTeam);
}
object OnTeamLeave(RelationshipManager.PlayerTeam team, BasePlayer player) {
LeaveTeamPlayer(player.userID);
return null;
}
private static Configuration config = new Configuration();
private const String patternIP = @"^\b(?:\d{1,3}\.){3}\d{1,3}\b$";
private void BanCommand(BasePlayer ownerCommand, String[] arg) {
if (arg == null) {
SendInfo(ownerCommand, LanguageEn ? "Use the syntax: ban SteamID/IP/Name* Time(1s/1m/1h/1d) Reason\nItems marked with `*` are mandatory" : "Используйте синтаксис : ban SteamID/IP/Name* Время(1s/1m/1h/1d) Причина\nПункты помеченные `*` - это обязательные пункты");
return;
}
if (ownerCommand != null) if (!permission.UserHasPermission(ownerCommand.UserIDString, permissionsBan)) return;
if (arg.Length < 1) {
SendInfo(ownerCommand, LanguageEn ? "Use the syntax: ban SteamID/IP/Name* Time(1s/1m/1h/1d) Reason\nItems marked with `*` are mandatory" : "Используйте синтаксис : ban SteamID/IP/Name* Время(1s/1m/1h/1d) Причина\nПункты помеченные `*` - это обязательные пункты");
return;
}
String userParams = arg[0];
UInt64 targetUserID = 0;
IPlayer iPlayer = GetIPlayer(userParams);
Boolean isIp = IsIpAdress(userParams);
if (!isIp) {
if (!UInt64.TryParse(userParams, out targetUserID)) {
if (iPlayer == null) {
SendInfo(ownerCommand, LanguageEn ? "Couldn't find a player" : "Не удалось найти игрока");
return;
}
targetUserID = UInt64.Parse(iPlayer.Id);
}
}
Double banTime = 0;
String reasonArg = String.Empty;
if (arg.Length >= 2) {
String potentialTime = arg[1];
if (!String.IsNullOrWhiteSpace(potentialTime) && TryParseTimeSpan(potentialTime, out banTime)) reasonArg = arg.Length > 2 ? String.Join(" ", arg.Skip(2)) : null;
else reasonArg = String.Join(" ", arg.Skip(1));
}
if (isIp) BanIp(userParams, iPlayer, reasonArg, banTime, ownerCommand);
else BanUser(targetUserID, iPlayer, reasonArg, banTime, ownerCommand);
}
private void HandlerSteam(IPlayer player, Int32 code, String response) {
if (code != 200 || string.IsNullOrEmpty(response)) {
ResponseError("Steam", $"{code}");
return;
}
Dictionary<String, Object> jsonresponse;
try {
jsonresponse = JsonConvert.DeserializeObject<Dictionary<String, Object>>(response);
}
catch (JsonReaderException e) {
ResponseError("Steam", e.Message);
return;
}
if (!jsonresponse.TryGetValue("response", out Object value)) {
ResponseError("Steam", "Response == null");
return;
}
JToken playerData = ((JObject)value)["players"]?[0];
if (playerData == null) {
ResponseError("Steam", "playerData == null");
return;
}
Int64? accountCreationDate = (Int64?)playerData["timecreated"];
webrequest.Enqueue($"https://api.steampowered.com/IPlayerService/GetOwnedGames/v1/?key={config.steamSetting.steamApiKey}&steamid={player.Id}&include_played_free_games=1", String.Empty, (gameCode, gameResponse) => HandleGameTimes(player, accountCreationDate, gameCode, gameResponse), this, timeout : 10f);
}
private void MarkerUpdate() {
for (Int32 i = 0; i < mapMarkers.Count; i++) {
MarkerRepository marker = mapMarkers[i];
TimeSpan timeSpan = DateTime.Now - marker.timeSetMarker;
Double totalSeconds = timeSpan.TotalSeconds;
if (!TryParseTimeSpan(config.bannedSetting.destroyedAfterBannedSetting.mapMarkerDestroyedObjectSetting.markerLifeTime, out Double markerUpdate)) {
PrintError(LanguageEn ? "Incorrect marker update time format.The marker has been deleted." : "Некорректный формат времени обновления маркера.Маркер был удален.");
if(!marker.vending.IsDestroyed) marker.vending.Kill();
if(!marker.marker.IsDestroyed) marker.marker.Kill();
mapMarkers.Remove(marker);
}
if(totalSeconds < markerUpdate) continue;
if(!marker.vending.IsDestroyed) marker.vending.Kill();
if(!marker.marker.IsDestroyed) marker.marker.Kill();
mapMarkers.Remove(marker);
}
}
public String FormatTime(Double Second, String UserID = null) {
TimeSpan time = TimeSpan.FromSeconds(Second);
String Result = String.Empty;
String Days = GetLang("TITLE_FORMAT_DAYS", UserID);
String Hourse = GetLang("TITLE_FORMAT_HOURSE", UserID);
String Minutes = GetLang("TITLE_FORMAT_MINUTES", UserID);
String Seconds = GetLang("TITLE_FORMAT_SECONDS", UserID);
if (time.Seconds != 0) Result = $"{Format(time.Seconds, Seconds, Seconds, Seconds)}";
if (time.Minutes != 0) Result = $"{Format(time.Minutes, Minutes, Minutes, Minutes)}";
if (time.Hours != 0) Result = $"{Format(time.Hours, Hourse, Hourse, Hourse)}";
if (time.Days != 0) Result = $"{Format(time.Days, Days, Days, Days)}";
return Result;
}
void HandlerProxyCheckIo(Int32 code, String response, String adress) {
ProcessCheckVPN processChecked = ipListChecked[adress];
if (code != 200 || string.IsNullOrEmpty(response)) {
ResponseError("ProxyCheckIO", $"{code}");
processChecked.isCompleteProxyCheck = true;
return;
}
JObject jsonResponse;
try {
jsonResponse = JObject.Parse(response);
}
catch (JsonReaderException e) {
ResponseError("ProxyCheckIO", e.Message);
processChecked.isCompleteProxyCheck = true;
return;
}
String status = jsonResponse["status"]?.ToString();
if (!status.Equals("ok")) {
String message = jsonResponse["message"]?.ToString();
ResponseError("ProxyCheckIO", $"{status} : {message}");
processChecked.isCompleteProxyCheck = true;
return;
}
foreach (JProperty ipInfoProperty in jsonResponse.Properties()) {
if (ipInfoProperty.Name.Equals("status", StringComparison.OrdinalIgnoreCase)) continue;
JToken ipInfo = ipInfoProperty.Value;
if (ipInfo["proxy"] != null && ipInfo["type"] != null) {
String proxy = ipInfo["proxy"].ToString();
String type = ipInfo["type"].ToString();
if (proxy.Equals("yes", StringComparison.OrdinalIgnoreCase) || type.Equals("VPN", StringComparison.OrdinalIgnoreCase)) {
//PrintError("DETECT ");
processChecked.detectedVpn++;
}
}
}
processChecked.isCompleteProxyCheck = true;
}
/// <summary>
/// Returned IsBanned status
/// </summary>
/// <param name="idOrIP"></param>
/// <returns></returns>
private Boolean IsBanned(String idOrIP) {
TypeAction typeAction = TypeAction.BannedSteamID;
if (IsIpAdress(idOrIP)) typeAction = TypeAction.BannedIP;
PlayerInfo pInfo = PlayerInfo.Get(idOrIP, typeAction);
return pInfo != null && pInfo.IsBanned();
}
private String SQL_Query_SelectedDatabase() => $"SELECT * FROM {config.mysqlConnected.dbTableName}";
public class Fields {
public String name {
get;
set;
}
public String value {
get;
set;
}
public bool inline {
get;
set;
}
public Fields(String name, String value, bool inline) {
this.name = name;
this.value = value;
this.inline = inline;
}
}
private void SaveDataFiles(TypeAction type) {
foreach (KeyValuePair<String, PlayerInfo> player in PlayerInfo._players) PlayerInfo.Save(player.Key, type);
}
private new void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<String, String> {
["BANNED_ALERT_TIME"]
= "You are banned for the reason {0}.Unban in: {1}", ["BANNED_ALERT_PERMANENT"] = "You are permanently banned for the reason {0}", ["BANNED_DEFAULT_REASON_PERMANENT"] = "You are permanently banned from the server", ["BANNED_DEFAULT_REASON"] = "You are banned from the server.Unban in: {0}", ["KICKED_VPN_REASON"] = "You were kicked from the server for using a VPN", ["KICKED_DEFAULT_REASON"] = "You were kicked from the server", ["KICKED_STEAM_ID_INCORRECTED"] = "Incorrect SteamID", ["KICKED_STEAM_NEW_ACCOUNT"] = "Your account is too new to play on our server", ["KICKED_STEAM_NO_GAME_TIME"] = "You don't have enough playtime in RUST to play on this server", ["BANNED_DEFAULT_REASON_GAME_WITH_CHEATER"] = "Playing with a cheater", ["ALERT_ALL_PLAYER_KICKED"] = "Player <color=#CD412B>{0}</color> was kicked from the server.\nReason: <color=#CD412B>{1}</color>\nKick issued by: <color=#1F6BA0>{2}</color>", ["ALERT_ALL_PLAYER_BANNED"] = "Player <color=#CD412B>{0}</color> was banned from the server.\nReason: <color=#CD412B>{1}</color>\nBan duration: <color=#CD412B>{2}</color>\nBan issued by: <color=#1F6BA0>{3}</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_ONLY_STORAGE_CLEAR"] = "\n\nAll this player's storage boxes were destroyed, and all items were deleted in the areas: <color=#C26D33>{0}</color>\nThe building was preserved, and you can claim it\n<color=#738D45>*Items will disappear over time!</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_ONLY_STORAGE"] = "\n\nAll this player's storage boxes were destroyed, and all items were dropped on the ground in the areas: <color=#C26D33>{0}</color>\nYou can raid the building and claim the items\n<color=#738D45>*Items will disappear over time!</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_CLEAR_STORAGE"] = "\n\nThis player's buildings were destroyed, and all items were deleted in the areas: <color=#C26D33>{0}</color>", ["ALERT_ALL_ADDITIONAL_DESTROY"] = "\n\nThis player's buildings were destroyed, and all items were dropped on the ground in the areas: <color=#C26D33>{0}</color>\n<color=#738D45>*Items will disappear over time!</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_ONLY_CODE_LOCK"] = "\n\nAll this player's locks were destroyed in houses in the areas: <color=#C26D33>{0}</color>\n<color=#738D45>You are free to claim the buildings and loot</color>", ["ALERT_ALL_USE_MARKER"] = "\n\nAll house locations have been marked on the G-map!\nThey will be removed in: <color=#CD412B>{0}</color>", ["ALERT_ALL_BANNED_TEAMS"] = "\nBanned teammates: <color=#CD412B>{0}</color>", ["ALERT_ALL_TITILE_PERMANENT"] = "permanently", ["ALERT_ALL_TITILE_ADMIN_BANNED"] = "administrator", ["TITLE_FORMAT_DAYS"] = "D", ["TITLE_FORMAT_HOURSE"] = "H", ["TITLE_FORMAT_MINUTES"] = "M", ["TITLE_FORMAT_SECONDS"] = "S",
}
, this);
lang.RegisterMessages(new Dictionary<String, String> {
["BANNED_ALERT_TIME"]
= "Вы заблокированы по причине {0}.Разблокировка через : {1}", ["BANNED_ALERT_PERMANENT"] = "Вы заблокированы навсегда по причине {0}", ["BANNED_DEFAULT_REASON_PERMANENT"] = "Вы навсегда заблокированы на сервере", ["BANNED_DEFAULT_REASON"] = "Вы заблокированы на сервере.Разблокировка через : {0}", ["KICKED_VPN_REASON"] = "Вы были кикнуты с сервера за использование VPN", ["KICKED_DEFAULT_REASON"] = "Вы были кикнуты с сервера", ["KICKED_STEAM_ID_INCORRECTED"] = "Некорректный SteamID", ["KICKED_STEAM_NEW_ACCOUNT"] = "Ваш аккаунт слишком новый для игры на нашем сервере", ["KICKED_STEAM_NO_GAME_TIME"] = "Вы слишком мало времени провели в RUST для игры на сервере", ["BANNED_DEFAULT_REASON_GAME_WITH_CHEATER"] = "игра с нарушителем", ["ALERT_ALL_PLAYER_KICKED"] = "Игрок <color=#CD412B>{0}</color> был кикнут с сервере.\nПричина : <color=#CD412B>{1}</color>\nВыдал кик : <color=#1F6BA0>{2}</color>", ["ALERT_ALL_PLAYER_BANNED"] = "Игрок <color=#CD412B>{0}</color> был заблокирован на сервере.\nПричина : <color=#CD412B>{1}</color>\nВремя блокировки : <color=#CD412B>{2}</color>\nВыдал блокировку : <color=#1F6BA0>{3}</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_ONLY_STORAGE_CLEAR"] = "\n\nВсе сундуки данного игрока были разрушены и все предметы удалены на квадратах : <color=#C26D33>{0}</color>\nСтроение было сохранено, вы можете завладеть им\n<color=#738D45>*Предметы исчезнут через время!</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_ONLY_STORAGE"] = "\n\nВсе сундуки данного игрока были разрушены и все предметы были выброшены на землю на квадратах : <color=#C26D33>{0}</color>\nВы можете пробраться в строение и забрать их\n<color=#738D45>*Предметы исчезнут через время!</color>", ["ALERT_ALL_ADDITIONAL_DESTROY_CLEAR_STORAGE"] = "\n\nСтроения данного игрока были разруш
// ... [Code preview truncated due to length. Full source in attached file] ...