using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using UnityEngine;
using rcon.Internal;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("rcon")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("rcon")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("61cbb59f-4d68-43c3-a12e-b2edaced107d")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace rcon
{
public abstract class AbstractCommand : ICommand
{
protected BaseUnityPlugin Plugin { get; private set; }
void ICommand.setOwner(BaseUnityPlugin owner)
{
Plugin = owner;
}
public abstract string onCommand(string[] args);
}
internal interface ICommand
{
void setOwner(BaseUnityPlugin owner);
string onCommand(string[] args);
}
[BepInPlugin("nl.avii.plugins.rcon", "rcon", "1.1")]
public class rcon : BaseUnityPlugin
{
public delegate string UnknownCommand(string command, string[] args);
public delegate string ParamsAction(params object[] args);
private AsynchronousSocketListener socketListener;
private ConfigEntry<bool> Enabled;
private ConfigEntry<int> Port;
private ConfigEntry<string> Password;
private Dictionary<string, Type> commands = new Dictionary<string, Type>();
private Dictionary<string, ParamsAction> customCommands = new Dictionary<string, ParamsAction>();
private Dictionary<string, BaseUnityPlugin> owners = new Dictionary<string, BaseUnityPlugin>();
public event UnknownCommand OnUnknownCommand;
private rcon()
{
Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("rcon", "enabled", false, "Enable RCON Communication");
Port = ((BaseUnityPlugin)this).Config.Bind<int>("rcon", "port", 2458, "Port to use for RCON Communication");
Password = ((BaseUnityPlugin)this).Config.Bind<string>("rcon", "password", "ChangeMe", "Password to use for RCON Communication");
}
private void OnEnable()
{
if (Enabled.Value)
{
socketListener = new AsynchronousSocketListener();
socketListener.OnMessage += SocketListener_OnMessage;
((BaseUnityPlugin)this).Logger.LogInfo((object)("RCON Listening on port: " + Port.Value));
socketListener.StartListening(Port.Value);
}
}
private void SocketListener_OnMessage(Socket socket, int requestId, PacketType type, string payload)
{
switch (type)
{
case PacketType.Login:
{
string payload4 = "Login Success";
if (payload.Trim() != Password.Value.Trim())
{
payload4 = "Login Failed";
requestId = -1;
}
byte[] buffer = PacketBuilder.CreatePacket(requestId, PacketType.Command, payload4);
socket.Send(buffer);
break;
}
case PacketType.Command:
{
if (payload[0] == '/')
{
payload = payload.Substring(1);
}
List<string> list = (from Match m in Regex.Matches(payload, "(?<=[ ][\\\"]|^[\\\"])[^\\\"]+(?=[\\\"][ ]|[\\\"]$)|(?<=[ ]|^)[^\\\" ]+(?=[ ]|$)")
select m.Value).ToList();
string text = list[0].ToLower();
list.RemoveAt(0);
if (!commands.ContainsKey(text) && !customCommands.ContainsKey(text))
{
string text2 = this.OnUnknownCommand?.Invoke(text, list.ToArray());
PacketType type2 = PacketType.Command;
if (text2.ToLower().Contains("unknown"))
{
type2 = PacketType.Error;
}
socket.Send(PacketBuilder.CreatePacket(requestId, type2, text2));
}
else if (commands.ContainsKey(text))
{
ICommand obj = (ICommand)Activator.CreateInstance(commands[text]);
obj.setOwner(owners[text]);
string payload2 = obj.onCommand(list.ToArray());
socket.Send(PacketBuilder.CreatePacket(requestId, type, payload2));
}
else if (customCommands.ContainsKey(text))
{
ParamsAction paramsAction = customCommands[text];
object[] args = list.ToArray();
string payload3 = paramsAction(args);
socket.Send(PacketBuilder.CreatePacket(requestId, type, payload3));
}
break;
}
default:
((BaseUnityPlugin)this).Logger.LogError((object)$"Unknown packet type: {type}");
break;
}
}
private void Update()
{
if (Enabled.Value && socketListener != null)
{
socketListener.Update();
}
}
private void OnDisable()
{
if (Enabled.Value)
{
socketListener.Close();
}
}
public void RegisterCommand<T>(BaseUnityPlugin owner, string command) where T : AbstractCommand, new()
{
command = command.ToLower();
if (owners.ContainsKey(command))
{
((BaseUnityPlugin)this).Logger.LogError((object)(command + " already registered"));
return;
}
owners[command] = owner;
commands[command] = typeof(T);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Registering Command: " + command));
}
public void RegisterCommand(BaseUnityPlugin owner, string command, ParamsAction action)
{
command = command.ToLower();
if (owners.ContainsKey(command))
{
((BaseUnityPlugin)this).Logger.LogError((object)(command + " already registered"));
return;
}
owners[command] = owner;
customCommands[command] = action;
((BaseUnityPlugin)this).Logger.LogInfo((object)("Registering Command: " + command));
}
public void UnRegisterCommand(BaseUnityPlugin owner, string command)
{
if (owners.ContainsKey(command) && !((Object)(object)owners[command] != (Object)(object)owner))
{
owners.Remove(command);
if (commands.ContainsKey(command))
{
commands.Remove(command);
}
if (customCommands.ContainsKey(command))
{
customCommands.Remove(command);
}
}
}
}
}
namespace rcon.Internal
{
internal static class PacketBuilder
{
internal static byte[] CreatePacket(int requestId, PacketType type, string payload)
{
int num = 12 + payload.Length + 2;
int num2 = 8 + payload.Length + 2;
byte[] array = new byte[num];
array[0] = (byte)num2;
array[4] = (byte)requestId;
array[8] = (byte)type;
for (int i = 0; i < payload.Length; i++)
{
array[12 + i] = (byte)payload[i];
}
return array;
}
}
internal class AsynchronousSocketListener
{
internal delegate void MessageReceived(Socket socket, int requestId, PacketType type, string payload);
private Socket listener;
private List<StateObject> clients = new List<StateObject>();
internal event MessageReceived OnMessage;
internal void StartListening(int port)
{
IPAddress any = IPAddress.Any;
IPEndPoint localEP = new IPEndPoint(any, port);
listener = new Socket(any.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEP);
listener.Listen(100);
}
catch (Exception ex)
{
Debug.LogError((object)ex.ToString());
}
}
private bool isConnected(Socket c)
{
try
{
if (c != null && c != null && c.Connected)
{
if (c.Poll(0, SelectMode.SelectRead))
{
return c.Receive(new byte[1], SocketFlags.Peek) != 0;
}
return true;
}
return false;
}
catch
{
return false;
}
}
internal void Update()
{
for (int i = 0; i < clients.Count; i++)
{
StateObject stateObject = clients[i];
if (!isConnected(stateObject.workSocket))
{
Debug.Log((object)"Rcon client disconnected");
stateObject.workSocket.Close();
clients.Remove(stateObject);
}
}
listener.BeginAccept(AcceptCallback, listener);
}
internal void AcceptCallback(IAsyncResult ar)
{
Socket socket = ((Socket)ar.AsyncState).EndAccept(ar);
StateObject stateObject = new StateObject();
stateObject.workSocket = socket;
clients.Add(stateObject);
Debug.Log((object)"Rcon client connected");
socket.BeginReceive(stateObject.buffer, 0, 4096, SocketFlags.None, ReadCallback, stateObject);
}
private void ReadCallback(IAsyncResult ar)
{
_ = string.Empty;
StateObject stateObject = (StateObject)ar.AsyncState;
Socket workSocket = stateObject.workSocket;
workSocket.EndReceive(ar);
int num = BitConverter.ToInt32(stateObject.buffer, 0);
int requestId = BitConverter.ToInt32(stateObject.buffer, 4);
int type = BitConverter.ToInt32(stateObject.buffer, 8);
num -= 10;
byte[] array = new byte[num];
for (int i = 0; i < num; i++)
{
array[i] = stateObject.buffer[12 + i];
}
this.OnMessage?.Invoke(workSocket, requestId, (PacketType)type, Encoding.ASCII.GetString(array));
stateObject.buffer = new byte[4096];
workSocket.BeginReceive(stateObject.buffer, 0, 4096, SocketFlags.None, ReadCallback, stateObject);
}
private void Send(Socket handler, string data)
{
byte[] bytes = Encoding.ASCII.GetBytes(data);
handler.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendCallback, handler);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket obj = (Socket)ar.AsyncState;
int num = obj.EndSend(ar);
Debug.Log((object)$"Sent {num} bytes to client.");
obj.Shutdown(SocketShutdown.Both);
obj.Close();
}
catch (Exception ex)
{
Debug.LogError((object)ex.ToString());
}
}
internal void Close()
{
if (!listener.Connected)
{
return;
}
foreach (StateObject client in clients)
{
if (isConnected(client.workSocket))
{
client.workSocket.Close();
}
}
listener.Close();
}
}
internal enum PacketType
{
Error = -1,
MultiPacket = 0,
Command = 2,
LoginResponse = 2,
Login = 3
}
internal class StateObject
{
internal const int BufferSize = 4096;
internal byte[] buffer = new byte[4096];
internal Socket workSocket;
}
}