Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generic overload for GetSlotData in DataStorageWrapper #98

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,63 +22,35 @@
<Reference Include="Newtonsoft.Json">
<HintPath>..\DLLs\net35\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net471' AND '$(Configuration)' == 'Debug'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Debug\net35\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net471' AND '$(Configuration)' == 'Release'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Release\net35\Archipelago.MultiClient.Net.dll</HintPath>
<HintPath>..\Archipelago.MultiClient.Net\bin\$(Configuration)\net35\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net472'">
<Reference Include="Newtonsoft.Json">
<HintPath>..\DLLs\net40\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472' AND '$(Configuration)' == 'Debug'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Debug\net40\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net472' AND '$(Configuration)' == 'Release'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Release\net40\Archipelago.MultiClient.Net.dll</HintPath>
<HintPath>..\Archipelago.MultiClient.Net\bin\$(Configuration)\net40\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net47'">
<Reference Include="Newtonsoft.Json">
<HintPath>..\DLLs\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net47' AND '$(Configuration)' == 'Debug'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Debug\net45\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net47' AND '$(Configuration)' == 'Release'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Release\net45\Archipelago.MultiClient.Net.dll</HintPath>
<HintPath>..\Archipelago.MultiClient.Net\bin\$(Configuration)\net45\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net48'">
<Reference Include="Newtonsoft.Json">
<HintPath>..\DLLs\netstandard2.0\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net48' AND '$(Configuration)' == 'Debug'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Debug\netstandard2.0\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net48' AND '$(Configuration)' == 'Release'">
<Reference Include="Archipelago.MultiClient.Net">
<HintPath>..\Archipelago.MultiClient.Net\bin\Release\netstandard2.0\Archipelago.MultiClient.Net.dll</HintPath>
<HintPath>..\Archipelago.MultiClient.Net\bin\$(Configuration)\netstandard2.0\Archipelago.MultiClient.Net.dll</HintPath>
</Reference>
</ItemGroup>
</Project>
55 changes: 55 additions & 0 deletions Archipelago.MultiClient.Net.Tests/DataStorageWrapperFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Archipelago.MultiClient.Net.Helpers;
using Archipelago.MultiClient.Net.Models;
using Archipelago.MultiClient.Net.Packets;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NSubstitute;
using NUnit.Framework;
Expand Down Expand Up @@ -321,6 +322,60 @@ public void GetSlotData_should_return_slot_data_for_current_player_slot()
Assert.That(slotData["Two"], Is.EqualTo(2));
}

private class CustomSlotDataModel
{
public class Options
{
public bool IsXRandomized { get; set; }
public bool IsYRandomized { get; set; }
}
public int One { get; set; }
public long Two { get; set; }
public uint? Three { get; set; }
[JsonProperty("ListOfStuff")]
public List<string> Strings { get; set; }
public Options SlotOptions { get; set; }
}
[Test]
public void GetSlotData_should_deserialize_custom_type_for_current_player_slot()
{
var socket = Substitute.For<IArchipelagoSocketHelper>();
var connectionInfo = Substitute.For<IConnectionInfoProvider>();
connectionInfo.Slot.Returns(4);

CustomSlotDataModel slotData = null;

var sut = new DataStorageHelper(socket, connectionInfo);

var serverSlotData = new Dictionary<string, object>
{
{ "One", 1 },
{ "Two", 2 },
{ "ListOfStuff", new string[] { "A", "B", "C" } },
{ "SlotOptions", new CustomSlotDataModel.Options
{
IsXRandomized = true,
IsYRandomized = false
} }
};

ExecuteAsyncWithDelay(
() => { slotData = sut.GetSlotData<CustomSlotDataModel>(); },
() => RaiseRetrieved(socket, "_read_slot_data_4", JObject.FromObject(serverSlotData)));

socket.Received().SendPacketAsync(Arg.Is<GetPacket>(p => p.Keys.FirstOrDefault() == "_read_slot_data_4"));

Assert.IsNotNull(slotData);

Assert.That(slotData.One, Is.EqualTo(1));
Assert.That(slotData.Two, Is.EqualTo(2));
Assert.That(slotData.Three, Is.Null);
Assert.That(slotData.Strings, Is.EquivalentTo(new List<string> { "A", "B", "C" }));
Assert.That(slotData.SlotOptions.IsXRandomized, Is.True);
Assert.That(slotData.SlotOptions.IsYRandomized, Is.False);

}

