Skip to content

Commit 022e9a0

Browse files
authored
Merge pull request #125 from Alchyr/develop
v0.2.7
2 parents 1e4e1a2 + a7180dc commit 022e9a0

15 files changed

Lines changed: 138 additions & 83 deletions

Abstracts/ConstructedCardModel.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,10 @@ private void SetupCalculatedVar(CalculatedVar var, int baseVal, int multVal,
176176
_hasCalculatedVar = true;
177177

178178
_dynamicVars.Add(new CalculationBaseVar(baseVal).WithUpgrade(upgrade));
179-
_dynamicVars.Add(new CalculationExtraVar(multVal).WithUpgrade(bonusUpgrade));
179+
_dynamicVars.Add(var is CalculatedDamageVar
180+
? new ExtraDamageVar(multVal).WithUpgrade(bonusUpgrade)
181+
: new CalculationExtraVar(multVal).WithUpgrade(bonusUpgrade));
182+
180183
_dynamicVars.Add(var.WithMultiplier(mult));
181184
}
182185

BaseLib.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
<PackageId>Alchyr.Sts2.BaseLib</PackageId>
2020
<Title>BaseLib-StS2</Title>
2121
<Description>Mod for Slay the Spire 2 providing utilities and features for other mods.</Description>
22-
<Version>0.2.6</Version>
22+
<Version>0.2.7</Version>
2323
<Authors>Alchyr</Authors>
24-
<PackageReleaseNotes>main/beta compatibility, harmony patch dumping, config adjustments</PackageReleaseNotes>
24+
<PackageReleaseNotes>smaller fixes</PackageReleaseNotes>
2525
<PackageTags>c#</PackageTags>
2626
<NoWarn>$(NoWarn);NU5128;MSB3270</NoWarn>
2727

BaseLib.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"name": "BaseLib",
44
"author": "Alchyr",
55
"description": "Modding utility for Slay the Spire 2",
6-
"version": "v0.2.6",
6+
"version": "v0.2.7",
77
"has_pck": true,
88
"has_dll": true,
99
"dependencies": [],

BaseLibScenes/NLogWindow.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public static void AddLog(string msg)
1818
_log.Enqueue(msg);
1919
foreach (var window in _listeners)
2020
{
21-
window.Refresh();
21+
window.SetDirty();
2222
}
2323
}
2424

@@ -36,6 +36,10 @@ public static void AddLog(string msg)
3636

3737
private bool _isFollowingLog = true;
3838
private int _currentFontSize; // Set on load
39+
private bool _needsRefresh;
40+
private double _timeSinceRefresh;
41+
42+
private void SetDirty() => _needsRefresh = true;
3943

4044
public override void _EnterTree()
4145
{
@@ -76,7 +80,7 @@ public override void _Ready()
7680
_regexButton.ButtonPressed = BaseLibConfig.LogUseRegex;
7781
_inverseButton.ButtonPressed = BaseLibConfig.LogInvertFilter;
7882
_filterInput.Text = BaseLibConfig.LogLastFilter;
79-
_currentFontSize = (int)BaseLibConfig.LogFontSize;
83+
_currentFontSize = BaseLibConfig.LogFontSize;
8084

8185
_filterInput.TextChanged += (_) => { _settingChanged = true; UpdateFilter(); };
8286
_regexButton.Toggled += (_) => { _settingChanged = true; UpdateFilter(); };
@@ -95,6 +99,21 @@ public override void _Ready()
9599
SetFontSize(_currentFontSize, false);
96100
ApplyMinSizeForScale();
97101
UpdateFilter(); // Also calls Refresh()
102+
103+
ProcessMode = ProcessModeEnum.Always;
104+
}
105+
106+
public override void _Process(double delta)
107+
{
108+
base._Process(delta);
109+
110+
_timeSinceRefresh += delta;
111+
if (!_needsRefresh || !Visible || Mode == ModeEnum.Minimized) return;
112+
if (_timeSinceRefresh < 1d / 30d) return;
113+
114+
_timeSinceRefresh = 0;
115+
_needsRefresh = false;
116+
Refresh();
98117
}
99118

100119
private void ApplyMinSizeForScale()
@@ -122,7 +141,7 @@ private void OnSizeChanged()
122141
{
123142
BaseLibConfig.LogLastSizeX = Size.X;
124143
BaseLibConfig.LogLastSizeY = Size.Y;
125-
UpdateText();
144+
SetDirty();
126145
ModConfig.SaveDebounced<BaseLibConfig>();
127146
}
128147

@@ -244,7 +263,7 @@ private static bool IsNearBottom(VScrollBar scrollbar, double value)
244263

