예제 #1
0
        // This can process passed in dependencies, either as the workshop id (ulong), or a path.
        // If a path is passed in, then an attempt will be made to grab the workshop id from the local mod.
        // Mod must be published for that to work.
        void ProcessDependencies(IEnumerable <string> deps, IEnumerable <string> add, IEnumerable <string> remove)
        {
            var existingDeps = m_workshopItems.GetValueOrDefault(m_modId.FirstOrDefault())?.Dependencies.ToList() ?? new List <ulong>();

            // Check if the deps contains exactly one element, and that element is a 0 or "none",
            // if so, set the result to a list of a single ulong value of 0
            // Otherwise, just fill it with the contents transformed to ids.
            var explicitDeps = (deps?.Count() == 1 && (deps.First() == "0" || deps.First().Equals("none", StringComparison.InvariantCultureIgnoreCase)))
                                    ? new List <ulong>()
            {
                0
            } : new List <ulong>(deps?.Select(id => ParseOrGetWorkshopID(id)) ?? new List <ulong>());
            var depsToAdd    = new List <ulong>(add.Select(id => ParseOrGetWorkshopID(id)));
            var depsToRemove = new List <ulong>(remove.Select(id => ParseOrGetWorkshopID(id)));

            // Steam actually requests the list of deps to add and remove explicitly, so we have to figure it out
            if (explicitDeps?.Count > 0)
            {
                if (explicitDeps.Count == 1 && explicitDeps[0] == 0)
                {
                    // Remove ALL dependencies
                    depsToRemove.AddRange(existingDeps);
                    explicitDeps.Clear();
                }
                else if (existingDeps?.Count > 0)
                {
                    // Any dependencies that existed, but weren't specified, will be removed
                    depsToRemove.AddRange(existingDeps.Except(explicitDeps));
                    depsToAdd.AddRange(explicitDeps.Except(existingDeps));
                }
            }

            // Remove from add list any that already exist
            depsToAdd.RemoveAll(d => existingDeps.Contains(d));
            // Remove from remove list any dependencies that don't exist, or aren't configured to set
            depsToRemove.RemoveAll(d => !existingDeps.Contains(d) && !(explicitDeps?.Contains(d) == true));

            // Filter out items that aren't actually mods, these can crash the game if set
            // Don't check depsToRemove though, so users can remove invalid ones that already exist
            WorkshopHelper.GetItemsBlocking(explicitDeps).ForEach(i => { if (!CheckDependency(i))
                                                                         {
                                                                             explicitDeps.Remove(i.Id);
                                                                         }
                                                                  });
            WorkshopHelper.GetItemsBlocking(depsToAdd).ForEach(i => { if (!CheckDependency(i))
                                                                      {
                                                                          depsToAdd.Remove(i.Id);
                                                                      }
                                                               });

            // Add all explicit deps to the add list that don't already exist
            depsToAdd.AddRange(explicitDeps.Except(existingDeps));

            m_deps         = existingDeps.Union(explicitDeps ?? new List <ulong>()).Union(depsToAdd).Except(depsToRemove).Where(i => i != 0).Distinct().ToArray();
            m_depsToAdd    = depsToAdd.Distinct().ToArray();
            m_depsToRemove = depsToRemove.Distinct().ToArray();
        }
예제 #2
0
        static System.Threading.Tasks.Task <bool> DownloadMods(Options options)
        {
            // Get PublishItemBlocking internal method via reflection
            MySandboxGame.Log.WriteLineAndConsole(string.Empty);

            var Task = System.Threading.Tasks.Task <bool> .Factory.StartNew(() =>
            {
                bool success = true;

                MySandboxGame.Log.WriteLineAndConsole("Beginning batch workshop download...");
                MySandboxGame.Log.WriteLineAndConsole(string.Empty);

                if (options.Collections?.Count() > 0)
                {
                    var items = new List <MyWorkshopItem>();

                    // get collection information
                    options.Collections.ForEach(s => items.AddRange(WorkshopHelper.GetCollectionDetails(ulong.Parse(s))));

                    options.ModPaths   = CombineCollectionWithList(WorkshopType.Mod, items, options.ModPaths);
                    options.Blueprints = CombineCollectionWithList(WorkshopType.Blueprint, items, options.Blueprints);
#if SE
                    options.IngameScripts = CombineCollectionWithList(WorkshopType.IngameScript, items, options.IngameScripts);
#endif
                    options.Worlds    = CombineCollectionWithList(WorkshopType.World, items, options.Worlds);
                    options.Scenarios = CombineCollectionWithList(WorkshopType.Scenario, items, options.Scenarios);
                }

                if (!ProcessItemsDownload(WorkshopType.Mod, options.ModPaths, options))
                {
                    success = false;
                }
                if (!ProcessItemsDownload(WorkshopType.Blueprint, options.Blueprints, options))
                {
                    success = false;
                }
#if SE
                if (!ProcessItemsDownload(WorkshopType.IngameScript, options.IngameScripts, options))
                {
                    success = false;
                }
#endif
                if (!ProcessItemsDownload(WorkshopType.World, options.Worlds, options))
                {
                    success = false;
                }
                if (!ProcessItemsDownload(WorkshopType.Scenario, options.Scenarios, options))
                {
                    success = false;
                }

                MySandboxGame.Log.WriteLineAndConsole("Batch workshop download complete!");
                return(success);
            });

            return(Task);
        }
