mirror of
https://github.com/Multiverse/Multiverse-Core.git
synced 2026-11-04 16:50:03 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
892ce24845 | ||
|
|
091eec96b9 | ||
|
|
37ecceb179 | ||
|
|
7697065519 | ||
|
|
ad7b9638f1 | ||
|
|
37ba5ecc04 | ||
|
|
2445464ab8 | ||
|
|
7fad9aa2e4 | ||
|
|
a8c0b221cd | ||
|
|
826fe4c6d0 | ||
|
|
97cbb4576d | ||
|
|
d50cd6cce5 | ||
|
|
b500956555 | ||
|
|
de80667bb4 |
No files matched your search
+5
-5
@@ -9,13 +9,13 @@ description = 'Multiverse-Core'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = 'aikar repo'
|
||||
url = uri('https://repo.aikar.co/content/groups/aikar/')
|
||||
name = 'jitpack repo'
|
||||
url = uri('https://jitpack.io')
|
||||
}
|
||||
|
||||
maven {
|
||||
name = 'glaremasters repo'
|
||||
url = 'https://repo.glaremasters.me/repository/towny/'
|
||||
name = 'aikar repo'
|
||||
url = uri('https://repo.aikar.co/content/groups/aikar/')
|
||||
}
|
||||
|
||||
maven {
|
||||
@@ -43,7 +43,7 @@ dependencies {
|
||||
shadowed 'co.aikar:acf-paper:0.5.1-SNAPSHOT'
|
||||
|
||||
// Config
|
||||
shadowed('io.github.townyadvanced.commentedconfiguration:CommentedConfiguration:1.0.1') {
|
||||
shadowed('com.github.TownyAdvanced:CommentedConfiguration:1.0.3') {
|
||||
exclude group: 'org.spigotmc', module: 'spigot-api'
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
package org.mvplugins.multiverse.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import io.vavr.control.Try;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import org.mvplugins.multiverse.core.anchor.AnchorManager;
|
||||
import org.mvplugins.multiverse.core.config.CoreConfig;
|
||||
import org.mvplugins.multiverse.core.destination.DestinationsProvider;
|
||||
@@ -16,18 +24,13 @@ import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
import org.mvplugins.multiverse.core.world.biomeprovider.BiomeProviderFactory;
|
||||
import org.mvplugins.multiverse.core.world.generators.GeneratorProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Provides access to the MultiverseCore API.
|
||||
*/
|
||||
public final class MultiverseCoreApi {
|
||||
|
||||
private static MultiverseCoreApi instance;
|
||||
private static final List<Consumer<MultiverseCoreApi>> whenLoadedCallbacks = new ArrayList<>();
|
||||
private static final List<Consumer<MultiverseCoreApi>> WHEN_LOADED_CALLBACKS = new ArrayList<>();
|
||||
|
||||
static void init(@NotNull MultiverseCore multiverseCore) {
|
||||
if (instance != null) {
|
||||
@@ -36,11 +39,24 @@ public final class MultiverseCoreApi {
|
||||
instance = new MultiverseCoreApi(multiverseCore.getServiceLocator());
|
||||
Bukkit.getServicesManager().register(MultiverseCoreApi.class, instance, multiverseCore, ServicePriority.Normal);
|
||||
|
||||
whenLoadedCallbacks.forEach(c -> c.accept(instance));
|
||||
whenLoadedCallbacks.clear();
|
||||
List<Consumer<MultiverseCoreApi>> callbacks = List.copyOf(WHEN_LOADED_CALLBACKS);
|
||||
WHEN_LOADED_CALLBACKS.clear();
|
||||
MultiverseCoreApi loadedApi = instance;
|
||||
callbacks.forEach(callback -> runLoadCallback(callback, loadedApi));
|
||||
}
|
||||
|
||||
private static void runLoadCallback(
|
||||
@NotNull Consumer<MultiverseCoreApi> callback,
|
||||
@NotNull MultiverseCoreApi loadedApi) {
|
||||
Try.run(() -> callback.accept(loadedApi))
|
||||
.onFailure(exception -> Logging.warning(
|
||||
"A Multiverse-Core API load callback failed: %s", exception.getMessage()));
|
||||
}
|
||||
|
||||
static void shutdown() {
|
||||
if (instance == null) {
|
||||
return;
|
||||
}
|
||||
Bukkit.getServicesManager().unregister(instance);
|
||||
instance = null;
|
||||
}
|
||||
@@ -62,7 +78,7 @@ public final class MultiverseCoreApi {
|
||||
if (instance != null) {
|
||||
consumer.accept(instance);
|
||||
} else {
|
||||
whenLoadedCallbacks.add(consumer);
|
||||
WHEN_LOADED_CALLBACKS.add(consumer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -96,12 +96,14 @@ public final class ExactDestination implements Destination<ExactDestination, Exa
|
||||
return Attempt.failure(InstanceFailureReason.INVALID_FORMAT);
|
||||
}
|
||||
|
||||
String worldName = items[0];
|
||||
String worldNameOrAlias = items[0];
|
||||
String positionStr = items[1];
|
||||
|
||||
World world = getLoadedMultiverseWorld(worldName).flatMap(LoadedMultiverseWorld::getBukkitWorld).getOrNull();
|
||||
World world = getLoadedMultiverseWorld(worldNameOrAlias)
|
||||
.flatMap(LoadedMultiverseWorld::getBukkitWorld)
|
||||
.getOrNull();
|
||||
if (world == null) {
|
||||
return Attempt.failure(InstanceFailureReason.WORLD_NOT_FOUND, Replace.WORLD.with(worldName));
|
||||
return Attempt.failure(InstanceFailureReason.WORLD_NOT_FOUND, Replace.WORLD.with(worldNameOrAlias));
|
||||
}
|
||||
|
||||
EntityPosition position;
|
||||
@@ -111,7 +113,7 @@ public final class ExactDestination implements Destination<ExactDestination, Exa
|
||||
return Attempt.failure(InstanceFailureReason.INVALID_NUMBER_FORMAT, Replace.ERROR.with(e));
|
||||
}
|
||||
|
||||
return Attempt.success(new ExactDestinationInstance(this, worldManager, worldName, position));
|
||||
return Attempt.success(new ExactDestinationInstance(this, worldManager, world.getName(), position));
|
||||
}
|
||||
|
||||
//TODO: Extract to a world finder class
|
||||
|
||||
@@ -10,6 +10,7 @@ package org.mvplugins.multiverse.core.listeners;
|
||||
import com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent;
|
||||
import com.dumptruckman.minecraft.util.Logging;
|
||||
import jakarta.inject.Inject;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
@@ -19,6 +20,7 @@ import org.bukkit.event.entity.EntityRegainHealthEvent;
|
||||
import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
|
||||
import org.bukkit.event.entity.EntitySpawnEvent;
|
||||
import org.bukkit.event.entity.FoodLevelChangeEvent;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jvnet.hk2.annotations.Service;
|
||||
|
||||
@@ -27,6 +29,8 @@ import org.mvplugins.multiverse.core.dynamiclistener.annotations.EventClass;
|
||||
import org.mvplugins.multiverse.core.dynamiclistener.annotations.EventMethod;
|
||||
import org.mvplugins.multiverse.core.world.WorldManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Multiverse's Entity {@link Listener}.
|
||||
*/
|
||||
@@ -132,7 +136,7 @@ final class MVEntityListener implements CoreListener {
|
||||
|
||||
worldManager.getLoadedWorld(event.getEntity().getWorld())
|
||||
.peek(world -> {
|
||||
if (!world.getEntitySpawnConfig().shouldAllowSpawn(event.getEntity())) {
|
||||
if (!world.getEntitySpawnConfig().shouldAllowSpawn(event.getEntityType())) {
|
||||
Logging.finest("Cancelling Creature Spawn Event for: " + event.getEntity());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
@@ -151,10 +155,26 @@ final class MVEntityListener implements CoreListener {
|
||||
|
||||
worldManager.getLoadedWorld(event.getEntity().getWorld())
|
||||
.peek(world -> {
|
||||
if (!world.getEntitySpawnConfig().shouldAllowSpawn(event.getEntity())) {
|
||||
if (!world.getEntitySpawnConfig().shouldAllowSpawn(event.getEntityType())) {
|
||||
Logging.finest("Cancelling Entity Spawn Event for: " + event.getEntity());
|
||||
event.setCancelled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@EventMethod
|
||||
void chunkLoad(ChunkLoadEvent event) {
|
||||
worldManager.getLoadedWorld(event.getWorld())
|
||||
.peek(world -> {
|
||||
long count = Arrays.stream(event.getChunk().getEntities())
|
||||
.filter(entity -> !(entity instanceof Player))
|
||||
.filter(entity -> !world.getEntitySpawnConfig().shouldAllowSpawn(entity))
|
||||
.peek(Entity::remove)
|
||||
.count();
|
||||
if (count > 0) {
|
||||
Logging.finest("Removed %d entities from chunk %d, %d in world %s due to spawn category settings.",
|
||||
count, event.getChunk().getX(), event.getChunk().getZ(), event.getWorld().getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ final class WorldConfig {
|
||||
@NotNull ConfigurationSection configSection,
|
||||
@NotNull MultiverseCore multiverseCore) {
|
||||
this.keyOrName = keyOrName;
|
||||
this.configNodes = new WorldConfigNodes(multiverseCore);
|
||||
this.configNodes = new WorldConfigNodes(multiverseCore, keyOrName);
|
||||
this.configHandle = MemoryConfigurationHandle.builder(configSection, configNodes.getNodes())
|
||||
.logger(Logging.getLogger())
|
||||
.migrator(migrator())
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.mvplugins.multiverse.core.economy.MVEconomist;
|
||||
import org.mvplugins.multiverse.core.utils.MaterialConverter;
|
||||
import org.mvplugins.multiverse.core.utils.text.ChatTextFormatter;
|
||||
import org.mvplugins.multiverse.core.world.helpers.EnforcementHandler;
|
||||
import org.mvplugins.multiverse.core.world.key.WorldKeyOrName;
|
||||
import org.mvplugins.multiverse.core.world.location.NullSpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.location.SpawnLocation;
|
||||
import org.mvplugins.multiverse.core.world.entity.EntitySpawnConfig;
|
||||
@@ -42,12 +43,14 @@ final class WorldConfigNodes {
|
||||
private WorldManager worldManager;
|
||||
private EnforcementHandler enforcementHandler;
|
||||
private CoreConfig config;
|
||||
private WorldKeyOrName keyOrName;
|
||||
private MultiverseWorld world = null;
|
||||
|
||||
WorldConfigNodes(@NotNull MultiverseCore multiverseCore) {
|
||||
WorldConfigNodes(@NotNull MultiverseCore multiverseCore, @NotNull WorldKeyOrName keyOrName) {
|
||||
this.worldManager = multiverseCore.getServiceLocator().getService(WorldManager.class);
|
||||
this.enforcementHandler = multiverseCore.getServiceLocator().getService(EnforcementHandler.class);
|
||||
this.config = multiverseCore.getServiceLocator().getService(CoreConfig.class);
|
||||
this.keyOrName = keyOrName;
|
||||
}
|
||||
|
||||
MultiverseWorld getWorld() {
|
||||
@@ -91,10 +94,13 @@ final class WorldConfigNodes {
|
||||
final ConfigNode<String> alias = node(ConfigNode.builder("alias", String.class)
|
||||
.defaultValue("")
|
||||
.onLoadAndChange((oldValue, newValue) -> {
|
||||
worldManager.getWorldStore().changeAlias(
|
||||
ChatTextFormatter.removeColor(oldValue),
|
||||
ChatTextFormatter.removeColor(newValue),
|
||||
keyOrName.usableKey()
|
||||
);
|
||||
if (world == null) return;
|
||||
world.updateColourlessAlias();
|
||||
worldManager.getWorldStore().changeAlias(
|
||||
ChatTextFormatter.removeColor(oldValue), ChatTextFormatter.removeColor(newValue), world);
|
||||
}));
|
||||
|
||||
final ConfigNode<Boolean> allowAdvancementGrant = node(ConfigNode.builder("allow-advancement-grant", Boolean.class)
|
||||
|
||||
@@ -15,6 +15,7 @@ import org.mvplugins.multiverse.core.world.key.WorldKeyOrName;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -119,16 +120,16 @@ final class WorldStore {
|
||||
unloadedList.add(unloadedMap.get(world.getKey().toString()));
|
||||
}
|
||||
|
||||
void changeAlias(@Nullable String oldAlias, @Nullable String newAlias, @NotNull MultiverseWorld world) {
|
||||
void changeAlias(@Nullable String oldAlias, @Nullable String newAlias, @NotNull NamespacedKey worldKey) {
|
||||
if (Objects.equals(oldAlias, newAlias)) {
|
||||
// nothing changed, ignore
|
||||
return;
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(oldAlias)) {
|
||||
aliasMap.remove(oldAlias, world.getKey().toString());
|
||||
aliasMap.remove(oldAlias.toLowerCase(Locale.ROOT), worldKey.toString());
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(newAlias)) {
|
||||
aliasMap.put(newAlias, world.getKey().toString());
|
||||
aliasMap.put(newAlias.toLowerCase(Locale.ROOT), worldKey.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,7 +264,7 @@ final class WorldStore {
|
||||
return null;
|
||||
}
|
||||
//TODO: Not sure if we should fail if there is multiple alias of the same name, but for now just return the first one
|
||||
return aliasMap.get(worldNameOrAlias).stream()
|
||||
return aliasMap.get(worldNameOrAlias.toLowerCase(Locale.ROOT)).stream()
|
||||
.findFirst()
|
||||
.orElse(worldNameOrAlias);
|
||||
}
|
||||
|
||||
@@ -7,58 +7,35 @@ import org.jvnet.hk2.annotations.Service;
|
||||
import org.mvplugins.multiverse.core.world.LoadedMultiverseWorld;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Service
|
||||
public final class EntityPurger {
|
||||
|
||||
public int purgeEntities(LoadedMultiverseWorld world) {
|
||||
AtomicInteger purgeCount = new AtomicInteger(0);
|
||||
world.getBukkitWorld().peek(bukkitWorld -> {
|
||||
for (Entity entity : bukkitWorld.getEntities()) {
|
||||
if (!world.getEntitySpawnConfig().shouldAllowSpawn(entity)) {
|
||||
entity.remove();
|
||||
purgeCount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
});
|
||||
return purgeCount.get();
|
||||
return purgeEntitiesWithCondition(world, entity -> !world.getEntitySpawnConfig().shouldAllowSpawn(entity));
|
||||
}
|
||||
|
||||
public int purgeEntities(LoadedMultiverseWorld world, SpawnCategory spawnCategory) {
|
||||
AtomicInteger purgeCount = new AtomicInteger(0);
|
||||
world.getBukkitWorld().peek(bukkitWorld -> {
|
||||
for (Entity entity : bukkitWorld.getEntities()) {
|
||||
if (entity.getSpawnCategory() == spawnCategory) {
|
||||
entity.remove();
|
||||
purgeCount.incrementAndGet();
|
||||
}
|
||||
}
|
||||
});
|
||||
return purgeCount.get();
|
||||
return purgeEntitiesWithCondition(world, entity -> entity.getSpawnCategory().equals(spawnCategory));
|
||||
}
|
||||
|
||||
public int purgeEntities(LoadedMultiverseWorld world, SpawnCategory... spawnCategories) {
|
||||
Set<SpawnCategory> spawnCategoriesSet = Set.of(spawnCategories);
|
||||
AtomicInteger purgeCount = new AtomicInteger(0);
|
||||
world.getBukkitWorld().peek(bukkitWorld -> bukkitWorld.getEntities().stream()
|
||||
.filter(entity -> !(entity instanceof Player))
|
||||
.filter(entity -> spawnCategoriesSet.contains(entity.getSpawnCategory()))
|
||||
.forEach(entity -> {
|
||||
entity.remove();
|
||||
purgeCount.incrementAndGet();
|
||||
}));
|
||||
return purgeCount.get();
|
||||
return purgeEntitiesWithCondition(world, entity -> spawnCategoriesSet.contains(entity.getSpawnCategory()));
|
||||
}
|
||||
|
||||
public int purgeAllEntities(LoadedMultiverseWorld world) {
|
||||
AtomicInteger purgeCount = new AtomicInteger(0);
|
||||
world.getBukkitWorld().peek(bukkitWorld -> bukkitWorld.getEntities().stream()
|
||||
.filter(entity -> !(entity instanceof Player))
|
||||
.forEach(entity -> {
|
||||
entity.remove();
|
||||
purgeCount.incrementAndGet();
|
||||
}));
|
||||
return purgeCount.get();
|
||||
return purgeEntitiesWithCondition(world, entity -> true);
|
||||
}
|
||||
|
||||
private int purgeEntitiesWithCondition(LoadedMultiverseWorld world, Predicate<Entity> condition) {
|
||||
return Math.toIntExact(world.getBukkitWorld()
|
||||
.map(bukkitWorld -> bukkitWorld.getEntities().stream()
|
||||
.filter(entity -> !(entity instanceof Player))
|
||||
.filter(condition)
|
||||
.peek(Entity::remove)
|
||||
.count())
|
||||
.getOrElse(0L));
|
||||
}
|
||||
}
|
||||
+23
-5
@@ -27,6 +27,9 @@ import java.util.stream.Stream;
|
||||
@Service
|
||||
public final class PotentialWorldFinder {
|
||||
|
||||
private static final int MAX_RECURSION_DEPTH = 3;
|
||||
private static final int MAX_FOLDER_TRAVERSAL_LIMIT = 100;
|
||||
|
||||
private final WorldManager worldManager;
|
||||
private final WorldNameChecker worldNameChecker;
|
||||
|
||||
@@ -56,6 +59,7 @@ public final class PotentialWorldFinder {
|
||||
private Stream<String> findFromRootFolder() {
|
||||
Path worldContainer = Bukkit.getWorldContainer().toPath();
|
||||
return Arrays.stream(listFolders(worldContainer))
|
||||
.limit(MAX_FOLDER_TRAVERSAL_LIMIT)
|
||||
.filter(worldNameChecker::isValidWorldFolder)
|
||||
.map(File::getName)
|
||||
.filter(worldNameChecker::isValidWorldName)
|
||||
@@ -65,15 +69,29 @@ public final class PotentialWorldFinder {
|
||||
private Stream<String> findFromDimensionsFolder() {
|
||||
Path worldContainer = BukkitCompatibility.getWorldFoldersDirectory();
|
||||
return Arrays.stream(listFolders(worldContainer))
|
||||
.map(File::getName)
|
||||
.flatMap(namespace -> Arrays.stream(listFolders(worldContainer.resolve(namespace)))
|
||||
.filter(worldNameChecker::isValidWorldFolder)
|
||||
.map(File::getName)
|
||||
.map(key -> namespace + ":" + key))
|
||||
.limit(MAX_FOLDER_TRAVERSAL_LIMIT)
|
||||
.flatMap(namespaceFile -> recursiveFindFromNamespaceFolder("", namespaceFile.toPath(), 0)
|
||||
.map(worldKey -> namespaceFile.getName() + ":" + worldKey))
|
||||
.filter(namespacedKey -> NamespacedKey.fromString(namespacedKey) != null)
|
||||
.filter(namespacedKey -> !worldManager.isWorld(namespacedKey));
|
||||
}
|
||||
|
||||
private Stream<String> recursiveFindFromNamespaceFolder(String prefix, Path subWorldContainer, int depth) {
|
||||
if (depth >= MAX_RECURSION_DEPTH) {
|
||||
return Stream.empty();
|
||||
}
|
||||
return Arrays.stream(listFolders(subWorldContainer))
|
||||
.limit(MAX_FOLDER_TRAVERSAL_LIMIT)
|
||||
.flatMap(folder -> worldNameChecker.isValidWorldFolder(folder)
|
||||
? Stream.of(concatPath(prefix, folder.getName()))
|
||||
: recursiveFindFromNamespaceFolder(
|
||||
concatPath(prefix, folder.getName()), folder.toPath(), depth + 1));
|
||||
}
|
||||
|
||||
private String concatPath(String prefix, String folderName) {
|
||||
return prefix.isEmpty() ? folderName : prefix + "/" + folderName;
|
||||
}
|
||||
|
||||
private @NotNull File[] listFolders(Path folder) {
|
||||
return Option.of(folder.toFile().listFiles(File::isDirectory))
|
||||
.getOrElse(() -> new File[0]);
|
||||
|
||||
Reference in new issue
Block a user