root rewrite

This commit is contained in:
SillyStar-Github 2025-04-19 13:11:08 -04:00
parent 400fe3d3cb
commit b7014a341f
127 changed files with 65 additions and 4080 deletions

63
.gitattributes vendored
View file

@ -1,2 +1,63 @@
# Auto detect text files and perform LF normalization
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

42
.gitignore vendored
View file

@ -1,7 +1,7 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
@ -29,6 +29,7 @@ x86/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
@ -90,7 +91,6 @@ StyleCopReport.xml
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
@ -294,17 +294,6 @@ node_modules/
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
@ -361,9 +350,6 @@ ASALocalRun/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
@ -374,26 +360,4 @@ MigrationBackup/
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
PvZ-Fusion-Blooms-master/MelonLoader/PvZ Fusion Translator \[MelonLoader\].csproj
FodyWeavers.xsd

View file

@ -1,63 +0,0 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

View file

@ -1,363 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Oo]ut/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd

View file

@ -1,115 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text.Encodings.Web;
using System.Text.Json;
using static PvZ_Fusion_Translator__BepInEx_.FileLoader;
namespace PvZ_Fusion_Translator__BepInEx_.AssetStore
{
public static class CheckSumStore
{
private static Dictionary<string, string> modifiedCheckSums = new Dictionary<string, string>();
private static Dictionary<string, string> checkSums = new Dictionary<string, string>()
{
};
static string GetCheckSum(string filename)
{
using (var md5 = SHA256.Create())
{
byte[] bytes = md5.ComputeHash(File.ReadAllBytes(filename));
return Convert.ToBase64String(bytes);
}
}
public static void SaveCheckSum()
{
string stringDir = GetAssetDir(AssetType.Dumps);
if (!Directory.Exists(stringDir))
{
Directory.CreateDirectory(stringDir);
}
string checkSumString = JsonSerializer.Serialize(checkSums, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
File.WriteAllText(Path.Combine(stringDir, "MD5.json"), checkSumString);
}
public static void SaveModifiedChecksum()
{
string stringDir = GetAssetDir(AssetType.Dumps);
if (!Directory.Exists(stringDir))
{
Directory.CreateDirectory(stringDir);
}
string modifiedCheckSumString = JsonSerializer.Serialize(modifiedCheckSums, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
File.WriteAllText(Path.Combine(stringDir, "Modified_MD5.json"), modifiedCheckSumString);
}
public static bool IsModified(string filepath)
{
string fileName = Path.GetFileNameWithoutExtension(filepath);
string directory = Path.GetDirectoryName(filepath);
string slicedFilePath = directory.Substring(directory.IndexOf("PvZ_Fusion_Translator\\") + "PvZ_Fusion_Translator\\".Length);
string slicedKey = Path.Combine(slicedFilePath, fileName);
#if DEBUG
if (!checkSums.ContainsKey(slicedKey))
{
checkSums.Add(slicedKey, GetCheckSum(filepath));
SaveCheckSum();
modifiedCheckSums.Add(slicedKey, GetCheckSum(filepath));
SaveModifiedChecksum();
}
else
{
if ((checkSums[slicedKey] != GetCheckSum(filepath)))
{
checkSums[slicedKey] = GetCheckSum(filepath);
modifiedCheckSums.Add(slicedKey, GetCheckSum(filepath));
SaveModifiedChecksum();
}
}
#elif RELEASE
if (!checkSums.ContainsKey(slicedKey) | (checkSums[slicedKey] != GetCheckSum(filepath)))
{
return true;
}
#endif
return false;
}
#if MELON
public static void ConvertMD5Json()
{
string stringDir = GetAssetDir(AssetType.Dumps);
if (!Directory.Exists(stringDir))
{
Directory.CreateDirectory(stringDir);
}
string checksumDumpPath = Path.Combine(stringDir, "MD5.json");
string checksumConvertPath = Path.Combine(stringDir, "MD5Convert.txt");
string json = File.ReadAllText(checksumDumpPath);
Dictionary<string, string> dictionary = DeserializeObject<Dictionary<string, string>>(json);
using StreamWriter writer = new StreamWriter(checksumConvertPath);
foreach (var kvp in dictionary)
{
string checksumKey = kvp.Key.Replace("\\", "\\\\");
writer.WriteLine($"{{ \"{kvp.Key}\" , \"{kvp.Value}\" }},");
}
Log.LogDebug($"MD5.json converted to MD5Convert.json at {checksumConvertPath}");
}
#endif
}
}

View file

@ -1,143 +0,0 @@
using PvZ_Fusion_Translator;
using System.Collections.Generic;
using System.IO;
using TMPro;
namespace PvZ_Fusion_Translator__BepInEx_.AssetStore
{
public static class FontStore
{
internal static Dictionary<string, TMP_FontAsset> fontAssetDict = [];
internal static Dictionary<string, TMP_FontAsset> fontAssetDictSecondary = [];
internal static void Init()
{
string fontsDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Fonts]");
foreach (string file in Directory.GetFiles(fontsDir))
{
string fileName = Path.GetFileNameWithoutExtension(file);
string fileExtension = Path.GetExtension(file);
if (fileExtension == ".ttf" || fileExtension == ".otf")
{
if (!fileName.EndsWith("_Almanac") && !fileName.EndsWith("_Fallback"))
{
string fontPath = Path.Combine("PvZ_Fusion_Translator", "[Custom Fonts]", fileName + fileExtension);
TMP_FontAsset fontAsset = FontHandler.LoadTMPFont(fontPath, true);
fontAsset.name = fileName;
fontAssetDict.Add(fileName, fontAsset);
Log.LogInfo($"Font for language '{fileName}' loaded");
}
}
}
InitFallback();
}
internal static void InitFallback()
{
string fontsDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Fonts]");
foreach (string file in Directory.GetFiles(fontsDir))
{
string fileName = Path.GetFileNameWithoutExtension(file);
string fileExtension = Path.GetExtension(file);
if (fileExtension == ".ttf" || fileExtension == ".otf")
{
if (fileName.EndsWith("_Almanac") || fileName.EndsWith("_Fallback"))
{
string fallbackPath = Path.Combine("PvZ_Fusion_Translator", "[Custom Fonts]", fileName + fileExtension);
TMP_FontAsset fallbackFont = FontHandler.LoadTMPFont(fallbackPath, true);
fallbackFont.name = fileName;
string fileNameLanguage = fileName.Replace("_Fallback", "").Replace("_Almanac", "");
if (fontAssetDictSecondary.ContainsKey(fileNameLanguage))
{
if (fileName.EndsWith("_Fallback"))
{
fontAssetDictSecondary.Add(fileNameLanguage + "_Almanac", fontAssetDictSecondary[fileNameLanguage]);
fontAssetDictSecondary.Remove(fileNameLanguage);
}
else
{
fontAssetDictSecondary.Add(fileNameLanguage + "_Fallback", fontAssetDictSecondary[fileNameLanguage]);
fontAssetDictSecondary.Remove(fileNameLanguage);
}
fontAssetDictSecondary.Add(fileName, fallbackFont);
}
else
fontAssetDictSecondary.Add(fileNameLanguage, fallbackFont);
}
}
}
AddFallback();
}
public static void AddFallback()
{
foreach (var lang in fontAssetDict.Keys)
{
if (fontAssetDict[lang].fallbackFontAssetTable == null)
{
fontAssetDict[lang].fallbackFontAssetTable = new Il2CppSystem.Collections.Generic.List<TMP_FontAsset>();
}
if (fontAssetDictSecondary.ContainsKey(lang))
{
fontAssetDict[lang].fallbackFontAssetTable.Add(fontAssetDictSecondary[lang]);
Log.LogInfo("Fallback font for language '" + lang + "' added");
continue;
}
if (fontAssetDictSecondary.ContainsKey(lang + "_Almanac"))
{
fontAssetDict[lang].fallbackFontAssetTable.Add(fontAssetDictSecondary[lang + "_Almanac"]);
Log.LogInfo("Fallback font for language '" + lang + "' added");
continue;
}
if (fontAssetDictSecondary.ContainsKey(lang + "_Fallback"))
{
fontAssetDict[lang].fallbackFontAssetTable.Add(fontAssetDictSecondary[lang + "_Fallback"]);
Log.LogInfo("Fallback font for language '" + lang + "' added");
continue;
}
}
}
public static TMP_FontAsset LoadTMPFont(string language)
{
if (fontAssetDict.TryGetValue(language, out TMP_FontAsset font))
{
return font;
}
return fontAssetDict.GetValueOrDefault("English");
}
public static TMP_FontAsset LoadTMPFontAlmanac(string language)
{
if (fontAssetDictSecondary.ContainsKey(language))
{
if (fontAssetDictSecondary.TryGetValue(language, out TMP_FontAsset almanacAsset))
{
return almanacAsset;
}
}
if (fontAssetDictSecondary.ContainsKey(language + "_Almanac"))
{
if (fontAssetDictSecondary.TryGetValue(language + "_Almanac", out TMP_FontAsset almanacAsset))
{
return almanacAsset;
}
}
return fontAssetDict.GetValueOrDefault("English");
}
public static void Reload()
{
// Get the current language
string currentLanguage = Utils.Language.ToString();
// Load the font for the current language
_ = LoadTMPFont(currentLanguage);
}
}
}

