/// <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); }
// 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(); }
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 }
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()); }