245264
private static void EnsureLogLimit()
246265
{
247-
int configuredLimit = (int)BaseLibConfig.LimitedLogSize;
266+
int configuredLimit = BaseLibConfig.LimitedLogSize;
248267
if (_log.Limit == configuredLimit) return;
249268

250269
_log.SetLimit(configuredLimit);
@@ -260,7 +279,7 @@ public override void _Input(InputEvent @event)
260279
}
261280

262281
private void ChangeFontSize(int deltaPx) =>
263-
SetFontSize((int)Mathf.Clamp(BaseLibConfig.LogFontSize + deltaPx, 8, 48));
282+
SetFontSize(Math.Clamp(BaseLibConfig.LogFontSize + deltaPx, 8, 48));
264283

265284
private void SetFontSize(int newSize, bool save = true)
266285
{

Config/BaseLibConfig.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ internal class BaseLibConfig : SimpleModConfig
1414

1515
[SliderRange(128, 2048, 64)]
1616
[SliderLabelFormat("{0:0} lines")]
17-
public static double LimitedLogSize { get; set; } = 256;
17+
public static int LimitedLogSize { get; set; } = 256;
1818

1919
[SliderRange(8, 48)]
2020
[SliderLabelFormat("{0:0} px")]
21-
public static double LogFontSize { get; set; } = 14;
21+
public static int LogFontSize { get; set; } = 14;
2222

2323
[ConfigSection("HarmonyDumpSection")]
2424
[ConfigTextInput(TextInputPreset.Anything, MaxLength = 1024)]

Config/ConfigAttributes.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
/// </summary>
66
/// <param name="name">The LocString name. Will be transformed just like property names, so for "FirstSection", you need to
77
/// specify a value for YOURMOD-FIRST_SECTION.title in the localization file(s).</param>
8-
[AttributeUsage(AttributeTargets.Property)]
8+
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
99
public class ConfigSectionAttribute(string name) : Attribute
1010
{
1111
public string Name { get; } = name;
1212
}
1313

1414
/// <summary>
1515
/// Specifies a range and step for a slider. Negative numbers are supported, as are noninteger numbers.<br/>
16+
/// Supported property types: <see cref="int"/>, <see cref="float"/>, <see cref="double"/>.
1617
/// </summary>
1718
[AttributeUsage(AttributeTargets.Property)]
1819
public class SliderRangeAttribute : Attribute
@@ -56,7 +57,7 @@ public class SliderLabelFormatAttribute(string format) : Attribute
5657
/// YOURMOD-PROPERTY_NAME.hover.desc (required)
5758
/// </summary>
5859
/// <param name="enabled">Enable hover tip for this property. Can be set to false in order to add exceptions for <see cref="HoverTipsByDefaultAttribute"/></param>
59-
[AttributeUsage(AttributeTargets.Property)]
60+
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)]
6061
public class ConfigHoverTipAttribute(bool enabled = true) : Attribute
6162
{
6263
public bool Enabled { get; } = enabled;

Config/SimpleModConfig.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ protected NConfigOptionRow GenerateOptionFromProperty(PropertyInfo property)
161161

162162
NConfigOptionRow optionRow;
163163
if (propertyType == typeof(bool)) optionRow = CreateToggleOption(property);
164-
else if (propertyType == typeof(double)) optionRow = CreateSliderOption(property);
165164
else if (propertyType == typeof(string)) optionRow = CreateLineEditOption(property);
165+
else if (NConfigSlider.SupportedTypes.Contains(propertyType)) optionRow = CreateSliderOption(property);
166166
else if (propertyType.IsEnum) optionRow = CreateDropdownOption(property);
167167
else throw new NotSupportedException($"Type {propertyType.FullName} is not supported by SimpleModConfig.");
168168

@@ -216,7 +216,7 @@ protected NConfigOptionRow GenerateButtonRowFromMethod(MethodInfo method)
216216
ShowAndClearPendingErrors();
217217
};
218218

219-
optionRow = CreateButton(method.Name, attr.ButtonLabelKey, onButtonClicked, true);
219+
optionRow = CreateButton(method.Name, attr.ButtonLabelKey, onButtonClicked);
220220
AddHoverTipToOptionRowIfEnabled(optionRow, method);
221221
return optionRow;
222222
}