View file

@ -1,327 +0,0 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.AssetStore
{
public static class StringStore
{
internal static Dictionary<string, string> stringsDict = [];
public static Dictionary<string, string> translationStringRegex = new()
{
{"Test", "Test" }
};
public static Dictionary<string, string> translationString = new()
{
{"Test", "Test" }
};
public static Dictionary<string, Dictionary<string, string>> patchesStore = new()
{
{ "Difficulty", new Dictionary<string, string>
{
{ "English" , "Difficulty:" },
{ "French" , "Difficulté:" },
{ "Italian" , "Difficoltà:" },
{ "German" , "Schwierigkeit:" },
{ "Spanish" , "Dificultad:" },
{ "Portuguese" , "Dificuldade:" },
{ "Filipino" , "Ang Hirap:" },
{ "Vietnamese" , "Độ Khó:" },
{ "Indonesian" , "Kesulitan:" },
{ "Russian" , "Сложность:" },
{ "Japanese" , "困難:" },
{ "Korean", "난이도:" },
{ "Javanese" , "Kesulitan:" },
// { "Ukrainian" , "Складність:" },
// { "Slovak" , "Náročnosť:" },
}
},
{ "Zombies", new Dictionary<string, string>
{
{ "English" , "Zombies:" },
{ "French" , "Les Zombies:" },
{ "Italian" , "Zombi:" },
{ "German" , "Zombies:" },
{ "Spanish" , "Zombis:" },
{ "Portuguese" , "Zumbis:" },
{ "Filipino" , "Mga Zombie:" },
{ "Vietnamese" , "Thây Ma:" },
{ "Indonesian" , "Zombi:" },
{ "Russian" , "Зомби:" },
{ "Japanese" , "ゾンビ:" },
{ "Korean", "좀비:" },
{ "Javanese" , "Mayit:" },
// { "Ukrainian" , "Зомбі:" },
// { "Slovak" , "Zombíci:"}
}
}
};
internal static void Init()
{
FileLoader.LoadStrings();
}
internal static void Reload()
{
translationString.Clear();
translationStringRegex.Clear();
FileLoader.LoadStrings();
}
public static TextMeshPro TranslateText(TextMeshPro originalTMP, bool isLog = false)
{
string currentLanguage = Utils.Language.ToString();
TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage);
string translatedText = TranslateText(originalTMP.text);
originalTMP.font = fontAsset;
originalTMP.text = translatedText;
return originalTMP;
}
public static TextMeshProUGUI TranslateText(TextMeshProUGUI originalTMP, bool isLog = false)
{
string currentLanguage = Utils.Language.ToString();
TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage);
string translatedText = TranslateText(originalTMP.text);
originalTMP.font = fontAsset;
originalTMP.text = translatedText;
return originalTMP;
}
public static string TranslateText(string originalText, bool isLog = false)
{
string text = DoTranslateText(originalText, false);
string checkText;
#if DEBUG
Regex regex = new("\\p{IsCJKUnifiedIdeographs}+");
Match match = regex.Match(text);
if(match.Success)
{
// Log.LogDebug("Untranslated String: " + match.Value);
// FileLoader.DumpUntranslatedStrings(text);
}
#endif
checkText = text;
return checkText;
}
public static string DoTranslateText(string originalText, bool isLog = false)
{
if (string.IsNullOrEmpty(originalText))
{
if (isLog)
Log.LogError("Text Null or Empty");
return string.Empty;
}
if (translationString.ContainsKey(originalText))
{
if (isLog)
Log.LogDebug($"Text '{originalText} found in translationString");
return translationString[originalText];
}
// Regex-based dynamic translation
foreach (var entry in translationStringRegex)
{
var regex = new Regex(entry.Key);
if (regex.IsMatch(originalText))
{
// Extract dynamic parts from the original text
var match = regex.Match(originalText);
int groupCount = match.Groups.Count;
if (isLog)
Log.LogDebug("Text found in translationStringRegex {0}: {1}", match, groupCount);
// List to hold formatted dynamic parts
List<string> dynamicParts = [];
// Loop through each group and determine its translation
for (int i = 1; i < groupCount; i++)
{
string groupValue = match.Groups[i].Value;
string translatedValue = translationString.ContainsKey(groupValue)
? translationString[groupValue]
: groupValue;
dynamicParts.Add(translatedValue);
}
// Format the output string with dynamic parts
return string.Format(entry.Value, [.. dynamicParts]);
}
}
if (isLog)
Log.LogDebug($"Text '{originalText}' not translated");
return originalText;
}
private static TextAlignmentOptions TextAnchorToTMPAlignment(TextAnchor anchor)
{
return anchor switch
{
TextAnchor.UpperLeft => TextAlignmentOptions.TopLeft,
TextAnchor.UpperCenter => TextAlignmentOptions.Top,
TextAnchor.UpperRight => TextAlignmentOptions.TopRight,
TextAnchor.MiddleLeft => TextAlignmentOptions.MidlineLeft,
TextAnchor.MiddleCenter => TextAlignmentOptions.Center,
TextAnchor.MiddleRight => TextAlignmentOptions.MidlineRight,
TextAnchor.LowerLeft => TextAlignmentOptions.BottomLeft,
TextAnchor.LowerCenter => TextAlignmentOptions.Bottom,
TextAnchor.LowerRight => TextAlignmentOptions.BottomRight,
_ => TextAlignmentOptions.Center
};
}
static TextMeshProUGUI ConvertToTextMeshPro(UnityEngine.UI.Text oldText, TMP_FontAsset fontAsset, bool isLog = false)
{
if (oldText == null)
{
Log.LogError("UnityEngine.UI.Text component is null.");
return null;
}
if (fontAsset == null)
{
Log.LogError("TMP_FontAsset is null. Conversion cannot proceed.");
return null;
}
GameObject textObject = oldText.gameObject;
// Preserve text content and settings
string originalText = oldText.text;
originalText = TranslateText(originalText, isLog);
TextAnchor alignment = oldText.alignment;
Color color = oldText.color;
// Remove old Text component
UnityEngine.Object.DestroyImmediate(oldText);
// Add TextMeshProUGUI component
TextMeshProUGUI newTMP = textObject.AddComponent<TextMeshProUGUI>();
if (newTMP == null)
{
Log.LogError($"Failed to add TextMeshProUGUI to object: {textObject.name}");
return null;
}
// Configure TextMeshProUGUI
newTMP.text = originalText;
newTMP.color = color;
newTMP.alignment = TextAnchorToTMPAlignment(alignment);
newTMP.font = fontAsset;
return newTMP;
}
public static void TranslateTextTransform(Transform baseTransform, bool isAutoTextContainer = false, bool isLog = false)
{
if (!baseTransform) return;
string currentLanguage = Utils.Language.ToString();
TMP_FontAsset fontAsset = FontStore.LoadTMPFont(currentLanguage);
if (fontAsset == null)
{
Log.LogError($"Font for language '{currentLanguage}' not found. Translation aborted.");
return;
}
// Local function for processing transforms
void ProcessTextTransform(Transform textTransform)
{
if (!textTransform) return;
// Handle TextMeshPro components
TextMeshPro textTMP = textTransform.GetComponent<TextMeshPro>();
if (textTMP)
{
textTMP.text = TranslateText(textTMP.text, isLog);
textTMP.autoSizeTextContainer = isAutoTextContainer;
textTMP.font = fontAsset;
}
TextMeshProUGUI textTMPUGUI = textTransform.GetComponent<TextMeshProUGUI>();
if (textTMPUGUI)
{
textTMPUGUI.text = TranslateText(textTMPUGUI.text, isLog);
textTMPUGUI.enableAutoSizing = isAutoTextContainer;
textTMPUGUI.font = fontAsset;
}
// Handle UnityEngine.UI.Text components
UnityEngine.UI.Text textUI = textTransform.GetComponent<UnityEngine.UI.Text>();
if (textUI)
{
ConvertToTextMeshPro(textUI, fontAsset, isLog);
}
}
// Process specific text paths
ProcessTextTransform(baseTransform.Find("text"));
ProcessTextTransform(baseTransform.Find("text1"));
Transform shadowTransform = baseTransform.Find("text/shadow");
if (shadowTransform) ProcessTextTransform(shadowTransform);
shadowTransform = baseTransform.Find("text1/shadow");
if (shadowTransform) ProcessTextTransform(shadowTransform);
}
public static void TranslateTextUI(TextMeshPro textTMP, bool? isAutoTextContainer = null, bool isLog = false)
{
string currentLanguage = Utils.Language.ToString();
if (textTMP)
{
textTMP.text = TranslateText(textTMP.text, isLog);
if (isAutoTextContainer!=null) textTMP.autoSizeTextContainer = isAutoTextContainer.Value;
textTMP.font = FontStore.LoadTMPFont(currentLanguage);
}
}
public static void TranslateTextUI(TextMeshProUGUI textTMP, bool? isAutoTextContainer = null, bool isLog = false)
{
string currentLanguage = Utils.Language.ToString();
if (textTMP)
{
string origText = textTMP.text;
textTMP.text = TranslateText(origText, isLog) == "" ? origText : TranslateText(origText, isLog);
if (isAutoTextContainer != null) textTMP.autoSizeTextContainer = isAutoTextContainer.Value;
if (origText != textTMP.text)
textTMP.font = FontStore.LoadTMPFont(currentLanguage);
}
}
public static void TranslateTextUI(TMP_InputField TextInput)
{
string currentLanguage = Utils.Language.ToString();
if (TextInput)
{
string oriText = TextInput.m_Text;
TextInput.m_Text = TranslateText(oriText);
TextInput.m_OriginalText = TranslateText(oriText);
TextInput.fontAsset = FontStore.LoadTMPFont(currentLanguage);
}
}
public static void LogAll()
{
Log.LogInfo("Logging all StringStore entries.");
Log.LogInfo("Regex Entries: {0}", translationStringRegex.Count);
Log.LogInfo("String Entries: {0}", translationString.Count);
}
}
}

