diff --git a/Archipelago.MultiClient.Net.Tests/ArchipelagoSessionFixture.cs b/Archipelago.MultiClient.Net.Tests/ArchipelagoSessionFixture.cs index 54edfdff..d6128257 100644 --- a/Archipelago.MultiClient.Net.Tests/ArchipelagoSessionFixture.cs +++ b/Archipelago.MultiClient.Net.Tests/ArchipelagoSessionFixture.cs @@ -193,8 +193,9 @@ static ArchipelagoSession CreateTestSession(IArchipelagoSocketHelper socket, var roomState = new RoomStateHelper(socket, locations); var dataStorage = new DataStorageHelper(socket, connectionInfo); var messageLog = new MessageLogHelper(socket, itemInfoResolver, players, connectionInfo); + var createHints = new CreateHintsHelper(socket, players, locations, roomState); - return new ArchipelagoSession(socket, items, locations, players, roomState, connectionInfo, dataStorage, messageLog); + return new ArchipelagoSession(socket, items, locations, players, roomState, connectionInfo, dataStorage, messageLog, createHints); } static void SetupLoginResultPacket(IArchipelagoSocketHelper socket, ArchipelagoPacketBase loginResultPacket) => diff --git a/Archipelago.MultiClient.Net/ArchipelagoSession.cs b/Archipelago.MultiClient.Net/ArchipelagoSession.cs index c2442a48..8339940a 100644 --- a/Archipelago.MultiClient.Net/ArchipelagoSession.cs +++ b/Archipelago.MultiClient.Net/ArchipelagoSession.cs @@ -149,6 +149,9 @@ public partial class ArchipelagoSession : IArchipelagoSession /// public IMessageLogHelper MessageLog { get; } + /// + public ICreateHintsHelper CreateHints { get; } + #if NET35 volatile bool awaitingRoomInfo; volatile bool expectingLoginResult; @@ -165,7 +168,8 @@ internal ArchipelagoSession(IArchipelagoSocketHelper socket, IRoomStateHelper roomState, ConnectionInfoHelper connectionInfoHelper, IDataStorageHelper dataStorage, - IMessageLogHelper messageLog) + IMessageLogHelper messageLog, + ICreateHintsHelper createHints) { Socket = socket; Items = items; @@ -175,6 +179,7 @@ internal ArchipelagoSession(IArchipelagoSocketHelper socket, connectionInfo = connectionInfoHelper; DataStorage = dataStorage; MessageLog = messageLog; + CreateHints = createHints; socket.PacketReceived += Socket_PacketReceived; } diff --git a/Archipelago.MultiClient.Net/ArchipelagoSessionFactory.cs b/Archipelago.MultiClient.Net/ArchipelagoSessionFactory.cs index 8c45701d..bb6df8d7 100644 --- a/Archipelago.MultiClient.Net/ArchipelagoSessionFactory.cs +++ b/Archipelago.MultiClient.Net/ArchipelagoSessionFactory.cs @@ -21,14 +21,15 @@ public static ArchipelagoSession CreateSession(Uri uri) var dataPackageCache = new DataPackageCache(socket); var connectionInfo = new ConnectionInfoHelper(socket); var players = new PlayerHelper(socket, connectionInfo); - var itemInfoResolver = new ItemInfoResolver(dataPackageCache, connectionInfo); - var locations = new LocationCheckHelper(socket, itemInfoResolver, connectionInfo, players); + var itemInfoResolver = new ItemInfoResolver(dataPackageCache, connectionInfo); + var locations = new LocationCheckHelper(socket, itemInfoResolver, connectionInfo, players); var items = new ReceivedItemsHelper(socket, locations, itemInfoResolver, connectionInfo, players); - var roomState = new RoomStateHelper(socket, locations); - var dataStorage = new DataStorageHelper(socket, connectionInfo); + var roomState = new RoomStateHelper(socket, locations); + var dataStorage = new DataStorageHelper(socket, connectionInfo); var messageLog = new MessageLogHelper(socket, itemInfoResolver, players, connectionInfo); + var createHints = new CreateHintsHelper(socket, players, locations, roomState); - return new ArchipelagoSession(socket, items, locations, players, roomState, connectionInfo, dataStorage, messageLog); + return new ArchipelagoSession(socket, items, locations, players, roomState, connectionInfo, dataStorage, messageLog, createHints); } /// diff --git a/Archipelago.MultiClient.Net/Converters/ArchipelagoPacketConverter.cs b/Archipelago.MultiClient.Net/Converters/ArchipelagoPacketConverter.cs index 7741aeae..4839554c 100644 --- a/Archipelago.MultiClient.Net/Converters/ArchipelagoPacketConverter.cs +++ b/Archipelago.MultiClient.Net/Converters/ArchipelagoPacketConverter.cs @@ -25,7 +25,8 @@ public class ArchipelagoPacketConverter : JsonConverter [ArchipelagoPacketType.Connect] = obj => obj.ToObject(), [ArchipelagoPacketType.ConnectUpdate] = obj => obj.ToObject(), [ArchipelagoPacketType.LocationChecks] = obj => obj.ToObject(), - [ArchipelagoPacketType.LocationScouts] = obj => obj.ToObject(), + [ArchipelagoPacketType.LocationScouts] = obj => obj.ToObject(), + [ArchipelagoPacketType.CreateHints] = obj => obj.ToObject(), [ArchipelagoPacketType.StatusUpdate] = obj => obj.ToObject(), [ArchipelagoPacketType.Say] = obj => obj.ToObject(), [ArchipelagoPacketType.GetDataPackage] = obj => obj.ToObject(), diff --git a/Archipelago.MultiClient.Net/Enums/ArchipelagoPacketType.cs b/Archipelago.MultiClient.Net/Enums/ArchipelagoPacketType.cs index fe6c551e..ba362164 100644 --- a/Archipelago.MultiClient.Net/Enums/ArchipelagoPacketType.cs +++ b/Archipelago.MultiClient.Net/Enums/ArchipelagoPacketType.cs @@ -15,6 +15,7 @@ public enum ArchipelagoPacketType ConnectUpdate, LocationChecks, LocationScouts, + CreateHints, StatusUpdate, Say, GetDataPackage, diff --git a/Archipelago.MultiClient.Net/Helpers/CreateHintsHelper.cs b/Archipelago.MultiClient.Net/Helpers/CreateHintsHelper.cs new file mode 100644 index 00000000..00ec6772 --- /dev/null +++ b/Archipelago.MultiClient.Net/Helpers/CreateHintsHelper.cs @@ -0,0 +1,107 @@ +using Archipelago.MultiClient.Net.Enums; +using Archipelago.MultiClient.Net.Packets; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Archipelago.MultiClient.Net.Helpers +{ + /// + /// Provides information about the current state of the server + /// + public interface ICreateHintsHelper + { + /// + /// Tell the server to create hints for the specified locations. + /// When creating hints for another slot's locations, the packet will fail if any of those locations do not contain an item for the requesting slot. + /// When creating hints for your own slot's locations, non-existing locations will be silently skipped. + /// + /// + /// The ID of the player whose locations ar ebeing hinted for. + /// + /// + /// If included, sets the status of the created hints to this status. + /// Defaults to unspecified. + /// + /// + /// The location ids to create hints for. + /// + /// + /// The websocket connection is not alive. + /// + void CreateHints(int player, HintStatus hintStatus = HintStatus.Unspecified, params long[] ids); + + /// + /// Tell the server to create hints for the specified locations. + /// This version does not include the player id, and as such will only hint for locations in the active player's game. + /// When creating hints, non-existing locations will be silently skipped. + /// + /// + /// If included, sets the status of the created hints to this status. + /// Defaults to unspecified. + /// + /// + /// The location ids to create hints for. + /// + /// + /// The websocket connection is not alive. + /// + void CreateHints(HintStatus hintStatus = HintStatus.Unspecified, params long[] ids); + } + + /// + public class CreateHintsHelper : ICreateHintsHelper + { + readonly IArchipelagoSocketHelper socket; + readonly ILocationCheckHelper locationCheckHelper; + readonly IRoomStateHelper roomStateHelper; + readonly IPlayerHelper players; + + /// + public Version Version { get; private set; } + + internal CreateHintsHelper(IArchipelagoSocketHelper socket, IPlayerHelper players, ILocationCheckHelper locationCheckHelper, IRoomStateHelper roomStateHelper) + { + this.socket = socket; + this.players = players; + this.locationCheckHelper = locationCheckHelper; + this.roomStateHelper = roomStateHelper; + } + + /// + public void CreateHints(int player, HintStatus hintStatus = HintStatus.Unspecified, params long[] ids) + { + // The server supports CreateHints after version 0.6.2 + if (roomStateHelper.Version.CompareTo(new Version(0, 6, 2)) <= 0) + { + CreateHintsFallback(ids); + } + else + { + socket.SendPacket(new CreateHintsPacket + { + Locations = ids, + Player = player, + Status = (int)hintStatus + }); + } + } + +#if NET35 + + /// + public void CreateHintsFallback(params long[] ids) => locationCheckHelper.ScoutLocationsAsync(null, createAsHint: true, ids); +#else + /// + public void CreateHintsFallback(params long[] ids) => locationCheckHelper.ScoutLocationsAsync(createAsHint: true, ids); +#endif + + /// + public void CreateHints(HintStatus hintStatus = HintStatus.Unspecified, params long[] ids) + { + // When the player is not included, it defaults to the requesting slot. + var currentPlayer = players.ActivePlayer.Slot; + CreateHints(currentPlayer, hintStatus, ids); + } + } +} diff --git a/Archipelago.MultiClient.Net/Helpers/LocationCheckHelper.cs b/Archipelago.MultiClient.Net/Helpers/LocationCheckHelper.cs index 9780417f..f7c56059 100644 --- a/Archipelago.MultiClient.Net/Helpers/LocationCheckHelper.cs +++ b/Archipelago.MultiClient.Net/Helpers/LocationCheckHelper.cs @@ -413,7 +413,7 @@ LocationChecksPacket GetLocationChecksPacket() => #if NET35 /// - public void ScoutLocationsAsync(Action> callback = null, + public void ScoutLocationsAsync(Action> callback = null, HintCreationPolicy hintCreationPolicy = HintCreationPolicy.None, params long[] ids) { var idsToScout = ids.Where(i => allLocations.Contains(i)).ToArray(); diff --git a/Archipelago.MultiClient.Net/Packets/CreateHintsPacket.cs b/Archipelago.MultiClient.Net/Packets/CreateHintsPacket.cs new file mode 100644 index 00000000..c1ed4081 --- /dev/null +++ b/Archipelago.MultiClient.Net/Packets/CreateHintsPacket.cs @@ -0,0 +1,19 @@ +using Archipelago.MultiClient.Net.Enums; +using Newtonsoft.Json; + +namespace Archipelago.MultiClient.Net.Packets +{ + public class CreateHintsPacket : ArchipelagoPacketBase + { + public override ArchipelagoPacketType PacketType => ArchipelagoPacketType.CreateHints; + + [JsonProperty("locations")] + public long[] Locations { get; set; } + + [JsonProperty("player")] + public int Player { get; set; } + + [JsonProperty("status")] + public int Status { get; set; } + } +}