Feat: 场景视图mod,UI框架更换标题

This commit is contained in:
m0_75251201
2025-11-08 14:03:17 +08:00
parent 786025f720
commit 9b91218973
114 changed files with 2654 additions and 177 deletions

View File

@@ -10,63 +10,60 @@ namespace UIFrame
{
public class GameOriginMainMenuUI
{
public GameObject mainMenuContainer;
public Image? title;
public TMP_Text[]? allTexts;
public Sprite titleSprite;
public bool linkMainMenu=false;
// public SpriteRenderer? title;
// public TMP_Text[]? allTexts;
public static Sprite? titleSprite=null;
public void Initialize()
{
SceneLoader.onAfterSceneInitialize += OnAfterSceneInitialize;
}
public void Cleanup()
{
SceneLoader.onAfterSceneInitialize -= OnAfterSceneInitialize;
}
// public void Initialize()
// {
// SceneManager.sceneLoaded += OnSceneLoaded;
// // SceneLoader.onAfterSceneInitialize += OnAfterSceneInitialize;
// LinkMainMenuObj();
// }
//
// public void Cleanup()
// {
// SceneManager.sceneLoaded -= OnSceneLoaded;
// // SceneLoader.onAfterSceneInitialize -= OnAfterSceneInitialize;
// }
//
// private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
// {
// Debug.Log("Loading game origin main menu...");
// LinkMainMenuObj();
// }
// // private void OnAfterSceneInitialize(SceneLoadingContext sceneLoadingContext)
// // {
// //
// // }
//
// public void LinkMainMenuObj()
// {
// var logoObj=GameObjectTool.FindObjectByPath("TimelineContent/LOGO/Logo");
// title = logoObj?.GetComponent<SpriteRenderer>();
// }
private void OnAfterSceneInitialize(SceneLoadingContext sceneLoadingContext)
{
linkMainMenu = false;
LinkMainMenuObj();
}
public void LinkMainMenuObj()
{
mainMenuContainer = GameObject.Find("MainMenuContainer");
if(!mainMenuContainer)
{
Debug.LogWarning("Could not find Main Menu Container");
return;
}
Debug.Log("Main Menu Container initialized");
allTexts = mainMenuContainer.GetComponentsInChildren<TMP_Text>();
title = GameObjectTool.FindChildByName(mainMenuContainer.transform, "MainTitle")?.GetComponent<Image>();
linkMainMenu = true;
}
public bool SetFont(TMP_FontAsset font)
{
if(allTexts == null || allTexts.Length == 0)
return false;
foreach (var text in allTexts)
{
text.font = font;
}
return true;
}
// public bool SetFont(TMP_FontAsset font)
// {
// if(allTexts == null || allTexts.Length == 0)
// return false;
// foreach (var text in allTexts)
// {
// text.font = font;
// }
// return true;
// }
public bool SetTitle(Sprite texture)
{
titleSprite=texture;
if(title==null)
return false;
title.sprite = texture;
// Debug.Log("Setting title...");
titleSprite = texture;
// if(title==null)
// {
// return false;
// }
// title.sprite = texture;
return true;
}
}

View File

@@ -5,6 +5,7 @@ using Duckov.UI;
using Duckov.UI.Animations;
using Duckov.Utilities;
using HarmonyLib;
using SodaCraft.Localizations;
using UnityEngine;
namespace UIFrame
@@ -16,7 +17,11 @@ namespace UIFrame
private GameObject? workerObject;
private Harmony? harmony;
private void Start()
{
}
protected override void OnAfterSetup()
{
CreateAPIObject();
@@ -31,6 +36,7 @@ namespace UIFrame
protected override void OnBeforeDeactivate()
{
ClearAPIObject();
harmony?.UnpatchAll(MOD_ID);
harmony = null;

View File

@@ -1,15 +0,0 @@
using UnityEngine;
namespace UIFrame.Patch
{
[HarmonyLib.HarmonyPatch(typeof(SceneLoader), "LoadMainMenu")]
public class PatchSceneLoaderLoadMainMenu
{
public static void Postfix()
{
Debug.Log("LoadMainMenu called");
}
}
}

View File

@@ -0,0 +1,34 @@
using HarmonyLib;
using SodaCraft.Localizations;
using System.Reflection;
using UnityEngine;
namespace UIFrame.Patch
{
[HarmonyPatch(typeof(SpriteRendererLocalizor), "Refresh")]
public class PatchSpriteRendererLocalizorRefresh
{
private static FieldInfo spriteRendererField = AccessTools.Field(typeof(SpriteRendererLocalizor), "spriteRenderer");
public static void Postfix(SpriteRendererLocalizor __instance)
{
if (GameOriginMainMenuUI.titleSprite != null && spriteRendererField != null)
{
SpriteRenderer targetSpriteRenderer = spriteRendererField.GetValue(__instance) as SpriteRenderer;
if (targetSpriteRenderer != null)
{
targetSpriteRenderer.sprite = GameOriginMainMenuUI.titleSprite;
}
else
{
UnityEngine.Debug.LogWarning($"Harmony Patch: Failed to get SpriteRenderer from {__instance.gameObject.name} (SpriteRendererLocalizor component)'s spriteRenderer field. Value was null or not a SpriteRenderer.");
}
} else if (GameOriginMainMenuUI.titleSprite == null) {
UnityEngine.Debug.LogWarning("Harmony Patch: GameOriginMainMenuUI.titleSprite is null, skipping sprite assignment.");
} else if (spriteRendererField == null){
UnityEngine.Debug.LogError("Harmony Patch: Failed to find 'spriteRenderer' field in SpriteRendererLocalizor. Is the field name correct or has it changed?");
}
}
}
}

View File

@@ -17,6 +17,9 @@
<Reference Include="$(DuckovPath)\Duckov_Data\Managed\ItemStatsSystem.dll" Private="False" />
<Reference Include="$(DuckovPath)\Duckov_Data\Managed\Unity*" Private="False" />
<Reference Include="$(DuckovPath)\Duckov_Data\Managed\FMODUnity.dll" Private="False" />
<Reference Include="SodaLocalization">
<HintPath>..\..\..\steam\steamapps\common\Escape from Duckov\Duckov_Data\Managed\SodaLocalization.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lib.Harmony" Version="2.4.1" />

View File

@@ -38,13 +38,14 @@ namespace UIFrame
{
return false;
}
return _apiComponent&&_apiComponent.SetTitleImage(texture);
}
/// <summary>
/// 设置标题图片(游戏中的标题是图片
/// 设置标题图片(游戏中的启动界面Logo
/// </summary>
/// <param name="sprite">贴图</param>
/// <returns></returns>
/// <returns>返回false表示函数调用时设置失败之后会自动再次尝试设置</returns>
public static bool SetGameTitle(Sprite sprite)
{
return _apiComponent&&_apiComponent.SetTitleImage(sprite);

View File

@@ -5,16 +5,16 @@ namespace UIFrameAPI
{
public abstract class UIFrameAPIComponent:MonoBehaviour
{
public abstract bool CreateCanvas(string name);
// public abstract bool CreateCanvas(string name);
//设置游戏主菜单的原版标题
public abstract bool SetTitleImage(Sprite sprite);
//创建一个TMP字体
public abstract TMP_FontAsset CreateFontAsset(string fontFilePath);
//设置游戏字体
public abstract bool SetFont(TMP_FontAsset font);
// //创建一个TMP字体
// public abstract TMP_FontAsset CreateFontAsset(string fontFilePath);
//
// //设置游戏字体
// public abstract bool SetFont(TMP_FontAsset font);
public abstract Texture2D? LoadTexture(string imageFilePath);
}

View File

@@ -14,21 +14,16 @@ namespace UIFrame
public Dictionary<string, Canvas> canvasDic = new Dictionary<string, Canvas>();
private void Awake()
{
gameOriginMainMenuUI.Initialize();
}
private void OnDestroy()
{
gameOriginMainMenuUI.Cleanup();
}
public override bool CreateCanvas(string name)
{
return false;
}
// private void Awake()
// {
// gameOriginMainMenuUI.Initialize();
// }
//
// private void OnDestroy()
// {
// gameOriginMainMenuUI.Cleanup();
// }
public override bool SetTitleImage(Sprite sprite)
{
@@ -36,26 +31,26 @@ namespace UIFrame
}
public override TMP_FontAsset CreateFontAsset(string fontFilePath)
{
var font = Font.CreateDynamicFontFromOSFont(fontFilePath, 24);
var tmpFont = TMP_FontAsset.CreateFontAsset(
font,
samplingPointSize: 72, // 采样点大小,影响字体质量
atlasPadding: 4, // 图集内字符间距
renderMode: GlyphRenderMode.SDFAA, // 推荐使用 SDF 抗锯齿模式
atlasWidth: 1024, // 图集宽度 (2的幂)
atlasHeight: 1024, // 图集高度 (2的幂)
atlasPopulationMode: AtlasPopulationMode.Dynamic, // 动态填充
enableMultiAtlasSupport: true // 启用多图集支持
);
return tmpFont;
}
// public override TMP_FontAsset CreateFontAsset(string fontFilePath)
// {
// var font = Font.CreateDynamicFontFromOSFont(fontFilePath, 24);
// var tmpFont = TMP_FontAsset.CreateFontAsset(
// font,
// samplingPointSize: 72, // 采样点大小,影响字体质量
// atlasPadding: 4, // 图集内字符间距
// renderMode: GlyphRenderMode.SDFAA, // 推荐使用 SDF 抗锯齿模式
// atlasWidth: 1024, // 图集宽度 (2的幂)
// atlasHeight: 1024, // 图集高度 (2的幂)
// atlasPopulationMode: AtlasPopulationMode.Dynamic, // 动态填充
// enableMultiAtlasSupport: true // 启用多图集支持
// );
// return tmpFont;
// }
public override bool SetFont(TMP_FontAsset font)
{
return gameOriginMainMenuUI.SetFont(font);
}
// public override bool SetFont(TMP_FontAsset font)
// {
// return gameOriginMainMenuUI.SetFont(font);
// }
public override Texture2D? LoadTexture(string imageFilePath)
{

View File

@@ -1,66 +1,76 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace UIFrame.Utilities
{
public class GameObjectTool
{
/// <summary>
/// 在指定父对象下查找第一个匹配名称的子GameObject可以是孙子、曾孙等
/// 根据Unity对象路径查找场景中的GameObject包括隐藏非激活对象。
/// 路径示例:"RootObject/ChildObject/GrandchildObject"
/// </summary>
/// <param name="parent">要查找的父Transform。</param>
/// <param name="name">要查找的GameObject的名称。</param>
/// <param name="path">要查找的GameObject的层级路径。</param>
/// <returns>找到的GameObject如果未找到则返回null。</returns>
public static GameObject? FindChildByName(Transform parent, string name)
public static GameObject FindObjectByPath(string path)
{
// 查找父对象本身是否就是目标对象
if (parent.name.Equals(name))
if (string.IsNullOrWhiteSpace(path))
{
return parent.gameObject;
Debug.LogWarning("FindObjectByPath: Provided path is null, empty, or whitespace. Returning null.");
return null;
}
// 遍历所有直接子对象
foreach (Transform child in parent)
string[] pathParts = path.Split(new char[] { '/' }, System.StringSplitOptions.RemoveEmptyEntries);
// 如果路径分割后没有有效部分(例如:"/" 或空字符串则直接返回null
if (pathParts.Length == 0)
{
// 检查当前子对象是否是目标对象
if (child.name.Equals(name))
Debug.LogWarning(
$"FindObjectByPath: Path '{path}' resulted in no valid segments after splitting. Returning null.");
return null;
}
GameObject currentObject = null;
// GetRootGameObjects() 会返回场景中所有根级别的GameObject无论它们是否激活。
Scene activeScene = SceneManager.GetActiveScene();
GameObject[] rootGameObjects = activeScene.GetRootGameObjects();
foreach (GameObject rootObj in rootGameObjects)
{
if (rootObj.name == pathParts[0])
{
return child.gameObject;
}
// 递归查找子对象的子对象
var found = FindChildByName(child, name);
if (found)
{
return found;
currentObject = rootObj;
break;
}
}
return null;
}
/// <summary>
/// 在指定父对象下查找所有匹配名称的子GameObject可以是孙子、曾孙等不区分大小写。
/// </summary>
/// <param name="parent">要查找的父Transform。</param>
/// <param name="name">要查找的GameObject的名称。</param>
/// <returns>所有找到的GameObject列表。</returns>
public static List<GameObject> FindChildrenByName(Transform parent, string name)
{
var foundObjects = new List<GameObject>();
FindChildrenByNameRecursive(parent, name, foundObjects);
return foundObjects;
}
private static void FindChildrenByNameRecursive(Transform currentTransform, string name, List<GameObject> foundObjects)
{
// 检查当前对象是否是目标对象
if (currentTransform.name.Equals(name))
// 如果根对象未找到,则路径无效
if (currentObject == null)
{
foundObjects.Add(currentTransform.gameObject);
Debug.LogWarning($"FindObjectByPath: Root object '{pathParts[0]}' not found in the active scene. Returning null.");
return null;
}
// 遍历所有子对象并递归查找
foreach (Transform child in currentTransform)
for (int i = 1; i < pathParts.Length; i++)
{
FindChildrenByNameRecursive(child, name, foundObjects);
if (currentObject == null)
{
Debug.LogError(
$"FindObjectByPath: Unexpected null currentObject while traversing path segment '{pathParts[i]}'. This indicates an internal logic error.");
return null;
}
// transform.Find() 能够查找包括非激活状态的子对象
Transform childTransform = currentObject.transform.Find(pathParts[i]);
if (childTransform == null)
{
Debug.LogWarning($"FindObjectByPath: Child object '{pathParts[i]}' not found under '{currentObject.name}'. Path invalid. Returning null.");
return null;
}
currentObject = childTransform.gameObject;
}
return currentObject;
}
}
}

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("UIFrame")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0206a83f56b5a794fe2f173b4a047cc4f0d4cd90")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+786025f720c05ae486c8c66d3a6114633ccd0dbf")]
[assembly: System.Reflection.AssemblyProductAttribute("UIFrame")]
[assembly: System.Reflection.AssemblyTitleAttribute("UIFrame")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
befe5a7453194406b1676f68d219a8c86bdf2f4cea49adddbaad5a1bb5006b5d
911460e450d98a36d352c39840be04d55f4d5ae8227da097050ab185b491cbc7

View File

@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("UIFrame")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+5d69efbc3f80a5422cef0884e02fb27adf20b467")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+786025f720c05ae486c8c66d3a6114633ccd0dbf")]
[assembly: System.Reflection.AssemblyProductAttribute("UIFrame")]
[assembly: System.Reflection.AssemblyTitleAttribute("UIFrame")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]

View File

@@ -1 +1 @@
2fde23c3fee254f6fc8f4689686f8631f1cec9f5b900327d5b657c6830a03267
d9927e767d78bd001547a17de1674f3773a1c4e78cf329975757d4b609c6bada

View File

@@ -1 +1 @@
8df4ddcbe4b7016ad51bf9e0b9ea8b606b36f4d0bbae7f1650b893a49036873e
0ee34f07c3de41359bb7fcfd63f21e2bd997731e7e65df6cde5e62762235bbce

View File

@@ -5,3 +5,4 @@ D:\vs_project\DuckovMods\UIFrame\obj\Release\UIFrame.AssemblyInfoInputs.cache
D:\vs_project\DuckovMods\UIFrame\obj\Release\UIFrame.AssemblyInfo.cs
D:\vs_project\DuckovMods\UIFrame\obj\Release\UIFrame.csproj.CoreCompileInputs.cache
D:\vs_project\DuckovMods\UIFrame\obj\Release\UIFrame.dll
D:\vs_project\DuckovMods\UIFrame\obj\Release\UIFrame.csproj.Up2Date

Binary file not shown.

View File

@@ -1 +1 @@
17620796287866771
17623343068138064