Files
mtgodot-poc/project/ui/ui_assets.gd
T

133 lines
4.6 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# UiAssets (P1) —— 解析 uiscript 里的图片路径(`.sub` / `.tga` / `.png` / `.jpg`)。
#
# 路径形如 `d:/ymir work/ui/public/middle_button_01.sub`。解析:
# 1) 去掉盘符前缀
# 2) 依次试: <assets>/<rel> · <assets>/<pack>/<rel>(散包目录)
# 3) `.sub` = 子图描述(title/image/left/top/right/bottom)→ 载入其 image + 裁剪成 AtlasTexture
# `.dds` 走 Metin2World.load_ddsC++ dxt 解码)运行时解成 Image。
extends RefCounted
static var _cache := {}
# DDS 运行时解码:走 Metin2World.load_ddsC++ 里的 dxt.cppDXT1/3/5 + BGRA8)。
# Godot 无原生运行时 DDS 解码,UI 里的 select.dds / 职业名图都得走这条路。
static func load_dds_image(path: String) -> Image:
if path == "" or not FileAccess.file_exists(path):
return null
if not ClassDB.class_exists("Metin2World"):
return null
# Metin2World is a Node, not RefCounted; a static reference never frees it.
# The decoder returns an independently owned Image, so release the helper
# after each decode (textures themselves remain cached by load_tex).
var helper: Object = ClassDB.instantiate("Metin2World")
var img = helper.call("load_dds", path)
helper.free()
return img if img is Image else null
static func load_tex(assets_root: String, vpath: String) -> Texture2D:
if vpath == "" or assets_root == "":
return null
var key := assets_root + "|" + vpath
if _cache.has(key):
return _cache[key]
var tex: Texture2D = _load_uncached(assets_root, vpath)
_cache[key] = tex
return tex
static func _strip_drive(p: String) -> String:
var s := p.replace("\\", "/")
if s.length() >= 2 and s[1] == ":":
s = s.substr(2)
return s.lstrip("/")
static func _resolve(assets_root: String, rel: String) -> String:
var direct := assets_root.path_join(rel)
if FileAccess.file_exists(direct):
return direct
# 散包:<assets>/<sub>/<rel>
var da := DirAccess.open(assets_root)
if da:
for sub in da.get_directories():
var cand := assets_root.path_join(sub).path_join(rel)
if FileAccess.file_exists(cand):
return cand
# 大小写不敏感兜底:<assets>/**/ymir work/ui/... —— 只按 basename 找
return ""
static func _load_uncached(assets_root: String, vpath: String) -> Texture2D:
var rel := _strip_drive(vpath)
var real := _resolve(assets_root, rel)
if real == "":
# 试把 .sub 换成 .tga / .png
for ext: String in [".tga", ".png", ".jpg"]:
real = _resolve(assets_root, rel.get_basename() + ext)
if real != "":
break
if real == "":
return null
if real.get_extension().to_lower() == "sub":
return _load_sub(real)
return _load_image_file(real)
static func _load_image_file(path: String) -> Texture2D:
# .sub 文件可能引用了未随当前资源包发布的共享贴图(例如 Public.tga)。
# 先做存在性检查,避免 headless/UI fallback 因缺失可选贴图刷错误日志。
if not FileAccess.file_exists(path):
return null
var ext := path.get_extension().to_lower()
if ext == "dds":
var di := load_dds_image(path)
return ImageTexture.create_from_image(di) if di != null else null
var img := Image.new()
if img.load(path) != OK:
return null
return ImageTexture.create_from_image(img)
static func _load_sub(path: String) -> Texture2D:
var txt := FileAccess.get_file_as_string(path)
var image_name := ""
var l := 0
var t := 0
var r := -1
var b := -1
for line in txt.split("\n"):
var parts := line.strip_edges().split(" ", false)
if parts.size() < 2:
continue
match parts[0]:
"image": image_name = parts[1].strip_edges().trim_prefix('"').trim_suffix('"')
"left": l = int(parts[1])
"top": t = int(parts[1])
"right": r = int(parts[1])
"bottom": b = int(parts[1])
if image_name == "":
return null
# Skill .sub files live below ui/skill/<job>, while their shared DDS
# lives in ui/. Search the containing directory and its parents.
var img_path := ""
var search_dir := path.get_base_dir()
for _i in 6:
for candidate in [image_name, image_name.get_basename() + ".tga",
image_name.get_basename() + ".png", image_name.get_basename() + ".dds"]:
var candidate_path := search_dir.path_join(candidate)
if FileAccess.file_exists(candidate_path):
img_path = candidate_path
break
if img_path != "":
break
var parent_dir := search_dir.get_base_dir()
if parent_dir == search_dir:
break
search_dir = parent_dir
if not FileAccess.file_exists(img_path):
return null
var base := _load_image_file(img_path)
if base == null:
return null
if r <= l or b <= t:
return base
var at := AtlasTexture.new()
at.atlas = base
at.region = Rect2(l, t, r - l, b - t)
return at