Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for alternate TextAsset translation #35

Merged
merged 3 commits into from
Mar 5, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
add support for alternate TextAsset translation
  • Loading branch information
GeBo1 committed Feb 18, 2020
commit d542ff09707f8d94d25a22d521b7f7055e141f2e
1 change: 1 addition & 0 deletions AI_TextResourceHelper/AI_TextResourceHelper.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using BepInEx.Logging;

namespace KK_Plugins
{
Expand Down
1 change: 1 addition & 0 deletions AI_TextResourceRedirector/AI.TextResourceRedirector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ public partial class TextResourceRedirector : BaseUnityPlugin
public const string PluginNameInternal = "AI_TextResourceRedirector";

private TextResourceHelper GetTextResourceHelper() => new AI_TextResourceHelper();
private TextAssetHelper GetTextAssetHelper() => null;
}
}
8 changes: 8 additions & 0 deletions AI_TextResourceRedirector/AI_TextResourceRedirector.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
<HintPath>..\packages\IllusionLibs.BepInEx.5.0.0\lib\net46\BepInEx.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="MonoMod.RuntimeDetour, Version=19.11.5.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\IllusionLibs.BepInEx.MonoMod.19.11.5.1\lib\net46\MonoMod.RuntimeDetour.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="MonoMod.Utils, Version=19.11.5.1, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\IllusionLibs.BepInEx.MonoMod.19.11.5.1\lib\net46\MonoMod.Utils.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
Expand Down
1 change: 1 addition & 0 deletions AI_TextResourceRedirector/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<package id="IllusionLibs.AIGirl.Assembly-CSharp" version="2019.11.8" targetFramework="net46" developmentDependency="true" />
<package id="IllusionLibs.AIGirl.UnityEngine.CoreModule" version="2018.2.21" targetFramework="net46" developmentDependency="true" />
<package id="IllusionLibs.BepInEx" version="5.0.0" targetFramework="net46" developmentDependency="true" />
<package id="IllusionLibs.BepInEx.MonoMod" version="19.11.5.1" targetFramework="net46" developmentDependency="true" />
<package id="IllusionLibs.XUnity.AutoTranslator.Plugin.Core" version="4.6.4" targetFramework="net46" developmentDependency="true" />
<package id="IllusionLibs.XUnity.ResourceRedirector" version="4.6.4.1" targetFramework="net46" developmentDependency="true" />
</packages>
198 changes: 198 additions & 0 deletions Core_TextResourceHelper/Core.TextAssetHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace KK_Plugins
{
public class TextAssetHelper
{
public bool Enabled { get; }
public IEnumerable<string> RowSplitStrings { get; }
public IEnumerable<string> ColSplitStrings { get; }
public IEnumerable<string> InvalidColStrings { get; }

public TextAssetHelper(IEnumerable<string> rowSplitStrings = null, IEnumerable<string> colSplitStrings = null)
{
int comp(string a, string b) => b.Length.CompareTo(a.Length);

List<string> tmpList = new List<string>();

// row split strings
tmpList.AddRange(rowSplitStrings?.ToArray() ?? new string[0]);
tmpList.Sort(comp);
RowSplitStrings = tmpList.ToArray();

// col split strings
tmpList.Clear();
tmpList.AddRange(colSplitStrings?.ToArray() ?? new string[0]);
tmpList.Sort(comp);
ColSplitStrings = tmpList.ToArray();

// invalid col strings
tmpList.Clear();
tmpList.AddRange(RowSplitStrings);
tmpList.AddRange(ColSplitStrings);
tmpList.Sort(comp);
InvalidColStrings = tmpList.ToArray();

Enabled = ColSplitStrings.Any() && RowSplitStrings.Any();

}

public bool IsTable(TextAsset textAsset)
{
return IsTable(textAsset.text);
}

public bool IsTable(string table)
{
foreach (string colSplit in ColSplitStrings)
{
if (table.Contains(colSplit))
{
return true;
}
}
return false;
}

public bool IsTableRow(string row)
{
foreach (string rowSplit in ColSplitStrings)
{
if (row.Contains(rowSplit))
{
return false;
}
}
return true;
}

public IEnumerable<string> SplitTableToRows(TextAsset textAsset)
{
return SplitTableToRows(textAsset.text);
}

public IEnumerable<string> SplitTableToRows(string table)
{
if (!IsTable(table))
{
throw new ArgumentException("textAsset does not contain a table");
}
return table.Split(RowSplitStrings.ToArray(), StringSplitOptions.None);
}

public IEnumerable<string> SplitRowToCells(string row)
{

#if DEBUG
if (!IsTableRow(row))
{
throw new ArgumentException("row does not contain a table row)");
}
#endif
return row.Split(ColSplitStrings.ToArray(), StringSplitOptions.None);
}

public void ActOnCells(TextAsset textAsset, Action<string> cellAction, out TableResult tableResult)
{
ActOnCells(textAsset, (cell) => { cellAction(cell); return false; }, out tableResult);
}

public bool ActOnCells(TextAsset textAsset, Func<string, bool> cellAction, out TableResult tableResult)
{
tableResult = new TableResult();
//foreach (string row in EnumerateRows(textAsset))
foreach (string row in SplitTableToRows(textAsset))
{
tableResult.Rows++;
int colCount = 0;

//foreach (string col in EnumerateCols(row))
foreach (string col in SplitRowToCells(row))
{
colCount++;
if (cellAction(col))
{
tableResult.CellsActedOn++;
}
}
tableResult.Cols = Math.Max(tableResult.Cols, colCount);
}
return tableResult.CellsActedOn > 0;
}

public string ProcessTable(TextAsset textAsset, Func<string, string> columnTransform, out TableResult tableResult)
{
tableResult = new TableResult();
string colJoin = ColSplitStrings.First();
StringBuilder result = new StringBuilder(textAsset.text.Length * 2);
//foreach (string row in EnumerateRows(textAsset))
foreach (string row in SplitTableToRows(textAsset))
{
tableResult.Rows++;
int colCount = 0;

bool rowUpdated = false;
//foreach (string col in EnumerateCols(row))
foreach (string col in SplitRowToCells(row))
{
colCount++;
string newCol = columnTransform(col);
if (newCol != null && col != newCol)
{
tableResult.CellsUpdated++;
rowUpdated = true;
foreach (string invalid in InvalidColStrings)
{
newCol = newCol.Replace(invalid, " ");
}
result.Append(newCol);
}
else
{
result.Append(col);
}
result.Append(colJoin);
}
// row complete
// remove trailing colSplit
result.Length -= colJoin.Length;
result.Append(Environment.NewLine);
if (rowUpdated)
{
tableResult.RowsUpdated++;
}
tableResult.Cols = Math.Max(tableResult.Cols, colCount);
}
// table complete
// remove last newline
result.Length -= Environment.NewLine.Length;

if (!tableResult.Updated)
{
return textAsset.text;
}
return result.ToString();
}

public class TableResult
{
public int Rows;
public int Cols;
public int RowsUpdated;
public int CellsUpdated;
public int CellsActedOn;

public TableResult()
{
Rows = Cols = RowsUpdated = CellsUpdated = CellsActedOn = 0;
}

public bool Updated { get => RowsUpdated > 0; }

}
}
}
1 change: 1 addition & 0 deletions Core_TextResourceHelper/Core_TextResourceHelper.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)Core.TextResourceHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Core.TextAssetHelper.cs" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
using System.IO;
using System;
using System.IO;
using System.Linq;
using XUnity.AutoTranslator.Plugin.Core;
using XUnity.AutoTranslator.Plugin.Core.AssetRedirection;
using XUnity.AutoTranslator.Plugin.Core.Utilities;
using XUnity.ResourceRedirector;
using BepInEx.Logging;



