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); } }