CNPC+ Debug Command for Energy Projectiles + Compile Fixes

This commit is contained in:
Kam committed 2026-02-25 04:31:17 -05:00
1 parent 744ffc5ab7
commit d8bc3d4177
16 files changed
+438 -32

No files matched your search

@@ -0,0 +1,42 @@
package kamkeel.npcs.client.command;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
import net.minecraft.util.ChatComponentText;
/**
* Client-only command to toggle debug logging.
* Registered via ClientCommandHandler so it runs entirely on the client
* without sending a packet to the server.
*/
public class CommandCNPCDebugger extends CommandBase {
@Override
public String getCommandName() {
return "cnpcdebugger";
}
@Override
public String getCommandUsage(ICommandSender sender) {
return "/cnpcdebugger <type> - Toggle client debug logging for a type (e.g. energy)";
}
@Override
public int getRequiredPermissionLevel() {
return 0;
}
@Override
public void processCommand(ICommandSender sender, String[] args) {
if (args.length == 0) {
sender.addChatMessage(new ChatComponentText("\u00A7cUsage: /cnpcdebugger <type>"));
return;
}
String type = args[0].toLowerCase();
boolean newState = CNPCDebug.toggleClient(type);
String stateText = newState ? "\u00A7aENABLED" : "\u00A7cDISABLED";
sender.addChatMessage(new ChatComponentText("\u00A77[CNPC+] \u00A7eClient debug '" + type + "' " + stateText));
}
}
@@ -52,6 +52,7 @@ public class CommandKamkeel extends CommandBase {
registerCommand(new AuctionCommand());
if (ConfigMain.AttributesEnabled)
registerCommand(new AttributeCommand());
registerCommand(new DebugCommand());
}
public void registerCommand(CommandKamkeelBase command) {
@@ -0,0 +1,41 @@
package kamkeel.npcs.command;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import static kamkeel.npcs.util.ColorUtil.sendResult;
public class DebugCommand extends CommandKamkeelBase {
@Override
public String getCommandName() {
return "debug";
}
@Override
public String getDescription() {
return "Toggle debug logging types";
}
@Override
public String getUsage() {
return "<type>";
}
@Override
public boolean runSubCommands() {
return false;
}
@Override
public void processCommand(ICommandSender sender, String[] args) throws CommandException {
if (args.length == 0) {
throw new CommandException("Usage: /kam debug <type> (e.g. energy)");
}
String type = args[0].toLowerCase();
boolean newState = CNPCDebug.toggleServer(type);
sendResult(sender, "Server debug '" + type + "' " + (newState ? "\u00A7aENABLED" : "\u00A7cDISABLED"));
}
}
@@ -2,6 +2,7 @@ package kamkeel.npcs.entity;
import kamkeel.npcs.controllers.data.ability.util.AbilityTargetHelper;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyBarrierData;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
@@ -617,4 +618,31 @@ public abstract class EntityAbilityBarrier extends EntityEnergyAbility {
this.dataWatcher.updateObject(DW_CHARGING, (byte) (charging ? 1 : 0));
barrierData.readNBT(nbt);
}
// ==================== DEBUG LOGGING ====================
/**
* Debug log called every tick for barriers. Subclasses override debugLogBarrierExtra().
*/
protected void debugLogBarrierTick() {
boolean isClient = worldObj.isRemote;
if (isClient ? !CNPCDebug.isClientEnabled("energy") : !CNPCDebug.isServerEnabled("energy"))
return;
String className = getClass().getSimpleName();
String base = String.format("[%s id=%d tick=%d] pos=(%.2f,%.2f,%.2f) charging=%b health=%.1f",
className, getEntityId(), ticksAlive,
posX, posY, posZ, isCharging(), currentHealth);
String extra = debugLogBarrierExtra();
String full = extra.isEmpty() ? base : base + " " + extra;
CNPCDebug.log("energy", isClient, full);
}
/**
* Subclass hook for barrier-specific debug data.
*/
protected String debugLogBarrierExtra() {
return "";
}
}
@@ -16,7 +16,6 @@ import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import noppes.npcs.LogWriter;
import java.util.ArrayList;
import java.util.Collections;
@@ -61,9 +60,6 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
private int trailFadeTime = 20; // Ticks for trail to fully fade
private List<Integer> trailPointAges = new ArrayList<>();
// Debug logging
private static final boolean DEBUG_LOGGING = false;
public EntityAbilityBeam(World world) {
super(world);
}
@@ -160,10 +156,6 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
// Add initial trail point at origin (relative 0,0,0)
trailPoints.add(Vec3.createVectorHelper(0, 0, 0));
if (DEBUG_LOGGING && !world.isRemote) {
LogWriter.info("[Beam] Created at origin " + x + ", " + y + ", " + z + " maxDist=" + lifespan.maxDistance);
}
// Calculate initial velocity toward target
calculateInitialVelocity(owner, target, x, y, z);
}
@@ -222,11 +214,6 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
trailPoints.add(Vec3.createVectorHelper(0, 0, 0));
if (isFadingMode()) trailPointAges.add(0);
if (DEBUG_LOGGING && !worldObj.isRemote) {
LogWriter.info("[Beam] startFiring: origin=(" + startX + "," + startY + "," + startZ +
") headOffset=(" + headOffsetX + "," + headOffsetY + "," + headOffsetZ +
") motion=(" + motionX + "," + motionY + "," + motionZ + ")");
}
}
@Override
@@ -237,11 +224,7 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
headOffsetY * headOffsetY +
headOffsetZ * headOffsetZ
);
boolean exceeded = distFromOrigin >= getMaxDistance();
if (exceeded && !worldObj.isRemote && DEBUG_LOGGING) {
LogWriter.info("[Beam] DEAD: Max distance exceeded. dist=" + distFromOrigin + " max=" + getMaxDistance());
}
return exceeded;
return distFromOrigin >= getMaxDistance();
}
@Override
@@ -312,17 +295,6 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
// Add trail point
addTrailPoint();
// Debug log periodically
if (DEBUG_LOGGING && ticksExisted % 20 == 0) {
LogWriter.info("[Beam] Server tick=" + ticksExisted + " headOffset=(" +
String.format("%.2f", headOffsetX) + "," +
String.format("%.2f", headOffsetY) + "," +
String.format("%.2f", headOffsetZ) + ") origin=(" +
String.format("%.2f", startX) + "," +
String.format("%.2f", startY) + "," +
String.format("%.2f", startZ) + ") trail=" + getActiveTrailSize());
}
// Skip collision checks on first few ticks
if (ticksExisted > 2) {
checkBlockCollision(headWorldX, headWorldY, headWorldZ);
@@ -528,9 +500,27 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
Math.max(prevHeadWorldZ, headZ) + hitSize
);
if (processEntitiesInHitBox(hitBox, headX, headY, headZ) && DEBUG_LOGGING) {
LogWriter.info("[Beam] DEAD: Entity collision at tick " + ticksExisted);
}
processEntitiesInHitBox(hitBox, headX, headY, headZ);
}
// ==================== DEBUG ====================
@Override
protected String debugLogExtra() {
double headWorldX = startX + headOffsetX;
double headWorldY = startY + headOffsetY;
double headWorldZ = startZ + headOffsetZ;
return String.format("headOff=(%.2f,%.2f,%.2f) prevHead=(%.2f,%.2f,%.2f) " +
"origin=(%.2f,%.2f,%.2f) headWorld=(%.2f,%.2f,%.2f) " +
"trail=%d mode=%s anchored=%b beamW=%.2f headSz=%.2f " +
"motion=(%.3f,%.3f,%.3f)",
headOffsetX, headOffsetY, headOffsetZ,
prevHeadOffsetX, prevHeadOffsetY, prevHeadOffsetZ,
startX, startY, startZ,
headWorldX, headWorldY, headWorldZ,
getActiveTrailSize(),
beamMode.name(), isAnchoredMode(), beamWidth, headSize,
motionX, motionY, motionZ);
}
// ==================== GETTERS FOR RENDERER ====================
@@ -330,6 +330,17 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
updateRotation();
}
// ==================== DEBUG ====================
@Override
protected String debugLogExtra() {
return String.format("motion=(%.3f,%.3f,%.3f) radius=%.2f thickness=%.2f " +
"boomerang=%b returning=%b vertical=%b ticksSinceMiss=%d",
motionX, motionY, motionZ,
discRadius, discThickness,
boomerang, returning, vertical, ticksSinceMiss);
}
// ==================== GETTERS ====================
public float getDiscRadius() {
@@ -122,6 +122,8 @@ public class EntityAbilityDome extends EntityAbilityBarrier {
if (worldObj.isRemote && barrierData.meleeEnabled && !isCharging()) {
adjustMeleeBoundingBox();
}
debugLogBarrierTick();
}
// ==================== INCOMING CHECK ====================
@@ -548,6 +550,14 @@ public class EntityAbilityDome extends EntityAbilityBarrier {
return surfaceDist * surfaceDist;
}
// ==================== DEBUG ====================
@Override
protected String debugLogBarrierExtra() {
return String.format("radius=%.2f targetRadius=%.2f follow=%b",
domeRadius, targetDomeRadius, followCaster);
}
// ==================== GETTERS ====================
public float getDomeRadius() {
@@ -624,6 +624,17 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
return -1;
}
// ==================== DEBUG ====================
@Override
protected String debugLogExtra() {
return String.format("dir=(%.3f,%.3f,%.3f) desired=%.2f current=%.2f max=%.2f " +
"fullyExtended=%b end=(%.2f,%.2f,%.2f) width=%.2f expSpd=%.2f origin=(%.2f,%.2f,%.2f)",
dirX, dirY, dirZ, desiredLength, currentLength, maxLength,
fullyExtended, endX, endY, endZ, laserWidth, expansionSpeed,
startX, startY, startZ);
}
// ==================== GETTERS / SETTERS ====================
public float getLaserWidth() {
@@ -150,6 +150,16 @@ public class EntityAbilityOrb extends EntityEnergyProjectile {
processEntitiesInHitBox(hitBox, nextX, nextY, nextZ);
}
// ==================== DEBUG ====================
@Override
protected String debugLogExtra() {
return String.format("motion=(%.3f,%.3f,%.3f) homing=%b start=(%.2f,%.2f,%.2f)",
motionX, motionY, motionZ,
homingData != null && homingData.isHoming(),
startX, startY, startZ);
}
// ==================== GETTERS ====================
// Legacy getter for renderer compatibility
@@ -143,6 +143,8 @@ public class EntityAbilityPanel extends EntityAbilityBarrier {
// Stationary, no update needed
break;
}
debugLogBarrierTick();
}
private void updateHeld() {
@@ -548,6 +550,14 @@ public class EntityAbilityPanel extends EntityAbilityBarrier {
return df * df + dr * dr + du * du;
}
// ==================== DEBUG ====================
@Override
protected String debugLogBarrierExtra() {
return String.format("mode=%s yaw=%.1f w=%.2f h=%.2f",
mode.name(), panelYaw, panelData.panelWidth, panelData.panelHeight);
}
// ==================== GETTERS ====================
public PanelMode getMode() {
@@ -3,6 +3,7 @@ package kamkeel.npcs.entity;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
@@ -168,6 +169,19 @@ public class EntityAbilitySweeper extends EntityEnergyAbility {
if (!worldObj.isRemote) {
handleDamage(owner);
}
// Debug logging
{
boolean isClient = worldObj.isRemote;
if (isClient ? CNPCDebug.isClientEnabled("energy") : CNPCDebug.isServerEnabled("energy")) {
CNPCDebug.log("energy", isClient, String.format(
"[Sweeper id=%d tick=%d] pos=(%.2f,%.2f,%.2f) angle=%.1f prevAngle=%.1f " +
"speed=%.1f rotations=%d/%d length=%.2f width=%.2f",
getEntityId(), ticksExisted, posX, posY, posZ,
currentAngle, prevAngle, sweepSpeed,
completedRotations, numberOfRotations, beamLength, beamWidth));
}
}
}
/**
@@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyDisplayData;
import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLightningData;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.MathHelper;
import net.minecraft.world.World;
@@ -57,6 +58,17 @@ public class EntityEnergyExplosion extends EntityEnergyAbility {
float eased = 1.0f - (1.0f - progress) * (1.0f - progress);
this.renderRadius = maxRadius * eased;
// Debug logging
{
boolean isClient = worldObj.isRemote;
if (isClient ? CNPCDebug.isClientEnabled("energy") : CNPCDebug.isServerEnabled("energy")) {
CNPCDebug.log("energy", isClient, String.format(
"[Explosion id=%d tick=%d] pos=(%.2f,%.2f,%.2f) renderRadius=%.2f maxRadius=%.2f progress=%.2f",
getEntityId(), ticksExisted, posX, posY, posZ,
renderRadius, maxRadius, getLifeProgress(0f)));
}
}
if (ticksExisted >= durationTicks) {
setDead();
}
@@ -16,6 +16,7 @@ import kamkeel.npcs.controllers.data.ability.data.energy.EnergyLightningData;
import kamkeel.npcs.network.packets.data.energy.ProjectileReflectPacket;
import kamkeel.npcs.network.packets.data.energyexplosion.EnergyExplosionSpawnPacket;
import kamkeel.npcs.util.AnchorPointHelper;
import kamkeel.npcs.util.CNPCDebug;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.Entity;
@@ -334,6 +335,8 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
if (!previewMode && !worldObj.isRemote) {
EventHooks.onEnergyProjectileTick(this);
}
debugLogTick();
}
/**
@@ -349,6 +352,53 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility {
if (this.rotationValZ > 360.0f) this.rotationValZ -= 360.0f;
}
// ==================== DEBUG LOGGING ====================
/**
* Debug log called every tick. Logs position/size/charging state.
* Subclasses override debugLogExtra() for type-specific data.
*/
protected void debugLogTick() {
boolean isClient = worldObj.isRemote;
if (isClient ? !CNPCDebug.isClientEnabled("energy") : !CNPCDebug.isServerEnabled("energy"))
return;
String className = getClass().getSimpleName();
boolean dwCharging = isCharging(); // DataWatcher value (what client sees)
boolean localCharging = this.charging; // Local field (server truth)
String base = String.format("[%s id=%d tick=%d] pos=(%.2f,%.2f,%.2f) prev=(%.2f,%.2f,%.2f) " +
"size=%.3f renderSize=%.3f prevRenderSize=%.3f " +
"charging(dw)=%b charging(local)=%b chargeTick=%d/%d chargeProgress=%.3f",
className, getEntityId(), ticksExisted,
posX, posY, posZ, prevPosX, prevPosY, prevPosZ,
size, renderCurrentSize, prevRenderSize,
dwCharging, localCharging, chargeTick, chargeDuration, getChargeProgress());
// Flag mismatch between DataWatcher and local field
if (dwCharging != localCharging) {
base += " !!CHARGE_MISMATCH!!";
}
// Client interpolation state (only meaningful on client)
if (isClient) {
base += String.format(" interp(steps=%d target=(%.2f,%.2f,%.2f))",
interpSteps, interpTargetX, interpTargetY, interpTargetZ);
}
String extra = debugLogExtra();
String full = extra.isEmpty() ? base : base + " " + extra;
CNPCDebug.log("energy", isClient, full);
}
/**
* Subclass hook for type-specific debug data.
* Return empty string if nothing extra to log.
*/
protected String debugLogExtra() {
return "";
}
/**
* Check if projectile has exceeded max distance.
*
@@ -192,6 +192,14 @@ public class EntityEnergySlicer extends EntityEnergyProjectile {
return lastTravelPitch;
}
// ==================== DEBUG ====================
@Override
protected String debugLogExtra() {
return String.format("motion=(%.3f,%.3f,%.3f) sliceW=%.2f sliceT=%.2f",
motionX, motionY, motionZ, sliceWidth, sliceThickness);
}
// ==================== GETTERS ====================
public float getSliceWidth() {
@@ -0,0 +1,163 @@
package kamkeel.npcs.util;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.StreamHandler;
/**
* Debug logging system for CNPC+ entities.
* Writes to logs/cnpc_debug/[type]_[side].log (file only, no console output).
* Toggle at runtime via /cnpcdebugger [type] (client) or /kam debug [type] (server).
*/
public class CNPCDebug {
private static final String DIR = "logs/cnpc_debug";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss");
// Runtime toggle state per type, separate for client and server
private static final Map<String, Boolean> serverToggles = new ConcurrentHashMap<>();
private static final Map<String, Boolean> clientToggles = new ConcurrentHashMap<>();
// Per-type file handlers (lazily initialized)
private static final Map<String, Handler> serverHandlers = new ConcurrentHashMap<>();
private static final Map<String, Handler> clientHandlers = new ConcurrentHashMap<>();
// ==================== TOGGLE API ====================
/**
* Toggle server-side debug for given type. Returns new state.
*/
public static boolean toggleServer(String type) {
type = type.toLowerCase();
boolean newState = !isServerEnabled(type);
serverToggles.put(type, newState);
if (newState) {
ensureHandler(type, false);
}
return newState;
}
/**
* Toggle client-side debug for given type. Returns new state.
*/
public static boolean toggleClient(String type) {
type = type.toLowerCase();
boolean newState = !isClientEnabled(type);
clientToggles.put(type, newState);
if (newState) {
ensureHandler(type, true);
}
return newState;
}
public static boolean isServerEnabled(String type) {
Boolean val = serverToggles.get(type.toLowerCase());
return val != null && val;
}
public static boolean isClientEnabled(String type) {
Boolean val = clientToggles.get(type.toLowerCase());
return val != null && val;
}
// ==================== LOGGING API ====================
/**
* Log a debug message for the given type on the given side.
* Callers should guard with isServerEnabled/isClientEnabled for performance.
*/
public static void log(String type, boolean client, String msg) {
type = type.toLowerCase();
Map<String, Boolean> toggles = client ? clientToggles : serverToggles;
Boolean enabled = toggles.get(type);
if (enabled == null || !enabled) return;
Handler handler = ensureHandler(type, client);
if (handler == null) return;
String side = client ? "CLIENT" : "SERVER";
String timestamp;
synchronized (DATE_FORMAT) {
timestamp = DATE_FORMAT.format(new Date());
}
String formatted = "[" + timestamp + "][" + side + "][DEBUG-" + type.toUpperCase() + "] " + msg + System.lineSeparator();
LogRecord record = new LogRecord(Level.INFO, formatted);
handler.publish(record);
handler.flush();
}
/**
* Log on server side.
*/
public static void logServer(String type, String msg) {
log(type, false, msg);
}
/**
* Log on client side.
*/
public static void logClient(String type, String msg) {
log(type, true, msg);
}
// ==================== INTERNALS ====================
private static Handler ensureHandler(String type, boolean client) {
Map<String, Handler> handlers = client ? clientHandlers : serverHandlers;
Handler existing = handlers.get(type);
if (existing != null) return existing;
synchronized (CNPCDebug.class) {
existing = handlers.get(type);
if (existing != null) return existing;
try {
File dir = new File(DIR);
if (!dir.exists()) dir.mkdirs();
String side = client ? "client" : "server";
File file = new File(dir, type + "_" + side + ".log");
// Rotate old log
if (file.exists()) {
File backup = new File(dir, type + "_" + side + "-prev.log");
if (backup.exists()) backup.delete();
file.renameTo(backup);
}
Handler handler = new StreamHandler(new FileOutputStream(file), new Formatter() {
@Override
public String format(LogRecord record) {
return record.getMessage();
}
});
handler.setLevel(Level.ALL);
handlers.put(type, handler);
// Log header
String timestamp;
synchronized (DATE_FORMAT) {
timestamp = DATE_FORMAT.format(new Date());
}
LogRecord header = new LogRecord(Level.INFO,
"[" + timestamp + "][" + (client ? "CLIENT" : "SERVER") + "][DEBUG-" + type.toUpperCase() + "] Debug logging started" + System.lineSeparator());
handler.publish(header);
handler.flush();
return handler;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
}
@@ -6,6 +6,7 @@ import cpw.mods.fml.client.registry.RenderingRegistry;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ObfuscationReflectionHelper;
import kamkeel.npcs.addon.client.DBCClient;
import kamkeel.npcs.client.command.CommandCNPCDebugger;
import kamkeel.npcs.client.renderer.RenderAbilityBeam;
import kamkeel.npcs.client.renderer.RenderAbilityDisc;
import kamkeel.npcs.client.renderer.RenderAbilityLaser;
@@ -53,6 +54,7 @@ import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ReportedException;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.client.ClientCommandHandler;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.FakePlayer;
@@ -360,6 +362,9 @@ public class ClientProxy extends CommonProxy {
ClientTagMapController.Instance = new ClientTagMapController();
MinecraftForge.EVENT_BUS.register(new ClientEventHandler());
// Debug commands
ClientCommandHandler.instance.registerCommand(new CommandCNPCDebugger());
// Telegraph rendering system
TelegraphManager.initClient();
MinecraftForge.EVENT_BUS.register(new TelegraphRenderer());