예제 #3
0
        void PrintItemDetails()
        {
            const int MAX_LENGTH = 40;

            MySandboxGame.Log.WriteLineAndConsole(string.Format("Visibility: {0}", m_visibility));
            MySandboxGame.Log.WriteLineAndConsole(string.Format("Tags: {0}", string.Join(", ", m_tags)));

            if (!string.IsNullOrEmpty(m_description))
            {
                MySandboxGame.Log.WriteLineAndConsole($"Description: {m_description.Substring(0, Math.Min(m_description.Length, MAX_LENGTH))}{(m_description.Length > MAX_LENGTH ? "..." : "")}");
            }

            if (!string.IsNullOrEmpty(m_changelog))
            {
                MySandboxGame.Log.WriteLineAndConsole($"Changelog: {m_changelog.Substring(0, Math.Min(m_changelog.Length, MAX_LENGTH))}{(m_changelog.Length > MAX_LENGTH ? "..." : "")}");
            }
#if SE
            MySandboxGame.Log.WriteLineAndConsole(string.Format("DLC requirements: {0}",
                                                                (m_dlcs?.Length > 0 ? string.Join(", ", m_dlcs.Select(i =>
            {
                try { return(Sandbox.Game.MyDLCs.DLCs[i].Name); }
                catch { return($"Unknown({i})"); }
            })) : "None")));
#endif
            MySandboxGame.Log.WriteLineAndConsole(string.Format("Dependencies: {0}", (m_deps?.Length > 0 ? string.Empty : "None")));

            if (m_deps?.Length > 0)
            {
                var width = Console.Out.IsInteractive() ? Console.WindowWidth : 256;

                var depIds   = m_deps.ToWorkshopIds();
                var depItems = WorkshopHelper.GetItemsBlocking(depIds.ToArray());

                if (depItems?.Count > 0)
                {
                    depItems.ForEach(i => MySandboxGame.Log.WriteLineAndConsole(string.Format("{0,15} -> {1}",
                                                                                              i.Id, i.Title.Substring(0, Math.Min(i.Title.Length, width - 45)))));
                }
                else
                {
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("     {0}", string.Join(", ", m_deps)));
                }
            }
            MySandboxGame.Log.WriteLineAndConsole(string.Format("Thumbnail: {0}", m_previewFilename ?? "No change"));
            ValidateThumbnail();
        }
예제 #4
0
        PublishedFileVisibility GetVisibility()
        {
            var results = m_workshopItems?.Values ?? (ICollection <MyWorkshopItem>)WorkshopHelper.GetItemsBlocking(m_modId);

            if (results?.Count > 0)
            {
                if (results.Count > 0)
                {
                    return((PublishedFileVisibility)(int)results.First().Visibility);
                }
                else
                {
                    return(PublishedFileVisibility.Private);
                }
            }

            return(PublishedFileVisibility.Private);
        }
예제 #5
0
        string[] GetTags()
        {
            var results = m_workshopItems?.Values ?? (ICollection <MyWorkshopItem>)WorkshopHelper.GetItemsBlocking(m_modId);

            if (results?.Count > 0)
            {
                if (results.Count > 0)
                {
                    return(results.First().Tags.ToArray());
                }
                else
                {
                    return(null);
                }
            }

            return(null);
        }
예제 #6
0
        static string[] TestPathAndMakeAbsolute(WorkshopType type, string[] paths)
        {
            for (int idx = 0; paths != null && idx < paths.Length; idx++)
            {
                // If the passed in path doesn't exist, and is relative, try to match it with the expected data directory
                if (!Directory.Exists(paths[idx]) && !Path.IsPathRooted(paths[idx]))
                {
                    // Check if value is actually a mod id, and work remotely, if so.
                    var newpath = Path.Combine(WorkshopHelper.GetWorkshopItemPath(type), paths[idx]);

                    if (Directory.Exists(newpath) || !ulong.TryParse(paths[idx], out var id))
                    {
                        paths[idx] = newpath;
                    }
                }
            }
            return(paths);
        }
예제 #7
0
        bool FillPropertiesFromPublished()
        {
            var results = WorkshopHelper.GetItemsBlocking(m_modId);

            if (results?.Count > 0)
            {
                System.Threading.Thread.Sleep(1000); // Fix for DLC not being filled in
                if (results.Count > 0)
                {
                    m_workshopItems[m_modId[0]] = results[0];

                    if (m_modId.Length > 1 && results.Count > 1)
                    {
                        m_workshopItems[m_modId[1]] = results[1];
                    }

                    m_title = results[0].Title;

                    // Check if the mod owner in the sbmi matches steam owner
                    var owner = results[0].OwnerId;

                    if (m_visibility == null)
                    {
                        m_visibility = (PublishedFileVisibility)(int)results[0].Visibility;
                    }

#if SE
                    m_dlcs = results[0].DLCs.ToArray();
#endif
                    m_deps = results[0].Dependencies.ToArray();

                    MyDebug.AssertDebug(owner == MyGameService.UserId);
                    if (owner != MyGameService.UserId)
                    {
                        MySandboxGame.Log.WriteLineError(string.Format("Owner mismatch! Mod owner: {0}; Current user: {1}", owner, MyGameService.UserId));
                        MySandboxGame.Log.WriteLineError("Upload/Publish FAILED!");
                        return(false);
                    }
                    return(true);
                }
                return(false);
            }
            return(false);
        }
예제 #8
0
        uint[] GetDLC()
        {
#if SE
            var results = m_workshopItems?.Values ?? (ICollection <MyWorkshopItem>)WorkshopHelper.GetItemsBlocking(m_modId);

            if (results?.Count > 0)
            {
                if (results.Count > 0)
                {
                    return(results.First().DLCs.ToArray());
                }
                else
                {
                    return(null);
                }
            }
#endif
            return(null);
        }
