using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CommonAPI; using CrewBoom.Behaviours; using CrewBoom.Compatibility; using CrewBoom.Data; using CrewBoom.Database; using CrewBoom.Mono; using CrewBoom.Properties; using CrewBoom.Utility; using CrewBoomAPI; using CrewBoomMono; using HarmonyLib; using Microsoft.CodeAnalysis; using Reptile; using Reptile.Phone; using TMPro; using UnityEngine; using UnityEngine.Audio; using UnityEngine.Events; using UnityEngine.Playables; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6", FrameworkDisplayName = ".NET Framework 4.6")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("CrewBoom")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("A plugin to load custom skins and characters for Bomb Rush Cyberfunk.")] [assembly: AssemblyFileVersion("4.2.0.0")] [assembly: AssemblyInformationalVersion("4.2.0+dabe070583f8c672c6e79d8343dd7bc3c6980984")] [assembly: AssemblyProduct("CrewBoom")] [assembly: AssemblyTitle("CrewBoom")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.2.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CrewBoom { public static class CharacterDatabase { private static readonly string ASSET_PATH = Path.Combine(Paths.ConfigPath, "CrewBoom"); private static readonly string NO_CYPHER_PATH = Path.Combine(ASSET_PATH, "no_cypher"); private static Dictionary _characterBundlePaths; private static Dictionary _customCharacters; private static Dictionary _cypherMapping; private static Dictionary> _characterIds; public static Shader GraffitiShader = null; private static ManualLogSource DebugLog = Logger.CreateLogSource("CrewBoom Database"); private static bool _appliedGrafShaders = false; public static int NewCharacterCount { get; private set; } = 0; public static bool HasCharacterOverride { get; private set; } public static Guid CharacterOverride { get; private set; } public static bool Initialize() { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Invalid comparison between Unknown and I4 //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Invalid comparison between Unknown and I4 //IL_00c4: Unknown result type (might be due to invalid IL or missing references) if (!Directory.Exists(ASSET_PATH)) { DebugLog.LogWarning((object)("Could not find character bundle directory \"" + ASSET_PATH + "\".\nIt was created instead.")); Directory.CreateDirectory(ASSET_PATH); return false; } if (!Directory.Exists(NO_CYPHER_PATH)) { DebugLog.LogMessage((object)"No cypher bundle path was not found. It was created instead."); Directory.CreateDirectory(NO_CYPHER_PATH); } _characterBundlePaths = new Dictionary(); _customCharacters = new Dictionary(); _cypherMapping = new Dictionary(); _characterIds = new Dictionary>(); foreach (Characters value in Enum.GetValues(typeof(Characters))) { if ((int)value == -1 || (int)value == 26) { _characterIds.Add(value, null); } else { _characterIds.Add(value, new List()); } } if (!LoadAllCharacterData()) { DebugLog.LogWarning((object)("There were no valid characters found in " + ASSET_PATH + ".\nMake sure your character bundles (.cbb) are in the CONFIG folder, NOT the PLUGIN folder.")); return false; } InitializeAPI(); return true; } private static bool LoadAllCharacterData() { int num = 0; bool result = false; string[] files = Directory.GetFiles(ASSET_PATH, "*.cbb"); for (int i = 0; i < files.Length; i++) { if (LoadCharacterBundle(files[i], enableCypher: true, out var generatedStream)) { result = true; if (generatedStream) { num++; } } } files = Directory.GetFiles(NO_CYPHER_PATH, "*.cbb"); for (int i = 0; i < files.Length; i++) { if (LoadCharacterBundle(files[i], enableCypher: false, out var generatedStream2)) { result = true; if (generatedStream2) { num++; } } } files = Directory.GetFiles(Paths.PluginPath, "*.cbb", SearchOption.AllDirectories); for (int i = 0; i < files.Length; i++) { if (LoadCharacterBundle(files[i], enableCypher: true, out var generatedStream3)) { result = true; if (generatedStream3) { num++; } } } if (num > 0) { if (CrewBoomSettings.UpdateCBBs) { DebugLog.LogInfo((object)$"Updated {num} .cbb files with stream data!"); } else { DebugLog.LogInfo((object)$"Created stream files (.ldcs) for {num} .cbb files!"); } } return result; } private static bool LoadCharacterBundle(string filePath, bool enableCypher) { bool generatedStream; return LoadCharacterBundle(filePath, enableCypher, out generatedStream); } private static bool SafelyAppendEmbedded(string filePath, EmbeddedBundle embedded, CharacterStreamData streamData) { string text = filePath + ".bak"; if (File.Exists(text)) { File.Delete(text); } File.Copy(filePath, text); try { embedded.OpenWrite(); embedded.AppendStreamData(streamData); } catch (Exception arg) { embedded.Close(); File.Replace(text, filePath, null); DebugLog.LogError((object)("Failed to update CBB for \"" + filePath + "\"")); DebugLog.LogError((object)$"{arg}"); return false; } File.Delete(text); return true; } private static bool LoadCharacterBundle(string filePath, bool enableCypher, out bool generatedStream) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Expected O, but got Unknown //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02ad: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Invalid comparison between Unknown and I4 //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02ea: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_02f8: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Invalid comparison between Unknown and I4 //IL_0346: Unknown result type (might be due to invalid IL or missing references) generatedStream = false; string fileName = Path.GetFileName(filePath); string path = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + ".json"); string path2 = Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath) + ".ldcs"); BrcCharacter val = (BrcCharacter)(-1); if (File.Exists(path)) { string text = File.ReadAllText(path); try { CharacterConfig val2 = JsonUtility.FromJson(text); if (Enum.TryParse(val2.CharacterToReplace, out BrcCharacter result)) { val = result; } else { DebugLog.LogWarning((object)("The configured replacement character for the bundle " + fileName + " (\"" + val2.CharacterToReplace + "\") is not a valid character!")); } } catch (Exception) { DebugLog.LogError((object)("Failed to read JSON config for \"" + fileName + "\"")); } } CharacterDefinition val3 = null; CharacterStreamData val4 = null; try { EmbeddedBundle val5 = new EmbeddedBundle(filePath); try { val5.OpenRead(); if (!val5.TryRetrieveStreamData(ref val4)) { if (File.Exists(path2)) { val4 = new CharacterStreamData(); using (FileStream input = new FileStream(path2, FileMode.Open, FileAccess.Read)) { using BinaryReader binaryReader = new BinaryReader(input); val4.Read(binaryReader, CrewBoomSettings.UpdateCBBs); } if (CrewBoomSettings.UpdateCBBs) { generatedStream = SafelyAppendEmbedded(filePath, val5, val4); } } else { AssetBundle val6 = val5.LoadAssetBundle(); GameObject[] array = val6.LoadAllAssets(); for (int i = 0; i < array.Length; i++) { val3 = array[i].GetComponent(); if (!((Object)(object)val3 != (Object)null)) { continue; } val4 = new CharacterStreamData(); val4.FromCharacter(val3); if (CrewBoomSettings.UpdateCBBs) { generatedStream = SafelyAppendEmbedded(filePath, val5, val4); break; } using (FileStream output = new FileStream(path2, FileMode.Create, FileAccess.Write)) { using BinaryWriter binaryWriter = new BinaryWriter(output); val4.Write(binaryWriter); } generatedStream = true; break; } val6.Unload(true); } } } finally { ((IDisposable)val5)?.Dispose(); } } catch (Exception arg) { DebugLog.LogError((object)("Failed to load bundle for \"" + fileName + "\"")); DebugLog.LogError((object)$"{arg}"); if (val4 != null) { val4.Release(); } return false; } if (val4 == null) { return false; } Guid guid = Guid.Parse(val4.Id); if (_characterBundlePaths.ContainsKey(guid)) { DebugLog.LogError((object)$"Failed to load \"{fileName}\" - there already is a character with the same GUID ({guid})"); val4.Release(); return false; } _characterBundlePaths[guid] = filePath; SfxCollectionID sfxID = (SfxCollectionID)(-1); if ((int)val != -1) { _characterIds[(Characters)val].Add(guid); } else { NewCharacterCount++; Characters key = (Characters)(26 + NewCharacterCount); sfxID = (SfxCollectionID)(67 + NewCharacterCount); if (_characterIds.ContainsKey(key)) { _characterIds[key].Add(guid); } else { _characterIds.Add(key, new List { guid }); } _cypherMapping.Add(guid, enableCypher); } bool replacement = (int)val != -1; bool forceLoad = false; if (!CrewBoomSettings.StreamCharacters) { forceLoad = true; } CustomCharacter value = new CustomCharacter(val4, sfxID, filePath, replacement, forceLoad); _customCharacters.Add(guid, value); return true; } public static void RefreshShaders() { _appliedGrafShaders = false; foreach (CustomCharacter value in _customCharacters.Values) { if (value.Loaded) { value.FixCharacterShader(); } } } public static void SetGraffitiShader(Shader shader) { if (_appliedGrafShaders || (Object)(object)shader == (Object)null) { return; } foreach (CustomCharacter value in _customCharacters.Values) { value.ApplyShaderToGraffiti(shader); } _appliedGrafShaders = true; } private static void InitializeAPI() { Dictionary dictionary = new Dictionary(); int num = 26; for (int i = num + 1; i <= num + NewCharacterCount; i++) { if (GetFirstOrConfigCharacterId((Characters)i, out var guid)) { dictionary.Add(i, guid); } } CrewBoomAPIDatabase.Initialize(dictionary); CrewBoomAPIDatabase.OnOverride += SetCharacterOverride; } private static void SetCharacterOverride(Guid id) { HasCharacterOverride = true; CharacterOverride = id; DebugLog.LogInfo((object)$"Received override for next character {id}"); } public static void SetCharacterOverrideDone() { HasCharacterOverride = false; DebugLog.LogInfo((object)"Finished override"); } public static void InitializeMissingSfxCollections(Characters character, SfxCollection collection) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!_characterIds.TryGetValue(character, out var value) || value == null || value.Count <= 0) { return; } foreach (Guid item in value) { if (GetCharacter(item, out var characterObject)) { characterObject.ApplySfxCollection(collection); } } } public static bool GetCharacterNameWithId(int localizationId, out string name) { name = string.Empty; switch (localizationId) { case 0: return false; case 6: return GetCharacterName((Characters)0, out name); case 10: return GetCharacterName((Characters)1, out name); case 24: return GetCharacterName((Characters)2, out name); case 4: return GetCharacterName((Characters)3, out name); case 3: return GetCharacterName((Characters)4, out name); case 5: return GetCharacterName((Characters)5, out name); case 26: return GetCharacterName((Characters)6, out name); case 12: if (GetCharacterName((Characters)7, out name)) { return true; } return GetCharacterName((Characters)24, out name); case 15: return GetCharacterName((Characters)8, out name); case 7: return GetCharacterName((Characters)9, out name); case 11: return GetCharacterName((Characters)10, out name); case 13: return GetCharacterName((Characters)11, out name); case 2: if (GetCharacterName((Characters)12, out name)) { return true; } return GetCharacterName((Characters)23, out name); case 8: return GetCharacterName((Characters)13, out name); case 16: return GetCharacterName((Characters)14, out name); case 21: return GetCharacterName((Characters)15, out name); case 20: return GetCharacterName((Characters)16, out name); case 30: return GetCharacterName((Characters)17, out name); case 31: return GetCharacterName((Characters)18, out name); case 28: return GetCharacterName((Characters)19, out name); case 14: return GetCharacterName((Characters)20, out name); case 25: return GetCharacterName((Characters)21, out name); case 27: return GetCharacterName((Characters)22, out name); case 22: return GetCharacterName((Characters)25, out name); default: return false; } } private static bool GetCharacterName(Characters character, out string name) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) name = string.Empty; if (GetCharacter(character, out var characterObject)) { name = characterObject.StreamData.Name; return true; } return false; } public static bool GetFirstOrConfigCharacterId(Characters character, out Guid guid) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) guid = Guid.Empty; if (HasCharacterOverride) { DebugLog.LogInfo((object)$"Getting override for {character} with ID {CharacterOverride}"); if (_characterBundlePaths.ContainsKey(CharacterOverride) && _customCharacters.ContainsKey(CharacterOverride)) { DebugLog.LogInfo((object)"Override was found locally."); guid = CharacterOverride; return true; } } if (!_characterIds.TryGetValue(character, out var value) || value == null || value.Count == 0) { return false; } if (CharacterDatabaseConfig.GetCharacterOverride(character, out var id, out var isDisabled)) { if (_characterBundlePaths.ContainsKey(id) && _customCharacters.ContainsKey(id)) { guid = id; return true; } } else if (isDisabled) { return false; } guid = value[0]; return true; } public static bool GetCharacter(Guid id, out CustomCharacter characterObject) { if (!_customCharacters.TryGetValue(id, out characterObject)) { return false; } return true; } public static bool GetCharacter(Characters character, out CustomCharacter characterObject) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) characterObject = null; if (GetFirstOrConfigCharacterId(character, out var guid)) { GetCharacter(guid, out characterObject); } return characterObject != null; } public static bool GetCharacterWithGraffitiTitle(string title, out CustomCharacter characterObject) { characterObject = null; foreach (CustomCharacter value in _customCharacters.Values) { if (value.Graffiti != null && value.Graffiti.title == title) { characterObject = value; return true; } } return false; } public static bool HasCharacter(Characters character) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (!_characterIds.TryGetValue(character, out var value)) { return false; } if (value != null) { return value.Count > 0; } return false; } public static bool HasCypherEnabledForCharacter(Characters character) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 if (!GetFirstOrConfigCharacterId(character, out var guid)) { return false; } if (GetCharacter(character, out var characterObject)) { if ((int)characterObject.StreamData.UnlockType == 2) { return false; } if ((int)characterObject.StreamData.UnlockType == 1 && CharacterSaveSlots.GetCharacterData(guid, out var progress)) { return progress.unlocked; } } if (_cypherMapping.TryGetValue(guid, out var value)) { return value; } return false; } public static bool GetCharacterValueFromGuid(Guid guid, out Characters character) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected I4, but got Unknown character = (Characters)(-1); foreach (KeyValuePair> characterId in _characterIds) { if (characterId.Value != null && characterId.Value.Contains(guid)) { character = (Characters)(int)characterId.Key; return true; } } return false; } } public static class CharacterDatabaseConfig { private const string CONFIG_DESCRIPTION = "Enter a GUID of a character bundle to always load for {0} (Blank = Auto-detect, \"OFF\" = Default character for you)"; private static ConfigEntry[] _characterIdOverrides; public static void Initialize(ConfigFile config) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Invalid comparison between Unknown and I4 //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) Array values = Enum.GetValues(typeof(Characters)); _characterIdOverrides = new ConfigEntry[values.Length - 2]; foreach (Characters item in values) { if ((int)item != -1 && (int)item != 26) { BrcCharacter val2 = (BrcCharacter)item; _characterIdOverrides[item] = config.Bind("Replacement IDs", ((object)(BrcCharacter)(ref val2)).ToString(), (string)null, $"Enter a GUID of a character bundle to always load for {val2} (Blank = Auto-detect, \"OFF\" = Default character for you)"); } } } public static bool GetCharacterOverride(Characters character, out Guid id, out bool isDisabled) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_001a: Unknown result type (might be due to invalid IL or missing references) id = Guid.Empty; isDisabled = false; if ((int)character > 26) { return false; } string value = _characterIdOverrides[character].Value; if (value == string.Empty) { return false; } if (value == "OFF") { isDisabled = true; return false; } if (Guid.TryParse(value, out id)) { return true; } return false; } } public class CharacterSaveSlots { public const int SAVE_SLOT_COUNT = 4; public const string SLOT_FILE_EXTENSION = ".cbs"; public const string SAVE_FILE_EXTENSION = ".cbc"; public static readonly string SAVE_PATH = Path.Combine(Paths.ConfigPath, "CrewBoom", "saves"); public static CharacterSaveSlot CurrentSaveSlot; private static Dictionary _progressLookup = new Dictionary(); public static ManualLogSource DebugLog = Logger.CreateLogSource("CrewBoom Saves"); public static int CurrentSaveSlotId { get; private set; } = -1; public static void LoadSlot(int slot) { if (!Directory.Exists(SAVE_PATH)) { Directory.CreateDirectory(SAVE_PATH); return; } string path = Path.Combine(SAVE_PATH, slot + ".cbs"); if (File.Exists(path)) { try { using FileStream input = File.OpenRead(path); using BinaryReader reader = new BinaryReader(input); CurrentSaveSlot.Read(reader); } catch (Exception) { DebugLog.LogWarning((object)$"Failed to read slot data for slot {slot}"); } DebugLog.LogMessage((object)$"Loaded custom character save slot {slot}"); } CurrentSaveSlotId = slot; } public static void SaveSlot() { if (CurrentSaveSlotId == -1) { return; } if (!Directory.Exists(SAVE_PATH)) { Directory.CreateDirectory(SAVE_PATH); } string path = Path.Combine(SAVE_PATH, CurrentSaveSlotId + ".cbs"); try { using FileStream output = File.OpenWrite(path); using BinaryWriter writer = new BinaryWriter(output); CurrentSaveSlot.Write(writer); } catch (Exception) { DebugLog.LogError((object)$"Failed to write slot data for slot {CurrentSaveSlotId}"); } } public static bool GetCharacterData(Guid guid, out CharacterProgress progress) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown if (_progressLookup.TryGetValue(guid, out progress)) { return true; } progress = new CharacterProgress(); progress.unlocked = false; if (CurrentSaveSlotId == -1) { LogUninitialized(); return false; } if (!EnsureSlotDirectory(out var slotPath)) { return false; } string path = CharacterFilePath(slotPath, guid); if (!File.Exists(path)) { if (CharacterDatabase.GetCharacter(guid, out var characterObject)) { progress = new CharacterProgress { outfit = 0, moveStyle = (MoveStyle)characterObject.StreamData.DefaultMoveStyle, moveStyleSkin = 0 }; _progressLookup.Add(guid, progress); return true; } return false; } try { using (FileStream input = File.OpenRead(path)) { using BinaryReader binaryReader = new BinaryReader(input); progress.Read(binaryReader); } _progressLookup.Add(guid, progress); return true; } catch (Exception) { DebugLog.LogError((object)$"Could not load character save data for character with GUID \"{guid}\"."); } return false; } public static void SaveCharacterData(Guid guid) { if (CurrentSaveSlotId == -1) { LogUninitialized(); return; } EnsureSlotDirectory(out var slotPath); if (!_progressLookup.TryGetValue(guid, out var value)) { DebugLog.LogError((object)$"No save data made for character with GUID \"{guid}\"."); return; } string path = CharacterFilePath(slotPath, guid); try { using FileStream output = File.OpenWrite(path); using BinaryWriter binaryWriter = new BinaryWriter(output); value.Write(binaryWriter); } catch (Exception) { DebugLog.LogError((object)$"Could not write character save data for character with GUID \"{guid}\"."); } } private static bool EnsureSlotDirectory(out string slotPath) { bool result = true; if (!Directory.Exists(SAVE_PATH)) { Directory.CreateDirectory(SAVE_PATH); result = false; } slotPath = Path.Combine(SAVE_PATH, CurrentSaveSlotId.ToString()); if (!Directory.Exists(slotPath)) { Directory.CreateDirectory(slotPath); result = false; } return result; } private static string CharacterFilePath(string slotPath, Guid guid) { return Path.Combine(slotPath, guid.ToString() + ".cbc"); } private static void LogUninitialized() { DebugLog.LogWarning((object)"Can't read or write character data before slot was initialized!"); } } public struct CharacterSaveSlot { public Guid LastPlayedCharacter; public void Write(BinaryWriter writer) { writer.Write(LastPlayedCharacter.ToString()); } public void Read(BinaryReader reader) { Guid.TryParse(reader.ReadString(), out LastPlayedCharacter); } } [BepInPlugin("CrewBoom", "CrewBoom", "4.2.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string CharacterAPIGuid = "com.Viliger.CharacterAPI"; private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected O, but got Unknown if (Chainloader.PluginInfos.ContainsKey("com.Viliger.CharacterAPI")) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"LD CrewBoom is incompatible with CharacterAPI (viliger) and will not load!\nUninstall CharacterAPI and restart the game if you want to use LD CrewBoom."); return; } ((BaseUnityPlugin)this).Logger.LogMessage((object)"LD CrewBoom v4.2.0 starting..."); CrewBoomSettings.Initialize(((BaseUnityPlugin)this).Config); CharacterDatabaseConfig.Initialize(((BaseUnityPlugin)this).Config); if (CharacterDatabase.Initialize()) { new Harmony("softGoat.crewBoom").PatchAll(); ((BaseUnityPlugin)this).Logger.LogMessage((object)"Loaded all available characters!"); } if (Chainloader.PluginInfos.ContainsKey("com.Dragsun.BunchOfEmotes")) { BunchOfEmotesSupport.Initialize(); StageManager.OnStagePostInitialization += new OnStageInitializedDelegate(BoE_StageManager_OnStagePostInitialization); } StageManager.OnStagePostInitialization += new OnStageInitializedDelegate(StageManager_OnStagePostInitialization); } private void Update() { CharacterStreamer.Update(Time.deltaTime); } private void BoE_StageManager_OnStagePostInitialization() { BunchOfEmotesSupport.CacheAnimations(); } private void StageManager_OnStagePostInitialization() { CharacterDatabase.RefreshShaders(); Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if ((Object)(object)currentPlayer != (Object)null) { PlayerStreamingComponent.GetOrCreate(currentPlayer).WaitForLoadSync(); } } } public static class CharUtil { public const string CHARACTER_BUNDLE = "characters"; public const string ADD_CHARACTER_METHOD = "AddCharacterFBX"; public const string ADD_MATERIAL_METHOD = "AddCharacterMaterial"; public const string MATERIAL_FORMAT = "{0}Mat{1}"; public const string SKATE_OFFSET_L = "skateOffsetL"; public const string SKATE_OFFSET_R = "skateOffsetR"; public const string GRAFFITI_ASSET = "charGraffiti"; private static readonly string[] PropBones = new string[7] { "propl", "propr", "footl", "footr", "handl", "handr", "jetpackPos" }; public static string GetOutfitMaterialName(Characters character, int outfitIndex) { return $"{((object)(Characters)(ref character)).ToString()}Mat{outfitIndex.ToString()}"; } public static void ReparentAllProps(Transform originalRoot, Transform targetRoot) { string[] propBones = PropBones; foreach (string text in propBones) { Transform val = TransformExtentions.FindRecursive(originalRoot, text); Transform val2 = TransformExtentions.FindRecursive(targetRoot, text); if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2)) { ReparentChildren(val, val2); } } } private static void ReparentChildren(Transform source, Transform target) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) Transform[] componentsInChildren = ((Component)source).GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { if (!((Object)(object)componentsInChildren[i] == (Object)null)) { componentsInChildren[i].SetParent(target, false); componentsInChildren[i].SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); } } } public static bool TrySetCustomOutfit(Component source, int outfit, out SkinnedMeshRenderer firstActiveRenderer) { firstActiveRenderer = null; CharacterDefinition componentInChildren = source.GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.SetOutfit(outfit, out firstActiveRenderer); return true; } return false; } public static int GetSavedCharacterOutfit(Characters character) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) int result = 0; if ((int)character > 26 && CharacterDatabase.GetFirstOrConfigCharacterId(character, out var guid)) { if (CharacterSaveSlots.GetCharacterData(guid, out var progress)) { result = progress.outfit; } } else { result = Core.Instance.SaveManager.CurrentSaveSlot.GetCharacterProgress(character).outfit; } return result; } } public static class VoiceUtility { public static SfxCollectionID VoiceCollectionFromCharacter(Characters character) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Expected I4, but got Unknown return (SfxCollectionID)((int)character switch { 0 => 40, 1 => 38, 2 => 47, 3 => 44, 4 => 31, 5 => 48, 6 => 30, 7 => 36, 8 => 35, 9 => 34, 10 => 43, 11 => 32, 12 => 50, 13 => 45, 14 => 41, 15 => 42, 16 => -1, 17 => 63, 18 => 64, 19 => 49, 20 => 39, 21 => 46, 22 => 33, 23 => 51, 24 => 37, 25 => 44, _ => -1, }); } public static Characters CharacterFromVoiceCollection(SfxCollectionID collectionID) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Expected I4, but got Unknown return (Characters)((collectionID - 30) switch { 0 => 6, 1 => 4, 2 => 11, 3 => 22, 4 => 9, 5 => 8, 6 => 7, 7 => 24, 8 => 1, 9 => 20, 10 => 0, 20 => 12, 21 => 23, 11 => 14, 12 => 15, 13 => 10, 14 => 3, 15 => 13, 16 => 21, 17 => 2, 18 => 5, 19 => 19, 33 => 17, 34 => 18, _ => -1, }); } } public static class PluginInfo { public const string PLUGIN_GUID = "CrewBoom"; public const string PLUGIN_NAME = "CrewBoom"; public const string PLUGIN_VERSION = "4.2.0"; } } namespace CrewBoom.Utility { public static class CharacterDefinitionExtensions { public static bool HasVoices(this CharacterDefinition characterDefinition) { if (characterDefinition.VoiceDie.Length == 0 && characterDefinition.VoiceDieFall.Length == 0 && characterDefinition.VoiceTalk.Length == 0 && characterDefinition.VoiceBoostTrick.Length == 0 && characterDefinition.VoiceCombo.Length == 0 && characterDefinition.VoiceGetHit.Length == 0) { return characterDefinition.VoiceJump.Length != 0; } return true; } public static bool SetOutfit(this CharacterDefinition characterDefinition, int outfit, out SkinnedMeshRenderer firstActiveRenderer) { firstActiveRenderer = null; for (int i = 0; i < characterDefinition.Renderers.Length; i++) { SkinnedMeshRenderer val = characterDefinition.Renderers[i]; ((Renderer)val).sharedMaterials = characterDefinition.Outfits[outfit].MaterialContainers[i].Materials; ((Component)val).gameObject.SetActive(characterDefinition.Outfits[outfit].EnabledRenderers[i]); if ((Object)(object)firstActiveRenderer == (Object)null && characterDefinition.Outfits[outfit].EnabledRenderers[i]) { firstActiveRenderer = val; } } StoryBlinkAnimation component = ((Component)characterDefinition).GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)firstActiveRenderer != (Object)null) { component.mainRenderer = firstActiveRenderer; component.characterMesh = firstActiveRenderer.sharedMesh; } return (Object)(object)firstActiveRenderer != (Object)null; } } public static class ReflectionUtility { public static Type GetTypeByName(string name) { foreach (Assembly item in AppDomain.CurrentDomain.GetAssemblies().Reverse()) { Type type = item.GetType(name); if (type != null) { return type; } } return null; } } public class TextureUtil { public static Texture2D GetTextureFromBitmap(Bitmap bitmap, FilterMode filterMode = 1) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown byte[] array = (byte[])((TypeConverter)new ImageConverter()).ConvertTo((object?)bitmap, typeof(byte[])); Texture2D val = new Texture2D(((Image)bitmap).Width, ((Image)bitmap).Height); ImageConversion.LoadImage(val, array); ((Texture)val).filterMode = filterMode; val.Apply(); return val; } } } namespace CrewBoom.Properties { [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [DebuggerNonUserCode] [CompilerGenerated] public class Resources { private static ResourceManager resourceMan; private static CultureInfo resourceCulture; [EditorBrowsable(EditorBrowsableState.Advanced)] public static ResourceManager ResourceManager { get { if (resourceMan == null) { resourceMan = new ResourceManager("CrewBoom.Properties.Resources", typeof(Resources).Assembly); } return resourceMan; } } [EditorBrowsable(EditorBrowsableState.Advanced)] public static CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } public static Bitmap default_graffiti => (Bitmap)ResourceManager.GetObject("default_graffiti", resourceCulture); public static Bitmap logo_background => (Bitmap)ResourceManager.GetObject("logo_background", resourceCulture); internal Resources() { } } } namespace CrewBoom.Patches { [HarmonyPatch(typeof(CharacterLoader), "GetCharacterFbx")] public class GetFbxPatch { public static void Postfix(Characters character, ref GameObject __result, CharacterLoader __instance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.GetCharacter(character, out var characterObject)) { if (characterObject.Loaded) { __result = ((Component)characterObject.Definition).gameObject; } else { __result = __instance.loadedCharacterFbxAssets[3]; } } } } [HarmonyPatch(typeof(CharacterVisual), "Init")] public class BlinkPatch { public static void Postfix(Characters character, ref bool ___canBlink) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.GetCharacter(character, out var characterObject)) { if (characterObject.Loaded) { ___canBlink = characterObject.Definition.CanBlink; } else { ___canBlink = false; } } } } [HarmonyPatch(typeof(CharacterVisual), "SetInlineSkatesPropsMode")] public class InlineSkatesTransformPatch { private static void Postfix(MoveStylePropMode mode, Transform ___footL, Transform ___footR, PlayerMoveStyleProps ___moveStyleProps, CharacterVisual __instance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) if ((int)mode != 1) { return; } Player componentInParent = ((Component)__instance).GetComponentInParent(true); if (!((Object)(object)componentInParent == (Object)null) && CharacterDatabase.HasCharacter(componentInParent.character)) { Transform val = ___footL.Find("skateOffsetL"); Transform val2 = ___footR.Find("skateOffsetR"); if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { ___moveStyleProps.skateL.transform.SetLocalPositionAndRotation(val.localPosition, val.localRotation); ___moveStyleProps.skateL.transform.localScale = val.localScale; ___moveStyleProps.skateR.transform.SetLocalPositionAndRotation(val2.localPosition, val2.localRotation); ___moveStyleProps.skateR.transform.localScale = val2.localScale; } } } } [HarmonyPatch(typeof(CharacterSelectCharacter), "Init")] public class CharacterSelectCharacterInitPatch { public static void Postfix(CharacterVisual ___visual, Characters setCharacter) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) CharUtil.TrySetCustomOutfit((Component)(object)___visual, CharUtil.GetSavedCharacterOutfit(setCharacter), out var _); } } [HarmonyPatch(typeof(CharacterSelectCharacter), "SetState")] public class CharacterSelectCharacterSetStatePatch { public static void Prefix(CharacterSelectCharacter __instance, CharSelectCharState setState) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Invalid comparison between Unknown and I4 //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 if (BunchOfEmotesSupport.Installed && BunchOfEmotesSupport.IsCustomAnimation(__instance.visual.bounceAnimHash) && ((int)setState == 5 || (int)setState == 1)) { __instance.visual.anim.runtimeAnimatorController = BunchOfEmotesSupport.AnimatorController; } } } [HarmonyPatch(typeof(CharacterSelect), "PopulateListOfSelectableCharacters")] public class CharacterSelectPopulateListPatch { public static void Postfix(Player player, List ___selectableCharacters, CharacterSelect __instance) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.NewCharacterCount == 0) { return; } int num = 26; for (int i = num + 1; i <= num + CharacterDatabase.NewCharacterCount; i++) { Characters val = (Characters)i; if (player.character != val && CharacterDatabase.HasCypherEnabledForCharacter(val)) { ___selectableCharacters.Add(val); } } __instance.Shuffle(___selectableCharacters); } } [HarmonyPatch(typeof(CharacterSelect), "SetPlayerToCharacter")] public class CharacterSelectSetPlayerPatch { public static bool Prefix(int index, out Characters __state, CharacterSelect __instance, CharacterSelectCharacter[] ___charactersInCircle, Player ___player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected I4, but got Unknown //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) CharacterSelectCharacter val = ___charactersInCircle[index]; __state = (Characters)(int)val.character; if ((int)__state > 26) { Characters character = ___player.character; Characters character2 = val.character; ___player.SetCharacter(character2, 0); ___player.InitVisual(); CharacterVisual characterVisual = ___player.characterVisual; ___player.PlayAnim(characterVisual.bounceAnimHash, false, false, -1f); ___player.SetCurrentMoveStyleEquipped(Core.Instance.SaveManager.CurrentSaveSlot.GetCharacterProgress(character2).moveStyle, true, true); CharacterVisual visual = val.visual; ___player.SetRotHard(visual.tf.forward); Object.Destroy((Object)(object)((Component)val).gameObject); __instance.CreateCharacterSelectCharacter(character, index, (CharSelectCharState)1); return false; } return true; } public static void Postfix(Player ___player, Characters __state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) int savedCharacterOutfit = CharUtil.GetSavedCharacterOutfit(__state); CharUtil.TrySetCustomOutfit((Component)(object)___player.characterVisual, savedCharacterOutfit, out var _); } } [HarmonyPatch(typeof(CharacterSelect), "CreateCharacterSelectCharacter")] public class CharacterSelectCreateCharacterPatch { public static bool Prefix(Characters character, int numInCircle, CharSelectCharState startState, CharacterSelect __instance, Player ___player, CharacterSelectCharacter[] ___charactersInCircle, List ___characterPositions, List ___characterDirections, Transform ___tf, GameObject ___charCollision, GameObject ___charTrigger, GameObject ___swapSequence) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if ((int)character > 26) { CustomCharacter characterObject = null; if (CharacterDatabase.GetCharacter(character, out characterObject)) { characterObject.WaitForLoadSync(); } CharacterVisual val = ___player.CharacterConstructor.CreateNewCharacterVisual(character, ___player.animatorController, true, ___player.motor.groundDetection.groundLimit); ___charactersInCircle[numInCircle] = ((Component)val).gameObject.AddComponent(); ((Component)___charactersInCircle[numInCircle]).transform.position = ___characterPositions[numInCircle]; ((Component)___charactersInCircle[numInCircle]).transform.rotation = Quaternion.LookRotation(___characterDirections[numInCircle] * -1f); ((Component)___charactersInCircle[numInCircle]).transform.parent = ___tf; ___charactersInCircle[numInCircle].Init(__instance, character, ___charCollision, ___charTrigger, ___tf.position, Object.Instantiate(___swapSequence, ((Component)___charactersInCircle[numInCircle]).transform).GetComponent()); ___charactersInCircle[numInCircle].SetState(startState); if (characterObject != null) { GenericCharacterStreamer.Create(((Component)val).gameObject, characterObject); } return false; } return true; } } [HarmonyPatch(typeof(CharacterSelect), "GetSelectSequenceAnim")] public class CharacterSelectSequencePatch { public static void Prefix(ref Characters c) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown if (CharacterDatabase.GetCharacter(c, out var characterObject)) { if (characterObject.Loaded) { c = (Characters)(int)characterObject.Definition.FreestyleAnimation; } else { c = (Characters)3; } } } } [HarmonyPatch(typeof(CharacterSelectUI), "SetCharacterInformation")] public class CharacterSelectUIInfoPatch { public static bool Prefix(Characters character, TextMeshProUGUI ___characterNameLabel, TextMeshProUGUI ___characterUnlockedOutfitCountLabel, CharacterSelectUI __instance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((int)character > 26 && CharacterDatabase.GetCharacter(character, out var characterObject)) { ((TMP_Text)___characterNameLabel).text = characterObject.StreamData.Name; ((TMP_Text)___characterUnlockedOutfitCountLabel).text = "4/4"; if (CharacterSaveSlots.GetCharacterData(Guid.Parse(characterObject.StreamData.Id), out var progress)) { __instance.SetCharacterSelectUIMoveStyle(progress.moveStyle); } return false; } return true; } } [HarmonyPatch(typeof(CharacterVisual), "GetCharacterFreestyleAnim")] public class CharacterFreestylePatch { public static void Prefix(ref Characters c) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected I4, but got Unknown if (CharacterDatabase.GetCharacter(c, out var characterObject)) { if (characterObject.Loaded) { c = (Characters)(int)characterObject.Definition.FreestyleAnimation; } else { c = (Characters)3; } } } } [HarmonyPatch(typeof(CharacterVisual), "GetCharacterBounceAnim")] public class CharacterBouncePatch { public static bool Prefix(ref Characters c, ref int __result) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected I4, but got Unknown if (CharacterDatabase.GetCharacter(c, out var characterObject)) { if (!string.IsNullOrWhiteSpace(characterObject.StreamData.BoEIdleDance)) { if (!characterObject.StreamData.BoEIdleDanceVanilla && BunchOfEmotesSupport.Installed) { if (BunchOfEmotesSupport.TryGetGameAnimationForCustomAnimationName(characterObject.StreamData.BoEIdleDance, out var gameAnim)) { __result = gameAnim; return false; } } else if (characterObject.StreamData.BoEIdleDanceVanilla) { __result = Animator.StringToHash(characterObject.StreamData.BoEIdleDance); return false; } } c = (Characters)(int)characterObject.StreamData.IdleDance; } return true; } } [HarmonyPatch(typeof(CharacterConstructor), "CreateNewCharacterVisual")] public class ConstructorCreateVisualPatch { public static bool Prefix(Characters character, RuntimeAnimatorController controller, bool IK, float setGroundAngleLimit, CharacterConstructor __instance, ref CharacterVisual __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.GetCharacter(character, out var characterObject)) { CharacterVisual val = null; val = ((!characterObject.Loaded) ? Object.Instantiate(CharacterStreamer.StreamingVisuals).AddComponent() : Object.Instantiate(characterObject.Visual).AddComponent()); val.Init(character, controller, IK, setGroundAngleLimit); ((Component)val).gameObject.SetActive(true); __result = val; return false; } return true; } } [HarmonyPatch(typeof(GraffitiLoader), "LoadGraffitiArtInfoAsync")] public class GraffitiLoadAsyncPatch { [CompilerGenerated] private sealed class d__0 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public Assets assets; public GraffitiLoader __instance; private AssetBundleRequest 5__2; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__0(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; <>1__state = -2; } private bool MoveNext() { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) switch (<>1__state) { default: return false; case 0: <>1__state = -1; 5__2 = assets.LoadAssetFromBundleASync("graffiti", "graffitiartinfo"); <>2__current = 5__2; <>1__state = 1; return true; case 1: { <>1__state = -1; GraffitiArtInfo val = (GraffitiArtInfo)5__2.asset; CharacterDatabase.SetGraffitiShader(val.graffitiArt.Find((GraffitiArt g) => g.title == "Red").graffitiMaterial.shader); for (int i = 0; i < Enum.GetValues(typeof(Characters)).Length - 1; i++) { Characters val2 = (Characters)i; if (CharacterDatabase.GetCharacter(val2, out var characterObject) && characterObject.StreamData.HasGraffiti) { GraffitiArt obj = val.FindByCharacter(val2); Texture2D graffitiTexture = characterObject.StreamData.GraffitiTexture; obj.graffitiMaterial.mainTexture = (Texture)(object)graffitiTexture; } } ref GraffitiArtInfo graffitiArtInfo = ref __instance.graffitiArtInfo; Object asset = 5__2.asset; graffitiArtInfo = (GraffitiArtInfo)(object)((asset is GraffitiArtInfo) ? asset : null); return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [IteratorStateMachine(typeof(d__0))] private static IEnumerator Postfix(IEnumerator __result, Assets assets, GraffitiLoader __instance) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__0(0) { assets = assets, __instance = __instance }; } } [HarmonyPatch(typeof(GraffitiArtInfo), "FindByCharacter")] public class GraffitiFindCharacterPatch { public static bool Prefix(ref Characters character, ref GraffitiArt __result) { if ((int)character > 26) { if (CharacterDatabase.GetCharacter(character, out var characterObject)) { __result = characterObject.Graffiti; return false; } character = (Characters)3; } return true; } } [HarmonyPatch(typeof(GraffitiArtInfo), "FindByTitle")] public class GraffitiFindTitlePatch { public static void Postfix(ref GraffitiArt __result, string grafTitle) { if ((__result != null || !string.IsNullOrEmpty(grafTitle)) && CharacterDatabase.GetCharacterWithGraffitiTitle(grafTitle, out var characterObject)) { __result = characterObject.Graffiti; } } } [HarmonyPatch(typeof(GraffitiGame), "SetStateVisual")] public class GraffitiVisualPatch { public static void Postfix(GraffitiGameState setState, Player ___player, GraffitiArt ___grafArt, GraffitiArtInfo ___graffitiArtInfo) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if ((int)setState == 2 && CharacterDatabase.GetCharacter(___player.character, out var characterObject) && characterObject.Graffiti != null && ___grafArt == ___graffitiArtInfo.FindByCharacter(___player.character)) { ((TMP_Text)___player.ui.graffitiTitle).text = "'" + characterObject.Graffiti.title + "'"; } } } [HarmonyPatch(typeof(MainMenuManager), "Init")] public class MainMenuPatch { public static void Postfix(MainMenuManager __instance) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) Texture2D textureFromBitmap = TextureUtil.GetTextureFromBitmap(Resources.logo_background, (FilterMode)1); GameObject val = new GameObject("CrewBoom Logo"); val.transform.SetParent(((Component)__instance).transform, false); val.AddComponent().sprite = Sprite.Create(textureFromBitmap, new Rect(0f, 0f, (float)((Texture)textureFromBitmap).width, (float)((Texture)textureFromBitmap).height), new Vector2(0.5f, 0.5f), 100f); RectTransform obj = GameObjectExtensions.RectTransform(val); obj.sizeDelta = new Vector2((float)((Texture)textureFromBitmap).width, (float)((Texture)textureFromBitmap).height); obj.anchorMin = new Vector2(0f, 1f); obj.anchorMax = obj.anchorMin; obj.pivot = obj.anchorMin; obj.anchoredPosition = Vector2.one * 32f; } } [HarmonyPatch(typeof(TextMeshProGameTextLocalizer), "GetCharacterName", new Type[] { typeof(Characters) })] public class CharacterNamePatch { public static void Postfix(Characters character, ref string __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.GetCharacter(character, out var characterObject)) { __result = characterObject.StreamData.Name; } } } [HarmonyPatch(typeof(TextMeshProGameTextLocalizer), "GetCharacterName", new Type[] { typeof(int) })] public class CharacterKeyNamePatch { public static void Postfix(int localizationKeyID, ref string __result) { if (CharacterDatabase.GetCharacterNameWithId(localizationKeyID, out var name)) { __result = name; } } } [HarmonyPatch(typeof(TextMeshProGameTextLocalizer), "GetSkinText")] public class SkinTextPatch { public static Characters Character; public const string SPRING_OUTFIT = "U_SKIN_SPRING"; public const string SUMMER_OUTFIT = "U_SKIN_SUMMER"; public const string AUTUMN_OUTFIT = "U_SKIN_AUTUMN"; public const string WINTER_OUTFIT = "U_SKIN_WINTER"; public static readonly string[] OUTFIT_NAMES = new string[4] { "U_SKIN_SPRING", "U_SKIN_SUMMER", "U_SKIN_AUTUMN", "U_SKIN_WINTER" }; public static void Postfix(string localizationKey, ref string __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.GetCharacter(Character, out var characterObject)) { int num; switch (localizationKey) { default: return; case "U_SKIN_SPRING": num = 0; break; case "U_SKIN_SUMMER": num = 1; break; case "U_SKIN_AUTUMN": num = 2; break; case "U_SKIN_WINTER": num = 3; break; } characterObject.WaitForLoadSync(); string name = characterObject.Definition.Outfits[num].Name; if (name != null && name != string.Empty) { __result = name; } } } } [HarmonyPatch(typeof(NPC), "InitSceneObject")] public class NPCInitPatch { public static void Prefix(NPC __instance, Characters ___character) { //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) OutfitSwappableCharacter[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(true); if (componentsInChildren != null && componentsInChildren.Length != 0) { OutfitSwappableCharacter[] array = componentsInChildren; foreach (OutfitSwappableCharacter val in array) { if (CharacterDatabase.GetCharacter(val.Character, out var characterObject)) { characterObject.WaitForLoadSync(); DynamicBone[] components = ((Component)val).GetComponents(); for (int j = 0; j < components.Length; j++) { ((Behaviour)components[j]).enabled = false; } CharacterDefinition val2 = Object.Instantiate(characterObject.Definition, ((Component)val).transform); Animator componentInChildren = ((Component)val).GetComponentInChildren(true); Animator component = ((Component)val2).GetComponent(); component.runtimeAnimatorController = componentInChildren.runtimeAnimatorController; Transform val3 = ((Component)componentInChildren).transform.Find("root"); if ((Object)(object)val3 != (Object)null) { CharUtil.ReparentAllProps(val3, ((Component)component).transform.Find("root")); } ((Component)val2).transform.SetLocalPositionAndRotation(((Component)componentInChildren).transform.localPosition, ((Component)componentInChildren).transform.localRotation); SkinnedMeshRenderer val4 = (val.mainRenderer = val2.Renderers[0]); ((Component)val2).gameObject.AddComponent(); ((Component)val2).gameObject.AddComponent(); if (characterObject.Definition.CanBlink) { StoryBlinkAnimation obj = ((Component)val2).gameObject.AddComponent(); obj.mainRenderer = val4; obj.characterMesh = val4.sharedMesh; } MeshCollider component2 = ((Component)componentInChildren).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { MeshCollider obj2 = ((Component)val2).gameObject.AddComponent(); obj2.sharedMesh = component2.sharedMesh; ((Collider)obj2).sharedMaterial = ((Collider)component2).sharedMaterial; obj2.convex = component2.convex; ((Collider)obj2).isTrigger = ((Collider)component2).isTrigger; } Object.DestroyImmediate((Object)(object)((Component)componentInChildren).gameObject); } } } else { ReplaceNonSwappableCharacter(__instance, ___character); } } private static void ReplaceNonSwappableCharacter(NPC __instance, Characters ___character) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!CharacterDatabase.GetCharacter(___character, out var characterObject)) { return; } DummyAnimationEventRelay componentInChildren = ((Component)__instance).GetComponentInChildren(true); if (!((Object)(object)componentInChildren == (Object)null)) { characterObject.WaitForLoadSync(); DynamicBone[] componentsInChildren = ((Component)__instance).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ((Behaviour)componentsInChildren[i]).enabled = false; } Animator component = ((Component)componentInChildren).GetComponent(); GameObject gameObject = Object.Instantiate(((Component)characterObject.Definition).gameObject, ((Component)component).transform.parent).gameObject; Animator component2 = gameObject.GetComponent(); component2.runtimeAnimatorController = component.runtimeAnimatorController; Transform val = ((Component)component).transform.Find("root"); if ((Object)(object)val != (Object)null) { CharUtil.ReparentAllProps(val, ((Component)component2).transform.Find("root")); } gameObject.transform.SetLocalPositionAndRotation(((Component)component).transform.localPosition, ((Component)component).transform.localRotation); gameObject.AddComponent(); gameObject.AddComponent(); MeshCollider component3 = ((Component)component).GetComponent(); if (Object.op_Implicit((Object)(object)component3)) { MeshCollider obj = gameObject.AddComponent(); obj.sharedMesh = component3.sharedMesh; ((Collider)obj).sharedMaterial = ((Collider)component3).sharedMaterial; obj.convex = component3.convex; ((Collider)obj).isTrigger = ((Collider)component3).isTrigger; } Object.DestroyImmediate((Object)(object)((Component)component).gameObject); } } } [HarmonyPatch(typeof(OutfitSwappableCharacter), "SetMaterialAndOutfit")] public class OutfitSwappablePatches { public static bool Prefix(OutfitSwappableCharacter __instance, ref SkinnedMeshRenderer ___mainRenderer, int outfitIndex) { if (CharUtil.TrySetCustomOutfit((Component)(object)__instance, outfitIndex, out var firstActiveRenderer)) { ___mainRenderer = firstActiveRenderer; return false; } return true; } } [HarmonyPatch(typeof(OutfitSwitchMenu), "SkinButtonSelected")] public class OutfitSwitchSelectPatch { public static bool Prefix(OutfitSwitchMenu __instance, MenuTimelineButton ___buttonClicked, CharacterVisual ___previewCharacterVisual, int skinIndex) { if (__instance.IsTransitioning || (Object)(object)___buttonClicked != (Object)null) { return false; } if (CharUtil.TrySetCustomOutfit((Component)(object)___previewCharacterVisual, skinIndex, out var _)) { return false; } return true; } } [HarmonyPatch(typeof(OutfitSwitchMenu), "SkinButtonClicked")] public class OutfitSwitchClickPatch { public static bool Prefix(OutfitSwitchMenu __instance, MenuTimelineButton clickedButton, int skinIndex, ref MenuTimelineButton ___buttonClicked, Player ___player) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Expected O, but got Unknown if ((int)___player.character > 26) { if (CharacterDatabase.GetCharacter(___player.character, out var _)) { if (__instance.IsTransitioning || (Object)(object)___buttonClicked != (Object)null) { return false; } ___buttonClicked = clickedButton; Core.Instance.AudioManager.PlaySfxUI((SfxCollectionID)23, (AudioClipID)547, 0f); ___player.SetOutfit(skinIndex); WantedManager.instance.StopPlayerWantedStatus(true, true); ((MonoBehaviour)__instance).StartCoroutine(((BaseMenuTimelineBehaviour)__instance.clipBehaviour).FlickerDelayedButtonPress(clickedButton, new UnityAction(((BaseMenuTimelineBehaviour)__instance.clipBehaviour).ExitMenu))); } return false; } return true; } } [HarmonyPatch(typeof(OutfitSwitchMenu), "Activate")] public class OutfitSwitchActivatePatch { private static OutfitSwitchMenu _lastMenu; public static bool Prefix(OutfitSwitchMenu __instance, Player ___player, MenuTimelineButton[] ___buttons, TMProLocalizationAddOn[] ___texts, GameFontType ___normalGameFontType, GameFontType ___selectedGameFontType, float ___nonSelectableAlphaValue) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Invalid comparison between Unknown and I4 //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Expected O, but got Unknown //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Expected O, but got Unknown _lastMenu = __instance; SkinTextPatch.Character = ___player.character; if ((int)___player.character > 26) { if (CharacterDatabase.GetCharacter(___player.character, out var _)) { CharacterProgress characterProgress = Core.Instance.SaveManager.CurrentSaveSlot.GetCharacterProgress(___player.character); _ = ___player.CharacterConstructor; MenuTimelineButton val = null; for (int i = 0; i < 4; i++) { string text = null; if (characterProgress.outfit == i) { text = ""; } ___texts[i].AssignAndUpdateTextWithTags(SkinTextPatch.OUTFIT_NAMES[i], (GroupOptions)5, text, (string)null, Array.Empty()); MenuTimelineButton val2 = null; if (i < 3) { val2 = ___buttons[i + 1]; } MenuTimelineButton button = ___buttons[i]; int skinIndex = i; button.SetButtonVariables((OnSelectButtonAction)delegate { __instance.SkinButtonSelected(button, skinIndex); }, true, (Button)(object)val, (Button)(object)val2, ___normalGameFontType, ___selectedGameFontType, ___nonSelectableAlphaValue); ((Selectable)button).interactable = true; ((UnityEventBase)((Button)button).onClick).RemoveAllListeners(); ((UnityEvent)((Button)button).onClick).AddListener((UnityAction)delegate { __instance.SkinButtonClicked(button, skinIndex); }); ((Component)button).gameObject.SetActive(true); val = button; } } return false; } return true; } } [HarmonyPatch(typeof(Player), "SetCharacter")] public class PlayerInitOverridePatch { public static void Prefix(Player __instance, ref Characters setChar, int setOutfit) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected I4, but got Unknown if (CharacterDatabase.HasCharacterOverride && CharacterDatabase.GetCharacterValueFromGuid(CharacterDatabase.CharacterOverride, out var character) && (int)character > 26) { setChar = (Characters)(int)character; } bool preloaded = false; if (CharacterDatabase.GetCharacter(setChar, out var characterObject)) { if (characterObject.Loaded) { preloaded = true; } else if (!CrewBoomSettings.LoadCharactersAsync) { characterObject.WaitForLoadSync(); preloaded = true; } } PlayerStreamingComponent.GetOrCreate(__instance).SetCharacter(setChar, setOutfit, preloaded); } public static void Postfix(Player __instance, Characters setChar) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown if (CharacterDatabase.HasCharacterOverride) { CharacterDatabase.SetCharacterOverrideDone(); } if (!((Object)(object)__instance == (Object)(object)WorldHandler.instance.GetCurrentPlayer())) { return; } if (CharacterDatabase.GetCharacter(setChar, out var characterObject)) { string text = ""; if (characterObject.Graffiti != null) { text = characterObject.Graffiti.title; } CrewBoomAPIDatabase.UpdatePlayerCharacter(new CharacterInfo(characterObject.StreamData.Name, text)); } else { CrewBoomAPIDatabase.UpdatePlayerCharacter((CharacterInfo)null); } } } [HarmonyPatch(typeof(Player), "SetOutfit")] public class PlayerSetOutfitPatch { public static bool Prefix(int setOutfit, Player __instance, CharacterVisual ___characterVisual, Characters ___character) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Invalid comparison between Unknown and I4 //IL_003e: Unknown result type (might be due to invalid IL or missing references) PlayerStreamingComponent.GetOrCreate(__instance).SetOutfit(setOutfit); if (!CharacterDatabase.HasCharacter(___character)) { return true; } if (!__instance.isAI) { Core.Instance.SaveManager.CurrentSaveSlot.GetCharacterProgress(___character).outfit = setOutfit; if ((int)___character > 26 && CharacterDatabase.GetFirstOrConfigCharacterId(___character, out var guid)) { CharacterSaveSlots.SaveCharacterData(guid); } } if (CharUtil.TrySetCustomOutfit((Component)(object)___characterVisual, setOutfit, out var firstActiveRenderer)) { ___characterVisual.mainRenderer = firstActiveRenderer; } return false; } } [HarmonyPatch(typeof(Player), "SetCurrentMoveStyleEquipped")] public class PlayerSetMovestyleEquipped { public static void Postfix(Player __instance, MoveStyle setMoveStyleEquipped) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) if (!__instance.isAI && (int)__instance.character > 26 && CharacterDatabase.GetFirstOrConfigCharacterId(__instance.character, out var guid) && CharacterSaveSlots.GetCharacterData(guid, out var progress)) { progress.moveStyle = setMoveStyleEquipped; CharacterSaveSlots.SaveCharacterData(guid); } } } [HarmonyPatch(typeof(Player), "SaveSelectedCharacter")] public class PlayerSaveCharacterPatch { public static bool Prefix(Player __instance, ref Characters selectedCharacter) { bool result = true; bool flag = (int)selectedCharacter > 26; if (!__instance.isAI) { CharacterSaveSlots.CurrentSaveSlot.LastPlayedCharacter = Guid.Empty; if (flag) { if (CharacterDatabase.GetFirstOrConfigCharacterId(selectedCharacter, out var guid)) { CharacterSaveSlots.CurrentSaveSlot.LastPlayedCharacter = guid; } result = false; } CharacterSaveSlots.SaveSlot(); } else if ((int)selectedCharacter > 26) { result = false; } return result; } } public struct UpdateAnimState { public int originalAnim; public int newAnim; public bool doingBoEDance; } [HarmonyPatch(typeof(Player), "UpdateAnim")] public class PlayerUpdateAnimPatch { public static void Prefix(Player __instance, ref UpdateAnimState __state) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) __state.originalAnim = __instance.curAnim; __state.doingBoEDance = false; if (CharacterDatabase.GetCharacter(__instance.character, out var characterObject)) { if (characterObject.StreamData.BoEIdleDanceVanilla && __instance.curAnim == __instance.characterVisual.bounceAnimHash) { __state.doingBoEDance = true; } else if (!characterObject.StreamData.BoEIdleDanceVanilla && BunchOfEmotesSupport.Installed && BunchOfEmotesSupport.IsCustomAnimation(__instance.curAnim) && __instance.curAnim == __instance.characterVisual.bounceAnimHash) { __state.doingBoEDance = true; } } if (__state.doingBoEDance) { __state.newAnim = __instance.softBounce1Hash; __instance.curAnim = __state.newAnim; } } public static void Postfix(Player __instance, UpdateAnimState __state) { if (__state.doingBoEDance && __state.newAnim == __instance.curAnim) { __instance.curAnim = __state.originalAnim; } } } [HarmonyPatch(typeof(Player), "PlayVoice")] public class PlayerVoicePatch { public static bool Prefix(AudioClipID audioClipID, VoicePriority voicePriority, bool fromPlayer, AudioManager ___audioManager, ref VoicePriority ___currentVoicePriority, Characters ___character, AudioSource ___playerGameplayVoicesAudioSource) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Invalid comparison between Unknown and I4 //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((int)___character > 26 && CharacterDatabase.GetCharacter(___character, out var characterObject) && !fromPlayer) { ___audioManager.PlaySfxGameplay(characterObject.SfxID, audioClipID, 0f); return false; } return true; } } [HarmonyPatch(typeof(PublicToilet), "DoSequence")] public class PublicToiletDoSequencePatch { public static void Prefix() { Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if ((Object)(object)currentPlayer != (Object)null) { PlayerStreamingComponent.GetOrCreate(currentPlayer).WaitForLoadSync(); } } } [HarmonyPatch(typeof(SaveSlotData), "GetCharacterProgress")] public class SaveSlotGetProgressPatch { public static bool Prefix(Characters character, ref CharacterProgress __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) if ((int)character > 26) { if (CharacterDatabase.GetFirstOrConfigCharacterId(character, out var guid) && CharacterSaveSlots.GetCharacterData(guid, out var progress)) { __result = progress; } return false; } return true; } } [HarmonyPatch(typeof(SaveSlotHandler), "SetCurrentSaveSlotDataBySlotId")] public class SaveSlotHandlerLoadPatch { public static void Postfix(int saveSlotId) { CharacterSaveSlots.LoadSlot(saveSlotId); } } [HarmonyPatch(typeof(SequenceHandler), "ReplaceMaterialsOnCharactersInCutscene")] public class SequenceCharacterModelPatch { private static Dictionary CutsceneOnlyCharacters = new Dictionary { { "FauxNoJetpackStory", (Characters)23 }, { "FauxStory", (Characters)12 }, { "SolaceStory", (Characters)8 }, { "IreneStory", (Characters)14 }, { "DJMaskedStory", (Characters)9 }, { "DJNoMaskStory", (Characters)9 }, { "FuturismStory", (Characters)20 }, { "FuturismBStory", (Characters)20 }, { "FuturismCStory", (Characters)20 }, { "FuturismDStory", (Characters)20 }, { "EclipseAStory", (Characters)10 }, { "EclipseBStory", (Characters)10 }, { "EclipseCStory", (Characters)10 }, { "EclipseDStory", (Characters)10 }, { "DotExeEStory", (Characters)24 }, { "DotExeAStory", (Characters)7 }, { "DotExeBStory", (Characters)7 }, { "DotExeCStory", (Characters)7 }, { "DotExeDStory", (Characters)7 }, { "RedShatteredStory", (Characters)25 }, { "DemonTheoryAStory", (Characters)11 }, { "DemonTheoryBStory", (Characters)11 }, { "DemonTheoryCStory", (Characters)11 }, { "FelixNoJetpackStory", (Characters)15 }, { "FrankAStory", (Characters)1 }, { "FrankBStory", (Characters)1 }, { "FrankCStory", (Characters)1 }, { "FrankDStory", (Characters)1 }, { "FleshPrinceStory", (Characters)13 } }; public static void Prefix(PlayableDirector ___sequence) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) OutfitSwappableCharacter[] componentsInChildren = ((Component)___sequence).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { SwapOutfitSwappable(componentsInChildren[i]); } Transform[] componentsInChildren2 = ((Component)___sequence).GetComponentsInChildren(true); foreach (Transform val in componentsInChildren2) { foreach (string key in CutsceneOnlyCharacters.Keys) { if (((Object)val).name.StartsWith(key)) { SwapCutsceneOnlyCharacter(val, CutsceneOnlyCharacters[key]); } } } } private static void SwapOutfitSwappable(OutfitSwappableCharacter swappable) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Expected O, but got Unknown //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) if (!CharacterDatabase.GetCharacter(swappable.Character, out var characterObject)) { return; } characterObject.WaitForLoadSync(); DynamicBone[] components = ((Component)((Component)swappable).transform).GetComponents(); for (int i = 0; i < components.Length; i++) { ((Behaviour)components[i]).enabled = false; } GameObject gameObject = Object.Instantiate(((Component)characterObject.Definition).gameObject, ((Component)swappable).transform).gameObject; Animator val = null; IEnumerator enumerator = ((Component)swappable).transform.GetEnumerator(); try { while (enumerator.MoveNext() && !((Object)(object)(val = ((Component)(Transform)enumerator.Current).GetComponent()) != (Object)null)) { } } finally { IDisposable disposable = enumerator as IDisposable; if (disposable != null) { disposable.Dispose(); } } Animator component = gameObject.GetComponent(); val.avatar = component.avatar; SkinnedMeshRenderer val2 = (swappable.mainRenderer = ((Component)component).GetComponentInChildren(true)); foreach (Transform item in ((Component)val).transform) { Transform val3 = item; if (((Object)val3).name == "root") { ((Object)val3).name = ((Object)val3).name + "_old"; CharUtil.ReparentAllProps(val3, ((Component)component).transform.Find("root")); } else { Object.Destroy((Object)(object)((Component)val3).gameObject); } } gameObject.transform.SetParent(((Component)val).transform, false); gameObject.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); Transform[] componentsInChildren = gameObject.GetComponentsInChildren(); foreach (Transform val4 in componentsInChildren) { if (!((Object)(object)val4.parent != (Object)(object)gameObject.transform)) { val4.SetParent(((Component)val).transform, false); } } StoryBlinkAnimation component2 = ((Component)val).GetComponent(); if (Object.op_Implicit((Object)(object)component2)) { if (characterObject.Definition.CanBlink) { component2.mainRenderer = val2; component2.characterMesh = val2.sharedMesh; } else { ((Behaviour)component2).enabled = false; } } Object.Destroy((Object)(object)gameObject); val.Rebind(true); } private static void SwapCutsceneOnlyCharacter(Transform root, Characters character) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.HasCharacter(character)) { OutfitSwappableCharacter obj = ((Component)root).gameObject.AddComponent(); obj.character = character; SwapOutfitSwappable(obj); } } } [HarmonyPatch(typeof(StageManager), "GetPlayerCharacter")] public class SetupPatch { public static bool Prefix(ref Characters __result) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected I4, but got Unknown Guid lastPlayedCharacter = CharacterSaveSlots.CurrentSaveSlot.LastPlayedCharacter; if (lastPlayedCharacter != Guid.Empty && CharacterDatabase.GetCharacterValueFromGuid(lastPlayedCharacter, out var character)) { __result = (Characters)(int)character; return false; } return true; } } [HarmonyPatch(typeof(StyleSwitchMenu), "SkinButtonClicked")] public class StyleSwitchMenuPatch { public static void Postfix() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_0016: Unknown result type (might be due to invalid IL or missing references) Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if ((int)currentPlayer.character > 26 && CharacterDatabase.GetFirstOrConfigCharacterId(currentPlayer.character, out var guid)) { CharacterSaveSlots.SaveCharacterData(guid); } } } [HarmonyPatch(typeof(SfxLibrary), "Init")] public class InitSfxLibraryPatch { public static void Postfix(SfxLibrary __instance) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Invalid comparison between Unknown and I4 //IL_006c: Unknown result type (might be due to invalid IL or missing references) foreach (KeyValuePair item in __instance.sfxCollectionIDDictionary) { CharacterDatabase.InitializeMissingSfxCollections(VoiceUtility.CharacterFromVoiceCollection(item.Key), item.Value); } int num = 26; for (int i = num + 1; i <= num + CharacterDatabase.NewCharacterCount; i++) { if (CharacterDatabase.GetCharacter((Characters)i, out var characterObject) && (int)characterObject.SfxID != -1) { __instance.sfxCollectionIDDictionary.Add(characterObject.SfxID, characterObject.Sfx); } } } } [HarmonyPatch(typeof(SfxLibrary), "GetSfxCollectionById")] public class GetSfxCollectionIdPatch { public static void Postfix(SfxCollectionID sfxCollectionId, ref SfxCollection __result, SfxLibrary __instance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) if (CharacterDatabase.GetCharacter(VoiceUtility.CharacterFromVoiceCollection(sfxCollectionId), out var characterObject)) { __result = characterObject.Sfx; } } } [HarmonyPatch(typeof(AudioManager), "GetCharacterVoiceSfxCollection")] public class GetSfxCharacterCollectionPatch { public static bool Prefix(Characters character, ref SfxCollectionID __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected I4, but got Unknown if ((int)character > 26) { if (CharacterDatabase.GetCharacter(character, out var characterObject)) { __result = (SfxCollectionID)(int)characterObject.SfxID; return false; } __result = (SfxCollectionID)(-1); return false; } return true; } } [HarmonyPatch(typeof(AudioManager), "PlayVoice")] [HarmonyPatch(/*Could not decode attribute arguments.*/)] public class PlayVoicePatch { public static bool Prefix(ref VoicePriority currentPriority, Characters character, AudioClipID audioClipID, AudioSource audioSource, VoicePriority playbackPriority, AudioManager __instance, AudioMixerGroup[] ___mixerGroups) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected I4, but got Unknown //IL_0035: Unknown result type (might be due to invalid IL or missing references) if ((int)character > 26) { if (CharacterDatabase.GetCharacter(character, out var characterObject)) { if ((int)playbackPriority <= (int)currentPriority && audioSource.isPlaying) { return false; } AudioClip val = null; if ((Object)(object)characterObject.Sfx != (Object)null) { val = characterObject.Sfx.GetRandomAudioClipById(audioClipID); } __instance.PlayNonloopingSfx(audioSource, val, ___mixerGroups[5], 0f); currentPriority = (VoicePriority)(int)playbackPriority; } return false; } return true; } } [HarmonyPatch(typeof(AudioManager), "PlayVoice", new Type[] { typeof(Characters), typeof(AudioClipID) })] public class PlayVoiceForCharacterPatch { public static bool Prefix(Characters character, AudioClipID audioClipID, AudioManager __instance, AudioMixerGroup[] ___mixerGroups, AudioSource[] ___audioSources, ref VoicePriority __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) __result = (VoicePriority)0; if ((int)character > 26) { if (CharacterDatabase.GetCharacter(character, out var characterObject)) { AudioClip val = null; if ((Object)(object)characterObject.Sfx != (Object)null) { val = characterObject.Sfx.GetRandomAudioClipById(audioClipID); } __instance.PlayNonloopingSfx(___audioSources[5], val, ___mixerGroups[5], 0f); } return false; } return true; } } } namespace CrewBoom.Data { public class CustomCharacter { private static readonly List VOICE_IDS = new List { (AudioClipID)484, (AudioClipID)485, (AudioClipID)486, (AudioClipID)498, (AudioClipID)487, (AudioClipID)488, (AudioClipID)489 }; private string _path; private AssetBundle _bundle; public AssetBundleCreateRequest BundleRequest; public int References; public Action OnLoadedCallback; private static Texture2D _defaultGraffitiTexture = null; public CharacterDefinition Definition { get; private set; } public CharacterStreamData StreamData { get; private set; } public SfxCollectionID SfxID { get; private set; } public SfxCollection Sfx { get; private set; } public GameObject Visual { get; private set; } public bool Loaded { get; private set; } public bool KeepLoaded { get; private set; } public GraffitiArt Graffiti { get; private set; } public Texture2D DefaultGraffitiTexture { get { if ((Object)(object)_defaultGraffitiTexture == (Object)null) { _defaultGraffitiTexture = TextureUtil.GetTextureFromBitmap(Resources.default_graffiti, (FilterMode)1); } return _defaultGraffitiTexture; } } public CustomCharacter(CharacterStreamData streamData, SfxCollectionID sfxID, string path, bool replacement, bool forceLoad) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) StreamData = streamData; InitializeSfxCollection(); SfxID = sfxID; _path = path; KeepLoaded = replacement || forceLoad; if (KeepLoaded) { LoadSyncFromStartup(); } if (!replacement) { CreateGraffiti(); } } private void CreateGraffiti() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) Material val = new Material(Shader.Find("Standard")); val.mainTexture = (Texture)(object)StreamData.GraffitiTexture; string title = StreamData.GrafTitle; string text = StreamData.GrafAuthor; if (!StreamData.HasGraffiti) { val.mainTexture = (Texture)(object)DefaultGraffitiTexture; title = "Crew BOOM"; text = "Capry"; } GraffitiArt val2 = new GraffitiArt(); val2.graffitiSize = (GraffitiSize)0; val2.graffitiMaterial = val; val2.title = title; val2.artistName = text; GraffitiAppEntry val3 = ScriptableObject.CreateInstance(); val3.Size = (GraffitiSize)0; val3.GraffitiTexture = val.mainTexture; val3.Title = title; val3.Artist = text; val2.unlockable = val3; Graffiti = val2; } public void AddReference() { if (!KeepLoaded) { References++; if (CrewBoomSettings.LoadCharactersAsync && CrewBoomSettings.StreamCharacters) { LoadAsync(); } else { LoadSync(); } } } public void RemoveReference() { if (CrewBoomSettings.UnloadCharacters && !KeepLoaded) { References--; if (References <= 0 && CrewBoomSettings.StreamCharacters) { Unload(); } } } public void WaitForLoadSync() { if (Loaded) { return; } if (BundleRequest != null) { while (((AsyncOperation)BundleRequest).progress < 0.9f) { } BundleRequest.assetBundle.Unload(true); BundleRequest = null; } LoadSync(); } private void CancelAsyncLoad() { if (!Loaded && BundleRequest != null) { CharacterStreamer.CancelBundleLoadRequest(this); _bundle = null; } } private void LoadAsync() { if (!Loaded) { if (BundleRequest == null) { BundleRequest = AssetBundle.LoadFromFileAsync(_path); } CharacterStreamer.AddToStreamQueue(this); } } private void LoadSyncFromStartup() { OnBundleLoaded(AssetBundle.LoadFromFile(_path), fixShaders: false); } private void LoadSync() { if (!Loaded) { CancelAsyncLoad(); OnBundleLoaded(AssetBundle.LoadFromFile(_path)); } } public bool UpdateAsyncLoad() { if (Loaded) { return true; } if (BundleRequest == null) { return true; } if (((AsyncOperation)BundleRequest).isDone) { OnBundleLoaded(BundleRequest.assetBundle); return true; } return false; } private void OnBundleLoaded(AssetBundle bundle, bool fixShaders = true) { _bundle = bundle; Loaded = true; BundleRequest = null; GameObject[] array = bundle.LoadAllAssets(); foreach (GameObject val in array) { Definition = val.GetComponent(); if ((Object)(object)Definition != (Object)null) { break; } } if (fixShaders) { FixCharacterShader(); } CreateVisual(); LoadSfxCollection(); OnLoadedCallback?.Invoke(this); } private void Unload() { CancelAsyncLoad(); if (Loaded) { _bundle.Unload(true); _bundle = null; BundleRequest = null; Loaded = false; Definition = null; DestroyVisual(); UnloadSfxCollection(); } } private void DestroyVisual() { if (!((Object)(object)Visual == (Object)null)) { Object.Destroy((Object)(object)Visual); Visual = null; } } private void CreateVisual() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (!((Object)(object)Visual != (Object)null)) { GameObject val = new GameObject(Definition.CharacterName + " Visuals"); Object.DontDestroyOnLoad((Object)(object)val); CharacterDefinition val2 = Object.Instantiate(Definition); ((Component)val2).transform.SetParent(val.transform, false); for (int i = 0; i < val2.Renderers.Length; i++) { SkinnedMeshRenderer obj = val2.Renderers[i]; ((Renderer)obj).sharedMaterials = Definition.Outfits[0].MaterialContainers[i].Materials; ((Renderer)obj).receiveShadows = false; ((Component)obj).gameObject.layer = 15; ((Component)obj).gameObject.SetActive(Definition.Outfits[0].EnabledRenderers[i]); } ((Component)val2).GetComponentInChildren().applyRootMotion = false; val.SetActive(false); Visual = val; } } private void InitializeSfxCollection() { Sfx = ScriptableObject.CreateInstance(); UnloadSfxCollection(); } private void UnloadSfxCollection() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Sfx != (Object)null) { Sfx.audioClipContainers = (RandomAudioClipContainer[])(object)new RandomAudioClipContainer[VOICE_IDS.Count]; for (int i = 0; i < VOICE_IDS.Count; i++) { Sfx.audioClipContainers[i] = new RandomAudioClipContainer(); Sfx.audioClipContainers[i].clipID = VOICE_IDS[i]; Sfx.audioClipContainers[i].clips = null; Sfx.audioClipContainers[i].lastRandomClip = 0; } } } private void LoadSfxCollection() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Expected I4, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Invalid comparison between Unknown and I4 if (!Definition.HasVoices()) { return; } SfxCollection val = Sfx; if ((Object)(object)val == (Object)null) { val = ScriptableObject.CreateInstance(); } val.audioClipContainers = (RandomAudioClipContainer[])(object)new RandomAudioClipContainer[VOICE_IDS.Count]; for (int i = 0; i < VOICE_IDS.Count; i++) { val.audioClipContainers[i] = new RandomAudioClipContainer(); val.audioClipContainers[i].clipID = VOICE_IDS[i]; val.audioClipContainers[i].clips = null; val.audioClipContainers[i].lastRandomClip = 0; } RandomAudioClipContainer[] audioClipContainers = val.audioClipContainers; foreach (RandomAudioClipContainer val2 in audioClipContainers) { AudioClipID clipID = val2.clipID; switch (clipID - 484) { default: if ((int)clipID == 498 && Definition.VoiceBoostTrick.Length != 0) { val2.clips = Definition.VoiceBoostTrick; } break; case 0: if (Definition.VoiceDie.Length != 0) { val2.clips = Definition.VoiceDie; } break; case 1: if (Definition.VoiceDieFall.Length != 0) { val2.clips = Definition.VoiceDieFall; } break; case 2: if (Definition.VoiceTalk.Length != 0) { val2.clips = Definition.VoiceTalk; } break; case 3: if (Definition.VoiceCombo.Length != 0) { val2.clips = Definition.VoiceCombo; } break; case 4: if (Definition.VoiceGetHit.Length != 0) { val2.clips = Definition.VoiceGetHit; } break; case 5: if (Definition.VoiceJump.Length != 0) { val2.clips = Definition.VoiceJump; } break; } } Sfx = val; } public void ApplySfxCollection(SfxCollection collection) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Sfx == (Object)null) { Sfx = collection; return; } RandomAudioClipContainer[] audioClipContainers = collection.audioClipContainers; foreach (RandomAudioClipContainer val in audioClipContainers) { if (!VOICE_IDS.Contains(val.clipID)) { Array.Resize(ref Sfx.audioClipContainers, Sfx.audioClipContainers.Length + 1); Sfx.audioClipContainers[Sfx.audioClipContainers.Length - 1] = val; } } } public void FixCharacterShader() { CharacterOutfit[] outfits = Definition.Outfits; for (int i = 0; i < outfits.Length; i++) { CharacterOutfitRenderer[] materialContainers = outfits[i].MaterialContainers; foreach (CharacterOutfitRenderer val in materialContainers) { for (int k = 0; k < val.Materials.Length; k++) { if (val.UseShaderForMaterial[k]) { val.Materials[k].shader = AssetAPI.GetShader((ShaderNames)0); } } } } } public void ApplyShaderToGraffiti(Shader shader) { if (Graffiti != null) { Graffiti.graffitiMaterial.shader = shader; } } } } namespace CrewBoom.Database { public static class CharacterStreamer { private static HashSet _cancelledRequests = new HashSet(); private static HashSet _characters = new HashSet(); private static Dictionary _keepAlives = new Dictionary(); private static GameObject _streamingVisuals; public static GameObject StreamingVisuals { get { if ((Object)(object)_streamingVisuals == (Object)null) { MakeStreamingVisuals(); } return _streamingVisuals; } } private static void MakeStreamingVisuals() { _streamingVisuals = Object.Instantiate(Core.Instance.BaseModule.StageManager.characterConstructor.GetCharacterVisual((Characters)3)); ((Object)_streamingVisuals).name = "Streaming Visuals"; _streamingVisuals.GetComponentInChildren(true).sharedMesh = null; _streamingVisuals.SetActive(false); } public static void AddToStreamQueue(CustomCharacter character) { _cancelledRequests.Remove(character); _characters.Add(character); } public static void CancelBundleLoadRequest(CustomCharacter character) { _characters.Remove(character); if (((AsyncOperation)character.BundleRequest).isDone) { character.BundleRequest.assetBundle.Unload(true); character.BundleRequest = null; } else { _cancelledRequests.Add(character); } } public static void Update(float delta) { _cancelledRequests.RemoveWhere(delegate(CustomCharacter req) { if (((AsyncOperation)req.BundleRequest).isDone) { req.BundleRequest.assetBundle.Unload(true); req.BundleRequest = null; return true; } return false; }); _characters.RemoveWhere((CustomCharacter req) => req.UpdateAsyncLoad()); foreach (CustomCharacter item in new List(_keepAlives.Keys)) { float num = _keepAlives[item] - delta; _keepAlives[item] = num; if (num <= 0f) { item.RemoveReference(); _keepAlives.Remove(item); } } if (Input.GetKeyDown((KeyCode)289)) { LogStreamingStats(); } } public static void LogStreamingStats() { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) Characters val = (Characters)27; int num = 0; int newCharacterCount = CharacterDatabase.NewCharacterCount; Console.WriteLine("----- CrewBoom Streaming Stats -----"); for (int i = 0; i < CharacterDatabase.NewCharacterCount; i++) { if (CharacterDatabase.GetCharacter((Characters)(val + i), out var characterObject)) { Console.WriteLine(characterObject.StreamData.Name + " - Loaded: " + (characterObject.Loaded ? "YES" : "NO") + $" - Refs: {characterObject.References}"); if (characterObject.Loaded) { num++; } } } Console.WriteLine($"In short, {num} characters are loaded out of {newCharacterCount}"); Console.WriteLine("--------------- END ----------------"); } public static void KeepAlive(CustomCharacter character, float time) { if (!(time <= 0f) && character.Loaded) { if (!_keepAlives.ContainsKey(character)) { character.AddReference(); } _keepAlives[character] = time; } } } public static class CrewBoomSettings { private static ConfigEntry _streamCharacters; private static ConfigEntry _loadCharactersAsync; private static ConfigEntry _unloadCharacters; private static ConfigEntry _keepAliveTime; private static ConfigEntry _updateCbbs; public static bool UpdateCBBs { get { return _updateCbbs.Value; } set { _updateCbbs.Value = value; } } public static bool StreamCharacters { get { return _streamCharacters.Value; } set { _streamCharacters.Value = value; } } public static bool LoadCharactersAsync { get { return _loadCharactersAsync.Value; } set { _loadCharactersAsync.Value = value; } } public static bool UnloadCharacters { get { return _unloadCharacters.Value; } set { _unloadCharacters.Value = value; } } public static float KeepAliveTime { get { return _keepAliveTime.Value; } set { _keepAliveTime.Value = value; } } public static void Initialize(ConfigFile configFile) { _streamCharacters = configFile.Bind("General", "Stream Characters", true, "If true, custom characters are dynamically loaded during gameplay, as necessary. If false, all custom characters are loaded at startup."); _unloadCharacters = configFile.Bind("General", "Unload Characters", true, "If true, and Stream Characters is also true, characters will be dynamically unloaded during gameplay as they're no longer used. If false, characters will never unload, lowering pop-in as characters load for the first time but increasing memory usage."); _loadCharactersAsync = configFile.Bind("General", "Stream Characters Async", true, "If true, and Stream Characters is also true, custom characters will be loaded in the background in order to keep gameplay smooth. This means there might be some pop-in as character models won't always be readily available in memory."); _keepAliveTime = configFile.Bind("General", "Keep Alive Time", 0.5f, "How long to keep characters lingering in memory after they've gone unused. Should reduce stutters and such as it keeps recent characters in memory, especially between transitions. Set to 0 to disable."); _updateCbbs = configFile.Bind("General", "Update CBBs", true, "If true, will update and overwrite your old .cbb files to embed .ldcs data into them. This makes them load way faster and streamable, while still keeping them compatible with original CrewBoom. If false, instead generates .ldcs data separate from the .cbb, for the same purpose."); } } } namespace CrewBoom.Compatibility { public static class BunchOfEmotesSupport { private static object BoEPluginInstance = null; private static Type BoEPluginType = null; private static FieldInfo CustomAnimsField = null; private static FieldInfo CustomAnimControllerField = null; private static bool Cached = false; private static Dictionary GameAnimationByCustomAnimationName = new Dictionary(); private static HashSet GameAnimations = new HashSet(); public static bool Installed { get; private set; } = false; public static RuntimeAnimatorController AnimatorController { get { object? value = CustomAnimControllerField.GetValue(BoEPluginInstance); return (RuntimeAnimatorController)((value is RuntimeAnimatorController) ? value : null); } } public static void Initialize() { Installed = true; BoEPluginInstance = Chainloader.PluginInfos["com.Dragsun.BunchOfEmotes"].Instance; BoEPluginType = ReflectionUtility.GetTypeByName("BunchOfEmotes.BunchOfEmotesPlugin"); CustomAnimsField = BoEPluginType.GetField("myCustomAnims2"); CustomAnimControllerField = BoEPluginType.GetField("myAnim"); } public static bool IsCustomAnimation(int animHash) { if (!Installed) { return false; } CacheAnimationsIfNecessary(); return GameAnimations.Contains(animHash); } public static void CacheAnimations() { Cached = true; foreach (KeyValuePair item in CustomAnimsField.GetValue(BoEPluginInstance) as Dictionary) { int key = item.Key; GameAnimationByCustomAnimationName[item.Value] = key; GameAnimations.Add(key); } RefreshLocalPlayer(); } private static void RefreshLocalPlayer() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) Player currentPlayer = WorldHandler.instance.GetCurrentPlayer(); if (!((Object)(object)currentPlayer == (Object)null) && CharacterDatabase.GetCharacter(currentPlayer.character, out var characterObject) && !characterObject.StreamData.BoEIdleDanceVanilla && TryGetGameAnimationForCustomAnimationName(characterObject.StreamData.BoEIdleDance, out var gameAnim)) { CharacterVisual characterVisual = currentPlayer.characterVisual; if (!((Object)(object)characterVisual == (Object)null)) { characterVisual.bounceAnimHash = gameAnim; } } } public static void CacheAnimationsIfNecessary() { if (!Cached) { CacheAnimations(); } } public static bool TryGetGameAnimationForCustomAnimationName(string name, out int gameAnim) { if (!Installed) { gameAnim = 0; return false; } CacheAnimationsIfNecessary(); if (GameAnimationByCustomAnimationName.TryGetValue(name, out gameAnim)) { return true; } return false; } } } namespace CrewBoom.Behaviours { public class GenericCharacterStreamer : MonoBehaviour { private CustomCharacter _targetCustomCharacter; public static GenericCharacterStreamer Create(GameObject go, CustomCharacter character) { GenericCharacterStreamer genericCharacterStreamer = go.AddComponent(); genericCharacterStreamer._targetCustomCharacter = character; character.AddReference(); return genericCharacterStreamer; } private void OnDestroy() { if (_targetCustomCharacter != null) { CharacterStreamer.KeepAlive(_targetCustomCharacter, CrewBoomSettings.KeepAliveTime); _targetCustomCharacter.RemoveReference(); } } } public class PlayerStreamingComponent : MonoBehaviour { private CustomCharacter _targetCustomCharacter; private Characters _targetCharacter = (Characters)(-1); private Player _player; private int _targetOutfit; public static PlayerStreamingComponent GetOrCreate(Player player) { PlayerStreamingComponent component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { return component; } component = ((Component)player).gameObject.AddComponent(); component._player = player; return component; } public void WaitForLoadSync() { if (_targetCustomCharacter != null) { _targetCustomCharacter.WaitForLoadSync(); OnLoad(_targetCustomCharacter); } } public void SetCharacter(Characters target, int outfit, bool preloaded = false) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Invalid comparison between Unknown and I4 //IL_0070: Unknown result type (might be due to invalid IL or missing references) _targetOutfit = outfit; if (target == _targetCharacter) { return; } if (_targetCustomCharacter != null) { CharacterStreamer.KeepAlive(_targetCustomCharacter, CrewBoomSettings.KeepAliveTime); CustomCharacter targetCustomCharacter = _targetCustomCharacter; targetCustomCharacter.OnLoadedCallback = (Action)Delegate.Remove(targetCustomCharacter.OnLoadedCallback, new Action(OnLoad)); _targetCustomCharacter.RemoveReference(); } _targetCharacter = target; _targetCustomCharacter = null; if ((int)target > 26 && CharacterDatabase.GetCharacter(target, out var characterObject)) { _targetCustomCharacter = characterObject; _targetCustomCharacter.AddReference(); if (!preloaded) { CustomCharacter targetCustomCharacter2 = _targetCustomCharacter; targetCustomCharacter2.OnLoadedCallback = (Action)Delegate.Combine(targetCustomCharacter2.OnLoadedCallback, new Action(OnLoad)); } } } public void SetOutfit(int outfit) { _targetOutfit = outfit; } private void OnDestroy() { if (_targetCustomCharacter != null) { CharacterStreamer.KeepAlive(_targetCustomCharacter, CrewBoomSettings.KeepAliveTime); CustomCharacter targetCustomCharacter = _targetCustomCharacter; targetCustomCharacter.OnLoadedCallback = (Action)Delegate.Remove(targetCustomCharacter.OnLoadedCallback, new Action(OnLoad)); _targetCustomCharacter.RemoveReference(); } } private void OnLoad(CustomCharacter customChar) { if (customChar == _targetCustomCharacter) { CustomCharacter targetCustomCharacter = _targetCustomCharacter; targetCustomCharacter.OnLoadedCallback = (Action)Delegate.Remove(targetCustomCharacter.OnLoadedCallback, new Action(OnLoad)); UpdateCharacterModel(); } } private void UpdateCharacterModel() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0397: Unknown result type (might be due to invalid IL or missing references) //IL_039c: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_player.visualTf != (Object)null) { Object.Destroy((Object)(object)((Component)_player.visualTf).gameObject); } _player.characterVisual = _player.characterConstructor.CreateNewCharacterVisual(_targetCharacter, _player.animatorController, !_player.isAI, _player.motor.groundDetection.groundLimit); _player.characterMesh = _player.characterVisual.mainRenderer.sharedMesh; if (_targetOutfit > 0) { _player.SetOutfit(_targetOutfit); } ((Component)_player.characterVisual).transform.SetParent(((Component)_player).transform.GetChild(0), false); ((Component)_player.characterVisual).transform.localPosition = Vector3.zero; ((Component)_player.characterVisual).transform.rotation = Quaternion.LookRotation(((Component)this).transform.forward); ((Component)_player.characterVisual.anim).gameObject.AddComponent().Init(); _player.visualTf = ((Component)_player.characterVisual).transform; _player.headTf = TransformExtentions.FindRecursive(_player.visualTf, "head"); _player.phoneDirBone = TransformExtentions.FindRecursive(_player.visualTf, "phoneDirection"); _player.heightToHead = (_player.headTf.position - _player.visualTf.position).y; _player.isGirl = _player.characterVisual.isGirl; _player.anim = _player.characterVisual.anim; if (_player.curAnim != 0) { int curAnim = _player.curAnim; _player.curAnim = 0; _player.PlayAnim(curAnim, false, false, -1f); } _player.characterVisual.InitVFX(_player.VFXPrefabs); _player.characterVisual.InitMoveStyleProps(_player.MoveStylePropsPrefabs); _player.characterConstructor.SetMoveStyleSkinsForCharacter(_player, _targetCharacter); if (_player.characterVisual.hasEffects) { _player.boostpackTrail = _player.characterVisual.VFX.boostpackTrail.GetComponent(); _player.boostpackTrailDefaultWidth = _player.boostpackTrail.startWidth; _player.boostpackTrailDefaultTime = _player.boostpackTrail.time; _player.spraypaintParticles = _player.characterVisual.VFX.spraypaint.GetComponent(); _player.characterVisual.VFX.spraypaint.transform.localScale = Vector3.one * 0.5f; _player.SetDustEmission(0); _player.ringParticles = _player.characterVisual.VFX.ring.GetComponent(); _player.SetRingEmission(0); } bool usingEquippedMovestyle = _player.usingEquippedMovestyle; MoveStyle moveStyleEquipped = _player.moveStyleEquipped; _player.SetMoveStyle((MoveStyle)0, true, true, (GameObject)null); _player.SetCurrentMoveStyleEquipped(moveStyleEquipped, true, true); _player.InitVisual(); if (usingEquippedMovestyle) { _player.SwitchToEquippedMovestyle(true, false, true, false); } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }