Esempio n. 1
0
    protected override async UniTask UpdateEditorFieldsAsync()
    {
        FileSystem.Mode fileMode = FileSystem.Mode.Normal;
        if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebGL)
        {
            fileMode = FileSystem.Mode.Web;
        }

        bool refreshGameActions = (GameModeDropdown?.HasChanged ?? false) || (MapSelectionDropdown?.HasChanged ?? false);

        // Increase label width due to it being cut off otherwise
        EditorGUIUtility.labelWidth = 192;

        if (TotalyPos == 0f)
        {
            TotalyPos = position.height;
        }

        scrollbarShown = TotalyPos > position.height;
        ScrollPosition = GUI.BeginScrollView(new Rect(0, 0, EditorGUIUtility.currentViewWidth, position.height), ScrollPosition, new Rect(0, 0, EditorGUIUtility.currentViewWidth - (scrollbarShown ? scrollbarWidth : 0f), TotalyPos));

        EditorGUI.BeginChangeCheck();

        if (fileMode == FileSystem.Mode.Web)
        {
            EditorGUI.HelpBox(GetNextRect(ref YPos, height: 40f), "Your build target is configured as WebGL. Ray1Map will attempt to load from the server.", MessageType.Warning);
        }

        // Mode

        DrawHeader("Mode");

        if (GameModeDropdown == null)
        {
            GameModeDropdown = new GameModeSelectionDropdown(new AdvancedDropdownState());
        }
        var rectTemp = GetNextRect(ref YPos);
        var rbutton  = EditorGUI.PrefixLabel(rectTemp, new GUIContent("Game"));

        rectTemp = new Rect(rbutton.x + rbutton.width - Mathf.Max(400f, rbutton.width), rbutton.y, Mathf.Max(400f, rbutton.width), rbutton.height);
        if (EditorGUI.DropdownButton(rbutton, new GUIContent(GameModeDropdown.SelectionName), FocusType.Passive))
        {
            GameModeDropdown.Show(rectTemp);
        }

        Settings.LoadFromMemory = EditorField("Load from memory", Settings.LoadFromMemory);

        // Memory

        if (Settings.LoadFromMemory)
        {
            DrawHeader("Memory");

            DefaultMemoryOptionsIndex = EditorField("Default memory options", DefaultMemoryOptionsIndex, DefaultMemoryOptionDisplayNames);

            if (DefaultMemoryOptionsIndex != PreviousDefaultMemoryOptionsIndex)
            {
                if (PreviousDefaultMemoryOptionsIndex == -1)
                {
                    var match = Enumerable.Range(0, DefaultMemoryOptionDisplayNames.Length - 1).FirstOrDefault(x =>
                                                                                                               DefaultMemoryConfigs[x].IsPointer == Settings.IsGameBaseAPointer &&
                                                                                                               DefaultMemoryConfigs[x].ProcessName == Settings.ProcessName &&
                                                                                                               DefaultMemoryConfigs[x].ModuleName == Settings.ModuleName &&
                                                                                                               DefaultMemoryConfigs[x].Offset == Settings.GameBasePointer);

                    DefaultMemoryOptionsIndex = match + 1;
                }

                PreviousDefaultMemoryOptionsIndex = DefaultMemoryOptionsIndex;

                if (DefaultMemoryOptionsIndex != 0)
                {
                    Settings.IsGameBaseAPointer = DefaultMemoryConfigs[DefaultMemoryOptionsIndex - 1].IsPointer;
                    Settings.ProcessName        = DefaultMemoryConfigs[DefaultMemoryOptionsIndex - 1].ProcessName;
                    Settings.ModuleName         = DefaultMemoryConfigs[DefaultMemoryOptionsIndex - 1].ModuleName;
                    Settings.GameBasePointer    = DefaultMemoryConfigs[DefaultMemoryOptionsIndex - 1].Offset;
                }
            }

            EditorGUI.BeginDisabledGroup(DefaultMemoryOptionsIndex != 0);

            Settings.ProcessName        = EditorField("Process name", Settings.ProcessName);
            Settings.ModuleName         = EditorField("Module name", Settings.ModuleName);
            Settings.GameBasePointer    = EditorField("Game memory offset", Settings.GameBasePointer);
            Settings.IsGameBaseAPointer = EditorField("Is offset a pointer", Settings.IsGameBaseAPointer);

            EditorGUI.EndDisabledGroup();

            Settings.FindPointerAutomatically = EditorField("Find pointer automatically", Settings.FindPointerAutomatically);
        }

        // Map

        DrawHeader("Map");

        if (fileMode == FileSystem.Mode.Normal)
        {
            rectTemp = GetNextRect(ref YPos);
            rbutton  = EditorGUI.PrefixLabel(rectTemp, new GUIContent("Map"));
            rectTemp = new Rect(rbutton.x + rbutton.width - Mathf.Max(400f, rbutton.width), rbutton.y, Mathf.Max(400f, rbutton.width), rbutton.height);

            if (MapSelectionDropdown == null || GameModeDropdown.HasChanged)
            {
                if (GameModeDropdown.HasChanged)
                {
                    Settings.SelectedGameMode   = GameModeDropdown.Selection;
                    GameModeDropdown.HasChanged = false;
                    Dirty = true;
                }

                GameInfo_Volume[] volumes;

                try {
                    var manager  = Settings.GetGameManager;
                    var settings = Settings.GetGameSettings;

                    volumes = manager.GetLevels(settings);
                } catch (Exception ex) {
                    volumes = new GameInfo_Volume[0];
                    Debug.LogWarning(ex.Message);
                }

                MapSelectionDropdown = new MapSelectionDropdown(new AdvancedDropdownState(), volumes, Settings.SelectedGameMode.GetAttribute <GameModeAttribute>().Game);

                // Debug.Log($"Map selection updated with {volumes.Length} volumes");
            }

            if (EditorGUI.DropdownButton(rbutton, new GUIContent($"{(!string.IsNullOrEmpty(Settings.EduVolume) ? $"{Settings.EduVolume} - " : String.Empty)}{MapSelectionDropdown.GetWorldName(Settings.World)} {MapSelectionDropdown.GetLevelName(Settings.World, Settings.Level)}"), FocusType.Passive))
            {
                MapSelectionDropdown.Show(rectTemp);
            }
        }
        else if (fileMode == FileSystem.Mode.Web)
        {
            if (GameModeDropdown.HasChanged)
            {
                Settings.SelectedGameMode   = GameModeDropdown.Selection;
                GameModeDropdown.HasChanged = false;
                Dirty = true;
            }
            Settings.World     = EditorField("World", Settings.World);
            Settings.Level     = EditorField("Level", Settings.Level);
            Settings.EduVolume = EditorField("Volume", Settings.EduVolume);
        }

        // Directories
        DrawHeader("Directories" + (fileMode == FileSystem.Mode.Web ? " (Web)" : ""));

        Settings.HideDirSettings = !EditorGUI.Foldout(GetNextRect(ref YPos), !Settings.HideDirSettings, "Directories", true);

        if (!Settings.HideDirSettings)
        {
            var modes = EnumHelpers.GetValues <GameModeSelection>();
            if (fileMode == FileSystem.Mode.Web)
            {
                foreach (var mode in modes)
                {
                    Settings.GameDirectoriesWeb[mode] = EditorField(mode.GetAttribute <GameModeAttribute>()?.DisplayName ?? "N/A", Settings.GameDirectoriesWeb.TryGetItem(mode, String.Empty));
                }
            }
            else
            {
                foreach (var mode in modes)
                {
                    Settings.GameDirectories[mode] = DirectoryField(GetNextRect(ref YPos), mode.GetAttribute <GameModeAttribute>()?.DisplayName ?? "N/A", Settings.GameDirectories.TryGetItem(mode, String.Empty));
                }
            }
        }

        // Visibility

        DrawHeader("Visibility");

        Settings.ShowObjects = EditorField("Show objects (O)", Settings.ShowObjects);

        Settings.ShowLinks = EditorField("Show links (L)", Settings.ShowLinks);

        Settings.ShowTiles = EditorField("Show tiles (T)", Settings.ShowTiles);

        Settings.ShowCollision = EditorField("Show tile collision (C)", Settings.ShowCollision);

        Settings.ShowGridMap = EditorField("Show grid map", Settings.ShowGridMap);

        Settings.ShowObjCollision = EditorField("Show object collision (B)", Settings.ShowObjCollision);

        Settings.ShowAlwaysObjects = EditorField("Show always objects (G)", Settings.ShowAlwaysObjects);

        Settings.ShowEditorObjects = EditorField("Show editor objects (E)", Settings.ShowEditorObjects);

        Settings.ShowDefaultObjIcons = EditorField("Show gizmos", Settings.ShowDefaultObjIcons);

        Settings.ShowObjOffsets = EditorField("Show object offsets (X)", Settings.ShowObjOffsets);

        Settings.ShowRayman = EditorField("Show Rayman object (R)", Settings.ShowRayman);

        Settings.HideUnusedLinks = EditorField("Hide unused links", Settings.HideUnusedLinks);

        // Miscellaneous

        DrawHeader("Miscellaneous");

        Settings.UseHDCollisionSheet = EditorField("Use HD collision sheet", Settings.UseHDCollisionSheet);

        Settings.AnimateSprites = EditorField("Animate sprites (P)", Settings.AnimateSprites);

        Settings.AnimateTiles = EditorField("Animate tiles (Y)", Settings.AnimateTiles);

        Settings.ShowDebugInfo = EditorField("Show debug info", Settings.ShowDebugInfo);

        Settings.FollowRaymanInMemoryMode = EditorField("Follow Rayman in memory mode", Settings.FollowRaymanInMemoryMode);

        // Game Settings

        DrawHeader("Game Settings");

        Settings.StateSwitchingMode = EditorField("R1: State switching", Settings.StateSwitchingMode);

        Settings.LoadIsometricMapLayer = EditorField("Isometric: Load map layer", Settings.LoadIsometricMapLayer);

        Settings.GBAVV_Crash_TimeTrialMode = EditorField("GBAVV Crash: Time trial mode", Settings.GBAVV_Crash_TimeTrialMode);

        // Editor Tools
        if (Application.isPlaying && Controller.LoadState == Controller.State.Finished)
        {
            var lvl = LevelEditorData.Level;

            if (lvl != null)
            {
                DrawHeader("Editor Tools");

                if (EditorButton("Copy localization"))
                {
                    if (lvl.Localization != null)
                    {
                        JsonConvert.SerializeObject(lvl.Localization, Formatting.Indented).CopyToClipboard();
                    }
                }

                if (LevelEditorData.ObjManager is Unity_ObjectManager_R1 r1 && r1.EventFlags != null)
                {
                    if (EditorButton("Copy event flag info"))
                    {
                        r1.GetEventFlagsDebugInfo().CopyToClipboard();
                    }
                }

                if (LevelEditorData.Level?.IsometricData != null)
                {
                    var cam = Controller.obj?.levelController?.editor?.cam;
                    if (cam != null)
                    {
                        cam.ToggleFreeCameraMode(EditorField($"Free camera mode (F)", cam.FreeCameraMode));
                    }
                }

                if (Controller.obj?.levelController?.controllerTilemap != null)
                {
                    var tilemapController = Controller.obj.levelController.controllerTilemap;

                    if (lvl.Background != null && tilemapController.background != null)
                    {
                        var bg = tilemapController.background;

                        var isActive = EditorField($"Show background", bg.gameObject.activeSelf);

                        if (isActive != bg.gameObject.activeSelf)
                        {
                            bg.gameObject.SetActive(isActive);
                        }
                    }

                    if (lvl.ParallaxBackground != null && tilemapController.backgroundParallax != null)
                    {
                        var bg = tilemapController.backgroundParallax;

                        var isActive = EditorField($"Show parallax background", bg.gameObject.activeSelf);

                        if (isActive != bg.gameObject.activeSelf)
                        {
                            bg.gameObject.SetActive(isActive);
                        }
                    }
                    var layerVisibilities = tilemapController.IsLayerVisible;
                    if (layerVisibilities != null)
                    {
                        for (int i = 0; i < layerVisibilities.Length; i++)
                        {
                            layerVisibilities[i] = EditorField($"Show layer {i} ({LevelEditorData.Level.Maps[i].Type})", layerVisibilities[i]);
                        }
                    }
                    if (lvl.Background != null && tilemapController.background != null)
                    {
                        var bg  = tilemapController.background;
                        var spr = bg.sprite;
                        if (spr == null ||
                            spr.rect.width / spr.pixelsPerUnit != LevelEditorData.MaxWidth * tilemapController.CellSizeInUnits ||
                            spr.rect.height / spr.pixelsPerUnit != LevelEditorData.MaxHeight * tilemapController.CellSizeInUnits)
                        {
                            bool wasTiled = bg.drawMode == SpriteDrawMode.Tiled;
                            bool setTiled = EditorField($"Tile background", wasTiled);

                            if (setTiled != wasTiled)
                            {
                                tilemapController.SetGraphicsLayerTiled(LevelTilemapController.Index_Background, setTiled);
                            }
                        }
                    }
                    if (lvl.Background != null && tilemapController.backgroundParallax != null)
                    {
                        var bg  = tilemapController.backgroundParallax;
                        var spr = bg.sprite;
                        if (spr == null ||
                            spr.rect.width / spr.pixelsPerUnit != LevelEditorData.MaxWidth * tilemapController.CellSizeInUnits ||
                            spr.rect.height / spr.pixelsPerUnit != LevelEditorData.MaxHeight * tilemapController.CellSizeInUnits)
                        {
                            bool wasTiled = bg.drawMode == SpriteDrawMode.Tiled;
                            bool setTiled = EditorField($"Tile parallax background", wasTiled);

                            if (setTiled != wasTiled)
                            {
                                tilemapController.SetGraphicsLayerTiled(LevelTilemapController.Index_ParallaxBackground, setTiled);
                            }
                        }
                    }
                    if (tilemapController.GraphicsTilemaps != null)
                    {
                        for (int i = 0; i < tilemapController.GraphicsTilemaps.Length; i++)
                        {
                            if (tilemapController.GraphicsTilemaps[i] != null)
                            {
                                var spr = tilemapController.GraphicsTilemaps[i].sprite;
                                if (spr == null ||
                                    spr.rect.width / spr.pixelsPerUnit != LevelEditorData.MaxWidth * tilemapController.CellSizeInUnits ||
                                    spr.rect.height / spr.pixelsPerUnit != LevelEditorData.MaxHeight * tilemapController.CellSizeInUnits)
                                {
                                    bool wasTiled = tilemapController.GraphicsTilemaps[i].drawMode == SpriteDrawMode.Tiled;
                                    bool setTiled = EditorField($"Tile graphics layer {i}", wasTiled);

                                    if (setTiled != wasTiled)
                                    {
                                        tilemapController.SetGraphicsLayerTiled(i, setTiled);
                                    }
                                }
                            }
                        }
                    }
                }

                if (LevelEditorData.ShowEventsForMaps != null)
                {
                    for (int i = 0; i < LevelEditorData.ShowEventsForMaps.Length; i++)
                    {
                        LevelEditorData.ShowEventsForMaps[i] = EditorField($"Show objects for layer {i}", LevelEditorData.ShowEventsForMaps[i]);
                    }
                }

                if (LevelEditorData.Level?.Sectors != null)
                {
                    LevelEditorData.ShowOnlyActiveSector = EditorField("Show only active sector", LevelEditorData.ShowOnlyActiveSector);

                    LevelEditorData.ActiveSector = EditorField("Active sector", LevelEditorData.ActiveSector, LevelEditorData.Level.Sectors.Select((x, i) => i.ToString()).ToArray(), isVisible: LevelEditorData.ShowOnlyActiveSector);
                }

                if (PalOptions == null)
                {
                    if (Controller.obj.levelController.controllerTilemap.HasAutoPaletteOption)
                    {
                        PalOptions = new string[]
                        {
                            "Auto"
                        }.Concat(Enumerable.Range(0, LevelEditorData.Level.Maps.Max(x => x.TileSet.Length)).Select(x => x.ToString())).ToArray();
                    }
                    else
                    {
                        PalOptions = Enumerable.Range(0, LevelEditorData.Level.Maps.Max(x => x.TileSet.Length)).Select(x => x.ToString()).ToArray();
                    }
                }

                if (Controller.obj?.levelController?.controllerTilemap != null)
                {
                    if (Controller.obj.levelController.controllerTilemap.HasAutoPaletteOption)
                    {
                        Controller.obj.levelController.controllerTilemap.currentPalette = EditorField("Palette", Controller.obj.levelController.controllerTilemap.currentPalette, PalOptions);
                    }
                    else
                    {
                        Controller.obj.levelController.controllerTilemap.currentPalette = EditorField("Palette", Controller.obj.levelController.controllerTilemap.currentPalette - 1, PalOptions) + 1;
                    }
                }
            }
        }
        else
        {
            PalOptions = null;
        }

        // Screenshots

        DrawHeader("Screenshots");

        Settings.ScreenshotEnumeration = EditorField("Screenshot enumeration", Settings.ScreenshotEnumeration);

        Settings.Screenshot_FileName = EditorField("File name", Settings.Screenshot_FileName);

        Settings.Screenshot_ShowDefaultObj = EditorField("Show default object", Settings.Screenshot_ShowDefaultObj);

        Settings.Screenshot_RayWikiMode = EditorField("RayWiki mode", Settings.Screenshot_RayWikiMode);

        // Serialization

        DrawHeader("Serialization");

        Settings.BackupFiles = EditorField("Create .BAK backup files", Settings.BackupFiles);

        Rect rect = GetNextRect(ref YPos);

        rect = EditorGUI.PrefixLabel(rect, new GUIContent("Serialization log"));
        bool log = Settings.Log;

        rect         = PrefixToggle(rect, ref log);
        Settings.Log = log;

        if (Settings.Log)
        {
            Settings.LogFile = FileField(rect, "Serialization log File", Settings.LogFile, true, "txt", includeLabel: false);
        }

        // External Tools

        DrawHeader("External Tools");

        Settings.Tool_mkpsxiso_filePath = FileField(GetNextRect(ref YPos), "mkpsxiso path", Settings.Tool_mkpsxiso_filePath, false, "exe");

        // Game Tools

        DrawHeader("Game Tools");

        // Only update if previous values don't match
        if (CurrentGameActions == null || refreshGameActions)
        {
            if (fileMode != FileSystem.Mode.Web)
            {
                MapSelectionDropdown.HasChanged = false;
                Settings.EduVolume = MapSelectionDropdown.SelectedVolume;
                Settings.World     = MapSelectionDropdown.SelectedWorld;
                Settings.Level     = MapSelectionDropdown.SelectedMap;
            }
            Dirty = true;
            CurrentGameActions = Settings.GetGameManager.GetGameActions(Settings.GetGameSettings);
        }

        // Add every game action
        foreach (GameAction action in CurrentGameActions)
        {
            if (EditorButton(action.DisplayName))
            {
                // Get the directories
                string inputDir = action.RequiresInputDir ? EditorUtility.OpenFolderPanel("Select input directory", null, "") : null;

                if (string.IsNullOrEmpty(inputDir) && action.RequiresInputDir)
                {
                    return;
                }

                string outputDir = action.RequiresOutputDir ? EditorUtility.OpenFolderPanel("Select output directory", null, "") : null;

                if (string.IsNullOrEmpty(outputDir) && action.RequiresOutputDir)
                {
                    return;
                }
                try {
                    Controller.StartStopwatch();
                    // Run the action
                    await action.GameActionFunc(inputDir, outputDir);
                } catch (Exception ex) {
                    Debug.LogError(ex.ToString());
                } finally {
                    Controller.StopStopwatch();
                }
            }
        }

        // Global Tools

        DrawHeader("Global Tools");

        async UniTask AddGlobalActionAsync(string actionName)
        {
            if (EditorButton(actionName))
            {
                // Get the output directory
                string outputDir = EditorUtility.OpenFolderPanel("Select output directory", null, "");

                if (string.IsNullOrEmpty(outputDir))
                {
                    return;
                }

                //const GameModeSelection start = GameModeSelection.RaymanJaguar;
                //var reachedStart = false;

                // Run each action
                foreach (var mode in EnumHelpers.GetValues <GameModeSelection>())
                {
                    //if (!reachedStart)
                    //{
                    //    if (mode == start)
                    //        reachedStart = true;
                    //    else
                    //        continue;
                    //}

                    // Make sure the mode is valid
                    if (!Settings.GameDirectories.ContainsKey(mode))
                    {
                        Debug.LogWarning($"Mode {mode} was skipped due to not having a valid directory");
                        continue;
                    }

                    // Create settings
                    var settings = new GameSettings(mode, Settings.GameDirectories[mode], Settings.World, Settings.Level);

                    // Get manager
                    var manager = settings.GetGameManager;

                    // Set to default EDU volume
                    settings.EduVolume = manager.GetLevels(settings).FirstOrDefault()?.Name;

                    // Get action
                    var action = manager.GetGameActions(settings).FirstOrDefault(x => x.DisplayName.Equals(actionName, StringComparison.CurrentCultureIgnoreCase));

                    // Make sure an action was found
                    if (action == null)
                    {
                        Debug.LogWarning($"Mode {mode} was skipped due to not having a matching action");
                        continue;
                    }

                    try
                    {
                        // Run the action
                        await action.GameActionFunc(null, Path.Combine(outputDir, mode.ToString()));
                    }
                    catch (Exception ex)
                    {
                        Debug.LogWarning($"Mode {mode} failed with exception: {ex.Message}");
                    }
                    finally
                    {
                        // Unload textures
                        await Resources.UnloadUnusedAssets();
                    }
                }
            }
        }

        // Add special game actions
        await AddGlobalActionAsync("Export Sprites");
        await AddGlobalActionAsync("Export Animation Frames");
        await AddGlobalActionAsync("Export Vignette");

        // Randomizer

        DrawHeader("Randomizer");

        if (EditorButton("Run Randomizer"))
        {
            string seed = $"{Settings.World},{Settings.Level},{Settings.RandomizerSeed}";
            Randomizer.Randomize(LevelEditorData.Level, Settings.World, Settings.Level, Settings.RandomizerFlags, seed.GetHashCode(), 0, null);
        }

        if (EditorButton("Run Batch Randomizer"))
        {
            await Randomizer.BatchRandomizeAsync();
        }

        Settings.RandomizerSeed = EditorField("Seed", Settings.RandomizerSeed);

        Settings.RandomizerFlags = (RandomizerFlags)EditorGUI.EnumFlagsField(GetNextRect(ref YPos), "Flags", Settings.RandomizerFlags);

        TotalyPos = YPos;
        GUI.EndScrollView();

        if (EditorGUI.EndChangeCheck() || Dirty)
        {
            Settings.Save();
            Dirty = false;
        }
    }
