C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using Oxide.Core.Configuration;
using UnityEngine;
using System.Linq;
using System.Diagnostics;
using System.Collections;
//Reference: Facepunch.Sqlite
namespace Oxide.Plugins
{
[Info("BanFix", "Jake_Rich", "1.0.0")]
[Description("")]
public class BanFix : RustPlugin
{
private Facepunch.Sqlite.Database banDB;
public const string TableName = "server_users";
void SetupDatabase()
{
banDB = new Facepunch.Sqlite.Database();
banDB.Open($"{ConVar.Server.rootFolder}/ServerUsers.db");
if (!banDB.TableExists(TableName))
{
//group is a reserved word: using usergroup instead
banDB.Execute($"CREATE TABLE {TableName} ( steamid INTEGER PRIMARY KEY, usergroup INTEGER, username TEXT, notes TEXT )");
OnServerSaveUsers();
}
}
private IEnumerator SaveBansToDatabase()
{
var bans = ServerUsers.GetAll(ServerUsers.UserGroup.Banned).ToList();
yield return null; //Gotta have that debug message show when you first load the plguin
Puts($"Starting To Push {bans.Count} Bans To Database");
foreach (var user in bans)
{
UpdateUserGroup(user.steamid, user.group, user.username, user.notes);
yield return null;
}
Puts("Finished Saving All Bans To The Database");
yield return null;
}
#region Hooks
void OnServerInitialized()
{
SetupDatabase();
OnServerLoadUsers();
}
void Unload()
{
banDB?.Close();
}
void OnServerShutdown()
{
//May as well write to default file on shutdown
ServerUsers.Save();
}
object OnServerCommand(ConsoleSystem.Arg arg)
{
if (arg.cmd.FullName == "global.ban")
{
if (arg.IsAdmin)
{
//Need to overwrite ban command as vanilla one will save to file
OverwriteBanCommand(arg);
}
return false;
}
return null;
}
//Not really a hook but sorta as we are copy paste overwriting it
void OverwriteBanCommand(ConsoleSystem.Arg arg)
{
BasePlayer player = ArgEx.GetPlayer(arg, 0);
if (!(bool)player || player.net == null || player.net.connection == null)
{
arg.ReplyWith("Player not found");
}
else
{
ServerUsers.User user = ServerUsers.Get(player.userID);
if (user != null && user.group == ServerUsers.UserGroup.Banned)
{
arg.ReplyWith("User " + player.userID + " is already banned");
}
else
{
string @string = arg.GetString(1, "No Reason Given");
ServerUsers.Set(player.userID, ServerUsers.UserGroup.Banned, player.displayName, @string);
string text = string.Empty;
if (player.IsConnected && player.net.connection.ownerid != player.net.connection.userid)
{
text = text + " and also banned ownerid " + player.net.connection.ownerid;
ServerUsers.Set(player.net.connection.ownerid, ServerUsers.UserGroup.Banned, player.displayName, arg.GetString(1, "Family share owner of " + player.net.connection.userid));
}
//We don't actually have to save, because we save on user group changed
//OnServerSaveUsers();
//ServerUsers.Save();
arg.ReplyWith("Kickbanned User: " + player.userID + " - " + player.displayName + text);
PrintToChat("Kickbanning " + player.displayName + " (" + @string + ")", "SERVER", "#eee", 0uL);
Network.Net.sv.Kick(player.net.connection, "Banned: " + @string);
}
}
}
Coroutine saveRoutine;
//Hook Save (Save To DB instead of File)
//Not used much: we're saving individual user changes instead of them all
void OnServerSaveUsers()
{
//OK RYAN DO YOUR SAVE SHIT HERE
//We needed to spread out the queries: took 16,000MS to load 4k bans
if (saveRoutine != null)
{
ServerMgr.Instance.StopCoroutine(saveRoutine); //Don't let users be stupid and save multiple times and lag their server
}
saveRoutine = ServerMgr.Instance.StartCoroutine(SaveBansToDatabase());
}
//Hook Load (Load from DB instead of File)
void OnServerLoadUsers()
{
//NOW DO YOUR LOAD STUFF HERE
LoadingServerUsers = true;
foreach (var row in banDB.Query($"SELECT * FROM {TableName}"))
{
//https://stackoverflow.com/questions/11226448/invalidcastexception-long-to-ulong
//Never knew you had to cast to long then ulong in a specific situation
ulong steamID = (ulong)((long)row.Value["steamid"]);
ServerUsers.UserGroup group = (ServerUsers.UserGroup)row.Value.GetInt("usergroup");
string name = row.Value.GetString("username") ?? "";
string reason = row.Value.GetString("notes") ?? "";
ServerUsers.Set(steamID, group, name, reason);
}
LoadingServerUsers = false;
}
void OnPlayerBanned(string name, ulong steamID, string IP, string reason)
{
if (LoadingServerUsers)
{
return;
}
UpdateUserGroup(steamID, ServerUsers.UserGroup.Banned, name, reason);
}
void OnPlayerUnbanned(string name, ulong steamID, string IP)
{
if (LoadingServerUsers)
{
return;
}
RemoveUserGroup(steamID);
}
#endregion
private bool LoadingServerUsers = false;
void ClearDatabase()
{
banDB.Execute($"DELETE FROM {TableName}");
banDB.Execute("VACUUM");
}
void UpdateUserGroup(ulong steamId, ServerUsers.UserGroup group, string name, string notes)
{
banDB.Execute($"INSERT OR REPLACE INTO {TableName} ( steamid, usergroup, username, notes ) VALUES ( ?, ?, ?, ? )", (long)steamId, (int)group, name ?? "", notes ?? "");
}
void RemoveUserGroup(ulong steamId)
{
banDB.Execute($"DELETE FROM {TableName} WHERE steamid = ?", steamId);
}
#region Commands
[ConsoleCommand("bans.save.db")]
void SaveBansToDB_CMD(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
OnServerSaveUsers();
}
[ConsoleCommand("bans.save.file")]
void SaveBansToFile_CMD(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
ServerUsers.Save();
}
[ConsoleCommand("bans.clear.db")]
void ClearBansTest(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
ClearDatabase();
Puts($"Cleared Database");
}
[ConsoleCommand("bans.clear.file")]
void ClearLocalBans(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
LoadingServerUsers = true;
foreach (var ban in ServerUsers.GetAll(ServerUsers.UserGroup.Banned).ToList())
{
ServerUsers.Remove(ban.steamid);
}
LoadingServerUsers = false;
Puts($"Cleared Server Bans");
}
[ConsoleCommand("bans.load.db")]
void LoadBansDB_CMD(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
OnServerLoadUsers();
Puts("Loaded Bans From DB");
}
[ConsoleCommand("bans.load.file")]
void LoadBansFile_CMD(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
LoadingServerUsers = true;
ServerUsers.Load();
LoadingServerUsers = false;
Puts("Loaded Bans From File");
}
[ConsoleCommand("bans.check")]
void ReadBansTest(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
int result = banDB.Query($"SELECT * FROM {TableName}").Count;
Puts($"Database: {result} Server: {ServerUsers.GetAll(ServerUsers.UserGroup.Banned).Count()}");
}
[ConsoleCommand("bans.test")]
void TestOldBan(ConsoleSystem.Arg arg)
{
if (!arg.IsAdmin)
{
return;
}
Stopwatch watch = new Stopwatch();
watch.Start();
ServerUsers.Save();
watch.Stop();
Puts($"Took {watch.ElapsedMilliseconds} ms for old ban method");
watch.Reset();
watch.Start();
UpdateUserGroup(76561198104673895u, ServerUsers.UserGroup.Moderator, "Jake", "PLEASE FUCKING WORK");
watch.Stop();
Puts($"Took {watch.ElapsedMilliseconds} ms for new ban method");
watch.Reset();
watch.Start();
RemoveUserGroup(76561198104673895u);
watch.Stop();
Puts($"Took {watch.ElapsedMilliseconds} ms for new unban method");
watch.Reset();
}
#endregion
}
}