private ResourceHandle *GetResourceHandler(bool isSync, ResourceManager *resourceManager, ResourceCategory *categoryId,
                                               ResourceType *resourceType, int *resourceHash, byte *path, void *unk, bool isUnk)
    {
        if (!Utf8GamePath.FromPointer(path, out var gamePath))
        {
            PluginLog.Error("Could not create GamePath from resource path.");
            return(CallOriginalHandler(isSync, resourceManager, categoryId, resourceType, resourceHash, path, unk, isUnk));
        }

        CompareHash(gamePath.Path.Crc32, *resourceHash, gamePath);

        ResourceRequested?.Invoke(gamePath, isSync);

        // If no replacements are being made, we still want to be able to trigger the event.
        var(resolvedPath, data) = ResolvePath(gamePath, *categoryId, *resourceType, *resourceHash);
        PathResolved?.Invoke(gamePath, resolvedPath, data);
        if (resolvedPath == null)
        {
            var retUnmodified = CallOriginalHandler(isSync, resourceManager, categoryId, resourceType, resourceHash, path, unk, isUnk);
            ResourceLoaded?.Invoke((Structs.ResourceHandle *)retUnmodified, gamePath, null, data);
            return(retUnmodified);
        }

        // Replace the hash and path with the correct one for the replacement.
        *resourceHash = resolvedPath.Value.InternalName.Crc32;
        path = resolvedPath.Value.InternalName.Path;
        var retModified = CallOriginalHandler(isSync, resourceManager, categoryId, resourceType, resourceHash, path, unk, isUnk);

        ResourceLoaded?.Invoke((Structs.ResourceHandle *)retModified, gamePath, resolvedPath.Value, data);
        return(retModified);
    }
 private ResourceHandle *GetResourceAsyncDetour(ResourceManager *resourceManager, ResourceCategory *categoryId, ResourceType *resourceType,
                                                int *resourceHash, byte *path, void *unk, bool isUnk)
 => GetResourceHandler(false, resourceManager, categoryId, resourceType, resourceHash, path, unk, isUnk);
 private ResourceHandle *CallOriginalHandler(bool isSync, ResourceManager *resourceManager, ResourceCategory *categoryId,
                                             ResourceType *resourceType, int *resourceHash, byte *path, void *unk, bool isUnk)
 => isSync
         ? GetResourceSyncHook.Original(resourceManager, categoryId, resourceType, resourceHash, path, unk)
         : GetResourceAsyncHook.Original(resourceManager, categoryId, resourceType, resourceHash, path, unk, isUnk);
 private ResourceHandle *GetResourceSyncDetour(ResourceManager *resourceManager, ResourceCategory *categoryId, ResourceType *resourceType,
                                               int *resourceHash, byte *path, void *unk)
 => GetResourceHandler(true, resourceManager, categoryId, resourceType, resourceHash, path, unk, false);