Esempio n. 2
0
    protected override void UpdateEditorFields()
    {
        FileSystem.Mode fileMode = FileSystem.Mode.Normal;
        if (EditorUserBuildSettings.activeBuildTarget == BuildTarget.WebGL)
        {
            fileMode = FileSystem.Mode.Web;
        }

        // Increase label width due to it being cut off otherwise
        EditorGUIUtility.labelWidth = 192;


        if (CategorizedGameModes == null)
        {
            CategorizedGameModes = EnumHelpers.GetValues <Settings.Mode>().Select(x => Settings.GetSettings(x))
                                   .GroupBy(x => x.engineVersion).ToDictionary(
                x => x.Key,
                x => x
                .GroupBy(y => y.game)
                .ToDictionary(y => y.Key, y => y.ToArray())
                );
        }


        EditorGUI.BeginChangeCheck();
        // Game Mode
        DrawHeader(ref YPos, "Mode");

        if (GameModeDropdown == null)
        {
            GameModeDropdown = new GameModeSelectionDropdown(new AdvancedDropdownState());
        }
        var rectTemp = GetNextRect(ref YPos);
        var rbutton  = EditorGUI.PrefixLabel(rectTemp, new GUIContent("Game"));

        rectTemp = new Rect(rbutton.x + rbutton.width - Mathf.Max(400f, rbutton.width), rbutton.y, Mathf.Max(400f, rbutton.width), rbutton.height);
        if (EditorGUI.DropdownButton(rbutton, new GUIContent(GameModeDropdown.SelectionName), FocusType.Passive))
        {
            GameModeDropdown.Show(rectTemp);
        }

        if (GameModeDropdown != null && GameModeDropdown.HasChanged)
        {
            UnitySettings.GameMode      = GameModeDropdown.Selection;
            GameModeDropdown.HasChanged = false;
            Dirty = true;
        }

        // Scene file
        DrawHeader(ref YPos, "Map");

        string buttonString = "No map selected";

        if (!string.IsNullOrEmpty(UnitySettings.MapName))
        {
            buttonString = UnitySettings.MapName;
            if (UnitySettings.UseLevelTranslation && Settings.settingsDict[UnitySettings.GameMode].levelTranslation != null)
            {
                buttonString = Settings.settingsDict[UnitySettings.GameMode].levelTranslation.Translate(UnitySettings.MapName);
            }
        }
        Rect rect = GetNextRect(ref YPos, vPaddingBottom: 4f);

        rect = EditorGUI.PrefixLabel(rect, new GUIContent("Map name"));
        if (fileMode == FileSystem.Mode.Web)
        {
            UnitySettings.MapName = EditorGUI.TextField(rect, UnitySettings.MapName);
            EditorGUI.HelpBox(GetNextRect(ref YPos, height: 40f), "Your build target is configured as WebGL. Raymap will attempt to load from the server. Make sure the caps in the map name are correct.", MessageType.Warning);
        }
        else
        {
            EditorGUI.BeginDisabledGroup(UnitySettings.LoadFromMemory);
            if (EditorGUI.DropdownButton(rect, new GUIContent(buttonString), FocusType.Passive))
            {
                // Initialize settings
                Settings.Init(UnitySettings.GameMode);
                string directory = CurrentGameDataDir;

                /*string directory = (UnitySettings.CurrentGameDataDir + "/" + Settings.s.ITFDirectory).Replace(Path.DirectorySeparatorChar, '/');
                 * if (!directory.EndsWith("/")) directory += "/";
                 * while (directory.Contains("//")) directory = directory.Replace("//", "/");
                 * string extension = "*.isc";
                 * if (Settings.s.cooked) {
                 *      extension += ".ckd";
                 * }*/

                if (MapDropdown == null || MapDropdown.directory != directory || MapDropdown.mode != UnitySettings.GameMode)
                {
                    MapDropdown = new MapSelectionDropdown(new UnityEditor.IMGUI.Controls.AdvancedDropdownState(), directory)
                    {
                        name = "Maps",
                        mode = UnitySettings.GameMode
                    };
                }
                MapDropdown.Show(rect);
            }
            EditorGUI.EndDisabledGroup();
        }
        if (MapDropdown != null && MapDropdown.selection != null)
        {
            UnitySettings.MapName = MapDropdown.selection;
            MapDropdown.selection = null;
            Dirty = true;
        }
        if (Settings.settingsDict[UnitySettings.GameMode].platform == Settings.Platform.PS1)
        {
            OpenSpace.PS1.PS1GameInfo.Games.TryGetValue(UnitySettings.GameMode, out OpenSpace.PS1.PS1GameInfo game);
            if (game != null && game.actors?.Where(a => a.isSelectable).Count() > 0)
            {
                int mapIndex = Array.IndexOf(game.maps.Select(s => s.ToLower()).ToArray(), UnitySettings.MapName.ToLower());
                if (mapIndex != -1 && game.files.FirstOrDefault(f => f.type == OpenSpace.PS1.PS1GameInfo.File.Type.Map).memoryBlocks[mapIndex].isActorSelectable)
                {
                    if (game.actors?.Where(a => a.isSelectable && a.isSelectableActor1).Count() > 0)
                    {
                        rect         = GetNextRect(ref YPos, vPaddingBottom: 4f);
                        rect         = EditorGUI.PrefixLabel(rect, new GUIContent("Actor 1"));
                        buttonString = "No actor selected";
                        if (!string.IsNullOrEmpty(UnitySettings.Actor1Name))
                        {
                            buttonString = UnitySettings.Actor1Name;
                        }
                        if (fileMode == FileSystem.Mode.Web)
                        {
                            UnitySettings.Actor1Name = EditorGUI.TextField(rect, UnitySettings.Actor1Name);
                        }
                        else
                        {
                            EditorGUI.BeginDisabledGroup(UnitySettings.LoadFromMemory);
                            if (EditorGUI.DropdownButton(rect, new GUIContent(buttonString), FocusType.Passive))
                            {
                                if (ActorDropdown1 == null || ActorDropdown1.mode != UnitySettings.GameMode)
                                {
                                    ActorDropdown1 = new PS1ActorSelectionDropdown(new UnityEditor.IMGUI.Controls.AdvancedDropdownState(), UnitySettings.GameMode, 0)
                                    {
                                        name = "Actors"
                                    };
                                }
                                ActorDropdown1.Show(rect);
                            }
                            EditorGUI.EndDisabledGroup();
                        }
                        if (ActorDropdown1 != null && ActorDropdown1.selection != null)
                        {
                            UnitySettings.Actor1Name = ActorDropdown1.selection;
                            ActorDropdown1.selection = null;
                            Dirty = true;
                        }
                    }
                    if (game.actors?.Where(a => a.isSelectable && a.isSelectableActor2).Count() > 0)
                    {
                        rect         = GetNextRect(ref YPos, vPaddingBottom: 4f);
                        rect         = EditorGUI.PrefixLabel(rect, new GUIContent("Actor 2"));
                        buttonString = "No actor selected";
                        if (!string.IsNullOrEmpty(UnitySettings.Actor2Name))
                        {
                            buttonString = UnitySettings.Actor2Name;
                        }
                        if (fileMode == FileSystem.Mode.Web)
                        {
                            UnitySettings.Actor2Name = EditorGUI.TextField(rect, UnitySettings.Actor2Name);
                        }
                        else
                        {
                            EditorGUI.BeginDisabledGroup(UnitySettings.LoadFromMemory);
                            if (EditorGUI.DropdownButton(rect, new GUIContent(buttonString), FocusType.Passive))
                            {
                                if (ActorDropdown2 == null || ActorDropdown2.mode != UnitySettings.GameMode)
                                {
                                    ActorDropdown2 = new PS1ActorSelectionDropdown(new UnityEditor.IMGUI.Controls.AdvancedDropdownState(), UnitySettings.GameMode, 1)
                                    {
                                        name = "Actors"
                                    };
                                }
                                ActorDropdown2.Show(rect);
                            }
                            EditorGUI.EndDisabledGroup();
                        }
                        if (ActorDropdown2 != null && ActorDropdown2.selection != null)
                        {
                            UnitySettings.Actor2Name = ActorDropdown2.selection;
                            ActorDropdown2.selection = null;
                            Dirty = true;
                        }
                    }
                }
            }

            UnitySettings.ExportPS1Files = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Export PS1 Files"), UnitySettings.ExportPS1Files);
        }
        if (fileMode != FileSystem.Mode.Web)
        {
            rect = GetNextRect(ref YPos);
            rect = EditorGUI.PrefixLabel(rect, new GUIContent("Load Process"));
            bool loadFromMemory = UnitySettings.LoadFromMemory;
            rect = PrefixToggle(rect, ref loadFromMemory);
            UnitySettings.LoadFromMemory = loadFromMemory;
            if (UnitySettings.LoadFromMemory)
            {
                Rect extensionRect = new Rect(rect.x + rect.width - 32, rect.y, 32, rect.height);
                EditorGUI.LabelField(extensionRect, ".exe");
                rect = new Rect(rect.x, rect.y, rect.width - 32, rect.height);
                UnitySettings.ProcessName = EditorGUI.TextField(rect, UnitySettings.ProcessName);
            }
        }

        // Directories
        DrawHeader(ref YPos, "Directories" + (fileMode == FileSystem.Mode.Web ? " (Web)" : ""));

        foreach (var modeCategory in CategorizedGameModes)
        {
            UnitySettings.HideDirectories[modeCategory.Key] = !EditorGUI.Foldout(GetNextRect(ref YPos), !UnitySettings.HideDirectories.TryGetItem(modeCategory.Key, true), $"Directories ({modeCategory.Key})", true);

            if (!UnitySettings.HideDirectories[modeCategory.Key])
            {
                foreach (var engine in modeCategory.Value)
                {
                    YPos += 8;

                    var modes = engine.Value;
                    if (fileMode == FileSystem.Mode.Web)
                    {
                        foreach (var mode in modes)
                        {
                            UnitySettings.GameDirectoriesWeb[mode.mode] = EditorField(mode.DisplayName ?? "N/A", UnitySettings.GameDirectoriesWeb.TryGetItem(mode.mode, String.Empty));
                        }
                    }
                    else
                    {
                        foreach (var mode in modes)
                        {
                            UnitySettings.GameDirectories[mode.mode] = DirectoryField(GetNextRect(ref YPos), mode.DisplayName ?? "N/A", UnitySettings.GameDirectories.TryGetItem(mode.mode, String.Empty));
                        }
                    }
                }

                YPos += 8;
            }
        }

        /*Settings.Mode[] modes = (Settings.Mode[])Enum.GetValues(typeof(Settings.Mode));
         * if (fileMode == FileSystem.Mode.Web) {
         *      foreach (Settings.Mode mode in modes) {
         *              UnitySettings.GameDirectoriesWeb[mode] = EditorGUI.TextField(GetNextRect(ref YPos), mode.GetDescription(), UnitySettings.GameDirectoriesWeb.ContainsKey(mode) ? UnitySettings.GameDirectoriesWeb[mode] : "");
         *      }
         * } else {
         *      foreach (Settings.Mode mode in modes) {
         *              UnitySettings.GameDirectories[mode] = DirectoryField(GetNextRect(ref YPos), mode.GetDescription(), UnitySettings.GameDirectories.ContainsKey(mode) ? UnitySettings.GameDirectories[mode] : "");
         *      }
         * }*/
        /*if (GUILayout.Button("Update available scenes")) {
         *      string path = EditorUtility.OpenFilePanel("Scene files", "", "isc.ckd");
         *      if (path.Length != 0) {
         *              //UbiCanvasSettings.SelectedLevelFile = AvailableFiles.ElementAtOrDefault(SelectedLevelFileIndex);
         *      }
         * }*/


        // Serialization
        DrawHeader("Serialization");
        UnitySettings.BackupFiles = EditorField("Create .BAK backup files", UnitySettings.BackupFiles);

        rect = GetNextRect(ref YPos);
        rect = EditorGUI.PrefixLabel(rect, new GUIContent("Serialization log"));
        bool log = UnitySettings.Log;

        rect = PrefixToggle(rect, ref log);
        UnitySettings.Log = log;

        if (UnitySettings.Log)
        {
            UnitySettings.LogFile = FileField(rect, "Serialization log File", UnitySettings.LogFile, true, "txt", includeLabel: false);
        }

        // Export
        DrawHeader(ref YPos, "Export Settings");
        rect = GetNextRect(ref YPos);
        rect = EditorGUI.PrefixLabel(rect, new GUIContent("Export After Load"));
        bool export = UnitySettings.ExportAfterLoad;

        rect = PrefixToggle(rect, ref export);
        UnitySettings.ExportAfterLoad = export;

        rect = GetNextRect(ref YPos);
        rect = EditorGUI.PrefixLabel(rect, new GUIContent("Export Flags"));
        Enum exportFlags = UnitySettings.ExportFlags;

        rect = EnumFlagsToggle(rect, ref exportFlags);
        UnitySettings.ExportFlags = (MapExporter.ExportFlags)exportFlags;

        UnitySettings.ExportPath = DirectoryField(GetNextRect(ref YPos), "Export Path", UnitySettings.ExportPath);

        if (GUI.Button(GetNextRect(ref YPos), "Copy export commands for all levels to clipboard..."))
        {
            GUIUtility.systemCopyBuffer = GenerateExportScript((f) => $"Raymap.exe -batchmode " +
                                                               $"--export {UnitySettings.ExportPath} " +
                                                               $"--flags {(int) UnitySettings.ExportFlags} " +
                                                               $"--mode {UnitySettings.GameMode} " +
                                                               $"--dir \"{UnitySettings.GameDirectories[UnitySettings.GameMode]}\" " +
                                                               $"--level {f}");
        }

        if (GUI.Button(GetNextRect(ref YPos), "Copy blend export commands for all levels to clipboard..."))
        {
            GUIUtility.systemCopyBuffer = GenerateExportScript((f) => $"blender --background --python generate_maps_blend.py -- {UnitySettings.ExportPath} {f} {UnitySettings.ExportPath}/BlendFiles/Levels");
        }

        UnitySettings.ScreenshotAfterLoad = (UnitySettings.ScreenshotAfterLoadSetting)EditorGUI.EnumPopup(GetNextRect(ref YPos), new GUIContent("Screenshot After Load"), UnitySettings.ScreenshotAfterLoad);

        string screenShotScaleString = EditorGUI.TextField(GetNextRect(ref YPos), "Screenshot Scale", UnitySettings.ScreenshotScale.ToString(CultureInfo.InvariantCulture));

        if (float.TryParse(screenShotScaleString, out var screenshotScale))
        {
            UnitySettings.ScreenshotScale = screenshotScale;
        }
        else
        {
            UnitySettings.ScreenshotScale = 1;
        }

        UnitySettings.HighlightObjectsFilter = EditorGUI.TextField(GetNextRect(ref YPos), "Highlight objects filter", UnitySettings.HighlightObjectsFilter);
        EditorGUI.LabelField(GetNextRect(ref YPos), "Comma separated list of Model/Family names, or * to highlight all");
        UnitySettings.HighlightObjectsTextFormat = EditorGUI.TextField(GetNextRect(ref YPos), "Highlight format string", UnitySettings.HighlightObjectsTextFormat);
        EditorGUI.LabelField(GetNextRect(ref YPos), "($f=family, $m=model, $i=instance name, $c=count)");

        if (GUI.Button(GetNextRect(ref YPos), "Copy screenshot commands for all levels to clipboard..."))
        {
            GUIUtility.systemCopyBuffer = GenerateExportScript((f) => $"Raymap.exe -batchmode " +
                                                               $"--mode {UnitySettings.GameMode} " +
                                                               $"--dir \"{UnitySettings.GameDirectories[UnitySettings.GameMode]}\" " +
                                                               $"--level {f} " +
                                                               $"--ScreenshotPath \"{UnitySettings.ScreenshotPath}\" " +
                                                               $"--ScreenshotAfterLoad {UnitySettings.ScreenshotAfterLoad} " +
                                                               $"--ScreenshotScale {UnitySettings.ScreenshotScale} " +
                                                               $"--HighlightObjectsFilter \"{UnitySettings.HighlightObjectsFilter}\" " +
                                                               $"--HighlightObjectsTextFormat \"{UnitySettings.HighlightObjectsTextFormat}\"");
        }

        /*if (UnitySettings.ExportAfterLoad) {
         * UnitySettings.ExportPath = DirectoryField(rect, "Export Path", UnitySettings.ExportPath, includeLabel: false);
         * }*/

        // Misc
        DrawHeader(ref YPos, "Miscellaneous Settings");
        UnitySettings.ScreenshotPath          = DirectoryField(GetNextRect(ref YPos), "Screenshot Path", UnitySettings.ScreenshotPath);
        UnitySettings.AllowDeadPointers       = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Allow Dead Pointers"), UnitySettings.AllowDeadPointers);
        UnitySettings.ForceDisplayBackfaces   = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Force Display Backfaces"), UnitySettings.ForceDisplayBackfaces);
        UnitySettings.BlockyMode              = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Blocky Mode"), UnitySettings.BlockyMode);
        UnitySettings.TracePointers           = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Trace Pointers (slow!)"), UnitySettings.TracePointers);
        UnitySettings.SaveTextures            = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Save Textures"), UnitySettings.SaveTextures);
        UnitySettings.ExportText              = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Export Text"), UnitySettings.ExportText);
        UnitySettings.UseLevelTranslation     = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Use Level Translation"), UnitySettings.UseLevelTranslation);
        UnitySettings.VisualizeSectorBorders  = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Visualize Sector Borders"), UnitySettings.VisualizeSectorBorders);
        UnitySettings.CreateFamilyGameObjects = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Create Family GameObjects"), UnitySettings.CreateFamilyGameObjects);
        UnitySettings.ShowCollisionDataForNoCollisionObjects = EditorGUI.Toggle(GetNextRect(ref YPos), new GUIContent("Show Collision Data For NoCollision SPOs"), UnitySettings.ShowCollisionDataForNoCollisionObjects);

        if (EditorGUI.EndChangeCheck() || Dirty)
        {
#if UNITY_EDITOR
            UnitySettings.Save();
#endif
            Dirty = false;
        }
    }