fixed # 修复头像框资源位置错误的BUG

This commit is contained in:
2026-10-20 11:49:44 +08:00
parent 2b0fca8828
commit 92a3944e43
20 changed files with 754 additions and 74 deletions
+2 -1
View File
@@ -44,7 +44,8 @@ def build(root, output):
files = {}
integration = root / "integrations/zhenxun"
for name in (
"__init__.py", "runtime.py", "commands.py", "requirements.txt",
"__init__.py", "runtime.py", "commands.py", "data_paths.py",
"requirements.txt",
):
files[name] = (integration / name).read_bytes()
files["_vendor/__init__.py"] = b'"""Private shared farm modules."""\n'
+1
View File
@@ -88,6 +88,7 @@ def export(root):
webgl_source = root / "src/farm_render/source_assets"
manifest = json.loads((webgl_source / "manifest.json").read_bytes())
metadata["pest"] = manifest["pest"]
metadata["panel"] = manifest["panel"]
entries = {path.relative_to(source).as_posix(): path for path in paths}
entries.update({name: webgl_source / name for name in manifest["images"]})
with ZipFile(output, "w", compression=ZIP_STORED) as bundle:
+89 -4
View File
@@ -8,10 +8,78 @@ import re
import sys
def panel_layout(environment):
prefab = next(
entry.asset for obj in environment.objects
if obj.type.name == 'AssetBundle'
for path, entry in obj.read().m_Container
if path.endswith('/webglpersioninfo.prefab')
)
nodes = {}
def visit(pointer, parent=None):
game_object = pointer.read()
components = [c.component for c in game_object.m_Component]
transform = next(c.read() for c in components
if c.type.name == 'RectTransform')
rect = [0, 0, 100, 100]
if parent is not None:
lo, hi = transform.m_AnchorMin, transform.m_AnchorMax
pivot, pos = transform.m_Pivot, transform.m_AnchoredPosition
w = parent[2] * (hi.x - lo.x) + transform.m_SizeDelta.x
h = parent[3] * (hi.y - lo.y) + transform.m_SizeDelta.y
rect = [
parent[0] + parent[2] * (lo.x + (hi.x-lo.x)*pivot.x)
+ pos.x - w*pivot.x,
parent[1] + parent[3] * (1-lo.y-(hi.y-lo.y)*pivot.y)
- pos.y - h*(1-pivot.y), w, h,
]
for component in components:
if component.type.name != 'MonoBehaviour':
continue
data = component.read_typetree()
if 'm_Sprite' in data or 'm_Text' in data:
nodes[game_object.m_Name] = {
'rect': rect, 'data': data,
}
for child in transform.m_Children:
visit(child.read().m_GameObject, rect)
visit(prefab)
sprites = []
sprite_ids = {}
for name in ('PersionInfoBG', 'HeadFrame', 'ExpBar', 'ExpProgress',
'GoldIcon', 'CouponIcon'):
node = nodes[name]
sprite_id = node['data']['m_Sprite']['m_PathID']
path = f'webgl/panel/{name}.png'
sprite_ids[sprite_id] = path
sprites.append({'name': name, 'sprite': path, 'rect': node['rect']})
fields = []
for node_name, field in (('NameT', 'name'), ('text', 'experience'),
('LevelT', 'level'), ('GoldT', 'point'),
('CouponT', 'vip_point')):
node = nodes[node_name]
color = node['data']['m_Color']
fields.append({
'field': field, 'rect': node['rect'],
'alignment': node['data']['m_FontData']['m_Alignment'],
'color': [round(color[c]*255) for c in ('r', 'g', 'b')],
})
return {
'reference_canvas': [1920, 1080],
'source_prefab': 'mainscene#WebGLPersionInfo',
'anchor': 'top_left', 'sprites': sprites,
'avatar': nodes['HeadIcon']['rect'], 'fields': fields,
}, sprite_ids
def extract(bundle, destination):
import UnityPy
from PIL import Image
environment = UnityPy.load(str(bundle))
panel, panel_ids = panel_layout(environment)
destination.mkdir(parents=True, exist_ok=True)
images = {}
for obj in environment.objects:
@@ -19,7 +87,9 @@ def extract(bundle, destination):
continue
sprite = obj.read()
name = sprite.m_Name
if re.fullmatch(r"pest\d+", name):
if obj.path_id in panel_ids:
path = panel_ids[obj.path_id]
elif re.fullmatch(r"pest\d+", name):
path = f"pest/{name}.png"
elif name in ("Icon_PlantSeed", "Icon_PlantWither"):
path = "webgl/" + (
@@ -28,9 +98,23 @@ def extract(bundle, destination):
else:
continue
image = sprite.image
full_size = (round(sprite.m_Rect.width), round(sprite.m_Rect.height))
if obj.path_id in panel_ids and image.size != full_size:
offset = sprite.m_RD.textureRectOffset
position = (round(offset.x),
full_size[1] - round(offset.y) - image.height)
if (min(position) < 0 or position[0]+image.width > full_size[0]
or position[1]+image.height > full_size[1]):
raise ValueError('Panel sprite exceeds its original canvas')
full = Image.new('RGBA', full_size)
full.paste(image, position)
image = full
if image.size != (round(sprite.m_Rect.width),
round(sprite.m_Rect.height)):
raise ValueError("Sprite extraction lost its full canvas")
raise ValueError(
f'Sprite extraction lost its full canvas: {name} '
f'{image.size} vs {sprite.m_Rect}'
)
target = destination / path
target.parent.mkdir(parents=True, exist_ok=True)
image.save(target)
@@ -38,8 +122,8 @@ def extract(bundle, destination):
"size": list(image.size),
"sha256": hashlib.sha256(target.read_bytes()).hexdigest(),
}
if len(images) != 40:
raise ValueError("Expected 38 pest frames and two common crop sprites")
if len(images) != 46:
raise ValueError("Expected 38 pests, two crop and six panel sprites")
manifest = {
"schema": 1,
"source_url": (
@@ -49,6 +133,7 @@ def extract(bundle, destination):
"source_sha256": hashlib.sha256(bundle.read_bytes()).hexdigest(),
"extractor": "UnityPy 1.25.4 Sprite.image; full sprite rect checked",
"images": images,
"panel": panel,
"pest": {
"frames": [f"pest/pest{i}.png" for i in range(1, 76, 2)],
"sample_rate": 24,