Пример #1
0
        public EnvironmentVariables(IMinecraftInstance instance, IDictionary <string, string> properties)
        {
            // Register defaults
            if (!properties.ContainsKey(ModsFolder))
            {
                properties.Add(ModsFolder, Path.Combine(instance.Location.FullName, "mods"));
            }

            if (!properties.ContainsKey(ConfigFolder))
            {
                properties.Add(ConfigFolder, Path.Combine(instance.Location.FullName, "config"));
            }

            if (!properties.ContainsKey(InstnaceFolder))
            {
                properties.Add(InstnaceFolder, instance.Location.FullName);
            }

            if (!properties.ContainsKey(RootFolder))
            {
                properties.Add(RootFolder, Path.Combine(instance.Location.FullName, "minecraft"));
            }

            // Order by longest value string (this is important when converting from paths)
            Properties = new ReadOnlyDictionary <string, string>(
                properties.OrderByDescending(prop => prop.Value.Length).ToDictionary(k => k.Key, v => v.Value)
                );

            logger.Debug($"Environment variables of minecraft instance {instance} were set to: {Environment.NewLine + string.Join(Environment.NewLine, Properties.Select(pair => $"{pair.Key} <-> {pair.Value}"))}");
        }
Пример #2
0
        public void Save(IMinecraftInstance instance, object config)
        {
            PackslyInstanceFile cfg = instance.PackslyConfig;

            cfg.Adapters.SetConfigFor(this, config);
            cfg.Save();
        }
Пример #3
0
 public void Publish(IMinecraftInstance instance, IEnumerable <string> eventNames)
 {
     foreach (string eventName in eventNames)
     {
         Publish(instance, eventName);
     }
 }
Пример #4
0
        public static void Publish(LifecycleOptions options)
        {
            Logo.Print();
            ApplySettings(options);

            IMinecraftInstance instance = Packsly.Launcher.GetInstance(options.InstanceId);

            instance.Load();
            logger.Debug($"Dispatching lifecycle events specified by command line arguments: {string.Join(", ", options.Events)}");
            Packsly.Lifecycle.EventBus.Publish(instance, options.Events);
            instance.Save();
        }
Пример #5
0
        public ModLoaderManager(IMinecraftInstance mcInstnace)
        {
            mcInstance = mcInstnace;
            modLoaders = new List <ModLoaderInfo>();
            ModLoaders = modLoaders.AsReadOnly();

            compatibleSchemata = InstalationSchemas.Where(s => s.IsCompatible(mcInstnace)).ToArray();
            foreach (IModLoaderHandler handler in compatibleSchemata)
            {
                handler.DetectModLoaders(mcInstnace, modLoaders);
            }

            Logger.Debug($"Detected mod loaders for instance {mcInstnace.GetType()} with name {mcInstance.Name}: {JsonConvert.SerializeObject(ModLoaders, Formatting.Indented)}");
        }
Пример #6
0
        private static void UpdateMods(IMinecraftInstance instance, ModpackDefinition modpack)
        {
            // Remove local mods that are no longer in modpack
            foreach (FileInfo modFile in instance.Files.GetGroup(FileManager.GroupType.Mod))
            {
                if (modpack.Mods.Any(mod => mod.GetFilePath(instance.EnvironmentVariables) == modFile.FullName))
                {
                    continue;
                }

                logger.Info($"Removing mod {modFile.Name}...");
                instance.Files.Remove(modFile, FileManager.GroupType.Mod);
            }

            // Remove local resource files (configuration) that are no longer in modpack
            RemoteResource[] modpackResources = modpack.Mods.SelectMany(m => m.Resources).ToArray();
            foreach (FileInfo resourceFile in instance.Files.GetGroup(FileManager.GroupType.Resource))
            {
                if (modpackResources.Any(res => res.GetFilePath(instance.EnvironmentVariables) == resourceFile.FullName))
                {
                    continue;
                }

                logger.Info($"Removing resource {resourceFile.Name}...");
                instance.Files.Remove(resourceFile, FileManager.GroupType.Resource);
            }

            // Download mods that are defined in modpack but aren't available locally
            // NOTE: CanDownload property handles environment specific restrictions
            foreach (ModSource modpackMod in modpack.Mods.Where(mod => mod.CanDownload))
            {
                // Download new mods based on file name
                if (!instance.Files.GroupContains(FileManager.GroupType.Mod, modpackMod))
                {
                    logger.Info($"Downloading mod {modpackMod.FileName}...");
                    instance.Files.Download(modpackMod, FileManager.GroupType.Mod);
                }

                // Re-downland all resource files, no matter if they changed or not
                foreach (RemoteResource modpackResource in modpackMod.Resources.Where(resource => resource.CanDownload))
                {
                    logger.Info($"Downloading resource {modpackResource.FileName}...");
                    instance.Files.Download(modpackResource, FileManager.GroupType.Resource);
                }
            }
        }