namespace KK_Plugins
{
public class ExcelDataResourceRedirector : AssetLoadedHandlerBaseV2<ExcelData>
{
private static ManualLogSource Logger => TextResourceRedirector.Logger;

public ExcelDataResourceRedirector() => CheckDirectory = true;

protected override string CalculateModificationFilePath(ExcelData asset, IAssetOrResourceLoadedContext context) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#if !HS
using ADV;
using BepInEx.Logging;
using System;
using System.IO;
using System.Linq;
Expand All @@ -13,6 +14,7 @@ namespace KK_Plugins
public class ScenarioDataResourceRedirector : AssetLoadedHandlerBaseV2<ScenarioData>
{
private readonly TextResourceHelper textResourceHelper;
private static ManualLogSource Logger => TextResourceRedirector.Logger;

public ScenarioDataResourceRedirector(TextResourceHelper helper)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#if !HS
using BepInEx.Logging;
using MonoMod.RuntimeDetour;
using System;
using System.Reflection;
using System.Text;
using UnityEngine;

namespace KK_Plugins
{
using LogLevel = BepInEx.Logging.LogLevel;

public static class TextAssetPatcher
{
// Harmony can't patch these getters (empty bodies) so using MonoMod for now
// if this changes this class could be replaced with postfix patches
private static bool patched = false;
private static Func<TextAsset, string> textGetterOrig;
private static Func<TextAsset, byte[]> bytesGetterOrig;

private static ManualLogSource Logger => TextResourceRedirector.Logger;

public static void PatchTextAsset()
{
if (!patched)
{
textGetterOrig = PatchGetter<TextAsset, string>("text", TextGetterNew);
bytesGetterOrig = PatchGetter<TextAsset, byte[]>("bytes", BytesGetterNew);
patched = true;
}
}

internal static Func<T, TResult> PatchGetter<T, TResult>(string propertyToPatch, Func<T, TResult> replacementGetter)
{
BindingFlags baseFlags = BindingFlags.Public | BindingFlags.NonPublic;
MethodInfo origGetter = typeof(TextAsset).GetProperty(propertyToPatch, baseFlags | BindingFlags.Instance)?.GetGetMethod();
if (origGetter is null)
{
throw new ArgumentException($"Unable to patch { propertyToPatch }. Property not found.");
}

NativeDetour detour = new NativeDetour(origGetter, replacementGetter.Method);

detour.Apply();
Logger.Log(LogLevel.Debug, $"patched: {origGetter.ReturnType} {nameof(TextAsset)}.{origGetter.Name}()");
return detour.GenerateTrampoline<Func<T, TResult>>();
}

internal static string TextGetterOrig(this TextAsset obj)
{
if (patched)
{
return textGetterOrig(obj);
}
else
{
return obj.text;
}
}

internal static string TextGetterNew(this TextAsset obj)
{
string result = obj.TextGetterOrig();
if (patched && TextAssetResourceRedirector.TryLoadReplacement(result, out string replacement))
{
return replacement;
}
return result;
}

internal static byte[] BytesGetterOrig(this TextAsset obj)
{
if (patched)
{
return bytesGetterOrig(obj);
}
else
{
return obj.bytes;
}
}

internal static byte[] BytesGetterNew(this TextAsset obj)
{
if (patched && TextAssetResourceRedirector.TryLoadReplacement(obj.TextGetterOrig(), out string replacement))
{
return Encoding.ASCII.GetBytes(replacement);
}
return obj.BytesGetterOrig();
}
}
}
#endif
Loading