Skip to content

Commit d80e4de

Browse files
authored
feat: New Changed Aspect Ratio Event & Player::AspectRatio Property (#556)
* Create AspectRatioType.cs * Create FloatExtensions.cs * Add Player Aspect Ratio Property * Create ChangedRatioEventArgs.cs * Added ChangedRatio handlers * Create ChangedAspectRatio.cs * Added 1_1 Square type * Added Unknow and 1_1 ratio
1 parent 24795f4 commit d80e4de

6 files changed

Lines changed: 271 additions & 0 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="AspectRatioType.cs" company="ExMod Team">
3+
// Copyright (c) ExMod Team. All rights reserved.
4+
// Licensed under the CC BY-SA 3.0 license.
5+
// </copyright>
6+
// -----------------------------------------------------------------------
7+
8+
namespace Exiled.API.Enums
9+
{
10+
/// <summary>
11+
/// All available screen aspect ratio types.
12+
/// </summary>
13+
public enum AspectRatioType : byte
14+
{
15+
/// <summary>
16+
/// Unknown aspect ratio.
17+
/// </summary>
18+
Unknown,
19+
20+
/// <summary>
21+
/// 1:1 aspect ratio (square screen).
22+
/// </summary>
23+
Ratio1_1,
24+
25+
/// <summary>
26+
/// 3:2 aspect ratio.
27+
/// </summary>
28+
Ratio3_2,
29+
30+
/// <summary>
31+
/// 4:3 aspect ratio (standard definition TVs, older monitors).
32+
/// </summary>
33+
Ratio4_3,
34+
35+
/// <summary>
36+
/// 5:4 aspect ratio (some older computer monitors).
37+
/// </summary>
38+
Ratio5_4,
39+
40+
/// <summary>
41+
/// 16:9 aspect ratio (modern widescreen displays, HDTV).
42+
/// </summary>
43+
Ratio16_9,
44+
45+
/// <summary>
46+
/// 16:10 aspect ratio (common in productivity monitors and laptops).
47+
/// </summary>
48+
Ratio16_10,
49+
50+
/// <summary>
51+
/// 21:9 aspect ratio (ultrawide displays).
52+
/// </summary>
53+
Ratio21_9,
54+
55+
/// <summary>
56+
/// 32:9 aspect ratio (super ultrawide displays).
57+
/// </summary>
58+
Ratio32_9,
59+
}
60+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="FloatExtensions.cs" company="ExMod Team">
3+
// Copyright (c) ExMod Team. All rights reserved.
4+
// Licensed under the CC BY-SA 3.0 license.
5+
// </copyright>
6+
// -----------------------------------------------------------------------
7+
8+
namespace Exiled.API.Extensions
9+
{
10+
using System;
11+
using System.Collections.Generic;
12+
13+
using Exiled.API.Enums;
14+
15+
/// <summary>
16+
/// A set of extensions for <see cref="float"/>.
17+
/// </summary>
18+
public static class FloatExtensions
19+
{
20+
private static readonly Dictionary<AspectRatioType, float> AspectRatioReferences = new()
21+
{
22+
{ AspectRatioType.Unknown, 0f },
23+
{ AspectRatioType.Ratio1_1, 1f },
24+
{ AspectRatioType.Ratio3_2, 3f / 2f },
25+
{ AspectRatioType.Ratio4_3, 4f / 3f },
26+
{ AspectRatioType.Ratio5_4, 5f / 4f },
27+
{ AspectRatioType.Ratio16_9, 16f / 9f },
28+
{ AspectRatioType.Ratio16_10, 16f / 10f },
29+
{ AspectRatioType.Ratio21_9, 21f / 9f },
30+
{ AspectRatioType.Ratio32_9, 32f / 9f },
31+
};
32+
33+
/// <summary>
34+
/// Gets the closest <see cref="AspectRatioType"/> for a given aspect ratio value.
35+
/// </summary>
36+
/// <param name="ratio">The aspect ratio value to compare.</param>
37+
/// <returns>The closest matching <see cref="AspectRatioType"/>.</returns>
38+
public static AspectRatioType GetAspectRatioLabel(this float ratio)
39+
{
40+
float closestDiff = float.MaxValue;
41+
AspectRatioType closestRatio = AspectRatioType.Unknown;
42+
43+
foreach (KeyValuePair<AspectRatioType, float> kvp in AspectRatioReferences)
44+
{
45+
float diff = Math.Abs(ratio - kvp.Value);
46+
if (diff < closestDiff)
47+
{
48+
closestDiff = diff;
49+
closestRatio = kvp.Key;
50+
}
51+
}
52+
53+
return closestRatio;
54+
}
55+
}
56+
}

EXILED/Exiled.API/Features/Player.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@ public PlayerInfoArea InfoArea
343343
set => ReferenceHub.nicknameSync.Network_playerInfoToShow = value;
344344
}
345345

346+
/// <summary>
347+
/// Gets the player's current aspect ratio type.
348+
/// </summary>
349+
public AspectRatioType AspectRatio => ReferenceHub.aspectRatioSync.AspectRatio.GetAspectRatioLabel();
350+
346351
/// <summary>
347352
/// Gets or sets the player's custom player info string. This string is displayed along with the player's <see cref="InfoArea"/>.
348353
/// </summary>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="ChangedRatioEventArgs.cs" company="ExMod Team">
3+
// Copyright (c) ExMod Team. All rights reserved.
4+
// Licensed under the CC BY-SA 3.0 license.
5+
// </copyright>
6+
// -----------------------------------------------------------------------
7+
8+
namespace Exiled.Events.EventArgs.Player
9+
{
10+
using Exiled.API.Enums;
11+
using Exiled.API.Extensions;
12+
using Exiled.API.Features;
13+
using Exiled.Events.EventArgs.Interfaces;
14+
15+
/// <summary>
16+
/// Contains all information after a player's Aspect Ratio changes.
17+
/// </summary>
18+
public class ChangedRatioEventArgs : IPlayerEvent
19+
{
20+
/// <summary>
21+
/// Initializes a new instance of the <see cref="ChangedRatioEventArgs"/> class.
22+
/// </summary>
23+
/// <param name="player">The player who is changed ratio.
24+
/// <inheritdoc cref="Player" />
25+
/// </param>
26+
/// <param name="oldratio">Old aspect ratio of the player.
27+
/// <inheritdoc cref="float" />
28+
/// </param>
29+
/// <param name="newratio">New aspect ratio of the player.
30+
/// <inheritdoc cref="float" />
31+
/// </param>
32+
public ChangedRatioEventArgs(ReferenceHub player, float oldratio, float newratio)
33+
{
34+
Player = Player.Get(player);
35+
OldRatio = oldratio.GetAspectRatioLabel();
36+
NewRatio = newratio.GetAspectRatioLabel();
37+
}
38+
39+
/// <summary>
40+
/// Gets the player who is changed ratio.
41+
/// </summary>
42+
public Player Player { get; }
43+
44+
/// <summary>
45+
/// Gets the players old ratio.
46+
/// </summary>
47+
public AspectRatioType OldRatio { get; }
48+
49+
/// <summary>
50+
/// Gets the players new ratio.
51+
/// </summary>
52+
public AspectRatioType NewRatio { get; }
53+
}
54+
}

EXILED/Exiled.Events/Handlers/Player.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ public class Player
103103
/// </summary>
104104
public static Event<CancelledItemUseEventArgs> CancelledItemUse { get; set; } = new();
105105

106+
/// <summary>
107+
/// Invoked after a <see cref="API.Features.Player"/>'s aspect ratio has changed.
108+
/// </summary>
109+
public static Event<ChangedRatioEventArgs> ChangedRatio { get; set; } = new();
110+
106111
/// <summary>
107112
/// Invoked after a <see cref="API.Features.Player"/> interacted with something.
108113
/// </summary>
@@ -684,6 +689,12 @@ public class Player
684689
/// <param name="ev">The <see cref="CancelledItemUseEventArgs"/> instance.</param>
685690
public static void OnCancelledItemUse(CancelledItemUseEventArgs ev) => CancelledItemUse.InvokeSafely(ev);
686691

692+
/// <summary>
693+
/// Called after a <see cref="API.Features.Player"/>'s aspect ratio changes.
694+
/// </summary>
695+
/// <param name="ev">The <see cref="ChangedRatioEventArgs"/> instance.</param>
696+
public static void OnChangedRatio(ChangedRatioEventArgs ev) => ChangedRatio.InvokeSafely(ev);
697+
687698
/// <summary>
688699
/// Called after a <see cref="API.Features.Player"/> interacted with something.
689700
/// </summary>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="ChangedAspectRatio.cs" company="ExMod Team">
3+
// Copyright (c) ExMod Team. All rights reserved.
4+
// Licensed under the CC BY-SA 3.0 license.
5+
// </copyright>
6+
// -----------------------------------------------------------------------
7+
8+
namespace Exiled.Events.Patches.Events.Player
9+
{
10+
using System.Collections.Generic;
11+
using System.Reflection.Emit;
12+
13+
using API.Features.Pools;
14+
using CentralAuth;
15+
using Exiled.Events.EventArgs.Player;
16+
using HarmonyLib;
17+
using UnityEngine;
18+
19+
using static HarmonyLib.AccessTools;
20+
21+
/// <summary>
22+
/// Patches <see cref="AspectRatioSync.UserCode_CmdSetAspectRatio__Single" />.
23+
/// Adds the <see cref="Handlers.Player.ChangedRatio" /> event.
24+
/// </summary>
25+
[HarmonyPatch(typeof(AspectRatioSync), nameof(AspectRatioSync.UserCode_CmdSetAspectRatio__Single))]
26+
internal class ChangedAspectRatio
27+
{
28+
private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator)
29+
{
30+
List<CodeInstruction> newInstructions = ListPool<CodeInstruction>.Pool.Get(instructions);
31+
32+
LocalBuilder oldratio = generator.DeclareLocal(typeof(float));
33+
LocalBuilder hub = generator.DeclareLocal(typeof(ReferenceHub));
34+
35+
Label retLabel = generator.DefineLabel();
36+
37+
newInstructions.InsertRange(0, new CodeInstruction[]
38+
{
39+
// float OldRatio = this.AspectRatio;
40+
new(OpCodes.Ldarg_0),
41+
new(OpCodes.Callvirt, PropertyGetter(typeof(AspectRatioSync), nameof(AspectRatioSync.AspectRatio))),
42+
new(OpCodes.Stloc_S, oldratio.LocalIndex),
43+
});
44+
45+
int index = newInstructions.FindLastIndex(i => i.opcode == OpCodes.Ret);
46+
newInstructions[index].WithLabels(retLabel);
47+
48+
newInstructions.InsertRange(index, new CodeInstruction[]
49+
{
50+
// ReferenceHub hub = this.GetComponent<ReferenceHub>();
51+
new(OpCodes.Ldarg_0),
52+
new(OpCodes.Call, Method(typeof(Component), nameof(Component.GetComponent)).MakeGenericMethod(typeof(ReferenceHub))),
53+
new(OpCodes.Dup),
54+
new(OpCodes.Stloc_S, hub.LocalIndex),
55+
56+
// if (hub.authManager._targetInstanceMode != ClientInstanceMode.ReadyClient) return;
57+
new(OpCodes.Ldfld, Field(typeof(ReferenceHub), nameof(ReferenceHub.authManager))),
58+
new(OpCodes.Ldfld, Field(typeof(PlayerAuthenticationManager), nameof(PlayerAuthenticationManager._targetInstanceMode))),
59+
new(OpCodes.Ldc_I4, 1),
60+
new(OpCodes.Bne_Un_S, retLabel),
61+
62+
// hub
63+
new(OpCodes.Ldloc, hub.LocalIndex),
64+
65+
// OldRatio
66+
new(OpCodes.Ldloc, oldratio.LocalIndex),
67+
68+
// this.AspectRatio
69+
new(OpCodes.Ldarg_0),
70+
new(OpCodes.Call, PropertyGetter(typeof(AspectRatioSync), nameof(AspectRatioSync.AspectRatio))),
71+
72+
// ChangedRatioEventArgs ev = new ChangedRatioEventArgs(ReferenceHub, float, float)
73+
new(OpCodes.Newobj, GetDeclaredConstructors(typeof(ChangedRatioEventArgs))[0]),
74+
75+
// Handlers.Player.OnChangedRatio(ev);
76+
new(OpCodes.Call, Method(typeof(Handlers.Player), nameof(Handlers.Player.OnChangedRatio))),
77+
});
78+
79+
for (int i = 0; i < newInstructions.Count; i++)
80+
yield return newInstructions[i];
81+
82+
ListPool<CodeInstruction>.Pool.Return(newInstructions);
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)