예제 #1
0
        private async Task <ContentEntryBase> CheckDirectoryNode(DirectoryNode directory, CancellationToken cancellation)
        {
            if (directory.Parent?.NameLowerCase == "python" && directory.Parent.Parent?.NameLowerCase == "apps" ||
                directory.HasSubFile(directory.Name + ".py"))
            {
                var id = directory.Name;
                if (id == null)
                {
                    // It’s unlikely there will be a car or a track in apps/python directory
                    return(null);
                }

                // App?
                var root = directory.Parent?.Parent?.Parent;
                var gui  = root?.GetSubDirectory("content")?.GetSubDirectory("gui")?.GetSubDirectory("icons");

                // Collecting values…
                var    missing = false;
                var    uiAppFound = false;
                string version = null, name = null;

                // Maybe, it’s done nicely?
                var uiApp = directory.GetSubDirectory("ui")?.GetSubFile("ui_app.json");
                if (uiApp != null)
                {
                    uiAppFound = true;
                    var data = await uiApp.Info.ReadAsync();

                    if (data == null)
                    {
                        missing = true;
                    }
                    else
                    {
                        var parsed = JsonExtension.Parse(data.ToUtf8String());
                        name    = parsed.GetStringValueOnly("name");
                        version = parsed.GetStringValueOnly("version");
                    }
                }

                // Let’s try to guess version
                if (version == null && !uiAppFound)
                {
                    foreach (var c in PythonAppObject.VersionSources.Select(directory.GetSubFile).NonNull())
                    {
                        var r = await c.Info.ReadAsync();

                        if (r == null)
                        {
                            missing = true;
                        }
                        else
                        {
                            version = PythonAppObject.GetVersion(r.ToUtf8String());
                            if (version != null)
                            {
                                break;
                            }
                        }
                    }
                }

                // And icon
                byte[]          icon;
                List <FileNode> icons;

                if (gui != null)
                {
                    icons = gui.Files.Where(x => x.NameLowerCase.EndsWith("_on.png") || x.NameLowerCase.EndsWith("_off.png")).ToList();
                    var mainIcon = icons.GetByIdOrDefault(directory.NameLowerCase + "_off.png") ??
                                   icons.OrderByDescending(x => x.NameLowerCase.Length).FirstOrDefault();

                    icon = await(mainIcon?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                    if (mainIcon != null && icon == null)
                    {
                        missing = true;
                    }

                    cancellation.ThrowIfCancellationRequested();
                }
                else
                {
                    icon  = null;
                    icons = null;
                }

                if (missing)
                {
                    throw new MissingContentException();
                }

                return(new PythonAppContentEntry(directory.Key ?? "", id,
                                                 name ?? id, version, icon, icons?.Select(x => x.Key)));
            }

            var ui = directory.GetSubDirectory("ui");

            if (ui != null)
            {
                // Is it a car?
                var uiCar = ui.GetSubFile("ui_car.json");
                if (uiCar != null)
                {
                    var icon = await(ui.GetSubFile("badge.png")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                    cancellation.ThrowIfCancellationRequested();

                    var data = await uiCar.Info.ReadAsync() ?? throw new MissingContentException();

                    var parsed = JsonExtension.Parse(data.ToUtf8String());
                    var carId  = directory.Name ??
                                 directory.GetSubDirectory("sfx")?.Files.Select(x => x.NameLowerCase)
                                 .FirstOrDefault(x => x.EndsWith(@".bank") && x.Count('.') == 1 && x != @"common.bank")?.ApartFromLast(@".bank");

                    if (carId != null)
                    {
                        return(new CarContentEntry(directory.Key ?? "", carId, parsed.GetStringValueOnly("parent") != null,
                                                   parsed.GetStringValueOnly("name"), parsed.GetStringValueOnly("version"), icon));
                    }
                }

                // A track?
                var foundTrack = await CheckDirectoryNodeForTrack(directory, cancellation);

                if (foundTrack != null)
                {
                    return(foundTrack);
                }

                // Or maybe a showroom?
                var uiShowroom = ui.GetSubFile(@"ui_showroom.json");
                if (uiShowroom != null)
                {
                    var icon = await(directory.GetSubFile(@"preview.jpg")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                    cancellation.ThrowIfCancellationRequested();

                    var data = await uiShowroom.Info.ReadAsync() ?? throw new MissingContentException();

                    var parsed     = JsonExtension.Parse(data.ToUtf8String());
                    var showroomId = directory.Name ??
                                     directory.Files.Where(x => x.NameLowerCase.EndsWith(@".kn5")).OrderByDescending(x => x.Info.Size)
                                     .FirstOrDefault()?.NameLowerCase.ApartFromLast(@".kn5");
                    if (showroomId != null)
                    {
                        return(new ShowroomContentEntry(directory.Key ?? "", showroomId,
                                                        parsed.GetStringValueOnly("name"), parsed.GetStringValueOnly("version"), icon));
                    }
                }
            }
            else
            {
                // Another case for showrooms
                if (directory.Name != null &&
                    directory.HasSubFile(directory.Name + @".kn5") &&
                    directory.HasSubFile(@"colorCurves.ini") && directory.HasSubFile(@"ppeffects.ini"))
                {
                    var icon = directory.HasSubFile(@"preview.jpg")
                            ? await(directory.GetSubFile(@"preview.jpg")?.Info.ReadAsync() ?? throw new MissingContentException())
                            : null;
                    cancellation.ThrowIfCancellationRequested();
                    return(new ShowroomContentEntry(directory.Key ?? "", directory.Name ?? throw new ArgumentException(), iconData: icon));
                }
            }

            var uiTrackSkin = directory.GetSubFile("ui_track_skin.json");

            if (uiTrackSkin != null && TracksManager.Instance != null)
            {
                var icon = await(directory.GetSubFile("preview.png")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                cancellation.ThrowIfCancellationRequested();

                var data = await uiTrackSkin.Info.ReadAsync() ?? throw new MissingContentException();

                var parsed  = JsonExtension.Parse(data.ToUtf8String());
                var skinId  = parsed.GetStringValueOnly("id") ?? directory.Name;
                var trackId = parsed.GetStringValueOnly("track");
                var name    = parsed.GetStringValueOnly("name");

                if (skinId != null && trackId != null)
                {
                    return(new TrackSkinContentEntry(directory.Key ?? "", skinId, trackId, name,
                                                     parsed.GetStringValueOnly("version"), icon));
                }
            }

            if (directory.HasSubFile("settings.ini"))
            {
                var kn5 = directory.Files.Where(x => x.NameLowerCase.EndsWith(@".kn5")).ToList();
                var id  = directory.Name;
                if (id != null)
                {
                    if (kn5.Any(x => x.NameLowerCase.ApartFromLast(@".kn5") == directory.NameLowerCase))
                    {
                        var icon = await(directory.GetSubFile("preview.jpg")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                        cancellation.ThrowIfCancellationRequested();

                        return(new ShowroomContentEntry(directory.Key ?? "", id,
                                                        AcStringValues.NameFromId(id), null, icon));
                    }
                }
            }

            var weatherIni = directory.GetSubFile("weather.ini");

            if (weatherIni != null)
            {
                var icon = await(directory.GetSubFile("preview.jpg")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                cancellation.ThrowIfCancellationRequested();

                var data = await weatherIni.Info.ReadAsync() ?? throw new MissingContentException();

                var parsed = IniFile.Parse(data.ToUtf8String());

                var name = parsed["LAUNCHER"].GetNonEmpty("NAME");
                if (name != null)
                {
                    var id = directory.Name ?? name;
                    return(new WeatherContentEntry(directory.Key ?? "", id, name, icon));
                }
            }

            var uiCarSkin = directory.GetSubFile("ui_skin.json");

            if ((uiCarSkin != null || directory.HasSubFile("preview.jpg") && directory.HasSubFile("livery.png")) &&
                CarsManager.Instance != null /* for crawlers only */)
            {
                var icon = await(directory.GetSubFile("livery.png")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                cancellation.ThrowIfCancellationRequested();

                string carId;
                var    skinFor = await(directory.GetSubFile("cm_skin_for.json")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                if (skinFor != null)
                {
                    carId = JsonExtension.Parse(skinFor.ToUtf8String())[@"id"]?.ToString();
                }
                else
                {
                    carId = _installationParams.CarId;

                    if (carId == null && directory.Parent?.NameLowerCase == "skins")
                    {
                        carId = directory.Parent.Parent?.Name;
                    }

                    if (carId == null)
                    {
                        carId = AcContext.Instance.CurrentCar?.Id;
                    }
                }

                if (carId == null)
                {
                    throw new Exception("Can’t figure out car’s ID");
                }

                var skinId = directory.Name;
                if (skinId != null)
                {
                    string name;
                    if (uiCarSkin != null)
                    {
                        var data = await uiCarSkin.Info.ReadAsync() ?? throw new MissingContentException();

                        var parsed = JsonExtension.Parse(data.ToUtf8String());
                        name = parsed.GetStringValueOnly("name");
                    }
                    else
                    {
                        name = AcStringValues.NameFromId(skinId);
                    }

                    return(new CarSkinContentEntry(directory.Key ?? "", skinId, carId, name, icon));
                }
            }

            // New textures
            if (directory.NameLowerCase == "damage" && directory.HasSubFile("flatspot_fl.png"))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? @"damage"));
            }

            if (directory.Parent?.NameLowerCase == "crew_brand" && directory.HasSubFile("Brands_Crew.dds") && directory.HasSubFile("Brands_Crew.jpg") &&
                directory.HasSubFile("Brands_Crew_NM.dds"))
            {
                return(new CrewBrandEntry(directory.Key ?? "", directory.Name ?? @"unknown"));
            }

            if (directory.Parent?.NameLowerCase == "crew_helmet" && directory.HasSubFile("Crew_HELMET_Color.dds"))
            {
                return(new CrewHelmetEntry(directory.Key ?? "", directory.Name ?? @"unknown"));
            }

            // TODO: More driver and crew textures

            if (directory.NameLowerCase == "clouds" && directory.Files.Any(
                    x => (x.NameLowerCase.StartsWith(@"cloud") || directory.Parent?.NameLowerCase == "texture") && x.NameLowerCase.EndsWith(@".dds")))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? @"clouds"));
            }

            if (directory.NameLowerCase == "clouds_shared" && directory.Files.Any(
                    x => (x.NameLowerCase.StartsWith(@"cloud") || directory.Parent?.NameLowerCase == "texture") && x.NameLowerCase.EndsWith(@".dds")))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? @"clouds_shared"));
            }

            if (directory.NameLowerCase == "people" && (directory.HasSubFile("crowd_sit.dds") || directory.HasSubFile("people_sit.dds")))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? @"people"));
            }

            if (directory.HasSubFile(PatchHelper.MainFileName) && directory.HasSubDirectory("extension"))
            {
                var    dwrite    = directory.GetSubFile(PatchHelper.MainFileName);
                var    extension = directory.GetSubDirectory("extension");
                var    manifest  = directory.GetSubDirectory("extension")?.GetSubDirectory("config")?.GetSubFile("data_manifest.ini");
                string version;
                if (manifest != null)
                {
                    var data = await manifest.Info.ReadAsync() ?? throw new MissingContentException();

                    version = IniFile.Parse(data.ToUtf8String())["VERSION"].GetNonEmpty("SHADERS_PATCH");
                }
                else
                {
                    var description = directory.GetSubFile("description.jsgme");
                    if (description != null)
                    {
                        var data = await description.Info.ReadAsync() ?? throw new MissingContentException();

                        version = Regex.Match(data.ToUtf8String(), @"(?<=v)\d.*").Value?.TrimEnd('.').Or(null);
                    }
                    else
                    {
                        var parent = directory;
                        while (parent.Parent?.Name != null)
                        {
                            parent = parent.Parent;
                        }
                        version = parent.Name != null?Regex.Match(parent.Name, @"(?<=v)\d.*").Value?.TrimEnd('.').Or(null) : null;
                    }
                }

                return(new ShadersPatchEntry(directory.Key ?? "", new[] { dwrite.Key, extension.Key }, version));
            }

            if (directory.NameLowerCase == "__gbwsuite")
            {
                return(new CustomFolderEntry(directory.Key ?? "", new[] { directory.Key }, "GBW scripts", "__gbwSuite"));
            }

            if (directory.HasSubFile("weather.lua") && directory.Parent.NameLowerCase == "weather")
            {
                return(new CustomFolderEntry(directory.Key ?? "", new[] { directory.Key }, $"Weather FX script “{AcStringValues.NameFromId(directory.Name)}”",
                                             Path.Combine(AcRootDirectory.Instance.RequireValue, "extension", "weather", directory.Name), 1e5));
            }

            if (directory.HasSubFile("controller.lua") && directory.Parent.NameLowerCase == "weather-controllers")
            {
                return(new CustomFolderEntry(directory.Key ?? "", new[] { directory.Key },
                                             $"Weather FX controller “{AcStringValues.NameFromId(directory.Name)}”",
                                             Path.Combine(AcRootDirectory.Instance.RequireValue, "extension", "weather-controllers", directory.Name), 1e5));
            }

            // Mod
            if (directory.Parent?.NameLowerCase == "mods" &&
                (directory.HasAnySubDirectory("content", "apps", "system", "launcher", "extension") || directory.HasSubFile(PatchHelper.MainFileName)))
            {
                var name = directory.Name;
                if (name != null && directory.GetSubDirectory("content")?.GetSubDirectory("tracks")?.Directories.Any(
                        x => x.GetSubDirectory("skins")?.GetSubDirectory("default")?.GetSubFile("ui_track_skin.json") != null) != true)
                {
                    var description = directory.Files.FirstOrDefault(x => x.NameLowerCase.EndsWith(@".jsgme"));
                    if (description == null && directory.HasSubDirectory("documentation"))
                    {
                        description = directory.GetSubDirectory("documentation")?.Files.FirstOrDefault(x => x.NameLowerCase.EndsWith(@".jsgme"));
                    }

                    if (description != null)
                    {
                        var data = await description.Info.ReadAsync() ?? throw new MissingContentException();

                        return(new GenericModConfigEntry(directory.Key ?? "", name, data.ToUtf8String()));
                    }

                    return(new GenericModConfigEntry(directory.Key ?? "", name));
                }
            }

            return(null);
        }
