Skip to content

Commit d49d862

Browse files
authored
Merge branch 'release-3.3.6' into fix/display-encryption-key
2 parents 31f4c8f + 66a5041 commit d49d862

File tree

4 files changed

+140
-18
lines changed

4 files changed

+140
-18
lines changed

Assets/Tests/PlayMode/Config/JsonConverters/ListOfStringsToEnumConverterTests.cs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace PlayEveryWare.EpicOnlineServices.Tests.Config
3030
using Newtonsoft.Json.Linq;
3131
public static partial class ListOfStringsToEnumConverterTests
3232
{
33-
private static readonly Dictionary<string, TestOrderEnum> CUSTOM_MAPPING = new()
33+
private static readonly Dictionary<string, TestOrderEnum> TESTORDERENUM_CUSTOM_MAPPING = new()
3434
{
3535
{ "FirstLetter", TestOrderEnum.A },
3636
{ "SecondLetter", TestOrderEnum.B },
@@ -47,18 +47,38 @@ private enum TestOrderEnum : int
4747
C = 0x00008
4848
}
4949

50-
private class ListOfStringsToEnumConverterTestClass : ListOfStringsToEnumConverter<TestOrderEnum>
50+
/// <summary>
51+
/// This Enum is explicitly marked as a flag, and lacks a "0" value.
52+
/// There are Flags inside the EOS SDK C# that do not set a "0".
53+
/// <seealso cref="Epic.OnlineServices.IntegratedPlatform.IntegratedPlatformManagementFlags"/>
54+
/// </summary>
55+
[Flags]
56+
private enum TestFlagWithoutZeroEnum : int
5157
{
52-
protected override TestOrderEnum FromStringArray(JArray array)
58+
A = 0x00001,
59+
B = 0x00002,
60+
C = 0x00004
61+
}
62+
63+
private class ListOfStringsToEnumConverterTestClass<TEnum> : ListOfStringsToEnumConverter<TEnum> where TEnum : struct, Enum
64+
{
65+
private readonly Dictionary<string, TEnum> mappings;
66+
67+
public ListOfStringsToEnumConverterTestClass(Dictionary<string, TEnum> inMappings)
5368
{
54-
return FromStringArrayWithCustomMapping(array, CUSTOM_MAPPING);
69+
mappings = inMappings;
70+
}
71+
72+
protected override TEnum FromStringArray(JArray array)
73+
{
74+
return FromStringArrayWithCustomMapping(array, mappings);
5575
}
5676
}
5777

5878
[Test]
5979
public static void ListOfStringsToEnumConverterTestClass_ReadJson_ArrayOfStrings_ReturnsCorrectEnum()
6080
{
61-
var converter = new ListOfStringsToEnumConverterTestClass();
81+
var converter = new ListOfStringsToEnumConverterTestClass<TestOrderEnum>(TESTORDERENUM_CUSTOM_MAPPING);
6282
var json = JArray.FromObject(new[] { "FirstLetter", "ThirdLetter", "B" });
6383
var result = (TestOrderEnum)converter.ReadJson(json.CreateReader(), typeof(InputStateButtonFlags), null, null);
6484

@@ -68,7 +88,7 @@ public static void ListOfStringsToEnumConverterTestClass_ReadJson_ArrayOfStrings
6888
[Test]
6989
public static void ListOfStringsToEnumConverterTestClass_ReadJson_SingleString_ReturnsCorrectEnum()
7090
{
71-
var converter = new ListOfStringsToEnumConverterTestClass();
91+
var converter = new ListOfStringsToEnumConverterTestClass<TestOrderEnum>(TESTORDERENUM_CUSTOM_MAPPING);
7292
var json = JToken.FromObject("A");
7393
var result = (TestOrderEnum)converter.ReadJson(json.CreateReader(), typeof(InputStateButtonFlags), null, null);
7494

@@ -78,7 +98,7 @@ public static void ListOfStringsToEnumConverterTestClass_ReadJson_SingleString_R
7898
[Test]
7999
public static void ListOfStringsToEnumConverterTestClass_ReadJson_Null_ReturnsDefaultEnum()
80100
{
81-
var converter = new ListOfStringsToEnumConverterTestClass();
101+
var converter = new ListOfStringsToEnumConverterTestClass<TestOrderEnum>(TESTORDERENUM_CUSTOM_MAPPING);
82102
var result = (TestOrderEnum)converter.ReadJson(new JValue((string)null).CreateReader(), typeof(InputStateButtonFlags), null, null);
83103

84104
Assert.AreEqual(TestOrderEnum.None, result);
@@ -87,11 +107,25 @@ public static void ListOfStringsToEnumConverterTestClass_ReadJson_Null_ReturnsDe
87107
[Test]
88108
public static void ListOfStringsToEnumConverterTestClass_ReadJson_InvalidTokenType_ThrowsException()
89109
{
90-
var converter = new ListOfStringsToEnumConverterTestClass();
110+
var converter = new ListOfStringsToEnumConverterTestClass<TestOrderEnum>(TESTORDERENUM_CUSTOM_MAPPING);
91111
var invalidJson = JToken.FromObject(123); // Invalid type for enum parsing
92112

93113
Assert.Throws<JsonSerializationException>(() => converter.ReadJson(invalidJson.CreateReader(), typeof(TestOrderEnum), null, null));
94114
}
95115

116+
/// <summary>
117+
/// Converts a '0' into <see cref="TestFlagWithoutZeroEnum"/> using the <see cref="ListOfStringsToEnumConverterTestClass"/>.
118+
/// Even though <see cref="TestFlagWithoutZeroEnum"/> lacks a 0, it is a Flag enum.
119+
/// The resulting value should be equivalent to a '0' integer, as opposed to using the lowest value.
120+
/// </summary>
121+
[Test]
122+
public static void ListOfStringsToEnumConverterTestClass_ReadJson_TestFlagWithoutZeroEnum_EvaluatesToZero()
123+
{
124+
var converter = new ListOfStringsToEnumConverterTestClass<TestFlagWithoutZeroEnum>(null);
125+
var json = JToken.FromObject(0);
126+
var result = (TestFlagWithoutZeroEnum)converter.ReadJson(json.CreateReader(), typeof(TestFlagWithoutZeroEnum), null, null);
127+
128+
Assert.AreEqual((TestFlagWithoutZeroEnum)0, result);
129+
}
96130
}
97131
}

com.playeveryware.eos/Runtime/Core/Common/Utility/EnumUtility.cs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -248,23 +248,45 @@ public static IEnumerable<TEnum> GetEnumerator(TEnum bitFlag)
248248
/// Gets the lowest value in an enum type.
249249
/// </summary>
250250
/// <returns>
251-
/// The lowest type within an enum. If the enum is empty, default is
252-
/// returned.
251+
/// The lowest value within an enum. If the enum is empty, default is returned.
253252
/// </returns>
254253
public static TEnum GetLowest()
255254
{
256-
object lowest = null;
255+
return GetExtreme((current, extreme) => Comparer<object>.Default.Compare(current, extreme) < 0);
256+
}
257+
258+
/// <summary>
259+
/// Gets the highest value in an enum type.
260+
/// </summary>
261+
/// <returns>
262+
/// The highest value within an enum. If the enum is empty, default is returned.
263+
/// </returns>
264+
public static TEnum GetHighest()
265+
{
266+
return GetExtreme((current, extreme) => Comparer<object>.Default.Compare(current, extreme) > 0);
267+
}
268+
269+
/// <summary>
270+
/// Private helper method to determine the extreme (lowest or highest) value in an enum.
271+
/// </summary>
272+
/// <param name="comparison">A comparison delegate to determine the extreme value.</param>
273+
/// <returns>
274+
/// The extreme value within an enum. If the enum is empty, default is returned.
275+
/// </returns>
276+
private static TEnum GetExtreme(Func<object, object, bool> comparison)
277+
{
278+
object extreme = null;
257279
foreach (var value in Enum.GetValues(typeof(TEnum)))
258280
{
259-
if (lowest == null || Comparer<object>.Default.Compare(value, lowest) < 0)
281+
if (extreme == null || comparison(value, extreme))
260282
{
261-
lowest = value;
283+
extreme = value;
262284
}
263285
}
264286

265-
if (lowest != null)
287+
if (extreme != null)
266288
{
267-
return (TEnum)Enum.ToObject(typeof(TEnum), lowest);
289+
return (TEnum)Enum.ToObject(typeof(TEnum), extreme);
268290
}
269291

270292
return default;

com.playeveryware.eos/Runtime/Core/Config/JsonConverter/ListOfStringsToEnumConverters.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace PlayEveryWare.EpicOnlineServices
3636
using Newtonsoft.Json.Linq;
3737
using System;
3838
using System.Collections.Generic;
39+
using System.Diagnostics;
3940
using Utility;
4041

4142
// This compile conditional is here so that when EOS is disabled, nothing is
@@ -184,15 +185,27 @@ protected TEnum FromNumberValue(JToken token)
184185
Type underlyingType = Enum.GetUnderlyingType(typeof(TEnum));
185186
object value = Convert.ChangeType(token, underlyingType);
186187

188+
// Get the lowest and highest values
187189
TEnum lowestEnumValue = EnumUtility<TEnum>.GetLowest();
190+
TEnum highestEnumValue = EnumUtility<TEnum>.GetHighest();
191+
188192
object lowestUnderlyingValue = Convert.ChangeType(lowestEnumValue, underlyingType);
193+
object highestUnderlyingValue = Convert.ChangeType(highestEnumValue, underlyingType);
194+
195+
TEnum finalEnumValue;
189196

190-
if (Comparer<object>.Default.Compare(value, lowestUnderlyingValue) < 0)
197+
// Ensure value is within range
198+
if (Comparer<object>.Default.Compare(value, lowestUnderlyingValue) < 0 || Comparer<object>.Default.Compare(value, highestUnderlyingValue) > 0)
199+
{
200+
UnityEngine.Debug.LogWarning($"Value {value} is out of range for {nameof(TEnum)}, setting to 0.");
201+
finalEnumValue = (TEnum)Enum.ToObject(typeof(TEnum), 0);
202+
}
203+
else
191204
{
192-
value = lowestUnderlyingValue;
205+
finalEnumValue = (TEnum)value;
193206
}
194207

195-
return (TEnum)value;
208+
return finalEnumValue;
196209
}
197210

198211
/// <summary>

com.playeveryware.eos/Runtime/Core/EOSManager.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,17 @@ enum EOSState
184184
static private bool s_isConstrained = true;
185185
static public bool ApplicationIsConstrained { get => s_isConstrained; }
186186

187+
/// <summary>
188+
/// Actions that need to be executed on the main thread.
189+
/// Lazy allocated in <see cref="DispatchAsync"/>.
190+
/// </summary>
191+
private static List<Action> s_enqueuedTasks;
192+
193+
/// <summary>
194+
/// Locak object used for <see cref="s_enqueuedTasks"/>, such that it can
195+
/// be executed thread-safe way.
196+
/// </summary>
197+
private static System.Object s_enqueuedTasksLock = new System.Object();
187198
//private static List
188199

189200
//-------------------------------------------------------------------------
@@ -1553,6 +1564,7 @@ public void RemovePersistentToken()
15531564
//-------------------------------------------------------------------------
15541565
public void Tick()
15551566
{
1567+
ExecuteQueuedMainThreadTasks();
15561568
if (GetEOSPlatformInterface() != null)
15571569
{
15581570
// Poll for any application constrained state change that didn't
@@ -1941,5 +1953,46 @@ void IEOSCoroutineOwner.StartCoroutine(IEnumerator routine)
19411953
{
19421954
base.StartCoroutine(routine);
19431955
}
1956+
1957+
/// <summary>
1958+
/// Enqueues an Action to be executed on the main thread.
1959+
/// </summary>
1960+
/// <param name="action">Action to execute.</param>
1961+
public static void DispatchAsync(Action action)
1962+
{
1963+
lock (s_enqueuedTasksLock)
1964+
{
1965+
// Lazy allocate the queue
1966+
if (s_enqueuedTasks == null)
1967+
{
1968+
s_enqueuedTasks = new List<Action>();
1969+
}
1970+
s_enqueuedTasks.Add(action);
1971+
}
1972+
}
1973+
1974+
private static void ExecuteQueuedMainThreadTasks()
1975+
{
1976+
// Lock the enqued tasks list, and hold reference to the enqueued tasks.
1977+
// This is done so that the foreach loop doesn't potentially go "forever"
1978+
// if a given action in the queue happens to generate a list of tasks that
1979+
// also generate a list of task. The s_enqueuedTasks list is also nulled out
1980+
// because we only allocate the list if we need to queue up new tasks. See DispatchSync
1981+
List<Action> actionsToRun;
1982+
lock (s_enqueuedTasksLock)
1983+
{
1984+
actionsToRun = s_enqueuedTasks;
1985+
s_enqueuedTasks = null;
1986+
if (actionsToRun == null)
1987+
{
1988+
return;
1989+
}
1990+
}
1991+
1992+
foreach (Action action in actionsToRun)
1993+
{
1994+
action.Invoke();
1995+
}
1996+
}
19441997
}
19451998
}

0 commit comments

Comments
 (0)