[Test]
public void GetSlotData_should_return_null_for_non_existing_player_slot()
{
Expand Down
38 changes: 35 additions & 3 deletions Archipelago.MultiClient.Net/Helpers/DataStorageWrappers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ void TrackHints(Action<Hint[]> onHintsUpdated,
/// <param name="slot">the slot id of the player to request slot data for, defaults to the current player's slot if left empty</param>
/// <returns>An Dictionary with string keys, and custom defined values, the keys and values differ per game</returns>
Dictionary<string, object> GetSlotData(int? slot = null);

/// <summary>
/// Retrieves the custom slot data for the specified slot
/// </summary>
/// <typeparam name="T">The type to convert the slot data to</typeparam>
/// <param name="slot">The slot ID of the player ot request slot data for, defaults to the current player's slot if left empty</param>
/// <returns>The slot data, converted to a modeled object of the specified type</returns>
T GetSlotData<T>(int? slot = null) where T : class;

#if NET35
/// <summary>
Expand All @@ -67,13 +75,28 @@ void TrackHints(Action<Hint[]> onHintsUpdated,
/// <param name="slot">the slot id of the player to request slot data for, defaults to the current player's slot if left empty</param>
/// <returns>An Dictionary with string keys, and custom defined values, the keys and values differ per game</returns>
void GetSlotDataAsync(Action<Dictionary<string, object>> onSlotDataRetrieved, int? slot = null);
/// <summary>
/// Retrieves the custom slot data for the specified slot
/// </summary>
/// <typeparam name="T">The type to convert the slot data to</typeparam>
/// <param name="onSlotDataRetrieved">the method to call with the retrieved slot data</param>
/// <param name="slot">the slot id of the player to request slot data for, defaults to the current player's slot if left empty</param>
/// <returns>The slot data, converted to a modeled object of the specified type</returns>
void GetSlotDataAsync<T>(Action<T> onSlotDataRetrieved, int? slot = null) where T : class;
#else
/// <summary>
/// Retrieves the custom slot data for the specified slot
/// </summary>
/// <param name="slot">the slot id of the player to request slot data for, defaults to the current player's slot if left empty</param>
/// <returns>An Dictionary with string keys, and custom defined values, the keys and values differ per game</returns>
Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null);
/// <summary>
/// Retrieves the custom slot data for the specified slot
/// </summary>
/// <typeparam name="T">The type to convert the slot data to</typeparam>
/// <param name="slot">the slot id of the player to request slot data for, defaults to the current player's slot if left empty</param>
/// <returns>The slot data, converted to a modeled object of the specified type</returns>
Task<T> GetSlotDataAsync<T>(int? slot = null) where T : class;
#endif

/// <summary>
Expand Down Expand Up @@ -203,16 +226,25 @@ public void TrackHints(Action<Hint[]> onHintsUpdated,
}

/// <inheritdoc />
public Dictionary<string, object> GetSlotData(int? slot = null) =>
GetSlotDataElement(slot).To<Dictionary<string, object>>();
public Dictionary<string, object> GetSlotData(int? slot = null) =>
GetSlotData<Dictionary<string, object>>(slot);
/// <inheritdoc/>
public T GetSlotData<T>(int? slot = null) where T : class =>
GetSlotDataElement(slot).To<T>();
#if NET35
/// <inheritdoc />
public void GetSlotDataAsync(Action<Dictionary<string, object>> onSlotDataRetrieved, int? slot = null) =>
GetSlotDataElement(slot).GetAsync(t => onSlotDataRetrieved(t?.ToObject<Dictionary<string, object>>()));
/// <inheritdoc/>
public void GetSlotDataAsync<T>(Action<T> onSlotDataRetrieved, int? slot = null) where T : class =>
GetSlotDataElement(slot).GetAsync(t => onSlotDataRetrieved(t?.ToObject<T>()));
#else
/// <inheritdoc />
public Task<Dictionary<string, object>> GetSlotDataAsync(int? slot = null) =>
GetSlotDataElement(slot).GetAsync<Dictionary<string, object>>();
GetSlotDataAsync<Dictionary<string, object>>(slot);
/// <inheritdoc/>
public Task<T> GetSlotDataAsync<T>(int? slot = null) where T : class =>
GetSlotDataElement(slot).GetAsync<T>();
#endif

/// <inheritdoc />
Expand Down
Loading