mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-13 06:37:34 +00:00
Merge branch 'dev' into syntax-highlighter-unified
This commit is contained in:
commit
ef01da4b5b
27 files changed
+1273
-857
No files matched your search
@@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.entity.EntityAbilityBeam;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.entity.RenderManager;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.Vec3;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
@@ -51,19 +52,20 @@ public class RenderEnergyBeam extends RenderEnergy {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get interpolated head offset
|
||||
// Get interpolated head offset (for head/trail rendering relative to origin)
|
||||
double headOffsetX = beam.getInterpolatedHeadOffsetX(partialTicks);
|
||||
double headOffsetY = beam.getInterpolatedHeadOffsetY(partialTicks);
|
||||
double headOffsetZ = beam.getInterpolatedHeadOffsetZ(partialTicks);
|
||||
|
||||
// The render system passes x,y,z as the position to render the entity at
|
||||
// Entity position = origin + headOffset (in world coords)
|
||||
// So origin render position = x,y,z - headOffset
|
||||
double renderOriginX = x - headOffsetX;
|
||||
double renderOriginY = y - headOffsetY;
|
||||
double renderOriginZ = z - headOffsetZ;
|
||||
// Compute render origin directly from the world origin and camera position.
|
||||
// We can't derive it from MC's x,y,z because syncPositionStateToCurrent() snaps
|
||||
// lastTickPos = posX on every sync packet, killing MC's position interpolation.
|
||||
// The headOffset interpolation then mismatches, causing the origin to wobble.
|
||||
double renderOriginX = beam.getOriginX() - RenderManager.renderPosX;
|
||||
double renderOriginY = beam.getOriginY() - RenderManager.renderPosY;
|
||||
double renderOriginZ = beam.getOriginZ() - RenderManager.renderPosZ;
|
||||
|
||||
// Get beam properties (interpolated for smooth size transitions)
|
||||
// Get beam properties (lerp-smoothed for smooth size transitions)
|
||||
float beamWidth = beam.getInterpolatedBeamWidth(partialTicks);
|
||||
float headSize = beam.getInterpolatedHeadSize(partialTicks);
|
||||
int innerColor = beam.getInnerColor();
|
||||
@@ -77,21 +79,22 @@ public class RenderEnergyBeam extends RenderEnergy {
|
||||
// Calculate head distance from origin (for overlap check)
|
||||
double headDistFromOrigin = Math.sqrt(headOffsetX * headOffsetX + headOffsetY * headOffsetY + headOffsetZ * headOffsetZ);
|
||||
|
||||
// Render tail orb at origin (0,0,0) - only in anchored mode
|
||||
// Don't render if head is too close to origin (would cause overlap/extra orb appearance)
|
||||
if (beam.shouldRenderTailOrb() && headDistFromOrigin > headSize * 0.5) {
|
||||
renderTailOrb(headSize * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, beam.getInnerAlpha() * proximityAlpha);
|
||||
}
|
||||
|
||||
float innerAlpha = beam.getInnerAlpha() * proximityAlpha;
|
||||
|
||||
// Render trail segments with smooth connections (with fading for non-anchored)
|
||||
// Render trail segments first (with fading for non-anchored)
|
||||
if (beam.hasFadingTrail()) {
|
||||
renderFadingTrail(beam, trail, beamWidth, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), innerAlpha);
|
||||
} else {
|
||||
renderSmoothTrail(trail, beamWidth, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), innerAlpha);
|
||||
}
|
||||
|
||||
// Render tail orb at origin (0,0,0) AFTER trail so it draws on top
|
||||
// Don't render if head is too close to origin (would cause overlap/extra orb appearance)
|
||||
// Use target headSize (not lerped) so the threshold isn't inflated by lerp lag
|
||||
if (beam.shouldRenderTailOrb() && headDistFromOrigin > beam.getHeadSize() * 0.5) {
|
||||
renderTailOrb(beam.getHeadSize() * 0.8f, innerColor, outerColor, beam.isOuterColorEnabled(), beam.getOuterColorWidth(), outerAlpha, innerAlpha);
|
||||
}
|
||||
|
||||
// Render head at interpolated offset position
|
||||
renderHead(beam, headOffsetX, headOffsetY, headOffsetZ, headSize, innerColor, outerColor, outerAlpha, innerAlpha, partialTicks);
|
||||
|
||||
|
||||
@@ -405,6 +405,8 @@ public class AbilityController implements IAbilityHandler {
|
||||
Ability original = customAbilities.get(originalName);
|
||||
if (original == null || original.isBuiltIn()) return null;
|
||||
|
||||
int originalCatId = customAbilityCatMap.getOrDefault(originalName, CategoryManager.UNCATEGORIZED_ID);
|
||||
|
||||
NBTTagCompound nbt = original.writeNBT(true);
|
||||
nbt.setString("id", UUID.randomUUID().toString());
|
||||
|
||||
@@ -416,6 +418,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
clone.setName(name);
|
||||
|
||||
saveCustomAbility(clone);
|
||||
|
||||
if (originalCatId > CategoryManager.UNCATEGORIZED_ID) {
|
||||
customAbilityCatMap.put(clone.getName(), originalCatId);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -770,6 +777,8 @@ public class AbilityController implements IAbilityHandler {
|
||||
ChainedAbility original = chainedAbilities.get(originalName);
|
||||
if (original == null) return null;
|
||||
|
||||
int originalCatId = chainedAbilityCatMap.getOrDefault(originalName, CategoryManager.UNCATEGORIZED_ID);
|
||||
|
||||
NBTTagCompound nbt = original.writeNBT(true);
|
||||
nbt.setString("Id", UUID.randomUUID().toString());
|
||||
|
||||
@@ -781,6 +790,11 @@ public class AbilityController implements IAbilityHandler {
|
||||
clone.setName(name);
|
||||
|
||||
saveChainedAbility(clone);
|
||||
|
||||
if (originalCatId > CategoryManager.UNCATEGORIZED_ID) {
|
||||
chainedAbilityCatMap.put(clone.getName(), originalCatId);
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,15 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
FREE_TRAIL
|
||||
}
|
||||
|
||||
// Beam shape properties
|
||||
// Beam shape properties (target values - set by sync packets/scripts)
|
||||
private float beamWidth = 0.3f;
|
||||
private float headSize = 0.5f;
|
||||
private float prevBeamWidth = 0.3f;
|
||||
private float prevHeadSize = 0.5f;
|
||||
|
||||
// Lerp-smoothed render values (approach target each tick)
|
||||
private float renderBeamWidth = 0.3f;
|
||||
private float renderHeadSize = 0.5f;
|
||||
private float prevRenderBeamWidth = 0.3f;
|
||||
private float prevRenderHeadSize = 0.5f;
|
||||
|
||||
// Trail - list of points showing beam path (RELATIVE to origin!)
|
||||
private List<Vec3> trailPoints = new ArrayList<>();
|
||||
@@ -236,18 +240,26 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
|
||||
@Override
|
||||
protected void updateProjectile() {
|
||||
// Save previous render values for sub-tick interpolation
|
||||
prevRenderBeamWidth = renderBeamWidth;
|
||||
prevRenderHeadSize = renderHeadSize;
|
||||
|
||||
// Handle charging state (windup phase) - use isCharging() for synced value
|
||||
if (isCharging()) {
|
||||
// During charging, snap render values to target (size grows smoothly already)
|
||||
renderBeamWidth = beamWidth;
|
||||
renderHeadSize = headSize;
|
||||
updateCharging();
|
||||
return;
|
||||
}
|
||||
|
||||
// Store previous values for interpolation
|
||||
// Lerp render values toward target (smooth out sync packet jumps)
|
||||
renderBeamWidth += (beamWidth - renderBeamWidth) * 0.15f;
|
||||
renderHeadSize += (headSize - renderHeadSize) * 0.15f;
|
||||
|
||||
prevHeadOffsetX = headOffsetX;
|
||||
prevHeadOffsetY = headOffsetY;
|
||||
prevHeadOffsetZ = headOffsetZ;
|
||||
prevBeamWidth = beamWidth;
|
||||
prevHeadSize = headSize;
|
||||
|
||||
// Age trail points for fading effect
|
||||
if (isFadingMode()) {
|
||||
@@ -585,11 +597,10 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
public float getInterpolatedBeamWidth(float partialTicks) {
|
||||
return prevBeamWidth + (beamWidth - prevBeamWidth) * partialTicks;
|
||||
return prevRenderBeamWidth + (renderBeamWidth - prevRenderBeamWidth) * partialTicks;
|
||||
}
|
||||
|
||||
public void setBeamWidth(float beamWidth) {
|
||||
this.prevBeamWidth = this.beamWidth;
|
||||
this.beamWidth = beamWidth;
|
||||
}
|
||||
|
||||
@@ -598,11 +609,10 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
public float getInterpolatedHeadSize(float partialTicks) {
|
||||
return prevHeadSize + (headSize - prevHeadSize) * partialTicks;
|
||||
return prevRenderHeadSize + (renderHeadSize - prevRenderHeadSize) * partialTicks;
|
||||
}
|
||||
|
||||
public void setHeadSize(float headSize) {
|
||||
this.prevHeadSize = this.headSize;
|
||||
this.headSize = headSize;
|
||||
}
|
||||
|
||||
@@ -761,8 +771,6 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
|
||||
@Override
|
||||
protected void applyProjectileClientSyncData(NBTTagCompound nbt) {
|
||||
prevBeamWidth = beamWidth;
|
||||
prevHeadSize = headSize;
|
||||
beamWidth = nbt.getFloat("BeamWidth");
|
||||
headSize = nbt.getFloat("HeadSize");
|
||||
setAttachedToOwner(nbt.getBoolean("AttachedToOwner"));
|
||||
@@ -774,8 +782,10 @@ public class EntityAbilityBeam extends EntityEnergyProjectile {
|
||||
protected void readProjectileNBT(NBTTagCompound nbt) {
|
||||
this.beamWidth = sanitize(nbt.hasKey("BeamWidth") ? nbt.getFloat("BeamWidth") : 0.3f, 0.3f, MAX_ENTITY_SIZE);
|
||||
this.headSize = sanitize(nbt.hasKey("HeadSize") ? nbt.getFloat("HeadSize") : 0.5f, 0.5f, MAX_ENTITY_SIZE);
|
||||
this.prevBeamWidth = this.beamWidth;
|
||||
this.prevHeadSize = this.headSize;
|
||||
this.renderBeamWidth = this.beamWidth;
|
||||
this.renderHeadSize = this.headSize;
|
||||
this.prevRenderBeamWidth = this.beamWidth;
|
||||
this.prevRenderHeadSize = this.headSize;
|
||||
this.headOffsetX = nbt.hasKey("HeadOffsetX") ? nbt.getDouble("HeadOffsetX") : 0;
|
||||
this.headOffsetY = nbt.hasKey("HeadOffsetY") ? nbt.getDouble("HeadOffsetY") : 0;
|
||||
this.headOffsetZ = nbt.hasKey("HeadOffsetZ") ? nbt.getDouble("HeadOffsetZ") : 0;
|
||||
|
||||
@@ -30,11 +30,15 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
private boolean returning = false;
|
||||
private int ticksSinceMiss = 0;
|
||||
|
||||
// Disc shape properties
|
||||
// Disc shape properties (target values)
|
||||
private float discRadius = 1.0f; // Width of disc
|
||||
private float discThickness = 0.2f; // Height of disc
|
||||
private float prevDiscRadius = 1.0f;
|
||||
private float prevDiscThickness = 0.2f;
|
||||
|
||||
// Lerp-smoothed render values
|
||||
private float renderDiscRadius = 1.0f;
|
||||
private float renderDiscThickness = 0.2f;
|
||||
private float prevRenderDiscRadius = 1.0f;
|
||||
private float prevRenderDiscThickness = 0.2f;
|
||||
|
||||
// Boomerang owner-gone tracking
|
||||
private int returnOwnerNullTicks = 0;
|
||||
@@ -136,16 +140,23 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
|
||||
@Override
|
||||
protected void updateProjectile() {
|
||||
// Store previous values for interpolation
|
||||
prevDiscRadius = discRadius;
|
||||
prevDiscThickness = discThickness;
|
||||
// Save previous render values for sub-tick interpolation
|
||||
prevRenderDiscRadius = renderDiscRadius;
|
||||
prevRenderDiscThickness = renderDiscThickness;
|
||||
|
||||
// Handle charging state (windup phase)
|
||||
if (isCharging()) {
|
||||
// During charging, snap render values to target (size grows smoothly already)
|
||||
renderDiscRadius = discRadius;
|
||||
renderDiscThickness = discThickness;
|
||||
updateCharging();
|
||||
return;
|
||||
}
|
||||
|
||||
// Lerp render values toward target (smooth out sync packet jumps)
|
||||
renderDiscRadius += (discRadius - renderDiscRadius) * 0.15f;
|
||||
renderDiscThickness += (discThickness - renderDiscThickness) * 0.15f;
|
||||
|
||||
// In preview mode, run movement on client (no server)
|
||||
if (previewMode) {
|
||||
updatePreviewMovement();
|
||||
@@ -354,11 +365,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
public float getInterpolatedDiscRadius(float partialTicks) {
|
||||
return prevDiscRadius + (discRadius - prevDiscRadius) * partialTicks;
|
||||
return prevRenderDiscRadius + (renderDiscRadius - prevRenderDiscRadius) * partialTicks;
|
||||
}
|
||||
|
||||
public void setDiscRadius(float radius) {
|
||||
this.prevDiscRadius = this.discRadius;
|
||||
this.discRadius = radius;
|
||||
}
|
||||
|
||||
@@ -367,11 +377,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
public float getInterpolatedDiscThickness(float partialTicks) {
|
||||
return prevDiscThickness + (discThickness - prevDiscThickness) * partialTicks;
|
||||
return prevRenderDiscThickness + (renderDiscThickness - prevRenderDiscThickness) * partialTicks;
|
||||
}
|
||||
|
||||
public void setDiscThickness(float thickness) {
|
||||
this.prevDiscThickness = this.discThickness;
|
||||
this.discThickness = thickness;
|
||||
}
|
||||
|
||||
@@ -459,8 +468,6 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
|
||||
@Override
|
||||
protected void applyProjectileClientSyncData(NBTTagCompound nbt) {
|
||||
prevDiscRadius = discRadius;
|
||||
prevDiscThickness = discThickness;
|
||||
discRadius = nbt.getFloat("DiscRadius");
|
||||
discThickness = nbt.getFloat("DiscThickness");
|
||||
vertical = nbt.getBoolean("Vertical");
|
||||
@@ -474,8 +481,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile {
|
||||
this.boomerangDelay = nbt.hasKey("BoomerangDelay") ? nbt.getInteger("BoomerangDelay") : 40;
|
||||
this.discRadius = sanitize(nbt.hasKey("DiscRadius") ? nbt.getFloat("DiscRadius") : 1.0f, 1.0f, MAX_ENTITY_SIZE);
|
||||
this.discThickness = sanitize(nbt.hasKey("DiscThickness") ? nbt.getFloat("DiscThickness") : 0.2f, 0.2f, MAX_ENTITY_SIZE);
|
||||
this.prevDiscRadius = this.discRadius;
|
||||
this.prevDiscThickness = this.discThickness;
|
||||
this.renderDiscRadius = this.discRadius;
|
||||
this.renderDiscThickness = this.discThickness;
|
||||
this.prevRenderDiscRadius = this.discRadius;
|
||||
this.prevRenderDiscThickness = this.discThickness;
|
||||
this.vertical = nbt.hasKey("Vertical") ? nbt.getBoolean("Vertical") : false;
|
||||
this.returning = nbt.hasKey("Returning") && nbt.getBoolean("Returning");
|
||||
// Charging state (common fields handled by base)
|
||||
|
||||
@@ -31,9 +31,12 @@ import java.util.List;
|
||||
*/
|
||||
public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
|
||||
// Laser-specific properties
|
||||
// Laser-specific properties (target value)
|
||||
private float laserWidth = 0.2f;
|
||||
private float prevLaserWidth = 0.2f;
|
||||
|
||||
// Lerp-smoothed render values
|
||||
private float renderLaserWidth = 0.2f;
|
||||
private float prevRenderLaserWidth = 0.2f;
|
||||
private float expansionSpeed = 2.0f; // Blocks per tick
|
||||
private float maxLength = 32.0f; // Maximum beam reach in blocks
|
||||
|
||||
@@ -145,14 +148,19 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
|
||||
@Override
|
||||
protected void updateProjectile() {
|
||||
// Store previous values for interpolation
|
||||
prevLaserWidth = laserWidth;
|
||||
// Save previous render value for sub-tick interpolation
|
||||
prevRenderLaserWidth = renderLaserWidth;
|
||||
|
||||
if (isCharging()) {
|
||||
// During charging, snap render value to target
|
||||
renderLaserWidth = laserWidth;
|
||||
updateCharging();
|
||||
return;
|
||||
}
|
||||
|
||||
// Lerp render value toward target (smooth out sync packet jumps)
|
||||
renderLaserWidth += (laserWidth - renderLaserWidth) * 0.15f;
|
||||
|
||||
// Save previous positions for partial tick interpolation
|
||||
prevStartX = startX;
|
||||
prevStartY = startY;
|
||||
@@ -708,11 +716,10 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
}
|
||||
|
||||
public float getInterpolatedLaserWidth(float partialTicks) {
|
||||
return prevLaserWidth + (laserWidth - prevLaserWidth) * partialTicks;
|
||||
return prevRenderLaserWidth + (renderLaserWidth - prevRenderLaserWidth) * partialTicks;
|
||||
}
|
||||
|
||||
public void setLaserWidth(float width) {
|
||||
this.prevLaserWidth = this.laserWidth;
|
||||
this.laserWidth = width;
|
||||
}
|
||||
|
||||
@@ -888,7 +895,6 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
|
||||
@Override
|
||||
protected void applyProjectileClientSyncData(NBTTagCompound nbt) {
|
||||
prevLaserWidth = laserWidth;
|
||||
laserWidth = nbt.getFloat("LaserWidth");
|
||||
expansionSpeed = nbt.getFloat("ExpansionSpeed");
|
||||
maxLength = nbt.getFloat("MaxLength");
|
||||
@@ -902,7 +908,8 @@ public class EntityAbilityLaser extends EntityEnergyProjectile {
|
||||
@Override
|
||||
protected void readProjectileNBT(NBTTagCompound nbt) {
|
||||
this.laserWidth = sanitize(nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f, 0.2f, MAX_ENTITY_SIZE);
|
||||
this.prevLaserWidth = this.laserWidth;
|
||||
this.renderLaserWidth = this.laserWidth;
|
||||
this.prevRenderLaserWidth = this.laserWidth;
|
||||
this.expansionSpeed = sanitize(nbt.hasKey("ExpansionSpeed") ? nbt.getFloat("ExpansionSpeed") : 2.0f, 0.1f, MAX_ENTITY_SIZE);
|
||||
this.maxLength = sanitize(nbt.hasKey("MaxLength") ? nbt.getFloat("MaxLength") : 32.0f, 1.0f, MAX_ENTITY_SIZE);
|
||||
this.dirX = nbt.getDouble("DirX");
|
||||
|
||||
@@ -101,12 +101,14 @@ import kamkeel.npcs.network.packets.request.category.CategoryListRequestPacket;
|
||||
import kamkeel.npcs.network.packets.request.category.CategoryMoveItemPacket;
|
||||
import kamkeel.npcs.network.packets.request.category.CategoryRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.category.CategorySavePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CopyAbilityScriptsPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilityClonePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilityGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilityRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.CustomAbilitySavePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationClonePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationSavePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationsGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.BuiltInAnimationGetPacket;
|
||||
@@ -498,6 +500,7 @@ public class PacketHandler {
|
||||
REQUEST_PACKET.registerPacket(new AnimationGetPacket());
|
||||
REQUEST_PACKET.registerPacket(new AnimationRemovePacket());
|
||||
REQUEST_PACKET.registerPacket(new AnimationSavePacket());
|
||||
REQUEST_PACKET.registerPacket(new AnimationClonePacket());
|
||||
REQUEST_PACKET.registerPacket(new BuiltInAnimationGetPacket());
|
||||
|
||||
// Moving Path
|
||||
@@ -541,6 +544,7 @@ public class PacketHandler {
|
||||
REQUEST_PACKET.registerPacket(new ChainedAbilityRemovePacket());
|
||||
REQUEST_PACKET.registerPacket(new CustomAbilityClonePacket());
|
||||
REQUEST_PACKET.registerPacket(new ChainedAbilityClonePacket());
|
||||
REQUEST_PACKET.registerPacket(new CopyAbilityScriptsPacket());
|
||||
|
||||
// Category Packets
|
||||
REQUEST_PACKET.registerPacket(new CategorySavePacket());
|
||||
|
||||
@@ -93,6 +93,7 @@ public enum EnumRequestPacket {
|
||||
AnimationGet,
|
||||
AnimationRemove,
|
||||
AnimationSave,
|
||||
AnimationClone,
|
||||
BuiltInAnimationGet,
|
||||
|
||||
RemoteNpcsGet,
|
||||
@@ -226,6 +227,7 @@ public enum EnumRequestPacket {
|
||||
|
||||
CustomAbilityClone,
|
||||
ChainedAbilityClone,
|
||||
CopyAbilityScripts,
|
||||
LinkedItemClone,
|
||||
EffectClone,
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
package kamkeel.npcs.network.packets.request.ability;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.Ability;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ChainedAbility;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import kamkeel.npcs.util.ByteBufUtils;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.CustomNpcsPermissions;
|
||||
import noppes.npcs.controllers.data.AbilityScript;
|
||||
import noppes.npcs.controllers.data.ChainedAbilityScript;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Copies script data from a source ability/chain to a target UUID.
|
||||
* Used when cloning into an NPC as inline - the clone gets a new UUID
|
||||
* but needs the source's script handler copied server-side (scripts are never sent to client).
|
||||
*
|
||||
* Mode 0 = ability scripts, Mode 1 = chained ability scripts.
|
||||
*/
|
||||
public final class CopyAbilityScriptsPacket extends AbstractPacket {
|
||||
public static String packetName = "Request|CopyAbilityScripts";
|
||||
|
||||
public static final int MODE_ABILITY = 0;
|
||||
public static final int MODE_CHAINED = 1;
|
||||
|
||||
private int mode;
|
||||
private String sourceName;
|
||||
private String targetId;
|
||||
|
||||
public CopyAbilityScriptsPacket() {
|
||||
}
|
||||
|
||||
public CopyAbilityScriptsPacket(String sourceName, String targetId) {
|
||||
this(MODE_ABILITY, sourceName, targetId);
|
||||
}
|
||||
|
||||
public CopyAbilityScriptsPacket(int mode, String sourceName, String targetId) {
|
||||
this.mode = mode;
|
||||
this.sourceName = sourceName;
|
||||
this.targetId = targetId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumRequestPacket.CopyAbilityScripts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.REQUEST_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomNpcsPermissions.Permission getPermission() {
|
||||
return CustomNpcsPermissions.GLOBAL_ABILITY;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
out.writeByte(mode);
|
||||
ByteBufUtils.writeString(out, sourceName);
|
||||
ByteBufUtils.writeString(out, targetId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
if (!(player instanceof EntityPlayerMP))
|
||||
return;
|
||||
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
int mode = in.readByte();
|
||||
String sourceName = ByteBufUtils.readString(in);
|
||||
String targetId = ByteBufUtils.readString(in);
|
||||
|
||||
if (targetId == null || targetId.isEmpty()) return;
|
||||
|
||||
if (mode == MODE_CHAINED) {
|
||||
copyChainedAbilityScripts(sourceName, targetId);
|
||||
} else {
|
||||
copyAbilityScripts(sourceName, targetId);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyAbilityScripts(String sourceKey, String targetId) {
|
||||
// Try name-based lookup first
|
||||
Ability source = AbilityController.Instance.getCustomAbility(sourceKey);
|
||||
|
||||
AbilityScript sourceHandler;
|
||||
if (source != null) {
|
||||
sourceHandler = source.getScriptHandler();
|
||||
} else {
|
||||
// sourceKey might be a UUID - try direct handler lookup
|
||||
sourceHandler = AbilityController.Instance.abilityScriptHandlers.get(sourceKey);
|
||||
}
|
||||
if (sourceHandler == null) return;
|
||||
|
||||
NBTTagCompound scriptNbt = sourceHandler.writeToNBT(new NBTTagCompound());
|
||||
AbilityScript targetHandler = new AbilityScript(targetId);
|
||||
targetHandler.readFromNBT(scriptNbt);
|
||||
AbilityController.Instance.abilityScriptHandlers.put(targetId, targetHandler);
|
||||
}
|
||||
|
||||
private void copyChainedAbilityScripts(String sourceName, String targetId) {
|
||||
ChainedAbility source = AbilityController.Instance.getChainedAbility(sourceName);
|
||||
if (source == null) return;
|
||||
|
||||
ChainedAbilityScript sourceHandler = source.getScriptHandler();
|
||||
if (sourceHandler == null) return;
|
||||
|
||||
NBTTagCompound scriptNbt = sourceHandler.writeToNBT(new NBTTagCompound());
|
||||
ChainedAbilityScript targetHandler = new ChainedAbilityScript(targetId);
|
||||
targetHandler.readFromNBT(scriptNbt);
|
||||
AbilityController.Instance.chainedAbilityScriptHandlers.put(targetId, targetHandler);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package kamkeel.npcs.network.packets.request.animation;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import kamkeel.npcs.network.AbstractPacket;
|
||||
import kamkeel.npcs.network.PacketChannel;
|
||||
import kamkeel.npcs.network.PacketHandler;
|
||||
import kamkeel.npcs.network.PacketUtil;
|
||||
import kamkeel.npcs.network.enums.EnumItemPacketType;
|
||||
import kamkeel.npcs.network.enums.EnumRequestPacket;
|
||||
import kamkeel.npcs.network.packets.data.large.GuiDataPacket;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import noppes.npcs.CustomNpcsPermissions;
|
||||
import noppes.npcs.NoppesUtilServer;
|
||||
import noppes.npcs.controllers.AnimationController;
|
||||
import noppes.npcs.controllers.data.Animation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public final class AnimationClonePacket extends AbstractPacket {
|
||||
public static String packetName = "Request|AnimationClone";
|
||||
|
||||
private int id;
|
||||
|
||||
public AnimationClonePacket() {
|
||||
}
|
||||
|
||||
public AnimationClonePacket(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enum getType() {
|
||||
return EnumRequestPacket.AnimationClone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketChannel getChannel() {
|
||||
return PacketHandler.REQUEST_PACKET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomNpcsPermissions.Permission getPermission() {
|
||||
return CustomNpcsPermissions.GLOBAL_ANIMATION;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
@Override
|
||||
public void sendData(ByteBuf out) throws IOException {
|
||||
out.writeInt(this.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveData(ByteBuf in, EntityPlayer player) throws IOException {
|
||||
if (!(player instanceof EntityPlayerMP))
|
||||
return;
|
||||
if (!PacketUtil.verifyItemPacket(packetName, EnumItemPacketType.WAND, player))
|
||||
return;
|
||||
|
||||
int animationId = in.readInt();
|
||||
Animation clone = AnimationController.getInstance().cloneAnimation(animationId);
|
||||
if (clone != null) {
|
||||
NoppesUtilServer.sendAnimationDataAll((EntityPlayerMP) player);
|
||||
GuiDataPacket.sendGuiData((EntityPlayerMP) player, clone.writeToNBT());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import kamkeel.npcs.controllers.data.ability.AbilityVariant;
|
||||
import kamkeel.npcs.controllers.data.ability.data.ChainedAbility;
|
||||
import kamkeel.npcs.controllers.data.ability.data.entry.ChainedAbilityEntry;
|
||||
import kamkeel.npcs.network.PacketClient;
|
||||
import kamkeel.npcs.network.packets.request.ability.CopyAbilityScriptsPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.AbilitiesGetAllPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.AbilitiesNpcGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.ability.AbilitiesNpcSavePacket;
|
||||
@@ -816,6 +817,14 @@ public class GuiNPCAbilities extends GuiNPCInterface2 implements IScrollData, IC
|
||||
* Adds as an inline slot.
|
||||
*/
|
||||
public void loadAbility(Ability loadedAbility) {
|
||||
loadAbility(loadedAbility, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from SubGuiAbilityLoad when a cloned ability is loaded with a known source.
|
||||
* Copies scripts server-side from source to the new inline ability.
|
||||
*/
|
||||
public void loadAbility(Ability loadedAbility, String sourceAbilityName) {
|
||||
if (loadedAbility != null) {
|
||||
loadedAbility.setId(UUID.randomUUID().toString());
|
||||
npcSlots.add(AbilityAction.inline(loadedAbility));
|
||||
@@ -825,6 +834,10 @@ public class GuiNPCAbilities extends GuiNPCInterface2 implements IScrollData, IC
|
||||
selectAbilityByIndex(selectedAbilityIndex);
|
||||
initGui();
|
||||
save();
|
||||
// Copy scripts from source ability server-side (scripts are never sent to client)
|
||||
if (sourceAbilityName != null && !sourceAbilityName.isEmpty()) {
|
||||
PacketClient.sendClient(new CopyAbilityScriptsPacket(sourceAbilityName, loadedAbility.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,12 +994,18 @@ public class GuiNPCAbilities extends GuiNPCInterface2 implements IScrollData, IC
|
||||
if (slot.isChain() && selectedEntryIndex == -1) {
|
||||
// Chain header (must be CHAIN_REFERENCE)
|
||||
if (mode == SubGuiAbilityEditMode.MODE_CLONE_MODIFY) {
|
||||
String sourceChainName = slot.getReferenceId();
|
||||
if (slot.convertToInline()) {
|
||||
ChainedAbility chain = slot.getInlineChain();
|
||||
if (chain != null) {
|
||||
pendingChain = chain;
|
||||
pendingChainSlotIdx = selectedSlotIndex;
|
||||
setSubGui(new SubGuiChainedAbilityConfig(chain, this, true, npcSlots));
|
||||
// Copy chain scripts server-side (client never has script handlers)
|
||||
if (sourceChainName != null && !sourceChainName.isEmpty()) {
|
||||
PacketClient.sendClient(new CopyAbilityScriptsPacket(
|
||||
CopyAbilityScriptsPacket.MODE_CHAINED, sourceChainName, chain.getId()));
|
||||
}
|
||||
}
|
||||
updateNpcAbilitiesList();
|
||||
save();
|
||||
@@ -1015,6 +1034,8 @@ public class GuiNPCAbilities extends GuiNPCInterface2 implements IScrollData, IC
|
||||
ChainedAbility chain = slot.getInlineChain();
|
||||
if (chain != null && selectedEntryIndex < chain.getEntries().size()) {
|
||||
ChainedAbilityEntry entry = chain.getEntries().get(selectedEntryIndex);
|
||||
// Capture source ability reference before convertToInline clears it
|
||||
String sourceAbilityRef = entry.getAbilityReference();
|
||||
if (entry.convertToInline()) {
|
||||
Ability a = entry.getInlineAbility();
|
||||
if (a != null && !a.isBuiltIn()) {
|
||||
@@ -1023,6 +1044,10 @@ public class GuiNPCAbilities extends GuiNPCInterface2 implements IScrollData, IC
|
||||
editChainEntryIdx = selectedEntryIndex;
|
||||
a.setNpcInlineEdit(true);
|
||||
setSubGui(a.createConfigGui(this));
|
||||
// Copy ability scripts server-side (client never has script handlers)
|
||||
if (sourceAbilityRef != null && !sourceAbilityRef.isEmpty()) {
|
||||
PacketClient.sendClient(new CopyAbilityScriptsPacket(sourceAbilityRef, a.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1043,12 +1068,18 @@ public class GuiNPCAbilities extends GuiNPCInterface2 implements IScrollData, IC
|
||||
// Standalone ability reference → convert to inline
|
||||
Ability preCheck = slot.getAbility();
|
||||
if (preCheck != null && preCheck.isBuiltIn()) return;
|
||||
// Capture source reference before convertToInline clears it
|
||||
String sourceAbilityRef = slot.getReferenceId();
|
||||
if (slot.convertToInline()) {
|
||||
Ability ability = slot.getAbility();
|
||||
if (ability != null && !ability.isBuiltIn()) {
|
||||
ability.setId(UUID.randomUUID().toString());
|
||||
// UUID already generated by convertToInline() - don't reassign or script handler is orphaned
|
||||
ability.setNpcInlineEdit(true);
|
||||
setSubGui(ability.createConfigGui(this));
|
||||
// Copy ability scripts server-side (client never has script handlers)
|
||||
if (sourceAbilityRef != null && !sourceAbilityRef.isEmpty()) {
|
||||
PacketClient.sendClient(new CopyAbilityScriptsPacket(sourceAbilityRef, ability.getId()));
|
||||
}
|
||||
}
|
||||
updateNpcAbilitiesList();
|
||||
save();
|
||||
|
||||
@@ -216,7 +216,7 @@ public class SubGuiAbilityLoad extends SubGuiInterface implements ICustomScrollL
|
||||
if (parentConfig != null) {
|
||||
parentConfig.loadAbility(loaded);
|
||||
} else if (parentAbilities != null) {
|
||||
parentAbilities.loadAbility(loaded);
|
||||
parentAbilities.loadAbility(loaded, selectedName);
|
||||
}
|
||||
}
|
||||
close();
|
||||
|
||||
@@ -3,6 +3,7 @@ package noppes.npcs.client.gui.global;
|
||||
import kamkeel.npcs.network.PacketClient;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationRemovePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationClonePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationSavePacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.AnimationsGetPacket;
|
||||
import kamkeel.npcs.network.packets.request.animation.BuiltInAnimationGetPacket;
|
||||
@@ -169,11 +170,7 @@ public class GuiAnimationDirectory extends GuiDirectoryCategorized {
|
||||
protected void onCloneItem() {
|
||||
if (showingBuiltIn || currentIsBuiltIn) return;
|
||||
if (animation != null && animation.id >= 0) {
|
||||
Animation clone = new Animation();
|
||||
clone.readFromNBT(animation.writeToNBT());
|
||||
clone.id = -1;
|
||||
while (itemData.containsKey(clone.name)) clone.name += "_";
|
||||
PacketClient.sendClient(new AnimationSavePacket(clone.writeToNBT()));
|
||||
PacketClient.sendClient(new AnimationClonePacket(animation.id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -544,65 +544,80 @@ public class RenderNPCInterface extends RenderLiving {
|
||||
|
||||
@Override
|
||||
public ResourceLocation getEntityTexture(Entity entity) {
|
||||
|
||||
EntityNPCInterface npc = (EntityNPCInterface) entity;
|
||||
if (npc.textureLocation == null) {
|
||||
if (npc.display.skinType == 0) {
|
||||
|
||||
// Early exit if texture already resolved
|
||||
if (npc.textureLocation != null) {
|
||||
return npc.textureLocation;
|
||||
}
|
||||
|
||||
// SkinType 0: custom texture or default
|
||||
if (npc.display.skinType == 0) {
|
||||
if (npc.display.texture.isEmpty()) {
|
||||
return npc.textureLocation = fallBackSkin(npc);
|
||||
}
|
||||
|
||||
try {
|
||||
if (npc instanceof EntityCustomNpc && ((EntityCustomNpc) npc).modelData.entityClass == null) {
|
||||
if (!(npc.display.texture).isEmpty()) {
|
||||
try {
|
||||
npc.textureLocation = adjustLocalTexture(npc, new ResourceLocation(npc.display.texture));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
npc.textureLocation = adjustLocalTexture(npc, new ResourceLocation(npc.display.texture));
|
||||
} else {
|
||||
npc.textureLocation = new ResourceLocation(npc.display.texture);
|
||||
ResourceLocation resLoc = new ResourceLocation(npc.display.texture);
|
||||
Minecraft.getMinecraft().getResourceManager().getResource(resLoc);
|
||||
npc.textureLocation = resLoc;
|
||||
}
|
||||
} else if (npc.display.skinType == 1 && npc.display.playerProfile != null) {
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
Map map = minecraft.func_152342_ad().func_152788_a(npc.display.playerProfile);
|
||||
if (map.containsKey(Type.SKIN)) {
|
||||
npc.textureLocation = minecraft.func_152342_ad().func_152792_a((MinecraftProfileTexture) map.get(Type.SKIN), Type.SKIN);
|
||||
}
|
||||
LastTextureTick = 0;
|
||||
} else if (npc.display.skinType == 2 || npc.display.skinType == 3) {
|
||||
ResourceLocation location = new ResourceLocation("skins/" + (npc.display.skinType + npc.display.url).hashCode());
|
||||
// If URL Empty Steve
|
||||
if (npc.display.url.isEmpty()) {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
// If URL Cached then grab it
|
||||
else if (ClientCacheHandler.isCachedNPC(location)) {
|
||||
try {
|
||||
ResourceLocation loc = ClientCacheHandler.getNPCTexture(npc.display.url, npc.display.skinType == 3, location).getLocation();
|
||||
if (loc != null) {
|
||||
npc.textureLocation = loc;
|
||||
} else {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
// For New URL Requests do not spam it
|
||||
else if (LastTextureTick < 5) { //fixes request flood somewhat
|
||||
return fallBackSkin(npc);
|
||||
} else {
|
||||
try {
|
||||
ResourceLocation loc = ClientCacheHandler.getNPCTexture(npc.display.url, npc.display.skinType == 3, location).getLocation();
|
||||
if (loc != null) {
|
||||
npc.textureLocation = loc;
|
||||
} else {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
LastTextureTick = 0;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} catch (IOException ignored) {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
}
|
||||
return npc.textureLocation;
|
||||
|
||||
// SkinType 1: player profile skin
|
||||
else if (npc.display.skinType == 1 && npc.display.playerProfile != null) {
|
||||
final Minecraft minecraft = Minecraft.getMinecraft();
|
||||
Map map = minecraft.func_152342_ad().func_152788_a(npc.display.playerProfile);
|
||||
if (map.containsKey(Type.SKIN)) {
|
||||
npc.textureLocation = minecraft.func_152342_ad()
|
||||
.func_152792_a((MinecraftProfileTexture) map.get(Type.SKIN), Type.SKIN);
|
||||
}
|
||||
LastTextureTick = 0;
|
||||
}
|
||||
|
||||
// SkinType 2 / 3: load from URL
|
||||
else if (npc.display.skinType == 2 || npc.display.skinType == 3) {
|
||||
if (npc.display.url.isEmpty()) { // If URL is empty → fallback
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
|
||||
ResourceLocation location = new ResourceLocation("skins/" + (npc.display.skinType + npc.display.url).hashCode());
|
||||
|
||||
try {
|
||||
if (ClientCacheHandler.isCachedNPC(location)) { // If URL is cached
|
||||
ResourceLocation loc = ClientCacheHandler
|
||||
.getNPCTexture(npc.display.url, npc.display.skinType == 3, location)
|
||||
.getLocation();
|
||||
if (loc == null) return fallBackSkin(npc);
|
||||
npc.textureLocation = loc;
|
||||
} else if (LastTextureTick >= 5) { // Prevent request flooding
|
||||
ResourceLocation loc = ClientCacheHandler
|
||||
.getNPCTexture(npc.display.url, npc.display.skinType == 3, location)
|
||||
.getLocation();
|
||||
if (loc == null) return fallBackSkin(npc);
|
||||
npc.textureLocation = loc;
|
||||
LastTextureTick = 0;
|
||||
} else {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: if no valid skin type matched
|
||||
else {
|
||||
return fallBackSkin(npc);
|
||||
}
|
||||
|
||||
// Final safety net
|
||||
return npc.textureLocation == null ? fallBackSkin(npc) : npc.textureLocation;
|
||||
}
|
||||
|
||||
private ResourceLocation adjustLocalTexture(EntityNPCInterface npc, ResourceLocation location) throws IOException {
|
||||
|
||||
@@ -311,6 +311,28 @@ public class AnimationController implements IAnimationHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Animation cloneAnimation(int originalId) {
|
||||
Animation original = animations.get(originalId);
|
||||
if (original == null || original instanceof BuiltInAnimation) return null;
|
||||
|
||||
int originalCatId = categoryManager.getItemCategory(originalId);
|
||||
|
||||
Animation clone = new Animation();
|
||||
clone.readFromNBT(original.writeToNBT());
|
||||
clone.id = getUnusedId();
|
||||
|
||||
String name = clone.name;
|
||||
while (hasName(name)) name += "_";
|
||||
clone.name = name;
|
||||
|
||||
if (originalCatId > CategoryManager.UNCATEGORIZED_ID) {
|
||||
categoryManager.registerItem(clone.id, originalCatId);
|
||||
}
|
||||
|
||||
saveAnimation(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public void delete(String name) {
|
||||
Animation delete = getAnimationFromName(name);
|
||||
if (delete != null) {
|
||||
|
||||
@@ -712,6 +712,8 @@ public class CustomEffectController implements ICustomEffectHandler {
|
||||
CustomEffect original = getCustomEffects().get(originalId);
|
||||
if (original == null) return null;
|
||||
|
||||
int originalCatId = categoryManager.getItemCategory(originalId);
|
||||
|
||||
NBTTagCompound nbt = original.writeToNBT(true);
|
||||
int newId = getUnusedId();
|
||||
nbt.setInteger("ID", newId);
|
||||
@@ -723,6 +725,10 @@ public class CustomEffectController implements ICustomEffectHandler {
|
||||
while (has(name)) name += "_";
|
||||
clone.name = name;
|
||||
|
||||
if (originalCatId > CategoryManager.UNCATEGORIZED_ID) {
|
||||
categoryManager.registerItem(newId, originalCatId);
|
||||
}
|
||||
|
||||
saveEffect(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -245,6 +245,8 @@ public class LinkedItemController implements ILinkedItemHandler {
|
||||
LinkedItem original = linkedItems.get(originalId);
|
||||
if (original == null) return null;
|
||||
|
||||
int originalCatId = categoryManager.getItemCategory(originalId);
|
||||
|
||||
NBTTagCompound nbt = original.writeToNBT(true);
|
||||
int newId = getUnusedId();
|
||||
nbt.setInteger("Id", newId);
|
||||
@@ -256,6 +258,10 @@ public class LinkedItemController implements ILinkedItemHandler {
|
||||
while (hasName(name)) name += "_";
|
||||
clone.name = name;
|
||||
|
||||
if (originalCatId > CategoryManager.UNCATEGORIZED_ID) {
|
||||
categoryManager.registerItem(newId, originalCatId);
|
||||
}
|
||||
|
||||
saveLinkedItem(clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package noppes.npcs.controllers.data;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraftforge.common.util.Constants;
|
||||
import noppes.npcs.api.handler.data.IQuest;
|
||||
import noppes.npcs.api.handler.data.IQuestCategory;
|
||||
|
||||
@@ -21,8 +22,8 @@ public class QuestCategory implements IQuestCategory {
|
||||
public void readNBT(NBTTagCompound nbttagcompound) {
|
||||
id = nbttagcompound.getInteger("Slot");
|
||||
title = nbttagcompound.getString("Title");
|
||||
NBTTagList questList = nbttagcompound.getTagList("Quests", 10);
|
||||
if (questList != null) {
|
||||
NBTTagList questList = getFirstValidList(nbttagcompound, Constants.NBT.TAG_COMPOUND, "Quests", "Dialogs");
|
||||
if (questList.tagCount() > 0) {
|
||||
for (int ii = 0; ii < questList.tagCount(); ii++) {
|
||||
NBTTagCompound nbttagcompound2 = questList.getCompoundTagAt(ii);
|
||||
Quest quest = new Quest();
|
||||
@@ -33,6 +34,18 @@ public class QuestCategory implements IQuestCategory {
|
||||
}
|
||||
}
|
||||
|
||||
private NBTTagList getFirstValidList(NBTTagCompound nbt, int type, String... keys) {
|
||||
for (String key : keys) {
|
||||
if (nbt.hasKey(key, Constants.NBT.TAG_LIST)) {
|
||||
NBTTagList list = nbt.getTagList(key, type);
|
||||
if (list.tagCount() > 0) {
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new NBTTagList();
|
||||
}
|
||||
|
||||
public NBTTagCompound writeNBT(NBTTagCompound nbttagcompound) {
|
||||
nbttagcompound.setInteger("Slot", id);
|
||||
nbttagcompound.setString("Title", title);
|
||||
|
||||
Reference in new issue
Block a user