mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 08:27:45 +00:00
157 lines
5.1 KiB
Java
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);
|
|
}
|
|
}
|