Config/UI/NConfigSlider.cs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ namespace BaseLib.Config.UI;
1313
// We don't inherit from NSettingsSlider because it's too rigid (forces % in the format, forces step of 5, fixed width)
1414
public partial class NConfigSlider : Control
1515
{
16+
public static readonly Type[] SupportedTypes = [typeof(int), typeof(float), typeof(double)];
1617
private ModConfig? _config;
1718
private PropertyInfo? _property;
1819
private string _displayFormat = "{0}";
@@ -56,6 +57,8 @@ public NConfigSlider()
5657
public double MaxValue { get; private set; }
5758
public double Step => _slider.Step;
5859

60+
private static bool IsInteger(double value) => Math.Abs(value - Math.Round(value)) < 1e-6;
61+
5962
/// <summary>
6063
/// Updates the slider's limits (and optionally step) atomically, ensuring no issues where e.g. min > max occur,
6164
/// even briefly.<br/>
@@ -68,15 +71,34 @@ public void SetRange(double min, double max, double? step = null)
6871
if (min >= max)
6972
throw new ArgumentException($"Invalid slider range: min ({min}) must be less than max ({max}).");
7073

74+
if (_property?.PropertyType == typeof(int))
75+
{
76+
if (!IsInteger(min) || !IsInteger(max))
77+
throw new ArgumentException("Invalid slider values: min and max must be integers for property type int");
78+
79+
min = Math.Round(min);
80+
max = Math.Round(max);
81+
82+
if (step.HasValue)
83+
{
84+
if (!IsInteger(step.Value))
85+
throw new ArgumentException("Invalid slider values: step must be integer for property type int");
86+
87+
step = Math.Round(step.Value);
88+
}
89+
}
90+
7191
// We use an offset to enable negative value support in NSlider
7292
var currentRealValue = _slider.Value + MinValue;
7393

7494
MinValue = min;
7595
MaxValue = max;
76-
if (step != null) _slider.Step = step.Value;
7796

78-
// _slider.MinValue is always 0, so we don't touch it here even if _realMin changes
97+
// The internal NSlider does not support negative numbers, so we force it to run from 0 and up, and handle the
98+
// "real" values manually
99+
_slider.MinValue = 0;
79100
_slider.MaxValue = MaxValue - MinValue;
101+
if (step != null) _slider.Step = step.Value;
80102
RecalculateMinRepeatDelay();
81103

82104
// NSlider.SetValueWithoutAnimation crashes unless its _Ready has executed, but if SetRange is called prior
@@ -111,45 +133,34 @@ public override void _Ready()
111133
Connect(Godot.Control.SignalName.FocusEntered, Callable.From(OnFocus));
112134
Connect(Godot.Control.SignalName.FocusExited, Callable.From(OnUnfocus));
113135

136+
_config!.OnConfigReloaded += SetFromProperty;
137+
114138
_fullyInitialized = true;
115139
}
116140

117141
public void Initialize(ModConfig modConfig, PropertyInfo property)
118142
{
119-
if (property.PropertyType != typeof(double))
120-
throw new ArgumentException("Attempted to assign NConfigSlider a non-double property");
143+
if (!SupportedTypes.Contains(property.PropertyType))
144+
throw new ArgumentException("Attempted to initialize NConfigSlider with an unsupported property type. " +
145+
$"Supported types: {string.Join<Type>(", ", SupportedTypes)}");
121146

122147
_config = modConfig;
123148
_property = property;
124149

125-
var rangeAttr = property.GetCustomAttribute<SliderRangeAttribute>();
126150
var formatAttr = property.GetCustomAttribute<SliderLabelFormatAttribute>();
151+
_displayFormat = formatAttr?.Format ?? "{0}";
127152

153+
var rangeAttr = property.GetCustomAttribute<SliderRangeAttribute>();
128154
var min = rangeAttr?.Min ?? 0;
129155
var max = rangeAttr?.Max ?? 100;
130156
var step = rangeAttr?.Step ?? 1;
131-
_displayFormat = formatAttr?.Format ?? "{0}";
132-
133-
if (min >= max)
134-
throw new ArgumentException($"Invalid slider range: min ({min}) must be less than max ({max}).");
135-
136-
MinValue = min;
137-
MaxValue = max;
138-
139-
// Force the internal Godot NSlider to run from 0 upwards, since it does not support negative numbers
140-
_slider.MinValue = 0;
141-
_slider.MaxValue = MaxValue - MinValue;
142-
_slider.Step = step;
143-
144-
RecalculateMinRepeatDelay();
145-
146-
_config.OnConfigReloaded += SetFromProperty;
157+
SetRange(min, max, step);
147158
}
148159

149160
private void SetFromProperty()
150161
{
151-
var propValue = (double)_property!.GetValue(null)!;
152-
SetValue(propValue);
162+
var rawValue = _property!.GetValue(null)!;
163+
SetValue(Convert.ToDouble(rawValue));
153164
}
154165

155166
private void SetValue(double value)
@@ -160,7 +171,7 @@ private void SetValue(double value)
160171

161172
// Clamp always returns one of its parameters, so exactness isn't an issue here
162173
// ReSharper disable once CompareOfFloatsByEqualityOperator
163-
if (value != clampedValue) _property?.SetValue(null, clampedValue);
174+
if (value != clampedValue) _property?.SetValue(null, Convert.ChangeType(clampedValue, _property.PropertyType));
164175
}
165176

