From b45d9be71542d07fc3e9c0bc2d575e21647fac2b Mon Sep 17 00:00:00 2001 From: Simon Date: Wed, 20 Dec 2023 10:28:07 +0100 Subject: [PATCH] Add Entity debug helper class to get an overview of the internal equipment state --- megamek/src/megamek/common/CriticalSlot.java | 20 ++++ megamek/src/megamek/common/Mounted.java | 63 ++++++++++- .../src/megamek/utilities/DebugEntity.java | 103 ++++++++++++++++++ 3 files changed, 181 insertions(+), 5 deletions(-) create mode 100644 megamek/src/megamek/utilities/DebugEntity.java diff --git a/megamek/src/megamek/common/CriticalSlot.java b/megamek/src/megamek/common/CriticalSlot.java index 0506b4c598a..f4890ed9ebd 100644 --- a/megamek/src/megamek/common/CriticalSlot.java +++ b/megamek/src/megamek/common/CriticalSlot.java @@ -14,6 +14,8 @@ package megamek.common; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; public class CriticalSlot implements Serializable { @@ -223,4 +225,22 @@ public void setRepairable(boolean repair) { public boolean isRepairable() { return repairable; } + + @Override + public String toString() { + String typeString = type == 0 ? "System Slot" : "Equipment Slot"; + List state = new ArrayList<>(); + if (type == 0) state.add("System No: " + index); + if (mount != null) state.add("[" + mount.equipmentIndex() + "] " + mount.getType().getInternalName()); + if (mount2 != null) state.add("Mount 2: [" + mount2.equipmentIndex() + "] " + mount2.getType().getInternalName()); + if (destroyed) state.add("Destroyed"); + if (hit) state.add("Hit"); + if (!hittable) state.add("Not hittable"); + if (breached) state.add("Breached"); + if (missing) state.add("Missing"); + if (armored) state.add("Armored"); + if (repairing) state.add("Repairing"); + if (!repairable) state.add("Not repairable"); + return typeString + " { " + String.join(", ", state) + " }"; + } } diff --git a/megamek/src/megamek/common/Mounted.java b/megamek/src/megamek/common/Mounted.java index 0e353aa7bbc..fe9076d7c6b 100644 --- a/megamek/src/megamek/common/Mounted.java +++ b/megamek/src/megamek/common/Mounted.java @@ -28,6 +28,7 @@ import java.io.Serializable; import java.util.*; +import java.util.stream.Collectors; /** * This describes equipment mounted on a mech. @@ -1461,11 +1462,6 @@ public int getVibraSetting() { return vibraSetting; } - @Override - public String toString() { - return "megamek.common.Mounted (" + typeName + ")"; - } - public int getBaseDamageAbsorptionRate() { return baseDamageAbsorptionRate; } @@ -2128,4 +2124,61 @@ public boolean isHomingAmmoInHomingMode() { return ammoType.getMunitionType().contains(AmmoType.Munitions.M_HOMING) && curMode().equals("Homing"); } + + public int equipmentIndex() { + if (entity != null) { + return entity.getEquipmentNum(this); + } else { + return -1; + } + } + + @Override + public String toString() { + List locations = allLocations().stream().map(entity::getLocationAbbr).collect(Collectors.toList()); + String intro = getType().getInternalName() + + " (" + String.join("/", locations) + + (rearMounted ? "-R" : "") + + (mechTurretMounted ? "-MTu" : "") + + (sponsonTurretMounted ? "-STu" : "") + + (pintleTurretMounted ? "-PTu" : "") + + (isDWPMounted ? "-DWP" : "") + + (isAPMMounted ? "-APM" : "") + + (squadSupportWeapon ? "-SSW" : "") + + (baMountLoc != -1 ? "-" + BattleArmor.MOUNT_LOC_NAMES[baMountLoc] : "") + + (omniPodMounted ? "-Pod" : "") + + + ")"; + + List state = new ArrayList<>(); + if (linked != null) state.add("Linked: [" + entity.getEquipment().indexOf(linked) + "]"); + if (linkedBy != null) state.add("LinkedBy: [" + entity.getEquipment().indexOf(linkedBy) + "]"); + if (crossLinkedBy != null) state.add("CrossLinkedBy: [" + entity.getEquipment().indexOf(crossLinkedBy) + "]"); + if (linkedBayId != -1) state.add("LinkedBay: [" + linkedBayId + "]"); + if (!bayWeapons.isEmpty()) { + List bayWeaponIds = bayWeapons.stream().map(id -> "[" + id + "]").collect(Collectors.toList()); + state.add("Bay Weapons: " + String.join(", ", bayWeaponIds)); + } + if (!bayAmmo.isEmpty()) { + List bayAmmoIds = bayAmmo.stream().map(id -> "[" + id + "]").collect(Collectors.toList()); + state.add("Bay Ammo: " + String.join(", ", bayAmmoIds)); + } + if (type instanceof AmmoType) { + state.add("Shots: " + shotsLeft); + } + if (destroyed) state.add("Destroyed"); + if (hit) state.add("Hit"); + if (missing) state.add("Missing"); + if (fired) state.add("Fired"); + if (rapidfire) state.add("Rapidfire"); + if (jammed) state.add("Jammed"); + if (useless) state.add("Useless"); + if (armoredComponent) state.add("Armored"); + if (facing != -1) state.add("Facing: " + facing); + if (!quirks.activeQuirks().isEmpty()) state.add("Quirks: " + quirks.getOptionList("/")); + if (weaponGroup) state.add("Group"); + if (nweapons != 1) state.add("#Weapons: " + nweapons); + if (size != 1) state.add("Size: " + size); + return intro + " { " + String.join(", ", state) + " }"; + } } \ No newline at end of file diff --git a/megamek/src/megamek/utilities/DebugEntity.java b/megamek/src/megamek/utilities/DebugEntity.java new file mode 100644 index 00000000000..85047fdd664 --- /dev/null +++ b/megamek/src/megamek/utilities/DebugEntity.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ +package megamek.utilities; + +import megamek.common.CriticalSlot; +import megamek.common.Entity; +import megamek.common.Mech; +import megamek.common.Protomech; + +import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; + +/** + * This class is for debugging Entity with respect to the internal state of equipment. + */ +@SuppressWarnings("unused") +public class DebugEntity { + + /** + * Gets a full listing of the internal representation of the unit's equipment and crit slots with most + * of the internal state of each ({@link #getEquipmentState(Entity)}) and copies it to the clipboard. + * + * @param entity The entity to debug + */ + public static void copyEquipmentState(Entity entity) { + copyToClipboard(getEquipmentState(entity)); + } + + /** Copies the given text to the Clipboard. */ + public static void copyToClipboard(String text) { + StringSelection stringSelection = new StringSelection(text); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(stringSelection, null); + } + + /** + * Returns a full listing of the internal representation of the unit's equipment and crit slots with most + * of the internal state of each. + * + * @param entity The entity to debug + * @return A String describing the internal state of the Entity's equipment + */ + public static String getEquipmentState(Entity entity) { + StringBuilder result = new StringBuilder(); + try { + result.append("Chassis: >").append(entity.getChassis()).append("<\n"); + result.append("Model: >").append(entity.getModel()).append("<\n"); + + result.append("Equipment:\n"); + for (int i = 0; i < entity.getEquipment().size(); i++) { + result.append("[" + i + "] ").append(entity.getEquipment(i)).append("\n"); + if (entity != entity.getEquipment(i).getEntity()) { + result.append("Different Entity!"); + } + } + result.append("\n"); + + result.append("Locations:\n"); + for (int location = 0; location < entity.locations(); location++) { + result.append(entity.getLocationAbbr(location)).append(":\n"); + for (int slot = 0; slot < entity.getNumberOfCriticals(location); slot++) { + CriticalSlot criticalSlot = entity.getCritical(location, slot); + if (criticalSlot != null) { + result.append("[" + slot + "] ").append(criticalSlot); + if (criticalSlot.getType() == 0) { + result.append(" ("); + if (entity instanceof Mech) { + result.append(((Mech) entity).getSystemName(criticalSlot.getIndex())); + } else if (entity instanceof Protomech) { + result.append(Protomech.systemNames[criticalSlot.getIndex()]); + } + result.append(")"); + } + result.append("\n"); + } + } + } + } catch (Exception e) { + result.append("\nAn exception was encountered here. " + e.getMessage()); + } + + return result.toString(); + } + + private DebugEntity() { } +}