Skip to content

Commit 1c5c7e6

Browse files
committed
Refactored main menu fully, all done. Cotlim plz test and confirm this is fine to update.
- Also made ExtraSmall world generate without errors working, but had to skip a lot of important world gen passes like dungeon, floating islands, etc
1 parent f1712e8 commit 1c5c7e6

8 files changed

Lines changed: 380 additions & 113 deletions

File tree

Lines changed: 174 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,121 @@
1-
using System;
2-
using System.IO;
1+
using System.IO;
2+
using System.Linq;
33
using Microsoft.Xna.Framework.Graphics;
44
using ModReloader.UI.Elements.MainMenuElements;
5+
using Terraria.GameContent;
56
using Terraria.GameContent.UI.Elements;
67
using Terraria.UI;
78

89
namespace ModReloader.Common.Systems.Hooks.MainMenu;
910

1011
internal sealed class MainMenuState : UIState
1112
{
12-
// Colors
13-
private static readonly Color Normal = new(173, 173, 198);
14-
private static readonly Color Hover = new(237, 246, 255);
15-
16-
// Position
17-
private float verticalSpacing = 23f;
18-
private float currentY = 15f;
19-
2013
// Elements
14+
private UIList mainMenuList;
2115
private TooltipPanel tooltipPanel;
22-
private UIText tooltipText;
2316

24-
#region constructor
2517
public MainMenuState()
2618
{
2719
// Null checks
2820
if (Conf.C is null || !Conf.C.ShowMainMenuInfo)
2921
return;
3022

23+
// Set up UIList
24+
mainMenuList = new UIList
25+
{
26+
Width = { Pixels = 310f },
27+
Height = StyleDimension.Fill,
28+
ListPadding = 0f,
29+
Left = { Pixels = 15f },
30+
Top = { Pixels = 15f },
31+
ManualSortMethod = (e) => { }
32+
};
33+
3134
// Extra spacing if other big menu mods are loaded
3235
if (ModLoader.HasMod("TerrariaOverhaul") || ModLoader.HasMod("Terramon"))
3336
{
34-
currentY += 205f;
35-
verticalSpacing = 20f; // tighter spacing to try to fit with terramon lol
37+
mainMenuList.Top.Pixels += 205f;
3638
}
3739
if (ModLoader.HasMod("CompatChecker"))
38-
currentY += 30f; // move everything down a bit to fit compat checker elements at the top
40+
mainMenuList.Top.Pixels += 30f;
41+
42+
tooltipPanel = new TooltipPanel();
3943

44+
// Add elements to the main menu list
45+
AddModReloaderSection(tooltipPanel);
46+
AddOptionsSection(tooltipPanel);
47+
AddSingleplayerSection(tooltipPanel);
48+
AddMultiplayerSection(tooltipPanel);
49+
AddWorldSection(tooltipPanel);
50+
51+
Append(tooltipPanel);
52+
Append(mainMenuList);
53+
}
54+
55+
private void AddModReloaderSection(TooltipPanel tooltipPanel)
56+
{
4057
// Helpers
4158
string headerModName = $"{ModContent.GetInstance<ModReloader>().DisplayName} v{ModContent.GetInstance<ModReloader>().Version}";
4259
string reloadHoverMods = ReloadUtilities.IsModsToReloadEmpty ? "No mods selected" : string.Join(",", Conf.C.ModsToReload);
4360

44-
// Add Mod Reloader section
45-
AddOption(headerModName, tooltip: () => Loc.Get("MainMenu.WelcomeTooltip"), isHeader: true);
46-
AddOption(Loc.Get("MainMenu.OpenConfigText"), () => Conf.C.Open(), () => Loc.Get("MainMenu.OpenConfigTooltip"));
47-
AddOption(Loc.Get("MainMenu.ReloadText"), async () => await ReloadUtilities.SinglePlayerReload(), () => Loc.Get("MainMenu.ReloadTooltip", $"[c/FFFF00:{reloadHoverMods}] "));
48-
AddOption(string.Empty);
49-
50-
// Add options section
51-
AddOption(Loc.Get("MainMenu.OptionsHeader"), () => Loc.Get("MainMenu.OptionsTooltip"), isHeader: true);
52-
AddOption(Loc.Get("MainMenu.StartServerText"), MainMenuActions.StartServer, () => Loc.Get("MainMenu.StartServerTooltip"));
53-
AddOption(Loc.Get("MainMenu.StartClientText"), MainMenuActions.StartClient, () => Loc.Get("MainMenu.StartClientTooltip"));
54-
AddOption(Loc.Get("MainMenu.OpenLogText"), Log.OpenClientLog, () => Loc.Get("MainMenu.OpenLogTooltip", $"[c/FFFF00:{Path.GetFileName(Logging.LogPath)}]"));
55-
AddOption(Loc.Get("MainMenu.ClearLogText"), Log.ClearClientLog, () => Loc.Get("MainMenu.ClearLogTooltip", $"[c/FFFF00:{Path.GetFileName(Logging.LogPath)}]"));
56-
AddOption(string.Empty);
57-
58-
// Add singleplayer section
61+
var headerElement = new HeaderMainMenuElement(headerModName, () => Loc.Get("MainMenu.WelcomeTooltip"), tooltipPanel);
62+
var configElement = new ActionMainMenuElement(
63+
() => Conf.C.Open(),
64+
Loc.Get("MainMenu.OpenConfigText"),
65+
() => Loc.Get("MainMenu.OpenConfigTooltip"),
66+
tooltipPanel
67+
);
68+
var reloadElement = new ActionMainMenuElement(
69+
async () => await ReloadUtilities.SinglePlayerReload(),
70+
Loc.Get("MainMenu.ReloadText"),
71+
() => Loc.Get("MainMenu.ReloadTooltip", $"[c/FFFF00:{reloadHoverMods}]"),
72+
tooltipPanel
73+
);
74+
var spacer = new SpacerMainMenuElement();
75+
mainMenuList.Add(headerElement);
76+
mainMenuList.Add(configElement);
77+
mainMenuList.Add(reloadElement);
78+
mainMenuList.Add(spacer);
79+
}
80+
81+
private void AddOptionsSection(TooltipPanel tooltipPanel)
82+
{
83+
var optionsHeader = new HeaderMainMenuElement(Loc.Get("MainMenu.OptionsHeader"), () => Loc.Get("MainMenu.OptionsTooltip"), tooltipPanel);
84+
var startServerElement = new ActionMainMenuElement(
85+
MainMenuActions.StartServer,
86+
Loc.Get("MainMenu.StartServerText"),
87+
() => Loc.Get("MainMenu.StartServerTooltip"),
88+
tooltipPanel
89+
);
90+
var startClientElement = new ActionMainMenuElement(
91+
MainMenuActions.StartClient,
92+
Loc.Get("MainMenu.StartClientText"),
93+
() => Loc.Get("MainMenu.StartClientTooltip"),
94+
tooltipPanel
95+
);
96+
var openLogElement = new ActionMainMenuElement(
97+
Log.OpenClientLog,
98+
Loc.Get("MainMenu.OpenLogText"),
99+
() => Loc.Get("MainMenu.OpenLogTooltip", $"[c/FFFF00:{Path.GetFileName(Logging.LogPath)}]"),
100+
tooltipPanel
101+
);
102+
var clearLogElement = new ActionMainMenuElement(
103+
Log.ClearClientLog,
104+
Loc.Get("MainMenu.ClearLogText"),
105+
() => Loc.Get("MainMenu.ClearLogTooltip", $"[c/FFFF00:{Path.GetFileName(Logging.LogPath)}]"),
106+
tooltipPanel
107+
);
108+
var spacer = new SpacerMainMenuElement();
109+
mainMenuList.Add(optionsHeader);
110+
mainMenuList.Add(startServerElement);
111+
mainMenuList.Add(startClientElement);
112+
mainMenuList.Add(openLogElement);
113+
mainMenuList.Add(clearLogElement);
114+
mainMenuList.Add(spacer);
115+
}
116+
117+
private void AddSingleplayerSection(TooltipPanel tooltipPanel)
118+
{
59119
// Load players and worlds for tooltips
60120
Main.LoadPlayers();
61121
int playerIdx = Conf.C.Player;
@@ -66,109 +126,119 @@ public MainMenuState()
66126
int worldIdx = Conf.C.World;
67127
if (worldIdx < 0 || worldIdx >= Main.WorldList.Count) worldIdx = 0;
68128
string worldName = Main.WorldList.Count > 0 ? Main.WorldList[worldIdx].Name : "";
129+
Log.Info("Loaded and found this many worlds in main menu: " + Main.WorldList.Count);
69130

70-
// Add singleplayer section
71-
AddOption(Loc.Get("MainMenu.SingleplayerHeader"), tooltip: () => Loc.Get("MainMenu.SingleplayerTooltip"), isHeader: true);
72-
AddOption(
73-
Loc.Get("MainMenu.JoinSingleplayerText"),
131+
var singleplayerHeader = new HeaderMainMenuElement(Loc.Get("MainMenu.SingleplayerHeader"), () => Loc.Get("MainMenu.SingleplayerTooltip"), tooltipPanel);
132+
var joinSingleplayer = new ActionMainMenuElement(
74133
() =>
75134
{
76135
ClientDataJsonHelper.ClientMode = ClientMode.SinglePlayer;
77136
ClientDataJsonHelper.PlayerPath = null;
78137
ClientDataJsonHelper.WorldPath = null;
79138
AutoloadPlayerInWorldSystem.EnterSingleplayerWorld();
80139
},
140+
Loc.Get("MainMenu.JoinSingleplayerText"),
81141
() =>
82142
{
83143
if (string.IsNullOrEmpty(playerName) || string.IsNullOrEmpty(worldName))
84144
return Loc.Get("MainMenu.JoinSingleplayerTooltipNoData");
85145
return Loc.Get("MainMenu.JoinSingleplayerTooltip", $"[c/FFFF00:{playerName}]", $"[c/FFFF00:{worldName}]");
86-
}
146+
},
147+
tooltipPanel
87148
);
88-
AddOption(string.Empty);
149+
var spacer = new SpacerMainMenuElement();
150+
mainMenuList.Add(singleplayerHeader);
151+
mainMenuList.Add(joinSingleplayer);
152+
mainMenuList.Add(spacer);
153+
}
89154

90-
// Add multiplayer section
91-
AddOption(Loc.Get("MainMenu.MultiplayerHeader"), tooltip: () => Loc.Get("MainMenu.MultiplayerTooltip"), isHeader: true);
92-
AddOption(Loc.Get("MainMenu.HostMultiplayerText"), AutoloadPlayerInWorldSystem.HostMultiplayerWorld, () => Loc.Get("MainMenu.HostMultiplayerTooltip"));
93-
AddOption(Loc.Get("MainMenu.JoinMultiplayerText"), AutoloadPlayerInWorldSystem.EnterMultiplayerWorld, () => Loc.Get("MainMenu.JoinMultiplayerTooltip"));
94-
AddOption(string.Empty);
155+
private void AddMultiplayerSection(TooltipPanel tooltipPanel)
156+
{
157+
var multiplayerHeader = new HeaderMainMenuElement(Loc.Get("MainMenu.MultiplayerHeader"), () => Loc.Get("MainMenu.MultiplayerTooltip"), tooltipPanel);
158+
var hostMultiplayer = new ActionMainMenuElement(
159+
AutoloadPlayerInWorldSystem.HostMultiplayerWorld,
160+
Loc.Get("MainMenu.HostMultiplayerText"),
161+
() => Loc.Get("MainMenu.HostMultiplayerTooltip"),
162+
tooltipPanel
163+
);
164+
var joinMultiplayer = new ActionMainMenuElement(
165+
AutoloadPlayerInWorldSystem.EnterMultiplayerWorld,
166+
Loc.Get("MainMenu.JoinMultiplayerText"),
167+
() => Loc.Get("MainMenu.JoinMultiplayerTooltip"),
168+
tooltipPanel
169+
);
170+
var spacer = new SpacerMainMenuElement();
171+
mainMenuList.Add(multiplayerHeader);
172+
mainMenuList.Add(hostMultiplayer);
173+
mainMenuList.Add(joinMultiplayer);
174+
mainMenuList.Add(spacer);
175+
}
95176

96-
// Add world section
97-
AddOption(Loc.Get("MainMenu.WorldHeader"), tooltip: () => Loc.Get("MainMenu.WorldTooltip"), isHeader: true);
98-
AddOption(
99-
Loc.Get("MainMenu.CreateNewWorld"),
177+
private void AddWorldSection(TooltipPanel tooltipPanel)
178+
{
179+
var worldHeader = new HeaderMainMenuElement(Loc.Get("MainMenu.WorldHeader"), () => Loc.Get("MainMenu.WorldTooltip"), tooltipPanel);
180+
var createNewWorld = new ActionMainMenuElement(
100181
() => MainMenuActions.CreateNewWorld(MainMenuActions.GetNextAvailableTestWorldName()),
101-
() => Loc.Get(
102-
"MainMenu.CreateNewWorldTooltip",
182+
Loc.Get("MainMenu.CreateNewWorld"),
183+
() => Loc.Get("MainMenu.CreateNewWorldTooltip",
103184
$"[c/FFFF00:{MainMenuActions.GetNextAvailableTestWorldName()}]",
104185
$"[c/FFFF00:{Conf.C.CreateTestWorldSize}]",
105186
$"[c/FFFF00:{Conf.C.CreateTestWorldDifficulty}]"
106-
)
187+
),
188+
tooltipPanel
107189
);
190+
var spacer = new SpacerMainMenuElement();
191+
mainMenuList.Add(worldHeader);
192+
mainMenuList.Add(createNewWorld);
193+
mainMenuList.Add(spacer);
194+
}
108195

109-
// Add tooltip panel
110-
tooltipPanel = new();
111-
tooltipPanel.BorderColor = new Color(33, 43, 79) * 0.8f;
112-
tooltipPanel.BackgroundColor = new Color(73, 94, 171);
113-
tooltipPanel.Left.Set(15 - 3, 0f); // -3 panel padding on each side is 6/2 = 3
114-
tooltipPanel.Top.Set(currentY + 10, 0f);
115-
tooltipPanel.Width.Set(310f, 0f);
116-
tooltipPanel.Height.Set(68f, 0f);
117-
118-
// Add tooltip text
119-
tooltipText = new UIText(string.Empty, 0.9f);
120-
tooltipText.Left.Set(0f, 0f);
121-
tooltipText.TextOriginX = 0;
122-
tooltipText.TextOriginY = 0;
123-
tooltipPanel.Append(tooltipText);
124-
Append(tooltipPanel);
196+
public override void Draw(SpriteBatch spriteBatch)
197+
{
198+
base.Draw(spriteBatch);
199+
200+
//DrawActionRowsDebug(spriteBatch);
125201
}
126-
#endregion
127-
128-
/// <summary>
129-
/// Helper method to add a menu option.
130-
/// </summary>
131-
private void AddOption(string text,
132-
Action action = null,
133-
Func<string> tooltip = null,
134-
bool isHeader = false)
202+
203+
private void PositionTooltip()
135204
{
136-
float size = isHeader ? 1.15f : 1f;
137-
var label = new UIText(text, size)
138-
{
139-
TextColor = isHeader ? Hover : Normal
140-
};
205+
tooltipPanel.Left.Set(15 + 3, 0f);
206+
tooltipPanel.Top.Set(470f, 0f); // 6 px under the list
207+
tooltipPanel.Recalculate();
208+
}
141209

142-
label.Left.Set(15f, 0f);
143-
label.Top.Set(currentY, 0f);
144-
currentY += verticalSpacing;
210+
public override void Update(GameTime gameTime)
211+
{
212+
base.Update(gameTime);
213+
PositionTooltip();
214+
}
215+
216+
private void DrawActionRowsDebug(SpriteBatch spriteBatch)
217+
{
218+
Texture2D pixel = TextureAssets.MagicPixel.Value;
219+
Color debugColor = Color.Red * 0.3f;
145220

146-
label.OnMouseOver += (_, _) =>
221+
// the first child is the inner list
222+
foreach (var inner in mainMenuList.Children)
147223
{
148-
if (!isHeader)
149-
label.TextColor = Hover;
150-
if (tooltip != null)
224+
if (inner is not UIElement) continue;
225+
226+
foreach (var child in inner.Children)
151227
{
152-
tooltipText.SetText(tooltip());
153-
tooltipPanel.Hidden = false;
228+
if (child is ActionMainMenuElement)
229+
{
230+
CalculatedStyle d = child.GetOuterDimensions();
231+
Rectangle rect = new(
232+
(int)d.X,
233+
(int)d.Y,
234+
(int)d.Width,
235+
(int)d.Height);
236+
237+
spriteBatch.Draw(pixel, rect, debugColor);
238+
}
154239
}
155-
};
156-
label.OnMouseOut += (_, _) =>
157-
{
158-
if (!isHeader)
159-
label.TextColor = Normal;
160-
tooltipText.SetText(string.Empty);
161-
tooltipPanel.Hidden = true;
162-
};
163-
164-
if (action != null)
165-
label.OnLeftClick += (_, _) => action.Invoke();
166-
167-
Append(label);
240+
}
168241
}
169242

170-
public override void Draw(SpriteBatch sb)
171-
{
172-
base.Draw(sb);
173-
}
243+
174244
}

0 commit comments

Comments
 (0)