Пример #7
0
        public FileManager(IMinecraftInstance instance)
        {
            this.instance = instance;

            // Remove missing or non-existent files
            foreach (GroupType group in Enum.GetValues(typeof(GroupType)))
            {
                FileInfo[] missingFiles = GetNotExistingFiles(group);

                if (missingFiles.Length == 0)
                {
                    continue;
                }

                foreach (FileInfo file in missingFiles)
                {
                    logger.Debug("Removing non-existing tracked file.");
                    Remove(file, group);
                }
            }
        }
Пример #8
0
        private static IMinecraftInstance CreateMinecraftInstnace(string instanceId, ModpackDefinition modpackDefinition)
        {
            IMinecraftInstance instance = Packsly.Launcher.CreateInstance(instanceId, modpackDefinition);

            // Set base minecraft instance properties
            instance.Name             = modpackDefinition.Name;
            instance.MinecraftVersion = modpackDefinition.MinecraftVersion;
            instance.Icon.Source      = modpackDefinition.Icon;
            logger.Debug($"Setting minecraft instance properties id={instance.Id} name={instance.Name} mc={instance.MinecraftVersion} icon={instance.Icon.Source}");

            // Load defaults
            instance.Load();

            // Save adapters defined in modpack along with configuration to packsly instance config file
            foreach (KeyValuePair <string, object> adapterDefinition in modpackDefinition.Adapters)
            {
                string adapterName     = adapterDefinition.Key;
                object adapterSettings = adapterDefinition.Value;

                logger.Debug($"Setting adapter config for {adapterName} for minecraft instance {instance.Id}");
                instance.PackslyConfig.Adapters.SetConfigFor(adapterName, adapterSettings);
            }

            // Configure instance using compatible environment settings
            foreach (KeyValuePair <string, object> environmentEntry in modpackDefinition.Environments)
            {
                string name = environmentEntry.Key;
                if (name != Packsly.Launcher.Name)
                {
                    continue;
                }

                string settings = environmentEntry.Value.ToString();
                logger.Debug($"Configuring minecraft instance {instance.Id} from modpack environment settings: {settings}");
                instance.Configure(settings);
                break;
            }

            return(instance);
        }
Пример #9
0
        private static void UpdateModloaders(IMinecraftInstance instance, ModpackDefinition modpack)
        {
            // Install or update mod-loaders
            foreach (KeyValuePair <string, string> modloaderEntry in modpack.ModLoaders)
            {
                string name    = modloaderEntry.Key;
                string version = modloaderEntry.Value;

                if (!instance.ModLoaderManager.ModLoaders.Any(ml => ml.Name == name && ml.Version != version))
                {
                    continue;
                }

                logger.Info($"Installing modloader '{name}' version '{version}'...");
                instance.ModLoaderManager.Install(name, version);
            }

            // Remove unused mod-loaders
            foreach (ModLoaderInfo modLoader in instance.ModLoaderManager.ModLoaders.Where(ml => !modpack.ModLoaders.ContainsKey(ml.Name)))
            {
                logger.Info($"Uninstalling modloader '{modLoader.Name}' version '{modLoader.Version}'");
                instance.ModLoaderManager.Uninstall(modLoader.Name);
            }
        }