예제 #9
0
        ulong ParseOrGetWorkshopID(string idOrName)
        {
            if (ulong.TryParse(idOrName, out var id))
            {
                return(id);
            }
            else
            {
                // Dependencies can only be mods (not blueprints, scripts, etc)
                id = WorkshopHelper.GetWorkshopIdFromMod(Path.Combine(WorkshopHelper.GetWorkshopItemPath(m_type), idOrName)).FirstOrDefault().GetId();

                // TODO: Better handle if an unpublished mod is passed in, but bailing on exception is fine for now
                if (id == 0)
                {
                    throw new ArgumentException($"Cannot determine Workshop ID of dependency '{idOrName}'. Is it a published mod?");
                }
                return(id);
            }
        }
예제 #10
0
        public bool UpdatePreviewFileOrTags(ulong modId, MyWorkshopItemPublisher publisher)
        {
            ProcessTags();

            publisher.Id         = modId;
            publisher.Title      = Title;
            publisher.Visibility = (MyPublishedFileVisibility)(int)(m_visibility ?? GetVisibility());
            publisher.Thumbnail  = m_previewFilename;
            publisher.Tags       = new List <string>(m_tags);
#if SE
            if (m_dlcs != null)
            {
                publisher.DLCs = new HashSet <uint>(m_dlcs);
            }
#else
            publisher.Folder = m_modPath;
#endif
            if (m_deps != null)
            {
                publisher.Dependencies = new List <ulong>(m_deps);
            }

            AutoResetEvent resetEvent = new AutoResetEvent(false);
            try
            {
                publisher.ItemPublished += ((result, id) =>
                {
                    if (result == MyGameServiceCallResult.OK)
                    {
                        MySandboxGame.Log.WriteLineAndConsole("Published file update successful");

                        if (!string.IsNullOrEmpty(m_previewFilename))
                        {
                            MySandboxGame.Log.WriteLineAndConsole(string.Format("Updated thumbnail: {0}", Title));
                        }
                    }
                    else
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("Error during publishing: {0}", (object)result));
                    }
                    resetEvent.Set();
                });

                PrintItemDetails();

                publisher.Publish();
                WorkshopHelper.PublishDependencies(m_modId, m_deps, m_depsToRemove);

                if (!resetEvent.WaitOne())
                {
                    return(false);
                }
            }
            finally
            {
                if (resetEvent != null)
                {
                    resetEvent.Dispose();
                }
            }

            return(true);
        }
예제 #11
0
        /// <summary>
        /// Publishes the mod to the workshop
        /// </summary>
        /// <returns></returns>
        public bool Publish()
        {
            bool newMod = false;

            if (!Directory.Exists(m_modPath))
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Directory does not exist {0}. Wrong option?", m_modPath ?? string.Empty));
                return(false);
            }

            // Upload/Publish
#if SE
            if (((IMod)this).ModId == 0)
#else
            if (m_modId == 0)
#endif
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Uploading new {0}: {1}", m_type.ToString(), m_title));
                newMod = true;

#if SE
                if (m_modId.Length == 0)
                {
                    m_modId = new WorkshopId[1] {
                        new WorkshopId(0, MyGameService.GetDefaultUGC().ServiceName)
                    }
                }
                ;
