195 lines
5.8 KiB
C#
195 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using ModelRenderer.Scripts.Common;
|
|
using UnityEngine;
|
|
|
|
namespace PerfectWorld.Scripts.Managers
|
|
{
|
|
public static class IconAtlasProvider
|
|
{
|
|
private const string IconsFolder = "UI/Icons"; // under Resources
|
|
private const string IconListFileName = "iconlist_ivtrm"; // .txt
|
|
private const string IconAtlasTexName = "iconlist_ivtrm"; // .dds
|
|
|
|
private static readonly Dictionary<string, Sprite> _iconNameToSprite = new Dictionary<string, Sprite>(StringComparer.OrdinalIgnoreCase);
|
|
private static readonly Dictionary<int, string> _templateIdToIconName = new Dictionary<int, string>();
|
|
|
|
private static bool _initialized;
|
|
private static Texture2D _atlasTexture;
|
|
private static string _fallbackIconName = "unknown";
|
|
|
|
public static void EnsureInitialized()
|
|
{
|
|
if (_initialized) return;
|
|
_initialized = true;
|
|
try
|
|
{
|
|
LoadAtlasAndIcons();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"[IconAtlas] Failed to initialize: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
public static Sprite GetSpriteByIconName(string iconName)
|
|
{
|
|
EnsureInitialized();
|
|
if (string.IsNullOrEmpty(iconName)) return GetFallback();
|
|
if (_iconNameToSprite.TryGetValue(iconName, out var sprite) && sprite != null) return sprite;
|
|
iconName = Path.GetFileNameWithoutExtension(iconName);
|
|
if (_iconNameToSprite.TryGetValue(iconName, out sprite) && sprite != null) return sprite;
|
|
return GetFallback();
|
|
}
|
|
|
|
public static Sprite GetSpriteForTemplateId(int templateId)
|
|
{
|
|
EnsureInitialized();
|
|
if (templateId <= 0) return GetFallback();
|
|
|
|
if (_templateIdToIconName.TryGetValue(templateId, out var name))
|
|
{
|
|
var s = GetSpriteByIconName(name);
|
|
if (s != null) return s;
|
|
}
|
|
|
|
string guessed = GuessIconNameFromTemplateId(templateId);
|
|
if (!string.IsNullOrEmpty(guessed))
|
|
{
|
|
_templateIdToIconName[templateId] = guessed;
|
|
var s = GetSpriteByIconName(guessed);
|
|
if (s != null) return s;
|
|
}
|
|
|
|
return GetFallback();
|
|
}
|
|
|
|
private static void LoadAtlasAndIcons()
|
|
{
|
|
_atlasTexture = Resources.Load<Texture2D>($"{IconsFolder}/{IconAtlasTexName}");
|
|
if (_atlasTexture == null)
|
|
{
|
|
Debug.LogWarning($"[IconAtlas] Could not load atlas texture '{IconAtlasTexName}' from Resources/{IconsFolder}");
|
|
return;
|
|
}
|
|
|
|
var textAsset = Resources.Load<TextAsset>($"{IconsFolder}/{IconListFileName}");
|
|
if (textAsset == null)
|
|
{
|
|
Debug.LogWarning($"[IconAtlas] Could not load icon list '{IconListFileName}.txt' from Resources/{IconsFolder}");
|
|
return;
|
|
}
|
|
|
|
ParseIconListAndCreateSprites(textAsset.bytes, _atlasTexture);
|
|
}
|
|
|
|
private static void ParseIconListAndCreateSprites(byte[] rawBytes, Texture2D atlas)
|
|
{
|
|
if (rawBytes == null || rawBytes.Length == 0 || atlas == null) return;
|
|
|
|
string fullText = ByteToStringUtils.ByteArrayToCP936String(rawBytes);
|
|
if (string.IsNullOrEmpty(fullText))
|
|
{
|
|
fullText = Encoding.UTF8.GetString(rawBytes);
|
|
}
|
|
|
|
var lines = fullText.Replace("\r\n", "\n").Replace("\r", "\n").Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
|
if (lines.Length < 4)
|
|
{
|
|
Debug.LogWarning("[IconAtlas] icon list too short");
|
|
return;
|
|
}
|
|
|
|
int tileWidth = SafeParseInt(lines[0]);
|
|
int tileHeight = SafeParseInt(lines[1]);
|
|
int columns = SafeParseInt(lines[2]);
|
|
int count = SafeParseInt(lines[3]);
|
|
|
|
if (tileWidth <= 0 || tileHeight <= 0 || columns <= 0)
|
|
{
|
|
Debug.LogWarning($"[IconAtlas] Invalid header: w={tileWidth} h={tileHeight} cols={columns} count={count}");
|
|
return;
|
|
}
|
|
|
|
int created = 0;
|
|
for (int i = 4; i < lines.Length; i++)
|
|
{
|
|
string fileName = lines[i].Trim();
|
|
if (string.IsNullOrEmpty(fileName)) continue;
|
|
|
|
string nameNoExt = Path.GetFileNameWithoutExtension(fileName);
|
|
|
|
int index = i - 4;
|
|
int col = index % columns;
|
|
int row = index / columns;
|
|
|
|
int x = col * tileWidth;
|
|
int y = atlas.height - ((row + 1) * tileHeight);
|
|
if (y < 0) y = 0;
|
|
|
|
var rect = new Rect(x, y, tileWidth, tileHeight);
|
|
var pivot = new Vector2(0.5f, 0.5f);
|
|
|
|
try
|
|
{
|
|
var sprite = Sprite.Create(atlas, rect, pivot, 100.0f, 0, SpriteMeshType.FullRect);
|
|
_iconNameToSprite[nameNoExt] = sprite;
|
|
|
|
int tidPrefix = ExtractLeadingInt(nameNoExt);
|
|
if (tidPrefix > 0 && !_templateIdToIconName.ContainsKey(tidPrefix))
|
|
{
|
|
_templateIdToIconName[tidPrefix] = nameNoExt;
|
|
}
|
|
|
|
if (string.Equals(nameNoExt, "unknown", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_fallbackIconName = nameNoExt;
|
|
}
|
|
|
|
created++;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning($"[IconAtlas] Failed to create sprite for '{fileName}': {ex.Message}");
|
|
}
|
|
}
|
|
|
|
Debug.Log($"[IconAtlas] Loaded {created} sprites from atlas '{IconAtlasTexName}' ({atlas.width}x{atlas.height}), tile {tileWidth}x{tileHeight}, cols {columns}, listed {count}");
|
|
}
|
|
|
|
private static Sprite GetFallback()
|
|
{
|
|
if (string.IsNullOrEmpty(_fallbackIconName)) return null;
|
|
_iconNameToSprite.TryGetValue(_fallbackIconName, out var s);
|
|
return s;
|
|
}
|
|
|
|
private static int SafeParseInt(string s)
|
|
{
|
|
if (string.IsNullOrEmpty(s)) return 0;
|
|
if (int.TryParse(s.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var v)) return v;
|
|
if (int.TryParse(s.Trim(), out v)) return v;
|
|
return 0;
|
|
}
|
|
|
|
private static int ExtractLeadingInt(string s)
|
|
{
|
|
if (string.IsNullOrEmpty(s)) return 0;
|
|
int i = 0;
|
|
while (i < s.Length && char.IsDigit(s[i])) i++;
|
|
if (i == 0) return 0;
|
|
if (int.TryParse(s.Substring(0, i), NumberStyles.Integer, CultureInfo.InvariantCulture, out var v)) return v;
|
|
return 0;
|
|
}
|
|
|
|
private static string GuessIconNameFromTemplateId(int templateId)
|
|
{
|
|
string tidStr = templateId.ToString(CultureInfo.InvariantCulture);
|
|
return _iconNameToSprite.Keys.FirstOrDefault(k => k.StartsWith(tidStr, StringComparison.Ordinal));
|
|
}
|
|
}
|
|
} |