예제 #2
0
        private async Task <ContentEntryBase> CheckDirectoryNode(DirectoryNode directory, CancellationToken cancellation)
        {
            if (directory.Parent?.NameLowerCase == "python" && directory.Parent.Parent?.NameLowerCase == "apps" ||
                directory.HasSubFile(directory.Name + ".py"))
            {
                var id = directory.Name;
                if (id == null)
                {
                    // It’s unlikely there will be a car or a track in apps/python directory
                    return(null);
                }

                // App?
                var root = directory.Parent?.Parent?.Parent;
                var gui  = root?.GetSubDirectory("content")?.GetSubDirectory("gui")?.GetSubDirectory("icons");

                // Let’s try to guess version
                var    missing = false;
                string version = null;
                foreach (var c in PythonAppObject.VersionSources.Select(directory.GetSubFile).NonNull())
                {
                    var r = await c.Info.ReadAsync();

                    if (r == null)
                    {
                        missing = true;
                    }
                    else
                    {
                        version = PythonAppObject.GetVersion(r.ToUtf8String());
                        if (version != null)
                        {
                            break;
                        }
                    }
                }

                if (missing)
                {
                    throw new MissingContentException();
                }

                // And icon
                byte[]          icon;
                List <FileNode> icons;

                if (gui != null)
                {
                    icons = gui.Files.Where(x => x.NameLowerCase.EndsWith("_on.png") || x.NameLowerCase.EndsWith("_off.png")).ToList();
                    var mainIcon = icons.GetByIdOrDefault(directory.NameLowerCase + "_on.png") ??
                                   icons.OrderByDescending(x => x.NameLowerCase.Length).FirstOrDefault();

                    icon = await(mainIcon?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                    cancellation.ThrowIfCancellationRequested();
                }
                else
                {
                    icon  = null;
                    icons = null;
                }

                return(new PythonAppContentEntry(directory.Key ?? "", id,
                                                 id, version, icon, icons?.Select(x => x.Key)));
            }

            var ui = directory.GetSubDirectory("ui");

            if (ui != null)
            {
                // Is it a car?
                var uiCar = ui.GetSubFile("ui_car.json");
                if (uiCar != null)
                {
                    var icon = await(ui.GetSubFile("badge.png")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                    cancellation.ThrowIfCancellationRequested();

                    var data = await uiCar.Info.ReadAsync() ?? throw new MissingContentException();

                    var parsed = JsonExtension.Parse(data.ToUtf8String());
                    var carId  = directory.Name ??
                                 directory.GetSubDirectory("sfx")?.Files.Select(x => x.NameLowerCase)
                                 .FirstOrDefault(x => x.EndsWith(".bank") && x.Count('.') == 1 && x != "common.bank")?.ApartFromLast(".bank");

                    if (carId != null)
                    {
                        return(new CarContentEntry(directory.Key ?? "", carId,
                                                   parsed.GetStringValueOnly("name"), parsed.GetStringValueOnly("version"), icon));
                    }
                }

                // A track?
                var foundTrack = await CheckDirectoryNodeForTrack(directory, cancellation);

                if (foundTrack != null)
                {
                    return(foundTrack);
                }

                // Or maybe a showroom?
                var uiShowroom = ui.GetSubFile("ui_showroom.json");
                if (uiShowroom != null)
                {
                    var icon = await(directory.GetSubFile("preview.jpg")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                    cancellation.ThrowIfCancellationRequested();

                    var data = await uiShowroom.Info.ReadAsync() ?? throw new MissingContentException();

                    var parsed     = JsonExtension.Parse(data.ToUtf8String());
                    var showroomId = directory.Name ??
                                     directory.Files.Where(x => x.NameLowerCase.EndsWith(".kn5")).OrderByDescending(x => x.Info.Size)
                                     .FirstOrDefault()?.NameLowerCase.ApartFromLast(".kn5");
                    if (showroomId != null)
                    {
                        return(new ShowroomContentEntry(directory.Key ?? "", showroomId,
                                                        parsed.GetStringValueOnly("name"), parsed.GetStringValueOnly("version"), icon));
                    }
                }
            }

            var uiCarSkin = directory.GetSubFile("ui_skin.json");

            if ((uiCarSkin != null || directory.HasSubFile("preview.jpg") || directory.HasSubFile("livery.png")) &&
                CarsManager.Instance != null /* for crawlers only */)
            {
                var icon = await(directory.GetSubFile("livery.png")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                cancellation.ThrowIfCancellationRequested();

                string carId;
                var    skinFor = await(directory.GetSubFile("cm_skin_for.json")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                if (skinFor != null)
                {
                    carId = JsonExtension.Parse(skinFor.ToUtf8String())["id"]?.ToString();
                }
                else
                {
                    carId = _installationParams.CarId;

                    if (carId == null && directory.Parent?.NameLowerCase == "skins")
                    {
                        carId = directory.Parent.Parent?.Name;
                    }

                    if (carId == null)
                    {
                        carId = AcContext.Instance.CurrentCar?.Id;
                    }
                }

                if (carId == null)
                {
                    throw new Exception("Can’t figure out car’s ID");
                }

                var skinId = directory.Name;
                if (skinId != null)
                {
                    string name;
                    if (uiCarSkin != null)
                    {
                        var data = await uiCarSkin.Info.ReadAsync() ?? throw new MissingContentException();

                        var parsed = JsonExtension.Parse(data.ToUtf8String());
                        name = parsed.GetStringValueOnly("name");
                    }
                    else
                    {
                        name = AcStringValues.NameFromId(skinId);
                    }

                    return(new CarSkinContentEntry(directory.Key ?? "", skinId, carId, name, icon));
                }
            }

            var uiTrackSkin = directory.GetSubFile("ui_track_skin.json");

            if (uiTrackSkin != null && TracksManager.Instance != null)
            {
                var icon = await(directory.GetSubFile("preview.png")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                cancellation.ThrowIfCancellationRequested();

                var data = await uiTrackSkin.Info.ReadAsync() ?? throw new MissingContentException();

                var parsed  = JsonExtension.Parse(data.ToUtf8String());
                var skinId  = parsed.GetStringValueOnly("id") ?? directory.Name;
                var trackId = parsed.GetStringValueOnly("track");
                var name    = parsed.GetStringValueOnly("name");

                if (skinId != null && trackId != null)
                {
                    return(new TrackSkinContentEntry(directory.Key ?? "", skinId, trackId, name,
                                                     parsed.GetStringValueOnly("version"), icon));
                }
            }

            if (directory.HasSubFile("settings.ini"))
            {
                var kn5 = directory.Files.Where(x => x.NameLowerCase.EndsWith(".kn5")).ToList();
                var id  = directory.Name;
                if (id != null)
                {
                    if (kn5.Any(x => x.NameLowerCase.ApartFromLast(".kn5") == directory.NameLowerCase))
                    {
                        var icon = await(directory.GetSubFile("preview.jpg")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                        cancellation.ThrowIfCancellationRequested();

                        return(new ShowroomContentEntry(directory.Key ?? "", id,
                                                        AcStringValues.NameFromId(id), null, icon));
                    }
                }
            }

            var weatherIni = directory.GetSubFile("weather.ini");

            if (weatherIni != null)
            {
                var icon = await(directory.GetSubFile("preview.jpg")?.Info.ReadAsync() ?? Task.FromResult((byte[])null));
                cancellation.ThrowIfCancellationRequested();

                var data = await weatherIni.Info.ReadAsync() ?? throw new MissingContentException();

                var parsed = IniFile.Parse(data.ToUtf8String());

                var name = parsed["LAUNCHER"].GetNonEmpty("NAME");
                if (name != null)
                {
                    var id = directory.Name ?? name;
                    return(new WeatherContentEntry(directory.Key ?? "", id, name, icon));
                }
            }

            // New textures
            if (directory.NameLowerCase == "damage" && directory.HasSubFile("flatspot_fl.png"))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? "damage"));
            }

            if (directory.NameLowerCase == "clouds" && directory.Files.Any(x => x.NameLowerCase.StartsWith("cloud") && x.NameLowerCase.EndsWith(".dds")))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? "clouds"));
            }

            if (directory.NameLowerCase == "people" && (directory.HasSubFile("crowd_sit.dds") || directory.HasSubFile("people_sit.dds")))
            {
                return(new TexturesConfigEntry(directory.Key ?? "", directory.Name ?? "people"));
            }

            // Mod
            if (directory.Parent?.NameLowerCase == "mods" && directory.HasAnySubDirectory("content", "apps", "system", "launcher"))
            {
                var name = directory.Name;
                if (name != null)
                {
                    var description = directory.Files.FirstOrDefault(x => x.NameLowerCase.EndsWith(".jsgme"));
                    if (description == null && directory.HasSubDirectory("documentation"))
                    {
                        description = directory.GetSubDirectory("documentation")?.Files.FirstOrDefault(x => x.NameLowerCase.EndsWith(".jsgme"));
                    }

                    if (description != null)
                    {
                        var data = await description.Info.ReadAsync() ?? throw new MissingContentException();

                        return(new GenericModConfigEntry(directory.Key ?? "", name, data.ToUtf8String()));
                    }

                    return(new GenericModConfigEntry(directory.Key ?? "", name));
                }
            }

            return(null);
        }