#endif
            }
            else
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Updating {0}: {1}; {2}", m_type.ToString(), m_modId.AsString(), m_title));
            }

            // Add the global game filter for file extensions
            _globalIgnoredExtensions?.ForEach(s => m_ignoredExtensions.Add(s));

            // Process Tags
            ProcessTags();

            PrintItemDetails();

            MyWorkshopItem[] items = null;

            if (m_dryrun)
            {
                MySandboxGame.Log.WriteLineAndConsole("DRY-RUN; Publish skipped");
                return(true);
            }
            else
            {
                if (_publishMethod != null)
                {
                    InjectedMethod.ChangeLog = m_changelog;
#if SE
                    var result = _publishMethod(m_modPath, m_title, m_description, m_modId, (MyPublishedFileVisibility)(m_visibility ?? PublishedFileVisibility.Private), m_tags, m_ignoredExtensions, m_ignoredPaths, m_dlcs, out items);
                    PublishSuccess = result.Item1 == MyGameServiceCallResult.OK;

                    if (PublishSuccess)
                    {
                        m_modId = items.Select(i => new WorkshopId(i.Id, i.ServiceName)).ToArray();
                    }
#else
                    m_modId = _publishMethod(m_modPath, m_title, m_description, m_modId, (MyPublishedFileVisibility)(m_visibility ?? PublishedFileVisibility.Private), m_tags, m_ignoredExtensions, m_ignoredPaths);
#endif
                }
                else
                {
                    MySandboxGame.Log.WriteLineAndConsole(string.Format(Constants.ERROR_Reflection, "PublishItemBlocking"));
                }

                // SE libraries don't support updating dependencies, so we have to do that separately
                WorkshopHelper.PublishDependencies(m_modId, m_deps, m_depsToRemove);
            }
            if (((IMod)this).ModId == 0 || !PublishSuccess)
            {
                MySandboxGame.Log.WriteLineAndConsole("Upload/Publish FAILED!");
                return(false);
            }
            else
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Upload/Publish success: {0}", m_modId.AsString()));
                if (newMod)
                {
#if SE
                    if (MyWorkshop.GenerateModInfo(m_modPath, items, MyGameService.UserId))
#else
                    if (MyWorkshop.UpdateModMetadata(m_modPath, m_modId, MySteam.UserId))
#endif
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("Create modinfo.sbmi success: {0}", m_modId.AsString()));
                    }
                    else
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("Create modinfo.sbmi FAILED: {0}", m_modId.AsString()));
                        return(false);
                    }
                }
            }
            return(true);
        }

        bool FillPropertiesFromPublished()
        {
            var results = new List <MyWorkshopItem>();

#if SE
            if (MyWorkshop.GetItemsBlockingUGC(m_modId.ToList(), results))
#else
            if (MyWorkshop.GetItemsBlocking(new List <ulong>()
            {
                m_modId
            }, results))
#endif
            {
                System.Threading.Thread.Sleep(1000); // Fix for DLC not being filled in
                if (results.Count > 0)
                {
#if SE
                    m_workshopItems[m_modId[0]] = results[0];

                    if (m_modId.Length > 1 && results.Count > 1)
                    {
                        m_workshopItems[m_modId[1]] = results[1];
                    }
#else
                    if (results.Count > 1)
                    {
                        m_modId = results[0].Id;
                    }
#endif

                    m_title = results[0].Title;

                    // Check if the mod owner in the sbmi matches steam owner
                    var owner = results[0].OwnerId;

                    if (m_visibility == null)
                    {
                        m_visibility = (PublishedFileVisibility)(int)results[0].Visibility;
                    }

#if SE
                    m_dlcs = results[0].DLCs.ToArray();
#endif
                    m_deps = results[0].Dependencies.ToArray();

                    MyDebug.AssertDebug(owner == MyGameService.UserId);
                    if (owner != MyGameService.UserId)
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("Owner mismatch! Mod owner: {0}; Current user: {1}", owner, MyGameService.UserId));
                        MySandboxGame.Log.WriteLineAndConsole("Upload/Publish FAILED!");
                        return(false);
                    }
                    return(true);
                }
                return(false);
            }
            return(true);
        }

        void ProcessTags()
        {
            // TODO: This code could be better.

            // Get the list of existing tags, if there are any
            var existingTags = GetTags();
            var length       = m_tags.Length;

            // Order or tag processing matters
            // 1) Copy mod type into tags
            var modtype = m_type.ToString();

            // 2) Verify the modtype matches what was listed in the workshop
            // TODO If type doesn't match, process as workshop type
            if (existingTags != null && existingTags.Length > 0)
            {
                MyDebug.AssertRelease(existingTags.Contains(modtype, StringComparer.InvariantCultureIgnoreCase), string.Format("Mod type '{0}' does not match workshop '{1}'", modtype, existingTags[0]));
            }

#if SE
            // 3a) check if user passed in the 'development' tag
            // If so, remove it, and mark the mod as 'dev' so it doesn't get flagged later
            if (m_tags.Contains(MyWorkshop.WORKSHOP_DEVELOPMENT_TAG))
            {
                m_tags  = (from tag in m_tags where tag != MyWorkshop.WORKSHOP_DEVELOPMENT_TAG select tag).ToArray();
                m_isDev = true;
            }
#endif
            // 3b If tags contain mod type, remove it
            if (m_tags.Contains(modtype, StringComparer.InvariantCultureIgnoreCase))
            {
                m_tags = (from tag in m_tags where string.Compare(tag, modtype, true) != 0 select tag).ToArray();
            }

            // 4)
            if (m_tags.Length == 1 && m_tags[0] == null && existingTags != null && existingTags.Length > 0)
            {
                // 4a) If user passed no tags, use existing ones
                Array.Resize(ref m_tags, existingTags.Length);
                Array.Copy(existingTags, m_tags, existingTags.Length);
            }
            else
            {
                // 4b) Verify passed in tags are valid for this mod type
                var validTags = new List <MyWorkshop.Category>()
                {
#if SE
                    // 'obsolete' tag is always available, as is 'No Mods' and 'experimental'
                    new MyWorkshop.Category()
                    {
                        Id = "obsolete"
                    },
                    new MyWorkshop.Category()
                    {
                        Id = "no mods"
                    },
                    new MyWorkshop.Category()
                    {
                        Id = "experimental"
                    },
#endif
                };
                switch (m_type)
                {
                case WorkshopType.Mod:
                    MyWorkshop.ModCategories.ForEach(c => validTags.Add(c));
                    // Mods have extra tags not in this list
#if SE
                    validTags.Add(new MyWorkshop.Category()
                    {
                        Id = "campaign"
                    });
                    validTags.Add(new MyWorkshop.Category()
                    {
                        Id = "font"
                    });
                    validTags.Add(new MyWorkshop.Category()
                    {
                        Id = "noscripts"
                    });
#endif
                    break;

                case WorkshopType.Blueprint:
                    MyWorkshop.BlueprintCategories.ForEach(c => validTags.Add(c));
#if SE
                    // Blueprints have extra tags not in this list
                    validTags.Add(new MyWorkshop.Category()
                    {
                        Id = "large_grid"
                    });
                    validTags.Add(new MyWorkshop.Category()
                    {
                        Id = "small_grid"
                    });
                    validTags.Add(new MyWorkshop.Category()
                    {
                        Id = "safe"
                    });                                                             // Mod.io only?
#endif
                    break;

                case WorkshopType.Scenario:
                    MyWorkshop.ScenarioCategories.ForEach(c => validTags.Add(c));
                    break;

                case WorkshopType.World:
                    MyWorkshop.WorldCategories.ForEach(c => validTags.Add(c));
                    break;

                case WorkshopType.IngameScript:
                    //tags = new MyWorkshop.Category[0];     // There are none currently
                    break;

                default:
                    MyDebug.FailRelease("Invalid category.");
                    break;
                }

                // This query gets all the items in 'm_tags' that do *not* exist in 'validTags'
                // This is for detecting invalid tags passed in
                var invalidItems = from utag in m_tags
                                   where !(
                    from tag in validTags
                    select tag.Id
                    ).Contains(utag, StringComparer.InvariantCultureIgnoreCase)
                                   select utag;

                if (invalidItems.Count() > 0)
                {
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("{0} invalid tags: {1}", (m_force ? "Forced" : "Removing"), string.Join(", ", invalidItems)));

                    if (!m_force)
                    {
                        m_tags = (from tag in m_tags where !invalidItems.Contains(tag) select tag).ToArray();
                    }
                }

                // Now prepend the 'Type' tag
                string[] newTags = new string[m_tags.Length + 1];
                newTags[0] = m_type.ToString();

                var tags = from tag in validTags select tag.Id;

                // Convert all tags to proper-case
                for (var x = 0; x < m_tags.Length; x++)
                {
                    var tag    = m_tags[x];
                    var newtag = (from vtag in tags where (string.Compare(vtag, tag, true) == 0) select vtag).FirstOrDefault();

                    if (!string.IsNullOrEmpty(newtag))
                    {
                        newTags[x + 1] = newtag;
                    }
                    else
                    {
                        newTags[x + 1] = m_tags[x];
                    }
                }

                m_tags = newTags;
            }