View file

@ -1,63 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.AssetStore
{
public static class TextureStore
{
internal static Dictionary<string, string> textureDict = [];
internal static void Init() => FileLoader.LoadTextures();
internal static void Reload()
{
textureDict.Clear();
RestoreTextures();
FileLoader.LoadDefaultTextures();
FileLoader.LoadTextures();
}
public static IEnumerator ReplaceTexturesCoroutine()
{
while (true)
{
ReplaceTextures();
yield return new WaitForSeconds(0.5f); // Adjust this interval as needed
}
}
public static void ReplaceTextures()
{
Texture2D[] textures = Resources.FindObjectsOfTypeAll<Texture2D>();
foreach (Texture2D texture in textures)
{
if (texture.name.StartsWith("replaced_"))
continue;
Utils.TryReplaceTexture2D(texture);
}
}
public static void RestoreTextures()
{
Texture2D[] textures = Resources.FindObjectsOfTypeAll<Texture2D>();
foreach (Texture2D texture in textures)
{
if (texture != null)
{
texture.name = texture.name.Replace("replaced_", "");
}
}
}
public static void LogAll()
{
Log.LogInfo("Logging all TextureStore entries.");
foreach (KeyValuePair<string, string> entry in textureDict)
{
Log.LogInfo("TextureDict Entry: " + entry.Key + " | " + entry.Value);
}
}
}
}

View file

@ -1,154 +0,0 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.AssetStore
{
public static class WarningStore
{
private static Dictionary<string, (string, string)> warningMessages = new()
{
{ "English", ("<size=10>The only valid source of this translation is from this community:\n" +
"<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. If you got this <i>anywhere</i> else like \n" +
"<color=#8B0000>Plants Hybrid</color> and <color=#8B0000>superhybrid.online</color>, they stole it.\n" +
"Stray away from other sources as they may contain viruses.\n" +
"Please visit our community for future updates.</size>",
"Okay! Got it.") },
{ "French", ("<size=9.5>La seule source valide pour cette traduction provient de cette\n" +
"communauté :<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Si vous l'avez obtenue \n" +
"<i>ailleurs</i>, comme <color=#8B0000>Plants Hybrid</color> ou <color=#8B0000>superhybrid.online</color>, ils l'ont volée.\n" +
"Évitez les autres sources, car elles peuvent contenir des virus.\n" +
"Veuillez visiter notre communauté pour les mises à jour futures.",
"D'accord !") },
{ "Italian", ("<size=10>L'unica fonte valida di questa traduzione è questa community:\n" +
"<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Se l'hai ottenuta <i>altrove</i>, come \n" +
"<color=#8B0000>Plants Hybrid</color> e <color=#8B0000>superhybrid.online</color>, l'hanno rubata.\n" +
"Evita altre fonti, potrebbero contenere virus.\n" +
"Visita la nostra community per aggiornamenti futuri.</size>",
"Va bene! Ho capito.") },
{ "German", ("<size=10>Die einzige gültige Quelle für diese Übersetzung stammt aus\n" +
"dieser Community: <color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Wenn Sie diese \n" +
"<i>irgendwo</i> anders gefunden haben, z. B. bei <color=#8B0000>Plants Hybrid</color> oder \n" +
"<color=#8B0000>superhybrid.online</color>, dann haben sie sie gestohlen.\n" +
"Meiden Sie andere Quellen, da diese Viren enthalten könnten.\n" +
"Bitte besuchen Sie unsere Community für zukünftige Updates.",
"Okay, verstanden!") },
{ "Spanish", ("<size=10>La única fuente válida de esta traducción proviene de esta\n" +
"comunidad: <color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Si la obtuvo <i>en cualquier</i>\n" +
"otro lugar como <color=#8B0000>Plants Hybrid</color> o <color=#8B0000>superhybrid.online</color>, la robaron.\n" +
"Manténgase alejado de otras fuentes, ya que podrían contener virus.\n" +
"Por favor, visite nuestra comunidad para futuras actualizaciones.",
"¡Entendido!") },
{ "Portuguese", ("<size=10>O lugar original e seguro dessa tradução vem daqui:\n" +
"<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Se você baixou ela de <i>qualquer \n" +
"lugar</i> como <color=#8B0000>Plants Hybrid</color> ou <color=#8B0000>superhybrid.online</color>, eles\n" +
"roubaram. Evite baixar deles, pode conter vírus.\n" +
"Por favor, visite nossa comunidade para atualizações futuras.</size>",
"Okay, entendido.") },
{ "Filipino", ("<size=9>Ang tanging opisyal na source ng pagsasaling ito ay mula\n" +
"lamang dito: <color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Kung nakuha nmo ito <i>kahit \n" +
"saan pa</i> tulad ng <color=#8B0000>Plants Hybrid</color> at <color=#8B0000>superhybrid.online</color>, ito ay ninakaw. \n" +
"Lumayo sa ibang source dahil posibleng may kasamang virus.\n" +
"Paki-bisita ang aming komunidad para sa mga darating na update.</size>" ,
"Naiintindihan!") },
{ "Vietnamese", ("<size=8>Nguồn duy nhất hợp lệ của bản dịch này là từ cộng\n" +
"đồng này: <color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Nếu bạn nhận \n" +
"được nó <i>ở bất cứ nơi nào</i> khác như <color=#8B0000>Plants Hybrid</color> \n" +
"hoặc <color=#8B0000>superhybrid.online</color>, họ đã ăn cắp nó.\n" +
"Tránh xa các nguồn khác vì chúng có thể chứa \n" +
"virus. Hãy ghé thăm cộng đồng của chúng tôi để \n" +
"cập nhật trong tương lai.</size>",
"Đồng ý!") },
{ "Indonesian", ("<size=10>Satu-satunya sumber resmi dari terjemahan ini adalah \n" +
"komunitas kami: <color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Jika Anda \n" +
"mendapatkannya dari <i>sumber lain</i> seperti <color=#8B0000>Plants Hybrid</color> \n" +
"dan <color=#8B0000>superhybrid.online</color>, mereka mencurinya. \n" +
"Jauhi sumber lain karena mungkin ada virus.\n" +
"Silakan kunjungi komunitas kami untuk pembaruan berikutnya.</size>",
"Oke! Mengerti.") },
{ "Russian", ("<size=9>Единственный проверенный источник этого перевода —\n" +
"сообщество <color=#E6E6FA>discord.gg/DPAC5ZVJ8T</color>.\n" +
"Или же его замена <color=#E6E6FA>https://t.me/nekoshkindom</color>\n" +
"Если вы скачали этот мод <i>где-либо ещё</i>, возможно он содержит вирусы.\n" +
"Программист перевода: LancerX0.\n" +
"Переводчик: Nekosha.", "Хорошо!") },
{ "Japanese", ("<size=6>この翻訳の唯一の有効なソースは、このコミュニティからです:\n" +
"<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>.<color=#8B0000>Plants Hybrid</color>や<color=#8B0000>superhybrid.online</color>、\n" +
"<color=#8B0000>YoutubeのBlue Fly</color>が作っているもの、他のどこかでこれを入手した場合、\n" +
"彼らはそれを盗んだことになります。ウイルスが含まれている可能性があるので、\n" +
"他のソースからは離れてください。今後のアップデートについては、\n私たちのコミュニティをご覧ください。</size>",
"了解しました!") },
{ "Korean", ("<size=8>이 번역은 Bloom(<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>)에서만\n" +
"제공됩니다. Bloom 디스코드 이외의 다른</i>서드 파티 사이트, \n" +
"예를 들어 <color=#8B0000>Plants Hybrid</color> 및 <color=#8B0000>superhybrid.online</color>, 또는\n" +
"<color=#8B0000>유튜브 Blue Fly</color>등에서 제공하는 파일은 무단으로 재배포된 것이며,\n" +
"이런 사이트들에는 바이러스가 포함되어 있을 가능성이 높습니다. \n향후 업데이트를 위해 저희 디스코드를 방문해 주세요.",
"확인") },
{ "Javanese" , ("<size=10>Sumber mung sing sah kanggo terjemahan iki saka komunitas iki:\n" +
"<color=#64DD17>discord.gg/DPAC5ZVJ8T</color>. Yen sampeyan nemokake iki <i>ing papan\n" +
"liya</i> kaya <color=#8B0000>Plants Hybrid</color> lan <color=#8B0000>superhybrid.online</color>, iku dicolong.\n" +
"Aja nyedhaki sumber liya amarga bisa ngandhut virus. Mangga\n" +
"ngunjungi komunitas kita kanggo nganyari ing mangsa ngarep.</size>",
"Oke! Ngertos.") },
};
public static (string, string) GetWarningMessage(Utils.LanguageEnum language)
{
if (warningMessages.TryGetValue(language.ToString(), out var message))
{
return message;
}
else
{
return warningMessages["English"]; // Default to English if language code is not found
}
}
public static void WarningLoad()
{
GameAPP.theGameStatus = -2;
GameObject gameObject = UnityEngine.Object.Instantiate<GameObject>(Resources.Load<GameObject>("UI/MainMenu/HelpMenu"), GameAPP.canvas.transform);
gameObject.name = "WarningMessage";
TextMeshProUGUI warning = gameObject.transform.GetChild(0).GetChild(0).GetComponent<TextMeshProUGUI>();
TextMeshProUGUI warningShadow = gameObject.transform.GetChild(0).GetChild(1).GetComponent<TextMeshProUGUI>();
Transform button = gameObject.transform.GetChild(1);
warning.transform.position = new Vector3(0.7f, 0.4f, 0f);
warningShadow.transform.position = new Vector3(0.7f, 0.4f, 0f);
var (warningMessage, okayButton) = WarningStore.GetWarningMessage(Utils.Language);
warning.text = warningMessage;
warningShadow.text = warningMessage;
warning.font = FontStore.LoadTMPFont(Utils.Language.ToString());
warningShadow.font = FontStore.LoadTMPFont(Utils.Language.ToString());
button.GetComponent<PauseMenu_Btn>().buttonNumber = 10;
button.GetChild(0).GetComponent<TextMeshProUGUI>().text = okayButton;
button.GetChild(0).GetComponent<TextMeshProUGUI>().font = FontStore.LoadTMPFont(Utils.Language.ToString());
button.GetChild(1).GetComponent<TextMeshProUGUI>().text = okayButton;
gameObject.SetActive(false);
gameObject.SetActive(true);
}
public static bool isWarningMessageLoaded = false;
public static void WarningReload(Utils.LanguageEnum language)
{
// Log.LogInfo("Current Language is " + Utils.OldLanguage);
// Log.LogInfo("Changed Language to " + language);
if (Utils.OldLanguage.ToString() == language.ToString() && Utils.OldLanguage.ToString() != "English")
{
return;
}
if (!isWarningMessageLoaded)
{
WarningLoad();
isWarningMessageLoaded = true;
}
return;
}
}
}

