Skip to content

Commit 7571153

Browse files
Implemented stat tracking into the server plugin
- Implemented stat tracking directly into the plugin! - BotCommands_Dynamo.exe is called from the plugin file when a player leaves the server to update the stats database - Significant code cleanup - Changed config file to use current directory as default location for botcmd.txt - botcmd.txt is created on server launch if it doesn't exist
1 parent 2565dc7 commit 7571153

File tree

11 files changed

+637
-50
lines changed

11 files changed

+637
-50
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,3 +348,5 @@ MigrationBackup/
348348

349349
# Ionide (cross platform F# VS Code tools) working folder
350350
.ionide/
351+
.idea
352+
lib

BotCommands.cs

Lines changed: 121 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,83 @@
1-
using System.IO;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics;
4+
using System.IO;
5+
using System.Linq;
6+
using System.Reflection;
27
using BepInEx;
38
using BepInEx.Configuration;
9+
using BepInEx.Logging;
410
using UnityEngine;
511
using RoR2;
612
using RoR2.Stats;
713
using UnityEngine.Networking;
814
using System.Threading.Tasks;
15+
using Console = RoR2.Console;
16+
using Debug = UnityEngine.Debug;
17+
using Path = System.IO.Path;
918

1019

1120
namespace BotCMDs
1221
{
1322
[BepInDependency("com.bepis.r2api")]
14-
[BepInPlugin("com.Rayss.BotCommands", "BotCommands", "0.2.0")]
23+
[BepInPlugin("com.Rayss.BotCommands", "BotCommands", "0.3.0")]
1524
public class BotCommands : BaseUnityPlugin
1625
{
1726
// Config
1827
private static ConfigEntry<string> Cmdpath { get; set; }
19-
private string botcmd_path;
28+
private string _botcmdPath;
29+
private static ConfigEntry<string> Servername { get; set; }
30+
private static string _serverName;
31+
// Create custom log source
32+
private static ManualLogSource Log = new ManualLogSource("BotCommands");
2033

2134
[System.Diagnostics.CodeAnalysis.SuppressMessage("Code Quality", "IDE0051:Remove unused private members")]
2235
private void Awake()
2336
{
37+
// Register custom log source
38+
BepInEx.Logging.Logger.Sources.Add(Log);
39+
40+
// Path is the current path of the .DLL
41+
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
2442
Cmdpath = Config.Bind<string>(
25-
"Config",
26-
"botcmd",
27-
"C:/Program Files (x86)/Steam/steamapps/common/Risk of Rain 2 Dedicated Server/BepInEx/plugins/botcmd.txt",
28-
"Insert the path of your botcmd.txt"
43+
"Config",
44+
"botcmd",
45+
path + @"\botcmd.txt",
46+
"Insert the path of your botcmd.txt"
2947
);
30-
botcmd_path = Cmdpath.Value;
48+
_botcmdPath = Cmdpath.Value;
49+
Servername = Config.Bind<string>(
50+
"Config",
51+
"Server Name",
52+
"Server1",
53+
"Enter the name of your server for stats tracking"
54+
);
55+
_serverName = Servername.Value;
3156

32-
Debug.Log("Created by Rayss and InfernalPlacebo.");
57+
Log.LogInfo("Created by Rayss and InfernalPlacebo.");
58+
#if DEBUG
59+
Log.LogWarning("You are using a debug build!");
60+
#endif
3361
}
3462

3563
[System.Diagnostics.CodeAnalysis.SuppressMessage("Code Quality", "IDE0051:Remove unused private members")]
3664
private void Start()
3765
{
3866
StartHooks();
3967
Reading();
68+
OpenExe();
4069
}
4170

4271
private async void Reading()
4372
{
44-
using (StreamReader reader = new StreamReader(new FileStream(botcmd_path,
73+
// Create botcmd.txt if it doesn't exist yet
74+
using (StreamWriter w = File.AppendText(_botcmdPath))
75+
76+
using (StreamReader reader = new StreamReader(new FileStream(_botcmdPath,
4577
FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
4678
{
4779
//start at the end of the file
4880
long lastMaxOffset = reader.BaseStream.Length;
49-
string line;
5081

5182
while (true)
5283
{
@@ -56,6 +87,7 @@ private async void Reading()
5687
reader.BaseStream.Seek(lastMaxOffset, SeekOrigin.Begin);
5788

5889
//read out of the file until the EOF
90+
string line;
5991
while ((line = reader.ReadLine()) != null)
6092
{
6193
// Exception handling, I guess
@@ -65,7 +97,7 @@ private async void Reading()
6597
}
6698
catch
6799
{
68-
Debug.Log("No sir, partner.");
100+
Log.LogWarning("No sir, partner.");
69101
}
70102
}
71103

@@ -75,8 +107,7 @@ private async void Reading()
75107
}
76108
}
77109

78-
79-
public static void StartHooks()
110+
private static void StartHooks()
80111
{
81112
// On run end
82113
// LogTime and LogStagesCleared won't be needed after stats are done
@@ -115,23 +146,19 @@ public static void StartHooks()
115146
On.RoR2.FadeToBlackManager.OnSceneUnloaded += (orig, run) =>
116147
{
117148
orig(run);
118-
if (Run.instance)
119-
{
120-
LogTime();
121-
LogStagesCleared();
122-
}
149+
if (!Run.instance) return;
150+
LogTime();
151+
LogStagesCleared();
123152
};
124153

125154
// On player join
126155
// Will be removed on new stat tracking
127156
On.RoR2.Networking.GameNetworkManager.OnServerConnect += (orig, run, conn) =>
128157
{
129158
orig(run, conn);
130-
if (Run.instance)
131-
{
132-
LogTime();
133-
LogStagesCleared();
134-
}
159+
if (!Run.instance) return;
160+
LogTime();
161+
LogStagesCleared();
135162
};
136163
}
137164

@@ -158,33 +185,93 @@ private static void LogStagesCleared()
158185
private static void GetStats(NetworkUser user)
159186
{
160187
GameObject playerMasterObject = user.masterObject;
188+
long steamId = System.Convert.ToInt64(user.id.steamId.ToString());
161189
StatSheet statSheet;
162190
PlayerStatsComponent component = playerMasterObject.GetComponent<PlayerStatsComponent>();
163191
statSheet = (component?.currentStats);
164-
// Print the statsheet to console / log
165-
// Will be changing this to parse and add to the database
192+
List<string> listOfStatNames = new List<string>
193+
{
194+
"totalTimeAlive",
195+
"totalKills",
196+
"totalDeaths",
197+
"totalGoldCollected",
198+
"totalDistanceTraveled",
199+
"totalItemsCollected",
200+
"totalStagesCompleted",
201+
"totalPurchases"
202+
};
203+
Dictionary<string, string> outputStats = new Dictionary<string, string>();
204+
Dictionary<string, string> sendToDynamo = new Dictionary<string, string>();
166205
// Don't need all the stats they access though, should only use some of the fields (may be able to split up by category)
167206
string[] array = new string[statSheet.fields.Length];
168207
for (int i = 0; i < array.Length; i++)
169208
{
170209
array[i] = string.Format("[\"{0}\"]={1}", statSheet.fields[i].name, statSheet.fields[i].ToString());
210+
outputStats[statSheet.fields[i].name] = statSheet.fields[i].ToString();
211+
}
212+
foreach (var kvp in outputStats.Where(kvp => listOfStatNames.Contains(kvp.Key)))
213+
{
214+
sendToDynamo[kvp.Key] = kvp.Value;
215+
}
216+
// Debug.Log(string.Join("\n", array)); <<<<< Used for seeing all the stat options
217+
// Argument organization: serverName, ID, timeAlive, kills, deaths, goldCollected, distanceTraveled, itemsCollected, stagesCompleted, purchases
218+
// Use ProcessStartInfo class
219+
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
220+
ProcessStartInfo startInfo = new ProcessStartInfo();
221+
startInfo.CreateNoWindow = true;
222+
startInfo.UseShellExecute = false;
223+
startInfo.FileName = path + @"\BotCommands_Dynamo.exe";
224+
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
225+
startInfo.Arguments = string.Format("{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}", _serverName, steamId,
226+
sendToDynamo["totalTimeAlive"], sendToDynamo["totalKills"], sendToDynamo["totalDeaths"],
227+
sendToDynamo["totalGoldCollected"], sendToDynamo["totalDistanceTraveled"],
228+
sendToDynamo["totalItemsCollected"], sendToDynamo["totalStagesCompleted"],
229+
sendToDynamo["totalPurchases"]);
230+
231+
try
232+
{
233+
// Start the process with the info we specified.
234+
using (Process exeProcess = Process.Start(startInfo))
235+
{
236+
Log.LogInfo("BotCommands: Updating stats database!");
237+
}
238+
}
239+
catch
240+
{
241+
Log.LogError("BotCommands: Unable to find executable file!");
171242
}
172-
// Literally all I have to do is parse the array to be used by the db
173-
Debug.Log(string.Join("\n", array));
174243
}
175244

176-
// Borrowed from R2DSEssentials.Util.Networking
177-
private static NetworkUser FindNetworkUserForConnectionServer(NetworkConnection connection)
245+
// Used for debugging database
246+
[Conditional("DEBUG")]
247+
private static void OpenExe()
178248
{
179-
foreach (var networkUser in NetworkUser.readOnlyInstancesList)
249+
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
250+
ProcessStartInfo startInfo = new ProcessStartInfo();
251+
startInfo.CreateNoWindow = true;
252+
startInfo.UseShellExecute = false;
253+
startInfo.FileName = path + @"\BotCommands_Dynamo.exe";
254+
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
255+
startInfo.Arguments = "server9 123456789 100 100 100 100 100 100 100 100";
256+
257+
try
180258
{
181-
if (networkUser.connectionToClient == connection)
259+
// Start the process with the info we specified.
260+
using (Process exeProcess = Process.Start(startInfo))
182261
{
183-
return networkUser;
262+
Log.LogWarning("BotCommands: Updating stats database!");
184263
}
185264
}
265+
catch
266+
{
267+
Log.LogError("BotCommands: Unable to find executable file!");
268+
}
269+
}
186270

187-
return null;
271+
// Borrowed from R2DSEssentials.Util.Networking
272+
private static NetworkUser FindNetworkUserForConnectionServer(NetworkConnection connection)
273+
{
274+
return NetworkUser.readOnlyInstancesList.FirstOrDefault(networkUser => networkUser.connectionToClient == connection);
188275
}
189276
}
190277
}

BotCommands.csproj

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
<TargetFramework>netstandard2.0</TargetFramework>
55
</PropertyGroup>
66

7+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
8+
<DocumentationFile>bin\Release\BotCommands.xml</DocumentationFile>
9+
</PropertyGroup>
10+
711
<ItemGroup>
812
<Reference Include="0Harmony">
913
<HintPath>..\misc\libs\0Harmony.dll</HintPath>
@@ -68,9 +72,18 @@
6872
<Reference Include="UnityEngine.Networking">
6973
<HintPath>..\misc\libs\UnityEngine.Networking.dll</HintPath>
7074
</Reference>
71-
<Reference Include="UnityEngine.UnityWebRequestModule">
72-
<HintPath>..\misc\libs\UnityEngine.UnityWebRequestModule.dll</HintPath>
73-
</Reference>
75+
</ItemGroup>
76+
77+
<ItemGroup>
78+
<Compile Remove="Dynamo\**" />
79+
</ItemGroup>
80+
81+
<ItemGroup>
82+
<EmbeddedResource Remove="Dynamo\**" />
83+
</ItemGroup>
84+
85+
<ItemGroup>
86+
<None Remove="Dynamo\**" />
7487
</ItemGroup>
7588

7689
</Project>

BotCommands.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29613.14
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotCommands", "BotCommands.csproj", "{9F3855A7-02AB-4E44-A337-F4594A1D2148}"
77
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotCommands_Dynamo", "Dynamo\BotCommands_Dynamo.csproj", "{5D6B7655-F5A9-4CAA-B697-83AFBF54B10D}"
9+
EndProject
810
Global
911
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1012
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +17,10 @@ Global
1517
{9F3855A7-02AB-4E44-A337-F4594A1D2148}.Debug|Any CPU.Build.0 = Debug|Any CPU
1618
{9F3855A7-02AB-4E44-A337-F4594A1D2148}.Release|Any CPU.ActiveCfg = Release|Any CPU
1719
{9F3855A7-02AB-4E44-A337-F4594A1D2148}.Release|Any CPU.Build.0 = Release|Any CPU
20+
{5D6B7655-F5A9-4CAA-B697-83AFBF54B10D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21+
{5D6B7655-F5A9-4CAA-B697-83AFBF54B10D}.Debug|Any CPU.Build.0 = Debug|Any CPU
22+
{5D6B7655-F5A9-4CAA-B697-83AFBF54B10D}.Release|Any CPU.ActiveCfg = Release|Any CPU
23+
{5D6B7655-F5A9-4CAA-B697-83AFBF54B10D}.Release|Any CPU.Build.0 = Release|Any CPU
1824
EndGlobalSection
1925
GlobalSection(SolutionProperties) = preSolution
2026
HideSolutionNode = FALSE

Dynamo/BotCommands_Dynamo.csproj

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp3.1</TargetFramework>
5+
<OutputType>Exe</OutputType>
6+
<LangVersion>8</LangVersion>
7+
<AssemblyVersion>1.0.0</AssemblyVersion>
8+
<FileVersion>1.0.0</FileVersion>
9+
<NeutralLanguage>en-US</NeutralLanguage>
10+
</PropertyGroup>
11+
12+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
13+
<DocumentationFile>bin\Release\BotCommands_Dynamo.xml</DocumentationFile>
14+
</PropertyGroup>
15+
16+
<ItemGroup>
17+
<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.3.105.26" />
18+
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
19+
</ItemGroup>
20+
21+
<ItemGroup>
22+
<Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604">
23+
<HintPath>..\lib\AWSSDK.Core.dll</HintPath>
24+
</Reference>
25+
<Reference Include="AWSSDK.DynamoDBv2, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604">
26+
<HintPath>..\lib\AWSSDK.DynamoDBv2.dll</HintPath>
27+
</Reference>
28+
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
29+
<HintPath>..\lib\Newtonsoft.Json.dll</HintPath>
30+
</Reference>
31+
</ItemGroup>
32+
33+
</Project>

0 commit comments

Comments
 (0)