#if SE
            // 5) Set or clear development tag
            if (m_isDev)
            {
                // If user selected dev, add dev tag
                if (!m_tags.Contains(MyWorkshop.WORKSHOP_DEVELOPMENT_TAG))
                {
                    Array.Resize(ref m_tags, m_tags.Length + 1);
                    m_tags[m_tags.Length - 1] = MyWorkshop.WORKSHOP_DEVELOPMENT_TAG;
                }
            }
            else
            {
                // If not, remove tag
                if (m_tags.Contains(MyWorkshop.WORKSHOP_DEVELOPMENT_TAG))
                {
                    m_tags = (from tag in m_tags where tag != MyWorkshop.WORKSHOP_DEVELOPMENT_TAG select tag).ToArray();
                }
            }
#endif
            // 6) Strip empty values
            m_tags = m_tags.Where(x => !string.IsNullOrEmpty(x)).ToArray();

            // Done
        }

        string[] GetTags()
        {
            var results = new List <MyWorkshopItem>();

#if SE
            if (MyWorkshop.GetItemsBlockingUGC(m_modId.ToList(), results))
#else
            if (MyWorkshop.GetItemsBlocking(new List <ulong>()
            {
                m_modId
            }, results))
#endif
            {
                if (results.Count > 0)
                {
                    return(results[0].Tags.ToArray());
                }
                else
                {
                    return(null);
                }
            }

            return(null);
        }

        uint[] GetDLC()
        {
#if SE
            var results = new List <MyWorkshopItem>();

            if (MyWorkshop.GetItemsBlockingUGC(m_modId.ToList(), results))
            {
                if (results.Count > 0)
                {
                    return(results[0].DLCs.ToArray());
                }
                else
                {
                    return(null);
                }
            }
#endif
            return(null);
        }

        PublishedFileVisibility GetVisibility()
        {
            var results = new List <MyWorkshopItem>();

#if SE
            if (MyWorkshop.GetItemsBlockingUGC(m_modId.ToList(), results))
#else
            if (MyWorkshop.GetItemsBlocking(new List <ulong>()
            {
                m_modId
            }, results))
#endif
            {
                if (results.Count > 0)
                {
                    return((PublishedFileVisibility)(int)results[0].Visibility);
                }
                else
                {
                    return(PublishedFileVisibility.Private);
                }
            }

            return(PublishedFileVisibility.Private);
        }
예제 #12
0
        public bool UpdatePreviewFileOrTags(WorkshopId modId)
        {
            MyWorkshopItemPublisher publisher = WorkshopHelper.GetPublisher(modId);
            var modid = modId.GetId();

            publisher.Id          = modid;
            publisher.Title       = Title;
            publisher.Visibility  = (MyPublishedFileVisibility)(int)(m_visibility ?? GetVisibility());
            publisher.Thumbnail   = m_previewFilename;
            publisher.Tags        = new List <string>(m_tags);
            publisher.Description = m_description;
#if SE
            if (m_dlcs != null)
            {
                publisher.DLCs = new HashSet <uint>(m_dlcs);
            }
#else
            // ME will throw an exception if this isn't set, however setting this in SE
            // will trigger a full change event (with a new change note entry), which we don't want.
            publisher.Folder = m_modPath;
#endif
            if (m_deps != null)
            {
                publisher.Dependencies = new List <ulong>(m_deps);
            }

            AutoResetEvent resetEvent = new AutoResetEvent(false);
            try
            {
                publisher.ItemPublished += ((result, id) =>
                {
                    if (result == MyGameServiceCallResult.OK)
                    {
                        MySandboxGame.Log.WriteLineAndConsole("Published file update successful");

                        if (!string.IsNullOrEmpty(m_previewFilename))
                        {
                            MySandboxGame.Log.WriteLineAndConsole(string.Format("Updated thumbnail: {0}", Title));
                        }
                    }
                    else
                    {
                        MySandboxGame.Log.WriteLineError(string.Format("Error during publishing: {0}", (object)result));
                    }
                    resetEvent.Set();
                });

                PrintItemDetails();

                if (m_dryrun)
                {
                    MySandboxGame.Log.WriteLineAndConsole("DRY-RUN; Publish skipped");
                    return(true);
                }
                publisher.Publish();
                WorkshopHelper.PublishDependencies(m_modId, m_depsToAdd, m_depsToRemove);

                if (!resetEvent.WaitOne())
                {
                    return(false);
                }
            }
            finally
            {
                if (resetEvent != null)
                {
                    resetEvent.Dispose();
                }
            }
            return(true);
        }
