00671e7c0d
Клиент запрашивал звук, движок его принимал и запускал, а на выходе было тихо. Причина оказалась не в коде игры. Minecraft 1.12.2 не умеет читать ассеты по индексу и объектному хранилищу. Он ждёт обычное дерево: <assetsDir>/minecraft/<путь>. А лаунчер хранит ассеты по-современному — indexes/1.12.json со ссылками на objects/<aa>/<sha1>. Мы передавали лаунчеру корень этого хранилища как --assetsDir. Игре это не выглядит как поломка: язык и текстуры берутся из самого jar, поэтому клиент выглядит полностью рабочим. Но звуки с 1.7.3 лежат только в ассетах, и их просто не было на диске. Движок поднимался, play() вызывался, ogg не находился, а paulscode на это молчит. - materialize_assets.py разворачивает дерево из индекса и хранилища, жёсткими ссылками где возможно, и идемпотентен - run-game.ps1 материализует ассеты перед запуском и указывает клиенту на развёрнутое дерево; --assetIndex больше не нужен - проверено: 1305 объектов, из них 1085 ogg, sounds.json на месте, ошибок загрузки в логе нет Заодно убрана временная диагностика звука и движения, добавленная ради поиска причины: она доказала, что запрос и воспроизведение доходят до OpenAL, и свою задачу выполнила. Полный prepare-game.ps1 после этого проходит целиком: 112 патчей, FORK COMPILES CLEAN, 3268 классов, RsxDebug в дереве не осталось.
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Materialise a 1.12 asset tree out of a hash-addressed asset store.
|
|
|
|
Minecraft 1.12.2 does not read an index plus an object store. It reads
|
|
``<assetsDir>/minecraft/<path>`` directly. A launcher such as AstralRinth keeps
|
|
assets the modern way, as ``indexes/1.12.json`` pointing at
|
|
``objects/<aa>/<sha1>``, and a launcher that wants them for an old client is
|
|
responsible for laying them out.
|
|
|
|
Passing the store root as ``--assetsDir`` does not fail loudly. Texts and
|
|
textures still appear, because those live inside the client jar, so the game
|
|
looks correct while every sound is silently absent: nothing requested is ever
|
|
found on disk.
|
|
|
|
Usage:
|
|
materialize_assets.py <meta-assets-dir> <out-dir> [--index 1.12]
|
|
|
|
Hard links are used where the filesystem allows it, so the materialised tree
|
|
costs almost nothing and repeated runs are cheap.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
|
|
def human(count):
|
|
return "{:,}".format(count).replace(",", " ")
|
|
|
|
|
|
def main(argv):
|
|
ap = argparse.ArgumentParser(description=__doc__,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
ap.add_argument("meta_assets", help="store root holding indexes/ and objects/")
|
|
ap.add_argument("out", help="assets dir to create for the client")
|
|
ap.add_argument("--index", default="1.12", help="index file name (default: 1.12)")
|
|
args = ap.parse_args(argv)
|
|
|
|
meta = args.meta_assets
|
|
index_path = os.path.join(meta, "indexes", args.index + ".json")
|
|
if not os.path.isfile(index_path):
|
|
sys.exit("no asset index at " + index_path)
|
|
|
|
with open(index_path, "r", encoding="utf-8") as fh:
|
|
objects = json.load(fh)["objects"]
|
|
|
|
out = args.out
|
|
linked = copied = reused = 0
|
|
missing = []
|
|
|
|
for name, info in sorted(objects.items()):
|
|
digest = info["hash"]
|
|
src = os.path.join(meta, "objects", digest[:2], digest)
|
|
dst = os.path.join(out, *name.split("/"))
|
|
|
|
if os.path.isfile(src) and os.path.getsize(src) == info["size"]:
|
|
if os.path.exists(dst) and os.path.getsize(dst) == info["size"]:
|
|
reused += 1
|
|
continue
|
|
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
|
if os.path.exists(dst):
|
|
os.remove(dst)
|
|
try:
|
|
os.link(src, dst)
|
|
linked += 1
|
|
except OSError:
|
|
with open(src, "rb") as r, open(dst, "wb") as w:
|
|
w.write(r.read())
|
|
copied += 1
|
|
else:
|
|
missing.append(name)
|
|
|
|
sounds = sum(1 for n in objects if n.endswith(".ogg"))
|
|
print("index : {} ({} objects, {} ogg)".format(
|
|
os.path.join("indexes", args.index + ".json"), human(len(objects)), human(sounds)))
|
|
print("output : {}".format(out))
|
|
print("hardlink: {} copy: {} reused: {}".format(
|
|
human(linked), human(copied), human(reused)))
|
|
if missing:
|
|
print("MISSING : {} object(s) not in the store".format(human(len(missing))))
|
|
for name in missing[:10]:
|
|
print(" " + name)
|
|
return 1
|
|
print("ok : every indexed object is present")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main(sys.argv[1:])) |