Implement MVWorldPropertyChangeEvent

This commit is contained in:
Ben Woo 2025-01-19 15:29:04 +08:00
parent 36aa144121
commit 4362453f90
5 changed files with 106 additions and 140 deletions

View File

@ -7,39 +7,32 @@
package org.mvplugins.multiverse.core.api.event;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.mvplugins.multiverse.core.api.world.MultiverseWorld;
/**
* This event is fired *before* the property is actually changed.
* This event is fired after the property is changed.
* <p>
* If it is cancelled, no change will happen.
* <p>
* If you want to get the values of the world before the change, query the world.
* To get the name of the property that was changed, use {@link #getPropertyName()}.
* To get the new value, use {@link #getTheNewValue()}. To change it, use {@link #setTheNewValue(Object)}.
* To get the name of the property that was changed, use {@link #getName()}.
* To get the old value, use {@link #getOldValue()}.
* To get the new value, use {@link #getNewValue()}.
*
* @param <T> The type of the property that was set.
* @since 5.0
*/
// todo: Implement or remove this
@Deprecated
public class MVWorldPropertyChangeEvent<T> extends Event implements Cancellable {
private MultiverseWorld world;
private CommandSender changer;
private boolean isCancelled = false;
private String name;
private T value;
public class MVWorldPropertyChangeEvent<T> extends Event {
private final MultiverseWorld world;
private final String name;
private final T oldValue;
private final T newValue;
public MVWorldPropertyChangeEvent(MultiverseWorld world, CommandSender changer, String name, T value) {
public MVWorldPropertyChangeEvent(MultiverseWorld world, String name, T oldValue, T value) {
this.world = world;
this.changer = changer;
this.name = name;
this.value = value;
this.oldValue = oldValue;
this.newValue = value;
}
private static final HandlerList HANDLERS = new HandlerList();
@ -67,64 +60,37 @@ public class MVWorldPropertyChangeEvent<T> extends Event implements Cancellable
* @return The changed world property's name.
* @since 5.0
*/
public String getPropertyName() {
public String getName() {
return this.name;
}
/**
* Gets the old value.
*
* @return The old value.
* @since 5.0
*/
public T getOldValue() {
return oldValue;
}
/**
* Gets the new value.
*
* @return The new value.
* @since 5.0
*/
public T getTheNewValue() {
return this.value;
}
/**
* Sets the new value.
*
* @param value The new value.
* @since 5.0
*/
public void setTheNewValue(T value) {
this.value = value;
public T getNewValue() {
return this.newValue;
}
/**
* Get the world targeted because of this change.
*
* @return A valid MultiverseWorld.
* @since 5.0
*/
public MultiverseWorld getWorld() {
return this.world;
}
/**
* Gets the person (or console) who was responsible for the change.
* <p>
* This may be null!
*
* @return The person (or console) who was responsible for the change.
* @since 5.0
*/
public CommandSender getCommandSender() {
return this.changer;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isCancelled() {
return this.isCancelled;
}
/**
* {@inheritDoc}
*/
@Override
public void setCancelled(boolean cancelled) {
this.isCancelled = cancelled;
}
}

View File

@ -66,7 +66,7 @@ public class ConfigHeaderNode implements CommentedNode {
comment = "# " + comment;
}
comments.add(comment);
return (B) this;
return self();
}
/**
@ -77,5 +77,11 @@ public class ConfigHeaderNode implements CommentedNode {
public @NotNull ConfigHeaderNode build() {
return new ConfigHeaderNode(path, comments.toArray(new String[0]));
}
protected @NotNull B self() {
//noinspection unchecked
return (B) this;
}
}
}

View File

@ -182,6 +182,15 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
this.type = type;
}
/**
* Gets the path of this node.
*
* @return The path of this node.
*/
public @NotNull String path() {
return path;
}
/**
* Sets the default value for this node.
*
@ -215,6 +224,15 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
return self();
}
/**
* Gets the name of this node. Used for identifying the node from user input.
*
* @return The name of this node, or {@code null} if the node has no name.
*/
public @Nullable String name() {
return name;
}
/**
* Sets the suggester for this node.
*
@ -266,7 +284,7 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
* @return This builder.
*/
public @NotNull B onSetValue(@NotNull BiConsumer<T, T> onSetValue) {
this.onSetValue = onSetValue;
this.onSetValue = this.onSetValue == null ? onSetValue : this.onSetValue.andThen(onSetValue);
return self();
}
@ -278,10 +296,5 @@ public class ConfigNode<T> extends ConfigHeaderNode implements ValueNode<T> {
return new ConfigNode<>(path, comments.toArray(new String[0]),
name, type, defaultValue, suggester, stringParser, serializer, validator, onSetValue);
}
protected @NotNull B self() {
//noinspection unchecked
return (B) this;
}
}
}

View File

@ -32,7 +32,7 @@ public class ListConfigNode<I> extends ConfigNode<List<I>> implements ListValueN
* @param <I> The type of the value.
* @return The new builder.
*/
public static @NotNull <I> Builder<I, ? extends Builder<I, ?>> listBuilder(
public static @NotNull <I, B extends Builder<I, B>> Builder<I, B> listBuilder(
@NotNull String path,
@NotNull Class<I> type) {
return new Builder<>(path, type);

View File

@ -2,7 +2,12 @@ package org.mvplugins.multiverse.core.world.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import com.dumptruckman.minecraft.util.Logging;
import io.vavr.control.Option;
import org.bukkit.Bukkit;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -11,12 +16,12 @@ import org.bukkit.block.Biome;
import org.jetbrains.annotations.NotNull;
import org.mvplugins.multiverse.core.MultiverseCore;
import org.mvplugins.multiverse.core.api.event.MVWorldPropertyChangeEvent;
import org.mvplugins.multiverse.core.api.world.config.AllowedPortalType;
import org.mvplugins.multiverse.core.api.world.LoadedMultiverseWorld;
import org.mvplugins.multiverse.core.api.world.config.SpawnLocation;
import org.mvplugins.multiverse.core.configuration.node.ConfigNode;
import org.mvplugins.multiverse.core.configuration.node.ListConfigNode;
import org.mvplugins.multiverse.core.configuration.node.Node;
import org.mvplugins.multiverse.core.configuration.node.NodeGroup;
import org.mvplugins.multiverse.core.economy.MVEconomist;
import org.mvplugins.multiverse.core.api.world.MultiverseWorld;
@ -52,7 +57,17 @@ public class WorldConfigNodes {
return nodes;
}
private <N extends Node> N node(N node) {
private <T> ConfigNode<T> node(ConfigNode.Builder<T, ?> nodeBuilder) {
nodeBuilder.onSetValue((oldValue, newValue) -> {
if (Objects.equals(oldValue, newValue)) return;
MVWorldPropertyChangeEvent<?> mvWorldPropertyChangeEvent = new MVWorldPropertyChangeEvent<>(
world, Option.of(nodeBuilder.name()).getOrElse(nodeBuilder.path()), oldValue, newValue);
Bukkit.getPluginManager().callEvent(mvWorldPropertyChangeEvent);
Logging.finer("MVWorldPropertyChangeEvent fired for world '%s' with name '%s' and value '%s'",
world.getName(), nodeBuilder.path(), newValue);
});
ConfigNode<T> node = nodeBuilder.build();
nodes.add(node);
return node;
}
@ -63,20 +78,17 @@ public class WorldConfigNodes {
// BEGIN CHECKSTYLE-SUPPRESSION: VisibilityModifier
final ConfigNode<Boolean> ADJUST_SPAWN = node(ConfigNode.builder("adjust-spawn", Boolean.class)
.defaultValue(false)
.build());
.defaultValue(false));
final ConfigNode<String> ALIAS = node(ConfigNode.builder("alias", String.class)
.defaultValue("")
.build());
.defaultValue(""));
final ConfigNode<Boolean> ALLOW_FLIGHT = node(ConfigNode.builder("allow-flight", Boolean.class)
.defaultValue(false)
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
enforcementHandler.handleAllFlightEnforcement(world);
})
.build());
}));
final ConfigNode<Boolean> ALLOW_WEATHER = node(ConfigNode.builder("allow-weather", Boolean.class)
.defaultValue(true)
@ -88,82 +100,67 @@ public class WorldConfigNodes {
world.setStorm(false);
}
});
})
.build());
}));
final ConfigNode<Boolean> ANCHOR_RESPAWN = node(ConfigNode.builder("anchor-respawn", Boolean.class)
.defaultValue(true)
.build());
.defaultValue(true));
final ConfigNode<Boolean> AUTO_HEAL = node(ConfigNode.builder("auto-heal", Boolean.class)
.defaultValue(true)
.build());
.defaultValue(true));
final ConfigNode<Boolean> AUTO_LOAD = node(ConfigNode.builder("auto-load", Boolean.class)
.defaultValue(true)
.build());
.defaultValue(true));
final ConfigNode<Boolean> BED_RESPAWN = node(ConfigNode.builder("bed-respawn", Boolean.class)
.defaultValue(true)
.build());
.defaultValue(true));
final ConfigNode<Biome> BIOME = node(ConfigNode.builder("biome", Biome.class)
.defaultValue(Biome.CUSTOM)
.name(null)
.serializer(new BiomeSerializer())
.build());
.serializer(new BiomeSerializer()));
final ConfigNode<Difficulty> DIFFICULTY = node(ConfigNode.builder("difficulty", Difficulty.class)
.defaultValue(Difficulty.NORMAL)
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setDifficulty(newValue));
})
.build());
}));
final ConfigNode<Boolean> ENTRY_FEE_ENABLED = node(ConfigNode.builder("entry-fee.enabled", Boolean.class)
.defaultValue(false)
.name("entryfee-enabled")
.build());
.name("entryfee-enabled"));
final ConfigNode<Double> ENTRY_FEE_AMOUNT = node(ConfigNode.builder("entry-fee.amount", Double.class)
.defaultValue(0.0)
.name("entryfee-amount")
.build());
.name("entryfee-amount"));
final ConfigNode<Material> ENTRY_FEE_CURRENCY = node(ConfigNode.builder("entry-fee.currency", Material.class)
.defaultValue(MVEconomist.VAULT_ECONOMY_MATERIAL)
.name("entryfee-currency")
.serializer(new CurrencySerializer())
.build());
.serializer(new CurrencySerializer()));
final ConfigNode<World.Environment> ENVIRONMENT = node(ConfigNode
.builder("environment", World.Environment.class)
.defaultValue(World.Environment.NORMAL)
.name(null)
.build());
.name(null));
final ConfigNode<GameMode> GAMEMODE = node(ConfigNode.builder("gamemode", GameMode.class)
.defaultValue(GameMode.SURVIVAL)
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
enforcementHandler.handleAllGameModeEnforcement(world);
})
.build());
}));
final ConfigNode<String> GENERATOR = node(ConfigNode.builder("generator", String.class)
// this should be set on world creation, if @error is shown in config, something went wrong
.defaultValue("@error")
.name(null)
.build());
.name(null));
final ConfigNode<Boolean> HIDDEN = node(ConfigNode.builder("hidden", Boolean.class)
.defaultValue(false)
.build());
.defaultValue(false));
final ConfigNode<Boolean> HUNGER = node(ConfigNode.builder("hunger", Boolean.class)
.defaultValue(true)
.build());
.defaultValue(true));
final ConfigNode<Boolean> KEEP_SPAWN_IN_MEMORY = node(ConfigNode
.builder("keep-spawn-in-memory", Boolean.class)
@ -171,33 +168,28 @@ public class WorldConfigNodes {
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setKeepSpawnInMemory(newValue));
})
.build());
}));
final ConfigNode<Integer> PLAYER_LIMIT = node(ConfigNode.builder("player-limit", Integer.class)
.defaultValue(-1)
.build());
.defaultValue(-1));
final ConfigNode<AllowedPortalType> PORTAL_FORM = node(ConfigNode
.builder("portal-form", AllowedPortalType.class)
.defaultValue(AllowedPortalType.ALL)
.build());
.defaultValue(AllowedPortalType.ALL));
final ConfigNode<Boolean> PVP = node(ConfigNode.builder("pvp", Boolean.class)
.defaultValue(true)
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setPVP(newValue));
})
.build());
}));
final ConfigNode<String> RESPAWN_WORLD = node(ConfigNode.builder("respawn-world", String.class)
.defaultValue("")
.suggester(input -> {
if (worldManager == null) return Collections.emptyList();
return worldManager.getWorlds().stream().map(MultiverseWorld::getName).toList();
})
.build());
}));
final ConfigNode<Double> SCALE = node(ConfigNode.builder("scale", Double.class)
.defaultValue(() -> {
@ -207,13 +199,11 @@ public class WorldConfigNodes {
case THE_END -> 16.0;
default -> 1.0;
};
})
.build());
}));
final ConfigNode<Long> SEED = node(ConfigNode.builder("seed", Long.class)
.defaultValue(Long.MIN_VALUE)
.name(null)
.build());
.name(null));
final ConfigNode<SpawnLocation> SPAWN_LOCATION = node(ConfigNode.builder("spawn-location", SpawnLocation.class)
.defaultValue(NullLocation.get())
@ -225,8 +215,7 @@ public class WorldConfigNodes {
bukkitWorld.setSpawnLocation(newValue.getBlockX(), newValue.getBlockY(), newValue.getBlockZ());
newValue.setWorld(bukkitWorld);
});
})
.build());
}));
final ConfigNode<Boolean> SPAWNING_ANIMALS = node(ConfigNode.builder("spawning.animals.spawn", Boolean.class)
.defaultValue(true)
@ -234,8 +223,7 @@ public class WorldConfigNodes {
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setSpawnFlags(world.getAllowMonsters(), newValue));
})
.build());
}));
final ConfigNode<Integer> SPAWNING_ANIMALS_TICKS = node(ConfigNode
.builder("spawning.animals.tick-rate", Integer.class)
@ -244,14 +232,12 @@ public class WorldConfigNodes {
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setTicksPerAnimalSpawns(newValue));
})
.build());
}));
final ListConfigNode<String> SPAWNING_ANIMALS_EXCEPTIONS = node(ListConfigNode
final ConfigNode<List<String>> SPAWNING_ANIMALS_EXCEPTIONS = node(ListConfigNode
.listBuilder("spawning.animals.exceptions", String.class)
.defaultValue(new ArrayList<>())
.name("spawning-animals-exceptions")
.build());
.name("spawning-animals-exceptions"));
final ConfigNode<Boolean> SPAWNING_MONSTERS = node(ConfigNode
.builder("spawning.monsters.spawn", Boolean.class)
@ -260,8 +246,7 @@ public class WorldConfigNodes {
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setSpawnFlags(newValue, world.getAllowAnimals()));
})
.build());
}));
final ConfigNode<Integer> SPAWNING_MONSTERS_TICKS = node(ConfigNode
.builder("spawning.monsters.tick-rate", Integer.class)
@ -270,22 +255,18 @@ public class WorldConfigNodes {
.onSetValue((oldValue, newValue) -> {
if (world == null) return;
world.getBukkitWorld().peek(world -> world.setTicksPerMonsterSpawns(newValue));
})
.build());
}));
final ListConfigNode<String> SPAWNING_MONSTERS_EXCEPTIONS = node(ListConfigNode
final ConfigNode<List<String>> SPAWNING_MONSTERS_EXCEPTIONS = node(ListConfigNode
.listBuilder("spawning.monsters.exceptions", String.class)
.defaultValue(new ArrayList<>())
.name("spawning-monsters-exceptions")
.build());
.name("spawning-monsters-exceptions"));
final ListConfigNode<String> WORLD_BLACKLIST = node(ListConfigNode.listBuilder("world-blacklist", String.class)
.build());
final ConfigNode<List<String>> WORLD_BLACKLIST = node(ListConfigNode.listBuilder("world-blacklist", String.class));
final ConfigNode<Double> VERSION = node(ConfigNode.builder("version", Double.class)
.defaultValue(CONFIG_VERSION)
.name(null)
.build());
.name(null));
// END CHECKSTYLE-SUPPRESSION: Javadoc
// END CHECKSTYLE-SUPPRESSION: MemberName