예제 #13
0
        public Uploader(WorkshopType type, string path, Options.UploadVerb options, string description = null, string changelog = null)
        {
            m_modPath = path;

            if (ulong.TryParse(m_modPath, out ulong id))
            {
                m_modId = WorkshopIdExtensions.ToWorkshopIds(new[] { id });
            }
            else
            {
                m_modId = WorkshopHelper.GetWorkshopIdFromMod(m_modPath);
            }

            // Fill defaults before assigning user-defined ones
            if (m_modId.Length > 0 && m_modId.GetIds()[0] != 0 && !FillPropertiesFromPublished())
            {
                MySandboxGame.Log.WriteLineWarning("Mod has a published ID, but unable to look up properties. This is wrong.");
            }

            m_compile = options.Compile;
            m_dryrun  = options.DryRun;

            // Set visibilty
            if (options.Visibility != null)
            {
                m_visibility = options.Visibility;
            }
            else
            {
                m_visibility = m_visibility ?? PublishedFileVisibility.Private; // If not already set, set to Private
            }
            if (string.IsNullOrEmpty(m_title))
            {
                m_title = Path.GetFileName(path);
            }

            m_description = description;
            m_changelog   = changelog;

            m_type  = type;
            m_force = options.Force;

            if (options.Thumbnail != null)
            {
                m_previewFilename = options.Thumbnail;
            }
            var mappedlc = MapDLCStringsToInts(options.DLCs);

            ProcessDLCs(mappedlc, MapDLCStringsToInts(options.DLCToAdd), MapDLCStringsToInts(options.DLCToRemove));

            if (options.Tags != null)
            {
                m_tags = options.Tags.ToArray();
            }
            if (options.TagsToAdd != null)
            {
                m_tagsToAdd = options.TagsToAdd.ToArray();
            }
            if (options.TagsToRemove != null)
            {
                m_tagsToRemove = options.TagsToRemove.ToArray();
            }

            ProcessTags();
            ProcessDependencies(options.Dependencies, options.DependenciesToAdd, options.DependenciesToRemove);

            // This file list should match the PublishXXXAsync methods in MyWorkshop
            switch (m_type)
            {
            case WorkshopType.Mod:
                m_ignoredPaths.Add("modinfo.sbmi");
                break;

            case WorkshopType.IngameScript:
                break;

            case WorkshopType.World:
                m_ignoredPaths.Add("Backup");
                break;

            case WorkshopType.Blueprint:
                break;

            case WorkshopType.Scenario:
                break;
            }

            options.ExcludeExtensions?.Select(s => "." + s.TrimStart(new[] { '.', '*' })).ForEach(s => m_ignoredExtensions.Add(s));
            options.IgnorePaths?.ForEach(s => m_ignoredPaths.Add(s));

            // Start with the parent file, if it exists. This is at %AppData%\SpaceEngineers\Mods.
            if (IgnoreFile.TryLoadIgnoreFile(Path.Combine(m_modPath, "..", ".wtignore"), Path.GetFileName(m_modPath), out var extensionsToIgnore, out var pathsToIgnore))
            {
                extensionsToIgnore.ForEach(s => m_ignoredExtensions.Add(s));
                pathsToIgnore.ForEach(s => m_ignoredPaths.Add(s));
            }

            if (IgnoreFile.TryLoadIgnoreFile(Path.Combine(m_modPath, ".wtignore"), out extensionsToIgnore, out pathsToIgnore))
            {
                extensionsToIgnore.ForEach(s => m_ignoredExtensions.Add(s));
                pathsToIgnore.ForEach(s => m_ignoredPaths.Add(s));
            }
        }
예제 #14
0
        /// <summary>
        /// Publishes the mod to the workshop
        /// </summary>
        /// <returns></returns>
        public bool Publish()
        {
            bool newMod = false;

            if (!Directory.Exists(m_modPath))
            {
                MySandboxGame.Log.WriteLineWarning(string.Format("Directory does not exist {0}. Wrong option?", m_modPath ?? string.Empty));
                return(false);
            }

            // Upload/Publish
            if (((IMod)this).ModId == 0)
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Uploading new {0}: {1}", m_type.ToString(), m_title));
                newMod = true;

                if (m_modId.Length == 0)
                {
                    m_modId = WorkshopIdExtensions.ToWorkshopIds(new ulong[] { 0 });
                }
            }
            else
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Updating {0}: {1}; {2}", m_type.ToString(), m_modId.AsString(), m_title));
            }

            // Add the global game filter for file extensions
            WorkshopHelper.IgnoredExtensions?.ForEach(s => m_ignoredExtensions.Add(s));

            PrintItemDetails();

            MyWorkshopItem[] items = null;

            if (m_dryrun)
            {
                MySandboxGame.Log.WriteLineAndConsole("DRY-RUN; Publish skipped");
                return(true);
            }
            else
            {
                InjectedMethod.ChangeLog = m_changelog;
                if (WorkshopHelper.PublishItemBlocking(m_modPath, m_title, m_description, m_modId, (MyPublishedFileVisibility)m_visibility, m_tags, m_ignoredExtensions, m_ignoredPaths, m_dlcs, out items))
                {
                    m_modId = items.ToWorkshopIds();
                }
                else
                {
                    MySandboxGame.Log.WriteLineError(string.Format(Constants.ERROR_Reflection, "PublishItemBlocking"));
                }

                // SE libraries don't support updating dependencies, so we have to do that separately
                WorkshopHelper.PublishDependencies(m_modId, m_depsToAdd, m_depsToRemove);
                // SE also doesn't support removing DLC items, so do that too
                WorkshopHelper.PublishDLC(m_modId, m_dlcsToAdd, m_dlcsToRemove);
            }
            if (((IMod)this).ModId == 0 || !WorkshopHelper.PublishSuccess)
            {
                MySandboxGame.Log.WriteLineError("Upload/Publish FAILED!");
                return(false);
            }
            else
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format("Upload/Publish success: {0}", m_modId.AsString()));
                if (newMod)
                {
                    if (WorkshopHelper.GenerateModInfo(m_modPath, items, m_modId, MyGameService.UserId))
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("Create modinfo.sbmi success: {0}", m_modId.AsString()));
                    }
                    else
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("Create modinfo.sbmi FAILED: {0}", m_modId.AsString()));
                        return(false);
                    }
                }
            }
            return(true);
        }
