Skip to content
Closed
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
8 changes: 8 additions & 0 deletions AquaMai.Core/Helpers/Shim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ public static byte[] EncryptNetPacketBody(byte[] data)
return (PacketUpsertUserAll)ctor2.Invoke(args);
};
}
else if (type.GetConstructor([typeof(int), typeof(UserData), typeof(int), typeof(Action<int>), typeof(Action<PacketStatus>)]) is ConstructorInfo ctor3)
{
return (index, src, onDone, onError) =>
{
var args = new object[] { index, src, GameManager.GetMaxTrackCount(), onDone, onError };
return (PacketUpsertUserAll)ctor3.Invoke(args);
};
}
Comment on lines +192 to +199

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While this new else if block is correct, the growing chain of if-else if statements for constructor resolution is becoming hard to maintain. Each block has very similar logic. Consider refactoring this method to use a more data-driven approach, for example, by using a list of 'strategies'.

Each strategy could define the constructor parameter types and a way to build the arguments array. This would reduce code duplication and make it easier to add support for new constructor signatures in the future.

Here's a conceptual example of how it could look for CreatePacketUpsertUserAll:

private record ConstructorStrategy(Type[] ParamTypes, Func<int, UserData, Action<int>, Action<PacketStatus>, object[]> BuildArgs);

public static readonly PacketUpsertUserAllCreator CreatePacketUpsertUserAll = Iife<PacketUpsertUserAllCreator>(() =>
{
    var strategies = new[]
    {
        new ConstructorStrategy(
            [typeof(int), typeof(UserData), typeof(Action<int>), typeof(Action<PacketStatus>)],
            (index, src, onDone, onError) => [index, src, onDone, onError]),
        new ConstructorStrategy(
            [typeof(int), typeof(UserData), typeof(string), typeof(Action<int>), typeof(Action<PacketStatus>)],
            (index, src, onDone, onError) => [index, src, GetAccessToken(index), onDone, onError]),
        new ConstructorStrategy(
            [typeof(int), typeof(UserData), typeof(int), typeof(Action<int>), typeof(Action<PacketStatus>)],
            (index, src, onDone, onError) => [index, src, GameManager.GetMaxTrackCount(), onDone, onError])
    };

    var type = typeof(PacketUpsertUserAll);
    foreach (var (paramTypes, buildArgs) in strategies)
    {
        if (type.GetConstructor(paramTypes) is ConstructorInfo ctor)
        {
            return (index, src, onDone, onError) =>
            {
                var args = buildArgs(index, src, onDone, onError);
                return (PacketUpsertUserAll)ctor.Invoke(args);
            };
        }
    }

    throw new MissingMethodException("No matching PacketUpsertUserAll constructor found");
});

A similar approach could be taken for CreatePacketUploadUserPlaylog, which has a similar structure, though it would require a different Func signature in its ConstructorStrategy.

else
{
throw new MissingMethodException("No matching PacketUpsertUserAll constructor found");
Expand Down