using System.Globalization;
using AcDream.Plugin.Abstractions;
using Newtonsoft.Json.Linq;
using OpenAC.MosswartMassacre.Sharing;
using OpenAC.MosswartMassacre.Tests.Streams;
namespace OpenAC.MosswartMassacre.Tests.Sharing;
///
/// The share_* frames exactly as the original's VitalSharingTracker wrote
/// them, and the way frames from other computers reach the host's peer
/// network.
///
public sealed class VitalSharingTests
{
private const string Stamp = "2026-09-25T08:30:15.1230000Z";
private const uint Me = 0x50000001;
private static readonly PluginSpellInfo Vuln = new(
2074u, "Fire Vulnerability Other VI", 300u, 6, 300, 60, 240f, 31u, "", false, false);
private static readonly PluginSpellInfo Heal = new(
4u, "Heal Other VI", 400u, 6, 300, 60, 0f, 33u, "", false, true);
private static PluginHarness Sharing(Action? arrange = null)
{
var harness = new PluginHarness("Mossy");
var c = harness.Host.Automation.Character;
c.CurrentHealth = 150; c.MaxHealth = 200;
c.CurrentStamina = 300; c.MaxStamina = 300;
c.CurrentMana = 50; c.MaxMana = 100;
c.Skills.Add(new PluginSkillInfo(31u, "Creature Enchantment", PluginSkillTraining.Specialized, 380u));
harness.Host.Automation.Spells.All = [Vuln, Heal];
harness.Host.Automation.Navigation.Snapshot = new PluginNavigationSnapshot(
true, false, 1u, StreamGoldenTests.Position(), false, false);
arrange?.Invoke(harness);
harness.Login();
harness.Context.Settings.Current.CharTag = "tank";
harness.Frames.Clear();
return harness;
}
private static VitalSharing Feature(PluginHarness harness) => harness.Feature();
[Fact]
public void Subscribe_on_start_carries_the_player_id_and_tags()
{
// VitalSharingTracker.cs:144-151.
using var harness = Sharing();
Feature(harness).Start();
Assert.Equal(
"{\"type\":\"share_subscribe\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"player_id\":1342177281,\"tags\":[\"tank\"]}",
harness.Frames[0]);
}
[Fact]
public void The_reconnect_subscribe_carries_no_player_id()
{
// WebSocket.cs:121-136: the replay after every reconnect.
using var harness = Sharing();
harness.Context.Settings.Current.VitalSharingEnabled = true;
harness.Context.Settings.Current.CharTag = "";
harness.SimulateConnected();
Assert.Contains(
"{\"type\":\"share_subscribe\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\",\"tags\":[]}",
harness.Frames);
}
[Fact]
public void Vital_position_and_item_frames()
{
// VitalSharingTracker.cs:422-528: vitals on change or 3 s, position
// on change or 10 s (ew/ns to 7 places, z to 2, heading to 1), the
// item heartbeat every 5 s with no item data.
using var harness = Sharing();
Feature(harness).Start();
harness.Frames.Clear();
Feature(harness).OnTick();
string ew = Math.Round((double)33.65f, 7).ToString("R", CultureInfo.InvariantCulture);
string ns = Math.Round((double)42.55f, 7).ToString("R", CultureInfo.InvariantCulture);
Assert.Equal(
[
"{\"type\":\"share_vital_update\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"player_id\":1342177281,\"tags\":[\"tank\"],\"current_health\":150,\"max_health\":200,"
+ "\"current_stamina\":300,\"max_stamina\":300,\"current_mana\":50,\"max_mana\":100}",
"{\"type\":\"share_position_update\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"player_id\":1342177281,\"tags\":[\"tank\"],\"ew\":" + ew + ",\"ns\":" + ns + ",\"z\":42.5,\"heading\":90.0}",
"{\"type\":\"share_item_update\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"player_id\":1342177281,\"tags\":[\"tank\"]}",
],
harness.Frames);
}
[Fact]
public void Vitals_resend_only_on_change_or_after_three_seconds()
{
using var harness = Sharing();
Feature(harness).Start();
Feature(harness).OnTick();
harness.Frames.Clear();
harness.Clock.Advance(TimeSpan.FromMilliseconds(150));
Feature(harness).OnTick();
Assert.Empty(harness.FramesOfType("share_vital_update"));
harness.Host.Automation.Character.CurrentHealth = 149;
Feature(harness).OnTick();
Assert.Single(harness.FramesOfType("share_vital_update"));
harness.Frames.Clear();
harness.Clock.Advance(TimeSpan.FromSeconds(3.1));
Feature(harness).OnTick();
Assert.Single(harness.FramesOfType("share_vital_update"));
}
[Fact]
public void A_debuff_the_bot_announced_goes_out_as_attempt_then_success()
{
// VitalSharingTracker.cs:530-636: spell_id/target_id as signed ints,
// skill a double, duration_ms = spell duration * 1000.
using var harness = Sharing();
Feature(harness).Start();
harness.Frames.Clear();
var network = harness.Host.Automation.Network;
network.OwnCasts.Add(new PluginPeerCast(1, 7, Me, 0x80001234, Vuln.SpellId, 380, 0, false));
network.OwnCasts.Add(new PluginPeerCast(2, 7, Me, 0x80001234, Vuln.SpellId, 380, 240, true));
network.OwnCasts.Add(new PluginPeerCast(3, 7, Me, 0x50000002, Heal.SpellId, 380, 0, false));
Feature(harness).OnTick();
JObject[] casts = [.. harness.Frames.Select(JObject.Parse)
.Where(f => ((string?)f["type"])!.StartsWith("share_cast", StringComparison.Ordinal))];
Assert.Equal(2, casts.Length);
Assert.Equal(
"{\"type\":\"share_cast_attempt\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"player_id\":1342177281,\"tags\":[\"tank\"],\"spell_id\":2074,\"target_id\":-2147478988,\"skill\":380.0}",
harness.Frames.Single(f => f.Contains("share_cast_attempt", StringComparison.Ordinal)));
Assert.Equal(
"{\"type\":\"share_cast_success\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\","
+ "\"player_id\":1342177281,\"tags\":[\"tank\"],\"spell_id\":2074,\"target_id\":-2147478988,\"duration_ms\":240000}",
harness.Frames.Single(f => f.Contains("share_cast_success", StringComparison.Ordinal)));
// Already relayed: nothing new next time.
harness.Frames.Clear();
Feature(harness).OnTick();
Assert.DoesNotContain(harness.Frames, f => f.Contains("share_cast", StringComparison.Ordinal));
}
[Fact]
public void A_hand_cast_debuff_is_shared_when_it_lands_and_only_once()
{
using var harness = Sharing();
Feature(harness).Start();
harness.Frames.Clear();
harness.Host.Automation.Magic.LastCompletion = new PluginCastCompletion(5, Vuln.SpellId, 0x80001234, 0);
Feature(harness).OnTick();
harness.Host.Automation.Network.OwnCasts.Add(new PluginPeerCast(1, 7, Me, 0x80001234, Vuln.SpellId, 380, 240, true));
Feature(harness).OnTick();
Assert.Single(harness.FramesOfType("share_cast_success"));
}
[Fact]
public void A_completion_from_before_sharing_started_is_not_reported()
{
using var harness = Sharing(h =>
h.Host.Automation.Magic.LastCompletion = new PluginCastCompletion(5, Vuln.SpellId, 0x80001234, 0));
Feature(harness).Start();
Feature(harness).OnTick();
Assert.Empty(harness.FramesOfType("share_cast_success"));
}
[Fact]
public void Another_computers_vitals_and_position_reach_the_peer_network()
{
using var harness = Sharing();
Feature(harness).Start();
harness.Receive("{\"type\":\"share_position_update\",\"character_name\":\"Horan\",\"player_id\":1342177282,"
+ "\"tags\":[\"tank\"],\"ew\":33.66,\"ns\":42.55,\"z\":12.5,\"heading\":45.0}");
harness.Receive("{\"type\":\"share_vital_update\",\"character_name\":\"Horan\",\"player_id\":1342177282,"
+ "\"tags\":[\"tank\"],\"current_health\":20,\"max_health\":200,\"current_stamina\":1,\"max_stamina\":2,"
+ "\"current_mana\":3,\"max_mana\":4}");
PluginNetworkClient imported = harness.Host.Automation.Network.ImportedClients[^1];
Assert.Equal(0x50000002u, imported.PlayerId);
Assert.Equal("Horan", imported.Name);
Assert.Equal(20u, imported.CurrentHealth);
Assert.Equal(200u, imported.MaxHealth);
Assert.Equal(33.66, imported.Position.EastWest);
Assert.Equal(12.5 / 240d, imported.Position.Elevation);
Assert.Equal(["tank"], imported.Tags);
Assert.Equal(
VitalSharing.LandcellFromCoordinates(33.66, 42.55),
imported.Position.CellId);
Assert.Single(Feature(harness).Peers.Current(harness.Clock.UtcNow));
}
[Fact]
public void Another_computers_casts_reach_the_peer_network_as_the_caster()
{
using var harness = Sharing();
Feature(harness).Start();
harness.Receive("{\"type\":\"share_cast_attempt\",\"character_name\":\"Horan\",\"player_id\":1342177282,"
+ "\"spell_id\":2074,\"target_id\":-2147478988,\"skill\":350.0}");
harness.Receive("{\"type\":\"share_cast_success\",\"character_name\":\"Horan\",\"player_id\":1342177282,"
+ "\"spell_id\":2074,\"target_id\":-2147478988,\"duration_ms\":240000}");
Assert.Equal(
[
(0x50000002u, 0x80001234u, 2074u, 350, 0d, false),
(0x50000002u, 0x80001234u, 2074u, 0, 240d, true),
],
harness.Host.Automation.Network.ImportedCasts);
}
[Fact]
public void Own_frames_echoed_back_are_ignored()
{
using var harness = Sharing();
Feature(harness).Start();
harness.Receive("{\"type\":\"share_vital_update\",\"character_name\":\"mossy\",\"player_id\":1342177281,"
+ "\"current_health\":1,\"max_health\":2}");
Assert.Empty(harness.Host.Automation.Network.ImportedClients);
}
[Fact]
public void Nothing_is_imported_while_sharing_is_off()
{
using var harness = Sharing();
harness.Receive("{\"type\":\"share_vital_update\",\"character_name\":\"Horan\",\"player_id\":1342177282,"
+ "\"current_health\":1,\"max_health\":2}");
Assert.Empty(harness.Host.Automation.Network.ImportedClients);
}
[Fact]
public void Stop_says_goodbye()
{
using var harness = Sharing();
Feature(harness).Start();
harness.Frames.Clear();
Feature(harness).Stop();
Assert.Equal(
"{\"type\":\"share_unsubscribe\",\"timestamp\":\"" + Stamp + "\",\"character_name\":\"Mossy\"}",
Assert.Single(harness.Frames));
}
[Fact]
public void The_command_needs_streaming_first_and_toggles_the_setting()
{
using var harness = new PluginHarness("Mossy", webSocketEnabled: false);
harness.Login();
harness.Context.Commands.Dispatch("vitalsharing on");
Assert.Contains("[Mosswart Massacre] [VitalShare] WebSocket must be enabled first. Run /mm ws enable", harness.ChatLines);
Assert.False(harness.Context.Settings.Current.VitalSharingEnabled);
harness.Context.Settings.Current.WebSocketEnabled = true;
harness.Context.Commands.Dispatch("vitalsharing on");
Assert.True(harness.Context.Settings.Current.VitalSharingEnabled);
Assert.True(harness.Feature().IsActive);
}
}