Skip to content

Commit

Permalink
Add file based localization capability
Browse files Browse the repository at this point in the history
  • Loading branch information
Banane9 committed Mar 7, 2024
1 parent 5ea918f commit 51b5a3e
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 6 deletions.
116 changes: 116 additions & 0 deletions MonkeyLoader.Resonite.Integration/LocaleDataInjector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using Elements.Core;
using FrooxEngine;
using HarmonyLib;
using MonkeyLoader.Patching;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Zio;

namespace MonkeyLoader.Resonite
{
[HarmonyPatchCategory(nameof(LocaleDataInjector))]
[HarmonyPatch(typeof(LocaleResource), nameof(LocaleResource.LoadTargetVariant))]
internal class LocaleDataInjector : Monkey<LocaleDataInjector>
{
protected override IEnumerable<IFeaturePatch> GetFeaturePatches() => Enumerable.Empty<IFeaturePatch>();

[HarmonyTranspiler]
[HarmonyPatch(MethodType.Async)]
private static IEnumerable<CodeInstruction> LoadTargetVariantMoveNextTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase targetMethod)
{
var onLoadStateChangeMethod = AccessTools.Method(typeof(Asset), nameof(Asset.OnLoadStateChanged));
//var variantField = AccessTools.Field(targetMethod.DeclaringType, "variant");

//var injectLocaleLoadingMethod = AccessTools.Method(typeof(LocaleDataInjector), nameof(InjectLocaleLoading));

//var instructionList = new List<CodeInstruction>(instructions);

/*
* Instructions at this point - bool flag for whether to call on stack and target being added
*
X IL_0233: ldloc.1
X IL_0234: call instance class [Elements.Assets]Elements.Assets.LocaleResource FrooxEngine.LocaleResource::get_Data()
X IL_0239: ldnull
X IL_023a: cgt.un
* IL_023c: ldloc.1
* IL_023d: ldarg.0
* IL_023e: ldfld class [Elements.Assets]Elements.Assets.LocaleResource FrooxEngine.LocaleResource/'<LoadTargetVariant>d__6'::'<resource>5__2'
* IL_0243: call instance void FrooxEngine.LocaleResource::set_Data(class [Elements.Assets]Elements.Assets.LocaleResource)
X IL_0248: brfalse.s IL_0250
X IL_024a: ldloc.1
X IL_024b: callvirt instance void FrooxEngine.Asset::OnLoadStateChanged()
*/

// Only once, but at the end, so start there
//var onLoadStateChangeIndex = instructionList.FindLastIndex(instruction => instruction.Calls(onLoadStateChangeMethod));

//instructionList[onLoadStateChangeIndex] = new CodeInstruction(OpCodes.Call, injectLocaleLoadingMethod);
//instructionList.InsertRange(onLoadStateChangeIndex, new[] { new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Ldfld, variantField) });
//instructionList.RemoveAt(onLoadStateChangeIndex - 2);

//instructionList.RemoveRange(onLoadStateChangeIndex - 10, 4);
//instructionList.RemoveRange(onLoadStateChangeIndex - 2, 3); // 1, 2 works, as is fails

foreach (var instruction in instructions)
{
if (instruction.Calls(onLoadStateChangeMethod))
yield return new CodeInstruction(OpCodes.Nop);
else
yield return instruction;
}
}

[HarmonyPostfix]
private static async Task LoadTargetVariantPostfixAsync(Task __result, LocaleResource __instance, LocaleVariantDescriptor variant, bool __state)
{
await __result;

var localeCodes = new List<string>();
localeCodes.AddUnique(variant.LocaleCode);
localeCodes.AddUnique(Elements.Assets.LocaleResource.GetMainLanguage(variant.LocaleCode));
localeCodes.AddUnique("en");

foreach (var localeCode in localeCodes)
{
var searchPath = (new UPath("Locale") / $"{localeCode}.json").ToRelative().ToString();

foreach (var mod in Mod.Loader.Mods)
{
var localeFilePaths = mod.ContentPaths.Where(path => path.ToString().EndsWith(searchPath, StringComparison.OrdinalIgnoreCase)).ToArray();

foreach (var localeFilePath in localeFilePaths)
{
try
{
using var localeFileStream = mod.FileSystem.OpenFile(localeFilePath, FileMode.Open, FileAccess.Read);

var localeData = await JsonSerializer.DeserializeAsync<Elements.Assets.LocaleData>(localeFileStream);

__instance.Data.LoadDataAdditively(localeData);
}
catch (Exception ex)
{
Warn(() => ex.Format($"Failed to deserialize file as LocaleData: {localeFilePath}"));
}
}
}
}

if (__state)
__instance.OnLoadStateChanged();
}

[HarmonyPrefix]
private static void LoadTargetVariantPrefix(LocaleResource __instance, ref bool __state)
{
__state = __instance.Data != null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,20 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="MonkeyLoader" Version="0.5.0-beta" />
<PackageReference Include="MonkeyLoader" Version="0.6.0-beta" />
<PackageReference Include="MonkeyLoader.GamePacks.Unity" Version="0.4.0-beta" />
<PackageReference Include="PolySharp" Version="1.14.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Resonite.Assembly-CSharp" Version="1.0.0" />
<PackageReference Include="Resonite.Elements.Core" Version="1.0.0" />
<PackageReference Include="Resonite.FrooxEngine" Version="2024.3.1.1178" />
<PackageReference Include="Resonite.UnityEngine.CoreModule" Version="1.0.0" />
<PackageReference Include="Resonite.UnityEngine.TextRenderingModule" Version="1.0.0" />
<PackageReference Include="Resonite.Assembly-CSharp" Version="1.0.2" />
<PackageReference Include="Resonite.Elements.Assets" Version="1.0.2" />
<PackageReference Include="Resonite.Elements.Core" Version="1.0.2" />
<PackageReference Include="Resonite.FrooxEngine" Version="2024.3.3.1178" />
<PackageReference Include="Resonite.UnityEngine.CoreModule" Version="1.0.3" />
<PackageReference Include="Resonite.UnityEngine.TextRenderingModule" Version="1.0.3" />
<PackageReference Include="System.Text.Json" Version="8.0.2" />
<PackageReference Include="Zio" Version="0.17.0" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit 51b5a3e

Please sign in to comment.