Add: armor plates support with new database tables and loadout functionality
fix: only required mods are applied to guns for weight management.
This commit is contained in:
125
import_gear.py
125
import_gear.py
@@ -64,6 +64,14 @@ GRAPHQL_QUERY_GEAR = """
|
||||
durability
|
||||
material { name }
|
||||
zones
|
||||
armorSlots {
|
||||
__typename
|
||||
... on ItemArmorSlotOpen {
|
||||
nameId
|
||||
zones
|
||||
allowedPlates { id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,6 +120,26 @@ GRAPHQL_QUERY_GEAR = """
|
||||
class
|
||||
durability
|
||||
zones
|
||||
armorSlots {
|
||||
__typename
|
||||
... on ItemArmorSlotOpen {
|
||||
nameId
|
||||
zones
|
||||
allowedPlates { id }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plates: items(types: [armorPlate]) {
|
||||
id name shortName weight gridImageLink wikiLink
|
||||
properties {
|
||||
... on ItemPropertiesArmorAttachment {
|
||||
class
|
||||
durability
|
||||
material { name }
|
||||
zones
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,6 +239,7 @@ def import_weapons(conn, weapons):
|
||||
def import_armor(conn, items):
|
||||
cursor = conn.cursor()
|
||||
counts = {"inserted": 0, "updated": 0, "skipped": 0}
|
||||
slot_data = {} # carrier_id -> armorSlots list
|
||||
for item in items:
|
||||
item_id = item.get("id")
|
||||
name = item.get("name")
|
||||
@@ -229,8 +258,11 @@ def import_armor(conn, items):
|
||||
zones=zones,
|
||||
)
|
||||
counts[result] += 1
|
||||
armor_slots = props.get("armorSlots") or []
|
||||
if armor_slots:
|
||||
slot_data[item_id] = armor_slots
|
||||
conn.commit()
|
||||
return counts
|
||||
return counts, slot_data
|
||||
|
||||
|
||||
def import_helmets(conn, items):
|
||||
@@ -291,6 +323,7 @@ def import_backpacks(conn, items):
|
||||
def import_rigs(conn, items):
|
||||
cursor = conn.cursor()
|
||||
counts = {"inserted": 0, "updated": 0, "skipped": 0}
|
||||
slot_data = {} # carrier_id -> armorSlots list
|
||||
for item in items:
|
||||
item_id = item.get("id")
|
||||
name = item.get("name")
|
||||
@@ -308,10 +341,75 @@ def import_rigs(conn, items):
|
||||
zones=zones,
|
||||
)
|
||||
counts[result] += 1
|
||||
armor_slots = props.get("armorSlots") or []
|
||||
if armor_slots:
|
||||
slot_data[item_id] = armor_slots
|
||||
conn.commit()
|
||||
return counts, slot_data
|
||||
|
||||
|
||||
def import_plates(conn, items):
|
||||
cursor = conn.cursor()
|
||||
counts = {"inserted": 0, "updated": 0, "skipped": 0}
|
||||
for item in items:
|
||||
item_id = item.get("id")
|
||||
name = item.get("name")
|
||||
if not item_id or not name:
|
||||
counts["skipped"] += 1
|
||||
continue
|
||||
props = item.get("properties") or {}
|
||||
material = (props.get("material") or {}).get("name")
|
||||
zones = ",".join(props.get("zones") or []) or None
|
||||
result = upsert_item(
|
||||
cursor, item_id, name, item.get("shortName"), "plate", item.get("weight"),
|
||||
item.get("gridImageLink"), item.get("wikiLink"),
|
||||
armor_class=props.get("class"),
|
||||
durability=props.get("durability"),
|
||||
material=material,
|
||||
zones=zones,
|
||||
)
|
||||
counts[result] += 1
|
||||
conn.commit()
|
||||
return counts
|
||||
|
||||
|
||||
def import_armor_open_slots(conn, carrier_id, armor_slots):
|
||||
"""
|
||||
Insert open plate slots and their compatible plates for a carrier item.
|
||||
armor_slots: list of armorSlots from the API (only ItemArmorSlotOpen are relevant).
|
||||
"""
|
||||
cursor = conn.cursor()
|
||||
slot_count = 0
|
||||
plate_count = 0
|
||||
# Build set of known item IDs for fast lookup
|
||||
known_ids = {row[0] for row in cursor.execute("SELECT id FROM gear_items").fetchall()}
|
||||
|
||||
for slot in armor_slots:
|
||||
if slot.get("__typename") != "ItemArmorSlotOpen":
|
||||
continue
|
||||
slot_nameid = slot.get("nameId")
|
||||
if not slot_nameid:
|
||||
continue
|
||||
zones = ",".join(slot.get("zones") or []) or None
|
||||
cursor.execute("""
|
||||
INSERT OR REPLACE INTO armor_open_slots (carrier_id, slot_nameid, zones)
|
||||
VALUES (?, ?, ?)
|
||||
""", (carrier_id, slot_nameid, zones))
|
||||
slot_count += 1
|
||||
|
||||
for plate in (slot.get("allowedPlates") or []):
|
||||
plate_id = plate.get("id")
|
||||
if not plate_id or plate_id not in known_ids:
|
||||
continue
|
||||
cursor.execute("""
|
||||
INSERT OR IGNORE INTO armor_slot_plates (carrier_id, slot_nameid, plate_id)
|
||||
VALUES (?, ?, ?)
|
||||
""", (carrier_id, slot_nameid, plate_id))
|
||||
plate_count += 1
|
||||
|
||||
return slot_count, plate_count
|
||||
|
||||
|
||||
def import_suppressors(conn, items):
|
||||
cursor = conn.cursor()
|
||||
counts = {"inserted": 0, "updated": 0, "skipped": 0}
|
||||
@@ -438,6 +536,7 @@ def main():
|
||||
rigs = gear_data.get("rigs", [])
|
||||
suppressors = gear_data.get("suppressors", [])
|
||||
mods = gear_data.get("mods", [])
|
||||
plates = gear_data.get("plates", [])
|
||||
|
||||
# Wearables: only keep those whose properties resolved to ItemPropertiesHelmet
|
||||
# (i.e. they have 'class' or 'headZones' set — not decorative items)
|
||||
@@ -451,7 +550,8 @@ def main():
|
||||
and (w["properties"].get("class") or w["properties"].get("headZones"))
|
||||
]
|
||||
print(f" armor={len(armor)}, helmets={len(helmets)}, wearable_helmets={len(wearable_helmets)}, "
|
||||
f"backpacks={len(backpacks)}, rigs={len(rigs)}, suppressors={len(suppressors)}, mods={len(mods)}")
|
||||
f"backpacks={len(backpacks)}, rigs={len(rigs)}, suppressors={len(suppressors)}, "
|
||||
f"mods={len(mods)}, plates={len(plates)})")
|
||||
|
||||
# Phase 2: insert into DB
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
@@ -462,8 +562,12 @@ def main():
|
||||
wcounts, slot_data = import_weapons(conn, weapons)
|
||||
print(f" guns: +{wcounts['inserted']} inserted, ~{wcounts['updated']} updated, -{wcounts['skipped']} skipped")
|
||||
|
||||
print("Importing plates (armorPlate items)...")
|
||||
c = import_plates(conn, plates)
|
||||
print(f" plates: +{c['inserted']} inserted, ~{c['updated']} updated, -{c['skipped']} skipped")
|
||||
|
||||
print("Importing armor...")
|
||||
c = import_armor(conn, armor)
|
||||
c, armor_slot_data = import_armor(conn, armor)
|
||||
print(f" armor: +{c['inserted']} inserted, ~{c['updated']} updated, -{c['skipped']} skipped")
|
||||
|
||||
print("Importing helmets...")
|
||||
@@ -479,7 +583,7 @@ def main():
|
||||
print(f" backpacks: +{c['inserted']} inserted, ~{c['updated']} updated, -{c['skipped']} skipped")
|
||||
|
||||
print("Importing rigs...")
|
||||
c = import_rigs(conn, rigs)
|
||||
c, rig_slot_data = import_rigs(conn, rigs)
|
||||
print(f" rigs: +{c['inserted']} inserted, ~{c['updated']} updated, -{c['skipped']} skipped")
|
||||
|
||||
print("Importing suppressors...")
|
||||
@@ -496,6 +600,19 @@ def main():
|
||||
print(f" gun_slots: {slots_ins} rows")
|
||||
print(f" gun_slot_items: {slot_items_ins} rows inserted, {slot_items_skip} skipped (item not in DB)")
|
||||
|
||||
# Phase 3b: armor open slots (needs plates in DB first)
|
||||
print("Importing armor open plate slots...")
|
||||
total_open_slots = 0
|
||||
total_plate_links = 0
|
||||
all_carrier_slots = {**armor_slot_data, **rig_slot_data}
|
||||
for carrier_id, armor_slots in all_carrier_slots.items():
|
||||
sc, pc = import_armor_open_slots(conn, carrier_id, armor_slots)
|
||||
total_open_slots += sc
|
||||
total_plate_links += pc
|
||||
conn.commit()
|
||||
print(f" armor_open_slots: {total_open_slots} rows")
|
||||
print(f" armor_slot_plates: {total_plate_links} rows")
|
||||
|
||||
# Phase 4: classify mod_type for mods based on which slots they appear in
|
||||
print("Classifying mod types from slot data...")
|
||||
cursor = conn.cursor()
|
||||
|
||||
Reference in New Issue
Block a user