View file

@ -1,125 +0,0 @@
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP.Utils;
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using System;
using System.IO;
using System.Reflection;
using UnityEngine;
[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)]
[BepInProcess("PlantsVsZombiesRH.exe")]
public class Core : BasePlugin
{
public string modsDirectory => Path.Combine(Paths.PluginPath, "PvZ_Fusion_Translator");
private static DateTime dtStart;
private static DateTime? dtStartToast;
private static string toast_txt;
public static Core Instance { get; private set; }
public static MonoBehaviour MonoInstance { get; private set; }
private Coroutine replaceTextureRoutine = null;
public ConfigEntry<bool> configDefaultTextures;
public ConfigEntry<bool> configDefaultAudio;
public ConfigEntry<string> configLanguage;
public override void Load()
{
Instance = this;
MonoInstance = AddComponent<UnityCoroutineHelper>();
Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly());
LoadConfig();
FileLoader.LoadLanguage();
// AudioStore.Init();
TextureStore.Init();
StringStore.Init();
FontStore.Init();
InitCoroutine();
}
public override bool Unload()
{
if (replaceTextureRoutine != null)
{
MonoInstance.StopCoroutine(replaceTextureRoutine);
Log.LogDebug("Coroutine Stopped");
}
FileLoader.SaveLanguage();
#if OBFUSCATE && !RELEASE
CheckSumStore.ConvertMD5Json();
#endif
return true;
}
public void InitCoroutine()
{
if (replaceTextureRoutine != null) return;
replaceTextureRoutine = MonoInstance.StartCoroutine(TextureStore.ReplaceTexturesCoroutine());
Log.LogDebug("Coroutine Started");
}
public static void ShowToast(string message)
{
toast_txt = message;
dtStartToast = DateTime.Now;
}
public void Update()
{
#if DEBUG
ModFeatures.OnLateUpdate();
#endif
if (Input.GetKeyDown(KeyCode.Insert))
{
Utils.OpenSaveDirectory();
}
if (Input.GetKeyDown(KeyCode.Delete))
{
Utils.OpenTrello();
}
}
public void OnGUI()
{
#if DEBUG
if (dtStartToast != null)
{
GUI.Button(new Rect(10f, 10f, 200f, 20f), "\n" + toast_txt + "\n");
TimeSpan? timeSpan = DateTime.Now - dtStartToast;
TimeSpan t = new TimeSpan(0, 0, 2);
if (timeSpan > t)
{
dtStartToast = null;
}
}
#endif
}
private void LoadConfig()
{
string mainCategory = "PvZ_Fusion_Translator";
configDefaultTextures = Config.Bind(new ConfigDefinition(mainCategory, "DefaultTextures"), false, new ConfigDescription("Use Default Textures + Translation Textures", new AcceptableValueList<bool>(true, false)));
configDefaultAudio = Config.Bind(new ConfigDefinition(mainCategory, "DefaultAudio"), false, new ConfigDescription("Use Default Audio", new AcceptableValueList<bool>(true, false)));
configLanguage = Config.Bind(new ConfigDefinition(mainCategory, "Language"), "English", new ConfigDescription("Load the Game in this Language", new AcceptableValueList<string>("English", "French", "Italian", "German", "Spanish", "Portuguese", "Indonesian", "Vietnamese", "Javanese", "Russian", "Japanese", "Korean")));
}
}
public class UnityCoroutineHelper : MonoBehaviour
{
public static UnityCoroutineHelper Instance { get; private set; }
public void Awake()
{
Instance = this;
}
}

View file

