Read manifest + stub load set button

This commit is contained in:
2026-07-15 15:09:14 +02:00
parent 8de9046929
commit 5cbc9d40d1
4 changed files with 107 additions and 1 deletions

View File

@@ -1,11 +1,13 @@
if "bpy" in locals():
import importlib
importlib.reload(globals)
importlib.reload(properties)
importlib.reload(operators)
importlib.reload(panels)
importlib.reload(preferences)
else:
from . import globals
from . import properties
from . import operators
from . import panels
from . import preferences
@@ -13,6 +15,7 @@ else:
import bpy
classes = (
*properties.classes,
*operators.classes,
*panels.classes,
preferences.D2ToolboxPreferences,
@@ -22,6 +25,8 @@ def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.d2toolbox = bpy.props.PointerProperty(type=properties.D2ToolboxProperties)
if globals.getManifest() is None and bpy.app.online_access:
try:
globals.fetchAndSaveManifest()
@@ -29,6 +34,8 @@ def register():
print(f"D2Toolbox: failed to fetch manifest on load: {e}")
def unregister():
del bpy.types.Scene.d2toolbox
for cls in reversed(classes):
bpy.utils.unregister_class(cls)

View File

@@ -23,7 +23,19 @@ class D2TOOLBOX_OT_refetch_manifest(bpy.types.Operator):
self.report({"INFO"}, "Manifest refreshed")
return {"FINISHED"}
class D2TOOLBOX_OT_load_set(bpy.types.Operator):
"""Load the selected armor set (stub)."""
bl_idname = "d2toolbox.load_set"
bl_label = "Load Set"
bl_options = {"REGISTER"}
def execute(self, context):
# Stub for now
self.report({"INFO"}, "Load Set (stub)")
return {"FINISHED"}
classes = (
D2TOOLBOX_OT_hello,
D2TOOLBOX_OT_refetch_manifest
D2TOOLBOX_OT_refetch_manifest,
D2TOOLBOX_OT_load_set
)

View File

@@ -17,6 +17,40 @@ class D2TOOLBOX_PT_main(bpy.types.Panel):
return
layout = self.layout
props = context.scene.d2toolbox
layout.label(text="Armor Set Loader")
layout.label(text="Class")
row = layout.row(align=True)
row.prop_enum(props, "d2_class", "hunter")
row.prop_enum(props, "d2_class", "warlock")
row.prop_enum(props, "d2_class", "titan")
layout.label(text="Sex")
row = layout.row(align=True)
row.prop_enum(props, "d2_sex", "male")
row.prop_enum(props, "d2_sex", "female")
ready = props.d2_class != "NONE" and props.d2_sex != "NONE"
col = layout.column()
col.enabled = ready # greyed out until Class + Sex chosen
col.prop(props, "slot_head")
col.prop(props, "slot_arms")
col.prop(props, "slot_chest")
col.prop(props, "slot_legs")
col.prop(props, "slot_class_item")
all_selected = ready and all(
getattr(props, a) != "NONE"
for a in ("slot_head", "slot_arms", "slot_chest", "slot_legs", "slot_class_item")
)
sub = layout.column()
sub.enabled = all_selected # greyed out until all 5 slots chosen
sub.operator("d2toolbox.load_set")
layout.separator()
layout.label(text="Miscellaneous")
layout.operator("d2toolbox.refetch_manifest")

53
d2toolbox/properties.py Normal file
View File

@@ -0,0 +1,53 @@
import bpy
from . import globals
# Blender garbage-collects strings returned by dynamic EnumProperty `items`
# callbacks unless a Python reference is kept. Cache each built list here,
# keyed by (class, sex), to keep them alive.
_armor_items_cache = {}
CLASS_ITEMS = [
("NONE", "", ""),
("hunter", "Hunter", ""),
("warlock", "Warlock", ""),
("titan", "Titan", ""),
]
SEX_ITEMS = [
("NONE", "", ""),
("male", "Male", ""),
("female", "Female", ""),
]
_SLOT_ATTRS = ("slot_head", "slot_arms", "slot_chest", "slot_legs", "slot_class_item")
def _armor_items(self, context):
key = (self.d2_class, self.d2_sex)
items = [("NONE", "— None —", "")]
if self.d2_class != "NONE" and self.d2_sex != "NONE":
manifest = globals.getManifest()
entries = (manifest.get(self.d2_class, {}).get(self.d2_sex, []) if manifest else []) or []
for i, entry in enumerate(entries):
name = entry.get("name", "Unknown")
season = entry.get("season", "")
label = f"{name} - {season}" if season else name
items.append((str(i), label, ""))
_armor_items_cache[key] = items
return items
def _reset_slots(self, context):
for attr in _SLOT_ATTRS:
self[attr] = 0 # index 0 == 'NONE'
class D2ToolboxProperties(bpy.types.PropertyGroup):
d2_class: bpy.props.EnumProperty(name="Class", items=CLASS_ITEMS, default="NONE", update=_reset_slots)
d2_sex: bpy.props.EnumProperty(name="Sex", items=SEX_ITEMS, default="NONE", update=_reset_slots)
slot_head: bpy.props.EnumProperty(name="Head", items=_armor_items)
slot_arms: bpy.props.EnumProperty(name="Arms", items=_armor_items)
slot_chest: bpy.props.EnumProperty(name="Chest", items=_armor_items)
slot_legs: bpy.props.EnumProperty(name="Legs", items=_armor_items)
slot_class_item: bpy.props.EnumProperty(name="Class Item", items=_armor_items)
classes = (
D2ToolboxProperties,
)