Пример #10
0
        public static bool TryGetAdapterConfig(IAdapter adapter, IMinecraftInstance instance, out JObject config)
        {
            // Set default return value for the config
            config = null;

            // Try to get adapter config from the instance
            object adapterConfig = instance.PackslyConfig.Adapters.GetConfigFor(adapter);

            // This adapter has no configuration
            if (adapterConfig == null)
            {
                return(true);
            }

            // Try to parse adapter config
            try {
                config = JObject.FromObject(adapterConfig);
                return(true);
            } catch (Exception ex) {
                logger.Error(ex, $"Failed to parse configuration for adapter {adapter.Id}");
            }

            return(false);
        }
Пример #11
0
 public abstract bool IsCompatible(IMinecraftInstance instance);
Пример #12
0
 private FileInfo GetForgeJarFile(IMinecraftInstance instance)
 {
     return(instance.Location
            .EnumerateFiles()
            .FirstOrDefault(file => forgeJarFilePattern.IsMatch(file.Name)));
 }
Пример #13
0
 public void Uninstall(IMinecraftInstance instance, string modLoader)
 => Uninstall((T)instance, modLoader);
Пример #14
0
 public bool IsCompatible(IMinecraftInstance instance)
 => instance.GetType() == typeof(T);
Пример #15
0
        public override void Execute(RevisionUpdateSchemaConfig config, string lifecycleEvent, IMinecraftInstance instance)
        {
            if (!Uri.IsWellFormedUriString(config.UpdateUrl, UriKind.Absolute))
            {
                throw new FormatException($"Revision based updater '{GetType().FullName}' could not resolve update url '{config.UpdateUrl}' provided by configuration.");
            }

            logger.Info("Checking for modpack updates...");

            using (WebClient client = new WebClient()) {
                ModpackDefinition remoteModpack = JsonConvert.DeserializeObject <ModpackDefinition>(client.DownloadString(config.UpdateUrl));

                // Check if remote modpack has configuration for this adapter type
                // Without this we can't check for revision number changes and perform the update
                if (!remoteModpack.Adapters.ContainsKey(Id))
                {
                    throw new InvalidOperationException($"Revision based updater '{GetType().FullName}' failed to obtain revision number from update source because adapter configuration is missing.");
                }

                RevisionUpdateSchemaConfig remoteConfig = JObject.FromObject(remoteModpack.Adapters[Id]).ToObject <RevisionUpdateSchemaConfig>();

                // If there is an update available
                if (config.Revision != remoteConfig.Revision)
                {
                    Packsly.Lifecycle.EventBus.Publish(instance, Lifecycle.UpdateStarted);
                    logger.Info($"Updating modpack from revision {config.Revision} to {remoteConfig.Revision}!");

                    // Update instance config
                    // TODO: Add config option to the update adapter for this

                    /*
                     * foreach (KeyValuePair<string, object> environmentEntry in remoteModpack.Environments) {
                     *  if (environmentEntry.Key != Packsly.Launcher.Name) {
                     *      continue;
                     *  }
                     *
                     *  string settings = environmentEntry.Value.ToString();
                     *  Logger.Debug($"Updating configuration of minecraft instance {instance.Id} from modpack environment settings: {settings}");
                     *  instance.Configure(settings);
                     *  break;
                     * }
                     */

                    // Update modloaders and mods
                    UpdateModloaders(instance, remoteModpack);
                    UpdateMods(instance, remoteModpack);

                    // Update adapter settings saved in instnace.packsly file, because revision number has changed
                    Save(instance, remoteConfig);
                    Packsly.Lifecycle.EventBus.Publish(instance, Lifecycle.UpdateFinished);
                }
            }

            logger.Info("Modpack is up to date.");
        }
Пример #16
0
 public override bool IsCompatible(IMinecraftInstance instance)
 => true;
