Add socketed items parsing

This commit is contained in:
2023-10-24 20:56:55 +02:00
parent c170241746
commit a48a833707
3 changed files with 37 additions and 18 deletions

View File

@@ -17,6 +17,7 @@
import json import json
import os import os
import re import re
from typing import Optional
from bitarray import bitarray from bitarray import bitarray
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum from enum import Enum
@@ -108,7 +109,7 @@ class Item:
defense: int | None = None defense: int | None = None
durability: int | None = None durability: int | None = None
max_durability: int | None = None max_durability: int | None = None
sockets: int | None = None sockets: list[Optional["Item"]] | None = None
quantity: int | None = None quantity: int | None = None
stats: list[Stat] | None = None stats: list[Stat] | None = None
@@ -157,8 +158,13 @@ class Item:
" " * indent, " " * indent,
f"Durability: {self.durability} out of {self.max_durability}", f"Durability: {self.durability} out of {self.max_durability}",
) )
if self.sockets: if self.is_socketed:
print(" " * indent, f"Num Sockets: {self.sockets}") print(" " * indent, f"{len(self.sockets)} sockets:")
for socket in self.sockets:
if socket:
socket.print(indent + 4)
else:
print(" " * (indent + 4), "Empty")
if self.quantity: if self.quantity:
print(" " * indent, f"Quantity: {self.quantity}") print(" " * indent, f"Quantity: {self.quantity}")
if self.stats: if self.stats:

View File

@@ -128,8 +128,7 @@ def parse_item(data: bytes) -> tuple[bytes, Item]:
code_end += 53 code_end += 53
# TODO: verify that this socket thing is really 1 bit for simple items...? # TODO: verify that this socket thing is really 1 bit for simple items...?
sockets_end = code_end + 1 if is_simple else code_end + 3 sockets_end = code_end + 1 if is_simple else code_end + 3
sockets_count = ba2int(bits[code_end:sockets_end]) filled_sockets = ba2int(bits[code_end:sockets_end])
print("sockets", sockets_count)
if is_ear: if is_ear:
raise UnsupportedItemError("Ear items are not supported") raise UnsupportedItemError("Ear items are not supported")
@@ -180,13 +179,28 @@ def parse_item(data: bytes) -> tuple[bytes, Item]:
item, itembase_end = parse_basetype_data(bits[personalized_end:], item) item, itembase_end = parse_basetype_data(bits[personalized_end:], item)
itembase_end += personalized_end itembase_end += personalized_end
item, enchantments_end = parse_enchantments(bits[itembase_end:], item) if item.is_socketed:
sockets_count = ba2int(bits[itembase_end : itembase_end + 4])
sockets_end = itembase_end + 4
else:
sockets_end = itembase_end
item, enchantments_end = parse_enchantments(bits[sockets_end:], item)
enchantments_end += itembase_end enchantments_end += itembase_end
extended_byte_size = int((enchantments_end + 7) / 8) extended_byte_size = int((enchantments_end + 7) / 8)
item.raw_data = data[:extended_byte_size] item.raw_data = data[:extended_byte_size]
return data[extended_byte_size:], item remaining_data = data[extended_byte_size:]
# Parse out sockets if any exist on the item
if item.is_socketed:
item.sockets = [None] * sockets_count
for i in range(0, filled_sockets):
remaining_data, socket = parse_item(remaining_data)
item.sockets[i] = socket
return remaining_data, item
def parse_item_graphic(bits: bitarray) -> tuple[int | None, int]: def parse_item_graphic(bits: bitarray) -> tuple[int | None, int]:
@@ -319,10 +333,6 @@ def parse_basetype_data(bits: bitarray, item: Item) -> tuple[Item, int]:
item.quantity = ba2int(bits[ptr : ptr + 9]) item.quantity = ba2int(bits[ptr : ptr + 9])
ptr += 9 ptr += 9
if item.is_socketed:
item.sockets = ba2int(bits[ptr : ptr + 4])
ptr += 4
return item, ptr return item, ptr

View File

@@ -68,7 +68,7 @@ class ParseItemTest(unittest.TestCase):
self.assertEqual(data, b"") self.assertEqual(data, b"")
self.assertEqual(item.quality, Quality.HIGH) self.assertEqual(item.quality, Quality.HIGH)
self.assertEqual(len(item.stats), 2) self.assertEqual(len(item.stats), 2)
self.assertEqual(item.sockets, 2) self.assertEqual(len(item.sockets), 2)
def test_ed_max(self): def test_ed_max(self):
# test bugfix for https://gitlab.com/omicron-oss/d2warehouse/-/issues/1 # test bugfix for https://gitlab.com/omicron-oss/d2warehouse/-/issues/1
@@ -81,21 +81,24 @@ class ParseItemTest(unittest.TestCase):
self.assertEqual(str(item.stats[0]), "+13% Enhanced Damage") self.assertEqual(str(item.stats[0]), "+13% Enhanced Damage")
self.assertEqual(str(item.stats[2]), "+2 to Maximum Damage") self.assertEqual(str(item.stats[2]), "+2 to Maximum Damage")
def test_runeworld_lore(self): def test_runeword_lore(self):
# Lore: Ort Sol # Lore: Ort Sol
data = bytes.fromhex( data = bytes.fromhex(
"1008800405c055c637f1073af4558697412981070881506049e87f005516fb134582ff1000a0003500e07cbb001000a0003504e07c9800" "1008800405c055c637f1073af4558697412981070881506049e87f005516fb134582ff1000a0003500e07cbb001000a0003504e07c9800"
) )
data, item = parse_item(data) data, item = parse_item(data)
# TODO: requires socket parsing self.assertEqual(data, b"")
# self.assertEqual(data, b"")
self.assertTrue(item.is_runeword) self.assertTrue(item.is_runeword)
self.assertEqual(item.sockets, 2) self.assertEqual(len(item.sockets), 2)
item.sockets[0].print()
item.sockets[1].print()
self.assertEqual(item.sockets[0].code, "r09")
self.assertEqual(item.sockets[1].code, "r12")
rw = lookup_runeword(item.runeword_id) rw = lookup_runeword(item.runeword_id)
self.assertEqual(rw["name"], "Lore") self.assertEqual(rw["name"], "Lore")
for stat in item.stats: for stat in item.stats:
print(str(stat)) print(str(stat))
self.assertEqual(str(item.stats[4]), "+1 to All Skills") # runeword stat self.assertEqual(str(item.stats[4]), "+1 to All Skills") # runeword stat
self.assertEqual(str(item.stats[2]), "+10 to Energy") # runeword stat self.assertEqual(str(item.stats[2]), "+10 to Energy") # runeword stat
# TODO: requires socket parsing # TODO: sol rune stat -- should it be in representation?
# self.assertEqual(str(item.stats[1]), "Lightning Resist 30%") # sol rune stat # self.assertEqual(str(item.sockets[1].stats[0]), "Lightning Resist 30%")