Ejemplo n.º 1
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);
        }
Ejemplo n.º 2
0
        // This is mostly copied from MyProgram.Main(), with UI stripped out.
        protected virtual void InitSandbox(string[] args)
        {
            m_args = args;
            // Infinario was removed from SE in update 1.184.6, but is still in ME
            var infinario = typeof(MyFakes).GetField("ENABLE_INFINARIO");

            if (infinario != null)
            {
                infinario.SetValue(null, false);
            }

            if (m_game != null)
            {
                m_game.Exit();
            }

            if (!SetupBasicGameInfo())
            {
                return;
            }

            // Init null render so profiler-enabled builds don't crash
            var render = new MyNullRender();

            MyRenderProxy.Initialize(render);
#if SE
            EmptyKeys.UserInterface.Engine engine = (EmptyKeys.UserInterface.Engine) new VRage.UserInterface.MyEngine();

            if (System.Diagnostics.Debugger.IsAttached)
            {
                m_startup.CheckSteamRunning();        // Just give the warning message box when debugging, ignore for release
            }
            if (!Sandbox.Engine.Platform.Game.IsDedicated)
            {
                MyFileSystem.InitUserSpecific(m_steamService.UserId.ToString());
            }
#endif

            try
            {
#if !SE
                MyRenderProxy.GetRenderProfiler().SetAutocommit(false);
                MyRenderProxy.GetRenderProfiler().InitMemoryHack("MainEntryPoint");
#endif
                // NOTE: an assert may be thrown in debug, about missing Tutorials.sbx. Ignore it.
                m_game = InitGame();

                // Initializing the workshop means the categories are available
                var initWorkshopMethod = m_game.GetType().GetMethod("InitSteamWorkshop", BindingFlags.NonPublic | BindingFlags.Instance);
                MyDebug.AssertRelease(initWorkshopMethod != null);

                if (initWorkshopMethod != null)
                {
                    var parameters = initWorkshopMethod.GetParameters();
                    MyDebug.AssertRelease(parameters.Count() == 0);
                }

                if (initWorkshopMethod != null)
                {
                    initWorkshopMethod.Invoke(m_game, null);
                }
                else
                {
                    MySandboxGame.Log.WriteLineAndConsole(string.Format(Constants.ERROR_Reflection, "InitSteamWorkshop"));
                }
            }
            catch (Exception ex)
            {
                // This shouldn't fail, but don't stop even if it does
                ex.Log("WARNING: An exception occured, ignoring: ");
            }

            AuthenticateWorkshop();
        }
Ejemplo n.º 3
0
        private void SetupReflection()
        {
            if (m_compile && m_type == WorkshopType.Mod)
            {
#if SE
                if (_scriptManager == null)
                {
                    _scriptManager = new MyScriptManager();
                }
#else
                if (_scriptManager == null)
                {
                    _scriptManager = new MyModManager();
                }
#endif
                if (_compileMethod == null)
                {
                    var compileMethod = _scriptManager.GetType().GetMethod("LoadScripts", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null
#if SE
                                                                           , new[] { typeof(string), typeof(MyModContext) }
#else
                                                                           , new[] { typeof(MyModContext) }
#endif
                                                                           , null);
                    MyDebug.AssertDebug(compileMethod != null);

                    if (compileMethod != null)
                    {
                        _compileMethod = Delegate.CreateDelegate(typeof(LoadScripts), _scriptManager, compileMethod, false) as LoadScripts;
                    }

                    if (_compileMethod == null)
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format(Constants.ERROR_Reflection, "LoadScripts"));
                    }
                }
            }

            var publishMethod = typeof(MyWorkshop).GetMethod("PublishItemBlocking", BindingFlags.Static | BindingFlags.NonPublic, Type.DefaultBinder, new Type[]
            {
                typeof(string),
                typeof(string),
                typeof(string),
                m_modId.GetType(),
                typeof(MyPublishedFileVisibility),
                typeof(string[]),
                typeof(HashSet <string>),
                typeof(HashSet <string>),
#if SE
                typeof(uint[]),
                typeof(MyWorkshopItem[]).MakeByRefType()
#endif
            }, null);

            MyDebug.AssertDebug(publishMethod != null);

            if (publishMethod != null)
            {
                _publishMethod = Delegate.CreateDelegate(typeof(PublishItemBlocking), publishMethod, false) as PublishItemBlocking;
            }

            if (_publishMethod == null)
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format(Constants.ERROR_Reflection, "PublishItemBlocking"));
            }

            if (_globalIgnoredExtensions == null)
            {
                _globalIgnoredExtensions = (HashSet <string>) typeof(MyWorkshop).GetField("m_ignoredExecutableExtensions", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null);
            }

            if (_previewFileNames == null)
            {
                _previewFileNames = (string[])typeof(MyWorkshop).GetField("m_previewFileNames", BindingFlags.Static | BindingFlags.NonPublic)?.GetValue(null);
            }

            if (_previewFileNames == null)
            {
                _previewFileNames = new string[] { "thumb.png", "thumb.jpg" }
            }
            ;

#if !SE
            try
            {
                if (__refget_m_publishSuccess == null)
                {
                    __refget_m_publishSuccess = MethodUtil.create_refgetter <MyWorkshop, bool>("m_publishSuccess", BindingFlags.NonPublic | BindingFlags.Static);
                }
            }
            catch (Exception ex)
            {
                MySandboxGame.Log.WriteLineAndConsole(string.Format(Constants.ERROR_Reflection, "m_publishSuccess"));
                MySandboxGame.Log.WriteLine(ex.Message);
            }
