Telemetry
This commit is contained in:
parent
e010b9d126
commit
78a2479d6c
8 changed files with 446 additions and 6 deletions
73
MosswartMassacre/Coordinates.cs
Normal file
73
MosswartMassacre/Coordinates.cs
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Numerics;
|
||||||
|
using Decal.Adapter;
|
||||||
|
|
||||||
|
namespace MosswartMassacre
|
||||||
|
{
|
||||||
|
public class Coordinates
|
||||||
|
{
|
||||||
|
public double NS { get; set; } // +N / –S
|
||||||
|
public double EW { get; set; } // +E / –W
|
||||||
|
public double Z { get; set; }
|
||||||
|
|
||||||
|
/* -- quick helper: player’s current AC coords -- */
|
||||||
|
public static Coordinates Me
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
Vector3 pos = Utils.GetPlayerPosition(); // world X,Y,Z
|
||||||
|
uint land = (uint)CoreManager.Current.Actions.Landcell;
|
||||||
|
|
||||||
|
double ew = Geometry.LandblockToEW(land, pos.X);
|
||||||
|
double ns = Geometry.LandblockToNS(land, pos.Y);
|
||||||
|
return new Coordinates(ew, ns, pos.Z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint LandBlock => Geometry.GetLandblockFromCoordinates(EW, NS);
|
||||||
|
|
||||||
|
/* -------- parsing “33.2S 72.9E” if you ever need it -------- */
|
||||||
|
|
||||||
|
private static readonly Regex Rx = new Regex(
|
||||||
|
@"(?<NSval>\d{1,3}(?:\.\d{1,3})?)(?<NSchr>[ns])[, ]+(?<EWval>\d{1,3}(?:\.\d{1,3})?)(?<EWchr>[ew])",
|
||||||
|
RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public Coordinates() { }
|
||||||
|
public Coordinates(double ew, double ns, double z = 0) { EW = ew; NS = ns; Z = z; }
|
||||||
|
|
||||||
|
public static Coordinates FromString(string s)
|
||||||
|
{
|
||||||
|
var m = Rx.Match(s);
|
||||||
|
if (!m.Success) return null;
|
||||||
|
|
||||||
|
double ns = double.Parse(m.Groups["NSval"].Value, CultureInfo.InvariantCulture);
|
||||||
|
if (m.Groups["NSchr"].Value.ToLower() == "s") ns *= -1;
|
||||||
|
|
||||||
|
double ew = double.Parse(m.Groups["EWval"].Value, CultureInfo.InvariantCulture);
|
||||||
|
if (m.Groups["EWchr"].Value.ToLower() == "w") ew *= -1;
|
||||||
|
|
||||||
|
return new Coordinates(ew, ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------- distance helpers ---------------- */
|
||||||
|
|
||||||
|
public double DistanceTo(Coordinates o)
|
||||||
|
{
|
||||||
|
double ns = (((NS * 10) + 1019.5) * 24) - (((o.NS * 10) + 1019.5) * 24);
|
||||||
|
double ew = (((EW * 10) + 1019.5) * 24) - (((o.EW * 10) + 1019.5) * 24);
|
||||||
|
return Math.Sqrt(ns * ns + ew * ew + Math.Pow(Z - o.Z, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DistanceToFlat(Coordinates o)
|
||||||
|
{
|
||||||
|
double ns = (((NS * 10) + 1019.5) * 24) - (((o.NS * 10) + 1019.5) * 24);
|
||||||
|
double ew = (((EW * 10) + 1019.5) * 24) - (((o.EW * 10) + 1019.5) * 24);
|
||||||
|
return Math.Sqrt(ns * ns + ew * ew);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString() =>
|
||||||
|
$"{Math.Abs(NS):F2}{(NS >= 0 ? 'N' : 'S')} {Math.Abs(EW):F2}{(EW >= 0 ? 'E' : 'W')}";
|
||||||
|
}
|
||||||
|
}
|
||||||
121
MosswartMassacre/Geometry.cs
Normal file
121
MosswartMassacre/Geometry.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Numerics; // Vector3 & Quaternion
|
||||||
|
|
||||||
|
namespace MosswartMassacre
|
||||||
|
{
|
||||||
|
public static class Geometry
|
||||||
|
{
|
||||||
|
/* ---------- heading / quaternion helpers ---------- */
|
||||||
|
|
||||||
|
public static Quaternion HeadingToQuaternion(float deg) =>
|
||||||
|
ToQuaternion((float)Math.PI * -deg / 180.0f, 0, 0);
|
||||||
|
|
||||||
|
public static Quaternion RadiansToQuaternion(float rad) =>
|
||||||
|
ToQuaternion(rad, 0, 0);
|
||||||
|
|
||||||
|
public static double QuaternionToHeading(Quaternion q)
|
||||||
|
{
|
||||||
|
double sinr = 2 * (q.W * q.X + q.Y * q.Z);
|
||||||
|
double cosr = 1 - 2 * (q.X * q.X + q.Y * q.Y);
|
||||||
|
return Math.Atan2(sinr, cosr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double CalculateHeading(Vector3 start, Vector3 target)
|
||||||
|
{
|
||||||
|
var dy = target.Y - start.Y;
|
||||||
|
var dx = target.X - start.X;
|
||||||
|
return (360 - (Math.Atan2(dy, dx) * 180 / Math.PI) + 90) % 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
// yaw (Z) - pitch (Y) - roll (X)
|
||||||
|
public static Quaternion ToQuaternion(float yaw, float pitch, float roll)
|
||||||
|
{
|
||||||
|
float cy = (float)Math.Cos(yaw * 0.5f); float sy = (float)Math.Sin(yaw * 0.5f);
|
||||||
|
float cp = (float)Math.Cos(pitch * 0.5f); float sp = (float)Math.Sin(pitch * 0.5f);
|
||||||
|
float cr = (float)Math.Cos(roll * 0.5f); float sr = (float)Math.Sin(roll * 0.5f);
|
||||||
|
|
||||||
|
return new Quaternion(
|
||||||
|
cy * cp * sr - sy * sp * cr, // X
|
||||||
|
sy * cp * sr + cy * sp * cr, // Y
|
||||||
|
sy * cp * cr - cy * sp * sr, // Z
|
||||||
|
cy * cp * cr + sy * sp * sr // W
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------- landblock / coordinate helpers ---------- */
|
||||||
|
|
||||||
|
public static uint GetLandblockFromCoordinates(double ew, double ns)
|
||||||
|
{
|
||||||
|
ns = (ns - 0.5) * 10.0;
|
||||||
|
ew = (ew - 0.5) * 10.0;
|
||||||
|
|
||||||
|
uint basex = (uint)(ew + 0x400);
|
||||||
|
uint basey = (uint)(ns + 0x400);
|
||||||
|
|
||||||
|
byte bx = (byte)(basex >> 3);
|
||||||
|
byte by = (byte)(basey >> 3);
|
||||||
|
byte cx = (byte)(basex & 7);
|
||||||
|
byte cy = (byte)(basey & 7);
|
||||||
|
|
||||||
|
int block = (bx << 8) | by;
|
||||||
|
int cell = (cx << 3) | cy;
|
||||||
|
|
||||||
|
return (uint)((block << 16) | (cell + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float LandblockToEW(uint landcell, float xOff)
|
||||||
|
{
|
||||||
|
uint l = (landcell & 0xFF000000) / 0x200000;
|
||||||
|
return (float)(((xOff / 24) + l - 1019.5) / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float LandblockToNS(uint landcell, float yOff)
|
||||||
|
{
|
||||||
|
uint l = (landcell & 0x00FF0000) / 0x2000;
|
||||||
|
return (float)(((yOff / 24) + l - 1019.5) / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float EWToLandblock(uint landcell, float ew)
|
||||||
|
{
|
||||||
|
uint l = (landcell & 0xFF000000) / 0x200000;
|
||||||
|
return (float)(((ew * 10) - l + 1019.5) * 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float NSToLandblock(uint landcell, float ns)
|
||||||
|
{
|
||||||
|
uint l = (landcell & 0x00FF0000) / 0x2000;
|
||||||
|
return (float)(((ns * 10) - l + 1019.5) * 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int LandblockXDifference(uint orig, uint dest) =>
|
||||||
|
(int)(((dest >> 24) - (orig >> 24)) * 192);
|
||||||
|
|
||||||
|
public static int LandblockYDifference(uint orig, uint dest) =>
|
||||||
|
(int)((((dest << 8) >> 24) - ((orig << 8) >> 24)) * 192);
|
||||||
|
|
||||||
|
/* ---------- misc helpers ---------- */
|
||||||
|
|
||||||
|
public static float Distance2d(float x1, float y1, float x2, float y2) =>
|
||||||
|
(float)Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2));
|
||||||
|
|
||||||
|
public static bool LineIntersectsRect(Point p1, Point p2, Rectangle r) =>
|
||||||
|
LineIntersectsLine(p1, p2, new Point(r.X, r.Y), new Point(r.Right, r.Y)) ||
|
||||||
|
LineIntersectsLine(p1, p2, new Point(r.Right, r.Y), new Point(r.Right, r.Bottom)) ||
|
||||||
|
LineIntersectsLine(p1, p2, new Point(r.Right, r.Bottom), new Point(r.X, r.Bottom)) ||
|
||||||
|
LineIntersectsLine(p1, p2, new Point(r.X, r.Bottom), new Point(r.X, r.Y)) ||
|
||||||
|
(r.Contains(p1) && r.Contains(p2));
|
||||||
|
|
||||||
|
public static bool LineIntersectsLine(Point a1, Point a2, Point b1, Point b2)
|
||||||
|
{
|
||||||
|
float q = (a1.Y - b1.Y) * (b2.X - b1.X) - (a1.X - b1.X) * (b2.Y - b1.Y);
|
||||||
|
float d = (a2.X - a1.X) * (b2.Y - b1.Y) - (a2.Y - a1.Y) * (b2.X - b1.X);
|
||||||
|
if (d == 0) return false;
|
||||||
|
|
||||||
|
float r = q / d;
|
||||||
|
q = (a1.Y - b1.Y) * (a2.X - a1.X) - (a1.X - b1.X) * (a2.Y - a1.Y);
|
||||||
|
float s = q / d;
|
||||||
|
return (r >= 0 && r <= 1 && s >= 0 && s <= 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<PlatformTarget>x86</PlatformTarget>
|
<PlatformTarget>x86</PlatformTarget>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
|
|
@ -46,9 +47,13 @@
|
||||||
<EmbedInteropTypes>False</EmbedInteropTypes>
|
<EmbedInteropTypes>False</EmbedInteropTypes>
|
||||||
<HintPath>lib\Decal.Interop.Inject.dll</HintPath>
|
<HintPath>lib\Decal.Interop.Inject.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
|
@ -64,6 +69,10 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Telemetry.cs" />
|
||||||
|
<Compile Include="Coordinates.cs" />
|
||||||
|
<Compile Include="Geometry.cs" />
|
||||||
|
<Compile Include="Utils.cs" />
|
||||||
<Compile Include="PluginSettings.cs" />
|
<Compile Include="PluginSettings.cs" />
|
||||||
<Compile Include="HttpCommandServer.cs" />
|
<Compile Include="HttpCommandServer.cs" />
|
||||||
<Compile Include="DelayedCommandManager.cs" />
|
<Compile Include="DelayedCommandManager.cs" />
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
|
|
@ -23,6 +24,7 @@ namespace MosswartMassacre
|
||||||
public static bool RemoteCommandsEnabled { get; set; } = false;
|
public static bool RemoteCommandsEnabled { get; set; } = false;
|
||||||
public static bool HttpServerEnabled { get; set; } = false;
|
public static bool HttpServerEnabled { get; set; } = false;
|
||||||
public static string CharTag { get; set; } = "";
|
public static string CharTag { get; set; } = "";
|
||||||
|
public static bool TelemetryEnabled { get; set; } = false;
|
||||||
private static Queue<string> rareMessageQueue = new Queue<string>();
|
private static Queue<string> rareMessageQueue = new Queue<string>();
|
||||||
private static DateTime _lastSent = DateTime.MinValue;
|
private static DateTime _lastSent = DateTime.MinValue;
|
||||||
private static readonly Queue<string> _chatQueue = new Queue<string>();
|
private static readonly Queue<string> _chatQueue = new Queue<string>();
|
||||||
|
|
@ -47,6 +49,9 @@ namespace MosswartMassacre
|
||||||
|
|
||||||
// Initialize the view (UI)
|
// Initialize the view (UI)
|
||||||
MainView.ViewInit();
|
MainView.ViewInit();
|
||||||
|
|
||||||
|
// Enable TLS1.2
|
||||||
|
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -59,6 +64,8 @@ namespace MosswartMassacre
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
PluginSettings.Save();
|
PluginSettings.Save();
|
||||||
|
if (TelemetryEnabled)
|
||||||
|
Telemetry.Stop(); // ensure no dangling timer / HttpClient
|
||||||
WriteToChat("Mosswart Massacre is shutting down...");
|
WriteToChat("Mosswart Massacre is shutting down...");
|
||||||
|
|
||||||
// Unsubscribe from chat message event
|
// Unsubscribe from chat message event
|
||||||
|
|
@ -92,7 +99,10 @@ namespace MosswartMassacre
|
||||||
RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled;
|
RareMetaEnabled = PluginSettings.Instance.RareMetaEnabled;
|
||||||
RemoteCommandsEnabled = PluginSettings.Instance.RemoteCommandsEnabled;
|
RemoteCommandsEnabled = PluginSettings.Instance.RemoteCommandsEnabled;
|
||||||
HttpServerEnabled = PluginSettings.Instance.HttpServerEnabled;
|
HttpServerEnabled = PluginSettings.Instance.HttpServerEnabled;
|
||||||
|
TelemetryEnabled = PluginSettings.Instance.TelemetryEnabled;
|
||||||
MainView.SetRareMetaToggleState(RareMetaEnabled);
|
MainView.SetRareMetaToggleState(RareMetaEnabled);
|
||||||
|
if (TelemetryEnabled)
|
||||||
|
Telemetry.Start();
|
||||||
|
|
||||||
WriteToChat("Settings loaded.");
|
WriteToChat("Settings loaded.");
|
||||||
}
|
}
|
||||||
|
|
@ -363,13 +373,42 @@ namespace MosswartMassacre
|
||||||
|
|
||||||
switch (subCommand)
|
switch (subCommand)
|
||||||
{
|
{
|
||||||
|
case "telemetry":
|
||||||
|
if (args.Length > 1)
|
||||||
|
{
|
||||||
|
if (args[1].Equals("enable", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
TelemetryEnabled = true;
|
||||||
|
Telemetry.Start();
|
||||||
|
PluginSettings.Instance.TelemetryEnabled = true;
|
||||||
|
WriteToChat("Telemetry streaming ENABLED.");
|
||||||
|
}
|
||||||
|
else if (args[1].Equals("disable", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
TelemetryEnabled = false;
|
||||||
|
Telemetry.Stop();
|
||||||
|
PluginSettings.Instance.TelemetryEnabled = false;
|
||||||
|
WriteToChat("Telemetry streaming DISABLED.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteToChat("Usage: /mm telemetry <enable|disable>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WriteToChat("Usage: /mm telemetry <enable|disable>");
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "help":
|
case "help":
|
||||||
WriteToChat("Mosswart Massacre Commands:");
|
WriteToChat("Mosswart Massacre Commands:");
|
||||||
WriteToChat("/mm report - Show current stats");
|
WriteToChat("/mm report - Show current stats");
|
||||||
WriteToChat("/mm reset - Reset all counters");
|
WriteToChat("/mm loc - Show current location");
|
||||||
WriteToChat("/mm meta - Toggle rare meta state");
|
WriteToChat("/mm telemetry - Telemetry streaming enable|disable"); // NEW
|
||||||
WriteToChat("/mm http - http server enable|disable");
|
WriteToChat("/mm reset - Reset all counters");
|
||||||
WriteToChat("/mm remotecommand - Listen to remote commands enable|disable");
|
WriteToChat("/mm meta - Toggle rare meta state");
|
||||||
|
WriteToChat("/mm http - Local http-command server enable|disable");
|
||||||
|
WriteToChat("/mm remotecommand - Listen to allegiance !do/!dot enable|disable");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "report":
|
case "report":
|
||||||
|
|
@ -378,10 +417,14 @@ namespace MosswartMassacre
|
||||||
WriteToChat(reportMessage);
|
WriteToChat(reportMessage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "loc":
|
||||||
|
Coordinates here = Coordinates.Me;
|
||||||
|
var pos = Utils.GetPlayerPosition();
|
||||||
|
WriteToChat($"Location: {here} (X={pos.X:F1}, Y={pos.Y:F1}, Z={pos.Z:F1})");
|
||||||
|
break;
|
||||||
case "reset":
|
case "reset":
|
||||||
RestartStats();
|
RestartStats();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "meta":
|
case "meta":
|
||||||
RareMetaEnabled = !RareMetaEnabled;
|
RareMetaEnabled = !RareMetaEnabled;
|
||||||
WriteToChat($"Rare meta state is now {(RareMetaEnabled ? "ON" : "OFF")}");
|
WriteToChat($"Rare meta state is now {(RareMetaEnabled ? "ON" : "OFF")}");
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ namespace MosswartMassacre
|
||||||
private bool _rareMetaEnabled = true;
|
private bool _rareMetaEnabled = true;
|
||||||
private bool _httpServerEnabled = false;
|
private bool _httpServerEnabled = false;
|
||||||
private string _charTag = "default";
|
private string _charTag = "default";
|
||||||
|
private bool _telemetryEnabled = false;
|
||||||
public static PluginSettings Instance => _instance;
|
public static PluginSettings Instance => _instance;
|
||||||
|
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
|
|
@ -41,6 +42,7 @@ namespace MosswartMassacre
|
||||||
PluginCore.RareMetaEnabled = _instance.RareMetaEnabled;
|
PluginCore.RareMetaEnabled = _instance.RareMetaEnabled;
|
||||||
PluginCore.RemoteCommandsEnabled = _instance.RemoteCommandsEnabled;
|
PluginCore.RemoteCommandsEnabled = _instance.RemoteCommandsEnabled;
|
||||||
PluginCore.HttpServerEnabled = _instance.HttpServerEnabled;
|
PluginCore.HttpServerEnabled = _instance.HttpServerEnabled;
|
||||||
|
PluginCore.TelemetryEnabled = _instance.TelemetryEnabled;
|
||||||
PluginCore.CharTag = _instance.CharTag;
|
PluginCore.CharTag = _instance.CharTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,5 +78,10 @@ namespace MosswartMassacre
|
||||||
get => _charTag;
|
get => _charTag;
|
||||||
set { _charTag = value; Save(); }
|
set { _charTag = value; Save(); }
|
||||||
}
|
}
|
||||||
|
public bool TelemetryEnabled
|
||||||
|
{
|
||||||
|
get => _telemetryEnabled;
|
||||||
|
set { _telemetryEnabled = value; Save(); }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
110
MosswartMassacre/Telemetry.cs
Normal file
110
MosswartMassacre/Telemetry.cs
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
using System;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Timers;
|
||||||
|
using Decal.Adapter;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace MosswartMassacre
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Periodically sends gameplay telemetry to your FastAPI collector.
|
||||||
|
/// Toggle with: Telemetry.Start() / Telemetry.Stop()
|
||||||
|
/// </summary>
|
||||||
|
public static class Telemetry
|
||||||
|
{
|
||||||
|
/* ============ CONFIG ============ */
|
||||||
|
|
||||||
|
private const string Endpoint = "https://mosswart.snakedesert.se/position";
|
||||||
|
private const string SharedSecret = "your_shared_secret";
|
||||||
|
private const int IntervalSec = 5; // send every 5 s
|
||||||
|
|
||||||
|
/* ============ internals ========== */
|
||||||
|
|
||||||
|
private static readonly HttpClient _http = new HttpClient();
|
||||||
|
private static Timer _timer;
|
||||||
|
private static bool _enabled;
|
||||||
|
private static string _sessionId;
|
||||||
|
|
||||||
|
/* ============ public API ========= */
|
||||||
|
|
||||||
|
public static void Start()
|
||||||
|
{
|
||||||
|
if (_enabled) return; // already on
|
||||||
|
|
||||||
|
_sessionId = $"{CoreManager.Current.CharacterFilter.Name}-{DateTime.UtcNow:yyyyMMdd-HHmmss}";
|
||||||
|
_timer = new Timer(IntervalSec * 1000);
|
||||||
|
_timer.Elapsed += (_, __) => SendSnapshot();
|
||||||
|
_timer.Start();
|
||||||
|
|
||||||
|
_enabled = true;
|
||||||
|
PluginCore.WriteToChat("[Telemetry] HTTP streaming ENABLED");
|
||||||
|
PluginCore.WriteToChat("[Tel] timer every " + IntervalSec + " s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stop()
|
||||||
|
{
|
||||||
|
if (!_enabled) return;
|
||||||
|
|
||||||
|
_enabled = false;
|
||||||
|
_timer?.Stop();
|
||||||
|
_timer?.Dispose();
|
||||||
|
_timer = null;
|
||||||
|
|
||||||
|
PluginCore.WriteToChat("[Telemetry] HTTP streaming DISABLED");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ============ snapshot builder === */
|
||||||
|
|
||||||
|
private static async void SendSnapshot()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var coords = Coordinates.Me;
|
||||||
|
|
||||||
|
var payload = new
|
||||||
|
{
|
||||||
|
character_name = CoreManager.Current.CharacterFilter.Name,
|
||||||
|
char_tag = PluginCore.CharTag,
|
||||||
|
session_id = _sessionId,
|
||||||
|
timestamp = DateTime.UtcNow.ToString("o"),
|
||||||
|
|
||||||
|
ew = coords.EW,
|
||||||
|
ns = coords.NS,
|
||||||
|
z = coords.Z,
|
||||||
|
|
||||||
|
kills = PluginCore.totalKills,
|
||||||
|
deaths = 0,
|
||||||
|
rares_found = PluginCore.rareCount,
|
||||||
|
prismatic_taper_count = 0,
|
||||||
|
vt_state = "Unknown"
|
||||||
|
};
|
||||||
|
|
||||||
|
string json = JsonConvert.SerializeObject(payload);
|
||||||
|
|
||||||
|
var req = new HttpRequestMessage(HttpMethod.Post, Endpoint)
|
||||||
|
{
|
||||||
|
Content = new StringContent(json, Encoding.UTF8, "application/json")
|
||||||
|
};
|
||||||
|
req.Headers.Add("X-Plugin-Secret", SharedSecret);
|
||||||
|
|
||||||
|
/* ---------- NEW: wait for response & print result ---------- */
|
||||||
|
var resp = await _http.SendAsync(req);
|
||||||
|
if (resp.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
PluginCore.WriteToChat($"[Tel] ✓ {resp.StatusCode}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PluginCore.WriteToChat($"[Tel] ✗ {resp.StatusCode} ({await resp.Content.ReadAsStringAsync()})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var inner = ex.InnerException?.Message ?? "no inner msg";
|
||||||
|
PluginCore.WriteToChat($"[Tel] FAILED — {ex.GetType().Name}: {ex.Message} ⇢ {inner}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
76
MosswartMassacre/Utils.cs
Normal file
76
MosswartMassacre/Utils.cs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
using System;
|
||||||
|
using Decal.Adapter;
|
||||||
|
using Decal.Adapter.Wrappers;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace MosswartMassacre
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Misc. helpers shared across the plugin.
|
||||||
|
/// Add new utilities here as your project grows.
|
||||||
|
/// </summary>
|
||||||
|
public static class Utils
|
||||||
|
{
|
||||||
|
/* ----------------------------------------------------------
|
||||||
|
* 1) Direct-memory physics helpers
|
||||||
|
* -------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the player’s raw world position by reading the
|
||||||
|
/// physics-object pointer (same offsets UB uses: +0x84/88/8C).
|
||||||
|
/// </summary>
|
||||||
|
public static unsafe Vector3 GetPlayerPosition()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int id = CoreManager.Current.CharacterFilter.Id;
|
||||||
|
if (!CoreManager.Current.Actions.IsValidObject(id))
|
||||||
|
return new Vector3();
|
||||||
|
|
||||||
|
byte* p = (byte*)CoreManager.Current.Actions.Underlying.GetPhysicsObjectPtr(id);
|
||||||
|
return new Vector3(
|
||||||
|
*(float*)(p + 0x84), // X
|
||||||
|
*(float*)(p + 0x88), // Y
|
||||||
|
*(float*)(p + 0x8C)); // Z
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new Vector3();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convenience: returns the current landcell (upper 16 bits of landblock).
|
||||||
|
/// </summary>
|
||||||
|
public static uint GetPlayerLandcell() =>
|
||||||
|
(uint)CoreManager.Current.Actions.Landcell;
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------
|
||||||
|
* 2) High-level wrappers around Geometry / Coordinates
|
||||||
|
* -------------------------------------------------------- */
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get AC-style coordinates (EW/NS) for the player in one call.
|
||||||
|
/// </summary>
|
||||||
|
public static Coordinates GetPlayerCoordinates()
|
||||||
|
{
|
||||||
|
Vector3 pos = GetPlayerPosition();
|
||||||
|
uint landcell = GetPlayerLandcell();
|
||||||
|
|
||||||
|
double ew = Geometry.LandblockToEW(landcell, pos.X);
|
||||||
|
double ns = Geometry.LandblockToNS(landcell, pos.Y);
|
||||||
|
|
||||||
|
return new Coordinates(ew, ns, pos.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------
|
||||||
|
* 3) Generic math helpers you may want later
|
||||||
|
* -------------------------------------------------------- */
|
||||||
|
|
||||||
|
public static double Clamp(double value, double min, double max) =>
|
||||||
|
value < min ? min : (value > max ? max : value);
|
||||||
|
|
||||||
|
public static double DegToRad(double deg) => deg * Math.PI / 180.0;
|
||||||
|
public static double RadToDeg(double rad) => rad * 180.0 / Math.PI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net48" />
|
||||||
<package id="YamlDotNet" version="16.3.0" targetFramework="net48" />
|
<package id="YamlDotNet" version="16.3.0" targetFramework="net48" />
|
||||||
</packages>
|
</packages>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue