Files
CustomNPC-Plus/src/main/java/kamkeel/npcs/controllers/data/ability/AbilitySlot.java
T

157 lines
5.1 KiB
Java

package kamkeel.npcs.controllers.data.ability;
import net.minecraft.nbt.NBTTagCompound;
/**
* Wrapper that stores either an inline ability (full NBT) or a reference
* to a built-in/custom ability (by name or UUID).
* <p>
* References are lazy-resolved via {@link AbilityController#resolveAbility(String)}
* and cached until the controller version changes.
*/
public class AbilitySlot {
private Ability inlineAbility;
private String referenceId;
/** Per-slot enabled override for reference slots (null = use master's default). */
private Boolean enabledOverride;
private transient Ability cachedAbility;
private transient int cachedVersion = -1;
private AbilitySlot() {}
/**
* Create a slot with an inline (embedded) ability.
*/
public static AbilitySlot inline(Ability ability) {
AbilitySlot slot = new AbilitySlot();
slot.inlineAbility = ability;
slot.referenceId = null;
return slot;
}
/**
* Create a slot that references a built-in ability (by name) or custom ability (by name).
*/
public static AbilitySlot reference(String referenceId) {
AbilitySlot slot = new AbilitySlot();
slot.inlineAbility = null;
slot.referenceId = referenceId;
return slot;
}
public boolean isReference() {
return referenceId != null;
}
public String getReferenceId() {
return referenceId;
}
/**
* Get the resolved ability. For inline slots, returns the ability directly.
* For reference slots, lazily resolves from AbilityController and caches.
* Returns null if the reference cannot be resolved (broken ref).
*/
public Ability getAbility() {
if (!isReference()) {
return inlineAbility;
}
// Lazy resolve with version-based cache invalidation
AbilityController controller = AbilityController.Instance;
if (controller == null) return null;
int currentVersion = controller.getCustomAbilityRevision();
if (cachedAbility != null && cachedVersion == currentVersion) {
return cachedAbility;
}
cachedAbility = controller.resolveAbility(referenceId);
// Apply per-slot enabled override so NPC-specific enable/disable persists
if (cachedAbility != null && enabledOverride != null) {
cachedAbility.setEnabled(enabledOverride);
}
cachedVersion = currentVersion;
return cachedAbility;
}
/**
* Set the per-slot enabled override for reference slots.
* For inline slots, delegates directly to the ability.
*/
public void setEnabled(boolean enabled) {
if (!isReference()) {
if (inlineAbility != null) {
inlineAbility.setEnabled(enabled);
}
} else {
this.enabledOverride = enabled;
// Also update the cached ability immediately if present
if (cachedAbility != null) {
cachedAbility.setEnabled(enabled);
}
}
}
/**
* Get the inline ability directly (null for reference slots).
*/
public Ability getInlineAbility() {
return inlineAbility;
}
/**
* Convert this reference slot to an inline slot by copying the resolved ability.
* No-op if already inline. Returns false if resolution fails.
*/
public boolean convertToInline() {
if (!isReference()) return true;
Ability resolved = getAbility();
if (resolved == null) return false;
// Deep copy via NBT round-trip
inlineAbility = AbilityController.Instance.fromNBT(resolved.writeNBT());
referenceId = null;
cachedAbility = null;
cachedVersion = -1;
return true;
}
// ═══════════════════════════════════════════════════════════════════
// NBT
// ═══════════════════════════════════════════════════════════════════
public NBTTagCompound writeNBT() {
if (isReference()) {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setString("Reference", referenceId);
if (enabledOverride != null) {
nbt.setBoolean("RefEnabled", enabledOverride);
}
return nbt;
}
return inlineAbility != null ? inlineAbility.writeNBT() : new NBTTagCompound();
}
public static AbilitySlot fromNBT(NBTTagCompound nbt) {
if (nbt == null) return null;
if (nbt.hasKey("Reference")) {
AbilitySlot slot = reference(nbt.getString("Reference"));
if (nbt.hasKey("RefEnabled")) {
slot.enabledOverride = nbt.getBoolean("RefEnabled");
}
return slot;
}
// Inline ability
Ability ability = AbilityController.Instance.fromNBT(nbt);
if (ability == null) return null;
return inline(ability);
}
}