Trigger system rewrite; #452; #782; #

This commit is contained in:
Daniel Saukel 2023-11-02 05:50:56 +01:00
parent 82ac4c47b6
commit d25c446dcf
80 changed files with 1797 additions and 1362 deletions

View File

@ -2,12 +2,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-adapter</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>

View File

@ -15,6 +15,7 @@ import de.erethon.bedrock.compatibility.Internals;
import de.erethon.bedrock.plugin.EPlugin;
import de.erethon.bedrock.plugin.EPluginSettings;
import de.erethon.bedrock.misc.Registry;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxxl.requirement.*;
import de.erethon.dungeonsxxl.sign.*;
import de.erethon.dungeonsxxl.util.GlowUtil;
@ -91,4 +92,8 @@ public class DungeonsXXL extends EPlugin implements DungeonModule {
public void initGameRules(Registry<String, GameRule> registry) {
}
@Override
public void initTriggers(Registry<Character, Class<? extends Trigger>> triggerRegistry) {
}
}

View File

@ -10,9 +10,8 @@ import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.sign.passive.InteractSign;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.util.BlockUtilCompat;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.block.Sign;
/**
@ -53,12 +52,9 @@ public class InteractWallSign extends InteractSign {
@Override
public void initialize() {
InteractTrigger trigger = InteractTrigger.getOrCreate(NumberUtil.parseInt(getSign().getLine(1)),
BlockUtilCompat.getAttachedBlock(getSign().getBlock()), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
String id = getSign().getLine(1);
InteractTrigger trigger = (InteractTrigger) getGameWorld().createTrigger(this, LogicalExpression.parse("I" + id));
trigger.setInteractBlock(BlockUtilCompat.getAttachedBlock(getSign().getBlock()));
}
}

View File

@ -10,7 +10,7 @@
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<modules>
<module>core</module>
@ -20,7 +20,7 @@
<dependency>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-dist</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>

View File

@ -2,12 +2,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-api</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<build>
<plugins>

View File

@ -17,6 +17,7 @@ package de.erethon.dungeonsxl.api;
import de.erethon.bedrock.misc.Registry;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.Trigger;
/**
* Class that manages initialization of several registries.
@ -55,4 +56,11 @@ public interface DungeonModule {
*/
void initGameRules(Registry<String, GameRule> gameRuleRegistry);
/**
* Initializes the {@link de.erethon.dungeonsxl.api.trigger.Trigger trigger} registry.
*
* @param triggerRegistry the registry
*/
void initTriggers(Registry<Character, Class<? extends Trigger>> triggerRegistry);
}

View File

