-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLocalization.cs
More file actions
149 lines (135 loc) · 6.43 KB
/
Copy pathLocalization.cs
File metadata and controls
149 lines (135 loc) · 6.43 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using Il2Cpp;
using HarmonyLib;
using MelonLoader;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Text.Json;
namespace FireImprovementsMod
{
/// <summary>
/// Loads FI.* translations from localization.json shipped alongside the DLL.
/// User override: UserData/FireImprovementsMod/localization.json takes priority.
/// Falls back to built-in English strings if the JSON is missing or corrupt.
/// </summary>
internal static class LocalizationManager
{
private static Dictionary<string, Dictionary<string, string>> _data;
internal static Dictionary<string, Dictionary<string, string>> Data
{
get { return _data ?? (_data = Load()); }
}
internal static void Reload() => _data = null;
// Имя встроенного ресурса: {RootNamespace}.{filename}
private const string EmbeddedResourceName = "FireImprovementsMod.localization.json";
private static Dictionary<string, Dictionary<string, string>> Load()
{
// 1. Пользовательский оверрайд: UserData/FireImprovementsMod/localization.json
string dllDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? "";
string userPath = Path.Combine(
Path.GetDirectoryName(dllDir) ?? dllDir, // выходим из Mods/ в корень игры
"UserData", "FireImprovementsMod", "localization.json");
if (File.Exists(userPath))
{
var fromFile = TryLoadJson(File.ReadAllText(userPath, Encoding.UTF8));
if (fromFile != null)
{
MelonLogger.Msg($"[FireImprovementsMod] Localization override loaded from: {userPath}");
return fromFile;
}
}
// 2. Встроенный ресурс внутри DLL
var asm = Assembly.GetExecutingAssembly();
var stream = asm.GetManifestResourceStream(EmbeddedResourceName);
if (stream != null)
{
using var reader = new StreamReader(stream, Encoding.UTF8);
var fromEmbedded = TryLoadJson(reader.ReadToEnd());
if (fromEmbedded != null)
{
MelonLogger.Msg("[FireImprovementsMod] Localization loaded from embedded resource.");
return fromEmbedded;
}
}
else
{
MelonLogger.Warning($"[FireImprovementsMod] Embedded resource '{EmbeddedResourceName}' not found — using built-in English strings.");
}
return FallbackEnglish;
}
private static Dictionary<string, Dictionary<string, string>> TryLoadJson(string json)
{
try
{
return JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(json);
}
catch (Exception ex)
{
MelonLogger.Warning($"[FireImprovementsMod] Failed to parse localization JSON: {ex.Message}");
return null;
}
}
// Minimal English fallback so the mod works even without the JSON file.
private static readonly Dictionary<string, Dictionary<string, string>> FallbackEnglish = new()
{
["English"] = new()
{
["FI.SEC_DURATION"] = "Fuel Burn Duration",
["FI.SEC_WIND"] = "Wind Resistance",
["FI.SEC_FIRESTART"] = "Fire Starting",
["FI.SEC_WARMTH"] = "Fire Warmth",
["FI.DURATION_MULT"] = "Burn Duration Multiplier",
["FI.MAX_DURATION"] = "Max Fire Duration (hours)",
["FI.WIND_RESIST"] = "Wind Blowout Resistance (%)",
["FI.START_BONUS"] = "Fire Start Bonus (%)",
["FI.INDOOR_WARMTH"] = "Indoor Warmth Bonus (\u00b0C)",
["FI.OUTDOOR_WARMTH"] = "Outdoor Warmth Bonus (\u00b0C)",
["FI.DESC_DURATION_MULT"] = "Fuel burn time multiplier.\n1.0 = no change | 1.5 = 50% longer | 2.0 = twice as long.\nAffects all fuel: wood, coal, accelerant.",
["FI.DESC_MAX_DURATION"] = "Maximum possible fire burn time in hours.\n12 = vanilla | 24 = one day | 72 = three days | 200 = eight days.",
["FI.DESC_WIND_RESIST"] = "Chance (%) that wind does NOT blow out the fire.\n0 = no protection | 50 = half as often | 100 = never.",
["FI.DESC_START_BONUS"] = "Flat bonus added to fire start success chance.\n0 = no change | 15 = +15% to success.",
["FI.DESC_INDOOR_WARMTH"] = "Extra warmth from fire indoors (stoves, fireplaces).\n0 = no change | 5 = +5\u00b0C.",
["FI.DESC_OUTDOOR_WARMTH"] = "Extra warmth from fire outdoors (campfires).\n0 = no change | 3 = +3\u00b0C.",
}
};
internal static string Get(string key)
{
string lang = Localization.Language ?? "English";
var data = Data;
if (data.TryGetValue(lang, out var dict) && dict.TryGetValue(key, out string val))
return val;
if (data.TryGetValue("English", out var en) && en.TryGetValue(key, out string enVal))
return enVal;
return key;
}
}
[HarmonyPatch(typeof(Localization), nameof(Localization.Get))]
internal static class LocalizationPatch
{
static void Postfix(string __0, ref string __result)
{
if (__0 == null || !__0.StartsWith("FI."))
return;
__result = LocalizationManager.Get(__0);
}
}
/// <summary>
/// Патч на DescriptionHolder.get_Text (ModSettings) —
/// перехватывает чтение описания в момент показа, когда язык уже установлен.
/// </summary>
[HarmonyPatch]
internal static class DescriptionTextTranslatePatch
{
static System.Reflection.MethodBase TargetMethod() =>
AccessTools.PropertyGetter(
AccessTools.TypeByName("ModSettings.DescriptionHolder"), "Text");
static void Postfix(ref string __result)
{
if (__result == null || !__result.StartsWith("FI."))
return;
__result = LocalizationManager.Get(__result);
}
}
}