RCON Support (#96)

* Added RCON dotnet submodule

* RCON Manager

* RCON works

* Switched inter-thread passing from tasks callbacks to BlockingCollection

* Cleanup

* Config based rcon port and password

* RCON is disabled by default in config

* Added SanAndreasUnity.RCON namespace to CommandInterpreter

* Pass command to main thread first and report progress afterwards

* Minor cleanup

* Removed InvalidOperationException as it was never possible

* Moved OnLoaderFinished code in RCONManager

* Added RCONManager script to prefab

* Added meta files
This commit is contained in:
Antonio Alexandru Ganea 2020-11-02 00:51:03 +02:00 committed by GitHub
parent 29d5a04db9
commit c3aebc3826
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 197 additions and 3 deletions

3
.gitmodules vendored
View file

@ -4,3 +4,6 @@
[submodule "Assets/UnityStandardAssets"]
path = Assets/UnityStandardAssets
url = https://github.com/GTA-ASM/UnityStandardAssets
[submodule "Assets/RCONdotnet"]
path = Assets/RCONdotnet
url = https://github.com/undbsd/rcon-dotnet

View file

@ -24,6 +24,7 @@ GameObject:
- component: {fileID: 1318502437576191535}
- component: {fileID: 7442340376164908290}
- component: {fileID: 8446601354455743255}
- component: {fileID: 5853763562556677784}
m_Layer: 0
m_Name: GameManager
m_TagString: Untagged
@ -299,3 +300,15 @@ MonoBehaviour:
type: 3}
messagesContainer: {fileID: 0}
messagePoolSize: 10
--- !u!114 &5853763562556677784
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1297494511425690}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c77317cdc437f244b8d409c229aa2e95, type: 3}
m_Name:
m_EditorClassIdentifier:

1
Assets/RCONdotnet Submodule

@ -0,0 +1 @@
Subproject commit b5e93d94fd0a3b46dd19e3d62cf427f72f58ed40

8
Assets/RCONdotnet.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: be08b0c2aac61f94f8676008c1f1a546
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -10,7 +10,7 @@
"sv_max_connections": 32,
"sv_port": 14242,
"game_dir" : "",
"game_dir": "",
"archive_paths": [
"${game_dir}/models/gta3.img",
@ -35,10 +35,13 @@
"water_path": "${game_dir}/data/water.dat",
"car_colors_path": "${game_dir}/data/carcols.dat",
"anim_groups_paths": [
"${game_dir}/data/animgrp.dat",
"${game_dir}/data/animgrp.dat"
],
"weapons_path": "${game_dir}/data/weapon.dat",
"dontLoadTextures": false,
"RCON_enabled": false,
"RCON_password": "super_secret_password",
"RCON_port": 25575
}

8
Assets/Scripts/RCON.meta Normal file
View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 381eb0e589457424db93a1587f86f9eb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,36 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace SanAndreasUnity.RCON
{
public class CommandInterpreter
{
public static String Interpret(String command)
{
string[] words = command.Split(' ');
if (command == "heartbeat")
{
// Implement heartbeat ping
return "Heartbeat was sent to master server";
}
if (command == "help")
{
return "The available commands for now are heartbeat, announce and help";
}
if (words[0] == "announce")
{
String announcement = String.Join(" ", words, 1, words.Length - 1);
SanAndreasUnity.Chat.ChatManager.SendChatMessageToAllPlayersAsServer(announcement);
return "Server : " + announcement;
}
return "Unknown command";
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9cf8ca8374941dd4aaa862202a1a2b7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,100 @@
using Rcon;
using Rcon.Events;
using SanAndreasUnity.Net;
using SanAndreasUnity.Utilities;
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Threading.Tasks;
using UnityEngine;
namespace SanAndreasUnity.RCON
{
public class RCONManager : MonoBehaviour
{
// Todo : set these from config
private static String password;
private static int portNumber;
// Objects used to pass commands and responses between threads
private static BlockingCollection<String> mainToSec = new BlockingCollection<String>(1);
private static BlockingCollection<String> secToMain = new BlockingCollection<String>(1);
private static BackgroundWorker workerInstance = null;
public static void StartServer()
{
password = Config.Get<string>("RCON_password");
portNumber = Config.Get<int>("RCON_port");
if (workerInstance != null)
return;
workerInstance = new BackgroundWorker();
workerInstance.DoWork += new DoWorkEventHandler( worker_doWork );
workerInstance.ProgressChanged += new ProgressChangedEventHandler( worker_progressChanged );
workerInstance.WorkerReportsProgress = true;
// workerInstance.WorkerSupportsCancellation = true;
workerInstance.RunWorkerAsync(); // Call the background worker
}
#region Code that runs in the RCON Server Thread
private static void worker_doWork(object sender, DoWorkEventArgs e)
{
using (RconServer server = new RconServer(password, portNumber))
{
server.OnClientCommandReceived += Server_OnClientCommandReceived;
server.OnClientConnected += Server_OnClientConnected;
server.OnClientAuthenticated += Server_OnClientAuthenticated;
server.OnClientDisconnected += Server_OnClientDisconnected;
server.Start();
}
}
static void Server_OnClientAuthenticated(object sender, ClientAuthenticatedEventArgs e)
{
// Console.WriteLine("{0} authenticated", e.Client.Client.LocalEndPoint);
}
static void Server_OnClientDisconnected(object sender, ClientDisconnectedEventArgs e)
{
// Console.WriteLine("{0} disconnected", e.EndPoint);
}
static void Server_OnClientConnected(object sender, ClientConnectedEventArgs e)
{
// Console.WriteLine("{0} connected", e.Client.Client.LocalEndPoint);
}
static string Server_OnClientCommandReceived(object sender, ClientSentCommandEventArgs e)
{
secToMain.Add(e.Command); // Pass the command to the main thread
workerInstance.ReportProgress(0); //Report our progress to the main thread
String commandResult = "Command didn't process correctly"; // default value
commandResult = mainToSec.Take();
return commandResult;
}
#endregion
// Runs in main thread
private static void worker_progressChanged(object sender, ProgressChangedEventArgs e)
{
String command = "unknown";
command = secToMain.Take();
mainToSec.Add(CommandInterpreter.Interpret(command));
}
void OnLoaderFinished()
{
if (NetStatus.IsServer)
{
if (Config.Get<bool>("RCON_enabled"))
StartServer();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c77317cdc437f244b8d409c229aa2e95
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: