Skip to content

Commit e364b0f

Browse files
feat: initial inventory rendering draft
1 parent 7fdba33 commit e364b0f

File tree

2,743 files changed

+18033
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,743 files changed

+18033
-4
lines changed

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"@tailwindcss/forms": "^0.5.10",
2626
"@tailwindcss/vite": "^4.1.16",
2727
"@vitest/browser": "^4.0.7",
28+
"clsx": "^2.1.1",
2829
"eslint": "^9.39.1",
2930
"eslint-config-prettier": "^10.1.8",
3031
"eslint-plugin-svelte": "^3.13.0",

scripts/Justfile

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ extract-precache-hgpak:
4949
@gum spin --spinner dot --title "Extracting..." -- ./out/hgpaktool ./PCBANKS/NMSARC.Precache.pak -O ./out/EXTRACTED
5050
@gum style --foreground 10 "✅ NMSARC.Precache.pak extracted."
5151

52+
extract-texui-hgpak:
53+
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "📦 HGPAK TexUI EXTRACTION"
54+
@gum spin --spinner dot --title "Extracting..." -- ./out/hgpaktool ./PCBANKS/NMSARC.TexUI.pak -O ./out/EXTRACTED
55+
@gum style --foreground 10 "✅ NMSARC.TexUI.pak extracted."
56+
5257
extract-locale: extract-metadata-hgpak
5358
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "📜 translations.json"
5459
@for f in ./out/EXTRACTED/language/*_usenglish.mbin; do \
@@ -57,35 +62,45 @@ extract-locale: extract-metadata-hgpak
5762
@gum spin --spinner dot --title "Extracting translations" -- python ./src/extract_translations.py
5863
@gum style --foreground 10 "✅ translations.json ready."
5964

60-
extract-items: extract-precache-hgpak extract-locale
65+
extract-item-name-mappings: extract-precache-hgpak extract-locale
6166
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "📜 item_to_name_mappings.json"
6267
@gum spin --spinner dot --title "Decoding nms_reality_gcproducttable.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/nms_reality_gcproducttable.mbin" > /dev/null;
6368
@gum spin --spinner dot --title "Decoding nms_basepartproducts.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/nms_basepartproducts.mbin" > /dev/null;
6469
@gum spin --spinner dot --title "Extracting item names" -- python ./src/extract_item_names.py
6570
@gum style --foreground 10 "✅ item_to_name_mappings.json created."
6671

72+
extract-items: extract-precache-hgpak extract-locale extract-texui-hgpak
73+
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "📜 items.json & item images"
74+
@gum spin --spinner dot --title "Decoding nms_reality_gcsubstancetable.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/nms_reality_gcsubstancetable.mbin" > /dev/null;
75+
@gum spin --spinner dot --title "Decoding nms_reality_gctechnologytable.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/nms_reality_gctechnologytable.mbin" > /dev/null;
76+
@gum spin --spinner dot --title "Decoding nms_reality_gcproceduraltechnologytable.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/nms_reality_gcproceduraltechnologytable.mbin" > /dev/null;
77+
@gum spin --spinner dot --title "Decoding proceduralproducttable.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/proceduralproducttable.mbin" > /dev/null;
78+
@gum spin --spinner dot --title "Extracting items" -- python ./src/extract_items.py
79+
@cp ./out/items.json ../src/data/items.json
80+
@npx prettier --write ../src/data/items.json --config ../.prettierrc > /dev/null
81+
@gum style --foreground 10 "✅ items.json & item images created."
6782
# ---------------------------------------------------------------------------
6883
# 🎁 REWARDS
6984
# ---------------------------------------------------------------------------
7085
extract-rewards: extract-season-rewards extract-twitch-rewards extract-platform-rewards
7186

72-
extract-season-rewards: extract-items
87+
extract-season-rewards: extract-item-name-mappings
7388
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "🎁 rewards/season.json"
7489
@gum spin --spinner dot --title "Decoding unlockableseasonrewards.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/unlockableseasonrewards.mbin" > /dev/null
7590
@gum spin --spinner dot --title "Extracting rewards" -- python ./src/extract_season_rewards.py
7691
@cp ./out/season_rewards.json ../src/data/rewards/season.json
7792
@npx prettier --write ../src/data/rewards/season.json --config ../.prettierrc > /dev/null
7893
@gum style --foreground 10 "✅ rewards/season.json created."
7994

80-
extract-twitch-rewards: extract-items
95+
extract-twitch-rewards: extract-item-name-mappings
8196
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "🎁 rewards/twitch.json"
8297
@gum spin --spinner dot --title "Decoding unlockabletwitchrewards.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/unlockabletwitchrewards.mbin" > /dev/null
8398
@gum spin --spinner dot --title "Extracting rewards" -- python ./src/extract_twitch_rewards.py
8499
@cp ./out/twitch_rewards.json ../src/data/rewards/twitch.json
85100
@npx prettier --write ../src/data/rewards/twitch.json --config ../.prettierrc > /dev/null
86101
@gum style --foreground 10 "✅ rewards/twitch.json created."
87102

88-
extract-platform-rewards: extract-items
103+
extract-platform-rewards: extract-item-name-mappings
89104
@gum style --border rounded --border-foreground 45 --margin "1 0 0 0" --padding "0 3" --width 80 --align left "🎁 rewards/platform.json"
90105
@gum spin --spinner dot --title "Decoding unlockableplatformrewards.mbin" -- ./out/mbincompiler -y -d ./out/ "./out/EXTRACTED/metadata/reality/tables/unlockableplatformrewards.mbin" > /dev/null
91106
@gum spin --spinner dot --title "Extracting rewards" -- python ./src/extract_platform_rewards.py

scripts/shell.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pkgs.mkShell {
1515
pkgs.jq
1616
pkgs.curl
1717
pkgs.python313
18+
pkgs.python313Packages.pillow
1819
pkgs.xmlstarlet
1920
];
2021

scripts/src/extract_items.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import xml.etree.ElementTree as ET
2+
import json
3+
import os
4+
from PIL import Image
5+
6+
xml_paths = [
7+
"./out/nms_reality_gcproducttable.MXML",
8+
"./out/nms_basepartproducts.MXML",
9+
"./out/nms_reality_gcsubstancetable.MXML",
10+
"./out/nms_reality_gctechnologytable.MXML",
11+
"./out/nms_reality_gcproceduraltechnologytable.MXML",
12+
"./out/proceduralproducttable.MXML"
13+
]
14+
translations_path = "./out/translations.json"
15+
output_json = "./out/items.json"
16+
17+
# Load translation strings
18+
with open(translations_path, "r", encoding="utf-8") as f:
19+
translations = json.load(f)
20+
21+
items = {}
22+
23+
def process_xml(xml_path):
24+
tree = ET.parse(xml_path)
25+
root = tree.getroot()
26+
27+
products = root.findall(".//Property[@value='GcProductData']")
28+
if(len(products) == 0):
29+
products = root.findall(".//Property[@value='GcRealitySubstanceData']")
30+
if(len(products) == 0):
31+
products = root.findall(".//Property[@value='GcProceduralTechnologyData']")
32+
if(len(products) == 0):
33+
products = root.findall(".//Property[@value='GcTechnology']")
34+
35+
print(len(products), "items found in", xml_path)
36+
37+
for product in products:
38+
prod_id = None
39+
name_lower_key = None
40+
texture_path = None
41+
42+
for prop in product.findall("Property"):
43+
if prop.get("name") == "ID":
44+
prod_id = prop.get("value")
45+
if prop.get("name") == "Subtitle" and "proceduralproducttable.MXML" in xml_path:
46+
name_lower_key = prop.get("value")
47+
if prop.get("name") == "NameLower":
48+
name_lower_key = prop.get("value")
49+
if prop.get("name") == "Template":
50+
template_value = prop.get("value")
51+
if template_value in items:
52+
texture_path = items[template_value]["texture"]
53+
if prop.get("name") == "Icon":
54+
icon_prop = prop.find("Property[@name='Filename']")
55+
if icon_prop is not None:
56+
texture_path = icon_prop.get("value").lower()
57+
if texture_path.startswith("textures/"):
58+
real_path = os.path.abspath(os.path.join(__file__, "../../out/EXTRACTED/", texture_path))
59+
target_path = os.path.abspath(os.path.join(__file__, "../../../static/nms/", texture_path))
60+
texture_path = "/nms/" + texture_path.replace(".dds", ".png")
61+
if "textures/ui/frontend/icons" in texture_path:
62+
if os.path.exists(real_path):
63+
if not os.path.exists(os.path.dirname(target_path)):
64+
os.makedirs(os.path.dirname(target_path), exist_ok=True)
65+
img = Image.open(real_path)
66+
img = img.resize((64, 64))
67+
img.save(target_path.replace(".dds", ".png"))
68+
else:
69+
texture_path = None
70+
else:
71+
texture_path = None
72+
73+
74+
if prod_id and name_lower_key:
75+
translated_value = translations.get(name_lower_key, name_lower_key)
76+
77+
items[prod_id] = {
78+
"name": translated_value,
79+
"texture": texture_path
80+
}
81+
82+
for path in xml_paths:
83+
process_xml(path)
84+
85+
with open(output_json, "w", encoding="utf-8") as f:
86+
json.dump(items, f, indent=4, ensure_ascii=False)
87+
88+
print(f"Saved {len(items)} combined entries to {output_json}")
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<script lang="ts">
2+
import type { JSONSaveData } from '$lib/json';
3+
import clsx from 'clsx';
4+
import itemData from '../../data/items.json';
5+
6+
type Props = {
7+
value: JSONSaveData;
8+
};
9+
10+
let { value = $bindable() }: Props = $props();
11+
12+
let size = $derived(value.Width * value.Height);
13+
</script>
14+
15+
<div class="grid w-full grid-cols-3 grid-rows-2 gap-px" style={`grid-template-columns: repeat(${value.Width}, minmax(0, 1fr)); grid-template-rows: repeat(${value.Height}, minmax(0, 1fr));`}>
16+
{#each Array.from({ length: size }, (_, i) => i) as index}
17+
{@const item = (value.Slots as { Index: { X: number; Y: number }; Id: string }[]).find((slot) => slot.Index.X + slot.Index.Y * value.Width === index)}
18+
{@const isSlotEnabled = (value.ValidSlotIndices as { X: number; Y: number }[]).some((slot) => slot.X + slot.Y * value.Width === index)}
19+
{@const isSlotSpecial = (value.SpecialSlots as { Index: { X: number; Y: number } }[]).some((slot) => slot.Index.X + slot.Index.Y * value.Width === index)}
20+
<div class={clsx('group relative flex aspect-square flex-col items-center justify-center gap-2 overflow-hidden px-3 py-2 text-gray-500', isSlotEnabled ? 'bg-white' : 'bg-gray-300', isSlotSpecial ? 'inset-ring-4 inset-ring-yellow-100' : '')}>
21+
{#if item}
22+
{@const itemMeta = itemData[item.Id.replaceAll('^', '').split('#')[0]] ?? { texture: '', name: item.Id }}
23+
<img class="aspect-square w-1/2" src={itemMeta.texture} alt="" />
24+
<p class="text-xs">{itemMeta.name}</p>
25+
<p class="text-xs">{item.Amount}/{item.MaxAmount}</p>
26+
{/if}
27+
</div>
28+
{/each}
29+
</div>

0 commit comments

Comments
 (0)