fix: comprehensive null/invalid value handling in weapon selector
- Add detailed logging for skipped weapons - Handle 'null', 'None', empty strings in decay/ammo values - Safe Decimal conversion with try/except blocks - Safe tooltip formatting for all weapon fields - Safe preview update with error handling
This commit is contained in:
parent
f6ec57d2a2
commit
3ae25503d6
|
|
@ -111,29 +111,42 @@ class WeaponSelectorDialog(QDialog):
|
|||
self._weapons = []
|
||||
for w in all_weapons:
|
||||
try:
|
||||
# Validate that decay and ammo are valid numbers
|
||||
decay_val = w.decay if w.decay is not None else 0
|
||||
# NexusWeapon uses ammo_burn, not ammo
|
||||
ammo_val = w.ammo_burn if w.ammo_burn is not None else 0
|
||||
# Get raw values
|
||||
decay_raw = w.decay
|
||||
ammo_raw = w.ammo_burn
|
||||
|
||||
# Additional validation - skip if values are empty strings or 'null'
|
||||
if decay_val == '' or decay_val == 'null':
|
||||
decay_val = 0
|
||||
if ammo_val == '' or ammo_val == 'null':
|
||||
ammo_val = 0
|
||||
# Log problematic values for debugging
|
||||
if decay_raw is None or str(decay_raw).strip() == '':
|
||||
logger.debug(f"Weapon {w.name}: decay is None or empty")
|
||||
decay_raw = 0
|
||||
if ammo_raw is None or str(ammo_raw).strip() == '':
|
||||
logger.debug(f"Weapon {w.name}: ammo_burn is None or empty")
|
||||
ammo_raw = 0
|
||||
|
||||
# Convert to string and strip
|
||||
decay_str = str(decay_raw).strip()
|
||||
ammo_str = str(ammo_raw).strip()
|
||||
|
||||
# Handle 'null' or 'None' strings
|
||||
if decay_str.lower() in ('null', 'none', ''):
|
||||
decay_str = '0'
|
||||
if ammo_str.lower() in ('null', 'none', ''):
|
||||
ammo_str = '0'
|
||||
|
||||
# Try to convert to Decimal
|
||||
decay_val = Decimal(decay_str)
|
||||
ammo_val = Decimal(ammo_str)
|
||||
|
||||
# Try to convert to Decimal to validate
|
||||
Decimal(str(decay_val))
|
||||
Decimal(str(ammo_val))
|
||||
self._weapons.append(w)
|
||||
except (InvalidOperation, ValueError, TypeError) as e:
|
||||
# Skip weapons with invalid data
|
||||
logger.debug(f"Skipping weapon {getattr(w, 'name', 'unknown')} due to invalid decay/ammo: {e}")
|
||||
# Log the exact problem
|
||||
logger.warning(f"Skipping weapon '{getattr(w, 'name', 'unknown')}': decay={getattr(w, 'decay', 'N/A')}, ammo_burn={getattr(w, 'ammo_burn', 'N/A')} - Error: {e}")
|
||||
continue
|
||||
|
||||
# Sort by name
|
||||
self._weapons.sort(key=lambda w: w.name.lower())
|
||||
|
||||
logger.info(f"Loaded {len(self._weapons)} valid weapons out of {len(all_weapons)} total")
|
||||
self._populate_list(self._weapons)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to load weapons: {e}")
|
||||
|
|
@ -145,32 +158,57 @@ class WeaponSelectorDialog(QDialog):
|
|||
|
||||
for weapon in weapons:
|
||||
try:
|
||||
# Get values with safe defaults
|
||||
# Get values with safe defaults and validation
|
||||
decay_raw = weapon.decay if weapon.decay is not None else 0
|
||||
ammo_raw = weapon.ammo_burn if weapon.ammo_burn is not None else 0
|
||||
|
||||
# Ensure they're valid strings for Decimal conversion
|
||||
decay_str = str(decay_raw).strip() if decay_raw else '0'
|
||||
ammo_str = str(ammo_raw).strip() if ammo_raw else '0'
|
||||
|
||||
if decay_str.lower() in ('null', 'none', ''):
|
||||
decay_str = '0'
|
||||
if ammo_str.lower() in ('null', 'none', ''):
|
||||
ammo_str = '0'
|
||||
|
||||
# Calculate cost per shot
|
||||
decay_pec = Decimal(str(decay_raw))
|
||||
ammo = Decimal(str(ammo_raw))
|
||||
decay_pec = Decimal(decay_str)
|
||||
ammo = Decimal(ammo_str)
|
||||
cost_per_shot = (decay_pec / Decimal("100")) + (ammo * Decimal("0.0001"))
|
||||
|
||||
item = QListWidgetItem(f"{weapon.name} (💰 {cost_per_shot:.4f} PED)")
|
||||
item.setData(Qt.ItemDataRole.UserRole, weapon)
|
||||
|
||||
# Tooltip
|
||||
tooltip = (
|
||||
f"Damage: {weapon.damage}\n"
|
||||
f"Decay: {decay_raw} PEC\n"
|
||||
f"Ammo: {ammo_raw}\n"
|
||||
f"Range: {weapon.range_val}\n"
|
||||
f"DPP: {weapon.dpp:.2f}" if weapon.dpp else "DPP: -"
|
||||
)
|
||||
item.setToolTip(tooltip)
|
||||
# Safe tooltip formatting
|
||||
try:
|
||||
damage_str = str(weapon.damage) if weapon.damage is not None else "-"
|
||||
range_str = str(weapon.range_val) if weapon.range_val is not None else "-"
|
||||
|
||||
# Format DPP safely
|
||||
dpp_str = "-"
|
||||
if weapon.dpp is not None:
|
||||
try:
|
||||
dpp_val = Decimal(str(weapon.dpp))
|
||||
dpp_str = f"{dpp_val:.2f}"
|
||||
except:
|
||||
dpp_str = str(weapon.dpp)
|
||||
|
||||
tooltip = (
|
||||
f"Damage: {damage_str}\n"
|
||||
f"Decay: {decay_str} PEC\n"
|
||||
f"Ammo: {ammo_str}\n"
|
||||
f"Range: {range_str}\n"
|
||||
f"DPP: {dpp_str}"
|
||||
)
|
||||
item.setToolTip(tooltip)
|
||||
except Exception as tooltip_error:
|
||||
logger.debug(f"Tooltip error for {weapon.name}: {tooltip_error}")
|
||||
item.setToolTip(f"{weapon.name}")
|
||||
|
||||
self.weapon_list.addItem(item)
|
||||
except Exception as e:
|
||||
# Skip weapons that fail to process
|
||||
logger.debug(f"Skipping weapon {getattr(weapon, 'name', 'unknown')}: {e}")
|
||||
logger.warning(f"Skipping weapon in populate_list {getattr(weapon, 'name', 'unknown')}: {e}")
|
||||
continue
|
||||
|
||||
def _on_search(self, text):
|
||||
|
|
@ -191,23 +229,38 @@ class WeaponSelectorDialog(QDialog):
|
|||
|
||||
self.selected_weapon = weapon
|
||||
|
||||
# Get values with safe defaults
|
||||
decay_raw = weapon.decay if weapon.decay is not None else 0
|
||||
ammo_raw = weapon.ammo_burn if weapon.ammo_burn is not None else 0
|
||||
|
||||
# Calculate cost per shot
|
||||
decay_pec = Decimal(str(decay_raw))
|
||||
ammo = Decimal(str(ammo_raw))
|
||||
cost_per_shot = (decay_pec / Decimal("100")) + (ammo * Decimal("0.0001"))
|
||||
|
||||
# Update preview
|
||||
self.preview_name.setText(weapon.name)
|
||||
self.preview_damage.setText(str(weapon.damage) if weapon.damage is not None else "-")
|
||||
self.preview_decay.setText(f"{decay_raw} PEC")
|
||||
self.preview_ammo.setText(str(ammo_raw))
|
||||
self.preview_cost.setText(f"{cost_per_shot:.4f} PED")
|
||||
|
||||
self.ok_btn.setEnabled(True)
|
||||
try:
|
||||
# Get values with safe defaults and validation
|
||||
decay_raw = weapon.decay if weapon.decay is not None else 0
|
||||
ammo_raw = weapon.ammo_burn if weapon.ammo_burn is not None else 0
|
||||
|
||||
# Ensure they're valid strings for Decimal conversion
|
||||
decay_str = str(decay_raw).strip() if decay_raw else '0'
|
||||
ammo_str = str(ammo_raw).strip() if ammo_raw else '0'
|
||||
|
||||
if decay_str.lower() in ('null', 'none', ''):
|
||||
decay_str = '0'
|
||||
if ammo_str.lower() in ('null', 'none', ''):
|
||||
ammo_str = '0'
|
||||
|
||||
# Calculate cost per shot
|
||||
decay_pec = Decimal(decay_str)
|
||||
ammo = Decimal(ammo_str)
|
||||
cost_per_shot = (decay_pec / Decimal("100")) + (ammo * Decimal("0.0001"))
|
||||
|
||||
# Update preview with safe string conversion
|
||||
self.preview_name.setText(str(weapon.name) if weapon.name else "Unknown")
|
||||
self.preview_damage.setText(str(weapon.damage) if weapon.damage is not None else "-")
|
||||
self.preview_decay.setText(f"{decay_str} PEC")
|
||||
self.preview_ammo.setText(str(ammo_str))
|
||||
self.preview_cost.setText(f"{cost_per_shot:.4f} PED")
|
||||
|
||||
self.ok_btn.setEnabled(True)
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating preview for {getattr(weapon, 'name', 'unknown')}: {e}")
|
||||
self.preview_name.setText(str(weapon.name) if weapon.name else "Unknown")
|
||||
self.preview_cost.setText("Error")
|
||||
self.ok_btn.setEnabled(False)
|
||||
|
||||
# Calculate cost per shot
|
||||
decay_pec = Decimal(str(weapon.decay))
|
||||
|
|
|
|||
Loading…
Reference in New Issue