diff --git a/.gitignore b/.gitignore
index 2a2b1d90..faafeb70 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
## files generated by popular Visual Studio add-ons.
PrePatcher/Output
+PostPatcher/Output
# User-specific files
*.suo
diff --git a/Assembly-CSharp/Assembly-CSharp.csproj b/Assembly-CSharp/Assembly-CSharp.csproj
index 337c16c9..0add8292 100644
--- a/Assembly-CSharp/Assembly-CSharp.csproj
+++ b/Assembly-CSharp/Assembly-CSharp.csproj
@@ -10,14 +10,14 @@
true
packages
latest
+ true
-
-
+
@@ -30,8 +30,8 @@
C:/Program Files (x86)/Steam/steamapps/common/Hollow Knight
$(HOME)/.local/share/Steam/steamapps/common/Hollow Knight
- $(GamePath)/hollow_knight_Data/Managed
-
+ $(GamePath)/hollow_knight_Data/Managed
+
mono
@@ -41,12 +41,23 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -58,13 +69,13 @@
-
+
-
+
-
+
@@ -72,16 +83,14 @@
-
+
-
-
-
+
-
+
-
+
.dll
@@ -95,14 +104,14 @@
-
+
-
+
full
bin\$(Configuration)\Assembly-CSharp.mm.xml
@@ -120,20 +129,23 @@
all
-
+
all
-
+
-
+
false
+
+ false
+
-
+
@@ -141,64 +153,16 @@
-
- ../Vanilla/Assembly-CSharp.dll
- False
-
-
- ..\override\mscorlib.dll
-
-
- ../Vanilla/netstandard.dll
-
-
- ../JsonNet/Newtonsoft.Json.dll
-
-
- ../Vanilla/PlayMaker.dll
- False
-
-
- ../Vanilla/UnityEngine.dll
-
-
- ../Vanilla/UnityEngine.AnimationModule.dll
-
-
- ../Vanilla/UnityEngine.AssetBundleModule.dll
-
-
- ../Vanilla/UnityEngine.AudioModule.dll
-
-
- ../Vanilla/UnityEngine.CoreModule.dll
-
-
- ../Vanilla/UnityEngine.ImageConversionModule.dll
-
-
- ../Vanilla/UnityEngine.IMGUIModule.dll
-
-
- ../Vanilla/UnityEngine.InputLegacyModule.dll
-
-
- ../Vanilla/UnityEngine.JSONSerializeModule.dll
-
-
- ../Vanilla/UnityEngine.ParticleSystemModule.dll
-
-
- ../Vanilla/UnityEngine.Physics2DModule.dll
-
-
- ../Vanilla/UnityEngine.TextRenderingModule.dll
-
-
- ../Vanilla/UnityEngine.UI.dll
-
-
- ../Vanilla/UnityEngine.UIModule.dll
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Assembly-CSharp/Console.cs b/Assembly-CSharp/Console.cs
index d9fb51a4..a29911f8 100644
--- a/Assembly-CSharp/Console.cs
+++ b/Assembly-CSharp/Console.cs
@@ -76,7 +76,8 @@ public void Start()
string.Join(string.Empty, _messages.ToArray()),
_fontSize,
TextAnchor.LowerLeft,
- new CanvasUtil.RectData(new Vector2(-5, -5), Vector2.zero, Vector2.zero, Vector2.one),
+ //new CanvasUtil.RectData(new Vector2(-5, -5), Vector2.zero, Vector2.zero, Vector2.one),
+ new CanvasUtil.RectData(Vector2.zero, Vector2.zero, Vector2.zero, Vector2.one),
_font
);
diff --git a/Assembly-CSharp/Language/Language.cs b/Assembly-CSharp/Language/Language.cs
new file mode 100644
index 00000000..bf80b6ab
--- /dev/null
+++ b/Assembly-CSharp/Language/Language.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using UObject = UnityEngine.Object;
+using USystemLanguage = UnityEngine.SystemLanguage;
+
+namespace Language;
+
+[Obsolete("Use `TeamCherry.Localization.Language` instead.")]
+public static class Language
+{
+ public static void LoadLanguage() => COMPAT_LoadLanguage();
+ public static void LoadAvailableLanguages() => COMPAT_LoadAvailableLanguages();
+ public static string[] GetLanguages() => COMPAT_GetLanguages();
+ public static bool SwitchLanguage(string langCode) => COMPAT_SwitchLanguage(langCode);
+ public static bool SwitchLanguage(LanguageCode code) => COMPAT_SwitchLanguage((TeamCherry.Localization.LanguageCode) code);
+ public static UObject GetAsset(string name) => COMPAT_GetAsset(name);
+ public static LanguageCode CurrentLanguage() => (LanguageCode) COMPAT_CurrentLanguage();
+ public static string Get(string key) => COMPAT_Get(key);
+ public static IEnumerable GetSheets() => COMPAT_GetSheets();
+ public static IEnumerable GetKeys(string sheetTitle) => COMPAT_GetKeys(sheetTitle);
+ public static bool Has(string key) => COMPAT_Has(key);
+ public static bool Has(string key, string sheet) => COMPAT_Has(key, sheet);
+ public static bool HasSheet(string sheet) => COMPAT_HasSheet(sheet);
+ public static LanguageCode LanguageNameToCode(USystemLanguage name) => (LanguageCode) COMPAT_LanguageNameToCode(name);
+ public static string GetInternal(string key, string sheetTitle) => COMPAT_Get(key, sheetTitle);
+ [MonoMod.MonoModLinkFrom("System.String TeamCherry.Localization.Language::Get(System.String,System.String)")]
+ public static string Get(string key, string sheetTitle) => Modding.ModHooks.LanguageGet(key, sheetTitle);
+
+ private static void DoSwitch(LanguageCode newLang) => COMPAT_DoSwitch((TeamCherry.Localization.LanguageCode) newLang);
+ private static bool HasLanguageFile(string lang, string sheetTitle) => COMPAT_HasLanguageFile(lang, sheetTitle);
+ private static string GetLanguageFileContents(string sheetTitle) => COMPAT_GetLanguageFileContents(sheetTitle);
+
+ // Keep these below the `[MonoMod.MonoModLinkFrom("TeamCherry.Localization.Language")]`, as the reverse order would cause a cyclic loop of methods calling themselves
+ // thanks to MonoMod resolving these links top-down
+ // which would make a `LinkTo(TCLL)->LinkFrom(TCLL)` into a fully recursive function ⟳
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Void LoadLanguage()")]
+ [MonoMod.MonoModRemove]
+ extern private static void COMPAT_LoadLanguage();
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Void LoadAvailableLanguages()")]
+ [MonoMod.MonoModRemove]
+ extern private static void COMPAT_LoadAvailableLanguages();
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String[] GetLanguages()")]
+ [MonoMod.MonoModRemove]
+ extern private static string[] COMPAT_GetLanguages();
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean SwitchLanguage(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static bool COMPAT_SwitchLanguage(string langCode);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean SwitchLanguage(TeamCherry.Localization.LanguageCode)")]
+ [MonoMod.MonoModRemove]
+ extern private static bool COMPAT_SwitchLanguage(TeamCherry.Localization.LanguageCode code);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "UnityEngine.Object GetAsset(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static UObject COMPAT_GetAsset(string name);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "TeamCherry.Localization.LanguageCode CurrentLanguage()")]
+ [MonoMod.MonoModRemove]
+ extern private static TeamCherry.Localization.LanguageCode COMPAT_CurrentLanguage();
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String Get(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static string COMPAT_Get(string key);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String Get(System.String,System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static string COMPAT_Get(string key, string sheetTitle);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Collections.Generic.IEnumerable`1 GetSheets()")]
+ [MonoMod.MonoModRemove]
+ extern private static IEnumerable COMPAT_GetSheets();
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Collections.Generic.IEnumerable`1 GetKeys(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static IEnumerable COMPAT_GetKeys(string sheetTitle);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean Has(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static bool COMPAT_Has(string key);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean Has(System.String,System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static bool COMPAT_Has(string key, string sheet);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean HasSheet(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static bool COMPAT_HasSheet(string sheet);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "TeamCherry.Localization.LanguageCode LanguageNameToCode(UnityEngine.SystemLanguage)")]
+ [MonoMod.MonoModRemove]
+ extern private static TeamCherry.Localization.LanguageCode COMPAT_LanguageNameToCode(USystemLanguage name);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Void DoSwitch(TeamCherry.Localization.LanguageCode)")]
+ [MonoMod.MonoModRemove]
+ extern private static void COMPAT_DoSwitch(TeamCherry.Localization.LanguageCode name);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.Boolean HasLanguageFile(System.String,System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static bool COMPAT_HasLanguageFile(string lang, string sheetTitle);
+ [MonoMod.MonoModLinkTo("TeamCherry.Localization.Language", "System.String GetLanguageFileContents(System.String)")]
+ [MonoMod.MonoModRemove]
+ extern private static string COMPAT_GetLanguageFileContents(string sheetTitle);
+}
\ No newline at end of file
diff --git a/Assembly-CSharp/Language/LanguageCode.cs b/Assembly-CSharp/Language/LanguageCode.cs
new file mode 100644
index 00000000..5f3fce38
--- /dev/null
+++ b/Assembly-CSharp/Language/LanguageCode.cs
@@ -0,0 +1,211 @@
+namespace Language;
+
+// for backwards compatibility
+public enum LanguageCode
+{
+ N = TeamCherry.Localization.LanguageCode.N,
+ AA = TeamCherry.Localization.LanguageCode.AA,
+ AB = TeamCherry.Localization.LanguageCode.AB,
+ AF = TeamCherry.Localization.LanguageCode.AF,
+ AM = TeamCherry.Localization.LanguageCode.AM,
+ AR = TeamCherry.Localization.LanguageCode.AR,
+ AR_SA = TeamCherry.Localization.LanguageCode.AR_SA,
+ AR_EG = TeamCherry.Localization.LanguageCode.AR_EG,
+ AR_DZ = TeamCherry.Localization.LanguageCode.AR_DZ,
+ AR_YE = TeamCherry.Localization.LanguageCode.AR_YE,
+ AR_JO = TeamCherry.Localization.LanguageCode.AR_JO,
+ AR_KW = TeamCherry.Localization.LanguageCode.AR_KW,
+ AR_BH = TeamCherry.Localization.LanguageCode.AR_BH,
+ AR_IQ = TeamCherry.Localization.LanguageCode.AR_IQ,
+ AR_MA = TeamCherry.Localization.LanguageCode.AR_MA,
+ AR_LY = TeamCherry.Localization.LanguageCode.AR_LY,
+ AR_OM = TeamCherry.Localization.LanguageCode.AR_OM,
+ AR_SY = TeamCherry.Localization.LanguageCode.AR_SY,
+ AR_LB = TeamCherry.Localization.LanguageCode.AR_LB,
+ AR_AE = TeamCherry.Localization.LanguageCode.AR_AE,
+ AR_QA = TeamCherry.Localization.LanguageCode.AR_QA,
+ AS = TeamCherry.Localization.LanguageCode.AS,
+ AY = TeamCherry.Localization.LanguageCode.AY,
+ AZ = TeamCherry.Localization.LanguageCode.AZ,
+ BA = TeamCherry.Localization.LanguageCode.BA,
+ BE = TeamCherry.Localization.LanguageCode.BE,
+ BG = TeamCherry.Localization.LanguageCode.BG,
+ BH = TeamCherry.Localization.LanguageCode.BH,
+ BI = TeamCherry.Localization.LanguageCode.BI,
+ BN = TeamCherry.Localization.LanguageCode.BN,
+ BO = TeamCherry.Localization.LanguageCode.BO,
+ BR = TeamCherry.Localization.LanguageCode.BR,
+ CA = TeamCherry.Localization.LanguageCode.CA,
+ CO = TeamCherry.Localization.LanguageCode.CO,
+ CS = TeamCherry.Localization.LanguageCode.CS,
+ CY = TeamCherry.Localization.LanguageCode.CY,
+ DA = TeamCherry.Localization.LanguageCode.DA,
+ DE = TeamCherry.Localization.LanguageCode.DE,
+ DE_AT = TeamCherry.Localization.LanguageCode.DE_AT,
+ DE_LI = TeamCherry.Localization.LanguageCode.DE_LI,
+ DE_CH = TeamCherry.Localization.LanguageCode.DE_CH,
+ DE_LU = TeamCherry.Localization.LanguageCode.DE_LU,
+ DZ = TeamCherry.Localization.LanguageCode.DZ,
+ EL = TeamCherry.Localization.LanguageCode.EL,
+ EN = TeamCherry.Localization.LanguageCode.EN,
+ EN_US = TeamCherry.Localization.LanguageCode.EN_US,
+ EN_AU = TeamCherry.Localization.LanguageCode.EN_AU,
+ EN_NZ = TeamCherry.Localization.LanguageCode.EN_NZ,
+ EN_ZA = TeamCherry.Localization.LanguageCode.EN_ZA,
+ EN_CB = TeamCherry.Localization.LanguageCode.EN_CB,
+ EN_TT = TeamCherry.Localization.LanguageCode.EN_TT,
+ EN_GB = TeamCherry.Localization.LanguageCode.EN_GB,
+ EN_CA = TeamCherry.Localization.LanguageCode.EN_CA,
+ EN_IE = TeamCherry.Localization.LanguageCode.EN_IE,
+ EN_JM = TeamCherry.Localization.LanguageCode.EN_JM,
+ EN_BZ = TeamCherry.Localization.LanguageCode.EN_BZ,
+ EO = TeamCherry.Localization.LanguageCode.EO,
+ ES = TeamCherry.Localization.LanguageCode.ES,
+ ES_MX = TeamCherry.Localization.LanguageCode.ES_MX,
+ ES_CR = TeamCherry.Localization.LanguageCode.ES_CR,
+ ES_DO = TeamCherry.Localization.LanguageCode.ES_DO,
+ ES_CO = TeamCherry.Localization.LanguageCode.ES_CO,
+ ES_AR = TeamCherry.Localization.LanguageCode.ES_AR,
+ ES_CL = TeamCherry.Localization.LanguageCode.ES_CL,
+ ES_PY = TeamCherry.Localization.LanguageCode.ES_PY,
+ ES_SV = TeamCherry.Localization.LanguageCode.ES_SV,
+ ES_NI = TeamCherry.Localization.LanguageCode.ES_NI,
+ ES_GT = TeamCherry.Localization.LanguageCode.ES_GT,
+ ES_PA = TeamCherry.Localization.LanguageCode.ES_PA,
+ ES_VE = TeamCherry.Localization.LanguageCode.ES_VE,
+ ES_PE = TeamCherry.Localization.LanguageCode.ES_PE,
+ ES_EC = TeamCherry.Localization.LanguageCode.ES_EC,
+ ES_UY = TeamCherry.Localization.LanguageCode.ES_UY,
+ ES_BO = TeamCherry.Localization.LanguageCode.ES_BO,
+ ES_HN = TeamCherry.Localization.LanguageCode.ES_HN,
+ ES_PR = TeamCherry.Localization.LanguageCode.ES_PR,
+ ET = TeamCherry.Localization.LanguageCode.ET,
+ EU = TeamCherry.Localization.LanguageCode.EU,
+ FA = TeamCherry.Localization.LanguageCode.FA,
+ FI = TeamCherry.Localization.LanguageCode.FI,
+ FJ = TeamCherry.Localization.LanguageCode.FJ,
+ FO = TeamCherry.Localization.LanguageCode.FO,
+ FR = TeamCherry.Localization.LanguageCode.FR,
+ FR_BE = TeamCherry.Localization.LanguageCode.FR_BE,
+ FR_CH = TeamCherry.Localization.LanguageCode.FR_CH,
+ FR_CA = TeamCherry.Localization.LanguageCode.FR_CA,
+ FR_LU = TeamCherry.Localization.LanguageCode.FR_LU,
+ FY = TeamCherry.Localization.LanguageCode.FY,
+ GA = TeamCherry.Localization.LanguageCode.GA,
+ GD = TeamCherry.Localization.LanguageCode.GD,
+ GL = TeamCherry.Localization.LanguageCode.GL,
+ GN = TeamCherry.Localization.LanguageCode.GN,
+ GU = TeamCherry.Localization.LanguageCode.GU,
+ HA = TeamCherry.Localization.LanguageCode.HA,
+ HI = TeamCherry.Localization.LanguageCode.HI,
+ HE = TeamCherry.Localization.LanguageCode.HE,
+ HR = TeamCherry.Localization.LanguageCode.HR,
+ HU = TeamCherry.Localization.LanguageCode.HU,
+ HY = TeamCherry.Localization.LanguageCode.HY,
+ IA = TeamCherry.Localization.LanguageCode.IA,
+ ID = TeamCherry.Localization.LanguageCode.ID,
+ IE = TeamCherry.Localization.LanguageCode.IE,
+ IK = TeamCherry.Localization.LanguageCode.IK,
+ IN = TeamCherry.Localization.LanguageCode.IN,
+ IS = TeamCherry.Localization.LanguageCode.IS,
+ IT = TeamCherry.Localization.LanguageCode.IT,
+ IT_CH = TeamCherry.Localization.LanguageCode.IT_CH,
+ IU = TeamCherry.Localization.LanguageCode.IU,
+ IW = TeamCherry.Localization.LanguageCode.IW,
+ JA = TeamCherry.Localization.LanguageCode.JA,
+ JI = TeamCherry.Localization.LanguageCode.JI,
+ JW = TeamCherry.Localization.LanguageCode.JW,
+ KA = TeamCherry.Localization.LanguageCode.KA,
+ KK = TeamCherry.Localization.LanguageCode.KK,
+ KL = TeamCherry.Localization.LanguageCode.KL,
+ KM = TeamCherry.Localization.LanguageCode.KM,
+ KN = TeamCherry.Localization.LanguageCode.KN,
+ KO = TeamCherry.Localization.LanguageCode.KO,
+ KS = TeamCherry.Localization.LanguageCode.KS,
+ KU = TeamCherry.Localization.LanguageCode.KU,
+ KY = TeamCherry.Localization.LanguageCode.KY,
+ LA = TeamCherry.Localization.LanguageCode.LA,
+ LN = TeamCherry.Localization.LanguageCode.LN,
+ LO = TeamCherry.Localization.LanguageCode.LO,
+ LT = TeamCherry.Localization.LanguageCode.LT,
+ LV = TeamCherry.Localization.LanguageCode.LV,
+ MG = TeamCherry.Localization.LanguageCode.MG,
+ MI = TeamCherry.Localization.LanguageCode.MI,
+ MK = TeamCherry.Localization.LanguageCode.MK,
+ ML = TeamCherry.Localization.LanguageCode.ML,
+ MN = TeamCherry.Localization.LanguageCode.MN,
+ MO = TeamCherry.Localization.LanguageCode.MO,
+ MR = TeamCherry.Localization.LanguageCode.MR,
+ MS = TeamCherry.Localization.LanguageCode.MS,
+ MT = TeamCherry.Localization.LanguageCode.MT,
+ MY = TeamCherry.Localization.LanguageCode.MY,
+ NA = TeamCherry.Localization.LanguageCode.NA,
+ NE = TeamCherry.Localization.LanguageCode.NE,
+ NL = TeamCherry.Localization.LanguageCode.NL,
+ NL_BE = TeamCherry.Localization.LanguageCode.NL_BE,
+ NO = TeamCherry.Localization.LanguageCode.NO,
+ OC = TeamCherry.Localization.LanguageCode.OC,
+ OM = TeamCherry.Localization.LanguageCode.OM,
+ OR = TeamCherry.Localization.LanguageCode.OR,
+ PA = TeamCherry.Localization.LanguageCode.PA,
+ PL = TeamCherry.Localization.LanguageCode.PL,
+ PS = TeamCherry.Localization.LanguageCode.PS,
+ PT = TeamCherry.Localization.LanguageCode.PT,
+ PT_BR = TeamCherry.Localization.LanguageCode.PT_BR,
+ QU = TeamCherry.Localization.LanguageCode.QU,
+ RM = TeamCherry.Localization.LanguageCode.RM,
+ RN = TeamCherry.Localization.LanguageCode.RN,
+ RO = TeamCherry.Localization.LanguageCode.RO,
+ RO_MO = TeamCherry.Localization.LanguageCode.RO_MO,
+ RU = TeamCherry.Localization.LanguageCode.RU,
+ RU_MO = TeamCherry.Localization.LanguageCode.RU_MO,
+ RW = TeamCherry.Localization.LanguageCode.RW,
+ SA = TeamCherry.Localization.LanguageCode.SA,
+ SD = TeamCherry.Localization.LanguageCode.SD,
+ SG = TeamCherry.Localization.LanguageCode.SG,
+ SH = TeamCherry.Localization.LanguageCode.SH,
+ SI = TeamCherry.Localization.LanguageCode.SI,
+ SK = TeamCherry.Localization.LanguageCode.SK,
+ SL = TeamCherry.Localization.LanguageCode.SL,
+ SM = TeamCherry.Localization.LanguageCode.SM,
+ SN = TeamCherry.Localization.LanguageCode.SN,
+ SO = TeamCherry.Localization.LanguageCode.SO,
+ SQ = TeamCherry.Localization.LanguageCode.SQ,
+ SR = TeamCherry.Localization.LanguageCode.SR,
+ SS = TeamCherry.Localization.LanguageCode.SS,
+ ST = TeamCherry.Localization.LanguageCode.ST,
+ SU = TeamCherry.Localization.LanguageCode.SU,
+ SV = TeamCherry.Localization.LanguageCode.SV,
+ SV_FI = TeamCherry.Localization.LanguageCode.SV_FI,
+ SW = TeamCherry.Localization.LanguageCode.SW,
+ TA = TeamCherry.Localization.LanguageCode.TA,
+ TE = TeamCherry.Localization.LanguageCode.TE,
+ TG = TeamCherry.Localization.LanguageCode.TG,
+ TH = TeamCherry.Localization.LanguageCode.TH,
+ TI = TeamCherry.Localization.LanguageCode.TI,
+ TK = TeamCherry.Localization.LanguageCode.TK,
+ TL = TeamCherry.Localization.LanguageCode.TL,
+ TN = TeamCherry.Localization.LanguageCode.TN,
+ TO = TeamCherry.Localization.LanguageCode.TO,
+ TR = TeamCherry.Localization.LanguageCode.TR,
+ TS = TeamCherry.Localization.LanguageCode.TS,
+ TT = TeamCherry.Localization.LanguageCode.TT,
+ TW = TeamCherry.Localization.LanguageCode.TW,
+ UG = TeamCherry.Localization.LanguageCode.UG,
+ UK = TeamCherry.Localization.LanguageCode.UK,
+ UR = TeamCherry.Localization.LanguageCode.UR,
+ UZ = TeamCherry.Localization.LanguageCode.UZ,
+ VI = TeamCherry.Localization.LanguageCode.VI,
+ VO = TeamCherry.Localization.LanguageCode.VO,
+ WO = TeamCherry.Localization.LanguageCode.WO,
+ XH = TeamCherry.Localization.LanguageCode.XH,
+ YI = TeamCherry.Localization.LanguageCode.YI,
+ YO = TeamCherry.Localization.LanguageCode.YO,
+ ZA = TeamCherry.Localization.LanguageCode.ZA,
+ ZH = TeamCherry.Localization.LanguageCode.ZH,
+ ZH_TW = TeamCherry.Localization.LanguageCode.ZH_TW,
+ ZH_HK = TeamCherry.Localization.LanguageCode.ZH_HK,
+ ZH_CN = TeamCherry.Localization.LanguageCode.ZH_CN,
+ ZH_SG = TeamCherry.Localization.LanguageCode.ZH_SG,
+ ZU = TeamCherry.Localization.LanguageCode.ZU,
+}
\ No newline at end of file
diff --git a/Assembly-CSharp/Mod.cs b/Assembly-CSharp/Mod.cs
index 3e476940..217698d8 100644
--- a/Assembly-CSharp/Mod.cs
+++ b/Assembly-CSharp/Mod.cs
@@ -10,6 +10,7 @@
using MonoMod.Utils;
using System.Linq;
using Newtonsoft.Json.Linq;
+using Lang = Language.Language;
// ReSharper disable file UnusedMember.Global
@@ -188,7 +189,7 @@ public virtual void Initialize() { }
/// change the text of the button to jump to this mod's menu.
///
///
- public virtual string GetMenuButtonText() => $"{GetName()} {Language.Language.Get("MAIN_OPTIONS", "MainMenu")}";
+ public virtual string GetMenuButtonText() => $"{GetName()} {Lang.Get("MAIN_OPTIONS", "MainMenu")}";
private void HookSaveMethods()
{
diff --git a/Assembly-CSharp/ModHooks.cs b/Assembly-CSharp/ModHooks.cs
index 1ba7815f..88b303aa 100644
--- a/Assembly-CSharp/ModHooks.cs
+++ b/Assembly-CSharp/ModHooks.cs
@@ -12,6 +12,7 @@
using System.Linq;
using Modding.Delegates;
using Object = UnityEngine.Object;
+using Lang = Language.Language;
// ReSharper disable PossibleInvalidCastExceptionInForeachLoop
// ReSharper disable SuggestVarOrType_SimpleTypes
@@ -61,10 +62,10 @@ static ModHooks()
{
string[] versionNums = Constants.GAME_VERSION.Split('.');
- gameVersion.major = Convert.ToInt32(versionNums[0]);
- gameVersion.minor = Convert.ToInt32(versionNums[1]);
- gameVersion.revision = Convert.ToInt32(versionNums[2]);
- gameVersion.package = Convert.ToInt32(versionNums[3]);
+ gameVersion.major = versionNums.Length > 0 ? Convert.ToInt32(versionNums[0]) : 0;
+ gameVersion.minor = versionNums.Length > 1 ? Convert.ToInt32(versionNums[1]) : 0;
+ gameVersion.revision = versionNums.Length > 2 ? Convert.ToInt32(versionNums[2]) : 0;
+ gameVersion.package = versionNums.Length > 3 ? Convert.ToInt32(versionNums[3]) : 0;
}
catch (Exception e)
{
@@ -225,7 +226,7 @@ internal static void LogConsole(string message, LogLevel level)
/// N/A
internal static string LanguageGet(string key, string sheet)
{
- string res = Patches.Language.GetInternal(key, sheet);
+ string res = Lang.GetInternal(key, sheet);
if (LanguageGetHook == null)
return res;
diff --git a/Assembly-CSharp/Patches/Attributes/IEnumeratorIlPatch.cs b/Assembly-CSharp/Patches/Attributes/IEnumeratorIlPatch.cs
new file mode 100644
index 00000000..ee204c50
--- /dev/null
+++ b/Assembly-CSharp/Patches/Attributes/IEnumeratorIlPatch.cs
@@ -0,0 +1,68 @@
+using System;
+using System.Linq;
+using System.Reflection;
+using JetBrains.Annotations;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using MonoMod;
+using MonoMod.Cil;
+using MonoMod.Utils;
+
+namespace Modding.Patches.Attributes
+{
+ ///
+ ///
+ /// MonoMod attribute for patching a method directly with IL
+ ///
+ [UsedImplicitly]
+ [MonoModCustomAttribute("IEnumeratorIlPatch")]
+ public class IEnumeratorIlPatch : Attribute
+ {
+ ///
+ ///
+ /// Patches a method directly with IL
+ ///
+ /// Method name that does the IL patch
+ public IEnumeratorIlPatch(string patcherMethod) { }
+ }
+}
+
+namespace MonoMod
+{
+ public static partial class MonoModRules
+ {
+ ///
+ /// Remove op
+ ///
+ /// Method to be patched
+ /// Attribute
+ [UsedImplicitly]
+ public static void IEnumeratorIlPatch(MethodDefinition method, CustomAttribute attrib)
+ {
+ CustomAttribute iteratorAttribute = method.CustomAttributes.First
+ (x => x.AttributeType.FullName == "System.Runtime.CompilerServices.IteratorStateMachineAttribute");
+ TypeReference stateMachineTypeRef = (TypeReference)iteratorAttribute.ConstructorArguments[0].Value;
+ TypeDefinition stateMachineTypeDef = stateMachineTypeRef.Resolve();
+ MethodDefinition stateMachineMoveNext = stateMachineTypeDef.Methods.First(m => m.Name == "MoveNext");
+ var context = new ILContext(stateMachineMoveNext);
+
+ string patcherTypeName = $"Modding.Patches.{nameof(Modding.Patches.IlPatches)}, Assembly-CSharp.mm";
+ string patcherMethodName = (string)attrib.ConstructorArguments[0].Value;
+
+ Type patcherType = Type.GetType(patcherTypeName);
+
+ if (patcherType is null)
+ throw new InvalidOperationException("Couldn't find patcher type!");
+
+ MethodBase patcherMethod = patcherType?.GetMethod(patcherMethodName, AllBindingFlags/*, null, [typeof(ILContext)], null*/);
+
+ if (patcherMethod is null)
+ throw new InvalidOperationException("Couldn't find patcher method!");
+
+ context.Invoke(delegate(ILContext ctx)
+ {
+ patcherMethod.Invoke(null, [ctx, stateMachineTypeDef]);
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/MonoModRules.cs b/Assembly-CSharp/Patches/Attributes/MonoModRules.cs
similarity index 100%
rename from Assembly-CSharp/Patches/MonoModRules.cs
rename to Assembly-CSharp/Patches/Attributes/MonoModRules.cs
diff --git a/Assembly-CSharp/Patches/Attributes/RawIlPatch.cs b/Assembly-CSharp/Patches/Attributes/RawIlPatch.cs
new file mode 100644
index 00000000..da34d26a
--- /dev/null
+++ b/Assembly-CSharp/Patches/Attributes/RawIlPatch.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Reflection;
+using JetBrains.Annotations;
+using Mono.Cecil;
+using MonoMod;
+using MonoMod.Cil;
+using MonoMod.Utils;
+
+namespace Modding.Patches.Attributes
+{
+ ///
+ ///
+ /// MonoMod attribute for patching a method directly with IL
+ ///
+ [UsedImplicitly]
+ [MonoModCustomAttribute("RawIlPatch")]
+ public class RawIlPatch : Attribute
+ {
+ ///
+ ///
+ /// Patches a method directly with IL
+ ///
+ /// Method name that does the IL patch
+ public RawIlPatch(string patcherMethod) { }
+ }
+}
+
+namespace MonoMod
+{
+ public static partial class MonoModRules
+ {
+ ///
+ /// Remove op
+ ///
+ /// Method to be patched
+ /// Attribute
+ [UsedImplicitly]
+ public static void RawIlPatch(MethodDefinition method, CustomAttribute attrib)
+ {
+ var context = new ILContext(method);
+
+ string patcherTypeName = $"Modding.Patches.{nameof(Modding.Patches.IlPatches)}, Assembly-CSharp.mm";
+ string patcherMethodName = (string)attrib.ConstructorArguments[0].Value;
+
+ Type patcherType = Type.GetType(patcherTypeName);
+
+ if (patcherType is null)
+ throw new InvalidOperationException("Couldn't find patcher type!");
+
+ MethodBase patcherMethod = patcherType?.GetMethod(patcherMethodName, AllBindingFlags/*, null, [typeof(ILContext)], null*/);
+
+ if (patcherMethod is null)
+ throw new InvalidOperationException("Couldn't find patcher method!");
+
+ context.Invoke(patcherMethod.CreateDelegate());
+ }
+ }
+}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/RemoveMethodCall.cs b/Assembly-CSharp/Patches/Attributes/RemoveMethodCall.cs
similarity index 97%
rename from Assembly-CSharp/Patches/RemoveMethodCall.cs
rename to Assembly-CSharp/Patches/Attributes/RemoveMethodCall.cs
index 14c895b6..db716b30 100644
--- a/Assembly-CSharp/Patches/RemoveMethodCall.cs
+++ b/Assembly-CSharp/Patches/Attributes/RemoveMethodCall.cs
@@ -7,7 +7,7 @@
using MonoMod;
using MonoMod.Cil;
-namespace Modding.Patches
+namespace Modding.Patches.Attributes
{
///
///
diff --git a/Assembly-CSharp/Patches/ReplaceMethodAttribute.cs b/Assembly-CSharp/Patches/Attributes/ReplaceMethod.cs
similarity index 91%
rename from Assembly-CSharp/Patches/ReplaceMethodAttribute.cs
rename to Assembly-CSharp/Patches/Attributes/ReplaceMethod.cs
index f5302616..df26c6e9 100644
--- a/Assembly-CSharp/Patches/ReplaceMethodAttribute.cs
+++ b/Assembly-CSharp/Patches/Attributes/ReplaceMethod.cs
@@ -7,7 +7,7 @@
using MonoMod;
using MonoMod.Cil;
-namespace Modding.Patches
+namespace Modding.Patches.Attributes
{
///
///
@@ -15,13 +15,13 @@ namespace Modding.Patches
///
[MonoModCustomAttribute("ReplaceMethod")]
[UsedImplicitly]
- internal class ReplaceMethodAttribute : Attribute
+ internal class ReplaceMethod : Attribute
{
///
///
/// Replace method call with alternate method call
///
- public ReplaceMethodAttribute(string type1, string method1, string[] params1, string type2, string method2, string[] params2) { }
+ public ReplaceMethod(string type1, string method1, string[] params1, string type2, string method2, string[] params2) { }
}
}
diff --git a/Assembly-CSharp/Patches/EnemyDeathEffects.cs b/Assembly-CSharp/Patches/EnemyDeathEffects.cs
index 320fb607..36192cc3 100644
--- a/Assembly-CSharp/Patches/EnemyDeathEffects.cs
+++ b/Assembly-CSharp/Patches/EnemyDeathEffects.cs
@@ -1,4 +1,6 @@
-using MonoMod;
+using Mono.Cecil.Cil;
+using MonoMod;
+using MonoMod.Cil;
// ReSharper disable All
#pragma warning disable 1591, 0108, 0169, 0649, 0414
@@ -10,32 +12,52 @@ namespace Modding.Patches
public class EnemyDeathEffects : global::EnemyDeathEffects
{
[MonoModIgnore]
- private bool didFire;
+ [Attributes.RawIlPatch(nameof(IlPatches.RecieveDeathEvent))]
+ extern public void RecieveDeathEvent(float? attackDirection, bool resetDeathEvent = false, bool spellBurn = false, bool isWatery = false);
- public extern void orig_RecieveDeathEvent(float? attackDirection, bool resetDeathEvent = false, bool spellBurn = false, bool isWatery = false);
+ [MonoModIgnore]
+ [Attributes.RawIlPatch(nameof(IlPatches.RecordKillForJournal))]
+ extern public static void RecordKillForJournal(string playerDataName);
+ }
- //Use this to hook into when an enemy dies. Check EnemyDeathEffects.didFire to prevent doing any actions on redundant invokes.
- public void RecieveDeathEvent(float? attackDirection, bool resetDeathEvent = false, bool spellBurn = false, bool isWatery = false)
+ [MonoModIgnore]
+ public static partial class IlPatches
+ {
+ [MonoModIgnore]
+ public static void RecieveDeathEvent(ILContext il)
{
- ModHooks.OnRecieveDeathEvent(this, didFire, ref attackDirection, ref resetDeathEvent, ref spellBurn, ref isWatery);
-
- orig_RecieveDeathEvent(attackDirection, resetDeathEvent, spellBurn, isWatery);
+ // add a `ModHooks.OnRecieveDeathEvent(this, didFire, ref attackDirection, ref resetDeathEvent, ref spellBurn, ref isWatery);` at the start of the method
+ ILCursor cursor = new ILCursor(il);
+
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchLdarg(0));
+
+ // Insert a call to your custom method
+ cursor.Emit(OpCodes.Ldarg_0);
+ cursor.Emit(OpCodes.Ldarg_0);
+ cursor.Emit(OpCodes.Ldfld, ReflectionHelper.GetFieldInfo(typeof(global::EnemyDeathEffects), "didFire", true));
+ cursor.Emit(OpCodes.Ldarga_S, il.Method.Parameters[0]); // attackDirection
+ cursor.Emit(OpCodes.Ldarga_S, il.Method.Parameters[1]); // resetDeathEvent
+ cursor.Emit(OpCodes.Ldarga_S, il.Method.Parameters[2]); // spellBurn
+ cursor.Emit(OpCodes.Ldarga_S, il.Method.Parameters[3]); // isWatery
+ cursor.EmitDelegate(global::Modding.ModHooks.OnRecieveDeathEvent);
}
[MonoModIgnore]
- private string playerDataName;
+ public static void RecordKillForJournal(ILContext il)
+ {
+ // add a `ModHooks.OnRecordKillForJournal(this, this.playerDataName, $"killed{this.playerDataName}", $"kills{this.playerDataName}", $"newData{this.playerDataName}");` at the start of the method
+ ILCursor cursor = new ILCursor(il);
- private extern void orig_RecordKillForJournal();
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchLdcI4(0));
- private void RecordKillForJournal()
- {
- string boolName = "killed" + this.playerDataName;
- string intName = "kills" + this.playerDataName;
- string boolName2 = "newData" + this.playerDataName;
-
- ModHooks.OnRecordKillForJournal(this, playerDataName, boolName, intName, boolName2);
-
- orig_RecordKillForJournal();
+ // Insert a call to your custom method
+ cursor.Emit(OpCodes.Ldarg_0); // this
+ cursor.Emit(OpCodes.Ldarg_0); // this
+ cursor.Emit(OpCodes.Ldfld, ReflectionHelper.GetFieldInfo(typeof(global::EnemyDeathEffects), "playerDataName", true)); // .playerDataName
+ cursor.Emit(OpCodes.Ldloc_1); // killed text
+ cursor.Emit(OpCodes.Ldloc_2); // kills text
+ cursor.Emit(OpCodes.Ldloc_3); // newData text
+ cursor.EmitDelegate(global::Modding.ModHooks.OnRecordKillForJournal);
}
}
}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/GameManager.cs b/Assembly-CSharp/Patches/GameManager.cs
index 9510c2d5..538babb7 100644
--- a/Assembly-CSharp/Patches/GameManager.cs
+++ b/Assembly-CSharp/Patches/GameManager.cs
@@ -1,13 +1,18 @@
+using Mono.Cecil.Cil;
+using MonoMod;
+using MonoMod.Cil;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
-using MonoMod;
+using Mono.Cecil;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.SceneManagement;
+using Encryption = TeamCherry.SharedUtils.Encryption;
// ReSharper disable all
#pragma warning disable 1591, 649, 414, 169, CS0108, CS0626
@@ -17,55 +22,65 @@ namespace Modding.Patches
[MonoModPatch("global::GameManager")]
public class GameManager : global::GameManager
{
- public extern void orig_OnApplicationQuit();
+ private static string ModdedSavePath(int slot) =>
+ Path.Combine
+ (
+ Application.persistentDataPath,
+ $"user{slot}.modded.json"
+ );
- public void OnApplicationQuit()
+ private UIManager _uiInstance;
+
+ public UIManager ui
{
- orig_OnApplicationQuit();
- ModHooks.OnApplicationQuit();
+ get
+ {
+ if (_uiInstance == null) _uiInstance = (UIManager)UIManager.instance;
+ return _uiInstance;
+ }
+ private set => _uiInstance = value;
}
- public extern void orig_LoadScene(string destScene);
-
- public void LoadScene(string destScene)
- {
- destScene = ModHooks.BeforeSceneLoad(destScene);
+ private ModSavegameData moddedData;
- orig_LoadScene(destScene);
+ [MonoModIgnore]
+ [Attributes.RawIlPatch(nameof(IlPatches.OnApplicationQuit))]
+ extern private void OnApplicationQuit();
- ModHooks.OnSceneChanged(destScene);
- }
+ [MonoModIgnore]
+ [Attributes.RawIlPatch(nameof(IlPatches.LoadScene))]
+ extern public void LoadScene(string destScene);
- public extern void orig_BeginSceneTransition(GameManager.SceneLoadInfo info);
+ [MonoModIgnore]
+ [Attributes.RawIlPatch(nameof(IlPatches.ClearSaveFile))]
+ extern public void ClearSaveFile(int saveSlot, Action callback);
- public void BeginSceneTransition(GameManager.SceneLoadInfo info)
- {
- info.SceneName = ModHooks.BeforeSceneLoad(info.SceneName);
+ [MonoModIgnore]
+ [Attributes.IEnumeratorIlPatch(nameof(IlPatches.PlayerDead))]
+ extern public IEnumerator PlayerDead(float waitTime);
- orig_BeginSceneTransition(info);
- }
+ [MonoModIgnore]
+ [Attributes.IEnumeratorIlPatch(nameof(IlPatches.LoadSceneAdditive))]
+ extern public IEnumerator LoadSceneAdditive(string destScene);
- public extern void orig_ClearSaveFile(int saveSlot, Action callback);
+ [MonoModIgnore]
+ [Attributes.IEnumeratorIlPatch(nameof(IlPatches.LoadFirstScene))]
+ extern public IEnumerator LoadFirstScene();
- public void ClearSaveFile(int saveSlot, Action callback)
- {
- ModHooks.OnSavegameClear(saveSlot);
- orig_ClearSaveFile(saveSlot, callback);
- ModHooks.OnAfterSaveGameClear(saveSlot);
- }
+ [MonoModIgnore]
+ [Attributes.RawIlPatch(nameof(IlPatches.OnWillActivateFirstLevel))]
+ extern public void OnWillActivateFirstLevel();
- public extern IEnumerator orig_PlayerDead(float waitTime);
+ // il patch just dies trying to resolve types for no reason?
+ public extern void orig_BeginSceneTransition(global::GameManager.SceneLoadInfo info);
- public IEnumerator PlayerDead(float waitTime)
+ public void BeginSceneTransition(GameManager.SceneLoadInfo info)
{
- ModHooks.OnBeforePlayerDead();
- yield return orig_PlayerDead(waitTime);
- ModHooks.OnAfterPlayerDead();
+ info.SceneName = ModHooks.BeforeSceneLoad(info.SceneName);
+ orig_BeginSceneTransition(info);
}
- #region SaveGame
-
- private ModSavegameData moddedData;
+ #region SaveGame & LoadGame
[MonoModIgnore]
private GameCameras gameCams;
@@ -91,23 +106,6 @@ public IEnumerator PlayerDead(float waitTime)
[MonoModIgnore]
private extern void HideSaveIcon();
- private static string ModdedSavePath(int slot) => Path.Combine(
- Application.persistentDataPath,
- $"user{slot}.modded.json"
- );
-
- private UIManager _uiInstance;
-
- public UIManager ui
- {
- get
- {
- if (_uiInstance == null) _uiInstance = (UIManager)UIManager.instance;
- return _uiInstance;
- }
- private set => _uiInstance = value;
- }
-
[MonoModReplace]
public void SaveGame(int saveSlot, Action callback)
{
@@ -148,13 +146,15 @@ public void SaveGame(int saveSlot, Action callback)
{
this.moddedData = new ModSavegameData();
}
+
ModHooks.OnSaveLocalSettings(this.moddedData);
// save modded data
try
{
var path = ModdedSavePath(saveSlot);
- string modded = JsonConvert.SerializeObject(
+ string modded = JsonConvert.SerializeObject
+ (
this.moddedData,
Formatting.Indented,
new JsonSerializerSettings
@@ -179,12 +179,17 @@ public void SaveGame(int saveSlot, Action callback)
try
{
- text = JsonConvert.SerializeObject(obj, Formatting.Indented, new JsonSerializerSettings()
- {
- ContractResolver = ShouldSerializeContractResolver.Instance,
- TypeNameHandling = TypeNameHandling.Auto,
- Converters = JsonConverterTypes.ConverterTypes
- });
+ text = JsonConvert.SerializeObject
+ (
+ obj,
+ Formatting.Indented,
+ new JsonSerializerSettings()
+ {
+ ContractResolver = ShouldSerializeContractResolver.Instance,
+ TypeNameHandling = TypeNameHandling.Auto,
+ Converters = JsonConverterTypes.ConverterTypes
+ }
+ );
}
catch (Exception e)
{
@@ -196,9 +201,7 @@ public void SaveGame(int saveSlot, Action callback)
text = JsonUtility.ToJson(obj);
}
- bool flag = this.gameConfig.useSaveEncryption && !Platform.Current.IsFileSystemProtected;
-
- if (flag)
+ if (this.gameConfig.useSaveEncryption && !Platform.Current.IsFileSystemProtected)
{
string graph = Encryption.Encrypt(text);
BinaryFormatter binaryFormatter = new BinaryFormatter();
@@ -210,7 +213,7 @@ public void SaveGame(int saveSlot, Action callback)
(
saveSlot,
binary,
- delegate (bool didSave)
+ delegate(bool didSave)
{
this.HideSaveIcon();
callback(didSave);
@@ -223,7 +226,7 @@ public void SaveGame(int saveSlot, Action callback)
(
saveSlot,
Encoding.UTF8.GetBytes(text),
- delegate (bool didSave)
+ delegate(bool didSave)
{
this.HideSaveIcon();
if (callback != null)
@@ -265,30 +268,6 @@ public void SaveGame(int saveSlot, Action callback)
}
}
- #endregion
-
- public extern void orig_SetupSceneRefs(bool refreshTilemapInfo);
-
- public void SetupSceneRefs(bool refreshTilemapInfo)
- {
- orig_SetupSceneRefs(refreshTilemapInfo);
-
-
- if (IsGameplayScene())
- {
- GameObject go = GameCameras.instance.soulOrbFSM.gameObject.transform.Find("SoulOrb_fill").gameObject;
- GameObject liquid = go.transform.Find("Liquid").gameObject;
- tk2dSpriteAnimator tk2dsa = liquid.GetComponent();
- tk2dsa.GetClipByName("Fill").fps = 15 * 1.05f;
- tk2dsa.GetClipByName("Idle").fps = 10 * 1.05f;
- tk2dsa.GetClipByName("Shrink").fps = 15 * 1.05f;
- tk2dsa.GetClipByName("Drain").fps = 30 * 1.05f;
- }
-
- }
-
- #region LoadGame
-
[MonoModReplace]
public void LoadGame(int saveSlot, Action callback)
{
@@ -318,7 +297,8 @@ public void LoadGame(int saveSlot, Action callback)
using FileStream fileStream = File.OpenRead(path);
using var reader = new StreamReader(fileStream);
string json = reader.ReadToEnd();
- this.moddedData = JsonConvert.DeserializeObject(
+ this.moddedData = JsonConvert.DeserializeObject
+ (
json,
new JsonSerializerSettings()
{
@@ -344,12 +324,13 @@ public void LoadGame(int saveSlot, Action callback)
Logger.APILogger.LogError(e);
this.moddedData = new ModSavegameData();
}
+
ModHooks.OnLoadLocalSettings(this.moddedData);
Platform.Current.ReadSaveSlot
(
saveSlot,
- delegate (byte[] fileBytes)
+ delegate(byte[] fileBytes)
{
bool obj;
try
@@ -372,13 +353,17 @@ public void LoadGame(int saveSlot, Action callback)
try
{
- saveGameData = JsonConvert.DeserializeObject(json, new JsonSerializerSettings()
- {
- ContractResolver = ShouldSerializeContractResolver.Instance,
- TypeNameHandling = TypeNameHandling.Auto,
- ObjectCreationHandling = ObjectCreationHandling.Replace,
- Converters = JsonConverterTypes.ConverterTypes
- });
+ saveGameData = JsonConvert.DeserializeObject
+ (
+ json,
+ new JsonSerializerSettings()
+ {
+ ContractResolver = ShouldSerializeContractResolver.Instance,
+ TypeNameHandling = TypeNameHandling.Auto,
+ ObjectCreationHandling = ObjectCreationHandling.Replace,
+ Converters = JsonConverterTypes.ConverterTypes
+ }
+ );
}
catch (Exception e)
{
@@ -424,270 +409,296 @@ public void LoadGame(int saveSlot, Action callback)
#endregion
- #region GetSaveStatsForSlot
+ extern public void orig_SetupSceneRefs(bool refreshTilemapInfo);
+ public void SetupSceneRefs(bool refreshTilemapInfo)
+ {
+ orig_SetupSceneRefs(refreshTilemapInfo);
+ if (IsGameplayScene())
+ {
+ GameObject go = GameCameras.instance.soulOrbFSM.gameObject.transform.Find("SoulOrb_fill").gameObject;
+ GameObject liquid = go.transform.Find("Liquid").gameObject;
+ tk2dSpriteAnimator tk2dsa = liquid.GetComponent();
+ tk2dsa.GetClipByName("Fill").fps = 15 * 1.05f;
+ tk2dsa.GetClipByName("Idle").fps = 10 * 1.05f;
+ tk2dsa.GetClipByName("Shrink").fps = 15 * 1.05f;
+ tk2dsa.GetClipByName("Drain").fps = 30 * 1.05f;
+ }
+ }
[MonoModReplace]
public void GetSaveStatsForSlot(int saveSlot, Action callback)
{
if (!Platform.IsSaveSlotIndexValid(saveSlot))
{
- Debug.LogErrorFormat
- (
- "Cannot get save stats for invalid slot {0}",
- new object[]
- {
- saveSlot
- }
- );
+ Debug.LogErrorFormat("Cannot get save stats for invalid slot {0}", new object[] { saveSlot });
if (callback != null)
{
CoreLoop.InvokeNext(delegate { callback(null); });
}
-
return;
}
-
- Platform.Current.ReadSaveSlot
- (
- saveSlot,
- delegate (byte[] fileBytes)
+ Platform.Current.ReadSaveSlot(saveSlot, delegate(byte[] fileBytes)
+ {
+ if (fileBytes == null)
{
- if (fileBytes == null)
+ if (callback != null)
{
- if (callback != null)
- {
- CoreLoop.InvokeNext(delegate { callback(null); });
- }
-
- return;
+ CoreLoop.InvokeNext(delegate { callback(null); });
}
-
+ return;
+ }
+ try
+ {
+ bool flag = this.gameConfig.useSaveEncryption && !Platform.Current.IsFileSystemProtected;
+ string json;
+ if (flag)
+ {
+ BinaryFormatter binaryFormatter = new BinaryFormatter();
+ MemoryStream serializationStream = new MemoryStream(fileBytes);
+ string encryptedString = (string)binaryFormatter.Deserialize(serializationStream);
+ json = Encryption.Decrypt(encryptedString);
+ }
+ else
+ {
+ json = Encoding.UTF8.GetString(fileBytes);
+ }
+ SaveGameData saveGameData;
try
{
- bool flag = this.gameConfig.useSaveEncryption && !Platform.Current.IsFileSystemProtected;
- string json;
- if (flag)
- {
- BinaryFormatter binaryFormatter = new BinaryFormatter();
- MemoryStream serializationStream = new MemoryStream(fileBytes);
- string encryptedString = (string)binaryFormatter.Deserialize(serializationStream);
- json = Encryption.Decrypt(encryptedString);
- }
- else
- {
- json = Encoding.UTF8.GetString(fileBytes);
- }
-
- SaveGameData saveGameData;
- try
- {
- saveGameData = JsonConvert.DeserializeObject(json, new JsonSerializerSettings()
- {
- ContractResolver = ShouldSerializeContractResolver.Instance,
- TypeNameHandling = TypeNameHandling.Auto,
- ObjectCreationHandling = ObjectCreationHandling.Replace,
- Converters = JsonConverterTypes.ConverterTypes
- });
- }
- catch (Exception)
+ saveGameData = JsonConvert.DeserializeObject(json, new JsonSerializerSettings()
{
- // Not a huge deal, this happens on saves with mod data which haven't been converted yet.
- Logger.APILogger.LogWarn($"Failed to get save stats for slot {saveSlot} using Json.NET, falling back");
-
- saveGameData = JsonUtility.FromJson(json);
- }
-
- global::PlayerData playerData = saveGameData.playerData;
- SaveStats saveStats = new SaveStats
- (
- playerData.GetInt(nameof(PlayerData.maxHealthBase)),
- playerData.GetInt(nameof(PlayerData.geo)),
- playerData.GetVariable(nameof(PlayerData.mapZone)),
- playerData.GetFloat(nameof(PlayerData.playTime)),
- playerData.GetInt(nameof(PlayerData.MPReserveMax)),
- playerData.GetInt(nameof(PlayerData.permadeathMode)),
- playerData.GetBool(nameof(PlayerData.bossRushMode)),
- playerData.GetFloat(nameof(PlayerData.completionPercentage)),
- playerData.GetBool(nameof(PlayerData.unlockedCompletionRate))
- );
- if (callback != null)
- {
- CoreLoop.InvokeNext(delegate { callback(saveStats); });
- }
+ ContractResolver = ShouldSerializeContractResolver.Instance,
+ TypeNameHandling = TypeNameHandling.Auto,
+ ObjectCreationHandling = ObjectCreationHandling.Replace,
+ Converters = JsonConverterTypes.ConverterTypes
+ });
}
- catch (Exception ex)
+ catch (Exception)
{
- Debug.LogError
- (
- string.Concat
- (
- new object[]
- {
- "Error while loading save file for slot ",
- saveSlot,
- " Exception: ",
- ex
- }
- )
- );
- if (callback != null)
- {
- CoreLoop.InvokeNext(delegate { callback(null); });
- }
+ // Not a huge deal, this happens on saves with mod data which haven't been converted yet.
+ Logger.APILogger.LogWarn($"Failed to get save stats for slot {saveSlot} using Json.NET, falling back");
+ saveGameData = JsonUtility.FromJson(json);
+ }
+ global::PlayerData playerData = saveGameData.playerData;
+ SaveStats saveStats = new SaveStats
+ (
+ playerData.GetInt(nameof(PlayerData.maxHealthBase)),
+ playerData.GetInt(nameof(PlayerData.geo)),
+ playerData.GetVariable(nameof(PlayerData.mapZone)),
+ playerData.GetFloat(nameof(PlayerData.playTime)),
+ playerData.GetInt(nameof(PlayerData.MPReserveMax)),
+ playerData.GetInt(nameof(PlayerData.permadeathMode)),
+ playerData.GetBool(nameof(PlayerData.bossRushMode)),
+ playerData.GetFloat(nameof(PlayerData.completionPercentage)),
+ playerData.GetBool(nameof(PlayerData.unlockedCompletionRate))
+ );
+ if (callback != null)
+ {
+ CoreLoop.InvokeNext(delegate { callback(saveStats); });
}
}
- );
+ catch (Exception ex)
+ {
+ Debug.LogError($"Error while loading save file for slot {saveSlot} Exception: {ex}");
+ if (callback != null)
+ {
+ CoreLoop.InvokeNext(delegate { callback(null); });
+ }
+ }
+ });
}
- #endregion
-
- #region LoadSceneAdditive
-
- [MonoModIgnore]
- private bool tilemapDirty;
-
- [MonoModIgnore]
- private bool waitForManualLevelStart;
+ #region PauseToDynamicMenu
[MonoModIgnore]
- public event GameManager.DestroyPooledObjects DestroyPersonalPools;
+ public extern void SetTimeScale(float timescale);
[MonoModIgnore]
- public event GameManager.UnloadLevel UnloadingLevel;
+ private extern void SetPausedState(bool value);
- [MonoModReplace]
- public IEnumerator LoadSceneAdditive(string destScene)
+ // code has been copied from PauseGameToggle
+ public IEnumerator PauseToggleDynamicMenu(MenuScreen screen, bool allowUnpause = false)
{
- Debug.Log("Loading " + destScene);
- destScene = ModHooks.BeforeSceneLoad(destScene);
- this.tilemapDirty = true;
- this.startedOnThisScene = false;
- this.nextSceneName = destScene;
- this.waitForManualLevelStart = true;
- if (this.DestroyPersonalPools != null)
+ if (this.TimeSlowed)
{
- this.DestroyPersonalPools();
+ yield break;
}
- if (this.UnloadingLevel != null)
+ if (!this.playerData.GetBool(nameof(PlayerData.disablePause)) && this.gameState == GlobalEnums.GameState.PLAYING)
{
- this.UnloadingLevel();
- }
+ this.isPaused = true;
+ this.ui.SetState(GlobalEnums.UIState.PAUSED);
+ this.SetPausedState(true);
+ this.SetState(GlobalEnums.GameState.PAUSED);
+ if (HeroController.instance != null)
+ {
+ HeroController.instance.Pause();
+ }
- string exitingScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name;
- AsyncOperation loadop = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync(destScene, LoadSceneMode.Additive);
- loadop.allowSceneActivation = true;
- yield return loadop;
- yield return UnityEngine.SceneManagement.SceneManager.UnloadSceneAsync(exitingScene);
- ModHooks.OnSceneChanged(destScene);
- this.RefreshTilemapInfo(destScene);
- if (this.IsUnloadAssetsRequired(exitingScene, destScene))
+ this.gameCams.MoveMenuToHUDCamera();
+ this.inputHandler.PreventPause();
+ this.inputHandler.StopUIInput();
+ yield return new WaitForSecondsRealtime(0.3f);
+ this.inputHandler.AllowPause();
+ }
+ else if (allowUnpause && this.gameState == GlobalEnums.GameState.PAUSED)
{
- Debug.LogFormat(this, "Unloading assets due to zone transition", new object[0]);
- yield return Resources.UnloadUnusedAssets();
+ this.isPaused = false;
+ this.inputHandler.PreventPause();
+ this.ui.SetState(GlobalEnums.UIState.PLAYING);
+ this.SetPausedState(false);
+ this.SetState(GlobalEnums.GameState.PLAYING);
+ if (HeroController.instance != null)
+ {
+ HeroController.instance.UnPause();
+ }
+
+ MenuButtonList.ClearAllLastSelected();
+ yield return new WaitForSecondsRealtime(0.3f);
+ this.inputHandler.AllowPause();
}
- GCManager.Collect();
- this.SetupSceneRefs(true);
- this.BeginScene();
- this.OnNextLevelReady();
- this.waitForManualLevelStart = false;
- Debug.Log("Done Loading " + destScene);
yield break;
}
#endregion
- #region LoadFirstScene
+ [MonoModIgnore]
+ private SceneLoad sceneLoad;
- [MonoModReplace]
- public IEnumerator LoadFirstScene()
+ /*
+ * This will allow modders to access the scene loader.
+ * Note that if there's no transition in progress, it will be null!
+ * Example use case: Start a co-routine that checks for an non null
+ * sceneLoad then hooks up a callback to the "Finish" delegate to do something when the game has completed loading a scene.
+ */
+ // [MonoModIgnore]
+ public SceneLoad SceneLoad
{
- yield return new WaitForEndOfFrame();
- this.OnWillActivateFirstLevel();
- this.LoadScene("Tutorial_01");
- ModHooks.OnNewGame();
- yield break;
+ get { return sceneLoad; }
}
+ }
- #endregion
-
- #region OnWillActivateFirstLevel
+ public static partial class IlPatches
+ {
+ [MonoModIgnore]
+ public static void OnApplicationQuit(ILContext il)
+ {
+ // add a `ModHooks.OnApplicationQuit();` at the end of the method
+ ILCursor cursor = new ILCursor(il);
- public extern void orig_OnWillActivateFirstLevel();
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchRet());
+ cursor.EmitDelegate(global::Modding.ModHooks.OnApplicationQuit);
+ }
- public void OnWillActivateFirstLevel()
+ [MonoModIgnore]
+ public static void LoadScene(ILContext il)
{
- orig_OnWillActivateFirstLevel();
- ModHooks.OnNewGame();
+ // add a `destScene = ModHooks.BeforeSceneLoad(destScene);` at the start and a `ModHooks.OnSceneChanged(destScene);` at the end of the method
+ ILCursor cursor = new ILCursor(il).Goto(0);
+
+ // Insert a call to your custom method
+ cursor.Emit(OpCodes.Ldarg_1);
+ cursor.EmitDelegate(global::Modding.ModHooks.BeforeSceneLoad);
+ cursor.Emit(OpCodes.Starg, 1);
+
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchRet());
+ cursor.Emit(OpCodes.Ldarg_1);
+ cursor.EmitDelegate(global::Modding.ModHooks.OnSceneChanged);
}
- #endregion
+ [MonoModIgnore]
+ public static void ClearSaveFile(ILContext il)
+ {
+ // add a `ModHooks.OnSavegameClear(saveSlot);` at the start and a `ModHooks.OnAfterSaveGameClear(saveSlot);` at the end of the method
+ ILCursor cursor = new ILCursor(il).Goto(0);
+
+ // Insert a call to your custom method
+ cursor.Emit(OpCodes.Ldarg_1);
+ cursor.EmitDelegate(global::Modding.ModHooks.OnSavegameClear);
+
+ // this goes just before both `ret`s
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchRet());
+ cursor.Emit(OpCodes.Ldarg_1);
+ cursor.EmitDelegate(global::Modding.ModHooks.OnAfterSaveGameClear);
+
+ // skip over the return
+ cursor.GotoNext();
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchRet());
+ cursor.Emit(OpCodes.Ldarg_1);
+ cursor.EmitDelegate(global::Modding.ModHooks.OnAfterSaveGameClear);
+ }
- #region PauseToDynamicMenu
[MonoModIgnore]
- public extern void SetTimeScale(float timescale);
+ public static void PlayerDead(ILContext il, TypeDefinition stateMachineTypeDef)
+ {
+ // add a `ModHooks.OnSavegameClear(saveSlot);` at the start and a `ModHooks.OnAfterSaveGameClear(saveSlot);` at the end of the method
+ ILCursor cursor = new ILCursor(il);
- // code has been copied from PauseGameToggle
- public IEnumerator PauseToggleDynamicMenu(MenuScreen screen, bool allowUnpause = false)
+ // Insert a call to your custom method
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchLdloc(1), x => x.MatchCallOrCallvirt(typeof(global::GameManager), "get_cameraCtrl"));
+ cursor.EmitDelegate(global::Modding.ModHooks.OnBeforePlayerDead);
+
+ // this goes just before all the `ret`s
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchLdcI4(0), x => x.MatchRet());
+ cursor.EmitDelegate(global::Modding.ModHooks.OnAfterPlayerDead);
+ }
+
+ [MonoModIgnore]
+ public static void LoadSceneAdditive(ILContext il, TypeDefinition stateMachineTypeDef)
{
- if (!this.TimeSlowed)
- {
- if (!this.playerData.GetBool(nameof(PlayerData.disablePause)) && this.gameState == GlobalEnums.GameState.PLAYING)
- {
- this.gameCams.StopCameraShake();
- this.inputHandler.PreventPause();
- this.inputHandler.StopUIInput();
- this.actorSnapshotPaused.TransitionTo(0f);
- this.isPaused = true;
- this.SetState(GlobalEnums.GameState.PAUSED);
- this.ui.AudioGoToPauseMenu(0.2f);
- this.ui.UIPauseToDynamicMenu(screen);
- if (HeroController.instance != null)
- {
- HeroController.instance.Pause();
- }
- this.gameCams.MoveMenuToHUDCamera();
- this.SetTimeScale(0f);
- yield return new WaitForSecondsRealtime(0.8f);
- this.inputHandler.AllowPause();
- }
- else if (allowUnpause && this.gameState == GlobalEnums.GameState.PAUSED)
- {
- this.gameCams.ResumeCameraShake();
- this.inputHandler.PreventPause();
- this.actorSnapshotUnpaused.TransitionTo(0f);
- this.isPaused = false;
- this.ui.AudioGoToGameplay(0.2f);
- this.ui.SetState( GlobalEnums.UIState.PLAYING);
- this.SetState( GlobalEnums.GameState.PLAYING);
- if (HeroController.instance != null)
- {
- HeroController.instance.UnPause();
- }
- MenuButtonList.ClearAllLastSelected();
- this.SetTimeScale(1f);
- yield return new WaitForSecondsRealtime(0.8f);
- this.inputHandler.AllowPause();
- }
- }
- yield break;
+ // add a `destScene = ModHooks.BeforeSceneLoad(destScene);` at the start and a `ModHooks.OnSceneChanged(destScene);` in the middle of the method
+ ILCursor cursor = new ILCursor(il);
+
+ // Insert a call to your custom method
+ cursor.GotoNext
+ (
+ MoveType.AfterLabel,
+ x => x.MatchLdloc(1),
+ x => x.MatchLdcI4(1),
+ x => x.MatchStfld("tilemapDirty")
+ );
+ cursor.Emit(OpCodes.Ldarg_0);
+ cursor.Emit(OpCodes.Ldarg_0);
+ cursor.Emit(OpCodes.Ldfld, stateMachineTypeDef.Fields.First(f => f.Name == "destScene"));
+ cursor.EmitDelegate(global::Modding.ModHooks.BeforeSceneLoad);
+ cursor.Emit(OpCodes.Stfld, stateMachineTypeDef.Fields.First(f => f.Name == "destScene"));
+
+ // somewhere before `this.RefreshTilemapInfo(destScene);`
+ cursor.GotoNext
+ (
+ MoveType.AfterLabel,
+ x => x.MatchLdloc(1),
+ x => x.MatchLdarg(0),
+ x => x.MatchLdfld(out _), // destScene field of statemachine type
+ x => x.MatchCallOrCallvirt(typeof(global::GameManager), "RefreshTilemapInfo")
+ );
+ cursor.Emit(OpCodes.Ldarg_0);
+ cursor.Emit(OpCodes.Ldfld, stateMachineTypeDef.Fields.First(f => f.Name == "destScene"));
+ cursor.EmitDelegate(global::Modding.ModHooks.OnSceneChanged);
}
- #endregion
[MonoModIgnore]
- private SceneLoad sceneLoad;
+ public static void LoadFirstScene(ILContext il, TypeDefinition stateMachineTypeDef)
+ {
+ // add a `ModHooks.OnNewGame();` at the end of the method
+ ILCursor cursor = new ILCursor(il);
+
+ // Insert a call to your custom method
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchLdloc(1));
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchLdcI4(0), x => x.MatchRet());
+ cursor.EmitDelegate(global::Modding.ModHooks.OnNewGame);
+ }
- /*
- * This will allow modders to access the scene loader.
- * Note that if there's no transition in progress, it will be null!
- * Example use case: Start a co-routine that checks for an non null
- * sceneLoad then hooks up a callback to the "Finish" delegate to do something when the game has completed loading a scene.
- */
[MonoModIgnore]
- public SceneLoad SceneLoad
+ public static void OnWillActivateFirstLevel(ILContext il)
{
- get { return sceneLoad; }
+ // add a `ModHooks.OnNewGame();` at the end of the method
+ ILCursor cursor = new ILCursor(il);
+
+ // Insert a call to your custom method
+ cursor.GotoNext(MoveType.AfterLabel, x => x.MatchRet());
+ cursor.EmitDelegate(global::Modding.ModHooks.OnNewGame);
}
}
}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/HasComponent.cs b/Assembly-CSharp/Patches/HasComponent.cs
index 378f3aa2..dd24f421 100644
--- a/Assembly-CSharp/Patches/HasComponent.cs
+++ b/Assembly-CSharp/Patches/HasComponent.cs
@@ -10,13 +10,13 @@ namespace Modding.Patches
public class HasComponent : global::HutongGames.PlayMaker.Actions.HasComponent
{
[MonoModIgnore]
- [RemoveMethodCall
+ [Attributes.RemoveMethodCall
(
"HutongGames.PlayMaker.ReflectionUtils",
"GetGlobalType"
)
]
- [ReplaceMethod
+ [Attributes.ReplaceMethod
(
"UnityEngine.GameObject, UnityEngine",
"GetComponent",
diff --git a/Assembly-CSharp/Patches/HealthManager.cs b/Assembly-CSharp/Patches/HealthManager.cs
index e222a423..54d4ebbb 100644
--- a/Assembly-CSharp/Patches/HealthManager.cs
+++ b/Assembly-CSharp/Patches/HealthManager.cs
@@ -11,7 +11,8 @@ public class HealthManager : global::HealthManager
{
[MonoModIgnore]
public bool isDead;
-
+
+ // todo: make IL hook: add ModHooks before isDead check
///This may be used by mods to find new enemies. Check this isDead flag to see if they're already dead
[MonoModReplace]
protected IEnumerator CheckPersistence()
diff --git a/Assembly-CSharp/Patches/HeroAnimationController.cs b/Assembly-CSharp/Patches/HeroAnimationController.cs
index 1a8e8651..46a970e3 100644
--- a/Assembly-CSharp/Patches/HeroAnimationController.cs
+++ b/Assembly-CSharp/Patches/HeroAnimationController.cs
@@ -20,10 +20,11 @@ public class HeroAnimationController : global::HeroAnimationController
[MonoModIgnore]
private extern void UpdateAnimation();
+ // todo: make IL hook: remove betaEnd pd check
[MonoModReplace]
private void Update()
{
- if (this.controlEnabled)
+ if (this.controlEnabled && !waitingToEnter)
{
this.UpdateAnimation();
}
diff --git a/Assembly-CSharp/Patches/HeroController.cs b/Assembly-CSharp/Patches/HeroController.cs
index f0430b60..28454dc5 100644
--- a/Assembly-CSharp/Patches/HeroController.cs
+++ b/Assembly-CSharp/Patches/HeroController.cs
@@ -67,27 +67,43 @@ public void Attack(AttackDirection attackDir)
this.slashFsm = this.wallSlashFsm;
if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_35)))
{
- if ((this.playerData.GetInt(nameof(PlayerData.health)) == this.playerData.CurrentMaxHealth && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
+ if ((this.playerData.GetInt(nameof(PlayerData.health)) == this.playerData.GetInt(nameof(PlayerData.CurrentMaxHealth)) && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
{
if (this.transform.localScale.x > 0f)
+ {
this.grubberFlyBeam = this.grubberFlyBeamPrefabR.Spawn(this.transform.position);
+ }
else
+ {
this.grubberFlyBeam = this.grubberFlyBeamPrefabL.Spawn(this.transform.position);
+ }
if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_13)))
+ {
this.grubberFlyBeam.transform.SetScaleY(this.MANTIS_CHARM_SCALE);
+ }
else
+ {
this.grubberFlyBeam.transform.SetScaleY(1f);
+ }
}
if (this.playerData.GetInt(nameof(PlayerData.health)) == 1 && this.playerData.GetBool(nameof(PlayerData.equippedCharm_6)) && this.playerData.GetInt(nameof(PlayerData.healthBlue)) < 1)
{
if (this.transform.localScale.x > 0f)
+ {
this.grubberFlyBeam = this.grubberFlyBeamPrefabR_fury.Spawn(this.transform.position);
+ }
else
+ {
this.grubberFlyBeam = this.grubberFlyBeamPrefabL_fury.Spawn(this.transform.position);
+ }
if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_13)))
+ {
this.grubberFlyBeam.transform.SetScaleY(this.MANTIS_CHARM_SCALE);
+ }
else
+ {
this.grubberFlyBeam.transform.SetScaleY(1f);
+ }
}
}
}
@@ -110,7 +126,7 @@ public void Attack(AttackDirection attackDir)
}
if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_35)))
{
- if ((this.playerData.GetInt(nameof(PlayerData.health)) >= this.playerData.CurrentMaxHealth && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
+ if ((this.playerData.GetInt(nameof(PlayerData.health)) >= this.playerData.GetInt(nameof(PlayerData.maxHealth)) && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
{
if (this.transform.localScale.x < 0f)
this.grubberFlyBeam = this.grubberFlyBeamPrefabR.Spawn(this.transform.position);
@@ -141,7 +157,7 @@ public void Attack(AttackDirection attackDir)
this.cState.upAttacking = true;
if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_35)))
{
- if ((this.playerData.GetInt(nameof(PlayerData.health)) >= this.playerData.CurrentMaxHealth && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
+ if ((this.playerData.GetInt(nameof(PlayerData.health)) >= this.playerData.GetInt(nameof(PlayerData.maxHealth)) && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
{
this.grubberFlyBeam = this.grubberFlyBeamPrefabU.Spawn(this.transform.position);
this.grubberFlyBeam.transform.SetScaleY(this.transform.localScale.x);
@@ -166,7 +182,7 @@ public void Attack(AttackDirection attackDir)
this.cState.downAttacking = true;
if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_35)))
{
- if ((this.playerData.GetInt(nameof(PlayerData.health)) >= this.playerData.CurrentMaxHealth && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
+ if ((this.playerData.GetInt(nameof(PlayerData.health)) >= this.playerData.GetInt(nameof(PlayerData.maxHealth)) && !this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))) || (this.joniBeam && this.playerData.GetBool(nameof(PlayerData.equippedCharm_27))))
{
this.grubberFlyBeam = this.grubberFlyBeamPrefabD.Spawn(this.transform.position);
this.grubberFlyBeam.transform.SetScaleY(this.transform.localScale.x);
@@ -218,17 +234,16 @@ public void Attack(AttackDirection attackDir)
[MonoModReplace]
public void SoulGain()
{
- int mpcharge = this.playerData.GetInt("MPCharge");
int num;
- if (mpcharge < this.playerData.GetInt("maxMP"))
+ if (this.playerData.GetInt(nameof(PlayerData.MPCharge)) < this.playerData.GetInt(nameof(PlayerData.maxMP)))
{
num = 11;
- if (this.playerData.GetBool("equippedCharm_20"))
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_20)))
{
num += 3;
}
- if (this.playerData.GetBool("equippedCharm_21"))
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_21)))
{
num += 8;
}
@@ -236,22 +251,22 @@ public void SoulGain()
else
{
num = 6;
- if (this.playerData.GetBool("equippedCharm_20"))
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_20)))
{
num += 2;
}
- if (this.playerData.GetBool("equippedCharm_21"))
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_21)))
{
num += 6;
}
}
- int mpreserve = this.playerData.GetInt("MPReserve");
+ int mpreserve = this.playerData.GetInt(nameof(PlayerData.MPReserve));
num = Modding.ModHooks.OnSoulGain(num);
this.playerData.AddMPCharge(num);
GameCameras.instance.soulOrbFSM.SendEvent("MP GAIN");
- if (this.playerData.GetInt("MPReserve") != mpreserve)
+ if (this.playerData.GetInt(nameof(PlayerData.MPReserve)) != mpreserve)
{
this.gm.soulVessel_fsm.SendEvent("MP RESERVE UP");
}
@@ -446,8 +461,7 @@ private void LookForQueueInput()
&& this.dashQueueSteps <= this.DASH_QUEUE_STEPS
&& this.CanDash()
&& this.dashQueuing
- && !ModHooks.OnDashPressed()
- && this.CanDash())
+ && !ModHooks.OnDashPressed())
{
this.HeroDash();
}
@@ -499,6 +513,9 @@ private void LookForQueueInput()
[MonoModIgnore]
public event HeroController.TakeDamageEvent OnTakenDamage;
+ [MonoModIgnore]
+ private HeroVibrationController vibrationCtrl;
+
[MonoModReplace]
public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount, int hazardType)
{
@@ -545,7 +562,7 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
mixer.StopAllEmissionsWithTag("heroAction");
}
- bool flag = false;
+ bool carefreeShouldStopDamage = false;
if (this.carefreeShieldEquipped && hazardType == 1)
{
if (this.hitsSinceShielded > 7)
@@ -558,58 +575,58 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
case 1:
if ((float) UnityEngine.Random.Range(1, 100) <= 10f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
case 2:
if ((float) UnityEngine.Random.Range(1, 100) <= 20f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
case 3:
if ((float) UnityEngine.Random.Range(1, 100) <= 30f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
case 4:
if ((float) UnityEngine.Random.Range(1, 100) <= 50f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
case 5:
if ((float) UnityEngine.Random.Range(1, 100) <= 70f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
case 6:
if ((float) UnityEngine.Random.Range(1, 100) <= 80f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
case 7:
if ((float) UnityEngine.Random.Range(1, 100) <= 90f)
{
- flag = true;
+ carefreeShouldStopDamage = true;
}
break;
default:
- flag = false;
+ carefreeShouldStopDamage = false;
break;
}
- if (flag)
+ if (carefreeShouldStopDamage)
{
this.hitsSinceShielded = 0;
this.carefreeShield.SetActive(true);
@@ -622,7 +639,7 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
}
}
- if (this.playerData.GetBool("equippedCharm_5") && this.playerData.GetInt("blockerHits") > 0 && hazardType == 1 && this.cState.focusing && !flag)
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_5)) && this.playerData.GetInt(nameof(PlayerData.blockerHits)) > 0 && hazardType == 1 && this.cState.focusing && !carefreeShouldStopDamage)
{
this.proxyFSM.SendEvent("HeroCtrl-TookBlockerHit");
this.audioSource.PlayOneShot(this.blockerImpact, 1f);
@@ -638,7 +655,7 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
if (this.cState.wallSliding)
{
this.cState.wallSliding = false;
- this.wallSlideVibrationPlayer.Stop();
+ this.vibrationCtrl.StopWallSlide();
}
if (this.cState.touchingWall)
@@ -654,24 +671,24 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
if (this.cState.bouncing)
{
this.CancelBounce();
- this.rb2d.velocity = new Vector2(this.rb2d.velocity.x, 0f);
+ this.rb2d.linearVelocity = new Vector2(this.rb2d.linearVelocity.x, 0f);
}
if (this.cState.shroomBouncing)
{
this.CancelBounce();
- this.rb2d.velocity = new Vector2(this.rb2d.velocity.x, 0f);
+ this.rb2d.linearVelocity = new Vector2(this.rb2d.linearVelocity.x, 0f);
}
- if (!flag)
+ if (!carefreeShouldStopDamage)
{
this.audioCtrl.PlaySound(HeroSounds.TAKE_HIT);
}
damageAmount = ModHooks.AfterTakeDamage(hazardType, damageAmount);
- if (!this.takeNoDamage && !this.playerData.GetBool("invinciTest"))
+ if (!this.takeNoDamage && !this.playerData.GetBool(nameof(PlayerData.invinciTest)))
{
- if (this.playerData.GetBool("overcharmed"))
+ if (this.playerData.GetBool(nameof(PlayerData.overcharmed)))
{
this.playerData.TakeHealth(damageAmount * 2);
}
@@ -681,9 +698,9 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
}
}
- if (this.playerData.GetBool("equippedCharm_3") && damageAmount > 0)
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_3)) && damageAmount > 0)
{
- if (this.playerData.GetBool("equippedCharm_35"))
+ if (this.playerData.GetBool(nameof(PlayerData.equippedCharm_35)))
{
this.AddMPCharge(this.GRUB_SOUL_MP_COMBO);
}
@@ -709,32 +726,35 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
this.OnTakenDamage();
}
- if (this.playerData.GetInt("health") == 0)
+ if (this.playerData.GetInt(nameof(PlayerData.health)) == 0)
{
base.StartCoroutine(this.Die());
+ return;
}
else if (hazardType == 2)
{
base.StartCoroutine(this.DieFromHazard(HazardType.SPIKES, (!(go != null)) ? 0f : go.transform.rotation.z));
+ return;
}
else if (hazardType == 3)
{
base.StartCoroutine(this.DieFromHazard(HazardType.ACID, 0f));
+ return;
}
else if (hazardType == 4)
{
Debug.Log("Lava death");
+ return;
}
else if (hazardType == 5)
{
base.StartCoroutine(this.DieFromHazard(HazardType.PIT, 0f));
+ return;
}
- else
- {
- base.StartCoroutine(this.StartRecoil(damageSide, spawnDamageEffect, damageAmount));
- }
+ base.StartCoroutine(this.StartRecoil(damageSide, spawnDamageEffect, damageAmount));
+ return;
}
- else if (this.cState.invulnerable && !this.cState.hazardDeath && !this.playerData.GetBool("isInvincible"))
+ else if (this.cState.invulnerable && !this.cState.hazardDeath && !this.playerData.GetBool(nameof(PlayerData.isInvincible)))
{
if (hazardType == 2)
{
@@ -751,8 +771,8 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
}
else
{
- this.audioCtrl.PlaySound(HeroSounds.TAKE_HIT);
- base.StartCoroutine(this.DieFromHazard(HazardType.SPIKES, (!(go != null)) ? 0f : go.transform.rotation.z));
+ this.audioCtrl.PlaySound(HeroSounds.TAKE_HIT, false);
+ base.StartCoroutine(this.DieFromHazard(HazardType.SPIKES, (go != null) ? go.transform.rotation.z : 0f));
}
}
else if (hazardType == 3)
@@ -760,14 +780,13 @@ public void TakeDamage(GameObject go, CollisionSide damageSide, int damageAmount
damageAmount = ModHooks.AfterTakeDamage(hazardType, damageAmount);
this.playerData.TakeHealth(damageAmount);
this.proxyFSM.SendEvent("HeroCtrl-HeroDamaged");
- if (this.playerData.GetInt("health") == 0)
+ if (this.playerData.GetInt(nameof(PlayerData.health)) == 0)
{
base.StartCoroutine(this.Die());
+ return;
}
- else
- {
- base.StartCoroutine(this.DieFromHazard(HazardType.ACID, 0f));
- }
+ base.StartCoroutine(this.DieFromHazard(HazardType.ACID, 0f));
+ return;
}
else if (hazardType == 4)
{
@@ -842,7 +861,7 @@ private Vector2 OrigDashVector()
origVector = new Vector2
(
velocity,
- (!this.cState.onGround) ? BUMP_VELOCITY_DASH : BUMP_VELOCITY
+ this.cState.onGround ? BUMP_VELOCITY : BUMP_VELOCITY_DASH
);
}
else
@@ -855,7 +874,7 @@ private Vector2 OrigDashVector()
origVector = new Vector2
(
-velocity,
- (!this.cState.onGround) ? BUMP_VELOCITY_DASH : BUMP_VELOCITY
+ this.cState.onGround ? BUMP_VELOCITY : BUMP_VELOCITY_DASH
);
}
else
@@ -879,7 +898,7 @@ private void Dash()
Vector2 vector = OrigDashVector();
vector = ModHooks.DashVelocityChange(vector);
- rb2d.velocity = vector;
+ rb2d.linearVelocity = vector;
dash_timer += Time.deltaTime;
}
diff --git a/Assembly-CSharp/Patches/InputHandler.cs b/Assembly-CSharp/Patches/InputHandler.cs
index 3e5a18b4..a9661846 100644
--- a/Assembly-CSharp/Patches/InputHandler.cs
+++ b/Assembly-CSharp/Patches/InputHandler.cs
@@ -21,30 +21,28 @@ public class InputHandler : global::InputHandler
[MonoModIgnore]
private GameManager gm;
+ // todo: make IL hook: add lockstate none before each ret
// Reverted cursor behavior
[MonoModReplace]
private void OnGUI()
{
Cursor.lockState = CursorLockMode.None;
- if (isTitleScreenScene)
+ if (this.isTitleScreenScene)
{
Cursor.visible = false;
return;
}
-
- if (!isMenuScene)
+ if (this.isMenuScene)
{
- ModHooks.OnCursor(gm);
+ Cursor.visible = !this.controllerPressed;
return;
}
-
- if (controllerPressed)
+ if (!this.gm.isPaused)
{
Cursor.visible = false;
return;
}
-
- Cursor.visible = true;
+ Cursor.visible = !this.controllerPressed;
}
}
}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/Language.cs b/Assembly-CSharp/Patches/Language.cs
deleted file mode 100644
index 5fbd34c2..00000000
--- a/Assembly-CSharp/Patches/Language.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Collections.Generic;
-using MonoMod;
-using UnityEngine;
-
-// ReSharper disable All
-#pragma warning disable 1591, CS0649
-
-namespace Modding.Patches
-{
- [MonoModPatch("global::Language.Language")]
- public static class Language
- {
- [MonoModIgnore]
- private static Dictionary> currentEntrySheets;
-
- public static string GetInternal(string key, string sheetTitle)
- {
- if (currentEntrySheets == null || !currentEntrySheets.ContainsKey(sheetTitle))
- {
- Debug.LogError($"The sheet with title \"{sheetTitle}\" does not exist!");
- return string.Empty;
- }
-
- if (currentEntrySheets[sheetTitle].ContainsKey(key))
- {
- return currentEntrySheets[sheetTitle][key];
- }
-
- return "#!#" + key + "#!#";
- }
-
- public static string Get(string key, string sheetTitle)
- {
- return ModHooks.LanguageGet(key, sheetTitle);
- }
- }
-}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/MenuSelectable.cs b/Assembly-CSharp/Patches/MenuSelectable.cs
index 5b2abbff..a906f8e6 100644
--- a/Assembly-CSharp/Patches/MenuSelectable.cs
+++ b/Assembly-CSharp/Patches/MenuSelectable.cs
@@ -60,6 +60,14 @@ public enum CancelAction
ApplyVideoSettings,
ApplyGameSettings,
ApplyKeyboardSettings,
+ GoToExtrasMenu,
+ ApplyControllerSettings,
+ GoToExplicitSwitchUser,
+ ReturnToProfileMenu,
+ ApplyAdvancedVideoSettings,
+ ApplyAdvancedControllerSettings,
+
+ // Added for the dynamic menu API
CustomCancelAction
}
}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/MenuSetting.cs b/Assembly-CSharp/Patches/MenuSetting.cs
index 51f1b298..c8ff0871 100644
--- a/Assembly-CSharp/Patches/MenuSetting.cs
+++ b/Assembly-CSharp/Patches/MenuSetting.cs
@@ -55,16 +55,23 @@ public enum MenuSettingType
VSync,
// where did 13 go
MonitorSelect = 14,
- FrameCap,
+ SwitchFrameCap,
ParticleLevel,
ShaderQuality,
+ Dithering,
+ Noise,
// HUH????
GameLanguage = 33,
GameBackerCredits,
NativeAchievements,
+ ControllerRumble = 37,
+ HudVisibility = 39,
+ CameraShake,
NativeInput,
- ControllerRumble,
- // peepoHappy
+ XInput,
+ MFi,
+
+ // Added for the dynamic menu API
CustomSetting
}
}
diff --git a/Assembly-CSharp/Patches/OnScreenDebugInfo.cs b/Assembly-CSharp/Patches/OnScreenDebugInfo.cs
deleted file mode 100644
index a04d41a0..00000000
--- a/Assembly-CSharp/Patches/OnScreenDebugInfo.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System.Threading;
-using MonoMod;
-using UnityEngine;
-
-// ReSharper disable All
-#pragma warning disable 1591, CS0626
-
-namespace Modding.Patches
-{
- [MonoModPatch("global::OnScreenDebugInfo")]
- public class OnScreenDebugInfo : global::OnScreenDebugInfo
- {
- private extern void orig_Awake();
-
- private void Awake()
- {
- if (ModLoader.LoadState == ModLoader.ModLoadState.NotStarted)
- {
- Logger.APILogger.Log("Main menu loading");
- ModLoader.LoadState = ModLoader.ModLoadState.Started;
-
- GameObject obj = new GameObject();
- DontDestroyOnLoad(obj);
-
- // Preload reflection
- new Thread(ReflectionHelper.PreloadCommonTypes).Start();
-
- // NonBouncer does absolutely nothing, which makes it a good dummy to run the loader
- obj.AddComponent().StartCoroutine(ModLoader.LoadModsInit(obj));
- }
- else
- {
- // Debug log because this is the expected code path
- Logger.APILogger.LogDebug($"OnScreenDebugInfo: Already begun mod loading (state {ModLoader.LoadState})");
- }
-
- orig_Awake();
- }
- }
-}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/Platform.cs b/Assembly-CSharp/Patches/Platform.cs
index 28b67b31..0bc59fe2 100644
--- a/Assembly-CSharp/Patches/Platform.cs
+++ b/Assembly-CSharp/Patches/Platform.cs
@@ -1,4 +1,5 @@
-using MonoMod;
+using System;
+using MonoMod;
// ReSharper disable all
#pragma warning disable 1591, 108, 114
@@ -8,9 +9,17 @@ namespace Modding.Patches
[MonoModPatch("global::Platform")]
public abstract class Platform : global::Platform
{
+ [Obsolete("Please update your mod to the new HK version and use `RoamingSharedData` instead")]
+ public ISharedData EncryptedSharedData
+ {
+ get { return RoamingSharedData; }
+ }
+
+ [MonoModReplace]
public static bool IsSaveSlotIndexValid(int slotIndex) => true;
// ReSharper disable once UnusedMember.Global
+ [MonoModReplace]
protected string GetSaveSlotFileName(int slotIndex, SaveSlotFileNameUsage usage)
{
string text = slotIndex == 0 ? "user.dat" : $"user{slotIndex}.dat";
diff --git a/Assembly-CSharp/Patches/PlayMakerUnity2DProxy.cs b/Assembly-CSharp/Patches/PlayMakerUnity2DProxy.cs
index 9cd2d27b..3f671904 100644
--- a/Assembly-CSharp/Patches/PlayMakerUnity2DProxy.cs
+++ b/Assembly-CSharp/Patches/PlayMakerUnity2DProxy.cs
@@ -9,6 +9,7 @@ namespace Modding.Patches
[MonoModPatch("global::PlayMakerUnity2DProxy")]
public class PlayMakerUnity2DProxy : global::PlayMakerUnity2DProxy
{
+ [MonoModReplace]
public void Start()
{
if (!PlayMakerUnity2d.isAvailable())
@@ -23,7 +24,7 @@ public void Start()
}
ModHooks.OnColliderCreate(gameObject);
- RefreshImplementation();
+ this.RefreshImplementation();
}
}
}
\ No newline at end of file
diff --git a/Assembly-CSharp/Patches/SceneManager.cs b/Assembly-CSharp/Patches/SceneManager.cs
index 677dfbbd..efc9876d 100644
--- a/Assembly-CSharp/Patches/SceneManager.cs
+++ b/Assembly-CSharp/Patches/SceneManager.cs
@@ -20,12 +20,14 @@ public class SceneManager : global::SceneManager
[MonoModIgnore]
private bool heroInfoSent;
+ // [MonoModIgnore]
private extern void orig_Update();
[MonoModIgnore]
private GameManager gm;
//Added checks for null and an attempt to fix any missing references
+ // [MonoModReplace]
private void Update()
{
if (this.gameplayScene)
@@ -40,40 +42,51 @@ private void Update()
orig_Update();
}
+ [MonoModIgnore]
+ private Transform borderLeft;
+
+ [MonoModIgnore]
+ private Transform borderRight;
+
+ [MonoModIgnore]
+ private Transform borderUp;
+
+ [MonoModIgnore]
+ private Transform borderDown;
+
+ // [MonoModIgnore]
+ private extern void orig_OnCameraAspectChanged(float aspect);
+
//add modhook to send the newly created borders to any mods that want them
- [MonoModReplace]
- private void DrawBlackBorders()
+ // [MonoModReplace]
+ private void OnCameraAspectChanged(float aspect)
{
- List borders = new List();
- GameObject gameObject = UnityEngine.Object.Instantiate(this.borderPrefab);
- gameObject.transform.SetPosition2D(this.gm.sceneWidth + 10f, this.gm.sceneHeight / 2f);
- gameObject.transform.localScale = new Vector2(20f, this.gm.sceneHeight + 40f);
- borders.Add(gameObject);
-
- gameObject = UnityEngine.Object.Instantiate(this.borderPrefab);
- gameObject.transform.SetPosition2D(-10f, this.gm.sceneHeight / 2f);
- gameObject.transform.localScale = new Vector2(20f, this.gm.sceneHeight + 40f);
- borders.Add(gameObject);
-
- gameObject = UnityEngine.Object.Instantiate(this.borderPrefab);
- gameObject.transform.SetPosition2D(this.gm.sceneWidth / 2f, this.gm.sceneHeight + 10f);
- gameObject.transform.localScale = new Vector2(40f + this.gm.sceneWidth, 20f);
- borders.Add(gameObject);
-
- gameObject = UnityEngine.Object.Instantiate(this.borderPrefab);
- gameObject.transform.SetPosition2D(this.gm.sceneWidth / 2f, -10f);
- gameObject.transform.localScale = new Vector2(40f + this.gm.sceneWidth, 20f);
- borders.Add(gameObject);
+ orig_OnCameraAspectChanged(aspect);
- ModHooks.OnDrawBlackBorders(borders);
-
- foreach (var border in borders)
+ List borders = new List();
+ if (this.borderLeft != null)
+ {
+ borders.Add(this.borderLeft.gameObject);
+ }
+ if (this.borderRight != null)
+ {
+ borders.Add(this.borderRight.gameObject);
+ }
+ if (this.borderUp != null)
+ {
+ borders.Add(this.borderUp.gameObject);
+ }
+ if (this.borderDown != null)
{
- UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(border, base.gameObject.scene);
+ borders.Add(this.borderDown.gameObject);
}
+ ModHooks.OnDrawBlackBorders(borders);
}
+ // [MonoModIgnore]
private extern void orig_Start();
+
+ // [MonoModReplace]
private void Start()
{
try
diff --git a/Assembly-CSharp/Patches/StartManager.cs b/Assembly-CSharp/Patches/StartManager.cs
index 01b8dbb1..7a569ccd 100644
--- a/Assembly-CSharp/Patches/StartManager.cs
+++ b/Assembly-CSharp/Patches/StartManager.cs
@@ -1,6 +1,10 @@
-using System.Collections;
+using System;
+using System.Collections;
+using System.Threading;
using MonoMod;
using UnityEngine;
+using UObject = UnityEngine.Object;
+using Lang = Language.Language;
// ReSharper disable All
#pragma warning disable 1591, CS0649
@@ -12,6 +16,37 @@ namespace Modding.Patches
[MonoModPatch("global::StartManager")]
public class StartManager : global::StartManager
{
+ private bool startedPreloading = false;
+ private MonoBehaviour modLoaderObj = null;
+
+ private extern void orig_Awake();
+
+ private void Awake()
+ {
+ if (ModLoader.LoadState == ModLoader.ModLoadState.NotStarted)
+ {
+ Logger.APILogger.Log("Main menu loading");
+ startedPreloading = true;
+ ModLoader.LoadState = ModLoader.ModLoadState.Started;
+
+ GameObject obj = new GameObject();
+ DontDestroyOnLoad(obj);
+
+ // Preload reflection
+ new Thread(ReflectionHelper.PreloadCommonTypes).Start();
+
+ // NonBouncer does absolutely nothing, which makes it a good dummy to run the loader
+ modLoaderObj = obj.AddComponent();
+ }
+ else
+ {
+ // Debug log because this is the expected code path
+ Logger.APILogger.LogDebug($"StartManager: Already begun mod loading (state {ModLoader.LoadState})");
+ }
+
+ orig_Awake();
+ }
+
[MonoModIgnore]
private bool confirmedLanguage;
@@ -30,11 +65,18 @@ public class StartManager : global::StartManager
[MonoModIgnore]
private extern IEnumerator LanguageSettingDone();
+ [MonoModReplace]
private IEnumerator Start()
{
this.controllerImage.sprite = this.GetControllerSpriteForPlatform(this.platform);
- AsyncOperation loadOperation = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Menu_Title");
- loadOperation.allowSceneActivation = false;
+
+ AsyncOperation loadOperation = null;
+ if (!startedPreloading)
+ {
+ loadOperation = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Menu_Title");
+ loadOperation.allowSceneActivation = false;
+ }
+ Platform.Current.SetSceneLoadState(true, false);
bool showLanguageSelect = !this.CheckIsLanguageSet();
if (showLanguageSelect && Platform.Current.ShowLanguageSelect)
{
@@ -46,14 +88,73 @@ private IEnumerator Start()
yield return base.StartCoroutine(this.LanguageSettingDone());
}
-
+ TeamCherry.Localization.LanguageCode currentLanguage = (TeamCherry.Localization.LanguageCode) Lang.CurrentLanguage();
+ while (!Platform.Current.IsSharedDataMounted)
+ {
+ yield return null;
+ }
+ bool flag = false;
+ string text;
+ if (TeamCherry.Localization.LocalizationProjectSettings.TryGetSavedLanguageCode(out text))
+ {
+ TeamCherry.Localization.LanguageCode languageEnum = TeamCherry.Localization.LocalizationSettings.GetLanguageEnum(text);
+ if (currentLanguage != languageEnum)
+ {
+ flag = true;
+ }
+ }
+ if (flag)
+ {
+ Lang.LoadLanguage();
+ ChangeFontByLanguage[] array = UObject.FindObjectsByType(FindObjectsSortMode.None);
+ for (int i = 0; i < array.Length; i++)
+ {
+ array[i].SetFont();
+ }
+ SetTextMeshProGameText[] componentsInChildren = base.GetComponentsInChildren(true);
+ for (int i = 0; i < componentsInChildren.Length; i++)
+ {
+ componentsInChildren[i].UpdateText();
+ }
+ LogoLanguage[] componentsInChildren2 = base.GetComponentsInChildren(true);
+ for (int i = 0; i < componentsInChildren2.Length; i++)
+ {
+ componentsInChildren2[i].SetSprite();
+ }
+ }
this.startManagerAnimator.SetBool("WillShowControllerNotice", false);
this.startManagerAnimator.SetBool("WillShowQuote", true);
StandaloneLoadingSpinner loadSpinner = UnityEngine.Object.Instantiate(this.loadSpinnerPrefab);
loadSpinner.Setup(null);
- loadOperation.allowSceneActivation = true;
- yield return loadOperation;
+ bool didWaitForPlayerPrefs = false;
+ while (!Platform.Current.IsPlayerPrefsLoaded)
+ {
+ if (!didWaitForPlayerPrefs)
+ {
+ didWaitForPlayerPrefs = true;
+ Debug.LogFormat("Waiting for PlayerPrefs load...", Array.Empty