166177
private void OnValueChanged(double proxyValue)
@@ -175,7 +186,7 @@ private void OnValueChanged(double proxyValue)
175186
realValue = Math.Round(realValue, decimalPlaces);
176187
}
177188

178-
_property?.SetValue(null, realValue);
189+
_property?.SetValue(null, Convert.ChangeType(realValue, _property.PropertyType));
179190
_config?.Changed();
180191
UpdateLabel(realValue);
181192
}

Config/UI/NModConfigSubmenu.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public partial class NModConfigSubmenu : NSubmenu
2727

2828
private ModConfig? _currentConfig;
2929
private double _saveTimer = -1;
30+
private bool _modLoadFailed;
3031
private const double AutosaveDelay = 5;
3132
private bool _isUsingController;
3233
private bool _lastFocusOnRight;
@@ -164,7 +165,7 @@ private void ModButtonClicked(NModListButton button, ModConfig modConfig)
164165
{
165166
LoadModConfig(modConfig);
166167

167-
if (!_isUsingController) return;
168+
if (!_isUsingController || _modLoadFailed) return;
168169

169170
SetBackButtonVisible(false);
170171
button.SetHotkeyIconVisible(true);
@@ -267,16 +268,30 @@ private void LoadModConfig(ModConfig config)
267268
try
268269
{
269270
config.SetupConfigUI(_optionContainer);
271+
_modLoadFailed = false;
270272
}
271273
catch (Exception e)
272274
{
273-
ModConfig.ModConfigLogger.Error($"Failed setting up config for mod {GetType().Assembly.GetName().Name}.\n" +
274-
"This is either because the mod set something up incorrectly, or a " +
275-
"compatibility issue.\n" +
276-
"Try updating BaseLib and the mod in question, if newer versions exist.");
277-
BaseLibMain.Logger.Error(e.ToString());
278-
_stack.Pop();
279-
return;
275+
_modLoadFailed = true;
276+
SaveAndClearCurrentMod();
277+
_currentConfig = config; // Cleared by the above, but should remain in this case
278+
279+
_optionContainer = CreateOptionContainer();
280+
_contentPanel.AddChild(_optionContainer);
281+
282+
var modName = GetModTitle(config);
283+
var message = $"[center]BaseLib failed setting up the mod config for {modName}.\n" +
284+
"This is either because the mod set something up incorrectly, or a " +
285+
"compatibility issue.\n" +
286+
$"Try updating BaseLib and {modName}, if newer versions exist.[/center]";
287+
var errorLabel = ModConfig.CreateRawLabelControl(message, 32);
288+
289+
errorLabel.FitContent = true;
290+
errorLabel.SizeFlagsHorizontal = SizeFlags.ExpandFill;
291+
292+
_optionContainer.AddChild(errorLabel);
293+
294+
BaseLibMain.Logger.Error($"SetupConfigUI failed for mod {modName}: {e}");
280295
}
281296

282297
try
@@ -399,6 +414,8 @@ private void RefreshSize()
399414

400415
// Emulate the game and add extra space at the bottom if scrolling is (almost, due to the 30f padding) needed
401416
var clipperSize = _contentPanel.GetParent<Control>().Size;
417+
_optionContainer.CustomMinimumSize = new Vector2(actualSettingsWidth, 0);
418+
_optionContainer.Size = new Vector2(actualSettingsWidth, 0);
402419
var requiredHeight = _optionContainer.GetMinimumSize().Y;
403420
var paddedHeight = requiredHeight + 30f;
404421

@@ -410,7 +427,7 @@ private void RefreshSize()
410427
_contentPanel.CustomMinimumSize = new Vector2(rightContentWidth, paddedHeight);
411428
_contentPanel.Size = new Vector2(rightContentWidth, paddedHeight);
412429

413-
_optionContainer.CustomMinimumSize = new Vector2(actualSettingsWidth, requiredHeight);
430+
_optionContainer.CustomMinimumSize = new Vector2(actualSettingsWidth, 0);
414431
_optionContainer.Size = new Vector2(actualSettingsWidth, requiredHeight);
415432

416433
// Force center the mod title over the actual settings
@@ -507,8 +524,11 @@ public override void _Process(double delta)
507524

508525
private void SaveCurrentConfig()
509526
{
510-
_currentConfig?.Save();
511527
_saveTimer = -1;
528+
if (_modLoadFailed)
529+
BaseLibMain.Logger.Warn($"Ignoring SaveCurrentConfig for {_currentConfig?.ModId}: UI setup failed");
530+
else
531+
_currentConfig?.Save();
512532
}
513533

514534
public override void _ExitTree()

0 commit comments

Comments
 (0)