@ -1,344 +0,0 @@
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using PvZ_Fusion_Translator__BepInEx_.Patches.OtherManagers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Encodings.Web;
using System.Text.Json;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_
{
internal static class FileLoader
{
internal enum AssetType
{
Textures,
Strings,
Dumps,
Almanac,
}
public static string GetAssetDir(AssetType assetType, Utils.LanguageEnum? language = null)
{
string languagePath = language.HasValue ? ("Localization" + Path.DirectorySeparatorChar + language.ToString()) : string.Empty;
return Path.Combine(Core.Instance.modsDirectory, languagePath, assetType.ToString());
}
internal static void LoadStrings() => LoadStrings(Utils.Language);
internal static void LoadStrings(Utils.LanguageEnum language)
{
string stringDir = GetAssetDir(AssetType.Strings, Utils.Language);
if (!Directory.Exists(stringDir))
{
Directory.CreateDirectory(stringDir);
}
try
{
foreach (string filepath in Directory.EnumerateFiles(stringDir, "*.json", SearchOption.AllDirectories))
{
#if OBFUSCATE
if (CheckSumStore.IsModified(filepath))
{
Log.LogError("File {0} was modified!" , filepath);
continue;
}
#endif
string fileName = Path.GetFileNameWithoutExtension(filepath);
StringStore.stringsDict[fileName] = filepath;
#if DEBUG
Log.LogInfo("Loading File : " + filepath);
#endif
string jsonString = File.ReadAllText(filepath);
if (fileName.EndsWith("_strings"))
{
Dictionary<string, string> dictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonString);
foreach (var (key, value) in dictionary)
{
StringStore.translationString[key] = value;
}
}
else if (fileName.EndsWith("_regexs"))
{
Dictionary<string, string> dictionary = JsonSerializer.Deserialize<Dictionary<string, string>>(jsonString);
foreach (var (key, value) in dictionary)
{
StringStore.translationStringRegex[key] = value;
}
}
}
SaveStrings();
#if DEBUG
DumpJson();
#endif
}
catch (Exception e)
{
Log.LogError("Error loading string.");
Log.LogError(e.GetType() + " " + e.Message);
}
Log.LogInfo("Strings loaded successfully.");
}
public static bool loadDefaultTextures = Core.Instance.configDefaultTextures.Value;
internal static void LoadTextures()
{
// Default or Custom Texturse -> English Textures -> Localized Textures
try
{
if (loadDefaultTextures == true)
{
LoadDefaultTextures();
}
else
{
LoadCustomTextures();
}
}
catch (Exception e)
{
Log.LogError("Error loading texture setting.");
Log.LogError($"{e.GetType()} {e.Message}");
}
if (Utils.Language != Utils.LanguageEnum.English)
{
LoadLocalizedTextures(Utils.LanguageEnum.English);
}
LoadLocalizedTextures(Utils.Language);
Log.LogInfo("Textures loaded successfully.");
}
internal static void LoadLocalizedTextures(Utils.LanguageEnum? language = null)
{
string textureDir = GetAssetDir(AssetType.Textures, language);
if (!Directory.Exists(textureDir))
{
Directory.CreateDirectory(textureDir);
}
try
{
foreach (string filepath in Directory.EnumerateFiles(textureDir, "*.png", SearchOption.AllDirectories))
{
if (filepath.Contains("[Custom Textures]", StringComparison.OrdinalIgnoreCase) && loadDefaultTextures)
{
continue;
}
#if OBFUSCATE
if (CheckSumStore.IsModified(filepath))
{
Log.LogError("File {0} was modified!" , filepath);
continue;
}
#endif
#if DEBUG
Log.LogDebug("Loading File : " + filepath);
#endif
Texture2D texture2D = Utils.LoadImage(filepath);
TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath;
}
}
catch (Exception e)
{
Log.LogError("Error loading Texture.");
Log.LogError(e.GetType() + " " + e.Message);
}
}
internal static void LoadDefaultTextures()
{
string textureDefaultDir = Path.Combine(Core.Instance.modsDirectory, AssetType.Dumps.ToString(), "Default Textures [Do Not Remove]");
if (!Directory.Exists(textureDefaultDir))
{
Directory.CreateDirectory(textureDefaultDir);
}
try
{
foreach (string filepath in Directory.EnumerateFiles(textureDefaultDir, "*.png", SearchOption.AllDirectories))
{
#if OBFUSCATE
if (CheckSumStore.IsModified(filepath))
{
Log.LogError("File {0} was modified!" , filepath);
continue;
}
#endif
Texture2D texture2D = Utils.LoadImage(filepath);
TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath;
}
}
catch (Exception e)
{
Log.LogError("Error loading Texture.");
Log.LogError(e.GetType() + " " + e.Message);
}
}
internal static void LoadCustomTextures()
{
string texturePackDir = Path.Combine(Core.Instance.modsDirectory, "[Custom Textures]");
if (!Directory.Exists(texturePackDir))
{
Directory.CreateDirectory(texturePackDir);
}
try
{
foreach (string filepath in Directory.EnumerateFiles(texturePackDir, "*.png", SearchOption.AllDirectories))
{
#if OBFUSCATE
if (CheckSumStore.IsModified(filepath))
{
Log.LogError("File {0} was modified!" , filepath);
continue;
}
#endif
Texture2D texture2D = Utils.LoadImage(filepath);
TextureStore.textureDict[Path.GetFileNameWithoutExtension(filepath)] = filepath;
}
}
catch (Exception e)
{
Log.LogError("Error loading Texture.");
Log.LogError(e.GetType() + " " + e.Message);
}
}
internal static void SaveStrings()
{
string stringDir = GetAssetDir(AssetType.Strings, Utils.Language);
if (!Directory.Exists(stringDir))
{
Directory.CreateDirectory(stringDir);
}
string translationStringRegex = JsonSerializer.Serialize(StringStore.translationStringRegex, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
File.WriteAllText(Path.Combine(stringDir, "translation_regexs.json"), translationStringRegex);
string translationString = JsonSerializer.Serialize(StringStore.translationString, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
});
File.WriteAllText(Path.Combine(stringDir, "translation_strings.json"), translationString);
}
#if DEBUG
public static void DumpJson()
{
string dumpDir = GetAssetDir(AssetType.Dumps);
if (!Directory.Exists(dumpDir))
{
Directory.CreateDirectory(dumpDir);
}
string LawnStrings = Resources.Load<TextAsset>("LawnStrings").text;
string ZombieStrings = Resources.Load<TextAsset>("ZombieStrings").text;
File.WriteAllText(Path.Combine(dumpDir, "LawnStrings.json"), LawnStrings);
File.WriteAllText(Path.Combine(dumpDir, "ZombieStrings.json"), ZombieStrings);
Dictionary<Achievement, AchievementObject> achievementsList = new Dictionary<Achievement, AchievementObject>();
foreach (Il2CppSystem.Collections.Generic.KeyValuePair<Achievement, Il2CppSystem.Tuple<string, string>> entry in AchievementClip.achievementsText)
{
achievementsList.Add(entry.Key, new AchievementObject(entry.Key, entry.Value.Item1, entry.Value.Item2));
}
File.WriteAllText(Path.Combine(dumpDir, "AchievementsText.json"), JsonSerializer.Serialize(achievementsList, new JsonSerializerOptions
{
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
}));
}
#endif
#if DEBUG && MELON
public static void DumpUntranslatedStrings(string text)
{
string dumpDir = GetAssetDir(AssetType.Dumps);
string jsonFile = Path.Combine(dumpDir, "UntranslatedStrings.json");
if (!Directory.Exists(dumpDir))
{
Directory.CreateDirectory(dumpDir);
}
if (!File.Exists(jsonFile))
{
File.WriteAllText(jsonFile, "{}"); // Initialize empty JSON object
}
string json = File.ReadAllText(jsonFile);
JObject untranslatedStrings = JObject.Parse(json);
if (!untranslatedStrings.ContainsKey(text))
{
untranslatedStrings[text] = text;
File.WriteAllText(jsonFile, untranslatedStrings.ToString());
}
}
#endif
internal static void LoadLanguage()
{
try
{
// Load the language preference as a string and parse it into the enum
string languageName = Core.Instance.configLanguage.Value;
if (Enum.TryParse(languageName, out Utils.LanguageEnum loadedLanguage))
{
Utils.Language = loadedLanguage;
}
else
{
Log.LogWarning($"Invalid language '{languageName}' found in preferences. Falling back to English.");
Utils.Language = Utils.LanguageEnum.English; // Default fallback
}
Log.LogWarning($"Loaded language {languageName}");
}
catch (Exception e)
{
Log.LogError("Error loading language setting.");
Log.LogError($"{e.GetType()} {e.Message}");
}
Log.LogInfo($"Language has been loaded: {Utils.Language}");
}
internal static void SaveLanguage()
{
try
{
// Save the current language as a string
if (Core.Instance.Config.TryGetEntry<string>("PvZ_Fusion_Translator", "Language", out var languageEntry))
{
languageEntry.Value = Utils.Language.ToString();
}
// Ensure changes are written to the config file
// MelonPreferences.Save();
}
catch (Exception e)
{
Log.LogError("Error saving language setting.");
Log.LogError($"{e.GetType()} {e.Message}");
}
// Log.LogInfo($"Language has been saved: {Utils.Language}");
}
}
}

View file

@ -1,45 +0,0 @@
using BepInEx;
using PvZ_Fusion_Translator__BepInEx_;
using System.IO;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator
{
public static class FontHandler
{
public static Font LoadFont(this string pathFromModsFolder, bool throwException)
{
string fontFilePath = Path.Combine(Paths.PluginPath, pathFromModsFolder);
if (!File.Exists(fontFilePath))
{
if (throwException)
Log.LogWarning($"Font not found at path: '{fontFilePath}'.");
return null;
}
Font font = new Font();
Font.Internal_CreateFontFromPath(font, fontFilePath); // Default size, adjust as needed
return font;
}
public static TMP_FontAsset ConvertToTMP(this Font font)
{
TMP_FontAsset fontAsset = TMP_FontAsset.CreateFontAsset(font);
if (fontAsset == null)
{
Log.LogWarning($"Failed to create TMP_FontAsset from font '{font.name}'.");
return null;
}
return fontAsset;
}
public static TMP_FontAsset LoadTMPFont(this string pathFromModsFolder, bool throwException)
{
Font font = pathFromModsFolder.LoadFont(throwException);
if (font == null)
return null;
return font.ConvertToTMP();
}
}
}

View file

@ -1,25 +0,0 @@
using BepInEx.Logging;
namespace PvZ_Fusion_Translator__BepInEx_
{
internal static class Log
{
private static readonly ManualLogSource Logger = BepInEx.Logging.Logger.CreateLogSource("PvZ_Fusion_Translator");
public static void LogDebug(object txt) => Logger.LogDebug(txt);
public static void LogDebug(string txt) => Logger.LogDebug(txt);
public static void LogDebug(string txt, params object[] args) => Logger.LogDebug(string.Format(txt, args));
public static void LogInfo(object txt) => Logger.LogInfo(txt);
public static void LogInfo(string txt) => Logger.LogInfo(txt);
public static void LogInfo(string txt, params object[] args) => Logger.LogInfo(string.Format(txt, args));
public static void LogWarning(object txt) => Logger.LogWarning(txt);
public static void LogWarning(string txt) => Logger.LogWarning(txt);
public static void LogWarning(string txt, params object[] args) => Logger.LogWarning(string.Format(txt, args));
public static void LogError(object txt) => Logger.LogError(txt);
public static void LogError(string txt) => Logger.LogError(txt);
public static void LogError(string txt, params object[] args) => Logger.LogError(string.Format(txt, args));
}
}

View file

