Skip to content

Commit ea29ca9

Browse files
authored
Update to v1.0.1
Errors fixed. Added hook for ending demo recording
1 parent 196ab8e commit ea29ca9

File tree

1 file changed

+166
-144
lines changed

1 file changed

+166
-144
lines changed

DemoRecorder/DemoRecorder.cs

Lines changed: 166 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,153 +1,177 @@
1-
using CounterStrikeSharp.API;
2-
using CounterStrikeSharp.API.Core;
3-
using CounterStrikeSharp.API.Core.Attributes.Registration;
4-
using CounterStrikeSharp.API.Modules.Admin;
5-
using CounterStrikeSharp.API.Modules.Commands;
6-
using CounterStrikeSharp.API.Modules.Config;
7-
using CounterStrikeSharp.API.Modules.Utils;
8-
using CounterStrikeSharp.API.Modules.Cvars;
9-
using Microsoft.Extensions.Logging;
10-
11-
namespace DemoRecorder;
12-
13-
public class DemoRecorder : BasePlugin, IPluginConfig<PluginConfig>
14-
{
15-
public override string ModuleName { get; } = "DemoRecorder";
16-
public override string ModuleVersion { get; } = "1.0.0";
17-
public override string ModuleAuthor { get; } = "SAPSAN";
18-
19-
public PluginConfig Config { get; set; }
20-
21-
public List<CCSPlayerController> connectedPlayers = new List<CCSPlayerController>();
22-
23-
public string g_sDemosName = "",
24-
g_sDemosDir = "",
25-
g_sServerName = "";
26-
27-
public bool g_bChangeMap, bOldState;
28-
29-
public void OnConfigParsed(PluginConfig config)
30-
{
31-
config = ConfigManager.Load<PluginConfig>(ModuleName);
32-
Config = config;
33-
}
34-
35-
public override void Load(bool hotReload)
36-
{
37-
RegisterEventHandler<EventCsIntermission>(OnEventCsIntermissionPost);
38-
RegisterListener<Listeners.OnMapStart>(OnMapStartHandler);
39-
RegisterListener<Listeners.OnMapEnd>(OnMapEndHandler);
40-
41-
g_sDemosDir = Directory.GetCurrentDirectory().Replace("bin/linuxsteamrt64", "");
42-
Directory.SetCurrentDirectory(g_sDemosDir);
43-
44-
g_sServerName = ConVar.Find("hostname").StringValue;
45-
46-
g_sDemosDir += "/csgo/addons/counterstrikesharp/data/" + Config.DemosDir;
47-
48-
if (!Directory.Exists(g_sDemosDir))
49-
{
50-
Logger.LogInformation(">> Create folder for demos: {Folder}.", g_sDemosDir);
51-
52-
Directory.CreateDirectory(g_sDemosDir);
53-
}
54-
g_sDemosName = new string(DateTime.Now.ToString("dd_MM_yyyy_HH_mm") + "-" + Server.MapName + ".dem");
55-
56-
UploadAllDemos();
57-
}
58-
59-
[GameEventHandler(mode: HookMode.Post)]
60-
private HookResult OnEventCsIntermissionPost(EventCsIntermission @event, GameEventInfo info)
61-
{
62-
RecordDemo(false, true);
1+
using CounterStrikeSharp.API;
2+
using CounterStrikeSharp.API.Core;
3+
using CounterStrikeSharp.API.Core.Attributes.Registration;
4+
using CounterStrikeSharp.API.Modules.Admin;
5+
using CounterStrikeSharp.API.Modules.Commands;
6+
using CounterStrikeSharp.API.Modules.Config;
7+
using CounterStrikeSharp.API.Modules.Utils;
8+
using CounterStrikeSharp.API.Modules.Memory.DynamicFunctions;
9+
using Microsoft.Extensions.Logging;
10+
using System.Runtime.InteropServices;
11+
12+
namespace DemoRecorder;
13+
14+
public class DemoRecorder : BasePlugin, IPluginConfig<PluginConfig>
15+
{
16+
public override string ModuleName { get; } = "DemoRecorder";
17+
public override string ModuleVersion { get; } = "1.0.1";
18+
public override string ModuleAuthor { get; } = "SAPSAN";
19+
public required PluginConfig Config { get; set; }
20+
21+
public List<CCSPlayerController> connectedPlayers = new();
22+
23+
private static string g_sDemosName = new (DateTime.Now.ToString("dd_MM_yyyy_HH_mm") + "-" + Server.MapName + ".dem"),
24+
g_sDemosDir = Server.GameDirectory;
25+
26+
private static readonly string g_BinaryPath = g_sDemosDir + "/bin/" + (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linuxsteamrt64/libengine2.so" : "win64/engine2.dll"),
27+
g_Signature = RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
28+
? @"\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x4C\x8D\x67\x08"
29+
: @"\x40\x55\x56\x41\x57\x48\x8D\x6C\x24\x00\x48\x81\xEC\x00\x00\x00\x00\x80\xB9\x00\x00\x00\x00\x00";
30+
31+
public bool g_bChangeMap, bOldState, g_bState;
32+
33+
public MemoryFunctionVoid<IntPtr, IntPtr> RecordEnd = new(g_Signature, g_BinaryPath);
34+
35+
private HookResult RecordEndHookResult(DynamicHook hook)
36+
{
37+
Task.Delay(1000).ContinueWith((task) =>
38+
{
39+
UploadDemo(g_sDemosDir + g_sDemosName, g_bState);
40+
});
41+
return HookResult.Continue;
42+
}
43+
44+
public void OnConfigParsed(PluginConfig config)
45+
{
46+
config = ConfigManager.Load<PluginConfig>(ModuleName);
47+
Config = config;
48+
49+
g_sDemosDir = Server.GameDirectory + "/csgo/addons/counterstrikesharp/data/" + Config.DemosDir;
50+
CreateDemoDir();
51+
}
52+
53+
public override void Load(bool hotReload)
54+
{
55+
Directory.SetCurrentDirectory(Server.GameDirectory);
56+
57+
CreateDemoDir();
58+
59+
RecordEnd.Hook(RecordEndHookResult, HookMode.Post);
60+
61+
RegisterEventHandler<EventCsIntermission>(OnEventCsIntermissionPost);
62+
RegisterListener<Listeners.OnMapStart>(OnMapStartHandler);
63+
RegisterListener<Listeners.OnMapEnd>(OnMapEndHandler);
64+
UploadAllDemos();
65+
}
66+
67+
public override void Unload (bool hotReload)
68+
{
69+
RecordEnd.Unhook(RecordEndHookResult, HookMode.Post);
70+
}
71+
72+
[GameEventHandler(mode: HookMode.Post)]
73+
private HookResult OnEventCsIntermissionPost(EventCsIntermission @event, GameEventInfo info)
74+
{
75+
g_bState = true;
76+
RecordDemo(false);
6377
g_bChangeMap = true;
64-
return HookResult.Continue;
65-
}
66-
67-
[RequiresPermissions("@css/root")]
68-
[ConsoleCommand("css_dr_reload")]
69-
public void OnReloadCommand(CCSPlayerController? controller, CommandInfo info)
70-
{
71-
OnConfigParsed(Config);
72-
Logger.LogInformation(">> Config reloaded!");
73-
controller?.PrintToChat($" {ChatColors.Red}[Demo Recorder] {ChatColors.Default}Config reloaded {ChatColors.Green}success{ChatColors.Default}!");
74-
}
75-
76-
[GameEventHandler]
77-
public HookResult OnPlayerConnectedFull(EventPlayerConnectFull @event, GameEventInfo info)
78-
{
79-
var player = @event.Userid;
80-
81-
if (!player.IsBot)
82-
{
83-
connectedPlayers.Add(player);
84-
78+
return HookResult.Continue;
79+
}
80+
81+
[RequiresPermissions("@css/root")]
82+
[ConsoleCommand("css_dr_reload")]
83+
public void OnReloadCommand(CCSPlayerController? controller, CommandInfo info)
84+
{
85+
OnConfigParsed(Config);
86+
Logger.LogInformation(">> Config reloaded!");
87+
controller?.PrintToChat($" {ChatColors.Red}[Demo Recorder] {ChatColors.Default}Config reloaded {ChatColors.Green}success{ChatColors.Default}!");
88+
}
89+
90+
[GameEventHandler]
91+
public HookResult OnPlayerConnectedFull(EventPlayerConnectFull @event, GameEventInfo info)
92+
{
93+
var player = @event.Userid;
94+
95+
if (!player.IsBot)
96+
{
97+
connectedPlayers.Add(player);
98+
8599
if (GetActivePlayerCount() >= Config.MinOnline)
86100
{
87-
RecordDemo(true, false);
101+
g_bState = false;
102+
RecordDemo(true);
88103
}
89-
return HookResult.Continue;
90-
}
91-
return HookResult.Continue;
92-
}
93-
94-
[GameEventHandler]
95-
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
96-
{
97-
var player = @event.Userid;
98-
99-
connectedPlayers.Remove(player);
100-
104+
return HookResult.Continue;
105+
}
106+
return HookResult.Continue;
107+
}
108+
109+
[GameEventHandler]
110+
public HookResult OnPlayerDisconnect(EventPlayerDisconnect @event, GameEventInfo info)
111+
{
112+
var player = @event.Userid;
113+
114+
connectedPlayers.Remove(player);
115+
101116
if (GetActivePlayerCount() < Config.MinOnline)
102117
{
103-
RecordDemo(false, true);
118+
g_bState = true;
119+
RecordDemo(false);
104120

105-
}
106-
return HookResult.Continue;
107-
}
108-
private void OnMapStartHandler(string mapName)
109-
{
110-
g_bChangeMap = false;
111-
g_sDemosName = new string(DateTime.Now.ToString("dd_MM_yyyy_HH_mm") + "-" + mapName + ".dem");
121+
}
122+
return HookResult.Continue;
112123
}
113124

114-
private void OnMapEndHandler()
115-
{
125+
private void OnMapStartHandler(string mapName)
126+
{
127+
g_bChangeMap = false;
128+
g_sDemosName = new string(DateTime.Now.ToString("dd_MM_yyyy_HH_mm") + "-" + mapName + ".dem");
129+
}
130+
131+
private void CreateDemoDir()
132+
{
133+
if (!Directory.Exists(g_sDemosDir))
134+
{
135+
Logger.LogInformation(">> Create folder for demos: {Folder}.", g_sDemosDir);
136+
137+
Directory.CreateDirectory(g_sDemosDir);
138+
}
139+
}
140+
141+
private void OnMapEndHandler()
142+
{
116143
if (!g_bChangeMap)
117144
{
118-
RecordDemo(false, false);
145+
g_bState = false;
146+
RecordDemo(false);
119147
g_bChangeMap = true;
120-
}
121-
}
122-
123-
private void RecordDemo(bool bState, bool State)
124-
{
125-
if (g_bChangeMap)
126-
{
127-
return;
128148
}
149+
}
129150

130-
if (bState && !bOldState)
131-
{
151+
private void RecordDemo(bool bState)
152+
{
153+
if (g_bChangeMap)
154+
{
155+
return;
156+
}
157+
158+
if (bState && !bOldState)
159+
{
132160
bOldState = true;
133161

134-
Server.ExecuteCommand($"tv_record \"addons/counterstrikesharp/data/{Config.DemosDir}{g_sDemosName}\"");
135-
136-
Logger.LogInformation(">> Recording start ({Name}).", g_sDemosName);
137-
}
138-
else if (!bState && bOldState)
139-
{
140-
bOldState = false;
141-
Server.ExecuteCommand($"tv_stoprecord");
142-
Logger.LogInformation(">> Recording stop ({Name}).", g_sDemosName);
162+
Server.ExecuteCommand($"tv_record \"addons/counterstrikesharp/data/{Config.DemosDir}{g_sDemosName}\"");
163+
164+
Logger.LogInformation(">> Recording start ({Name}).", g_sDemosName);
165+
}
166+
else if (!bState && bOldState)
167+
{
168+
bOldState = false;
169+
Server.ExecuteCommand($"tv_stoprecord");
170+
Logger.LogInformation(">> Recording stop ({Name}).", g_sDemosName);
143171

144-
Task.Delay(800).ContinueWith((task) =>
145-
{
146-
UploadDemo(g_sDemosDir + g_sDemosName, State);
147-
});
148-
}
149-
}
150-
172+
}
173+
}
174+
151175
async void UploadDemo(string path, bool bUploadOld = false)
152176
{
153177
if (!File.Exists(path)) return;
@@ -166,16 +190,15 @@ async void UploadDemo(string path, bool bUploadOld = false)
166190
}
167191
catch (Exception ex)
168192
{
169-
Logger.LogInformation(">> HttpPut Exception: {ex}", ex);
193+
Logger.LogInformation(">> UploadDemo Exception: {ex}", ex);
170194
}
171195

172196
if(bUploadOld)
173197
{
174198
UploadAllDemos();
175199
}
176-
177-
}
178-
200+
}
201+
179202
public async Task<string> UploadFile(string path)
180203
{
181204
using var client = new HttpClient();
@@ -188,8 +211,6 @@ public async Task<string> UploadFile(string path)
188211
using var req = new HttpRequestMessage(HttpMethod.Put, Config.UploadUrl);
189212
{
190213
req.Headers.Add("Auth", Config.Token);
191-
req.Headers.Add("Server-Name", g_sServerName);
192-
req.Headers.Add("Map-Name", path.Split('-').Last().Replace(".dem", ""));
193214
req.Headers.Add("Demo-Name", path.Split('/').Last());
194215
req.Headers.Add("Demo-ServerId", Config.ServerId.ToString());
195216
req.Headers.Add("Demo-Time", File.GetCreationTime(path).ToString());
@@ -204,18 +225,19 @@ public async Task<string> UploadFile(string path)
204225
}
205226
}
206227
}
207-
}
228+
}
229+
208230
void UploadAllDemos()
209231
{
210232
foreach (string file in Directory.GetFiles(g_sDemosDir))
211233
{
212234
Logger.LogInformation(">> Try upload old demo: {File}", file);
213235
UploadDemo(file);
214236
}
215-
}
216-
237+
}
238+
217239
private int GetActivePlayerCount()
218240
{
219241
return connectedPlayers.Count;
220-
}
221-
}
242+
}
243+
}

0 commit comments

Comments
 (0)