fix: add safe decimal conversion to armor_system from_dict methods

- ProtectionProfile.from_dict now handles int/float/Decimal/string values
- ArmorPlate.from_dict uses safe_decimal for block_chance
- ArmorPiece.from_dict uses safe_decimal for decay_per_hp and weight
- Prevents 'Decimal + str' type errors when loading saved loadouts
This commit is contained in:
LemonNexus 2026-02-09 19:33:05 +00:00
parent a0211a8425
commit ff2ae329c1
1 changed files with 43 additions and 15 deletions

View File

@ -117,18 +117,27 @@ class ProtectionProfile:
}
@classmethod
def from_dict(cls, data: Dict[str, str]) -> "ProtectionProfile":
"""Create from dictionary."""
def from_dict(cls, data: Dict[str, Any]) -> "ProtectionProfile":
"""Create from dictionary with validation."""
def safe_decimal(val):
if isinstance(val, Decimal):
return val
if isinstance(val, (int, float)):
return Decimal(str(val))
if isinstance(val, str):
return Decimal(val) if val else Decimal('0')
return Decimal('0')
return cls(
stab=Decimal(data.get('stab', '0')),
cut=Decimal(data.get('cut', '0')),
impact=Decimal(data.get('impact', '0')),
penetration=Decimal(data.get('penetration', '0')),
shrapnel=Decimal(data.get('shrapnel', '0')),
burn=Decimal(data.get('burn', '0')),
cold=Decimal(data.get('cold', '0')),
acid=Decimal(data.get('acid', '0')),
electric=Decimal(data.get('electric', '0')),
stab=safe_decimal(data.get('stab', '0')),
cut=safe_decimal(data.get('cut', '0')),
impact=safe_decimal(data.get('impact', '0')),
penetration=safe_decimal(data.get('penetration', '0')),
shrapnel=safe_decimal(data.get('shrapnel', '0')),
burn=safe_decimal(data.get('burn', '0')),
cold=safe_decimal(data.get('cold', '0')),
acid=safe_decimal(data.get('acid', '0')),
electric=safe_decimal(data.get('electric', '0')),
)
@ -202,13 +211,22 @@ class ArmorPlate:
@classmethod
def from_dict(cls, data: Dict) -> "ArmorPlate":
"""Create from dictionary."""
"""Create from dictionary with validation."""
def safe_decimal(val):
if isinstance(val, Decimal):
return val
if isinstance(val, (int, float)):
return Decimal(str(val))
if isinstance(val, str):
return Decimal(val) if val else Decimal('0')
return Decimal('0')
return cls(
name=data['name'],
item_id=data['item_id'],
protection=ProtectionProfile.from_dict(data.get('protection', {})),
durability=data.get('durability', 2000),
block_chance=Decimal(data.get('block_chance', '0')),
block_chance=safe_decimal(data.get('block_chance', '0')),
)
@ -328,7 +346,16 @@ class ArmorPiece:
@classmethod
def from_dict(cls, data: Dict) -> "ArmorPiece":
"""Create from dictionary."""
"""Create from dictionary with validation."""
def safe_decimal(val):
if isinstance(val, Decimal):
return val
if isinstance(val, (int, float)):
return Decimal(str(val))
if isinstance(val, str):
return Decimal(val) if val else Decimal('0')
return Decimal('0')
piece = cls(
name=data['name'],
item_id=data['item_id'],
@ -336,7 +363,8 @@ class ArmorPiece:
set_name=data.get('set_name'),
protection=ProtectionProfile.from_dict(data.get('protection', {})),
durability=data.get('durability', 2000),
weight=Decimal(data.get('weight', '1.0')),
decay_per_hp=safe_decimal(data.get('decay_per_hp', '0.05')),
weight=safe_decimal(data.get('weight', '1.0')),
)
if data.get('attached_plate'):
piece.attached_plate = ArmorPlate.from_dict(data['attached_plate'])