chore(unity): 固定Unity CLI Loop本地包并移除UnitySkills依赖

This commit is contained in:
Liubing\LB
2026-09-28 18:14:59 +08:00
parent 0eb43b2b40
commit c4ae02def9
952 changed files with 70137 additions and 11 deletions

View File

@@ -0,0 +1,204 @@
#if UNITY_EDITOR
#nullable enable
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace io.github.hatayama.uLoopMCP
{
public class SimulateKeyboardOverlay : MonoBehaviour
{
public const float CONTAINER_BACKGROUND_ALPHA = 0.8f;
private const float PRESS_DISPLAY_DURATION = 0.5f;
private const float FADE_DURATION = 0.2f;
private const int FONT_SIZE = 48;
private const int GLYPH_FONT_SIZE = 64;
private static readonly Color ContainerBackgroundColor = new Color(0.15f, 0.15f, 0.15f, CONTAINER_BACKGROUND_ALPHA);
[SerializeField] private GameObject _container = null!;
[SerializeField] private Image _containerImage = null!;
private readonly List<BadgeEntry> _badgePool = new();
private readonly List<string> _cachedKeyNames = new();
private readonly List<string> _displayKeys = new();
private void Awake()
{
Debug.Assert(_container != null, "_container must be assigned in prefab");
Debug.Assert(_containerImage != null, "_containerImage must be assigned in prefab");
// Prefab keeps preview badges for editor inspection, but runtime badges must start empty.
for (int i = _container!.transform.childCount - 1; i >= 0; i--)
{
DestroyImmediate(_container.transform.GetChild(i).gameObject);
}
_container.SetActive(false);
}
private void LateUpdate()
{
bool hasHeldKeys = SimulateKeyboardOverlayState.HeldKeys.Count > 0;
string? pressKey = SimulateKeyboardOverlayState.PressKey;
bool isPressHeld = SimulateKeyboardOverlayState.IsPressHeld;
float pressElapsedSinceRelease = 0f;
if (pressKey != null && !isPressHeld)
{
pressElapsedSinceRelease = Time.realtimeSinceStartup - SimulateKeyboardOverlayState.PressReleasedTime;
if (pressElapsedSinceRelease > PRESS_DISPLAY_DURATION + FADE_DURATION)
{
SimulateKeyboardOverlayState.ClearPress();
pressKey = null;
}
}
if (!hasHeldKeys && pressKey == null)
{
SetBadgeCount(0);
_container.SetActive(false);
return;
}
_displayKeys.Clear();
IReadOnlyList<string> heldKeys = SimulateKeyboardOverlayState.HeldKeys;
for (int i = 0; i < heldKeys.Count; i++)
{
_displayKeys.Add(heldKeys[i]);
}
if (pressKey != null && !_displayKeys.Contains(pressKey))
{
_displayKeys.Add(pressKey);
}
SetBadgeCount(_displayKeys.Count);
_container.SetActive(true);
float maxAlpha = 0f;
for (int i = 0; i < _displayKeys.Count; i++)
{
float alpha = GetBadgeAlpha(_displayKeys[i], pressKey, isPressHeld, pressElapsedSinceRelease);
UpdateBadge(_badgePool[i], i, _displayKeys[i], alpha);
if (alpha > maxAlpha)
{
maxAlpha = alpha;
}
}
_containerImage.color = new Color(
ContainerBackgroundColor.r,
ContainerBackgroundColor.g,
ContainerBackgroundColor.b,
ContainerBackgroundColor.a * maxAlpha);
}
private void SetBadgeCount(int count)
{
while (_badgePool.Count < count)
{
_badgePool.Add(CreateBadge());
_cachedKeyNames.Add("");
}
for (int i = 0; i < _badgePool.Count; i++)
{
_badgePool[i].Root.SetActive(i < count);
}
}
private BadgeEntry CreateBadge()
{
GameObject badge = new GameObject("KeyBadge");
badge.transform.SetParent(_container.transform, false);
badge.AddComponent<RectTransform>();
Image bg = badge.AddComponent<Image>();
bg.color = new Color(0f, 0f, 0f, 0f);
bg.raycastTarget = false;
LayoutElement layoutElement = badge.AddComponent<LayoutElement>();
GameObject textGo = new GameObject("KeyText");
textGo.transform.SetParent(badge.transform, false);
RectTransform textRect = textGo.AddComponent<RectTransform>();
textRect.anchorMin = Vector2.zero;
textRect.anchorMax = Vector2.one;
textRect.offsetMin = Vector2.zero;
textRect.offsetMax = Vector2.zero;
Text text = textGo.AddComponent<Text>();
text.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
text.fontSize = FONT_SIZE;
text.fontStyle = FontStyle.Bold;
text.color = Color.white;
text.alignment = TextAnchor.MiddleCenter;
text.horizontalOverflow = HorizontalWrapMode.Overflow;
text.raycastTarget = false;
// Thicken glyph strokes so Unicode symbols don't look too thin
Outline outline = textGo.AddComponent<Outline>();
outline.effectColor = Color.white;
outline.effectDistance = new Vector2(1f, -1f);
return new BadgeEntry(badge, bg, text, layoutElement);
}
private void UpdateBadge(BadgeEntry badge, int index, string keyName, float alpha)
{
badge.Text.color = new Color(1f, 1f, 1f, alpha);
if (_cachedKeyNames[index] == keyName)
{
return;
}
_cachedKeyNames[index] = keyName;
string symbol = KeySymbolMap.GetSymbol(keyName);
badge.Text.text = symbol;
badge.Text.fontSize = KeySymbolMap.IsGlyphSymbol(symbol) ? GLYPH_FONT_SIZE : FONT_SIZE;
TextGenerationSettings settings = badge.Text.GetGenerationSettings(new Vector2(float.MaxValue, float.MaxValue));
float preferredWidth = badge.Text.cachedTextGeneratorForLayout.GetPreferredWidth(symbol, settings);
float preferredHeight = badge.Text.cachedTextGeneratorForLayout.GetPreferredHeight(symbol, settings);
badge.Layout.preferredWidth = Mathf.Max(preferredWidth / badge.Text.pixelsPerUnit, preferredHeight / badge.Text.pixelsPerUnit);
badge.Layout.preferredHeight = preferredHeight / badge.Text.pixelsPerUnit;
}
private static float GetBadgeAlpha(
string keyName,
string? pressKey,
bool isPressHeld,
float pressElapsedSinceRelease)
{
if (pressKey == null || keyName != pressKey || isPressHeld || pressElapsedSinceRelease <= PRESS_DISPLAY_DURATION)
{
return 1f;
}
float fadeT = Mathf.Clamp01((pressElapsedSinceRelease - PRESS_DISPLAY_DURATION) / FADE_DURATION);
return 1f - fadeT;
}
private readonly struct BadgeEntry
{
public readonly GameObject Root;
public readonly Image Background;
public readonly Text Text;
public readonly LayoutElement Layout;
public BadgeEntry(GameObject root, Image background, Text text, LayoutElement layout)
{
Root = root;
Background = background;
Text = text;
Layout = layout;
}
}
}
}
#endif