@ -1,79 +0,0 @@
#if DEBUG
using System;
using System.Collections.Generic;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_
{
public static class ModFeatures
{
public enum ModType
{
ReloadStrings,
ReloadTextures,
}
private class ModFeature
{
public string Name { get; private set; }
public ModType ModType { get; private set; }
public KeyCode KeyCode { get; private set; }
public bool IsActive { get; set; }
public ModFeature(string name, ModType modType, KeyCode keyCode, bool defaultValue = false)
{
Name = name;
ModType = modType;
KeyCode = keyCode;
IsActive = defaultValue;
}
public void ToggleFeature()
{
if (ModType == ModType.ReloadStrings)
{
StringStore.Reload();
Core.ShowToast("Strings Reloaded!");
return;
}
if (ModType == ModType.ReloadTextures)
{
TextureStore.Reload();
Core.ShowToast("Textures Reloaded!");
return;
}
}
}
private static readonly Dictionary<ModType, ModFeature> featureLists = new()
{
{ ModType.ReloadStrings, new ModFeature("Reload Strings", ModType.ReloadStrings, KeyCode.Home, true) },
{ ModType.ReloadTextures, new ModFeature("Reload Textures", ModType.ReloadTextures, KeyCode.End, true) },
};
public static void ToggleFeature(ModType modType)
{
if (!featureLists.ContainsKey(modType))
return;
featureLists[modType].ToggleFeature();
}
public static void OnLateUpdate()
{
foreach (var feature in featureLists.Values)
{
if (feature.KeyCode != KeyCode.None && Enum.IsDefined(typeof(KeyCode), feature.KeyCode))
{
if (Input.GetKeyDown(feature.KeyCode))
{
feature.ToggleFeature();
}
}
}
}
}
}
#endif

View file

@ -1,25 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using System;
using TMPro;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects
{
[HarmonyPatch(typeof(InGameText))]
public static class InGameText_Patch
{
[HarmonyPatch(nameof(InGameText.EnableText), new Type[] { typeof(string), typeof(float), typeof(bool) })]
[HarmonyPrefix]
private static void EnableText(InGameText __instance, ref string text) => text = StringStore.TranslateText(text, true);
[HarmonyPatch(nameof(InGameText.EnableText), new Type[] { typeof(string), typeof(float), typeof(bool) })]
[HarmonyPostfix]
private static void EnableText(InGameText __instance)
{
TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString());
__instance.t.text = StringStore.TranslateText(__instance.t.text, true);
__instance.t.font = fontAsset;
}
}
}

View file

@ -1,23 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects
{
[HarmonyPatch(typeof(TMP_InputField))]
public static class TMP_InputField_Patch
{
[HarmonyPatch(nameof(TMP_InputField.OnEnable))]
[HarmonyPostfix]
private static void OnEnable(TMP_InputField __instance)
{
if (!string.IsNullOrEmpty(__instance.text))
{
string text = StringStore.TranslateText(__instance.text);
__instance.m_Text = StringStore.TranslateText(text);
__instance.m_OriginalText = StringStore.TranslateText(text);
__instance.m_TextComponent.text = StringStore.TranslateText(text);
}
}
}
}

View file

@ -1,77 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine.UI;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects
{
[HarmonyPatch(typeof(TextMeshProUGUI))]
public static class TextMeshProUGUI_Patch
{
[HarmonyPatch(nameof(TextMeshProUGUI.OnEnable))]
[HarmonyPostfix]
private static void OnEnable(TextMeshProUGUI __instance)
{
if (!string.IsNullOrEmpty(__instance.text))
{
__instance = StringStore.TranslateText(__instance);
__instance.autoSizeTextContainer = false;
if (__instance.name.StartsWith("LevelName"))
{
__instance.text = __instance.text.Replace("\n", " ");
}
if ((__instance.transform.parent != null) && (__instance.transform.parent.name.StartsWith("Window")))
{
__instance.fontSizeMin = 10;
__instance.fontSize = 12;
}
// __instance.ForceMeshUpdate();
}
}
[HarmonyPatch(nameof(TextMeshProUGUI.Awake))]
[HarmonyPostfix]
private static void Awake(TextMeshProUGUI __instance)
{
if (!string.IsNullOrEmpty(__instance.text))
{
__instance = StringStore.TranslateText(__instance);
__instance.autoSizeTextContainer = false;
if (__instance.name.StartsWith("LevelName"))
{
__instance.text = __instance.text.Replace("\n", " ");
}
if ((__instance.transform.parent != null) && (__instance.transform.parent.name.StartsWith("Window")))
{
__instance.fontSizeMin = 10;
__instance.fontSize = 12;
}
if (__instance.text == "Полный Хаос" && __instance.transform.parent.parent.Find("Image").GetComponent<Image>().activeSprite.name == "Present")
{
__instance.text += "\nБесконечно";
}
// __instance.ForceMeshUpdate();
}
}
}
[HarmonyPatch(typeof(TMP_SubMeshUI))]
public static class TMP_SubMeshUI_Patch
{
[HarmonyPatch(nameof(TMP_SubMeshUI.OnEnable))]
[HarmonyPostfix]
public static void OnEnable(TMP_SubMeshUI __instance)
{
if (!string.IsNullOrEmpty(__instance.textComponent.text))
{
string text = StringStore.TranslateText(__instance.textComponent.text);
__instance.m_TextComponent.text = StringStore.TranslateText(text);
__instance.textComponent.text = StringStore.TranslateText(text);
}
}
}
}

View file

@ -1,27 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.BaseTextObjects
{
[HarmonyPatch(typeof(TextMeshPro))]
public static class TextMeshPro_Patch
{
[HarmonyPatch(nameof(TextMeshPro.OnEnable))]
[HarmonyPostfix]
private static void OnEnable(TextMeshPro __instance)
{
if (!string.IsNullOrEmpty(__instance.text))
{
if (__instance.transform.parent.name.StartsWith("AlmanacHelp"))
{
__instance = StringStore.TranslateText(__instance);
__instance.autoSizeTextContainer = false;
return;
}
__instance = StringStore.TranslateText(__instance);
__instance.autoSizeTextContainer = true;
}
}
}
}

View file

@ -1,102 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
[HarmonyPatch(typeof(Advanture_Btn))]
public static class Advanture_Btn_Patch
{
[HarmonyPatch(nameof(Advanture_Btn.Start))]
[HarmonyPostfix]
private static void Start(Advanture_Btn __instance)
{
StringStore.TranslateTextTransform(__instance.transform, true);
Transform parentTransform = __instance.transform.parent.transform;
if (__instance.name == "Goback")
{
Transform backgroundTransform = parentTransform.Find("Background");
backgroundTransform.Find("Name").GetComponent<TMP_Text>().autoSizeTextContainer = true;
backgroundTransform.Find("Shadow").GetComponent<TMP_Text>().autoSizeTextContainer = true;
}
Transform levelTransform = parentTransform.Find("Levels");
if (levelTransform != null)
{
StringStore.TranslateTextTransform(levelTransform.Find("Nextpage"));
StringStore.TranslateTextTransform(levelTransform.Find("LastPage"));
Transform pageMiniGamesTransform = levelTransform.transform.Find("PageMiniGames");
if (pageMiniGamesTransform != null)
{
StringStore.TranslateTextTransform(pageMiniGamesTransform.Find("BackToIndex"));
StringStore.TranslateTextTransform(pageMiniGamesTransform.Find("Nextpage"));
StringStore.TranslateTextTransform(pageMiniGamesTransform.Find("LastPage"));
}
Transform pageUnlockChallengeTransform = levelTransform.transform.Find("PageUnlockChallenge");
if (pageUnlockChallengeTransform != null)
{
StringStore.TranslateTextTransform(pageUnlockChallengeTransform.Find("BackToIndex"));
}
Transform pageFlagChallengeTransform = levelTransform.transform.Find("PageFlagChallenge");
if (pageFlagChallengeTransform != null)
{
StringStore.TranslateTextTransform(pageFlagChallengeTransform.Find("BackToIndex"));
}
Transform pageTravelExperienceTransform = levelTransform.transform.Find("PageTravelExperience");
if (pageTravelExperienceTransform != null)
{
StringStore.TranslateTextTransform(pageTravelExperienceTransform.Find("BackToIndex"));
}
Transform pageGardenProtectionTransform = levelTransform.transform.Find("PageGardenProtection");
if (pageGardenProtectionTransform != null)
{
StringStore.TranslateTextTransform(pageGardenProtectionTransform.Find("BackToIndex"));
}
Transform pageNormalTravelTransform = levelTransform.transform.Find("PageNormalTravel");
if (pageNormalTravelTransform != null)
{
StringStore.TranslateTextTransform(pageNormalTravelTransform.Find("BackToIndex"));
}
Transform pageRandomLevelTransform = levelTransform.transform.Find("PageRandomLevel");
if (pageRandomLevelTransform != null)
{
StringStore.TranslateTextTransform(pageRandomLevelTransform.Find("BackToIndex"));
}
Transform pageUltimateExperienceTransform = levelTransform.transform.Find("PageUltimateExprience");
if (pageUltimateExperienceTransform != null)
{
StringStore.TranslateTextTransform(pageUltimateExperienceTransform.Find("BackToIndex"));
}
Transform pageAdvantureLevelTransform = levelTransform.transform.Find("PageAdvantureLevel");
if (pageAdvantureLevelTransform != null)
{
StringStore.TranslateTextTransform(pageAdvantureLevelTransform.Find("BackToIndex"));
StringStore.TranslateTextTransform(pageAdvantureLevelTransform.Find("Nextpage"));
StringStore.TranslateTextTransform(pageAdvantureLevelTransform.Find("LastPage"));
}
Transform pageScaryPotTransform = levelTransform.transform.Find("PageScaryPot");
if (pageScaryPotTransform != null)
{
StringStore.TranslateTextTransform(pageScaryPotTransform.Find("BackToIndex"));
StringStore.TranslateTextTransform(pageScaryPotTransform.Find("Nextpage"));
StringStore.TranslateTextTransform(pageScaryPotTransform.Find("LastPage"));
}
}
StringStore.TranslateTextTransform(parentTransform.Find("CameraSize"));
StringStore.TranslateTextTransform(parentTransform.Find("CanvasSize"));
}
}
}

