Implement proper spawn location

This commit is contained in:
Ben Woo 2023-09-03 23:25:10 +08:00
parent dc75e87223
commit f524c5bdde
No known key found for this signature in database
GPG Key ID: FB2A3645536E12C8
15 changed files with 177 additions and 22 deletions

View File

@ -26,10 +26,13 @@ import com.onarandombox.MultiverseCore.utils.TestingMode;
import com.onarandombox.MultiverseCore.utils.metrics.MetricsConfigurator;
import com.onarandombox.MultiverseCore.world.WorldProperties;
import com.onarandombox.MultiverseCore.worldnew.WorldManager;
import com.onarandombox.MultiverseCore.worldnew.config.NullLocation;
import com.onarandombox.MultiverseCore.worldnew.config.SpawnLocation;
import io.vavr.control.Try;
import jakarta.inject.Inject;
import jakarta.inject.Provider;
import me.main__.util.SerializationConfig.SerializationConfig;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
@ -102,6 +105,8 @@ public class MultiverseCore extends JavaPlugin implements MVCore {
@Override
public void onEnable() {
initializeDependencyInjection();
ConfigurationSerialization.registerClass(NullLocation.class);
ConfigurationSerialization.registerClass(SpawnLocation.class);
// Load our configs first as we need them for everything else.
var config = configProvider.get();

View File

@ -73,7 +73,7 @@ public class CreateCommand extends MultiverseCommand {
.add(CommandValueFlag.enumBuilder("--world-type", WorldType.class)
.addAlias("-t")
.build())
.add(CommandFlag.builder("--adjust-spawn")
.add(CommandFlag.builder("--no-adjust-spawn")
.addAlias("-n")
.build())
.add(CommandFlag.builder("--no-structures")
@ -109,7 +109,7 @@ public class CreateCommand extends MultiverseCommand {
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ENVIRONMENT, "{environment}", environment.name());
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_SEED, "{seed}", parsedFlags.flagValue("--seed", "RANDOM", String.class));
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_WORLDTYPE, "{worldType}", parsedFlags.flagValue("--world-type", WorldType.NORMAL, WorldType.class).name());
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ADJUSTSPAWN, "{adjustSpawn}", String.valueOf(parsedFlags.hasFlag("--adjust-spawn")));
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_ADJUSTSPAWN, "{adjustSpawn}", String.valueOf(!parsedFlags.hasFlag("--no-adjust-spawn")));
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_GENERATOR, "{generator}", parsedFlags.flagValue("--generator", "", String.class));
issuer.sendInfo(MVCorei18n.CREATE_PROPERTIES_STRUCTURES, "{structures}", String.valueOf(!parsedFlags.hasFlag("--no-structures")));
@ -119,7 +119,7 @@ public class CreateCommand extends MultiverseCommand {
.environment(environment)
.seed(parsedFlags.flagValue("--seed", String.class))
.worldType(parsedFlags.flagValue("--world-type", WorldType.NORMAL, WorldType.class))
.useSpawnAdjust(parsedFlags.hasFlag("--adjust-spawn"))
.useSpawnAdjust(!parsedFlags.hasFlag("--no-adjust-spawn"))
.generator(parsedFlags.flagValue("--generator", "", String.class))
.generateStructures(!parsedFlags.hasFlag("--no-structures"))
).onSuccess((success) -> {

View File

@ -24,7 +24,7 @@ import com.onarandombox.MultiverseCore.exceptions.PropertyDoesNotExistException;
import com.onarandombox.MultiverseCore.listeners.MVPlayerListener;
import com.onarandombox.MultiverseCore.world.configuration.AllowedPortalType;
import com.onarandombox.MultiverseCore.world.configuration.EnglishChatColor;
import com.onarandombox.MultiverseCore.world.configuration.SpawnLocation;
import com.onarandombox.MultiverseCore.worldnew.config.SpawnLocation;
import com.onarandombox.MultiverseCore.world.configuration.SpawnSettings;
import com.onarandombox.MultiverseCore.world.configuration.WorldPropertyValidator;
import me.main__.util.SerializationConfig.ChangeDeniedException;

View File

@ -9,7 +9,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.onarandombox.MultiverseCore.world.configuration.EntryFee;
import com.onarandombox.MultiverseCore.world.configuration.SpawnLocation;
import com.onarandombox.MultiverseCore.worldnew.config.SpawnLocation;
import com.onarandombox.MultiverseCore.world.configuration.SpawnSettings;
import com.onarandombox.MultiverseCore.world.configuration.WorldPropertyValidator;
import com.onarandombox.MultiverseCore.world.configuration.AllowedPortalType;

View File

@ -1,25 +1,45 @@
package com.onarandombox.MultiverseCore.worldnew;
import com.dumptruckman.minecraft.util.Logging;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.worldnew.config.NullLocation;
import com.onarandombox.MultiverseCore.worldnew.config.SpawnLocation;
import com.onarandombox.MultiverseCore.worldnew.config.WorldConfig;
import io.vavr.control.Option;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class MVWorld extends OfflineWorld {
private static final int SPAWN_LOCATION_SEARCH_TOLERANCE = 16;
private static final int SPAWN_LOCATION_SEARCH_RADIUS = 16;
private final UUID worldUid;
private final BlockSafety blockSafety;
private final SafeTTeleporter safeTTeleporter;
private final LocationManipulation locationManipulation;
MVWorld(
@NotNull World world,
@NotNull WorldConfig worldConfig
@NotNull WorldConfig worldConfig,
@NotNull BlockSafety blockSafety,
@NotNull SafeTTeleporter safeTTeleporter,
@NotNull LocationManipulation locationManipulation
) {
super(world.getName(), worldConfig);
this.worldUid = world.getUID();
this.blockSafety = blockSafety;
this.safeTTeleporter = safeTTeleporter;
this.locationManipulation = locationManipulation;
setupWorldConfig(world);
setupSpawnLocation(world);
}
private void setupWorldConfig(World world) {
@ -29,6 +49,56 @@ public class MVWorld extends OfflineWorld {
worldConfig.setSeed(world.getSeed());
}
private void setupSpawnLocation(World world) {
Location spawnLocation = worldConfig.getSpawnLocation();
if (spawnLocation == null || spawnLocation instanceof NullLocation) {
SpawnLocation newLocation = new SpawnLocation(readSpawnFromWorld(world));
worldConfig.setSpawnLocation(newLocation);
world.setSpawnLocation(newLocation.getBlockX(), newLocation.getBlockY(), newLocation.getBlockZ());
}
worldConfig.getSpawnLocation().setWorld(world);
}
private Location readSpawnFromWorld(World world) { // TODO: Refactor... this is copy pasted and bad
Location location = world.getSpawnLocation();
// Set the worldspawn to our configspawn
// Verify that location was safe
if (!blockSafety.playerCanSpawnHereSafely(location)) {
if (!this.getAdjustSpawn()) {
Logging.fine("Spawn location from world.dat file was unsafe!!");
Logging.fine("NOT adjusting spawn for '" + this.getAlias() + "' because you told me not to.");
Logging.fine("To turn on spawn adjustment for this world simply type:");
Logging.fine("/mvm set adjustspawn true " + this.getAlias());
return location;
}
// If it's not, find a better one.
Logging.warning("Spawn location from world.dat file was unsafe. Adjusting...");
Logging.warning("Original Location: " + locationManipulation.strCoordsRaw(location));
Location newSpawn = safeTTeleporter.getSafeLocation(location,
SPAWN_LOCATION_SEARCH_TOLERANCE, SPAWN_LOCATION_SEARCH_RADIUS);
// I think we could also do this, as I think this is what Notch does.
// Not sure how it will work in the nether...
//Location newSpawn = this.spawnLocation.getWorld().getHighestBlockAt(this.spawnLocation).getLocation();
if (newSpawn != null) {
Logging.info("New Spawn for '%s' is located at: %s",
this.getName(), locationManipulation.locationToString(newSpawn));
return newSpawn;
} else {
// If it's a standard end world, let's check in a better place:
Location newerSpawn;
newerSpawn = blockSafety.getTopBlock(new Location(world, 0, 0, 0));
if (newerSpawn != null) {
Logging.info("New Spawn for '%s' is located at: %s",
this.getName(), locationManipulation.locationToString(newerSpawn));
return newerSpawn;
} else {
Logging.severe("Safe spawn NOT found!!!");
}
}
}
return location;
}
public Option<World> getBukkitWorld() {
return Option.of(Bukkit.getWorld(worldUid));
}

View File

@ -2,6 +2,9 @@ package com.onarandombox.MultiverseCore.worldnew;
import com.dumptruckman.minecraft.util.Logging;
import com.google.common.base.Strings;
import com.onarandombox.MultiverseCore.api.BlockSafety;
import com.onarandombox.MultiverseCore.api.LocationManipulation;
import com.onarandombox.MultiverseCore.api.SafeTTeleporter;
import com.onarandombox.MultiverseCore.utils.file.FileUtils;
import com.onarandombox.MultiverseCore.utils.result.Result;
import com.onarandombox.MultiverseCore.worldnew.config.WorldConfig;
@ -34,13 +37,25 @@ public class WorldManager {
private final Map<String, MVWorld> worldsMap;
private final WorldsConfigManager worldsConfigManager;
private final WorldNameChecker worldNameChecker;
private final BlockSafety blockSafety;
private final SafeTTeleporter safeTTeleporter;
private final LocationManipulation locationManipulation;
@Inject
WorldManager(@NotNull WorldsConfigManager worldsConfigManager, @NotNull WorldNameChecker worldNameChecker) {
WorldManager(
@NotNull WorldsConfigManager worldsConfigManager,
@NotNull WorldNameChecker worldNameChecker,
@NotNull BlockSafety blockSafety,
@NotNull SafeTTeleporter safeTTeleporter,
@NotNull LocationManipulation locationManipulation
) {
this.offlineWorldsMap = new HashMap<>();
this.worldsMap = new HashMap<>();
this.worldsConfigManager = worldsConfigManager;
this.worldNameChecker = worldNameChecker;
this.blockSafety = blockSafety;
this.safeTTeleporter = safeTTeleporter;
this.locationManipulation = locationManipulation;
}
public void initAllWorlds() {
@ -166,7 +181,7 @@ public class WorldManager {
OfflineWorld offlineWorld = new OfflineWorld(world.getName(), worldConfig);
offlineWorldsMap.put(offlineWorld.getName(), offlineWorld);
MVWorld mvWorld = new MVWorld(world, worldConfig);
MVWorld mvWorld = new MVWorld(world, worldConfig, blockSafety, safeTTeleporter, locationManipulation);
worldsMap.put(mvWorld.getName(), mvWorld);
return mvWorld;
}
@ -197,7 +212,7 @@ public class WorldManager {
// Our multiverse world
WorldConfig worldConfig = worldsConfigManager.getWorldConfig(offlineWorld.getName());
MVWorld mvWorld = new MVWorld(world, worldConfig);
MVWorld mvWorld = new MVWorld(world, worldConfig, blockSafety, safeTTeleporter, locationManipulation);
worldsMap.put(mvWorld.getName(), mvWorld);
saveWorldsConfig();

View File

@ -0,0 +1,53 @@
package com.onarandombox.MultiverseCore.worldnew.config;
import com.onarandombox.MultiverseCore.world.SimpleMVWorld;
import org.bukkit.Location;
import org.bukkit.configuration.serialization.SerializableAs;
import org.bukkit.util.Vector;
import java.util.Collections;
import java.util.Map;
/**
* Null-location.
*/
@SerializableAs("MVNullLocation (It's a bug if you see this in your config file)")
public final class NullLocation extends SpawnLocation {
public NullLocation() {
super(0, -1, 0);
}
@Override
public Location clone() {
throw new UnsupportedOperationException();
};
@Override
public Map<String, Object> serialize() {
return Collections.emptyMap();
}
/**
* Let Bukkit be able to deserialize this.
* @param args The map.
* @return The deserialized object.
*/
public static SimpleMVWorld.NullLocation deserialize(Map<String, Object> args) {
return new SimpleMVWorld.NullLocation();
}
@Override
public Vector toVector() {
throw new UnsupportedOperationException();
}
@Override
public int hashCode() {
return -1;
};
@Override
public String toString() {
return "Location{null}";
};
}

View File

@ -1,4 +1,4 @@
package com.onarandombox.MultiverseCore.world.configuration;
package com.onarandombox.MultiverseCore.worldnew.config;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

View File

@ -154,6 +154,7 @@ public class WorldConfigNodes {
.build());
public final ConfigNode<Location> SPAWN_LOCATION = node(ConfigNode.builder("spawn-location", Location.class)
.defaultValue(new NullLocation())
.name("spawn-location")
.build());

View File

@ -7,25 +7,15 @@
package com.onarandombox.MultiverseCore;
import java.io.File;
import com.onarandombox.MultiverseCore.api.MVWorldManager;
import com.onarandombox.MultiverseCore.api.MVWorld;
import com.onarandombox.MultiverseCore.world.configuration.SpawnLocation;
import com.onarandombox.MultiverseCore.utils.MockWorldFactory;
import com.onarandombox.MultiverseCore.utils.TestInstanceCreator;
import com.onarandombox.MultiverseCore.world.WorldProperties;
import org.bukkit.ChatColor;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.EntityRegainHealthEvent;
@ -47,9 +37,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

View File

@ -1,5 +1,6 @@
package org.mvplugins.multiverse.core.world
import com.onarandombox.MultiverseCore.worldnew.config.SpawnLocation
import com.onarandombox.MultiverseCore.worldnew.config.WorldsConfigManager
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
@ -47,6 +48,7 @@ class WorldConfigMangerTest : TestWithMockBukkit() {
val worldConfig = worldConfigManager.getWorldConfig("world")
worldConfig.setProperty("adjust-spawn", true)
worldConfig.setProperty("alias", "newalias")
worldConfig.setProperty("spawn-location", SpawnLocation(-64.0, 64.0, 48.0))
worldConfigManager.save()
compareConfigFile("worlds2.yml", "/properties_worlds.yml")
}

View File

@ -22,6 +22,8 @@ world:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true
@ -56,6 +58,8 @@ world_nether:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true

View File

@ -22,6 +22,8 @@ world_nether:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true

View File

@ -22,6 +22,8 @@ world:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true
@ -56,6 +58,8 @@ world_nether:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true
@ -90,6 +94,8 @@ newworld:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true

View File

@ -22,6 +22,13 @@ world:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVSpawnLocation
x: -64.0
y: 64.0
z: 48.0
pitch: 0.0
yaw: 0.0
spawning:
animals:
spawn: true
@ -56,6 +63,8 @@ world_nether:
respawn-world: ''
scale: 1.0
seed: -9223372036854775808
spawn-location:
==: MVNullLocation (It's a bug if you see this in your config file)
spawning:
animals:
spawn: true