1using Microsoft.Xna.Framework.Audio;
2using Microsoft.Xna.Framework.Graphics;
5using System.Collections.Generic;
6using System.Diagnostics;
8using System.Linq.Expressions;
9using System.Reflection;
10using System.Security.Cryptography;
11using System.Threading;
12using System.Threading.Tasks;
13using System.Windows.Forms;
15using Terraria.Localization;
17using Terraria.ModLoader.Core;
18using Terraria.ModLoader.Default;
19using Terraria.ModLoader.Engine;
20using Terraria.ModLoader.UI;
38 public static readonly
int beta = 0;
41 public static readonly
string versionedName = $
"tModLoader v{version}" +
42 (branchName.Length == 0 ?
"" : $
" {branchName}") +
43 (
beta == 0 ?
"" : $
" Beta {beta}");
45 public static readonly
string versionTag = $
"v{version}" +
46 (branchName.Length == 0 ?
"" : $
"-{branchName.ToLower()}") +
47 (
beta == 0 ?
"" : $
"-beta{beta}");
49 [Obsolete(
"Use Platform.IsWindows")]
50 public static readonly
bool windows = Platform.IsWindows;
51 [Obsolete(
"Use Platform.IsLinux")]
52 public static readonly
bool linux = Platform.IsLinux;
53 [Obsolete(
"Use Platform.IsOSX")]
54 public static readonly
bool mac = Platform.IsOSX;
56 [Obsolete(
"Use CompressedPlatformRepresentation instead")]
61 public static string ModPath => ModOrganizer.modPath;
63 private static readonly IDictionary<string, Mod>
modsByName =
new Dictionary<string, Mod>(StringComparer.OrdinalIgnoreCase);
66 internal static readonly
string modBrowserPublicKey =
"<RSAKeyValue><Modulus>oCZObovrqLjlgTXY/BKy72dRZhoaA6nWRSGuA+aAIzlvtcxkBK5uKev3DZzIj0X51dE/qgRS3OHkcrukqvrdKdsuluu0JmQXCv+m7sDYjPQ0E6rN4nYQhgfRn2kfSvKYWGefp+kqmMF9xoAq666YNGVoERPm3j99vA+6EIwKaeqLB24MrNMO/TIf9ysb0SSxoV8pC/5P/N6ViIOk3adSnrgGbXnFkNQwD0qsgOWDks8jbYyrxUFMc4rFmZ8lZKhikVR+AisQtPGUs3ruVh4EWbiZGM2NOkhOCOM4k1hsdBOyX2gUliD0yjK5tiU3LBqkxoi2t342hWAkNNb4ZxLotw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
67 internal static string modBrowserPassphrase =
"";
70 internal static string SteamID64 {
71 get => InstallVerifier.IsGoG ?
steamID64 : Steamworks.SteamUser.GetSteamID().ToString();
75 internal static bool autoReloadAndEnableModsLeavingModBrowser =
true;
76 internal static bool dontRemindModBrowserUpdateReload;
77 internal static bool dontRemindModBrowserDownloadEnable;
78 internal static bool removeForcedMinimumZoom;
79 internal static bool showMemoryEstimates =
true;
81 internal static bool skipLoad;
83 internal static Action OnSuccessfulLoad;
85 public static Mod[]
Mods {
get;
private set; } =
new Mod[0];
96 public static Mod GetMod(
int index) => index >= 0 && index < Mods.Length ?
Mods[index] :
null;
98 [Obsolete(
"Use ModLoader.Mods",
true)]
101 [Obsolete(
"Use ModLoader.Mods.Length",
true)]
104 [Obsolete(
"Use ModLoader.Mods.Select(m => m.Name)",
true)]
107 internal static void EngineInit()
110 FileAssociationSupport.UpdateFileAssociation();
112 HiDefGraphicsIssues.Init();
114 ZipExtractFix.Init();
117 internal static void BeginLoad(CancellationToken token) => Task.Run(() =>
Load(token));
120 private static void Load(CancellationToken token =
default)
124 throw new Exception(
"Load called twice");
130 var modInstances = ModOrganizer.LoadMods(token);
133 modInstances.Insert(0,
new ModLoaderMod());
134 Mods = modInstances.ToArray();
135 foreach (var mod
in Mods)
140 if (OnSuccessfulLoad !=
null) {
147 catch when (token.IsCancellationRequested) {
150 OnSuccessfulLoad += () => Main.menuMode = Interface.modsMenuID;
156 var responsibleMods =
new List<string>();
157 if (e.Data.Contains(
"mod"))
158 responsibleMods.Add((
string)e.Data[
"mod"]);
159 if (e.Data.Contains(
"mods"))
161 responsibleMods.Remove(
"ModLoader");
163 if (responsibleMods.Count == 0 && AssemblyManager.FirstModInStackTrace(
new StackTrace(e), out var stackMod))
164 responsibleMods.Add(stackMod);
166 var msg = Language.GetTextValue(
"tModLoader.LoadError",
string.Join(
", ", responsibleMods));
167 if (responsibleMods.Count == 1) {
168 var mod = ModOrganizer.FindMods().FirstOrDefault(m => m.Name == responsibleMods[0]);
169 if (mod !=
null && (mod.tModLoaderVersion.Major !=
version.Major || mod.tModLoaderVersion.Minor !=
version.Minor || mod.tModLoaderVersion.Build !=
version.Build))
170 msg +=
"\n" + Language.GetTextValue(
"tModLoader.LoadErrorVersionMessage", mod.tModLoaderVersion,
versionedName);
172 if (responsibleMods.Count > 0)
173 msg +=
"\n" + Language.GetTextValue(
"tModLoader.LoadErrorDisabled");
175 msg +=
"\n" + Language.GetTextValue(
"tModLoader.LoadErrorCulpritUnknown");
177 if (e is ReflectionTypeLoadException reflectionTypeLoadException)
178 msg +=
"\n\n" +
string.Join(
"\n", reflectionTypeLoadException.LoaderExceptions.Select(x => x.Message));
182 foreach (var mod
in responsibleMods)
186 DisplayLoadError(msg, e, e.Data.Contains(
"fatal"), responsibleMods.Count == 0);
190 OnSuccessfulLoad =
null;
192 ModNet.NetReloadActive =
false;
201 var msg = Language.GetTextValue(
"tModLoader.LoadErrorDotNet45Required");
203 Interface.MessageBoxShow(msg);
204 Process.Start(
"https://dotnet.microsoft.com/download/dotnet-framework");
206 Console.ForegroundColor = ConsoleColor.Red;
209 Console.WriteLine(
"Press any key to exit...");
215 internal static void Reload()
220 Main.menuMode = Interface.loadModsID;
232 var msg = Language.GetTextValue(
"tModLoader.UnloadError");
234 if (e.Data.Contains(
"mod"))
235 msg +=
"\n" + Language.GetTextValue(
"tModLoader.DefensiveUnload", e.Data[
"mod"]);
246 Logging.tML.Info(
"Unloading mods");
248 Console.WriteLine(
"Unloading mods...");
251 Interface.loadMods.SetLoadStage(
"tModLoader.MSUnloading",
Mods.Length);
259 MemoryTracking.Clear();
260 Thread.MemoryBarrier();
264 internal static List<string> badUnloaders =
new List<string>();
267 badUnloaders =
weakModReferences.Where(r => r.IsAlive).Select(r => ((
Mod)r.Target).Name).ToList();
268 foreach (var modName
in badUnloaders)
269 Logging.tML.WarnFormat(
"{0} not fully unloaded during unload.", modName);
274 msg +=
"\n\n" + (e.Data.Contains(
"hideStackTrace") ? e.Message : e.ToString());
277 Console.ForegroundColor = ConsoleColor.Red;
282 Console.WriteLine(
"Press any key to exit...");
291 Interface.errorMessage.Show(msg,
292 gotoMenu: fatal ? -1 : Interface.reloadModsID,
293 webHelpURL: e.HelpLink,
294 continueIsRetry: continueIsRetry,
300 public static bool IsSignedBy(TmodFile mod,
string xmlPublicKey)
302 var f =
new RSAPKCS1SignatureDeformatter();
303 var v = AsymmetricAlgorithm.Create(
"RSA");
304 f.SetHashAlgorithm(
"SHA1");
305 v.FromXmlString(xmlPublicKey);
307 return f.VerifySignature(mod.hash, mod.signature);
312 internal static bool PauseSavingEnabledMods {
317 ModOrganizer.SaveEnabledMods();
327 internal static bool IsEnabled(
string modName) => EnabledMods.Contains(modName);
328 internal static void EnableMod(
string modName) => SetModEnabled(modName,
true);
329 internal static void DisableMod(
string modName) => SetModEnabled(modName,
false);
330 internal static void SetModEnabled(
string modName,
bool active)
333 EnabledMods.Add(modName);
334 Logging.tML.InfoFormat(
"Enabling Mod: {0}", modName);
337 EnabledMods.Remove(modName);
338 Logging.tML.InfoFormat(
"Disabling Mod: {0}", modName);
340 if (PauseSavingEnabledMods) {
344 ModOrganizer.SaveEnabledMods();
348 internal static void SaveConfiguration()
350 Main.Configuration.Put(
"ModBrowserPassphrase", modBrowserPassphrase);
351 Main.Configuration.Put(
"SteamID64",
steamID64);
352 Main.Configuration.Put(
"DownloadModsFromServers",
ModNet.downloadModsFromServers);
353 Main.Configuration.Put(
"OnlyDownloadSignedModsFromServers",
ModNet.onlyDownloadSignedMods);
354 Main.Configuration.Put(
"AutomaticallyReloadAndEnableModsLeavingModBrowser", autoReloadAndEnableModsLeavingModBrowser);
355 Main.Configuration.Put(
"DontRemindModBrowserUpdateReload", dontRemindModBrowserUpdateReload);
356 Main.Configuration.Put(
"DontRemindModBrowserDownloadEnable", dontRemindModBrowserDownloadEnable);
357 Main.Configuration.Put(
"RemoveForcedMinimumZoom", removeForcedMinimumZoom);
358 Main.Configuration.Put(
"ShowMemoryEstimates", showMemoryEstimates);
359 Main.Configuration.Put(
"AvoidGithub", UI.ModBrowser.UIModBrowser.AvoidGithub);
360 Main.Configuration.Put(
"AvoidImgur", UI.ModBrowser.UIModBrowser.AvoidImgur);
361 Main.Configuration.Put(nameof(UI.ModBrowser.UIModBrowser.EarlyAutoUpdate), UI.ModBrowser.UIModBrowser.EarlyAutoUpdate);
362 Main.Configuration.Put(
"LastLaunchedTModLoaderVersion",
version.ToString());
365 internal static void LoadConfiguration()
367 Main.Configuration.Get(
"ModBrowserPassphrase", ref modBrowserPassphrase);
368 Main.Configuration.Get(
"SteamID64", ref
steamID64);
369 Main.Configuration.Get(
"DownloadModsFromServers", ref
ModNet.downloadModsFromServers);
370 Main.Configuration.Get(
"OnlyDownloadSignedModsFromServers", ref
ModNet.onlyDownloadSignedMods);
371 Main.Configuration.Get(
"AutomaticallyReloadAndEnableModsLeavingModBrowser", ref autoReloadAndEnableModsLeavingModBrowser);
372 Main.Configuration.Get(
"DontRemindModBrowserUpdateReload", ref dontRemindModBrowserUpdateReload);
373 Main.Configuration.Get(
"DontRemindModBrowserDownloadEnable", ref dontRemindModBrowserDownloadEnable);
374 Main.Configuration.Get(
"RemoveForcedMinimumZoom", ref removeForcedMinimumZoom);
375 Main.Configuration.Get(
"ShowMemoryEstimates", ref showMemoryEstimates);
376 Main.Configuration.Get(
"AvoidGithub", ref UI.ModBrowser.UIModBrowser.AvoidGithub);
377 Main.Configuration.Get(
"AvoidImgur", ref UI.ModBrowser.UIModBrowser.AvoidImgur);
378 Main.Configuration.Get(nameof(UI.ModBrowser.UIModBrowser.EarlyAutoUpdate), ref UI.ModBrowser.UIModBrowser.EarlyAutoUpdate);
382 internal static void MigrateSettings()
385 showMemoryEstimates =
true;
397 internal static void BuildGlobalHook<T, F>(ref F[] list, IList<T> providers, Expression<Func<T, F>> expr)
399 list = BuildGlobalHook(providers, expr).Select(expr.Compile()).ToArray();
402 internal static T[] BuildGlobalHook<T, F>(IList<T> providers, Expression<Func<T, F>> expr)
404 return BuildGlobalHook(providers, Method(expr));
407 internal static T[] BuildGlobalHook<T>(IList<T> providers, MethodInfo method)
409 if (!method.IsVirtual)
throw new ArgumentException(
"Cannot build hook for non-virtual method " + method);
410 var argTypes = method.GetParameters().Select(p => p.ParameterType).ToArray();
411 return providers.Where(p => p.GetType().GetMethod(method.Name, argTypes).DeclaringType != typeof(T)).ToArray();
414 internal static MethodInfo Method<T, F>(Expression<Func<T, F>> expr)
418 var convert = expr.Body as UnaryExpression;
419 var makeDelegate = convert.Operand as MethodCallExpression;
420 var methodArg = makeDelegate.Object as ConstantExpression;
421 method = methodArg.Value as MethodInfo;
422 if (method ==
null)
throw new NullReferenceException();
425 throw new ArgumentException(
"Invalid hook expression " + expr, e);
433 [Obsolete(
"ModLoader.GetFileBytes is deprecated since v0.11, use ModContent.GetFileBytes instead.",
true)]
436 [Obsolete(
"ModLoader.FileExists is deprecated since v0.11, use ModContent.FileExists instead.",
true)]
439 [Obsolete(
"ModLoader.GetTexture is deprecated since v0.11, use ModContent.GetTexture instead.",
true)]
442 [Obsolete(
"ModLoader.TextureExists is deprecated since v0.11, use ModContent.TextureExists instead.",
true)]
445 [Obsolete(
"ModLoader.GetSound is deprecated since v0.11, use ModContent.GetSound instead.",
true)]
448 [Obsolete(
"ModLoader.SoundExists is deprecated since v0.1, use ModContent.SoundExists instead.",
true)]
451 [Obsolete(
"ModLoader.GetMusic is deprecated since v0.11, use ModContent.GetMusic instead.",
true)]
454 [Obsolete(
"ModLoader.MusicExists is deprecated since v0.11, use ModContent.MusicExists instead.",
true)]
static readonly Version Version
static readonly Framework Framework
Manages content added by mods. Liasons between mod content and Terraria's arrays and oversees the Loa...
static bool TextureExists(string name)
Returns whether or not a texture with the specified name exists.
static bool FileExists(string name)
Returns whether or not a file with the specified name exists.
static SoundEffect GetSound(string name)
Gets the sound with the specified name. The name is in the same format as for texture names....
static Music GetMusic(string name)
Gets the music with the specified name. The name is in the same format as for texture names....
static Texture2D GetTexture(string name)
Gets the texture with the specified name. The name is in the format of "ModFolder/OtherFolders/FileNa...
static bool SoundExists(string name)
Returns whether or not a sound with the specified name exists.
static bool MusicExists(string name)
Returns whether or not a sound with the specified name exists.
static byte[] GetFileBytes(string name)
Gets the byte representation of the file with the specified name. The name is in the format of "ModFo...
Mod is an abstract class that you will override. It serves as a central place from which the mod's co...
This serves as the central class which loads mods. It contains many static fields and methods related...
static readonly IDictionary< string, Mod > modsByName
static readonly Version version
static bool SoundExists(string name)
static void Load(CancellationToken token=default)
static string CompressedPlatformRepresentation
static Music GetMusic(string name)
static void DisplayLoadError(string msg, Exception e, bool fatal, bool continueIsRetry=false)
static bool TextureExists(string name)
static SoundEffect GetSound(string name)
static readonly bool linux
static Mod GetMod(int index)
static void DotNet45Check()
static HashSet< string > _enabledMods
A cached list of enabled mods (not necessarily currently loaded or even installed),...
static byte[] GetFileBytes(string name)
static Texture2D GetTexture(string name)
static bool _pauseSavingEnabledMods
static string[] GetLoadedMods()
static readonly bool windows
static readonly string compressedPlatformRepresentation
static bool MusicExists(string name)
static bool _needsSavingEnabledMods
static Version LastLaunchedTModLoaderVersion
static readonly string versionedName
static bool ShowFirstLaunchWelcomeMessage
static void WarnModsStillLoaded()
static WeakReference[] weakModReferences
static readonly string versionTag
static bool FileExists(string name)
static Mod GetMod(string name)
Gets the instance of the Mod with the specified name.
static bool IsSignedBy(TmodFile mod, string xmlPublicKey)
static readonly string branchName
@ Environment
Sandstorm, Hell, Above surface during Eclipse, Space
@ Console
Command can be used in server console during MP.