#endif
        }
Ejemplo n.º 4
0
        public virtual int InitGame(string[] args)
        {
            var options = new Options();
            var parser  = new CommandLine.Parser(with => with.HelpWriter = Console.Error);

            if (parser.ParseArgumentsStrict(args, options, HandleInputError))
            {
                if (options.ModPaths == null &&
                    options.Blueprints == null &&
#if SE
                    options.IngameScripts == null &&
#endif
                    options.Scenarios == null &&
                    options.Worlds == null &&
                    options.Collections == null)
                {
                    if (!options.ClearSteamCloud && !options.ListDLCs)
                    {
                        Console.WriteLine(CommandLine.Text.HelpText.AutoBuild(options).ToString());
                        return(Cleanup(1));
                    }
                }

                // If a "0" or "none" was specified for DLC, that means remove them all.
                if (options.DLCs?.Length > 0 &&
                    (options.DLCs.Contains("0") || options.DLCs.Contains("none", StringComparer.InvariantCultureIgnoreCase)))
                {
                    options.DLCs = new string[0];
                }

                // If a 0 was specified for dependencies, that means remove them all.
                if (options.Dependencies?.Length > 0 && options.Dependencies.Contains((ulong)0))
                {
                    options.Dependencies = new ulong[0];
                }

                // SE requires -appdata, but the commandline dll requires --appdata, so fix it
                for (var idx = 0; idx < args.Length; idx++)
                {
                    if (string.Compare(args[idx], "--appdata", StringComparison.InvariantCultureIgnoreCase) == 0)
                    {
                        args[idx] = "-appdata";
                    }
                }

                m_useModIO = options.ModIO;
                try
                {
                    // Initialize game code
                    InitSandbox(args);
                }
                catch (Exception ex)
                {
                    ex.Log("ERROR: An exception occurred intializing game libraries: ");
                    return(Cleanup(2));
                }

                if (!SteamAPI.IsSteamRunning())
                {
                    MySandboxGame.Log.WriteLineAndConsole("ERROR: * Steam not detected. Is Steam running and not as Admin? *");
                    MySandboxGame.Log.WriteLineAndConsole("* Only compile testing is available. *");
                    MySandboxGame.Log.WriteLineAndConsole("");

                    if (options.Download)
                    {
                        return(Cleanup(3));
                    }

                    options.Upload = false;
                }

                MySandboxGame.Log.WriteLineAndConsole($"{AppName} {Assembly.GetExecutingAssembly().GetName().Version}");

                ProgramBase.CheckForUpdate(MySandboxGame.Log.WriteLineAndConsole);

                MySandboxGame.Log.WriteLineToConsole(string.Empty);
                MySandboxGame.Log.WriteLineAndConsole($"Log file: {MySandboxGame.Log.GetFilePath()}");
                MySandboxGame.Log.WriteLineToConsole(string.Empty);

                // Make sure file paths are properly rooted based on the user's current directory at launch
                MySandboxGame.Log.WriteLineAndConsole($"Relative root: {LaunchDirectory}");

#if SE
                ParameterInfo[] parameters;
                if (options.Compile)
                {
                    // Init ModAPI
                    var initmethod = typeof(MySandboxGame).GetMethod("InitModAPI", BindingFlags.Instance | BindingFlags.NonPublic);
                    MyDebug.AssertRelease(initmethod != null);

                    if (initmethod != null)
                    {
                        parameters = initmethod.GetParameters();
                        MyDebug.AssertRelease(parameters.Count() == 0);

                        if (!(parameters.Count() == 0))
                        {
                            initmethod = null;
                        }
                    }

                    if (initmethod != null)
                    {
                        initmethod.Invoke(m_game, null);
                    }
                    else
                    {
                        MySandboxGame.Log.WriteLineAndConsole(string.Format(Constants.ERROR_Reflection, "InitModAPI"));
                    }
                }
#endif
                ReplaceMethods();

                System.Threading.Tasks.Task <bool> Task;

                if (options.Download)
                {
                    Task = DownloadMods(options);
                }
                else if (options.ClearSteamCloud)
                {
                    Task = ClearSteamCloud(options.DeleteSteamCloudFiles, options.Force);
                }
                else if (options.ListDLCs)
                {
                    Task = System.Threading.Tasks.Task <bool> .Factory.StartNew(() => { ListDLCs(); return(true); });
                }
                else
                {
                    Task = UploadMods(options);
                }

                try
                {
                    // Wait for file transfers to finish (separate thread)
                    while (!Task.Wait(100))
                    {
                        MyGameService.Update();
                    }
                }
                catch (AggregateException ex)
                {
                    MyDebug.AssertRelease(Task.IsFaulted);
                    MyDebug.AssertRelease(ex.InnerException != null);
                    ex.InnerException.Log();
                    return(Cleanup(4));
                }
                catch (Exception ex)
                {
                    ex.Log();
                    return(Cleanup(5));
                }

                // If the task reported any error, return exit code
                if (!Task.Result)
                {
                    return(Cleanup(-1));
                }
            }

            return(Cleanup());
        }