C#:
//watch
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Database;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using UnityEngine;
using Oxide.Game.Rust.Cui;
using System.Text.RegularExpressions;
using Mono.Cecil;
using System.Security.Cryptography;
namespace Oxide.Plugins;
[Info("DiscordSync", "Chris", "1.0.2")]
public class DiscordSync : RustPlugin
{
void OnServerInitialized()
{
if (config == null)
{
PrintError("DiscordSync config failed to load.");
return;
}
_cleanupTimer = timer.Every(60f, CleanupExpiredTokens);
var sqlLibrary = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
var sqlConnection = sqlLibrary.OpenDb($"{config.db_host}", config.db_port, $"{config.db_database}", $"{config.db_user}", $"{config.db_pw}", this);
EnsureRustTableExists(sqlLibrary, sqlConnection);
sqlLibrary.CloseDb(sqlConnection);
}
private void Unload()
{
_cleanupTimer?.Destroy();
}
[ChatCommand("link")]
private void token_cmd(BasePlayer player)
{
if (player == null || config == null) return;
bool isLinked = permission.UserHasGroup(player.UserIDString, $"{config.group_name}");
if (isLinked)
{
player.ChatMessage("You have already linked your Discord account.");
return;
}
if (tokenCache.TryGetValue(player.userID, out var data))
{
player.ChatMessage($"Your token:<br><br><size=22><color=#4DA6FF><b>{data.Token}</b></color></size>");
return;
}
TokenSend(player);
}
class TokenData
{
public string Token;
public DateTime Timestamp;
}
Dictionary<ulong, TokenData> tokenCache = new Dictionary<ulong, TokenData>();
private Timer _cleanupTimer;
private void CleanupExpiredTokens()
{
if (config == null) return;
var now = DateTime.UtcNow;
var expiredKeys = new List<ulong>();
foreach (var kvp in tokenCache)
{
var age = now - kvp.Value.Timestamp;
if (age.TotalMinutes > config.token_valid_time)
expiredKeys.Add(kvp.Key);
}
foreach (var key in expiredKeys)
{
tokenCache.Remove(key);
DeletePair(key);
}
}
private void TokenSend(BasePlayer player)
{
if (player == null || config == null) return;
Core.MySql.Libraries.MySql sqlLibrary = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
Connection sqlConnection = sqlLibrary.OpenDb($"{config.db_host}", config.db_port, $"{config.db_database}", $"{config.db_user}", $"{config.db_pw}", this);
EnsureRustTableExists(sqlLibrary, sqlConnection);
GenerateAndInsert(player, sqlLibrary, sqlConnection);
}
private void GenerateAndInsert(BasePlayer player, Core.MySql.Libraries.MySql sqlLibrary, Connection sqlConnection)
{
string token = GenerateToken();
string sqlQuery = "SELECT * FROM discord_link_table WHERE token = @0;";
Sql selectCommand = Oxide.Core.Database.Sql.Builder.Append(sqlQuery, token);
sqlLibrary.Query(selectCommand, sqlConnection, list =>
{
if (list == null)
return;
bool tokenExists = list.Any(row => row["token"].ToString() == token);
if (tokenExists)
{
GenerateAndInsert(player, sqlLibrary, sqlConnection);
return;
}
tokenCache[player.userID] = new TokenData
{
Token = token,
Timestamp = DateTime.UtcNow
};
InsertDb(player, token);
player.ChatMessage($"Your token valid for {config.token_valid_time} minutes is:<br><br><size=22><color=#4DA6FF><b>{token}</b></color></size>");
sqlLibrary.CloseDb(sqlConnection);
});
}
private static string GenerateToken(int length = 4)
{
const string chars = "ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
var data = new byte[length];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(data);
}
var result = new char[length];
for (int i = 0; i < length; i++)
{
result[i] = chars[data[i] % chars.Length];
}
return new string(result);
}
private void EnsureRustTableExists(Core.MySql.Libraries.MySql sqlLibrary, Connection sqlConnection)
{
// id: INT(11) AUTO_INCREMENT
// user_id: TEXT
// discord_id: TEXT
// token: TEXT
string createTableSql = @"
CREATE TABLE IF NOT EXISTS `discord_link_table` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` TEXT NOT NULL,
`discord_id` TEXT NOT NULL,
`token` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
Sql createCmd = Oxide.Core.Database.Sql.Builder.Append(createTableSql);
sqlLibrary.ExecuteNonQuery(createCmd, sqlConnection, rows =>
{
Puts("Checked/created discord_link_table.");
});
}
private void InsertDb(BasePlayer player, string token)
{
Core.MySql.Libraries.MySql sqlLibrary = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
Connection sqlConnection = sqlLibrary.OpenDb($"{config.db_host}", config.db_port, $"{config.db_database}", $"{config.db_user}", $"{config.db_pw}", this);
string sqlQuery = "INSERT INTO discord_link_table (`user_id`, `token`) VALUES (@0, @1);";
Sql insertCommand = Oxide.Core.Database.Sql.Builder.Append(sqlQuery, player.UserIDString, token);
sqlLibrary.Insert(insertCommand, sqlConnection, rowsAffected =>
{
if (rowsAffected > 0)
{
Puts("New record inserted.");
}
else
{
Puts("Insert failed");
}
});
}
private void DeletePair(ulong key)
{
Core.MySql.Libraries.MySql sqlLibrary = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
Connection sqlConnection = sqlLibrary.OpenDb($"{config.db_host}", config.db_port, $"{config.db_database}", $"{config.db_user}", $"{config.db_pw}", this);
string sqlQuery = "DELETE FROM discord_link_table WHERE `user_id` = @0;";
Sql deleteCommand = Oxide.Core.Database.Sql.Builder.Append(sqlQuery, key);
sqlLibrary.Delete(deleteCommand, sqlConnection, rowsAffected =>
{
if (rowsAffected > 0)
{
//Puts("Record successfully deleted!");
}
});
sqlLibrary.CloseDb(sqlConnection);
}
private Configuration config;
protected override void LoadConfig()
{
base.LoadConfig();
config = Config.ReadObject<Configuration>();
SaveConfig();
}
protected override void LoadDefaultConfig()
{
config = Configuration.CreateConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
class Configuration
{
[JsonProperty("Host of service:")]
public string db_host {get; set;}
[JsonProperty("Port:")]
public int db_port {get; set;}
[JsonProperty("Database:")]
public string db_database {get; set;}
[JsonProperty("User:")]
public string db_user {get; set;}
[JsonProperty("Password:")]
public string db_pw {get; set;}
[JsonProperty("Token valid time (minutes):")]
public int token_valid_time {get; set;}
[JsonProperty("Name of GROUP you would like to assign:")]
public string group_name {get; set;}
public static Configuration CreateConfig()
{
return new Configuration
{
db_host = "mysql12.yourhosting.com",
db_port = 1234,
db_database = "123456_mysql12",
db_user = "123456_mysql12",
db_pw = "YourPasswordHere",
token_valid_time = 15,
group_name = "linked"
};
}
}
}