View file

@ -1,41 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
[HarmonyPatch(typeof(EveBtn))]
public static class EveBtn_Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(EveBtn.OnMouseUp))]
private static void OnMouseUp(EveBtn __instance)
{
Transform sceneText = __instance.transform.FindChild("text");
if(sceneText != null)
{
TextMeshProUGUI sceneTextTMP = sceneText.transform.GetComponent<TextMeshProUGUI>();
if(sceneTextTMP != null)
{
sceneTextTMP.text = StringStore.TranslateText(sceneTextTMP.text);
}
}
Transform sceneTextShadow = sceneText.transform.FindChild("text2");
if(sceneTextShadow != null)
{
TextMeshProUGUI sceneTextShadowTMP = sceneTextShadow.transform.GetComponent<TextMeshProUGUI>();
if (sceneTextShadowTMP != null)
{
sceneTextShadowTMP.text = StringStore.TranslateText(sceneTextShadowTMP.text);
}
}
if (__instance.name.Equals("Balanced"))
{
__instance.gameObject.SetActive(false);
__instance.gameObject.SetActive(true);
}
}
}
}

View file

@ -1,34 +0,0 @@
using HarmonyLib;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
[HarmonyPatch(typeof(InGameBtn))]
public static class InGameBtn_Patch
{
[HarmonyPatch(nameof(InGameBtn.Update))]
[HarmonyPostfix]
private static void Update(InGameBtn __instance)
{
Transform sceneText = __instance.transform.FindChild("SceneText");
if(sceneText != null)
{
TextMeshProUGUI sceneTextTMP = sceneText.transform.GetComponent<TextMeshProUGUI>();
if(sceneTextTMP != null)
{
sceneTextTMP = AssetStore.StringStore.TranslateText(sceneTextTMP);
}
Transform sceneTextShadow = sceneText.transform.FindChild("SceneText");
if(sceneTextShadow != null)
{
TextMeshProUGUI sceneTextShadowTMP = sceneTextShadow.transform.GetComponent<TextMeshProUGUI>();
if (sceneTextShadowTMP != null)
{
sceneTextShadowTMP = AssetStore.StringStore.TranslateText(sceneTextShadowTMP);
}
}
}
}
}
}

View file

@ -1,213 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using Object = UnityEngine.Object;
public class OptionButtonData
{
public OptionBtn Button { get; set; }
public Vector3 Position { get; set; }
public Utils.LanguageEnum? Language { get; set; } // Null if it's the "Next" button
public bool IsNextButton { get; set; }
}
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
internal class OptLanguageBtn_Patch
{
public static Dictionary<int, OptionButtonData> LanguageBtnDict = new();
private static bool buttonsCreated = false;
private static OptionBtn cachedTemplateButton;
private const float startX = 4.3241f + 2.56f;
private const float startY = 2.7769f;
private const float ySpacing = 1.2505f;
private static List<Utils.LanguageEnum> AvailableLanguages;
private const int LanguagesPerPage = 5;
private static int currentPage = 0;
private static OptionBtn[] buttonSlots = new OptionBtn[6]; // 5 language buttons + 1 next button
public static void CreateLanguageButtons(OptionBtn templateButton)
{
if (buttonsCreated) return;
buttonsCreated = true;
cachedTemplateButton = templateButton;
AvailableLanguages = Enum.GetValues(typeof(Utils.LanguageEnum))
.Cast<Utils.LanguageEnum>()
.Where(lang => lang != Utils.LanguageEnum.LANG_END)
.ToList();
for (int i = 0; i < 6; i++)
{
var newButton = Object.Instantiate(templateButton, templateButton.transform.parent);
newButton.optionType = 80 + i;
float yPos = startY - i * ySpacing;
Vector3 pos = new(startX, yPos);
newButton.transform.position = pos;
buttonSlots[i] = newButton;
LanguageBtnDict[newButton.GetInstanceID()] = new OptionButtonData
{
Button = newButton,
Position = pos
};
}
UpdatePage();
}
private static void UpdatePage()
{
int startIndex = currentPage * LanguagesPerPage;
int langCount = AvailableLanguages.Count;
for (int i = 0; i < 5; i++)
{
var btn = buttonSlots[i];
var data = LanguageBtnDict[btn.GetInstanceID()];
if (startIndex + i < langCount)
{
var lang = AvailableLanguages[startIndex + i];
data.Language = lang;
data.IsNextButton = false;
btn.gameObject.SetActive(true);
UpdateButtonText(btn, lang.ToString());
}
else
{
data.Language = null;
data.IsNextButton = false;
btn.gameObject.SetActive(false);
}
}
// "Next" button always visible at index 5
var nextBtn = buttonSlots[5];
var nextData = LanguageBtnDict[nextBtn.GetInstanceID()];
nextData.Language = null;
nextData.IsNextButton = true;
nextBtn.gameObject.SetActive(true);
UpdateButtonText(nextBtn, "Next");
}
public static void UpdateButtonText(OptionBtn button, string languageName)
{
TMP_FontAsset defaultAsset = FontStore.LoadTMPFont("English");
for (int i = 0; i < 3; i++)
{
Transform textTransform = button.transform.GetChild(i);
if (textTransform != null)
{
if (i == 0) textTransform.gameObject.SetActive(false);
TextMeshProUGUI text = textTransform.GetComponent<TextMeshProUGUI>();
if (text != null)
{
if (i == 0)
{
text.text = "";
text.color = Color.red;
}
else
{
text.text = languageName;
}
text.fontSize = 16;
text.font = defaultAsset;
text.autoSizeTextContainer = false;
}
}
}
}
private static void FlashMessage(OptionBtn button, string message)
{
var child = button.transform.GetChild(0);
if (child != null)
{
var text = child.GetComponent<TextMeshProUGUI>();
if (text != null)
{
text.text = message;
}
child.gameObject.SetActive(true);
Task.Delay(1000).ContinueWith(_ =>
{
if (button != null && child != null && child.gameObject.activeSelf)
{
child.gameObject.SetActive(false);
}
});
}
}
[HarmonyPatch(typeof(OptionBtn))]
public static class OptLangBtn_Patch
{
[HarmonyPatch(nameof(OptionBtn.Awake))]
[HarmonyPostfix]
private static void Awake(OptionBtn __instance)
{
if (!buttonsCreated || cachedTemplateButton == null)
{
buttonsCreated = false;
CreateLanguageButtons(__instance);
}
}
[HarmonyPatch("OnMouseUpAsButton")]
[HarmonyPrefix]
private static void OnMouseUpAsButton(OptionBtn __instance)
{
if (LanguageBtnDict.TryGetValue(__instance.GetInstanceID(), out var btnData))
{
if (btnData.IsNextButton)
{
currentPage = (currentPage + 1) % (int)Math.Ceiling((float)AvailableLanguages.Count / LanguagesPerPage);
UpdatePage();
return;
}
if (btnData.Language is Utils.LanguageEnum selectedLang)
{
string currentLang = Utils.Language.ToString();
if (currentLang == selectedLang.ToString())
{
FlashMessage(btnData.Button, "Already Selected!");
}
else
{
Utils.ChangeLanguage(selectedLang.ToString());
Debug.Log($"Language changed to: {selectedLang}");
FlashMessage(btnData.Button, "Language Changed!");
}
}
}
}
[HarmonyPatch(nameof(OptionBtn.Update))]
[HarmonyPostfix]
private static void Update(OptionBtn __instance)
{
if (LanguageBtnDict.TryGetValue(__instance.GetInstanceID(), out var btnData))
{
btnData.Button.transform.position = btnData.Position;
}
}
}
}
}

View file

@ -1,68 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
[HarmonyPatch(typeof(OptionBtn))]
public static class OptionBtn_Patch
{
[HarmonyPatch(nameof(OptionBtn.Awake))]
[HarmonyPostfix]
private static void Awake(OptionBtn __instance)
{
Transform text_1Transform = __instance.transform.GetChild(0)?.transform;
if (text_1Transform != null)
{
TextMeshProUGUI text_1 = text_1Transform.GetComponent<TextMeshProUGUI>();
text_1 = StringStore.TranslateText(text_1);
text_1.autoSizeTextContainer = false;
}
Transform textTransform = __instance.transform.GetChild(1)?.transform;
if (textTransform != null)
{
TextMeshProUGUI text = textTransform.GetComponent<TextMeshProUGUI>();
text = StringStore.TranslateText(text);
text.autoSizeTextContainer = false;
}
Transform text2Transform = __instance.transform.GetChild(2)?.transform;
if (text2Transform != null)
{
TextMeshProUGUI text2 = text2Transform.GetComponent<TextMeshProUGUI>();
text2 = StringStore.TranslateText(text2);
text2.autoSizeTextContainer = false;
}
}
[HarmonyPatch("OnMouseUpAsButton")]
[HarmonyPostfix]
private static void OnMouseUpAsButtonPostfix(OptionBtn __instance)
{
Transform text_1Transform = __instance.transform.GetChild(0)?.transform;
if (text_1Transform != null)
{
TextMeshProUGUI text_1 = text_1Transform.GetComponent<TextMeshProUGUI>();
text_1 = StringStore.TranslateText(text_1);
text_1.autoSizeTextContainer = false;
}
Transform textTransform = __instance.transform.GetChild(1)?.transform;
if (textTransform != null)
{
TextMeshProUGUI text = textTransform.GetComponent<TextMeshProUGUI>();
text = StringStore.TranslateText(text);
text.autoSizeTextContainer = false;
}
Transform text2Transform = __instance.transform.GetChild(2)?.transform;
if (text2Transform != null)
{
TextMeshProUGUI text2 = text2Transform.GetComponent<TextMeshProUGUI>();
text2 = StringStore.TranslateText(text2);
}
}
}
}

