using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using HarmonyLib;
using Newtonsoft.Json;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("SceneMaterialEditor")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("SceneMaterialEditor")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("0e0ebe3a-06b3-4c4f-a970-c2431cfdcb4b")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace MapPlugin;
[BepInPlugin("com.morsecodeguy.mapplugin", "Map Plugin", "1.0.0")]
public class MapPlugin : BaseUnityPlugin
{
public static Dictionary<string, CustomMapData> customMapDataDict = new Dictionary<string, CustomMapData>();
public static List<MapItem> allMapItems = new List<MapItem>();
public static string selectedCustomMapName = null;
public static List<SongSound> customSongs = new List<SongSound>();
private string mapsFolderPath;
private void Awake()
{
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
mapsFolderPath = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "Maps");
((Object)Chainloader.ManagerObject).hideFlags = (HideFlags)61;
((BaseUnityPlugin)this).Logger.LogInfo((object)("Maps folder path: " + mapsFolderPath));
Harmony val = new Harmony("com.morsecodeguy.mapplugin");
val.PatchAll();
SceneManager.sceneLoaded += OnSceneLoaded;
((MonoBehaviour)this).StartCoroutine(LoadMapsFromAssetBundles());
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
private IEnumerator LoadMapsFromAssetBundles()
{
if (!Directory.Exists(mapsFolderPath))
{
((BaseUnityPlugin)this).Logger.LogError((object)("Maps folder not found: " + mapsFolderPath));
yield break;
}
string[] mapDirectories = Directory.GetDirectories(mapsFolderPath);
string[] array = mapDirectories;
AudioClip audioClip = default(AudioClip);
foreach (string mapDir in array)
{
string jsonPath = Path.Combine(mapDir, "mapinfo.json");
if (!File.Exists(jsonPath))
{
((BaseUnityPlugin)this).Logger.LogError((object)("Map configuration file not found: " + jsonPath));
continue;
}
string json = File.ReadAllText(jsonPath);
MapInfo mapInfo;
try
{
mapInfo = JsonConvert.DeserializeObject<MapInfo>(json);
}
catch (Exception ex2)
{
Exception ex = ex2;
((BaseUnityPlugin)this).Logger.LogError((object)("Failed to parse JSON in " + jsonPath + ": " + ex.Message));
continue;
}
if (mapInfo == null)
{
((BaseUnityPlugin)this).Logger.LogError((object)("MapInfo is null after deserialization in " + jsonPath));
continue;
}
string assetsBundlePath = Path.Combine(mapDir, mapInfo.assetsBundleFileName);
if (!File.Exists(assetsBundlePath))
{
((BaseUnityPlugin)this).Logger.LogError((object)("Assets bundle file not found: " + assetsBundlePath));
continue;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)("Loading assets bundle from: " + assetsBundlePath));
AssetBundle assetsBundle = AssetBundle.LoadFromFile(assetsBundlePath);
if ((Object)(object)assetsBundle == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Failed to load assets bundle: " + assetsBundlePath));
continue;
}
Dictionary<string, Object> renamedAssets = LoadAndRenameAssets(assetsBundle, mapInfo.mapName);
string rawBackgroundName = Path.GetFileName(mapInfo.mapBackgroundAssetName);
((BaseUnityPlugin)this).Logger.LogInfo((object)("Raw background asset name from JSON: " + rawBackgroundName));
string backgroundAssetKey = string.Concat(str2: Path.GetFileNameWithoutExtension(rawBackgroundName), str0: mapInfo.mapName, str1: "_");
((BaseUnityPlugin)this).Logger.LogInfo((object)("Constructed background asset key: " + backgroundAssetKey));
if (!renamedAssets.TryGetValue(backgroundAssetKey, out var backgroundObj))
{
string availableKeys = string.Join(", ", renamedAssets.Keys);
((BaseUnityPlugin)this).Logger.LogError((object)("Failed to load MapBackground with key " + backgroundAssetKey + " from " + assetsBundlePath + ". Available keys: " + availableKeys));
assetsBundle.Unload(false);
continue;
}
Texture backgroundImage = (Texture)(object)((backgroundObj is Texture) ? backgroundObj : null);
if ((Object)(object)backgroundImage == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)("MapBackground asset with key " + backgroundAssetKey + " is not a Texture."));
assetsBundle.Unload(false);
continue;
}
string sceneBundlePath = Path.Combine(mapDir, mapInfo.sceneBundleFileName);
if (!File.Exists(sceneBundlePath))
{
((BaseUnityPlugin)this).Logger.LogError((object)("Scene bundle file not found: " + sceneBundlePath));
assetsBundle.Unload(false);
continue;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)("Loading scene bundle from: " + sceneBundlePath));
AssetBundle sceneBundle = AssetBundle.LoadFromFile(sceneBundlePath);
if ((Object)(object)sceneBundle == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Failed to load scene bundle: " + sceneBundlePath));
assetsBundle.Unload(false);
continue;
}
string scenePath = mapInfo.sceneAssetPath;
bool sceneFound = false;
string[] scenePaths = sceneBundle.GetAllScenePaths();
string[] array2 = scenePaths;
foreach (string s in array2)
{
if (s.Equals(scenePath, StringComparison.OrdinalIgnoreCase))
{
sceneFound = true;
break;
}
}
if (!sceneFound)
{
((BaseUnityPlugin)this).Logger.LogError((object)("Scene path " + scenePath + " not found in scene bundle: " + sceneBundlePath));
assetsBundle.Unload(false);
sceneBundle.Unload(false);
continue;
}
MapItem mapItem = new MapItem
{
mapName = mapInfo.mapName,
backgroundImage = backgroundImage
};
allMapItems.Add(mapItem);
customMapDataDict[mapInfo.mapName] = new CustomMapData
{
scenePath = scenePath,
assetsBundle = assetsBundle,
sceneBundle = sceneBundle,
renamedAssets = renamedAssets
};
string sceneName = Path.GetFileNameWithoutExtension(scenePath);
string audioKey = mapInfo.mapName + "_" + sceneName;
int num;
if (renamedAssets.TryGetValue(audioKey, out var audioAsset))
{
audioClip = (AudioClip)(object)((audioAsset is AudioClip) ? audioAsset : null);
num = ((audioClip != null) ? 1 : 0);
}
else
{
num = 0;
}
if (num != 0)
{
SongSound song = new SongSound
{
AudioClip = audioClip,
sceneName = sceneName
};
if ((Object)(object)MusicManager.singleton != (Object)null)
{
MusicManager.singleton.musicList.Add(song);
}
else
{
customSongs.Add(song);
}
}
backgroundObj = null;
audioAsset = null;
audioClip = null;
}
}
private Dictionary<string, Object> LoadAndRenameAssets(AssetBundle bundle, string prefix)
{
Dictionary<string, Object> dictionary = new Dictionary<string, Object>();
Object[] array = bundle.LoadAllAssets();
Object[] array2 = array;
foreach (Object val in array2)
{
string text = Path.GetFileName(val.name);
if (!text.StartsWith(prefix + "_"))
{
text = prefix + "_" + text;
}
val.name = text;
dictionary[text] = val;
}
foreach (string key in dictionary.Keys)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)("Renamed asset: " + key));
}
((BaseUnityPlugin)this).Logger.LogInfo((object)("All assets in bundle have been renamed with prefix: " + prefix + "_"));
return dictionary;
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
((MonoBehaviour)this).StartCoroutine(UpdateGameSettingsPanel());
bool flag = false;
foreach (CustomMapData value in customMapDataDict.Values)
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(value.scenePath);
if (((Scene)(ref scene)).name.Equals(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
{
flag = true;
break;
}
}
if (flag)
{
((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom map scene loaded; scheduling object modifications...");
((MonoBehaviour)this).StartCoroutine(ModifyCustomMapObjects());
}
}
private IEnumerator UpdateGameSettingsPanel()
{
while ((Object)(object)GameSettingsPanel.singleton == (Object)null)
{
yield return null;
}
GameSettingsPanel singleton = GameSettingsPanel.singleton;
foreach (MapItem mapItem in allMapItems)
{
if (!singleton.mapList.Exists((MapItem x) => x.mapName == mapItem.mapName))
{
singleton.mapList.Add(mapItem);
}
if (!singleton.mapSelect.buttonOptions.Exists((ButtonOption x) => x.optionValue == mapItem.mapName))
{
singleton.mapSelect.buttonOptions.Add(new ButtonOption
{
optionText = mapItem.mapName,
optionValue = mapItem.mapName
});
}
}
singleton.UpdateMapBackground();
}
private IEnumerator ModifyCustomMapObjects()
{
float timeout = 5f;
float timer = 0f;
while (timer < timeout && (Object)(object)Object.FindObjectOfType<Renderer>() == (Object)null && (Object)(object)Object.FindObjectOfType<Collider>() == (Object)null)
{
timer += Time.deltaTime;
yield return null;
}
ReconnectShaders();
Collider[] colliders = Object.FindObjectsOfType<Collider>();
int mapPartLayer = LayerMask.NameToLayer("MapPart");
Collider[] array = colliders;
foreach (Collider col in array)
{
((Component)col).gameObject.layer = mapPartLayer;
}
((BaseUnityPlugin)this).Logger.LogInfo((object)"Custom map scene object modifications complete.");
}
private void ReconnectShaders()
{
Renderer[] array = Object.FindObjectsOfType<Renderer>();
for (int i = 0; i < array.Length; i++)
{
Material[] materials = array[i].materials;
foreach (Material val in materials)
{
val.shader = Shader.Find(((Object)val.shader).name);
}
}
}
}
[Serializable]
public class MapInfo
{
public string mapName;
public string assetsBundleFileName;
public string sceneBundleFileName;
public string sceneAssetPath;
public string mapBackgroundAssetName;
}
public class CustomMapData
{
public string scenePath;
public AssetBundle assetsBundle;
public AssetBundle sceneBundle;
public Dictionary<string, Object> renamedAssets;
}
[HarmonyPatch(typeof(SceneManagerWithParameters), "DoSceneLoad")]
public class DoSceneLoadPatch
{
private static bool Prefix(bool forceShowLoadingBar, bool manuallyHideLoadingBar)
{
if (!string.IsNullOrEmpty(MapPlugin.selectedCustomMapName) && MapPlugin.customMapDataDict.TryGetValue(MapPlugin.selectedCustomMapName, out var value))
{
Debug.Log((object)("Overriding scene load with custom map: " + MapPlugin.selectedCustomMapName));
LoadMaterialsFromBundle(value.assetsBundle);
SceneManager.LoadSceneAsync(value.scenePath);
SceneManagerWithParameters.loadingGameScene = true;
return false;
}
return true;
}
private static void LoadMaterialsFromBundle(AssetBundle bundle)
{
if ((Object)(object)bundle == (Object)null)
{
Debug.LogError((object)"Asset bundle is null. Materials will not load.");
return;
}
Material[] array = bundle.LoadAllAssets<Material>();
Material[] array2 = array;
foreach (Material val in array2)
{
Debug.Log((object)("Loaded material: " + ((Object)val).name));
}
}
}
[HarmonyPatch(typeof(MusicManager), "Awake")]
public class MusicManagerAwakePatch
{
private static void Postfix(MusicManager __instance)
{
foreach (SongSound song in MapPlugin.customSongs)
{
if (!__instance.musicList.Exists((SongSound x) => x.sceneName == song.sceneName))
{
__instance.musicList.Add(song);
}
}
MapPlugin.customSongs.Clear();
}
}