예제 #15
0
        /// <summary>
        /// Compiles the mod
        /// </summary>
        /// <returns></returns>
        public bool Compile()
        {
            // Compile
            if (m_compile)
            {
                if (m_type == WorkshopType.Mod)
                {
                    MySandboxGame.Log.WriteLineAndConsole("Compiling...");
                    var mod = WorkshopHelper.GetContext(m_modPath, m_workshopItems.GetValueOrDefault(m_modId.FirstOrDefault()), m_modId, m_title);
                    if (WorkshopHelper.LoadScripts(m_modPath, mod))
                    {
                        // Process any errors
                        var errors = WorkshopHelper.GetErrors();

                        if (errors.Count > 0)
                        {
                            int errorCount   = 0;
                            int warningCount = 0;

                            // This is not efficient, but I'm lazy
                            foreach (var error in errors)
                            {
                                if (error.Severity >= TErrorSeverity.Error)
                                {
                                    errorCount++;
                                }
                                if (error.Severity == TErrorSeverity.Warning)
                                {
                                    warningCount++;
                                }
                            }

                            if (errorCount > 0)
                            {
                                MySandboxGame.Log.WriteLineError(string.Format("There are {0} compile errors:", errorCount));
                            }
                            if (warningCount > 0)
                            {
                                MySandboxGame.Log.WriteLineWarning(string.Format("There are {0} compile warnings:", warningCount));
                            }

                            // Output raw message, which is usually in msbuild friendly format, for automated tools
                            foreach (var error in errors)
                            {
                                var color = error.Severity == TErrorSeverity.Warning ? ConsoleColor.Yellow : ConsoleColor.Red;
                                ProgramBase.ConsoleWriteColored(color, () =>
                                                                System.Console.Error.WriteLine(error.GetErrorText()));
                            }

                            WorkshopHelper.ClearErrors();

                            if (errorCount > 0)
                            {
                                MySandboxGame.Log.WriteLineError("Compilation FAILED!");
                                return(false);
                            }
                        }
                        MySandboxGame.Log.WriteLineAndConsole("Compilation successful!");
                    }
                }
#if SE
                else if (m_type == WorkshopType.IngameScript)
                {
                    MySandboxGame.Log.WriteLineAndConsole("Compiling...");
                    // Load the ingame script from the disk
                    // I don't like this, but meh
                    var input   = new StreamReader(Path.Combine(m_modPath, "Script.cs"));
                    var program = input.ReadToEnd();
                    input.Close();
                    var scripts = new List <Script>();
                    scripts.Add(MyScriptCompiler.Static.GetIngameScript(program, "Program", typeof(Sandbox.ModAPI.Ingame.MyGridProgram).Name, "sealed partial"));

                    var messages = new List <Message>();
                    var assembly = MyVRage.Platform.Scripting.CompileIngameScriptAsync(Path.Combine(VRage.FileSystem.MyFileSystem.UserDataPath, "SEWT-Script - " + Path.GetFileName(m_modPath)), program, out messages, "SEWT Compiled PB Script", "Program", typeof(Sandbox.ModAPI.Ingame.MyGridProgram).Name).Result;

                    if (messages.Count > 0)
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format("There are {0} compile messages:", messages.Count));
                        int errors = 0;
                        foreach (var msg in messages)
                        {
                            var color = msg.IsError ? ConsoleColor.Red : ConsoleColor.Gray;
                            ProgramBase.ConsoleWriteColored(color, () =>
                                                            MySandboxGame.Log.WriteLineAndConsole(msg.Text));

                            if (msg.IsError)
                            {
                                errors++;
                            }
                        }
                        if (errors > 0)
                        {
                            MySandboxGame.Log.WriteLineError("Compilation FAILED!");
                            return(false);
                        }
                    }

                    if (assembly == null)
                    {
                        // How can this happen?
                        MySandboxGame.Log.WriteLineError("Compilation FAILED!");
                        return(false);
                    }

                    MySandboxGame.Log.WriteLineAndConsole("Compilation successful!");
                }
#endif
                return(true);
            }
            return(true);
        }
예제 #16
0
        static bool ProcessItemsDownload(WorkshopType type, string[] paths, Options options)
        {
            if (paths == null)
            {
                return(true);
            }

            var width = Console.IsOutputRedirected ? 256 : Console.WindowWidth;

            var items  = new List <MyWorkshopItem>();
            var modids = paths.Select(ulong.Parse);

            MySandboxGame.Log.WriteLineAndConsole(string.Format("Processing {0}s...", type.ToString()));

            var downloadPath = WorkshopHelper.GetWorkshopItemPath(type);

#if SE
            var workshopIds = new List <VRage.Game.WorkshopId>();
            foreach (var id in modids)
            {
                workshopIds.Add(new VRage.Game.WorkshopId(id, MyGameService.GetDefaultUGC().ServiceName));
            }

            if (MyWorkshop.GetItemsBlockingUGC(workshopIds, items))
#else
            if (MyWorkshop.GetItemsBlocking(modids, items))
#endif
            {
                System.Threading.Thread.Sleep(1000); // Fix for DLC not being filled in

                bool success = false;
                if (type == WorkshopType.Mod)
                {
#if SE
                    var result = MyWorkshop.DownloadModsBlockingUGC(items, null);
#else
                    var result = MyWorkshop.DownloadModsBlocking(items, null);
#endif
                    success = result.Success;
                }
                else
                {
                    if (type == WorkshopType.Blueprint)
                    {
                        var loopsuccess = false;
                        foreach (var item in items)
                        {
#if SE
                            loopsuccess = MyWorkshop.DownloadBlueprintBlockingUGC(item);
#else
                            loopsuccess = MyWorkshop.DownloadBlueprintBlocking(item, null);
#endif
                            if (!loopsuccess)
                            {
                                MySandboxGame.Log.WriteLineAndConsole(string.Format("Download of {0} FAILED!", item.Id));
                            }
                            else
                            {
                                success = true;
                            }
                        }
                    }
#if SE
                    else if (type == WorkshopType.IngameScript)
                    {
                        var loopsuccess = false;
                        foreach (var item in items)
                        {
                            loopsuccess = MyWorkshop.DownloadScriptBlocking(item);
                            if (!loopsuccess)
                            {
                                MySandboxGame.Log.WriteLineAndConsole(string.Format("Download of {0} FAILED!", item.Id));
                            }
                            else
                            {
                                success = true;
                            }
                        }
                    }
#endif
#if SE
                    else if (type == WorkshopType.World || type == WorkshopType.Scenario)
                    {
                        var    loopsuccess = false;
                        string path;
                        MyWorkshop.MyWorkshopPathInfo pathinfo = type == WorkshopType.World ?
                                                                 MyWorkshop.MyWorkshopPathInfo.CreateWorldInfo() :
                                                                 MyWorkshop.MyWorkshopPathInfo.CreateScenarioInfo();

                        foreach (var item in items)
                        {
                            // This downloads and extracts automatically, no control over it
                            loopsuccess = MyWorkshop.TryCreateWorldInstanceBlocking(item, pathinfo, out path, false);
                            if (!loopsuccess)
                            {
                                MySandboxGame.Log.WriteLineAndConsole(string.Format("Download of {0} FAILED!", item.Id));
                            }
                            else
                            {
                                MySandboxGame.Log.WriteLineAndConsole(string.Format("Downloaded '{0}' to {1}", item.Title, path));
                                success = true;
                            }
                        }
                    }
#endif
                    else
                    {
                        throw new NotSupportedException(string.Format("Downloading of {0} not yet supported.", type.ToString()));
                    }
                }

                if (success)
                {
                    MySandboxGame.Log.WriteLineAndConsole("Download success!");
                }
                else
                {
                    MySandboxGame.Log.WriteLineAndConsole("Download FAILED!");
                    return(false);
                }

                foreach (var item in items)
                {
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("Downloading mod: {0}; {1}", item.Id, item.Title));
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("Visibility: {0}", item.Visibility));
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("Tags: {0}", string.Join(", ", string.Join(", ", item.Tags))));

#if SE
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("DLC requirements: {0}",
                                                                        (item.DLCs.Count > 0 ? string.Join(", ", item.DLCs.Select(i =>
                    {
                        try { return(Sandbox.Game.MyDLCs.DLCs[i].Name); }
                        catch { return($"Unknown({i})"); }
                    })) : "None")));
#endif
                    MySandboxGame.Log.WriteLineAndConsole(string.Format("Dependencies: {0}", (item.Dependencies.Count > 0 ? string.Empty : "None")));

                    if (item.Dependencies.Count > 0)
                    {
                        List <MyWorkshopItem> depItems = new List <MyWorkshopItem>();
#if SE
                        workshopIds.Clear();
                        foreach (var id in item.Dependencies)
                        {
                            workshopIds.Add(new VRage.Game.WorkshopId(id, MyGameService.GetDefaultUGC().ServiceName));
                        }

                        if (MyWorkshop.GetItemsBlockingUGC(workshopIds, depItems))
#else
                        if (MyWorkshop.GetItemsBlocking(item.Dependencies, depItems))
#endif
                        { depItems.ForEach(i => MySandboxGame.Log.WriteLineAndConsole(string.Format("{0,15} -> {1}",
                                                                                                    i.Id, i.Title.Substring(0, Math.Min(i.Title.Length, width - 45))))); }
                        else
                        {
                            MySandboxGame.Log.WriteLineAndConsole(string.Format("     {0}", string.Join(", ", item.Dependencies)));
                        }
                    }

                    MySandboxGame.Log.WriteLineAndConsole(string.Format("Location: {0}", item.Folder));

                    if (options.Extract)
                    {
                        var mod = new Downloader(downloadPath, item);
                        mod.Extract();
                    }
                    MySandboxGame.Log.WriteLineAndConsole(string.Empty);
                }
            }
            return(true);
        }