View file

@ -1,41 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
[HarmonyPatch(typeof(PVPPotBtn))]
public class PVPPotBtn_Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(PVPPotBtn.OnMouseUpAsButton))]
public static void OnMouseUpAsButton(PVPPotBtn __instance)
{
Transform sceneText = __instance.transform.FindChild("text");
if(sceneText != null)
{
TextMeshProUGUI sceneTextTMP = sceneText.transform.GetComponent<TextMeshProUGUI>();
if(sceneTextTMP != null)
{
sceneTextTMP.text = StringStore.TranslateText(sceneTextTMP.text);
}
}
Transform sceneTextShadow = sceneText.transform.FindChild("text_1");
if(sceneTextShadow != null)
{
TextMeshProUGUI sceneTextShadowTMP = sceneTextShadow.transform.GetComponent<TextMeshProUGUI>();
if (sceneTextShadowTMP != null)
{
sceneTextShadowTMP.text = StringStore.TranslateText(sceneTextShadowTMP.text);
}
}
if (__instance.name.Equals("ChangeBg_3") || __instance.name.Equals("ChangeBg_4"))
{
__instance.gameObject.SetActive(false);
__instance.gameObject.SetActive(true);
}
}
}
}

View file

@ -1,13 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.ButtonObjects
{
[HarmonyPatch(typeof(PauseMenu_Btn))]
public static class PauseMenu_Btn_Patch
{
[HarmonyPatch(nameof(PauseMenu_Btn.Start))]
[HarmonyPostfix]
private static void Start(PauseMenu_Btn __instance) => StringStore.TranslateTextTransform(__instance.transform);
}
}

View file

@ -1,48 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects
{
[HarmonyPatch(typeof(Close))]
public static class Close_Patch
{
[HarmonyPatch(nameof(Close.Start))]
[HarmonyPostfix]
private static void Close_Start(Close __instance)
{
TextMeshPro closeText = __instance.transform.GetChild(0).GetComponent<TextMeshPro>();
closeText.text = "合上";
closeText = StringStore.TranslateText(closeText);
closeText.autoSizeTextContainer = true;
Transform AlmanacTransform = __instance.transform.parent.transform;
Transform nameTransform = AlmanacTransform.Find("Name");
if (nameTransform != null)
{
TextMeshPro nameTMP = nameTransform.transform.GetComponent<TextMeshPro>();
if (nameTMP)
{
nameTMP = StringStore.TranslateText(nameTMP);
nameTMP.autoSizeTextContainer = true;
}
Transform nameShadowTransform = nameTransform.Find("NameShadow");
if (nameShadowTransform)
{
TextMeshPro nameShadowTMP = nameShadowTransform.transform.GetComponent<TextMeshPro>();
if (nameShadowTMP)
{
nameShadowTMP = StringStore.TranslateText(nameShadowTMP);
nameShadowTMP.autoSizeTextContainer = true;
}
}
}
StringStore.TranslateTextTransform(AlmanacTransform.Find("Back"), true);
StringStore.TranslateTextTransform(AlmanacTransform.Find("NextPage"));
StringStore.TranslateTextTransform(AlmanacTransform.Find("LastPage"));
}
}
}

View file

@ -1,23 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects
{
[HarmonyPatch(typeof(CustomSettings))]
public static class CustomSettings_Patch
{
[HarmonyPatch(nameof(CustomSettings.Awake))]
[HarmonyPostfix]
private static void Awake(CustomSettings __instance)
{
__instance.textMesh = StringStore.TranslateText(__instance.textMesh);
}
[HarmonyPatch(nameof(CustomSettings.ChangeText))]
[HarmonyPostfix]
private static void ChangeText(CustomSettings __instance)
{
__instance.textMesh = StringStore.TranslateText(__instance.textMesh);
}
}
}

View file

@ -1,44 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects
{
[HarmonyPatch(typeof(CustomSun))]
public static class CustomSun_Patch
{
[HarmonyPatch(nameof(CustomSun.Awake))]
[HarmonyPostfix]
private static void Awake(CustomSun __instance)
{
if (__instance.inputField.gameObject.activeSelf)
{
string oriTextSun = __instance.inputField.m_Text;
__instance.inputField.gameObject.SetActive(false);
__instance.inputField.m_Text = StringStore.TranslateText(oriTextSun);
__instance.inputField.m_OriginalText = StringStore.TranslateText(oriTextSun);
__instance.inputField.gameObject.SetActive(true);
}
if (__instance.setFlags.gameObject.activeSelf)
{
string oriTextFlags = __instance.setFlags.m_Text;
__instance.setFlags.gameObject.SetActive(false);
__instance.setFlags.m_Text = StringStore.TranslateText(oriTextFlags);
__instance.setFlags.m_OriginalText = StringStore.TranslateText(oriTextFlags);
__instance.setFlags.gameObject.SetActive(true);
}
Transform lookZombieTransform = __instance.lookZombie.transform.GetChild(0).transform;
if (lookZombieTransform != null)
{
TextMeshProUGUI lookZombieTMP = lookZombieTransform.GetComponent<TextMeshProUGUI>();
if (lookZombieTMP != null)
{
lookZombieTMP = StringStore.TranslateText(lookZombieTMP);
}
}
}
}
}

View file

@ -1,23 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects
{
[HarmonyPatch(typeof(GardenPlant))]
public static class GardenPlant_Patch
{
[HarmonyPatch(nameof(GardenPlant.Update))]
[HarmonyPostfix]
private static void Update(GardenPlant __instance)
{
__instance.infoText = StringStore.TranslateText(__instance.infoText);
}
[HarmonyPatch(nameof(GardenPlant.UpdateInfo))]
[HarmonyPostfix]
private static void UpdateInfo(GardenPlant __instance)
{
__instance.infoText = StringStore.TranslateText(__instance.infoText);
}
}
}

View file

@ -1,31 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
using TMPro;
using UnityEngine;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects
{
[HarmonyPatch(typeof(Help_))]
public class Help__Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(Help_.Start))]
private static void Start(Help_ __instance)
{
TMP_FontAsset fontAsset = FontStore.LoadTMPFont(Utils.Language.ToString());
Transform warningTransform = __instance.transform.GetChild(0);
Transform warningTextTransform = warningTransform.FindChild("文字");
Transform warningTextShadowTransform = warningTransform.FindChild("文字2");
Transform[] array = [warningTextTransform, warningTextShadowTransform];
for (int i = 0; i < array.Length; i++)
{
if (array[i] != null)
{
array[i].GetComponent<TextMeshProUGUI>().text = StringStore.TranslateText(array[i].GetComponent<TextMeshProUGUI>().text);
array[i].GetComponent<TextMeshProUGUI>().font = fontAsset;
}
}
}
}
}

View file

@ -1,16 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects
{
[HarmonyPatch(typeof(DY))]
public static class DY_Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(DY.Update))]
private static void Update(DY __instance)
{
__instance.TextMeshPro.text = StringStore.TranslateText(__instance.TextMeshPro.text);
}
}
}

View file

@ -1,17 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects
{
[HarmonyPatch(typeof(LanternUmbrella))]
public class LanternUmbrella_Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(LanternUmbrella.Update))]
private static void Update(LanternUmbrella __instance)
{
__instance.energyText = StringStore.TranslateText(__instance.energyText);
__instance.energyTextShadow = StringStore.TranslateText(__instance.energyTextShadow);
}
}
}

View file

@ -1,16 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects
{
[HarmonyPatch(typeof(MagnetBox))]
public class MagnetBox_Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(MagnetBox.Update))]
private static void Update(MagnetBox __instance)
{
StringStore.TranslateTextTransform(__instance.transform);
}
}
}

View file

@ -1,16 +0,0 @@
using HarmonyLib;
using PvZ_Fusion_Translator__BepInEx_.AssetStore;
namespace PvZ_Fusion_Translator__BepInEx_.Patches.GameObjects.MinorObjects
{
[HarmonyPatch(typeof(MagnetInterface))]
public class MagnetInterface_Patch
{
[HarmonyPostfix]
[HarmonyPatch(nameof(MagnetInterface.Update))]
private static void Update(MagnetInterface __instance)
{
StringStore.TranslateTextTransform(__instance.transform);
}
}
}

Some files were not shown because too many files have changed in this diff Show more