/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.providers.npc.traits; import com.jcwhatever.nucleus.mixins.IDisposable; import com.jcwhatever.nucleus.mixins.INamed; import com.jcwhatever.nucleus.providers.npc.INpc; import com.jcwhatever.nucleus.providers.npc.INpcRegistry; import com.jcwhatever.nucleus.providers.npc.events.NpcDespawnEvent.NpcDespawnReason; import com.jcwhatever.nucleus.providers.npc.events.NpcSpawnEvent.NpcSpawnReason; import com.jcwhatever.nucleus.storage.IDataNode; import com.jcwhatever.nucleus.utils.PreCon; /** * Abstract implementation of an NPC Trait. * * <p>The name of the trait is the same as the parent {@link NpcTraitType}</p> * * <p>The {@link NpcTrait} can optionally implement the {@link java.lang.Runnable} * interface. If this is the case, the {@link java.lang.Runnable#run} method is called * every tick while the NPC is spawned so long as {@link #canRun} returns true.</p> * * <p>The trait may also be reused for a different Npc. The trait is only ever used for * one Npc at a time, but can be reused for a different NPC once its current NPC is disposed. * If the trait cannot be reused, override the {@link #isReusable} method and return false.</p> * * <p>Whenever the trait is assigned to an {@link INpc}, the {@link #onAttach} method is invoked. This * method is intended for optional override and passes the new {@link INpc} as argument.</p> */ public abstract class NpcTrait implements INamed, IDisposable { private final NpcTraitType _type; private INpc _npc; private boolean _isEnabled = true; private boolean _isDisposed; /** * Constructor. * * @param type The parent type that instantiated the trait. */ public NpcTrait(NpcTraitType type) { PreCon.notNull(type, "type"); _type = type; } @Override public final String getName() { return _type.getName(); } /** * Get the traits lookup name. */ public final String getLookupName() { return _type.getLookupName(); } /** * Get the NPC the trait was instantiated for. */ public final INpc getNpc() { return _npc; } /** * Get the registry of the NPC the trait was instantiated for. */ public final INpcRegistry getRegistry() { return _npc.getRegistry(); } /** * Get the trait type. */ public final NpcTraitType getType() { return _type; } /** * Determine if the trait can be reused for a different NPC after its current * NPC is disposed. * * @return Returns true. Override to change to false. */ public boolean isReusable() { return true; } /** * Determine if the trait is enabled. */ public boolean isEnabled() { return _isEnabled; } /** * Set the traits enabled state. * * @param isEnabled True to enable, false to disable. * * @return Self for chaining. */ public NpcTrait setEnabled(boolean isEnabled) { if (isEnabled) enable(); else disable(); return this; } /** * Enable the trait. * * @return Self for chaining. */ public NpcTrait enable() { if (!_isDisposed && !_isEnabled) { _isEnabled = true; onEnable(); } return this; } /** * Disable the trait. * * @return Self for chaining. */ public NpcTrait disable() { if (!_isDisposed && _isEnabled) { _isEnabled = false; onDisable(); } return this; } /** * Determine if the Trait should be run. * * <p>Used when the trait implements {@link java.lang.Runnable} to * determine if the trait wants to be run. This is always checked * before {@link java.lang.Runnable#run} is invoked.</p> * * <p>The default implementation always returns true if the trait implements * {@link java.lang.Runnable}.</p> */ public boolean canRun() { return this instanceof Runnable && _isEnabled; } /** * Save the trait settings to an {@link IDataNode}. * * <p>Default implementation does nothing. Intended for optional * override.</p> * * @param dataNode The data node to save to. */ public void save(IDataNode dataNode) { PreCon.notNull(dataNode); } /** * Load trait settings from an {@link IDataNode}. * * <p>Default implementation does nothing. Intended for optional * override.</p> * * @param dataNode The data node to load from. */ public void load(IDataNode dataNode) { PreCon.notNull(dataNode); } @Override public final boolean isDisposed() { return _isDisposed; } /** * @inheritDoc * * <p>Note that the trait may be un-disposed if the provider reuses it. * This can be detected by overriding {@link #onAttach}.</p> */ @Override public final void dispose() { if (_isDisposed) return; INpc npc = getNpc(); if (npc != null) { getNpc().getTraits().remove(getName()); } if (_isEnabled) { disable(); } _isDisposed = true; } /** * Invoked when the trait is attached to an {@link INpc}. * * <p>Intended for optional override.</p> * * @param npc The npc that trait is being attached to. */ protected void onAttach(INpc npc) {} /** * Invoked when the trait is detached from an {@link INpc} and/or * disposed. * * <p>Intended for optional override.</p> */ protected void onDetach() {} /** * Invoked when traits NPC is spawned. * * <p>Intended for optional override.</p> */ protected void onSpawn(NpcSpawnReason reason) {} /** * Invoked when the traits NPC is despawned. * * <p>Intended for optional override.</p> */ protected void onDespawn(NpcDespawnReason reason) {} /** * Invoked when the trait is enabled. * * <p>Intended for optional override.</p> */ protected void onEnable() {} /** * Invoked when the trait is disabled. * * <p>Intended for optional override.</p> */ protected void onDisable() {} /** * Initialize the trait or re-init. * * @param npc The NPC the trait is added to. */ void init(INpc npc) { PreCon.notNull(npc); if (!isReusable() && _npc != null) throw new IllegalStateException("Trait is not reusable."); _isDisposed = false; _npc = npc; onAttach(npc); } /** * Set the traits dispose flag to true. */ void setDisposeFlag() { _isDisposed = true; } }