Пример #17
0
 public void Install(IMinecraftInstance instance, string modLoader, string version)
 => Install((T)instance, modLoader, version);
Пример #18
0
 public void Execute(JObject config, string lifecycleEvent, IMinecraftInstance instance)
 {
     Execute((TConfig)config?.ToObject(typeof(TConfig)), lifecycleEvent, instance);
 }
Пример #19
0
 protected internal ChangedEventArgs(IMinecraftInstance instance, string eventName)
 {
     Instance  = instance;
     EventName = eventName;
 }
Пример #20
0
 public void Publish(IMinecraftInstance instance, string eventName)
 {
     logger.Debug($"Publishing lifecycle event '{eventName}' {(instance == null ? "..." : $" for minecraft instance '{instance.Id}'...")}");
Пример #21
0
 public abstract void Execute(TConfig config, string lifecycleEvent, IMinecraftInstance instance);
Пример #22
0
        public static IMinecraftInstance CreateFromModpack(string modpackJson)
        {
            ModpackDefinition modpackDefinition = JsonConvert.DeserializeObject <ModpackDefinition>(modpackJson);

            char[] invalidChars = Path.GetInvalidFileNameChars();
            // TODO: Allow name overrides
            string instanceId = new string(modpackDefinition.Name.ToLowerInvariant().Where(m => !invalidChars.Contains(m)).ToArray());

            instanceId = instanceId.Replace(" ", "-");
            logger.Info($"Modpack name is '{modpackDefinition.Name}' using instance id '{instanceId}'.");

            IMinecraftInstance instance = CreateMinecraftInstnace(instanceId, modpackDefinition);

            Packsly.Lifecycle.EventBus.Publish(instance, Lifecycle.PreInstallation);

            try {
                // Install modloaders
                logger.Info("Setting up modloaders...");
                foreach (KeyValuePair <string, string> modloaderEntry in modpackDefinition.ModLoaders)
                {
                    string name    = modloaderEntry.Key;
                    string version = modloaderEntry.Value;

                    logger.Info($"Installing modloader '{name}' with version {version}.");
                    instance.ModLoaderManager.Install(name, version);
                }

                // Download mods
                logger.Info("Downloading required files...");
                foreach (ModSource mod in modpackDefinition.Mods)
                {
                    if (mod.CanDownload)
                    {
                        logger.Info($"Downloading mod {mod.FileName}...");
                        instance.Files.Download(mod, FileManager.GroupType.Mod);
                    }
                    else
                    {
                        logger.Info($"Skipping downloading mod {mod.FileName} since it is {(mod.EnvironmentOnly.IsBlacklist ? "blacklisted" : "whitelisted")} at '{string.Join(", ", mod.EnvironmentOnly.Entries)}'...");
                    }

                    // Download mod resources
                    foreach (RemoteResource resource in mod.Resources)
                    {
                        if (resource.CanDownload)
                        {
                            logger.Info($" - Downloading resource {resource.FileName}...");
                            instance.Files.Download(resource, FileManager.GroupType.Resource);
                        }
                        else
                        {
                            logger.Info($" - Skipping downloading resource {resource.FileName} since it is {(resource.EnvironmentOnly.IsBlacklist ? "blacklisted" : "whitelisted")} at '{string.Join(", ", resource.EnvironmentOnly.Entries)}'...");
                        }
                    }
                }

                instance.Save();
                logger.Info("Finishing installation.");
                Packsly.Lifecycle.EventBus.Publish(instance, Lifecycle.PostInstallation);
            } catch (Exception) {
                // Delete the instance if creation fails
                logger.Warn("Modpack installation failed, removing instance files.");
                instance.Delete();
                throw;
            }

            return(instance);
        }
Пример #23
0
 public override bool IsCompatible(IMinecraftInstance instance)
 {
     return(instance.GetType() == typeof(TInstance));
 }
Пример #24
0
 public void DetectModLoaders(IMinecraftInstance instance, List <ModLoaderInfo> modLoaders)
 => DetectModLoaders((T)instance, modLoaders);