/* * 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.internal.managed.scripting.api; import com.jcwhatever.nucleus.Nucleus; import com.jcwhatever.nucleus.managed.scripting.regions.IScriptRegion; import com.jcwhatever.nucleus.mixins.IDisposable; import com.jcwhatever.nucleus.regions.IRegion; import com.jcwhatever.nucleus.regions.IRegionEventHandler; import com.jcwhatever.nucleus.regions.options.EnterRegionReason; import com.jcwhatever.nucleus.regions.options.LeaveRegionReason; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.observer.script.IScriptUpdateSubscriber; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import java.util.ArrayDeque; import java.util.Deque; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.annotation.Nullable; /** * General API for {@link IRegion}'s. */ public class SAPI_Regions implements IDisposable { private Set<IScriptRegion> _referencedRegions = new HashSet<>(15); private final Deque<ScriptRegionEvents> _eventHandlers = new ArrayDeque<>(15); private boolean _isDisposed; @Override public boolean isDisposed() { return _isDisposed; } @Override public void dispose() { while (!_eventHandlers.isEmpty()) { _eventHandlers.remove().dispose(); } for (IScriptRegion region : _referencedRegions) { region.dispose(); } _referencedRegions = null; _isDisposed = true; } /** * Get a script region by name. * * @param name The name of the script region. */ public IScriptRegion get(String name) { PreCon.notNullOrEmpty(name); IScriptRegion region = Nucleus.getScriptManager().getRegions().get(name); PreCon.isValid(region != null, "Region named '{0}' not found.", name); _referencedRegions.add(region); return region; } /** * Get a region by plugin name and region name. * * @param pluginName The name of the regions owning plugin. * @param regionName The name of the region. * * @return The region. */ public IRegion get(String pluginName, String regionName) { PreCon.notNullOrEmpty(pluginName, "pluginName"); PreCon.notNullOrEmpty(regionName, "regionName"); Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName); PreCon.isValid(plugin != null, "Plugin named '{0}' not found.", pluginName); List<IRegion> regions = Nucleus.getRegionManager().getRegions(plugin, regionName); PreCon.isValid(!regions.isEmpty(), "Region named '{0}' from plugin named '{1}' not found.", regionName, pluginName); PreCon.isValid(regions.size() == 1, "More than 1 region named '{0}' from plugin named '{1}' was found.", regionName, pluginName); return regions.get(0); } /** * Add a handler to execute whenever a player enters a script region. * * @param regionName The name of the script region. * @param onEnter The handler. */ public void onEnter(String regionName, IScriptUpdateSubscriber<Player> onEnter) { PreCon.notNullOrEmpty(regionName); PreCon.notNull(onEnter); IScriptRegion region = Nucleus.getScriptManager().getRegions().get(regionName); if (region == null) { throw new RuntimeException("Failed to find quest region named:" + regionName); } region.onEnter(onEnter); _referencedRegions.add(region); } /** * Attach an event handler to a region to be called when a player enters it. * * @param pluginName The name of the regions owning plugin. * @param regionName The name of the region. * @param enterHandler The event handler. */ public void onEnter(String pluginName, String regionName, IScriptRegionEnter enterHandler) { IRegion region = get(pluginName, regionName); ScriptRegionEvents handler = new ScriptRegionEvents(region, enterHandler, null); region.addEventHandler(handler); _eventHandlers.add(handler); } /** * Add a handler to execute whenever a player leaves a script region. * * @param regionName The name of the script region. * @param onLeave The handler. */ public void onLeave(String regionName, IScriptUpdateSubscriber<Player> onLeave) { PreCon.notNullOrEmpty(regionName); PreCon.notNull(onLeave); IScriptRegion region = Nucleus.getScriptManager().getRegions().get(regionName); if (region == null) { throw new RuntimeException("Failed to find quest region named:" + regionName); } region.onLeave(onLeave); _referencedRegions.add(region); } /** * Attach an event handler to a region to be called when a player leaves it. * * @param pluginName The name of the regions owning plugin. * @param regionName The name of the region. * @param leaveHandler The event handler. */ public void onLeave(String pluginName, String regionName, IScriptRegionLeave leaveHandler) { IRegion region = get(pluginName, regionName); ScriptRegionEvents handler = new ScriptRegionEvents(region, null, leaveHandler); region.addEventHandler(handler); _eventHandlers.add(handler); } public interface IScriptRegionEnter { void onEnter(Player player, EnterRegionReason reason); } public interface IScriptRegionLeave { void onLeave(Player player, LeaveRegionReason reason); } private static class ScriptRegionEvents implements IRegionEventHandler, IDisposable { private final IRegion region; private final IScriptRegionEnter enter; private final IScriptRegionLeave leave; private boolean isDisposed; ScriptRegionEvents(IRegion region, @Nullable IScriptRegionEnter enter, @Nullable IScriptRegionLeave leave) { this.region = region; this.enter = enter; this.leave = leave; } public IRegion getRegion() { return region; } @Override public boolean canDoPlayerEnter(Player player, EnterRegionReason reason) { return enter != null; } @Override public boolean canDoPlayerLeave(Player player, LeaveRegionReason reason) { return leave != null; } @Override public void onPlayerEnter(Player player, EnterRegionReason reason) { assert enter != null; enter.onEnter(player, reason); } @Override public void onPlayerLeave(Player player, LeaveRegionReason reason) { assert leave != null; leave.onLeave(player, reason); } @Override public boolean isDisposed() { return this.isDisposed; } @Override public void dispose() { region.removeEventHandler(this); this.isDisposed = true; } } }