Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions MatrixFishingUI/Framework/Fish/FishHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ public static class FishHelper
{
private static HashSet<string>? FarmLocalTypes { get; set; }
private static Dictionary<string, LocationData> Locations = GetLocations()!;
private static readonly Dictionary<string, string> LocationDisplayNameCache = new();

public static void DailyRefresh()
{
Locations = GetLocations()!;
LocationDisplayNameCache.Clear();
}

public static Dictionary<FishId, List<SpawningCondition>> GetFishSpawningConditions()
Expand Down Expand Up @@ -73,6 +75,7 @@ public static Dictionary<FishId, List<SpawningCondition>> GetFishSpawningConditi
public static void InvalidateCache()
{
FarmLocalTypes = null;
LocationDisplayNameCache.Clear();
}

private static Dictionary<string, LocationData>? GetLocations()
Expand Down Expand Up @@ -117,6 +120,24 @@ public static void InvalidateCache()
return locations;
}

private static string GetReadableLocationName(GameLocation location)
{
var key = location.NameOrUniqueName;
if (LocationDisplayNameCache.TryGetValue(key, out var cached)) return cached;

var dataDisplay = location.GetData()?.DisplayName;
if (!string.IsNullOrEmpty(dataDisplay))
{
var parsed = StardewValley.TokenizableStrings.TokenParser.ParseText(dataDisplay);
LocationDisplayNameCache[key] = parsed;
return parsed;
}

var display = location.DisplayName;
LocationDisplayNameCache[key] = display;
return display;
}

private static Dictionary<FishId, List<SpawningCondition>> GetFishSpawningConditions(
LocationData locationData,
LocationData defaultLocationData,
Expand Down Expand Up @@ -204,7 +225,7 @@ void AddSpawningCondition(HashSet<Season> seasons, SpawnFishData fish, List<stri
var locationArea = new LocationArea(locationName, fish.FishAreaId, locationName, fish.BobberPosition ?? null);
if (locationArea.TryGetGameLocation(out var location))
{
locationArea = locationArea with { LocationReadableName = location.DisplayName };
locationArea = locationArea with { LocationReadableName = GetReadableLocationName(location) };
}
spawningConditions.Add(new SpawningCondition(locationArea, seasons.ToList(), specialConditions));
}
Expand All @@ -223,7 +244,7 @@ void AddSpawningCondition(HashSet<Season> seasons, SpawnFishData fish, List<stri
var locationArea = new LocationArea(locationName, fish.FishAreaId, locationName);
if (locationArea.TryGetGameLocation(out var location))
{
locationArea = locationArea with { LocationReadableName = location.DisplayName };
locationArea = locationArea with { LocationReadableName = GetReadableLocationName(location) };
}
spawningConditions.Add(new SpawningCondition(locationArea, seasons.ToList(), specialConditions));
}
Expand All @@ -243,7 +264,7 @@ void AddManualSpawningCondition(HashSet<Season> seasons, FishId fish, List<strin
var locationArea = new LocationArea(locationName, "", locationName);
if (locationArea.TryGetGameLocation(out var location))
{
locationArea = locationArea with { LocationReadableName = location.DisplayName };
locationArea = locationArea with { LocationReadableName = GetReadableLocationName(location) };
}
spawningConditions.Add(new SpawningCondition(locationArea, seasons.ToList(), specialConditions));
}
Expand All @@ -253,24 +274,29 @@ void AddManualSpawningCondition(HashSet<Season> seasons, FishId fish, List<strin
{
var conditions = conditionQuery.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var result = new HashSet<Season>();
var sawHere = false;
foreach (var condition in conditions)
{
var split = condition.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
if (!split[0].Equals("LOCATION_SEASON", StringComparison.OrdinalIgnoreCase) && !split[0].Equals("SEASON", StringComparison.OrdinalIgnoreCase)) continue;
for (var i = 1; i < split.Length; i++)
{
var rawSeason = split[i];
if(rawSeason.Equals("Here", StringComparison.OrdinalIgnoreCase)) continue;
if(rawSeason.Equals("Here", StringComparison.OrdinalIgnoreCase)) { sawHere = true; continue; }
if (rawSeason.Equals("spring", StringComparison.OrdinalIgnoreCase)) result.Add(Season.Spring);
else if (rawSeason.Equals("summer", StringComparison.OrdinalIgnoreCase)) result.Add(Season.Summer);
else if (rawSeason.Equals("fall", StringComparison.OrdinalIgnoreCase)) result.Add(Season.Fall);
else if (rawSeason.Equals("winter", StringComparison.OrdinalIgnoreCase)) result.Add(Season.Winter);
else ModEntry.LogError($"Unknown Season caught when parsing: {conditionQuery}, Split: {rawSeason}");
}
}


return result.Count == 0 ? null : result;
if (result.Count == 0)
{
if (sawHere) return Enum.GetValues<Season>().ToHashSet();
Copy link

Copilot AI Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expression Enum.GetValues<Season>().ToHashSet() is called every time 'Here' is encountered without explicit seasons. Consider caching this HashSet as a static readonly field to avoid repeated allocations and enum value retrievals.

Copilot uses AI. Check for mistakes.
return null;
}
return result;
}

private static List<string> ParseConditionGeneric(string conditionQuery)
Expand Down Expand Up @@ -361,7 +387,7 @@ public FishId(string value)
public record SpawningCondition(LocationArea Location, List<Season> Seasons, List<string>? SpecialConditions = null)
{
public bool HasSpecialConditions => SpecialConditions is not null && SpecialConditions.Count > 0;
public bool HasArea => !Location.AreaName.Equals(string.Empty);
public bool HasArea => !string.IsNullOrEmpty(Location.AreaName);

public static bool VerifyCondition(string condition, Item? targetItem, Item? inputItem)
{
Expand Down
12 changes: 12 additions & 0 deletions MatrixFishingUI/Framework/Fish/FishInfoData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ public partial class FishInfoData : INotifyPropertyChanged
.Select(tab =>
new FishInfoTabViewModel(tab, tab == FishInfoTab.General))
.ToArray();
public string CaughtStatusLabel => CaughtStatus switch
{
CaughtStatus.Caught => I18n.Ui_Fishipedia_CaughtStatus_Caught(),
_ => I18n.Ui_Fishipedia_CaughtStatus_Uncaught()
};

public static FishInfoData GetSingleFish(FishInfo fish, FishInfo prevFish, FishInfo nextFish, int index, FishState fishState)
{
Expand Down Expand Up @@ -201,6 +206,13 @@ public partial class FishInfoTabViewModel(FishInfoTab value, bool active)
public Tuple<int, int, int, int> Margin =>
IsActive ? new Tuple<int, int, int, int>(0, 0, -12, 0) : new Tuple<int, int, int, int>(0, 0, 0, 0);
public FishInfoTab Value { get; } = value;
public string DisplayName => Value switch
{
FishInfoTab.General => I18n.Ui_Fishipedia_Tabs_General(),
FishInfoTab.CatchInfo => I18n.Ui_Fishipedia_Tabs_Catchinfo(),
FishInfoTab.PondInfo => I18n.Ui_Fishipedia_Tabs_Pondinfo(),
_ => Value.ToString()
};

[Notify] private bool isActive = active;
public event PropertyChangedEventHandler? PropertyChanged;
Expand Down
2 changes: 1 addition & 1 deletion MatrixFishingUI/Framework/Fish/HudMenuData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace MatrixFishingUI.Framework.Fish;

public class HudMenuData() : INotifyPropertyChanged
public partial class HudMenuData() : INotifyPropertyChanged
{
// ReSharper disable once MemberCanBePrivate.Global
public Dictionary<FishId,FishInfo> FishInfos { get; set; } = [];
Expand Down
38 changes: 29 additions & 9 deletions MatrixFishingUI/Framework/Fish/VanillaProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,22 @@ public IEnumerable<FishState> GetFishState()
if (!rawData[i].Equals('/')) continue;
var section = rawData.Slice(startIndex, i - startIndex);
startIndex = i + 1;
if (currentSectionIndex is indexName)
{
fishInfo.Name = section.ToString();
} else if (currentSectionIndex is indexDifficultyNumber or indexTrapSpecification)
if (currentSectionIndex is indexName)
{
// Ensure FishData is not null before accessing DisplayName; fallback to section or a default name
if (fishInfo.FishData != null && !string.IsNullOrWhiteSpace(fishInfo.FishData.DisplayName))
{
fishInfo.Name = fishInfo.FishData.DisplayName;
}
else if (!section.IsEmpty)
{
fishInfo.Name = section.ToString();
}
else
{
fishInfo.Name = $"UnknownFish_{id.Value}";
}
} else if (currentSectionIndex is indexDifficultyNumber or indexTrapSpecification)
{
if (section.Equals("Trap", StringComparison.OrdinalIgnoreCase))
{
Expand Down Expand Up @@ -157,7 +169,7 @@ public IEnumerable<FishState> GetFishState()
break;
}
}
fishInfo.CatchInfo.Difficulty = ParseInt(section, "Difficulty", id, defaultValue: 0);
fishInfo.CatchInfo.Difficulty = ParseInt(section, "Difficulty", id, defaultValue: 0);
}
}

Expand Down Expand Up @@ -299,9 +311,13 @@ public IEnumerable<FishState> GetFishState()
return fishInfo;
}

private static int ParseInt(ReadOnlySpan<char> input, string name, FishId id, int defaultValue = 0)
private static int ParseInt(ReadOnlySpan<char> input, string name, FishId id, int defaultValue = 0)
{
if (int.TryParse(input, out var result))
if (input.IsEmpty || input.SequenceEqual("null".AsSpan()))
{
return defaultValue;
}
if (int.TryParse(input, out var result))
{
return result;
}
Expand All @@ -310,9 +326,13 @@ private static int ParseInt(ReadOnlySpan<char> input, string name, FishId id, in
return defaultValue;
}

private static float ParseFloat(ReadOnlySpan<char> input, string name, FishId id, float defaultValue = 0)
private static float ParseFloat(ReadOnlySpan<char> input, string name, FishId id, float defaultValue = 0)
{
if (float.TryParse(input, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
if (input.IsEmpty || input.SequenceEqual("null".AsSpan()))
{
return defaultValue;
}
if (float.TryParse(input, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
return result;
}
Expand Down
12 changes: 6 additions & 6 deletions MatrixFishingUI/assets/views/FishInformation.sml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
background={@Mods/Borealis.MatrixFishingUI/Sprites/MenuTiles:TabButton}
focusable="true"
click=|^SelectTab(Value)|>
<label text={:Value} />
<label text={:DisplayName} />
</frame>
</lane>
<frame *switch={SelectedTab}
Expand Down Expand Up @@ -69,7 +69,7 @@
</lane>
<lane orientation="horizontal" horizontal-content-alignment="middle">
<label bold="true" margin="0, 8" color="#136" text={#ui.fishipedia.labels.caught_status} />
<label margin="0, 8" color="#136" text={:CaughtStatus} />
<label margin="0, 8" color="#136" text={:CaughtStatusLabel} />
</lane>
<lane orientation="horizontal" horizontal-content-alignment="middle">
<label bold="true" margin="0, 8" color="#136" text={#ui.fishipedia.labels.min_size} />
Expand All @@ -84,7 +84,7 @@
<label margin="0, 8" color="#136" text={#ui.fishipedia.labels.inches} />
</lane>
<lane orientation="horizontal" horizontal-content-alignment="start">
<label bold="true" margin="0, 8" color="#136" text="Special Information: " />
<label bold="true" margin="0, 8" color="#136" text={#ui.fishipedia.labels.special_information} />
<label margin="0, 8" color="#136" text={:SpecialInfo} />
</lane>
</lane>
Expand Down Expand Up @@ -172,7 +172,7 @@
<label bold="true" margin="0, 8" color="#136" text={:LocationReadableName} />
</lane>
<spacer layout="4px 0px" />
<label margin="0, 8" color="#136" text="during" />
<label margin="0, 8" color="#136" text={#ui.fishipedia.labels.during} />
<spacer layout="4px 0px" />
<lane *repeat={:Seasons}>
<lane *switch={:this}>
Expand All @@ -188,7 +188,7 @@
horizontal-alignment="middle"
vertical-alignment="middle"
sprite={@Mods/Borealis.MatrixFishingUI/Sprites/cursors:Exclamation}
tooltip="Special Condition(s)"
tooltip={#ui.fishipedia.tooltips.special_conditions}
focusable="true"
click=|^^ViewConditions(LocationName)| />
</lane>
Expand All @@ -197,7 +197,7 @@
horizontal-alignment="middle"
vertical-alignment="middle"
sprite={@Mods/Borealis.MatrixFishingUI/Sprites/cursors:Area}
tooltip="Area Name(s)"
tooltip={#ui.fishipedia.tooltips.area_names}
focusable="true"
click=|^^GetArea(LocationName)| />
</lane>
Expand Down
11 changes: 11 additions & 0 deletions MatrixFishingUI/i18n/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,17 @@
"ui.fishipedia.labels.weather_required": "Weather Required: ",
"ui.fishipedia.labels.seasons": "Season(s) Available: ",
"ui.fishipedia.labels.difficulty": "Catch Difficulty: ",
"ui.fishipedia.labels.during": "during",
"ui.fishipedia.labels.special_information": "Special Information: ",
"ui.fishipedia.tooltips.special_conditions": "Special Condition(s)",
"ui.fishipedia.tooltips.area_names": "Area Name(s)",

"ui.fishipedia.tabs.general": "General",
"ui.fishipedia.tabs.catchinfo": "Catch Info",
"ui.fishipedia.tabs.pondinfo": "Pond Info",

"ui.fishipedia.caught_status.caught": "Caught",
"ui.fishipedia.caught_status.uncaught": "Uncaught",

"ui.special.title": "Special Condition(s)",
"ui.special.segment": "Condition: ",
Expand Down
91 changes: 91 additions & 0 deletions MatrixFishingUI/i18n/zh.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{
"mod-name": "ArgonMatrix 钓鱼界面",
"controls.pressnewkey": "按键触发",
"ui.fishipedia.title": "鱼图鉴",

"ui.hud.title": "钓鱼助手",

"watertype.freshwater": "淡水",
"watertype.ocean": "海水",

"ui.fishipedia.weather.rainy": "雨天",
"ui.fishipedia.weather.sunny": "晴天",
"ui.fishipedia.weather.any": "任意天气",
"ui.fishipedia.weather.none": "无",

"ui.fishipedia.season.spring": "春季",
"ui.fishipedia.season.summer": "夏季",
"ui.fishipedia.season.fall": "秋季",
"ui.fishipedia.season.winter": "冬季",

"ui.fishipedia.time.time_available": "可钓时间",
"ui.fishipedia.time.between": "在 ",
"ui.fishipedia.time.and": "至 ",

"ui.fishipedia.titles.general": "基本信息",
"ui.fishipedia.titles.trap": "蟹笼信息",
"ui.fishipedia.titles.catch": "垂钓信息",
"ui.fishipedia.titles.locations": "地点",
"ui.fishipedia.titles.pond": "鱼塘信息",
"ui.fishipedia.titles.items_produced": "产出物品",

"ui.fishipedia.tooltips.legendary": "传说鱼",

"ui.fishipedia.ponds.pop_required": "所需数量:",
"ui.fishipedia.ponds.sale_price": "售价:",

"ui.fishipedia.spawntime.one": "繁殖周期:",
"ui.fishipedia.spawntime.two": "天",

"ui.fishipedia.labels.description": "描述:",
"ui.fishipedia.labels.caught_status": "捕获状态:",
"ui.fishipedia.labels.min_size": "最小尺寸:",
"ui.fishipedia.labels.max_size": "最大尺寸:",
"ui.fishipedia.labels.inches": "英寸",
"ui.fishipedia.labels.water_type": "水域类型:",
"ui.fishipedia.labels.fish_caught": "捕获数量:",
"ui.fishipedia.labels.fishing_level": "所需钓鱼等级:",
"ui.fishipedia.labels.biggest": "最大捕获:",
"ui.fishipedia.labels.every_season": "全年",
"ui.fishipedia.labels.weather_required": "所需天气:",
"ui.fishipedia.labels.seasons": "可钓季节:",
"ui.fishipedia.labels.difficulty": "钓鱼难度:",
"ui.fishipedia.labels.during": "于",
"ui.fishipedia.labels.special_information": "特殊说明:",
"ui.fishipedia.tooltips.special_conditions": "特殊条件",
"ui.fishipedia.tooltips.area_names": "区域名称",

"ui.fishipedia.tabs.general": "概要",
"ui.fishipedia.tabs.catchinfo": "垂钓",
"ui.fishipedia.tabs.pondinfo": "鱼塘",

"ui.fishipedia.caught_status.caught": "已捕获",
"ui.fishipedia.caught_status.uncaught": "未捕获",

"ui.special.title": "特殊条件",
"ui.special.segment": "条件:",

"ui.area.title": "区域信息",
"ui.area.segment": "区域:",

"ui.hud.labels.no_fish": "当前位置无可钓鱼!",

"specialinfo.ghostfish": "亦可在矿井20层与60层捕获,无等级要求,且可由幽灵掉落。",
"specialinfo.stonefish": "亦可在矿井20层捕获,无等级要求。",
"specialinfo.icepip": "亦可在矿井60层捕获,无等级要求。",
"specialinfo.tiger": "在年度鳟鱼大赛期间无视捕获条件。",
"specialinfo.none": "无特殊说明。",
"specialinfo.extended_family": "仅在奇先生的“家族团聚”特别委托期间可钓。",

"gmcm.title": "主要设置",
"gmcm.tooltip": "开发中:此处包含当前可用的配置项。",
"gmcm.keybind": "设置鱼图鉴快捷键:",
"gmcm.hud_size": "HUD 大小(百分比):",
"gmcm.columns": "HUD 列数:",
"gmcm.hide_collected_name": "HUD 隐藏已捕获:",
"gmcm.hide_collected_tooltip": "在鱼类 HUD 中隐藏你已捕获过的鱼。",
"gmcm.hide_daily_name": "仅显示今日可钓:",
"gmcm.hide_daily_tooltip": "隐藏今天不可钓的鱼(优先于“仅显示当季”)。",
"gmcm.hide_season_name": "仅显示当季可钓:",
"gmcm.hide_season_tooltip": "隐藏非本季节可钓的鱼。"
}