@ -14,9 +14,9 @@
*/
package de.erethon.dungeonsxl.api;
import de.erethon.bedrock.misc.Registry;
import de.erethon.caliburn.CaliburnAPI;
import de.erethon.caliburn.mob.ExMob;
import de.erethon.bedrock.misc.Registry;
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
@ -27,6 +27,7 @@ import de.erethon.dungeonsxl.api.player.PlayerCache;
import de.erethon.dungeonsxl.api.player.PlayerClass;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.world.EditWorld;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
@ -132,6 +133,13 @@ public interface DungeonsAPI extends Plugin {
*/
Registry<String, GameRule> getGameRuleRegistry();
/**
* Returns a registry of the triggers.
*
* @return a registry of the triggers
*/
Registry<Character, Class<? extends Trigger>> getTriggerRegistry();
/**
* Returns a registry of the external mob providers.
*

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.trigger;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import java.util.List;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Fired when a {@link Trigger} is satisfied.
*
* @author Daniel Saukel
*/
public class TriggerActionEvent extends TriggerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
private List<TriggerListener> fired;
public TriggerActionEvent(Trigger trigger, List<TriggerListener> fired) {
super(trigger);
this.fired = fired;
}
/**
* Returns a List of the fired listeners, e.g. the dungeon signs that are triggered because all their trigger expression is fully satisfied.
*
* @return a List of the fired listeners
*/
public List<TriggerListener> getFiredListeners() {
return fired;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{trigger=" + trigger + "}";
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.trigger;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import org.bukkit.event.Event;
/**
* Superclass for events involving triggers.
*
* @author Daniel Saukel
*/
public abstract class TriggerEvent extends Event {
protected Trigger trigger;
protected TriggerEvent(Trigger trigger) {
this.trigger = trigger;
}
/**
* Returns the Trigger involved in this event.
*
* @return the trigger involved in this event
*/
public Trigger getTrigger() {
return trigger;
}
/**
* Sets the trigger involved in this event to the given value.
*
* @param trigger the trigger to set
*/
public void setTrigger(Trigger trigger) {
this.trigger = trigger;
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.trigger;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Fired when a {@link Trigger} is created.
*
* @author Daniel Saukel
*/
public class TriggerRegistrationEvent extends TriggerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public TriggerRegistrationEvent(Trigger trigger) {
super(trigger);
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{trigger=" + trigger + "}";
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.event.trigger;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* Fired when a {@link Trigger} is unregistered.
*
* @author Daniel Saukel
*/
public class TriggerUnregistrationEvent extends TriggerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public TriggerUnregistrationEvent(Trigger trigger) {
super(trigger);
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public String toString() {
return getClass().getSimpleName() + "{trigger=" + trigger + "}";
}
}

View File

@ -14,16 +14,18 @@
*/
package de.erethon.dungeonsxl.api.sign;
import de.erethon.caliburn.item.VanillaItem;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.caliburn.item.VanillaItem;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.Trigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.world.EditWorld;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.block.Sign;
/**
@ -43,7 +45,8 @@ public abstract class AbstractDSign implements DungeonSign {
private String[] lines;
private InstanceWorld instance;
String worldName;
private Set<Trigger> triggers = new HashSet<>();
private LogicalExpression triggerExpression;
private List<Trigger> triggers;
private boolean initialized;
private boolean erroneous;
@ -65,6 +68,11 @@ public abstract class AbstractDSign implements DungeonSign {
return lines;
}
@Override
public Location getLocation() {
return sign.getLocation();
}
@Override
public EditWorld getEditWorld() {
return instance instanceof EditWorld ? (EditWorld) instance : null;
@ -76,25 +84,45 @@ public abstract class AbstractDSign implements DungeonSign {
}
@Override
public Set<Trigger> getTriggers() {
public LogicalExpression getTriggerExpression() {
return triggerExpression;
}
@Override
public List<Trigger> getTriggers() {
if (triggers != null) {
return triggers;
}
List<LogicalExpression> contents = triggerExpression.getContents(true);
triggers = new ArrayList<>(contents.size());
contents.forEach(e -> triggers.add(e.toTrigger(api, this, false)));
return triggers;
}
@Override
public void addTrigger(Trigger trigger) {
triggers.add(trigger);
}
@Override
public void removeTrigger(Trigger trigger) {
triggers.remove(trigger);
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void updateTriggers(Trigger lastFired) {
if (isErroneous()) {
return;
}
if (!triggerExpression.isSatisfied()) {
return;
}
try {
trigger(lastFired != null ? lastFired.getTriggeringPlayer() : null);
} catch (Exception exception) {
markAsErroneous("An error occurred while triggering a sign of the type " + getName()
+ ". This is not a user error. Please report the following stacktrace to the developer of the plugin:");
exception.printStackTrace();
}
}
@Override
public boolean setToAir() {
sign.getBlock().setType(VanillaItem.AIR.getMaterial());

View File

@ -14,20 +14,16 @@
*/
package de.erethon.dungeonsxl.api.sign;
import de.erethon.dungeonsxl.api.Trigger;
import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.world.EditWorld;
import de.erethon.dungeonsxl.api.world.GameWorld;
import java.util.Set;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
/**
* Interface for all dungeon signs.
*
* @author Frank Baumann, Milan Albrecht, Daniel Saukel
*/
public interface DungeonSign {
public interface DungeonSign extends TriggerListener {
/**
* Returns the name to identify the sign.
@ -57,6 +53,18 @@ public interface DungeonSign {
*/
boolean isProtected();
/**
* Returns true if the fourth line of the sign that usually contains the trigger is used differently.
*
* @deprecated This is overriden by interact signs, but it is strongly advised to stick to the convention to fetch data only from the second and third line.
*
* @return true if the fourth line of the sign that usually contains the trigger is used differently
*/
@Deprecated
default boolean isTriggerLineDisabled() {
return false;
}
/**
* Returns if the block type of the sign is set to air after the initialization.
*
@ -101,99 +109,6 @@ public interface DungeonSign {
*/
EditWorld getEditWorld();
/**
* Returns the game world this sign is in; null if this is in an edit world.
*
* @return the game world this sign is in; null if this is in an edit world
*/
GameWorld getGameWorld();
/**
* Returns the game played in the world of this sign.
*
* @return the game played in the world of this sign
*/
default Game getGame() {
return getGameWorld().getGame();
}
/**
* Returns a Set of the triggers registered for this sign.
*
* @return a Set of the triggers registered for this sign
*/
Set<Trigger> getTriggers();
/**
* Returns if the sign has triggers.
*
* @return if the sign has triggers
*/
default boolean hasTriggers() {
return !getTriggers().isEmpty();
}
/**
* Adds a trigger to the sign.
*
* @param trigger the trigger
*/
void addTrigger(Trigger trigger);
/**
* Attempts to remove a trigger from the sign.
*
* @param trigger the trigger
*/
void removeTrigger(Trigger trigger);
/**
* Makes the sign listen for its triggers if it {@link #hasTriggers()}.
* <p>
* {@link #trigger(org.bukkit.entity.Player)}s the sign if it does not have any triggers.
* (Note that some signs have interaction triggers by default, like ready signs).
*/
void initialize();
/**
* Returns if the sign is {@link #initialize()}d.
*
* @return if the sign is {@link #initialize()}d
*/
boolean isInitialized();
/**
* Triggers the sign. The effects are defined by the implementation.
*
* @param player the player who triggered the sign or null if no one in particular triggered it
*/
void trigger(Player player);
/**
* Checks if the triggers of the sign have been triggered. If they all are, the sign itself is triggered.
*
* @param lastFired the last trigger that has been triggered
*/
default void updateTriggers(Trigger lastFired) {
if (isErroneous()) {
return;
}
for (Trigger trigger : getTriggers()) {
if (!trigger.isTriggered()) {
return;
}
}
try {
trigger(lastFired != null ? lastFired.getPlayer() : null);
} catch (Exception exception) {
markAsErroneous("An error occurred while triggering a sign of the type " + getName()
+ ". This is not a user error. Please report the following stacktrace to the developer of the plugin:");
exception.printStackTrace();
}
}
/**
* Sets the sign to air if it is not erroneous and if its type requires this.
* <p>

View File

@ -15,7 +15,7 @@
package de.erethon.dungeonsxl.api.sign;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.Trigger;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.trigger;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.event.trigger.TriggerUnregistrationEvent;
import de.erethon.dungeonsxl.api.world.GameWorld;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
* Skeletal implementation of {@link Trigger}.
*
* @author Daniel Saukel, Frank Baumann, Milan Albrecht
*/
public abstract class AbstractTrigger implements Trigger {
private Set<TriggerListener> listeners = new HashSet<>();
private GameWorld gameWorld;
private LogicalExpression expression;
private String value;
private Player player;
protected AbstractTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
listeners.add(owner);
gameWorld = owner.getGameWorld();
this.expression = expression;
expression.setTrigger(this);
this.value = value;
}
@Override
public String getValue() {
return value;
}
@Override
public GameWorld getGameWorld() {
return gameWorld;
}
@Override
public boolean isTriggered() {
return expression.isSatisfied();
}
@Override
public void setTriggered(boolean triggered) {
expression.setSatisfied(triggered);
}
@Override
public Player getTriggeringPlayer() {
return player;
}
@Override
public void setTriggeringPlayer(Player player) {
this.player = player;
}
@Override
public Set<TriggerListener> getListeners() {
return listeners;
}
@Override
public boolean addListener(TriggerListener owner) {
return listeners.add(owner);
}
@Override
public boolean removeListener(TriggerListener listener) {
return listeners.remove(listener);
}
@Override
public boolean unregisterTrigger() {
TriggerUnregistrationEvent event = new TriggerUnregistrationEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
return gameWorld.unregisterTrigger(this);
}
return false;
}
@Override
public void updateListeners() {
for (TriggerListener dSign : listeners.toArray(TriggerListener[]::new)) {
dSign.updateTriggers(this);
}
}
@Override
public String toString() {
return getClass().getSimpleName() + "{expression=" + expression + "}";
}
}

View File

@ -0,0 +1,334 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.trigger;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.world.GameWorld;
import java.util.ArrayList;
import java.util.List;
/**
* This class represents a logical expression of elements in an AND and OR relation to each other.
* <p>
* Valid operators are:
* <ul>
* <li>, = AND</li>
* <li>/ = OR</li>
* <li>() = priority</li>
* </ul>
* OR is prioritized over AND if no brackets indicate otherwise.
* <p>
* Logical expressions tolerate spaces and redundant operators, but no wrong brackets.
*
* @author Daniel Saukel
*/
public class LogicalExpression {
private enum ComponentType {
FIRST,
AND,
OR;
@Override
public String toString() {
return this == FIRST ? "" : name() + ":";
}
}
/**
* A satisfied, empty expression.
*/
public static final LogicalExpression EMPTY = new LogicalExpression(ComponentType.FIRST, "");
static {
EMPTY.satisfied = true;
}
private ComponentType type;
private String text;
private Trigger trigger;
private List<LogicalExpression> contents;
private boolean satisfied;
private LogicalExpression(ComponentType type, String text) {
this.type = type;
this.text = text;
contents = new ArrayList<>();
}
/**
* Interpretes the given string as a expression.
*
* @param string the string to parse
* @throws IllegalArgumentException if the string is not a valid logical expression.
* @return a expression that represents the given string; null if erroneous
*/
public static LogicalExpression parse(String string) {
if (string == null || string.isBlank()) {
return null;
}
string = string.replace(" ", "");
// Crop redundant end
int i = string.length() - 1;
while (string.charAt(i) == ',' || string.charAt(i) == '/') {
i--;
}
string = string.substring(0, i + 1);
return parse(ComponentType.FIRST, string);
}
private static LogicalExpression parse(ComponentType type, String string) {
LogicalExpression root = new LogicalExpression(type, string);
if (!string.contains(",") && !string.contains("/")) {
return root;
}
int i = 0;
int bracketStart = -1;
int innerBrackets = 0;
int currentCompStart = 0;
boolean bracketLegal = true;
ComponentType currentCompType = ComponentType.FIRST;
while (string.length() > i) {
char c = string.charAt(i);
if (c == '(') {
if (!bracketLegal) {
throw new IllegalArgumentException("Bracket on illegal position at index " + i);
}
if (bracketStart == -1) {
bracketStart = i + 1; // One after bracket start
} else {
innerBrackets++;
}
} else if (c == ')') {
if (bracketStart == -1) {
throw new IllegalArgumentException("Closed bracket before it was opened at index " + i);
}
innerBrackets--;
if (innerBrackets == -1) {
// Bracket closed
LogicalExpression subexpression = parse(currentCompType, string.substring(bracketStart, i));
if (bracketStart == 1 && i == string.length() - 1) {
// Bracket encapsulates the whole string and was redundant
return subexpression;
}
root.contents.add(subexpression);
innerBrackets = 0;
bracketStart = -1;
currentCompStart = i + 2;
}
bracketLegal = false;
} else if (bracketStart == -1 && (c == ',' || c == '/')) {
if (currentCompStart == i) {
// Multiple commas / leading comma -> ignore
currentCompStart++;
} else {
// Component had ended
if (i > currentCompStart) {
// Component had ended
root.contents.add(parse(currentCompType, string.substring(currentCompStart, i)));
}
currentCompStart = i + 1;
currentCompType = c == ',' ? ComponentType.AND : ComponentType.OR;
}
bracketLegal = true;
} else {
bracketLegal = false;
}
i++;
}
if (innerBrackets != 0 || bracketStart != -1) {
throw new IllegalArgumentException("Bracket never closed");
}
// Last component
if (currentCompStart < string.length()) {
LogicalExpression comp = parse(currentCompType, string.substring(currentCompStart, i));
if (comp != null) {
root.contents.add(comp);
}
}
return root;
}
/**
* Returns the text this expression wraps.
* <p>
* This is not guaranteed to be equal to the string that had been passed to {@link #parse(java.lang.String)} as it may be stripped from redundant symbols.
*
* @return the text this expression wraps
*/
public String getText() {
return text;
}
/**
* Returns if this expression only consists of exactly one component.
*
* @return if this expression only consists of exactly one component
*/
public boolean isAtomic() {
return contents.isEmpty();
}
void setTrigger(Trigger trigger) {
this.trigger = trigger;
}
/**
* Creates a {@link Trigger} from an atomic element of the expression.
*
* @param api the {@link DungeonsAPI} reference; not null
* @param listener the listener that belongs to the trigger; not null
* @param generic if a generic trigger should be created if there is no specific trigger identifier (e.g. second line of a trigger sign)
* @throws IllegalArgumentException if the listener is null or not in a {@link GameWorld}
* @return the {@link Trigger} the string represents; null if there is none.
*/
public Trigger toTrigger(DungeonsAPI api, TriggerListener listener, boolean generic) {
if (trigger != null) {
return trigger;
}
if (!isAtomic()) {
return null;
}
if (listener == null || listener.getGameWorld() == null) {
throw new IllegalArgumentException("Listener must not be null and must be in a game world");
}
listener.getGameWorld().createTrigger(listener, this);
return trigger;
}
/**
* Returns a List of the contents of this expression.<p>
* Changes made to this list do not update the expression.
*
* @param deep if true, brackets are resolved to atomic components; if false, brackets are one element in the list
* @return a List of the contents the contents of this expression
*/
public List<LogicalExpression> getContents(boolean deep) {
if (!deep || isAtomic()) {
return new ArrayList<>(contents);
}
List<LogicalExpression> atomicContents = new ArrayList<>();
for (LogicalExpression comp : contents) {
if (comp.isAtomic()) {
atomicContents.add(comp);
} else {
atomicContents.addAll(comp.getContents(true));
}
}
return atomicContents;
}
/**
* Returns if this expression is satisfied.
*
* @return if this expression is satisfied
*/
public boolean isSatisfied() {
if (isAtomic()) {
return satisfied;
}
int[] orChains = new int[contents.size()];
int ors = 0;
boolean inChain = false;
boolean chainSatisfied = false;
// Check OR chains, return false if NONE is satisfied
for (int i = 1; contents.size() > i; i++) {
if (contents.get(i).type != ComponentType.OR) {
if (inChain) {
if (!chainSatisfied) {
return false;
}
orChains[ors] = i - 1; // write to even index
inChain = false;
chainSatisfied = false;
ors++; // switch to even index for possible upcoming chain
}
continue;
}
if (!inChain) {
inChain = true;
orChains[ors] = i - 1; // write to even index
chainSatisfied = contents.get(i - 1).isSatisfied();
ors++; // switch to uneven index
} else {
orChains[ors] = i; // update uneven index
}
if (contents.get(i).isSatisfied()) {
chainSatisfied = true;
}
}
if (inChain) {
if (!chainSatisfied) {
return false;
}
orChains[ors] = contents.size() - 1;
}
// Check AND chains, return false if ONE IS NOT satisfied
int i = 0, j = 0;
while (contents.size() > i) {
if (!(orChains[j] == 0 && orChains[j + 1] == 0)) {
while (i < orChains[j]) {
if (!contents.get(i).isSatisfied()) {
return false;
}
i++;
}
j++;
i = orChains[j] + 1;
j++;
} else {
if (!contents.get(i).isSatisfied()) {
return false;
}
i++;
}
}
return true;
}
/**
* Sets the value of an atomic expression to the given boolean.
* <p>
* If the expression is not atomic, update the atomic components instead.
*
* @param satisfied if the expression is satisfied
* @return if the expression could be updated (false if the expression is not atomic)
*/
public boolean setSatisfied(boolean satisfied) {
if (!isAtomic()) {
return false;
}
this.satisfied = satisfied;
return true;
}
@Override
public String toString() {
if (contents.isEmpty()) {
return type + text + (isSatisfied() ? "(t)" : "(f)");
}
return type + contents.toString() + (isSatisfied() ? "(t)" : "(f)");
}
}

View File

@ -0,0 +1,238 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.trigger;
import com.google.common.collect.Sets;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.event.trigger.TriggerActionEvent;
import static de.erethon.dungeonsxl.api.trigger.TriggerTypeKey.*;
import de.erethon.dungeonsxl.api.world.GameWorld;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
* A condition to fulfill in order to trigger a {@link TriggerListener} such as a {@link de.erethon.dungeonsxl.api.sign.DungeonSign}.
* <p>
* Implementations of this interface must always include a constructor of the types (DungeonsAPI, TriggerListener, LogicalExpression, String).
*
* @author Daniel Saukel
*/
public interface Trigger {
/**
* A Set of trigger types that are looked up in their game world before they are created, and, if an equal trigger already exists, returned instead of a new
* one. For example, an instance trigger is not created when its entered into the trigger line of a listening sign, but when an interact sign explicitly
* creates it.
*
* @see GameWorld#createTrigger(TriggerListener, LogicalExpression)
*/
static final Set<Character> IDENTIFIABLE = Sets.newHashSet(GENERIC, INTERACT, MOB, PROGRESS, USE_ITEM, WAVE);
/**
* Constructs a subtype of Trigger.
* <p>
* Implementations of this interface must always include a constructor of the types (DungeonsAPI, TriggerListener, LogicalExpression, String).
*
* @param <T> the type of the trigger
* @param typeKey the key that represents the type on dungeon signs and in the registry, see {@link TriggerTypeKey}
* @param api the API instance; not null
* @param owner an object that listens to the trigger
* @param expression the atomic expression that the trigger uses; not null
* @param value the value of the trigger. This is the text of the expression without the type key; not null
* @see GameWorld#createTrigger(TriggerListener, LogicalExpression)
* @see AbstractTrigger#AbstractTrigger(DungeonsAPI, TriggerListener, LogicalExpression, String)
* @return the constructed Trigger object
*/
static <T extends Trigger> T construct(char typeKey, DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
Class<T> clss = null;
try {
clss = (Class<T>) api.getTriggerRegistry().get(typeKey);
return construct(clss, api, owner, expression, value);
} catch (Exception exception) {
MessageUtil.log(api, "&4It looks like the trigger \"" + typeKey + "\"/" + clss + " was not registered correctly:");
exception.printStackTrace();
return null;
}
}
/**
* Constructs a subtype of Trigger.
* <p>
* Implementations of this interface must always include a constructor of the types (DungeonsAPI, TriggerListener, LogicalExpression, String).
*
* @param <T> the type of the trigger
* @param clss the implementation Class object
* @param api the API instance
* @param owner an object that listens to the trigger
* @param expression the atomic expression that the trigger uses; not null
* @param value the value of the trigger. This is the text of the expression without the type key; not null
* @see GameWorld#createTrigger(TriggerListener, LogicalExpression)
* @see AbstractTrigger#AbstractTrigger(DungeonsAPI, TriggerListener, LogicalExpression, String)
* @return the constructed Trigger object
*/
static <T extends Trigger> T construct(Class<T> clss, DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
try {
Constructor constructor = clss.getConstructor(DungeonsAPI.class, TriggerListener.class, LogicalExpression.class, String.class);
return (T) constructor.newInstance(api, owner, expression, value);
} catch (NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException exception) {
MessageUtil.log(api, "&4Could not create a trigger of the type \"" + clss
+ "\". A trigger implementation needs a constructor with the types (DungeonsAPI, TriggerListener, LogicalExpression, String).");
exception.printStackTrace();
return null;
}
}
/**
* Returns a char that that identifies the trigger as of a specific type.
* <p>
* Triggers from the default implementations are stored in {@link TriggerTypeKey}.
*
* @return a char that that identifies the trigger as of a specific type
*/
char getKey();
/**
* Returns the raw value the trigger was initialized with. May contain an identifier or arguments in any shape or form.
*
* @return the raw value the trigger was initialized with. May contain an identifier or arguments in any shape or form
*/
String getValue();
/**
* The {@link GameWorld} the trigger works in.
*
* @return the {@link GameWorld} the trigger works in
*/
GameWorld getGameWorld();
/**
* Returns if the trigger is triggered.
*
* @return if the trigger is triggered
*/
boolean isTriggered();
/**
* Sets if the trigger is triggered.
*
* @param triggered the state of the trigger
*/
void setTriggered(boolean triggered);
/**
* Returns the last player who triggered the trigger.
*
* @return the last player who triggered the trigger
*/
Player getTriggeringPlayer();
/**
* Updates {@link #getTriggeringPlayer()} to the given player.
*
* @param player the player to set
*/
void setTriggeringPlayer(Player player);
/**
* A set of the objects that listen to this trigger.
*
* @return a set of the objects that listen to this trigger
*/
Set<TriggerListener> getListeners();
/**
* Adds the given object to listen to this trigger.
*
* @param listener the listener to add
* @return if adding the listener was successful
*/
boolean addListener(TriggerListener listener);
/**
* Removes the given listener.
*
* @param listener the listener to remove
* @return if removing the listener was successful
*/
boolean removeListener(TriggerListener listener);
/**
* Unregisters the trigger from the {@link GameWorld}.
* <p>
* This is used to disable triggers, such as distance triggers removing themselves after the first player got into range.
*
* @return if unregistering the listener was successful
*/
boolean unregisterTrigger();
/**
* Updates the listeners; to be used when the state of the trigger is updated; by default in {@link #trigger()}.
*/
void updateListeners();
/**
* Called when the trigger is triggered.
* <p>
* This method provides default procedures when the conditions of any trigger are fulfilled, such as calling events and updating listeners. Use
* {@link #onTrigger()} to implement specific behavior (such as self-removal for default distance triggers).
* <p>
* This method does NOT change {@link #isTriggered()}. Due to the difference in behavior of triggers (working button-like, switch-like etc.), this is to be
* handled in {@link #onTrigger()}.
*
* @param switching if the action changes the the state of {@link #isTriggered()}
* @param triggeringPlayer the player who fulfilled the (last) conditions of this trigger
*/
default void trigger(boolean switching, Player triggeringPlayer) {
List<TriggerListener> fired = getListeners().stream()
.filter(l -> l.getTriggerExpression().isSatisfied())
.toList();
TriggerActionEvent event = new TriggerActionEvent(this, fired);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
setTriggeringPlayer(triggeringPlayer);
onTrigger(switching);
updateListeners();
postTrigger();
}
/**
* Called when the trigger is triggered.
* <p>
* This method can be used to implement specific behavior (such as self-removal for default distance triggers). Call {@link #trigger()} instead when the
* condition to trigger the trigger is fulfilled.
*
* @param switching if the action changes the the state of {@link #isTriggered()}
*/
void onTrigger(boolean switching);
/**
* Called after listeners are updated.
* <p>
* This method can be used to implement specific behavior such as reactivating itself after the actions of the listeners are done, such as presence triggers
* performing their action every time a player gets close.
*/
default void postTrigger() {
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2014-2023 Daniel Saukel
*
* This library is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNULesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api.trigger;
import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.world.GameWorld;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.entity.Player;
/**
* @author Daniel Saukel
*/
public interface TriggerListener {
/**
* Returns a {@link LogicalExpression} of the triggers registered for this listener.
*
* @return a a {@link LogicalExpression} of the triggers registered for this listener
*/
LogicalExpression getTriggerExpression();
/**
* Returns a deep List of triggers of this listener.
* <p>
* WARNING: Do not iterate and check if each is satisfied to get if the sign should fire. Use {@link #getTriggerExpression()} instead.
*
* @return a deep List of triggers of this listener
*/
List<Trigger> getTriggers();
/**
* Returns if the listener has triggers.
*
* @return if the listener has triggers
*/
default boolean hasTriggers() {
return getTriggerExpression() != null;
}
/**
* The location of this listener.
*
* @return the location of this listener
*/
Location getLocation();
/**
* Returns the game world this listener is in; null if this is in an edit world.
*
* @return the game world this listener is in; null if this is in an edit world
*/
GameWorld getGameWorld();
/**
* Returns the game played in the world of this listener.
*
* @return the game played in the world of this listener
*/
default Game getGame() {
if (getGameWorld() == null) {
return null;
}
return getGameWorld().getGame();
}
/**
* Makes the listener listen for its triggers if it {@link #hasTriggers()}.
* <p>
* {@link #trigger(org.bukkit.entity.Player)}s the listener if it does not have any triggers. (Note that some signs have interaction triggers by default,
* like ready signs).
*/
void initialize();
/**
* Returns if the listener is {@link #initialize()}d.
*
* @return if the listener is {@link #initialize()}d
*/
boolean isInitialized();
/**
* Triggers the listener. The effects are defined by the implementation.
*
* @param player the player who triggered the listener or null if no one in particular triggered it
*/
void trigger(Player player);
/**
* Checks if the triggers of the listener have been triggered. If they all are, the listener itself is triggered.
*
* @param lastFired the last trigger that has been triggered
*/
void updateTriggers(Trigger lastFired);
}

View File

@ -12,22 +12,29 @@
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.api;
import org.bukkit.entity.Player;
package de.erethon.dungeonsxl.api.trigger;
/**
* @deprecated stub
* Type keys of default triggers.
*
* @author Daniel Saukel
*/
@Deprecated
public interface Trigger {
public class TriggerTypeKey {
public static final char DISTANCE = 'D';
public static final char FORTUNE = 'F';
public static final char INTERACT = 'I';
/**
* The terms "generic" and "sign trigger" are used synonymously. Trigger strings without prefix default to generic triggers.
*/
public static final char GENERIC = 'T';
public static final char MOB = 'M';
public static final char PRESENCE = 'P';
@Deprecated
boolean isTriggered();
public static final char PROGRESS = 'P';
public static final char REDSTONE = 'R';
public static final char USE_ITEM = 'U';
@Deprecated
Player getPlayer();
public static final char WAVE = 'W';
}

View File

@ -18,7 +18,11 @@ import de.erethon.dungeonsxl.api.dungeon.Dungeon;
import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.mob.DungeonMob;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import java.util.Collection;
import java.util.List;
import org.bukkit.Location;
import org.bukkit.block.Block;
@ -69,21 +73,75 @@ public interface GameWorld extends InstanceWorld {
Dungeon getDungeon();
/**
* Returns the living dungeon mobs
* Creates a trigger represented by the given atomic expression.
* <p>
* For example, if the expression may wrap the string "D 10", but not "D 10, M ZOMBIE".
* <p>
* Use {@link #initTriggers(TriggerListener, LogicalExpression)} to get an array of all {@link Trigger} objects for a compound expression (such as just "D
* 10, M ZOMBIE").
*
* @param owner the {@link TriggerListener} that the trigger belongs to
* @param expression the expression; must be {@link LogicalExpression#isAtomic() atomic}.
* @throws IllegalArgumentException if the expression is not atomic
* @throws IllegalStateException if the owner is not in a game world
* @return a trigger represented by the given atomic expression; null if the expression is {@link LogicalExpression#EMPTY}.
*/
Trigger createTrigger(TriggerListener owner, LogicalExpression expression);
/**
* Creates triggers represented by the given expression.
* <p>
* For example, if the expression wraps the string "D 10, M ZOMBIE", this returns an array where the 0st entry represents "D 10" and the 1st "M ZOMBIE".
* <p>
* Use {@link #createTrigger(TriggerListener, LogicalExpression)} to get one {@link Trigger} object for exactly one atomic part (such as just "D 10").
*
* @param owner the {@link TriggerListener} that the trigger belongs to
* @param expression the expression; must be {@link LogicalExpression#isAtomic() atomic}.
* @throws IllegalStateException if the owner is not in a game world
* @return a List of triggers represented by the given expression; an empty List if the expression is {@link LogicalExpression#EMPTY}.
*/
List<Trigger> createTriggers(TriggerListener owner, LogicalExpression expression);
/**
* Returns a Collection of the triggers registered in this world.
*
* @return a Collection of the triggers registered in this world
*/
Collection<Trigger> getTriggers();
/**
* Returns a Collection of the triggers registered in this world that use the given key.
*
* @param key the key char
* @see de.erethon.dungeonsxl.api.trigger.TriggerTypeKey
* @return a Collection of the triggers registered in this world that use the given key.
*/
Collection<Trigger> getTriggersFromKey(char key);
/**
* Unregisters the given trigger, which prevents them from firing unless explicitly done in code.
*
* @param trigger the trigger to unregister
* @return if unregistering the trigger was successful
*/
boolean unregisterTrigger(Trigger trigger);
/**
* Returns the living dungeon mobs.
*
* @return the living dungeon mobs
*/
Collection<DungeonMob> getMobs();
/**
* Registers the given dungeon mob
* Registers the given dungeon mob.
*
* @param mob the mob
*/
void addMob(DungeonMob mob);
/**
* Unregisters the given dungeon mob
* Unregisters the given dungeon mob.
*
* @param mob the mob
*/

View File

@ -2,12 +2,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-bukkit_blockdata</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>

View File

@ -2,12 +2,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-bukkit_magicvalues</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>

View File

@ -2,12 +2,12 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-core</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<build>
<resources>

View File

@ -16,18 +16,21 @@
*/
package de.erethon.dungeonsxl;
import de.erethon.bedrock.misc.Registry;
import de.erethon.dungeonsxl.api.DungeonModule;
import de.erethon.dungeonsxl.api.Requirement;
import de.erethon.dungeonsxl.api.Reward;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import static de.erethon.dungeonsxl.api.trigger.TriggerTypeKey.*;
import de.erethon.dungeonsxl.requirement.*;
import de.erethon.dungeonsxl.reward.*;
import de.erethon.dungeonsxl.sign.button.*;
import de.erethon.dungeonsxl.sign.passive.*;
import de.erethon.dungeonsxl.sign.rocker.*;
import de.erethon.dungeonsxl.sign.windup.*;
import de.erethon.bedrock.misc.Registry;
import de.erethon.dungeonsxl.trigger.*;
/**
* @author Daniel Saukel
@ -99,4 +102,18 @@ public class DXLModule implements DungeonModule {
}
}
@Override
public void initTriggers(Registry<Character, Class<? extends Trigger>> triggerRegistry) {
triggerRegistry.add(DISTANCE, DistanceTrigger.class);
triggerRegistry.add(FORTUNE, FortuneTrigger.class);
triggerRegistry.add(INTERACT, InteractTrigger.class);
triggerRegistry.add(MOB, MobTrigger.class);
triggerRegistry.add(PRESENCE, PresenceTrigger.class);
//triggerRegistry.add("P", ProgressTrigger.class);
triggerRegistry.add(REDSTONE, RedstoneTrigger.class);
triggerRegistry.add(GENERIC, SignTrigger.class);
triggerRegistry.add(USE_ITEM, UseItemTrigger.class);
triggerRegistry.add(WAVE, WaveTrigger.class);
}
}

View File

@ -16,6 +16,14 @@
*/
package de.erethon.dungeonsxl;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.compatibility.Internals;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.bedrock.misc.FileUtil;
import de.erethon.bedrock.misc.Registry;
import de.erethon.bedrock.plugin.EPlugin;
import de.erethon.bedrock.plugin.EPluginSettings;
import de.erethon.bedrock.spiget.comparator.VersionComparator;
import de.erethon.caliburn.CaliburnAPI;
import de.erethon.caliburn.mob.ExMob;
import de.erethon.dungeonsxl.adapter.block.BlockAdapter;
@ -36,6 +44,7 @@ import de.erethon.dungeonsxl.api.player.PlayerCache;
import de.erethon.dungeonsxl.api.player.PlayerClass;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.world.EditWorld;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
@ -67,17 +76,8 @@ import de.erethon.dungeonsxl.sign.passive.SignScript;
import de.erethon.dungeonsxl.sign.windup.CommandScript;
import de.erethon.dungeonsxl.sign.windup.MobSign;
import de.erethon.dungeonsxl.trigger.TriggerListener;
import de.erethon.dungeonsxl.trigger.TriggerTypeCache;
import de.erethon.dungeonsxl.util.LWCUtil;
import de.erethon.dungeonsxl.util.PlaceholderUtil;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.compatibility.Internals;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.bedrock.plugin.EPlugin;
import de.erethon.bedrock.plugin.EPluginSettings;
import de.erethon.bedrock.misc.FileUtil;
import de.erethon.bedrock.misc.Registry;
import de.erethon.bedrock.spiget.comparator.VersionComparator;
import de.erethon.dungeonsxl.world.DEditWorld;
import de.erethon.dungeonsxl.world.DResourceWorld;
import de.erethon.dungeonsxl.world.DWorldListener;
@ -148,12 +148,12 @@ public class DungeonsXL extends EPlugin implements DungeonsAPI {
private Registry<String, ResourceWorld> mapRegistry;
private Registry<Integer, InstanceWorld> instanceCache;
private Registry<String, GameRule> gameRuleRegistry;
private Registry<Character, Class<? extends Trigger>> triggerRegistry;
private Registry<String, ExternalMobProvider> externalMobProviderRegistry;
private Registry<String, PlayerGroup> playerGroupCache;
@Deprecated
private class SignRegistry extends Registry<String, Class<? extends DungeonSign>> {
@Override
public Class<? extends DungeonSign> get(String key) {
Class<? extends DungeonSign> clss = super.get(key);
@ -162,7 +162,6 @@ public class DungeonsXL extends EPlugin implements DungeonsAPI {
}
return clss;
}
}
private class GameRuleRegistry extends Registry<String, GameRule> {
@ -214,7 +213,6 @@ public class DungeonsXL extends EPlugin implements DungeonsAPI {
/* Caches & registries of internal features */
private DCommandCache dCommands;
private TriggerTypeCache triggers;
private GlobalProtectionCache protections;
private Registry<String, SignScript> signScriptRegistry;
private Registry<String, CommandScript> commandScriptRegistry;
@ -309,8 +307,8 @@ public class DungeonsXL extends EPlugin implements DungeonsAPI {
gameRuleRegistry = new GameRuleRegistry();
modules.forEach(m -> m.initGameRules(gameRuleRegistry));
triggers = new TriggerTypeCache();
// modules.forEach(m -> m.initTriggers(triggerRegistry));
triggerRegistry = new Registry<>();
modules.forEach(m -> m.initTriggers(triggerRegistry));
mainConfig = new MainConfig(this, new File(getDataFolder(), "config.yml"));
@ -528,6 +526,11 @@ public class DungeonsXL extends EPlugin implements DungeonsAPI {
return gameRuleRegistry;
}
@Override
public Registry<Character, Class<? extends Trigger>> getTriggerRegistry() {
return triggerRegistry;
}
@Override
public Registry<String, ExternalMobProvider> getExternalMobProviderRegistry() {
return externalMobProviderRegistry;
@ -605,13 +608,6 @@ public class DungeonsXL extends EPlugin implements DungeonsAPI {
return mainConfig;
}
/**
* @return the triggers
*/
public TriggerTypeCache getTriggerCache() {
return triggers;
}
/**
* @return the loaded instance of GlobalProtectionCache
*/

View File

@ -23,6 +23,7 @@ import de.erethon.dungeonsxl.api.dungeon.GameGoal;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.api.world.ResourceWorld;
import de.erethon.dungeonsxl.config.DMessage;
@ -351,10 +352,14 @@ public class DGame implements Game {
waveCount++;
resetWaveKills();
Set<ProgressTrigger> triggers = ProgressTrigger.getByGameWorld(getWorld());
for (ProgressTrigger trigger : triggers) {
if (getWaveCount() >= trigger.getWaveCount() & getFloorCount() >= trigger.getFloorCount() - 1 || !getUnplayedFloors().contains(trigger.getFloor()) & trigger.getFloor() != null) {
trigger.onTrigger();
for (Trigger uncasted : getWorld().getTriggers()) {
if (!(uncasted instanceof ProgressTrigger)) {
continue;
}
ProgressTrigger trigger = (ProgressTrigger) uncasted;
if (getWaveCount() >= trigger.getWaveCount() & getFloorCount() >= trigger.getFloorCount() - 1
|| !getUnplayedFloors().contains(trigger.getFloor()) & trigger.getFloor() != null) {
trigger.trigger(true, null);
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.event.trigger;
import de.erethon.dungeonsxl.trigger.Trigger;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* @author Daniel Saukel
*/
public class TriggerActionEvent extends TriggerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public TriggerActionEvent(Trigger trigger) {
super(trigger);
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -1,40 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.event.trigger;
import de.erethon.dungeonsxl.trigger.Trigger;
import org.bukkit.event.Event;
/**
* @author Daniel Saukel
*/
public abstract class TriggerEvent extends Event {
protected Trigger trigger;
public TriggerEvent(Trigger trigger) {
this.trigger = trigger;
}
/**
* @return the trigger
*/
public Trigger getTrigger() {
return trigger;
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.event.trigger;
import de.erethon.dungeonsxl.trigger.Trigger;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
/**
* @author Daniel Saukel
*/
public class TriggerRegistrationEvent extends TriggerEvent implements Cancellable {
private static final HandlerList handlers = new HandlerList();
private boolean cancelled;
public TriggerRegistrationEvent(Trigger trigger) {
super(trigger);
}
/**
* @param trigger the trigger to set
*/
public void setTrigger(Trigger trigger) {
this.trigger = trigger;
}
@Override
public HandlerList getHandlers() {
return handlers;
}
public static HandlerList getHandlerList() {
return handlers;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}

View File

@ -16,6 +16,7 @@
*/
package de.erethon.dungeonsxl.mob;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.caliburn.mob.ExMob;
import de.erethon.caliburn.mob.VanillaMob;
import de.erethon.dungeonsxl.DungeonsXL;
@ -23,12 +24,14 @@ import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.event.mob.DungeonMobDeathEvent;
import de.erethon.dungeonsxl.api.event.mob.DungeonMobSpawnEvent;
import de.erethon.dungeonsxl.api.mob.DungeonMob;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.dungeon.DGame;
import de.erethon.dungeonsxl.trigger.MobTrigger;
import de.erethon.dungeonsxl.trigger.WaveTrigger;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.Collection;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.entity.LivingEntity;
@ -107,13 +110,14 @@ public class DMob implements DungeonMob {
MobTrigger mobTrigger = MobTrigger.getByName(trigger, gameWorld);
if (mobTrigger != null) {
mobTrigger.onTrigger();
mobTrigger.trigger(true, null);
}
Set<WaveTrigger> waveTriggers = WaveTrigger.getByGameWorld(gameWorld);
for (WaveTrigger waveTrigger : waveTriggers) {
Collection<Trigger> waveTriggers = gameWorld.getTriggersFromKey(TriggerTypeKey.WAVE);
for (Trigger uncasted : waveTriggers) {
WaveTrigger waveTrigger = (WaveTrigger) uncasted;
if (((DGame) gameWorld.getGame()).getWaveKills() >= Math.ceil(gameWorld.getMobCount() * waveTrigger.getMustKillRate())) {
waveTrigger.onTrigger();
waveTrigger.trigger(true, null);
}
}

View File

@ -16,6 +16,7 @@
*/
package de.erethon.dungeonsxl.sign;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.caliburn.item.VanillaItem;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.DungeonsAPI;
@ -25,7 +26,6 @@ import de.erethon.dungeonsxl.api.world.EditWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DPlayerListener;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.ChatColor;
import org.bukkit.block.Block;
@ -70,10 +70,11 @@ public class DSignListener implements Listener {
}
InteractTrigger trigger = InteractTrigger.getByBlock(clickedBlock, gameWorld);
if (trigger != null) {
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
trigger.onTrigger(player);
}
if (trigger == null) {
return;
}
if (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_BLOCK) {
trigger.trigger(true, player);
}
}

View File

@ -16,9 +16,9 @@
*/
package de.erethon.dungeonsxl.sign;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.bedrock.misc.BlockUtil;
import org.bukkit.Location;
/**
@ -33,11 +33,11 @@ public interface LocationSign extends DungeonSign {
double z = getSign().getZ() + 0.5;
float yaw = BlockUtil.blockFaceToYaw(DungeonsXL.BLOCK_ADAPTER.getFacing(getSign().getBlock()).getOppositeFace());
float pitch = 0;
setLocation(new Location(getGameWorld().getWorld(), x, y, z, yaw, pitch));
setTargetLocation(new Location(getGameWorld().getWorld(), x, y, z, yaw, pitch));
}
Location getLocation();
Location getTargetLocation();
void setLocation(Location location);
void setTargetLocation(Location location);
}

View File

@ -16,10 +16,10 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.chat.MessageUtil;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -16,18 +16,16 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.black_ixx.bossshop.BossShop;
import org.black_ixx.bossshop.core.BSShop;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@ -104,17 +102,7 @@ public class BossShopSign extends Button {
return;
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, ChatColor.GREEN + getLine(1));
getSign().setLine(2, ChatColor.GREEN + getLine(2));
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, getLine(1), getLine(2));
}
@Override

View File

@ -16,10 +16,10 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.chat.MessageUtil;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -16,6 +16,7 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.player.GamePlayer;
import de.erethon.dungeonsxl.api.player.InstancePlayer;
@ -23,7 +24,6 @@ import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.chat.MessageUtil;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.block.Sign;

View File

@ -23,8 +23,6 @@ import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@ -81,20 +79,8 @@ public class ClassesSign extends Button {
@Override
public void initialize() {
if (playerClass != null) {
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, ChatColor.GREEN + playerClass.getName());
getSign().setLine(2, "");
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, playerClass.getName(), "");
getGameWorld().setClassesEnabled(true);
} else {
markAsErroneous("No such class");
}

View File

@ -16,6 +16,7 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
import de.erethon.dungeonsxl.api.dungeon.GameGoal;
@ -27,10 +28,7 @@ import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DGamePlayer;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.dungeonsxl.world.DResourceWorld;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
@ -102,26 +100,20 @@ public class EndSign extends Button {
return;
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
String line1, line2;
Dungeon dungeon = getGame().getDungeon();
if (dungeon.isMultiFloor() && !getGame().getUnplayedFloors().isEmpty() && getGameWorld().getResource() != dungeon.getEndFloor()) {
getSign().setLine(1, DMessage.SIGN_FLOOR_1.getMessage());
line1 = DMessage.SIGN_FLOOR_1.getMessage();
if (floor == null) {
getSign().setLine(2, DMessage.SIGN_FLOOR_2.getMessage());
line2 = DMessage.SIGN_FLOOR_2.getMessage();
} else {
getSign().setLine(2, ChatColor.GREEN + floor.getName().replace("_", " "));
line2 = floor.getName().replace("_", " ");
}
} else {
getSign().setLine(1, DMessage.SIGN_END.getMessage());
line1 = DMessage.SIGN_END.getMessage();
line2 = "";
}
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, line1, line2);
}
@Override

View File

@ -24,9 +24,7 @@ import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@ -73,19 +71,9 @@ public class LeaveSign extends Button {
public void initialize() {
if (!getTriggers().isEmpty()) {
setToAir();
return;
} else {
InteractTrigger.addDefault(api, this, DMessage.SIGN_LEAVE.getMessage(), "");
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, DMessage.SIGN_LEAVE.getMessage());
getSign().setLine(2, "");
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
}
@Override

View File

@ -16,6 +16,9 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.misc.EnumUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.player.GamePlayer;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
@ -23,9 +26,6 @@ import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.misc.EnumUtil;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -16,11 +16,11 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -16,6 +16,8 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.bedrock.misc.ProgressBar;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.player.GamePlayer;
@ -26,12 +28,9 @@ import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DGamePlayer;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.bedrock.misc.ProgressBar;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@ -98,17 +97,7 @@ public class ReadySign extends Button {
return;
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, DMessage.SIGN_READY.getMessage());
getSign().setLine(2, "");
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, DMessage.SIGN_READY.getMessage(), "");
}
@Override

View File

@ -23,8 +23,6 @@ import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@ -100,17 +98,7 @@ public class ResourcePackSign extends Button {
return;
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, DMessage.SIGN_RESOURCE_PACK.getMessage());
getSign().setLine(2, ChatColor.GREEN + getLine(1));
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, DMessage.SIGN_RESOURCE_PACK.getMessage(), getLine(1));
}
@Override

View File

@ -16,13 +16,13 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.bedrock.misc.EnumUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.bedrock.misc.EnumUtil;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.SoundCategory;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -16,13 +16,13 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.sign.LocationSign;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.Location;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
@ -32,20 +32,20 @@ import org.bukkit.entity.Player;
*/
public class TeleportSign extends Button implements LocationSign {
private Location location;
private Location targetLocation;
public TeleportSign(DungeonsAPI api, Sign sign, String[] lines, InstanceWorld instance) {
super(api, sign, lines, instance);
}
@Override
public Location getLocation() {
return location;
public Location getTargetLocation() {
return targetLocation;
}
@Override
public void setLocation(Location location) {
this.location = location;
public void setTargetLocation(Location location) {
this.targetLocation = location;
}
@Override
@ -97,7 +97,7 @@ public class TeleportSign extends Button implements LocationSign {
}
Integer yaw = BlockUtil.lettersToYaw(getLine(i));
if (yaw != null) {
location.setYaw(yaw);
targetLocation.setYaw(yaw);
} else {
String[] loc = getLine(i).split(",");
if (loc.length == 3) {
@ -113,9 +113,9 @@ public class TeleportSign extends Button implements LocationSign {
z += 0.5;
}
location.setX(x);
location.setY(y);
location.setZ(z);
targetLocation.setX(x);
targetLocation.setY(y);
targetLocation.setZ(z);
}
}
}
@ -123,8 +123,8 @@ public class TeleportSign extends Button implements LocationSign {
@Override
public boolean push(Player player) {
if (location != null) {
player.teleport(location);
if (targetLocation != null) {
player.teleport(targetLocation);
return true;
} else {
return false;

View File

@ -16,12 +16,12 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.misc.NumberUtil;
import java.util.Map;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;

View File

@ -16,6 +16,7 @@
*/
package de.erethon.dungeonsxl.sign.button;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Button;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
@ -23,9 +24,6 @@ import de.erethon.dungeonsxl.config.DMessage;
import de.erethon.dungeonsxl.dungeon.DGame;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
/**
@ -101,17 +99,7 @@ public class WaveSign extends Button {
return;
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, DMessage.SIGN_WAVE_1.getMessage());
getSign().setLine(2, DMessage.SIGN_WAVE_2.getMessage());
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, DMessage.SIGN_WAVE_1.getMessage(), DMessage.SIGN_WAVE_2.getMessage());
}
@Override

View File

@ -16,13 +16,13 @@
*/
package de.erethon.dungeonsxl.sign.passive;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.category.Category;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Passive;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DGroup;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.util.BlockUtilCompat;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.dungeonsxl.world.block.TeamBed;

View File

@ -16,12 +16,12 @@
*/
package de.erethon.dungeonsxl.sign.passive;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Passive;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DGroup;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.dungeonsxl.world.block.TeamFlag;
import org.bukkit.block.Sign;

View File

@ -18,13 +18,13 @@ package de.erethon.dungeonsxl.sign.passive;
import com.gmail.filoghost.holographicdisplays.api.Hologram;
import com.gmail.filoghost.holographicdisplays.api.HologramsAPI;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.item.ExItem;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.sign.Passive;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;

View File

@ -16,14 +16,13 @@
*/
package de.erethon.dungeonsxl.sign.passive;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.sign.Passive;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.ChatColor;
@ -66,6 +65,11 @@ public class InteractSign extends Passive {
return false;
}
@Override
public boolean isTriggerLineDisabled() {
return true;
}
@Override
public boolean validate() {
Set<Integer> used = new HashSet<>();
@ -84,11 +88,7 @@ public class InteractSign extends Passive {
} else {
id = NumberUtil.parseInt(getLine(1));
if (id == 0 || used.contains(id)) {
return false;
} else {
return true;
}
return !(id == 0 || used.contains(id));
}
new BukkitRunnable() {
@ -103,11 +103,7 @@ public class InteractSign extends Passive {
@Override
public void initialize() {
InteractTrigger trigger = InteractTrigger.getOrCreate(NumberUtil.parseInt(getSign().getLine(1)), getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
addTrigger(trigger);
}
getGameWorld().createTrigger(this, LogicalExpression.parse("I" + id));
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, ChatColor.GREEN + getLine(2));

View File

@ -29,20 +29,20 @@ import org.bukkit.block.Sign;
*/
public class LobbySign extends Passive implements LocationSign {
private Location location;
private Location targetLocation;
public LobbySign(DungeonsAPI api, Sign sign, String[] lines, InstanceWorld instance) {
super(api, sign, lines, instance);
}
@Override
public Location getLocation() {
return location;
public Location getTargetLocation() {
return targetLocation;
}
@Override
public void setLocation(Location location) {
this.location = location;
public void setTargetLocation(Location location) {
this.targetLocation = location;
}
@Override
@ -78,7 +78,7 @@ public class LobbySign extends Passive implements LocationSign {
@Override
public void initialize() {
LocationSign.super.initialize();
getGameWorld().setLobbyLocation(getLocation());
getGameWorld().setLobbyLocation(targetLocation);
}
}

View File

@ -16,12 +16,12 @@
*/
package de.erethon.dungeonsxl.sign.passive;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.item.VanillaItem;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.dungeonsxl.world.block.RewardChest;
import java.util.Arrays;
@ -106,7 +106,7 @@ public class RewardChestSign extends ChestSign {
return;
}
((DGameWorld) getGameWorld()).addGameBlock(new RewardChest((DungeonsXL) api, chest, moneyReward, levelReward, list.toArray(new ItemStack[list.size()])));
((DGameWorld) getGameWorld()).addGameBlock(new RewardChest((DungeonsXL) api, chest, moneyReward, levelReward, list.toArray(ItemStack[]::new)));
}
}

View File

@ -16,12 +16,12 @@
*/
package de.erethon.dungeonsxl.sign.passive;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Passive;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.sign.LocationSign;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.Location;
import org.bukkit.block.Sign;
@ -30,7 +30,7 @@ import org.bukkit.block.Sign;
*/
public class StartSign extends Passive implements LocationSign {
private Location location;
private Location targetLocation;
private int id;
public StartSign(DungeonsAPI api, Sign sign, String[] lines, InstanceWorld instance) {
@ -46,13 +46,13 @@ public class StartSign extends Passive implements LocationSign {
}
@Override
public Location getLocation() {
return location;
public Location getTargetLocation() {
return targetLocation;
}
@Override
public void setLocation(Location location) {
this.location = location;
public void setTargetLocation(Location location) {
this.targetLocation = location;
}
@Override

View File

@ -16,14 +16,14 @@
*/
package de.erethon.dungeonsxl.sign.rocker;
import de.erethon.bedrock.compatibility.CompatibilityHandler;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.item.ExItem;
import de.erethon.caliburn.item.VanillaItem;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Rocker;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.compatibility.CompatibilityHandler;
import de.erethon.bedrock.misc.NumberUtil;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.bukkit.block.Block;

View File

@ -21,7 +21,6 @@ import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Rocker;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.dungeonsxl.util.BlockUtilCompat;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.dungeonsxl.world.block.LockedDoor;

View File

@ -16,17 +16,17 @@
*/
package de.erethon.dungeonsxl.sign.rocker;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.sign.Rocker;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.SignTrigger;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.block.Sign;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
/**
@ -83,11 +83,7 @@ public class TriggerSign extends Rocker {
} else {
id = NumberUtil.parseInt(getLine(1));
if (id == 0 || used.contains(id)) {
return false;
} else {
return true;
}
return !(id == 0 || used.contains(id));
}
new BukkitRunnable() {
@ -107,18 +103,38 @@ public class TriggerSign extends Rocker {
@Override
public void activate() {
SignTrigger trigger = SignTrigger.getById(id, (DGameWorld) getGameWorld());
SignTrigger trigger = SignTrigger.getById(id, getGameWorld());
if (trigger != null) {
trigger.onTrigger(true);
trigger.trigger(true, null);
}
}
@Override
public boolean activate(Player player) {
SignTrigger trigger = SignTrigger.getById(id, getGameWorld());
if (trigger == null) {
return false;
}
trigger.trigger(true, player);
return true;
}
@Override
public void deactivate() {
SignTrigger trigger = SignTrigger.getById(id, (DGameWorld) getGameWorld());
SignTrigger trigger = SignTrigger.getById(id, getGameWorld());
if (trigger != null) {
trigger.onTrigger(false);
trigger.trigger(false, null);
}
}
@Override
public boolean deactivate(Player player) {
SignTrigger trigger = SignTrigger.getById(id, getGameWorld());
if (trigger == null) {
return false;
}
trigger.trigger(false, player);
return true;
}
}

View File

@ -16,17 +16,15 @@
*/
package de.erethon.dungeonsxl.sign.windup;
import de.erethon.bedrock.misc.EnumUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Windup;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.dungeonsxl.trigger.InteractTrigger;
import de.erethon.bedrock.misc.EnumUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.block.Sign;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -135,17 +133,7 @@ public class CommandSign extends Windup {
return;
}
InteractTrigger trigger = InteractTrigger.getOrCreate(0, getSign().getBlock(), (DGameWorld) getGameWorld());
if (trigger != null) {
trigger.addListener(this);
getTriggers().add(trigger);
}
getSign().setLine(0, ChatColor.DARK_BLUE + "############");
getSign().setLine(1, ChatColor.GREEN + script.getName());
getSign().setLine(2, "");
getSign().setLine(3, ChatColor.DARK_BLUE + "############");
getSign().update();
InteractTrigger.addDefault(api, this, script.getName(), "");
}
@Override

View File

@ -16,12 +16,12 @@
*/
package de.erethon.dungeonsxl.sign.windup;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.item.ExItem;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Windup;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.Location;
import org.bukkit.block.Sign;
import org.bukkit.inventory.ItemStack;

View File

@ -16,14 +16,14 @@
*/
package de.erethon.dungeonsxl.sign.windup;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.bedrock.misc.Registry;
import de.erethon.caliburn.mob.ExMob;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.mob.ExternalMobProvider;
import de.erethon.dungeonsxl.api.sign.Windup;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.bedrock.misc.Registry;
import java.util.ArrayList;
import java.util.Collection;
import org.bukkit.Location;

View File

@ -16,12 +16,12 @@
*/
package de.erethon.dungeonsxl.sign.windup;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.item.VanillaItem;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Rocker;
import de.erethon.dungeonsxl.api.world.InstanceWorld;
import de.erethon.dungeonsxl.player.DPermission;
import de.erethon.bedrock.misc.NumberUtil;
import org.bukkit.block.Sign;
import org.bukkit.scheduler.BukkitTask;

View File

@ -16,58 +16,46 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class DistanceTrigger extends Trigger {
private TriggerType type = TriggerTypeDefault.DISTANCE;
public class DistanceTrigger extends AbstractTrigger {
private int distance = 5;
private Location loc;
public DistanceTrigger(int distance, Location loc) {
if (distance >= 2) {
this.distance = distance;
} else {
this.distance = 2;
}
this.loc = loc;
}
public DistanceTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
public DistanceTrigger(Location loc) {
this.loc = loc;
}
public void onTrigger(Player player) {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
distance = NumberUtil.parseInt(value, distance);
if (distance < 2) {
distance = 2;
}
setTriggered(true);
setPlayer(player);
updateDSigns();
DGameWorld gameWorld = null;
for (DungeonSign sign : getDSigns()) {
gameWorld = (DGameWorld) sign.getGameWorld();
removeDSign(sign);
sign.removeTrigger(this);
}
unregister(gameWorld);
this.loc = owner.getLocation();
}
@Override
public TriggerType getType() {
return type;
public char getKey() {
return TriggerTypeKey.DISTANCE;
}
@Override
public void onTrigger(boolean switching) {
setTriggered(true);
unregisterTrigger();
getListeners().clear();
getGameWorld().unregisterTrigger(this);
}
/* Statics */
@ -76,12 +64,13 @@ public class DistanceTrigger extends Trigger {
return;
}
for (Trigger trigger : gameWorld.getTriggers().toArray(new Trigger[gameWorld.getTriggers().size()])) {
if (trigger instanceof DistanceTrigger) {
DistanceTrigger distanceTrigger = (DistanceTrigger) trigger;
if (player.getLocation().distance(distanceTrigger.loc) < distanceTrigger.distance) {
distanceTrigger.onTrigger(player);
}
for (Trigger trigger : gameWorld.getTriggers().toArray(Trigger[]::new)) {
if (!(trigger instanceof DistanceTrigger)) {
continue;
}
DistanceTrigger distanceTrigger = (DistanceTrigger) trigger;
if (player.getLocation().distance(distanceTrigger.loc) < distanceTrigger.distance) {
distanceTrigger.trigger(true, player);
}
}
}

View File

@ -16,23 +16,29 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import java.util.Random;
import org.bukkit.Bukkit;
/**
* @author Daniel Saukel
*/
public class FortuneTrigger extends Trigger {
private TriggerType type = TriggerTypeDefault.FORTUNE;
public class FortuneTrigger extends AbstractTrigger {
private double chance = 0;
public FortuneTrigger(double chance) {
this.chance = chance;
public FortuneTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
this.chance = NumberUtil.parseDouble(value, chance);
}
@Override
public char getKey() {
return TriggerTypeKey.FORTUNE;
}
/* Getters and setters */
@ -50,32 +56,13 @@ public class FortuneTrigger extends Trigger {
this.chance = chance;
}
@Override
public TriggerType getType() {
return type;
}
/* Actions */
public void onTrigger() {
@Override
public void onTrigger(boolean switching) {
int random = new Random().nextInt(100);
if (chance * 100 < random) {
return;
if (chance * 100 >= random) {
setTriggered(true);
}
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
setTriggered(true);
updateDSigns();
}
/* Statics */
public static FortuneTrigger getOrCreate(String chance, DGameWorld gameWorld) {
return new FortuneTrigger(NumberUtil.parseDouble(chance));
}
}

View File

@ -16,88 +16,101 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
import org.bukkit.ChatColor;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.block.Sign;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class InteractTrigger extends Trigger {
public class InteractTrigger extends AbstractTrigger {
private TriggerType type = TriggerTypeDefault.INTERACT;
private static int unusedId = Integer.MIN_VALUE;
private int interactId;
private int id;
private Block interactBlock;
public InteractTrigger(int id, Block block) {
interactId = id;
public InteractTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
id = NumberUtil.parseInt(value);
interactBlock = getGameWorld().getWorld().getBlockAt(owner.getLocation());
}
private InteractTrigger(DungeonsAPI api, TriggerListener owner) {
super(api, owner, LogicalExpression.parse("I" + unusedId), String.valueOf(unusedId++));
interactBlock = getGameWorld().getWorld().getBlockAt(owner.getLocation());
}
public Block getInteractBlock() {
return interactBlock;
}
public void setInteractBlock(Block block) {
interactBlock = block;
}
public void onTrigger(Player player) {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
setTriggered(true);
this.setPlayer(player);
updateDSigns();
@Override
public char getKey() {
return TriggerTypeKey.INTERACT;
}
@Override
public TriggerType getType() {
return type;
public void onTrigger(boolean switching) {
setTriggered(true);
}
/* Statics */
public static InteractTrigger getOrCreate(int id, DGameWorld gameWorld) {
if (id == 0) {
public static InteractTrigger getByBlock(Block block, GameWorld gameWorld) {
if (block == null || gameWorld == null) {
return null;
}
InteractTrigger trigger = getById(id, gameWorld);
if (trigger != null) {
return trigger;
}
return new InteractTrigger(id, null);
}
public static InteractTrigger getOrCreate(int id, Block block, DGameWorld gameWorld) {
InteractTrigger trigger = getById(id, gameWorld);
if (trigger != null) {
trigger.interactBlock = block;
return trigger;
}
return new InteractTrigger(id, block);
}
public static InteractTrigger getByBlock(Block block, DGameWorld gameWorld) {
for (Trigger uncasted : gameWorld.getTriggers(TriggerTypeDefault.INTERACT)) {
for (Trigger uncasted : gameWorld.getTriggers()) {
if (!(uncasted instanceof InteractTrigger)) {
continue;
}
InteractTrigger trigger = (InteractTrigger) uncasted;
if (trigger.interactBlock != null) {
if (trigger.interactBlock.equals(block)) {
return trigger;
}
if (block.equals(trigger.interactBlock)) {
return trigger;
}
}
return null;
}
public static InteractTrigger getById(int id, DGameWorld gameWorld) {
if (id != 0) {
for (Trigger uncasted : gameWorld.getTriggers(TriggerTypeDefault.INTERACT)) {
InteractTrigger trigger = (InteractTrigger) uncasted;
if (trigger.interactId == id) {
return trigger;
}
public static InteractTrigger getById(int id, GameWorld gameWorld) {
if (gameWorld == null) {
return null;
}
for (Trigger uncasted : gameWorld.getTriggers()) {
if (!(uncasted instanceof InteractTrigger)) {
continue;
}
InteractTrigger trigger = (InteractTrigger) uncasted;
if (id == trigger.id) {
return trigger;
}
}
return null;
}
public static void addDefault(DungeonsAPI api, DungeonSign dungeonSign, String line1, String line2) {
InteractTrigger trigger = new InteractTrigger(api, dungeonSign);
trigger.addListener(dungeonSign);
Sign sign = dungeonSign.getSign();
sign.setLine(0, ChatColor.DARK_BLUE + "############");
sign.setLine(1, ChatColor.GREEN + line1);
sign.setLine(2, ChatColor.GREEN + line2);
sign.setLine(3, ChatColor.DARK_BLUE + "############");
sign.update();
}
}

View File

@ -16,53 +16,47 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class MobTrigger extends Trigger {
private TriggerType type = TriggerTypeDefault.MOB;
public class MobTrigger extends AbstractTrigger {
private String name;
public MobTrigger(String name) {
this.name = name;
}
public void onTrigger() {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
setTriggered(true);
updateDSigns();
public MobTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
name = value;
}
@Override
public TriggerType getType() {
return type;
public char getKey() {
return TriggerTypeKey.MOB;
}
@Override
public void onTrigger(boolean switching) {
setTriggered(true);
}
/* Statics */
public static MobTrigger getOrCreate(String name, DGameWorld gameWorld) {
MobTrigger trigger = getByName(name, gameWorld);
if (trigger != null) {
return trigger;
public static MobTrigger getByName(String name, GameWorld gameWorld) {
if (name == null || gameWorld == null) {
return null;
}
return new MobTrigger(name);
}
public static MobTrigger getByName(String name, DGameWorld gameWorld) {
for (Trigger uncasted : gameWorld.getTriggers(TriggerTypeDefault.MOB)) {
for (Trigger uncasted : gameWorld.getTriggers()) {
if (!(uncasted instanceof MobTrigger)) {
continue;
}
MobTrigger trigger = (MobTrigger) uncasted;
if (trigger.name.equalsIgnoreCase(name)) {
if (name.equalsIgnoreCase(trigger.name)) {
return trigger;
}
}

View File

@ -16,41 +16,36 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
/**
* @author Daniel Saukel
*/
public class PresenceTrigger extends DistanceTrigger {
public PresenceTrigger(int distance, Location loc) {
super(distance, loc);
}
public PresenceTrigger(Location loc) {
super(loc);
public PresenceTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
}
@Override
public void onTrigger(Player player) {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
public char getKey() {
return TriggerTypeKey.PRESENCE;
}
@Override
public void onTrigger(boolean switching) {
setTriggered(true);
setPlayer(player);
updateDSigns();
unregisterTrigger();
getListeners().clear();
getGameWorld().unregisterTrigger(this);
}
@Override
public void postTrigger() {
setTriggered(false);
}
@Override
public TriggerType getType() {
return TriggerTypeDefault.PRESENCE;
}
}

View File

@ -16,30 +16,37 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.dungeonsxl.world.DGameWorld;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.world.DResourceWorld;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class ProgressTrigger extends Trigger {
public class ProgressTrigger extends AbstractTrigger {
private DResourceWorld floor;
private int floorCount;
private int waveCount;
public ProgressTrigger(int floorCount, int waveCount) {
// Unused
public ProgressTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
this(api, owner, expression, value, NumberUtil.parseInt(value.split("/")[0]), NumberUtil.parseInt(value.split("/")[1]));
}
public ProgressTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value, int floorCount, int waveCount) {
super(api, owner, expression, value);
this.floorCount = floorCount;
this.waveCount = waveCount;
}
public ProgressTrigger(DResourceWorld floor) {
this.floor = floor;
@Override
public char getKey() {
return TriggerTypeKey.PROGRESS;
}
/* Getters and setters */
@ -86,50 +93,20 @@ public class ProgressTrigger extends Trigger {
}
/* Actions */
public void onTrigger() {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
setTriggered(true);
updateDSigns();
}
@Override
public TriggerType getType() {
return TriggerTypeDefault.PRESENCE;
public void onTrigger(boolean switching) {
setTriggered(true);
}
/* Statics */
public static ProgressTrigger getOrCreate(int floorCount, int waveCount, DGameWorld gameWorld) {
public static ProgressTrigger getOrCreate(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
String[] values = value.split("/");
int floorCount = NumberUtil.parseInt(values[0]);
int waveCount = NumberUtil.parseInt(values[1]);
if (floorCount == 0 & waveCount == 0 || floorCount < 0 || waveCount < 0) {
return null;
}
return new ProgressTrigger(floorCount, waveCount);
}
public static ProgressTrigger getOrCreate(DungeonsXL plugin, String floor, DGameWorld gameWorld) {
DResourceWorld resource = (DResourceWorld) plugin.getMapRegistry().get(floor);
if (resource != null) {
return new ProgressTrigger(resource);
} else {
return null;
}
}
public static Set<ProgressTrigger> getByGameWorld(DGameWorld gameWorld) {
Set<ProgressTrigger> toReturn = new HashSet<>();
for (Trigger trigger : gameWorld.getTriggers()) {
if (trigger instanceof ProgressTrigger) {
toReturn.add((ProgressTrigger) trigger);
}
}
return toReturn;
return new ProgressTrigger(api, owner, expression, value, floorCount, waveCount);
}
}

View File

@ -17,91 +17,79 @@
package de.erethon.dungeonsxl.trigger;
import de.erethon.caliburn.category.Category;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.sign.Deactivatable;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.util.BlockUtilCompat;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class RedstoneTrigger extends Trigger {
private TriggerType type = TriggerTypeDefault.REDSTONE;
public class RedstoneTrigger extends AbstractTrigger {
private Block rtBlock;
public RedstoneTrigger(Block block) {
rtBlock = block;
public RedstoneTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
Location loc = owner.getLocation();
if (Category.WALL_SIGNS.containsBlock(loc.getBlock())) {
rtBlock = BlockUtilCompat.getAttachedBlock(loc.getBlock());
} else {
rtBlock = loc.getBlock();
}
}
public void onTrigger() {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
@Override
public char getKey() {
return TriggerTypeKey.REDSTONE;
}
@Override
public void onTrigger(boolean switching) {
if (rtBlock.isBlockPowered()) {
if (!isTriggered()) {
setTriggered(true);
updateDSigns();
}
} else if (isTriggered()) {
setTriggered(false);
for (DungeonSign dSign : getDSigns().toArray(new DungeonSign[getDSigns().size()])) {
if (!(dSign instanceof Deactivatable)) {
for (TriggerListener listener : getListeners().toArray(TriggerListener[]::new)) {
if (!(listener instanceof Deactivatable)) {
return;
}
if (dSign.isErroneous()) {
Deactivatable sign = ((Deactivatable) listener);
if (sign.isErroneous()) {
return;
}
for (de.erethon.dungeonsxl.api.Trigger trigger : dSign.getTriggers()) {
for (Trigger trigger : sign.getTriggers()) {
if (trigger.isTriggered()) {
return;
}
}
((Deactivatable) dSign).deactivate();
sign.deactivate();
}
}
}
@Override
public TriggerType getType() {
return type;
}
/* Statics */
public static RedstoneTrigger getOrCreate(Sign sign, DGameWorld gameWorld) {
Block rtBlock;
if (Category.WALL_SIGNS.containsBlock(sign.getBlock())) {
rtBlock = BlockUtilCompat.getAttachedBlock(sign.getBlock());
} else {
rtBlock = sign.getBlock();
public static void updateAll(GameWorld gameWorld) {
if (gameWorld == null) {
return;
}
if (rtBlock == null) {
return null;
}
for (Trigger uncasted : gameWorld.getTriggers(TriggerTypeDefault.REDSTONE)) {
RedstoneTrigger trigger = (RedstoneTrigger) uncasted;
if (trigger.rtBlock.equals(rtBlock)) {
return trigger;
for (Trigger uncasted : gameWorld.getTriggers()) {
if (!(uncasted instanceof RedstoneTrigger)) {
continue;
}
}
return new RedstoneTrigger(rtBlock);
}
public static void updateAll(DGameWorld gameWorld) {
for (Trigger trigger : gameWorld.getTriggers(TriggerTypeDefault.REDSTONE)) {
((RedstoneTrigger) trigger).onTrigger();
((RedstoneTrigger) uncasted).trigger(true, null);
}
}

View File

@ -16,55 +16,52 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class SignTrigger extends Trigger {
public class SignTrigger extends AbstractTrigger {
private TriggerType type = TriggerTypeDefault.SIGN;
private int id;
private int stId;
public SignTrigger(int stId) {
this.stId = stId;
}
public void onTrigger(boolean enable) {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
if (enable != isTriggered()) {
setTriggered(enable);
updateDSigns();
}
public SignTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
char key = expression.getText().charAt(0);
int i = Character.toUpperCase(key) == getKey() ? 1 : 0;
id = NumberUtil.parseInt(expression.getText().substring(i));
}
@Override
public TriggerType getType() {
return type;
public char getKey() {
return TriggerTypeKey.GENERIC;
}
@Override
public void onTrigger(boolean switching) {
if (switching != isTriggered()) {
setTriggered(switching);
}
}
/* Statics */
public static SignTrigger getOrCreate(int id, DGameWorld gameWorld) {
SignTrigger trigger = getById(id, gameWorld);
if (trigger != null) {
return trigger;
public static SignTrigger getById(int id, GameWorld gameWorld) {
if (gameWorld == null) {
return null;
}
return new SignTrigger(id);
}
public static SignTrigger getById(int id, DGameWorld gameWorld) {
for (Trigger uncasted : gameWorld.getTriggers(TriggerTypeDefault.SIGN)) {
for (Trigger uncasted : gameWorld.getTriggers()) {
if (!(uncasted instanceof SignTrigger)) {
continue;
}
SignTrigger trigger = (SignTrigger) uncasted;
if (trigger.stId == id) {
if (id == trigger.id) {
return trigger;
}
}

View File

@ -1,210 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.event.trigger.TriggerRegistrationEvent;
import de.erethon.bedrock.chat.MessageUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
/**
* Extend this to create a custom Trigger.
*
* @author Frank Baumann, Daniel Saukel
*/
public abstract class Trigger implements de.erethon.dungeonsxl.api.Trigger {
private boolean triggered;
private Player player; // Holds Player for Player specific TriggerTypes
private Set<DungeonSign> dSigns = new HashSet<>();
/**
* @return the triggered
*/
public boolean isTriggered() {
return triggered;
}
/**
* @param triggered the triggered to set
*/
public void setTriggered(boolean triggered) {
this.triggered = triggered;
}
/**
* @return the player
*/
public Player getPlayer() {
return player;
}
/**
* @param player the player to set
*/
public void setPlayer(Player player) {
this.player = player;
}
/**
* @return the dSigns
*/
public Set<DungeonSign> getDSigns() {
return dSigns;
}
/**
* @param dSign the dSign to add
*/
public void addDSign(DungeonSign dSign) {
dSigns.add(dSign);
}
/**
* @param dSign the dSign to remove
*/
public void removeDSign(DungeonSign dSign) {
dSigns.remove(dSign);
}
public void addListener(DungeonSign dSign) {
if (dSigns.isEmpty()) {
register((DGameWorld) dSign.getGameWorld());
}
dSigns.add(dSign);
}
public void removeListener(DungeonSign dSign) {
dSigns.remove(dSign);
if (dSigns.isEmpty()) {
unregister((DGameWorld) dSign.getGameWorld());
}
}
public void updateDSigns() {
for (DungeonSign dSign : dSigns.toArray(new DungeonSign[dSigns.size()])) {
dSign.updateTriggers(this);
}
}
public void register(DGameWorld gameWorld) {
gameWorld.addTrigger(this);
}
public void unregister(DGameWorld gameWorld) {
gameWorld.removeTrigger(this);
}
public static Trigger getOrCreate(DungeonsXL plugin, String identifier, String value, DungeonSign dSign) {
TriggerType type = plugin.getTriggerCache().getByIdentifier(identifier);
DGameWorld gameWorld = (DGameWorld) dSign.getGameWorld();
Trigger trigger = null;
if (type == TriggerTypeDefault.REDSTONE) {
trigger = RedstoneTrigger.getOrCreate(dSign.getSign(), gameWorld);
} else if (type == TriggerTypeDefault.DISTANCE) {
if (value != null) {
trigger = new DistanceTrigger(NumberUtil.parseInt(value), dSign.getSign().getLocation());
} else {
trigger = new DistanceTrigger(dSign.getSign().getLocation());
}
} else if (type == TriggerTypeDefault.FORTUNE) {
if (value != null) {
trigger = new FortuneTrigger(NumberUtil.parseDouble(value));
}
} else if (type == TriggerTypeDefault.SIGN) {
if (value != null) {
trigger = SignTrigger.getOrCreate(NumberUtil.parseInt(value), gameWorld);
}
} else if (type == TriggerTypeDefault.INTERACT) {
if (value != null) {
trigger = InteractTrigger.getOrCreate(NumberUtil.parseInt(value), gameWorld);
}
} else if (type == TriggerTypeDefault.MOB) {
if (value != null) {
trigger = MobTrigger.getOrCreate(value, gameWorld);
}
} else if (type == TriggerTypeDefault.PRESENCE) {
if (value != null) {
if (value.matches("[0-99]/[0-999]")) {
int floorCount = NumberUtil.parseInt(value.split("/")[0]);
int waveCount = NumberUtil.parseInt(value.split("/")[1]);
trigger = ProgressTrigger.getOrCreate(floorCount, waveCount, gameWorld);
} else {
trigger = new PresenceTrigger(NumberUtil.parseInt(value), dSign.getSign().getLocation());
}
} else {
trigger = new PresenceTrigger(dSign.getSign().getLocation());
}
} else if (type == TriggerTypeDefault.USE_ITEM) {
if (value != null) {
trigger = UseItemTrigger.getOrCreate(plugin, value, gameWorld);
}
} else if (type == TriggerTypeDefault.WAVE) {
if (value != null) {
trigger = WaveTrigger.getOrCreate(NumberUtil.parseDouble(value, 1), gameWorld);
}
} else if (type != null) {
Method method;
try {
method = type.getHandler().getDeclaredMethod("getOrCreate", String.class, DGameWorld.class);
trigger = (Trigger) method.invoke(value, dSign.getGameWorld());
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException exception) {
MessageUtil.log("An error occurred while accessing the handler class of the sign " + type.getIdentifier() + ": " + exception.getClass().getSimpleName());
if (!(type instanceof TriggerTypeDefault)) {
MessageUtil.log("Please note that this trigger is an unsupported feature added by an addon!");
}
}
}
TriggerRegistrationEvent event = new TriggerRegistrationEvent(trigger);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return null;
}
return trigger;
}
/* Abstracts */
public abstract TriggerType getType();
@Override
public String toString() {
return getClass().getSimpleName() + "{type=" + getType() + "}";
}
}

View File

@ -20,7 +20,6 @@ import de.erethon.caliburn.item.VanillaItem;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.player.DPlayerListener;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -49,7 +48,7 @@ public class TriggerListener implements Listener {
public void run() {
GameWorld gameWorld = plugin.getGameWorld(event.getBlock().getWorld());
if (gameWorld != null) {
RedstoneTrigger.updateAll((DGameWorld) gameWorld);
RedstoneTrigger.updateAll(gameWorld);
}
}
}.runTaskLater(plugin, 1L);
@ -64,7 +63,7 @@ public class TriggerListener implements Listener {
if (DPlayerListener.isCitizensNPC(player)) {
return;
}
DGameWorld gameWorld = (DGameWorld) plugin.getGameWorld(player.getWorld());
GameWorld gameWorld = plugin.getGameWorld(player.getWorld());
if (gameWorld == null) {
return;
}
@ -93,7 +92,7 @@ public class TriggerListener implements Listener {
UseItemTrigger trigger = UseItemTrigger.getByName(name, gameWorld);
if (trigger != null) {
trigger.onTrigger(player);
trigger.trigger(true, player);
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.trigger;
/**
* Implement this to create custom trigger types.
*
* @author Daniel Saukel
*/
public interface TriggerType {
/**
* @return the identifier
*/
String getIdentifier();
/**
* @return the handler
*/
Class<? extends Trigger> getHandler();
}

View File

@ -1,71 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.trigger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* TriggerType instance manager.
*
* @author Daniel Saukel
*/
public class TriggerTypeCache {
private List<TriggerType> types = new ArrayList<>();
public TriggerTypeCache() {
types.addAll(Arrays.asList(TriggerTypeDefault.values()));
}
/**
* @param identifier the identifier to check
* @return the trigger which has the identifier
*/
public TriggerType getByIdentifier(String identifier) {
for (TriggerType type : types) {
if (type.getIdentifier().equalsIgnoreCase(identifier)) {
return type;
}
}
return null;
}
/**
* @return the trigger types
*/
public List<TriggerType> getTriggers() {
return types;
}
/**
* @param type the type to add
*/
public void addTrigger(TriggerType type) {
types.add(type);
}
/**
* @param type the type to remove
*/
public void removeTrigger(TriggerType type) {
types.remove(type);
}
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2012-2023 Frank Baumann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.erethon.dungeonsxl.trigger;
/**
* Default implementation of TriggerType.
*
* @author Daniel Saukel
*/
public enum TriggerTypeDefault implements TriggerType {
DISTANCE("D", DistanceTrigger.class),
FORTUNE("F", FortuneTrigger.class),
INTERACT("I", InteractTrigger.class),
MOB("M", MobTrigger.class),
PRESENCE("P", PresenceTrigger.class),
REDSTONE("R", RedstoneTrigger.class),
SIGN("T", SignTrigger.class),
USE_ITEM("U", UseItemTrigger.class),
WAVE("W", WaveTrigger.class);
private String identifier;
private Class<? extends Trigger> handler;
TriggerTypeDefault(String identifier, Class<? extends Trigger> handler) {
this.identifier = identifier;
this.handler = handler;
}
@Override
public String getIdentifier() {
return identifier;
}
@Override
public Class<? extends Trigger> getHandler() {
return handler;
}
}

View File

@ -17,66 +17,55 @@
package de.erethon.dungeonsxl.trigger;
import de.erethon.caliburn.item.ExItem;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.dungeonsxl.world.DGameWorld;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class UseItemTrigger extends Trigger {
private TriggerType type = TriggerTypeDefault.USE_ITEM;
public class UseItemTrigger extends AbstractTrigger {
private String name;
private String matchedName;
public UseItemTrigger(DungeonsXL plugin, String name) {
this.name = name;
ExItem item = plugin.getCaliburn().getExItem(name);
public UseItemTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
name = value;
ExItem item = api.getCaliburn().getExItem(name);
if (item != null) {
matchedName = item.toString();
}
}
public void onTrigger(Player player) {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
setTriggered(true);
this.setPlayer(player);
updateDSigns();
@Override
public char getKey() {
return TriggerTypeKey.USE_ITEM;
}
@Override
public TriggerType getType() {
return type;
public void onTrigger(boolean switching) {
setTriggered(true);
}
/* Statics */
public static UseItemTrigger getOrCreate(DungeonsXL plugin, String name, DGameWorld gameWorld) {
UseItemTrigger trigger = getByName(name, gameWorld);
if (trigger != null) {
return trigger;
public static UseItemTrigger getByName(String name, GameWorld gameWorld) {
if (name == null || gameWorld == null) {
return null;
}
return new UseItemTrigger(plugin, name);
}
public static UseItemTrigger getByName(String name, DGameWorld gameWorld) {
for (Trigger uncasted : gameWorld.getTriggers(TriggerTypeDefault.USE_ITEM)) {
for (Trigger uncasted : gameWorld.getTriggers()) {
if (!(uncasted instanceof UseItemTrigger)) {
continue;
}
UseItemTrigger trigger = (UseItemTrigger) uncasted;
if (trigger.name.equalsIgnoreCase(name)) {
if (name.equalsIgnoreCase(trigger.name)) {
return trigger;
} else if (name.equalsIgnoreCase(trigger.matchedName)) {
return trigger;
} else if (trigger.matchedName != null) {
if (trigger.matchedName.equalsIgnoreCase(name)) {
return trigger;
}
}
}
return null;

View File

@ -16,23 +16,28 @@
*/
package de.erethon.dungeonsxl.trigger;
import de.erethon.dungeonsxl.event.trigger.TriggerActionEvent;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.api.trigger.AbstractTrigger;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
/**
* @author Frank Baumann, Daniel Saukel
*/
public class WaveTrigger extends Trigger {
private TriggerType type = TriggerTypeDefault.WAVE;
public class WaveTrigger extends AbstractTrigger {
private double mustKillRate = 1;
public WaveTrigger(double mustKillRate) {
this.mustKillRate = mustKillRate;
public WaveTrigger(DungeonsAPI api, TriggerListener owner, LogicalExpression expression, String value) {
super(api, owner, expression, value);
mustKillRate = NumberUtil.parseDouble(value, mustKillRate);
}
@Override
public char getKey() {
return TriggerTypeKey.WAVE;
}
/**
@ -49,39 +54,14 @@ public class WaveTrigger extends Trigger {
this.mustKillRate = mustKillRate;
}
public void onTrigger() {
TriggerActionEvent event = new TriggerActionEvent(this);
Bukkit.getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
@Override
public void onTrigger(boolean switching) {
setTriggered(true);
updateDSigns();
setTriggered(false);
}
@Override
public TriggerType getType() {
return type;
}
/* Statics */
public static WaveTrigger getOrCreate(double mustKillRate, DGameWorld gameWorld) {
return new WaveTrigger(mustKillRate);
}
/**
* @param gameWorld the game world to check
* @return the WaveTriggers in the DGameWorld
*/
public static Set<WaveTrigger> getByGameWorld(DGameWorld gameWorld) {
Set<WaveTrigger> toReturn = new HashSet<>();
for (Trigger trigger : gameWorld.getTriggers(TriggerTypeDefault.WAVE)) {
toReturn.add((WaveTrigger) trigger);
}
return toReturn;
public void postTrigger() {
setTriggered(false);
}
}

View File

@ -16,18 +16,26 @@
*/
package de.erethon.dungeonsxl.world;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.bedrock.misc.FileUtil;
import de.erethon.caliburn.CaliburnAPI;
import de.erethon.dungeonsxl.DungeonsXL;
import de.erethon.dungeonsxl.api.dungeon.BuildMode;
import de.erethon.dungeonsxl.api.dungeon.Dungeon;
import de.erethon.dungeonsxl.api.dungeon.Game;
import de.erethon.dungeonsxl.api.dungeon.GameRule;
import de.erethon.dungeonsxl.api.dungeon.GameRuleContainer;
import de.erethon.dungeonsxl.api.event.trigger.TriggerRegistrationEvent;
import de.erethon.dungeonsxl.api.event.world.GameWorldStartGameEvent;
import de.erethon.dungeonsxl.api.event.world.InstanceWorldPostUnloadEvent;
import de.erethon.dungeonsxl.api.event.world.InstanceWorldUnloadEvent;
import de.erethon.dungeonsxl.api.mob.DungeonMob;
import de.erethon.dungeonsxl.api.player.PlayerGroup;
import de.erethon.dungeonsxl.api.sign.DungeonSign;
import de.erethon.dungeonsxl.api.trigger.LogicalExpression;
import de.erethon.dungeonsxl.api.trigger.Trigger;
import de.erethon.dungeonsxl.api.trigger.TriggerListener;
import de.erethon.dungeonsxl.api.trigger.TriggerTypeKey;
import de.erethon.dungeonsxl.api.world.GameWorld;
import de.erethon.dungeonsxl.mob.CitizensMobProvider;
import de.erethon.dungeonsxl.sign.button.ReadySign;
@ -36,11 +44,7 @@ import de.erethon.dungeonsxl.sign.windup.MobSign;
import de.erethon.dungeonsxl.trigger.FortuneTrigger;
import de.erethon.dungeonsxl.trigger.ProgressTrigger;
import de.erethon.dungeonsxl.trigger.RedstoneTrigger;
import de.erethon.dungeonsxl.trigger.Trigger;
import de.erethon.dungeonsxl.trigger.TriggerType;
import de.erethon.dungeonsxl.trigger.TriggerTypeDefault;
import de.erethon.bedrock.compatibility.Version;
import de.erethon.bedrock.misc.FileUtil;
import de.erethon.dungeonsxl.util.BlockUtilCompat;
import de.erethon.dungeonsxl.world.block.GameBlock;
import de.erethon.dungeonsxl.world.block.LockedDoor;
import de.erethon.dungeonsxl.world.block.MultiBlock;
@ -63,8 +67,6 @@ import org.bukkit.entity.Hanging;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.inventory.ItemStack;
import de.erethon.dungeonsxl.api.dungeon.BuildMode;
import de.erethon.dungeonsxl.util.BlockUtilCompat;
/**
* @author Frank Baumann, Milan Albrecht, Daniel Saukel
@ -128,14 +130,14 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
if (sign instanceof StartSign) {
anyStartSign = (StartSign) sign;
if (anyStartSign.getId() == index) {
return anyStartSign.getLocation();
return anyStartSign.getTargetLocation();
}
}
}
// Try any start sign
if (anyStartSign != null) {
return anyStartSign.getLocation();
return anyStartSign.getTargetLocation();
}
// Lobby location as fallback
@ -163,24 +165,18 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
return null;
}
String[] triggerTypes = lines[3].replaceAll("\\s", "").split(",");
for (String triggerString : triggerTypes) {
if (triggerString.isEmpty()) {
continue;
}
String id = triggerString.substring(0, 1);
String value = null;
if (triggerString.length() > 1) {
value = triggerString.substring(1);
}
Trigger trigger = Trigger.getOrCreate(plugin, id, value, dSign);
if (trigger != null) {
trigger.addListener(dSign);
dSign.addTrigger(trigger);
LogicalExpression expression = null;
if (!dSign.isTriggerLineDisabled()) {
try {
expression = LogicalExpression.parse(lines[3]);
} catch (IllegalArgumentException exception) {
dSign.markAsErroneous("The trigger string " + lines[3] + " is invalid.");
}
}
createTriggers(dSign, expression);
for (Trigger trigger : triggers) {
trigger.addListener(dSign);
}
if (dSign.isOnDungeonInit()) {
try {
@ -198,6 +194,79 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
return dSign;
}
@Override
public Trigger createTrigger(TriggerListener owner, LogicalExpression expression) {
if (!expression.isAtomic()) {
throw new IllegalArgumentException("Expression is not atomic");
}
String text = expression.getText();
if (text.isBlank()) {
return null;
}
char key = Character.toUpperCase(text.charAt(0));
String value;
if (plugin.getTriggerRegistry().containsKey(key)) {
value = text.substring(1, text.length() - 1);
} else {
key = 'T';
value = text;
}
Trigger trigger = getTrigger(key, value);
if (trigger != null) {
return trigger;
}
Class<? extends Trigger> clss = plugin.getTriggerRegistry().get(key);
if (clss == null) {
return null;
}
// Legacy shit
if (key == TriggerTypeKey.PROGRESS && value.matches("[0-99]/[0-999]")) {
trigger = ProgressTrigger.getOrCreate(plugin, owner, expression, value);
} else {
trigger = Trigger.construct(key, plugin, owner, expression, value);
}
if (trigger == null) {
return null;
}
TriggerRegistrationEvent event = new TriggerRegistrationEvent(trigger);
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
triggers.add(trigger);
}
return trigger;
}
@Override
public List<Trigger> createTriggers(TriggerListener owner, LogicalExpression expression) {
List<LogicalExpression> atomicExpressions = expression.getContents(true);
List<Trigger> created = new ArrayList<>(atomicExpressions.size());
for (LogicalExpression atomic : atomicExpressions) {
Trigger trigger = atomic.toTrigger(plugin, owner, true);
created.add(trigger);
}
return created;
}
public Trigger getTrigger(char key, String value) {
if (!Trigger.IDENTIFIABLE.contains(key)) {
return null;
}
for (Trigger trigger : triggers) {
if (trigger.getKey() != key) {
continue;
}
if (trigger.getValue().equalsIgnoreCase(value)) {
return trigger;
}
}
return null;
}
@Override
public Collection<Block> getPlacedBlocks() {
return placedBlocks;
@ -321,39 +390,21 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
this.isPlaying = isPlaying;
}
/**
* @return the triggers
*/
public List<Trigger> getTriggers() {
@Override
public Collection<Trigger> getTriggers() {
return triggers;
}
/**
* @param type the type to filter
* @return the triggers with the type
*/
public List<Trigger> getTriggers(TriggerType type) {
List<Trigger> triggersOfType = new ArrayList<>();
for (Trigger trigger : triggers) {
if (trigger.getType() == type) {
triggersOfType.add(trigger);
}
}
return triggersOfType;
@Override
public Collection<Trigger> getTriggersFromKey(char key) {
return triggers.stream()
.filter(t -> t.getKey() == key)
.toList();
}
/**
* @param trigger the trigger to add
*/
public void addTrigger(Trigger trigger) {
triggers.add(trigger);
}
/**
* @param trigger the trigger to remove
*/
public void removeTrigger(Trigger trigger) {
triggers.remove(trigger);
@Override
public boolean unregisterTrigger(Trigger trigger) {
return triggers.remove(trigger);
}
/**
@ -362,12 +413,12 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
public int getMobCount() {
int mobCount = 0;
signs: for (DungeonSign sign : getDungeonSigns().toArray(new DungeonSign[getDungeonSigns().size()])) {
signs: for (DungeonSign sign : getDungeonSigns().toArray(DungeonSign[]::new)) {
if (!(sign instanceof MobSign)) {
continue;
}
for (de.erethon.dungeonsxl.api.Trigger trigger : sign.getTriggers()) {
for (Trigger trigger : sign.getTriggers()) {
if (trigger instanceof ProgressTrigger) {
if (((ProgressTrigger) trigger).getFloorCount() > getGame().getFloorCount()) {
break signs;
@ -449,12 +500,12 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
}
}
for (Trigger trigger : getTriggers(TriggerTypeDefault.REDSTONE)) {
((RedstoneTrigger) trigger).onTrigger();
for (Trigger trigger : getTriggersFromKey(TriggerTypeKey.REDSTONE)) {
((RedstoneTrigger) trigger).trigger(true, null);
}
for (Trigger trigger : getTriggers(TriggerTypeDefault.FORTUNE)) {
((FortuneTrigger) trigger).onTrigger();
for (Trigger trigger : getTriggersFromKey(TriggerTypeKey.FORTUNE)) {
((FortuneTrigger) trigger).trigger(true, null);
}
}
@ -598,7 +649,7 @@ public class DGameWorld extends DInstanceWorld implements GameWorld {
}
return true;
}
placeableBlock.onPlace();
placeableBlock.onPlace(player);
return false;
}

View File

@ -16,16 +16,17 @@
*/
package de.erethon.dungeonsxl.world.block;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.caliburn.item.ExItem;
import de.erethon.dungeonsxl.api.DungeonsAPI;
import de.erethon.dungeonsxl.trigger.SignTrigger;
import de.erethon.bedrock.misc.BlockUtil;
import de.erethon.bedrock.misc.NumberUtil;
import de.erethon.dungeonsxl.world.DGameWorld;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.block.BlockBreakEvent;
/**
@ -68,9 +69,9 @@ public class PlaceableBlock extends GameBlock {
return false;
}
public void onPlace() {
public void onPlace(Player player) {
if (triggerId != -1) {
SignTrigger.getById(triggerId, gameWorld).onTrigger(true);
SignTrigger.getById(triggerId, gameWorld).trigger(true, player);
}
gameWorld.removeGameBlock(this);
}

2
dist/pom.xml vendored
View File

@ -7,7 +7,7 @@
<parent>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
</parent>
<build>
<finalName>${project.artifactId}-${project.version}${buildNo}</finalName>

View File

@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.erethon.dungeonsxl</groupId>
<artifactId>dungeonsxl-parent</artifactId>
<version>0.18-SNAPSHOT</version>
<version>0.19-SNAPSHOT</version>
<packaging>pom</packaging>
<name>DungeonsXL</name>
<url>https://dre2n.github.io</url>