-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPlugin.cs
More file actions
133 lines (112 loc) · 3.91 KB
/
Plugin.cs
File metadata and controls
133 lines (112 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using BepInEx;
using BepInEx.Logging;
using Fika.Core.Main.Utils;
using SPT.Common.Http;
using UnityEngine;
namespace ZSlayerHeadlessTelemetry;
[BepInPlugin("com.zslayerhq.headlesstelemetry", "ZSlayer Headless Telemetry", "1.4.0")]
[BepInDependency("com.fika.core", BepInDependency.DependencyFlags.HardDependency)]
public class Plugin : BaseUnityPlugin
{
internal static ManualLogSource Log;
internal static TelemetryReporter Reporter;
internal static string SourceId = "";
private RaidEventHooks _hooks;
private LogStreamService _logStream;
private Coroutine _idleFlushCoroutine;
private void Awake()
{
Log = Logger;
// Only activate on headless clients
if (!FikaBackendUtils.IsHeadless)
{
Log.LogInfo("[ZSlayerHQ] Not headless — telemetry disabled");
enabled = false;
return;
}
// Extract source ID (headless profile ID)
SourceId = RequestHandler.SessionId ?? "";
Log.LogInfo($"[ZSlayerHQ] Source ID: {SourceId}");
// Build the telemetry URL from SPT's backend URL
var baseUrl = RequestHandler.Host.TrimEnd('/');
var telemetryUrl = $"{baseUrl}/zslayer/cc/telemetry";
Log.LogInfo($"[ZSlayerHQ] Headless telemetry active — posting to {telemetryUrl}");
Reporter = new TelemetryReporter(telemetryUrl);
// Register log listener for console streaming
_logStream = new LogStreamService();
BepInEx.Logging.Logger.Listeners.Add(_logStream);
_hooks = new RaidEventHooks(Reporter, _logStream, SourceId);
_hooks.Subscribe();
// Enable Harmony patches
new OnDamagePatch().Enable();
// Report versions to server
var telemetryVersion = Info.Metadata.Version.ToString();
var fikaVersion = typeof(FikaBackendUtils).Assembly.GetName().Version?.ToString() ?? "?";
Log.LogInfo($"[ZSlayerHQ] Versions — Telemetry: {telemetryVersion}, Fika.Core: {fikaVersion}");
var hostname = Dns.GetHostName();
var ip = ResolveLocalIp();
Reporter.Post("hello", new
{
telemetryVersion,
fikaClientVersion = fikaVersion,
sourceId = SourceId,
hostname,
ip
});
// Async ping to verify server is reachable
Reporter.PingAsync();
// Start idle console flush
_idleFlushCoroutine = StartCoroutine(IdleConsoleFlushLoop());
}
private IEnumerator IdleConsoleFlushLoop()
{
while (true)
{
yield return new WaitForSeconds(10f);
// Only flush when NOT in raid (during raid, RaidEventHooks flushes every 5s)
if (_hooks != null && !_hooks.IsInRaid)
{
FlushConsoleBuffer();
}
}
}
internal void FlushConsoleBuffer()
{
if (_logStream == null || Reporter == null) return;
var entries = _logStream.DrainBuffer();
if (entries.Count > 0)
{
Reporter.Post("console", new { sourceId = SourceId, entries });
}
}
private static string ResolveLocalIp()
{
try
{
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0);
socket.Connect("8.8.8.8", 65530);
var endpoint = socket.LocalEndPoint as IPEndPoint;
return endpoint?.Address.ToString() ?? "127.0.0.1";
}
catch
{
return "127.0.0.1";
}
}
private void OnDestroy()
{
if (_idleFlushCoroutine != null)
StopCoroutine(_idleFlushCoroutine);
_hooks?.Unsubscribe();
Reporter?.Dispose();
if (_logStream != null)
{
try { BepInEx.Logging.Logger.Listeners.Remove(_logStream); }
catch { /* best effort */ }
}
}
}