A game framework written with osu! in mind.
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'master' into bassmix

+227 -193
+43
osu.Framework.Benchmarks/BenchmarkLocalisableDescription.cs
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + using BenchmarkDotNet.Attributes; 5 + using osu.Framework.Extensions; 6 + using osu.Framework.Localisation; 7 + 8 + namespace osu.Framework.Benchmarks 9 + { 10 + public class BenchmarkLocalisableDescription 11 + { 12 + private LocalisableString[] descriptions; 13 + 14 + [Params(1, 10, 100, 1000)] 15 + public int Times { get; set; } 16 + 17 + [GlobalSetup] 18 + public void SetUp() 19 + { 20 + descriptions = new LocalisableString[Times]; 21 + } 22 + 23 + [Benchmark] 24 + public LocalisableString[] GetLocalisableDescription() 25 + { 26 + for (int i = 0; i < Times; i++) 27 + descriptions[i] = TestLocalisableEnum.One.GetLocalisableDescription(); 28 + 29 + return descriptions; 30 + } 31 + 32 + private enum TestLocalisableEnum 33 + { 34 + [LocalisableDescription(typeof(TestStrings), nameof(TestStrings.One))] 35 + One, 36 + } 37 + 38 + private static class TestStrings 39 + { 40 + public static LocalisableString One => "1"; 41 + } 42 + } 43 + }
+1 -1
osu.Framework.Templates/templates/template-empty/TemplateGame.Game/TemplateGame.Game.csproj
··· 6 6 <ProjectReference Include="..\TemplateGame.Resources\TemplateGame.Resources.csproj" /> 7 7 </ItemGroup> 8 8 <ItemGroup> 9 - <PackageReference Include="ppy.osu.Framework" Version="2021.630.0" /> 9 + <PackageReference Include="ppy.osu.Framework" Version="2021.728.0" /> 10 10 </ItemGroup> 11 11 </Project>
+2 -2
osu.Framework.Templates/templates/template-empty/TemplateGame.iOS/TemplateGame.iOS.csproj
··· 150 150 <Reference Include="System.Net.Http" /> 151 151 </ItemGroup> 152 152 <ItemGroup Label="Package References"> 153 - <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.630.0" /> 153 + <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.728.0" /> 154 154 </ItemGroup> 155 155 <ItemGroup Label="Transitive Dependencies"> 156 - <PackageReference Include="ppy.osu.Framework" Version="2021.630.0" /> 156 + <PackageReference Include="ppy.osu.Framework" Version="2021.728.0" /> 157 157 <PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.1104.0" ExcludeAssets="all" /> 158 158 </ItemGroup> 159 159 <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
+1 -1
osu.Framework.Templates/templates/template-flappy/FlappyDon.Game/FlappyDon.Game.csproj
··· 3 3 <TargetFramework>netstandard2.1</TargetFramework> 4 4 </PropertyGroup> 5 5 <ItemGroup> 6 - <PackageReference Include="ppy.osu.Framework" Version="2021.630.0" /> 6 + <PackageReference Include="ppy.osu.Framework" Version="2021.728.0" /> 7 7 </ItemGroup> 8 8 <ItemGroup> 9 9 <ProjectReference Include="..\FlappyDon.Resources\FlappyDon.Resources.csproj" />
+2 -2
osu.Framework.Templates/templates/template-flappy/FlappyDon.iOS/FlappyDon.iOS.csproj
··· 162 162 <Reference Include="System.Net.Http" /> 163 163 </ItemGroup> 164 164 <ItemGroup Label="Package References"> 165 - <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.630.0" /> 165 + <PackageReference Include="ppy.osu.Framework.iOS" Version="2021.728.0" /> 166 166 </ItemGroup> 167 167 <ItemGroup Label="Transitive Dependencies"> 168 - <PackageReference Include="ppy.osu.Framework" Version="2021.630.0" /> 168 + <PackageReference Include="ppy.osu.Framework" Version="2021.728.0" /> 169 169 <PackageReference Include="ppy.osu.Framework.NativeLibs" Version="2019.1104.0" ExcludeAssets="all" /> 170 170 </ItemGroup> 171 171 <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
+89
osu.Framework.Tests/Localisation/LocalisableDescriptionAttributeTest.cs
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + using System; 5 + using NUnit.Framework; 6 + using osu.Framework.Extensions; 7 + using osu.Framework.Localisation; 8 + 9 + namespace osu.Framework.Tests.Localisation 10 + { 11 + [TestFixture] 12 + public class LocalisableDescriptionAttributeTest 13 + { 14 + [TestCase(EnumA.Item1, "Item1")] 15 + [TestCase(EnumA.Item2, "B")] 16 + public void TestNonLocalisableDescriptionReturnsDescriptionOrToString(EnumA value, string expected) 17 + { 18 + Assert.That(value.GetLocalisableDescription().ToString(), Is.EqualTo(expected)); 19 + } 20 + 21 + [TestCase(EnumB.Item1, "Localised A")] 22 + [TestCase(EnumB.Item2, "Localised B")] 23 + public void TestLocalisableDescriptionReturnsDesignatedString(EnumB value, string expected) 24 + { 25 + Assert.That(value.GetLocalisableDescription().ToString(), Is.EqualTo(expected)); 26 + } 27 + 28 + [Test] 29 + public void TestClassLocalisableDescription() 30 + { 31 + Assert.That(new ClassA().GetLocalisableDescription().ToString(), Is.EqualTo("Localised A")); 32 + } 33 + 34 + [Test] 35 + public void TestLocalisableDescriptionWithNonExistingMemberThrows() 36 + { 37 + Assert.Throws<InvalidOperationException>(() => EnumC.Item1.GetLocalisableDescription()); 38 + } 39 + 40 + [Test] 41 + public void TestLocalisableDescriptionWithInstanceMemberThrows() 42 + { 43 + Assert.Throws<InvalidOperationException>(() => EnumD.Item1.GetLocalisableDescription()); 44 + } 45 + 46 + public enum EnumA 47 + { 48 + Item1, 49 + 50 + [System.ComponentModel.Description("B")] 51 + Item2 52 + } 53 + 54 + public enum EnumB 55 + { 56 + [LocalisableDescription(typeof(TestStrings), nameof(TestStrings.A))] 57 + Item1, 58 + 59 + [LocalisableDescription(typeof(TestStrings), nameof(TestStrings.B))] 60 + Item2 61 + } 62 + 63 + public enum EnumC 64 + { 65 + [LocalisableDescription(typeof(LocalisableDescriptionAttributeTest), nameof(TestStrings.A))] 66 + Item1, 67 + } 68 + 69 + public enum EnumD 70 + { 71 + [LocalisableDescription(typeof(TestStrings), nameof(TestStrings.Instance))] 72 + Item1, 73 + } 74 + 75 + [LocalisableDescription(typeof(TestStrings), nameof(TestStrings.A))] 76 + public class ClassA 77 + { 78 + } 79 + 80 + private class TestStrings 81 + { 82 + public static LocalisableString A => "Localised A"; 83 + 84 + public static readonly LocalisableString B = "Localised B"; 85 + 86 + public LocalisableString Instance => string.Empty; 87 + } 88 + } 89 + }
-96
osu.Framework.Tests/Localisation/LocalisableEnumAttributeTest.cs
··· 1 - // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 - // See the LICENCE file in the repository root for full licence text. 3 - 4 - using System; 5 - using NUnit.Framework; 6 - using osu.Framework.Extensions; 7 - using osu.Framework.Localisation; 8 - 9 - namespace osu.Framework.Tests.Localisation 10 - { 11 - [TestFixture] 12 - public class LocalisableEnumAttributeTest 13 - { 14 - [TestCase(EnumA.Item1, "Item1")] 15 - [TestCase(EnumA.Item2, "B")] 16 - public void TestNonLocalisableEnumReturnsDescriptionOrToString(EnumA value, string expected) 17 - { 18 - Assert.That(value.GetLocalisableDescription().ToString(), Is.EqualTo(expected)); 19 - } 20 - 21 - [TestCase(EnumB.Item1, "A")] 22 - [TestCase(EnumB.Item2, "B")] 23 - public void TestLocalisableEnumReturnsMappedValue(EnumB value, string expected) 24 - { 25 - Assert.That(value.GetLocalisableDescription().ToString(), Is.EqualTo(expected)); 26 - } 27 - 28 - [Test] 29 - public void TestLocalisableEnumWithInvalidBaseTypeThrows() 30 - { 31 - // ReSharper disable once ReturnValueOfPureMethodIsNotUsed 32 - Assert.Throws<ArgumentException>(() => EnumC.Item1.GetLocalisableDescription().ToString()); 33 - } 34 - 35 - [Test] 36 - public void TestLocalisableEnumWithInvalidGenericTypeThrows() 37 - { 38 - // ReSharper disable once ReturnValueOfPureMethodIsNotUsed 39 - Assert.Throws<InvalidOperationException>(() => EnumD.Item1.GetLocalisableDescription().ToString()); 40 - } 41 - 42 - public enum EnumA 43 - { 44 - Item1, 45 - 46 - [System.ComponentModel.Description("B")] 47 - Item2 48 - } 49 - 50 - [LocalisableEnum(typeof(EnumBEnumLocalisationMapper))] 51 - public enum EnumB 52 - { 53 - Item1, 54 - Item2 55 - } 56 - 57 - private class EnumBEnumLocalisationMapper : EnumLocalisationMapper<EnumB> 58 - { 59 - public override LocalisableString Map(EnumB value) 60 - { 61 - switch (value) 62 - { 63 - case EnumB.Item1: 64 - return "A"; 65 - 66 - case EnumB.Item2: 67 - return "B"; 68 - 69 - default: 70 - throw new ArgumentOutOfRangeException(nameof(value), value, null); 71 - } 72 - } 73 - } 74 - 75 - [LocalisableEnum(typeof(EnumCEnumLocalisationMapper))] 76 - public enum EnumC 77 - { 78 - Item1, 79 - } 80 - 81 - private class EnumCEnumLocalisationMapper 82 - { 83 - } 84 - 85 - [LocalisableEnum(typeof(EnumDEnumLocalisationMapper))] 86 - public enum EnumD 87 - { 88 - Item1, 89 - } 90 - 91 - private class EnumDEnumLocalisationMapper : EnumLocalisationMapper<EnumA> 92 - { 93 - public override LocalisableString Map(EnumA value) => "A"; 94 - } 95 - } 96 - }
+25 -24
osu.Framework/Extensions/ExtensionMethods.cs
··· 4 4 using System; 5 5 using System.Collections.Generic; 6 6 using System.ComponentModel; 7 - using System.Diagnostics; 8 7 using System.Drawing; 9 8 using System.IO; 10 9 using System.Linq; 11 10 using System.Reflection; 12 11 using System.Security.Cryptography; 13 12 using System.Text; 14 - using osu.Framework.Extensions.TypeExtensions; 13 + using osu.Framework.Extensions.ObjectExtensions; 15 14 using osu.Framework.Localisation; 16 15 using osu.Framework.Platform; 17 16 using osuTK; ··· 178 177 } 179 178 180 179 /// <summary> 181 - /// Returns the description of a given enum value, via (in order): 180 + /// Returns the localisable description of a given object, via (in order): 182 181 /// <list type="number"> 183 182 /// <item> 184 - /// <description>Any <see cref="LocalisableEnumAttribute"/> attached to the enum type.</description> 183 + /// <description>Any attached <see cref="LocalisableDescriptionAttribute"/>.</description> 185 184 /// </item> 186 185 /// <item> 187 186 /// <description><see cref="GetDescription"/></description> 188 187 /// </item> 189 188 /// </list> 190 189 /// </summary> 191 - /// <exception cref="InvalidOperationException">When the enum type has an attached <see cref="LocalisableEnumAttribute"/> 192 - /// and the <see cref="EnumLocalisationMapper{T}"/> could not be instantiated.</exception> 193 - /// <exception cref="InvalidOperationException">When the enum type has an attached <see cref="LocalisableEnumAttribute"/> 194 - /// and the type handled by the <see cref="EnumLocalisationMapper{T}"/> is not <typeparamref name="T"/>.</exception> 190 + /// <exception cref="InvalidOperationException"> 191 + /// When the <see cref="LocalisableDescriptionAttribute.Name"/> specified in the <see cref="LocalisableDescriptionAttribute"/> 192 + /// does not match any of the existing members in <see cref="LocalisableDescriptionAttribute.DeclaringType"/>. 193 + /// </exception> 195 194 public static LocalisableString GetLocalisableDescription<T>(this T value) 196 - where T : Enum 197 195 { 198 - var enumType = value.GetType(); 196 + MemberInfo type; 199 197 200 - var mapperType = enumType.GetCustomAttribute<LocalisableEnumAttribute>()?.MapperType; 201 - if (mapperType == null) 202 - return GetDescription(value); 198 + if (value is Enum) 199 + type = value.GetType().GetField(value.ToString()); 200 + else 201 + type = value.GetType(); 203 202 204 - var mapperInstance = Activator.CreateInstance(mapperType); 205 - if (mapperInstance == null) 206 - throw new InvalidOperationException($"Could not create the {nameof(EnumLocalisationMapper<T>)} for enum type {enumType.ReadableName()}"); 203 + var attribute = type.GetCustomAttribute<LocalisableDescriptionAttribute>(); 204 + if (attribute == null) 205 + return GetDescription(value); 207 206 208 - var mapMethod = mapperType.GetMethod(nameof(EnumLocalisationMapper<T>.Map), BindingFlags.Instance | BindingFlags.Public); 209 - Debug.Assert(mapMethod != null); 207 + var property = attribute.DeclaringType.GetMember(attribute.Name, BindingFlags.Static | BindingFlags.Public).FirstOrDefault(); 210 208 211 - var expectedMappingType = mapMethod.GetParameters()[0].ParameterType; 212 - if (expectedMappingType != enumType) 213 - throw new InvalidOperationException($"Cannot use {mapperType.ReadableName()} (maps {expectedMappingType.ReadableName()} enum values) to map {enumType.ReadableName()} enum values."); 209 + switch (property) 210 + { 211 + case FieldInfo f: 212 + return (LocalisableString)f.GetValue(null).AsNonNull(); 214 213 215 - var mappedValue = mapMethod.Invoke(mapperInstance, new object[] { value }); 216 - Debug.Assert(mappedValue != null); 214 + case PropertyInfo p: 215 + return (LocalisableString)p.GetValue(null).AsNonNull(); 217 216 218 - return (LocalisableString)mappedValue; 217 + default: 218 + throw new InvalidOperationException($"Member \"{attribute.Name}\" was not found in type {attribute.DeclaringType} (must be a static field or property)"); 219 + } 219 220 } 220 221 221 222 /// <summary>
+2 -2
osu.Framework/Graphics/Drawable.cs
··· 428 428 /// <summary> 429 429 /// A lock exclusively used for initial acquisition/construction of the <see cref="Scheduler"/>. 430 430 /// </summary> 431 - private readonly object schedulerAcquisitionLock = new object(); 431 + private static readonly object scheduler_acquisition_lock = new object(); 432 432 433 433 private Scheduler scheduler; 434 434 ··· 443 443 if (scheduler != null) 444 444 return scheduler; 445 445 446 - lock (schedulerAcquisitionLock) 446 + lock (scheduler_acquisition_lock) 447 447 return scheduler ??= new Scheduler(() => ThreadSafety.IsUpdateThread, Clock); 448 448 } 449 449 }
-29
osu.Framework/Localisation/EnumLocalisationMapper.cs
··· 1 - // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 - // See the LICENCE file in the repository root for full licence text. 3 - 4 - using System; 5 - 6 - namespace osu.Framework.Localisation 7 - { 8 - /// <summary> 9 - /// Describes the values of an <see cref="Enum"/> type by <see cref="LocalisableString"/>s. 10 - /// </summary> 11 - /// <typeparam name="T">The <see cref="Enum"/> type.</typeparam> 12 - public abstract class EnumLocalisationMapper<T> : IEnumLocalisationMapper 13 - where T : Enum 14 - { 15 - /// <summary> 16 - /// Describes a <typeparamref name="T"/> value by a <see cref="LocalisableString"/>. 17 - /// </summary> 18 - /// <param name="value">The value to map.</param> 19 - /// <returns>The <see cref="LocalisableString"/> describing <paramref name="value"/>.</returns> 20 - public abstract LocalisableString Map(T value); 21 - } 22 - 23 - /// <summary> 24 - /// Marker class for <see cref="EnumLocalisationMapper{T}"/>. Do not use. 25 - /// </summary> 26 - internal interface IEnumLocalisationMapper 27 - { 28 - } 29 - }
+57
osu.Framework/Localisation/LocalisableDescriptionAttribute.cs
··· 1 + // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 + // See the LICENCE file in the repository root for full licence text. 3 + 4 + using System; 5 + using osu.Framework.Extensions; 6 + 7 + namespace osu.Framework.Localisation 8 + { 9 + /// <summary> 10 + /// Specifies a <see cref="LocalisableString"/>-based description for the target element. 11 + /// The description can be retrieved through <see cref="ExtensionMethods.GetLocalisableDescription{T}"/>. 12 + /// </summary> 13 + /// <remarks> 14 + /// The C# language specification 15 + /// <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/attributes#attribute-parameter-types"> 16 + /// only permits a limited set of parameter types for attributes, 17 + /// </a> 18 + /// and as such <see cref="LocalisableString"/> instances cannot be passed in directly. 19 + /// Therefore usages must pass both the target type in which the <see cref="LocalisableString"/> description is declared, 20 + /// as well as the name of the member which contains/returns the <see cref="LocalisableString"/> (using <see langword="nameof"/> for this is strongly encouraged). 21 + /// </remarks> 22 + /// <example> 23 + /// Assuming the following source class from which the <see cref="LocalisableString"/> description should be returned: 24 + /// <code> 25 + /// class Strings 26 + /// { 27 + /// public static LocalisableString Example => "example string"; 28 + /// } 29 + /// </code> 30 + /// the attribute should be used in the following way: 31 + /// <code> 32 + /// [LocalisableDescription(typeof(Strings), nameof(Strings.Example))] 33 + /// </code> 34 + /// </example> 35 + [AttributeUsage(AttributeTargets.All)] 36 + public sealed class LocalisableDescriptionAttribute : Attribute 37 + { 38 + /// <summary> 39 + /// The type declaring the static member providing the localisable description. 40 + /// </summary> 41 + public readonly Type DeclaringType; 42 + 43 + /// <summary> 44 + /// The name of the static member providing the localisable description. 45 + /// </summary> 46 + public readonly string Name; 47 + 48 + /// <summary> 49 + /// Creates a new <see cref="LocalisableDescriptionAttribute"/>. 50 + /// </summary> 51 + public LocalisableDescriptionAttribute(Type declaringType, string name) 52 + { 53 + DeclaringType = declaringType; 54 + Name = name; 55 + } 56 + } 57 + }
-34
osu.Framework/Localisation/LocalisableEnumAttribute.cs
··· 1 - // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2 - // See the LICENCE file in the repository root for full licence text. 3 - 4 - using System; 5 - using osu.Framework.Extensions; 6 - using osu.Framework.Extensions.TypeExtensions; 7 - 8 - namespace osu.Framework.Localisation 9 - { 10 - /// <summary> 11 - /// Indicates that the values of an enum have <see cref="LocalisableString"/> descriptions. 12 - /// The descriptions can be retrieved through <see cref="ExtensionMethods.GetLocalisableDescription{T}"/>. 13 - /// </summary> 14 - [AttributeUsage(AttributeTargets.Enum)] 15 - public sealed class LocalisableEnumAttribute : Attribute 16 - { 17 - /// <summary> 18 - /// The <see cref="EnumLocalisationMapper{T}"/> type that maps enum values to <see cref="LocalisableString"/>s. 19 - /// </summary> 20 - public readonly Type MapperType; 21 - 22 - /// <summary> 23 - /// Creates a new <see cref="LocalisableEnumAttribute"/>. 24 - /// </summary> 25 - /// <param name="mapperType">The <see cref="EnumLocalisationMapper{T}"/> type that maps enum values to <see cref="LocalisableString"/>s.</param> 26 - public LocalisableEnumAttribute(Type mapperType) 27 - { 28 - MapperType = mapperType; 29 - 30 - if (!typeof(IEnumLocalisationMapper).IsAssignableFrom(mapperType)) 31 - throw new ArgumentException($"Type \"{mapperType.ReadableName()}\" must inherit from {nameof(EnumLocalisationMapper<Enum>)}.", nameof(mapperType)); 32 - } 33 - } 34 - }
+5 -2
osu.Framework/Platform/Windows/Native/Input.cs
··· 10 10 internal static class Input 11 11 { 12 12 [DllImport("user32.dll")] 13 - public static extern bool RegisterRawInputDevices([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] 14 - RawInputDevice[] pRawInputDevices, int uiNumDevices, int cbSize); 13 + public static extern bool RegisterRawInputDevices( 14 + [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] 15 + RawInputDevice[] pRawInputDevices, 16 + int uiNumDevices, 17 + int cbSize); 15 18 16 19 [DllImport("user32.dll")] 17 20 public static extern int GetRawInputData(IntPtr hRawInput, RawInputCommand uiCommand, out RawInputData pData, ref int pcbSize, int cbSizeHeader);