Add persistent spawns. Persistent spawns now saved to disk.

This commit is contained in:
2026-01-04 14:36:14 +01:00
commit 7ff811cb97
19 changed files with 942 additions and 0 deletions
@@ -0,0 +1,64 @@
package nl.getagripgal.persistentspawn;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.arguments.coordinates.Coordinates;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.phys.Vec3;
/**
* The command handlers for the mod.
*/
public class CommandHandlers {
/**
* The command handler for the `setpersistentspawn` command.
*
* @param context The command context.
* @return The exit code.
*/
public static int setPersistentSpawn(CommandContext<CommandSourceStack> context) {
Coordinates positionArgument = context.getArgument("position", Coordinates.class);
Identifier dimensionArgument = context.getArgument("dimension", Identifier.class);
PersistentSpawnManager.CurrentSpawn = positionArgument.getPosition(context.getSource());
PersistentSpawnManager.Dimension = ResourceKey.create(Registries.DIMENSION, dimensionArgument);
PersistentSpawnManager.syncToDisk();
Vec3 position = PersistentSpawnManager.CurrentSpawn;
context.getSource()
.sendSuccess(
() -> Component.literal("Set spawn at %s in %s".formatted(position.toString(),
dimensionArgument.toString())),
false);
return 1;
}
/**
* The command handler for the `setpersistentspawnenabled` command.
*
* @param context The command context.
* @return The exit code.
*/
public static int enablePersistentSpawn(CommandContext<CommandSourceStack> context) {
boolean enable = context.getArgument("enable", Boolean.class);
PersistentSpawnManager.Enabled = enable;
PersistentSpawnManager.syncToDisk();
if (!enable) {
context.getSource()
.sendSuccess(
() -> Component.literal("Disabled persistent spawn."), false);
return 1;
}
context.getSource()
.sendSuccess(
() -> Component.literal("Enabled persistent spawn."), false);
return 1;
}
}
@@ -0,0 +1,26 @@
package nl.getagripgal.persistentspawn;
import java.util.Set;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
/**
* The event handlers for the mod.
*/
public class EventHandlers {
/**
* The handler for the player join event.
*
* @param player
*/
@SuppressWarnings("null")
public static void onPlayerJoin(ServerPlayer player) {
if (!PersistentSpawnManager.Enabled) {
return;
}
ServerLevel level = (ServerLevel) player.level().getServer().getLevel(PersistentSpawnManager.Dimension);
player.teleportTo(level, PersistentSpawnManager.CurrentSpawn.x, PersistentSpawnManager.CurrentSpawn.y,
PersistentSpawnManager.CurrentSpawn.z, Set.of(), 0.0f, 0.0f, false);
}
}
@@ -0,0 +1,55 @@
package nl.getagripgal.persistentspawn;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.DimensionArgument;
import net.minecraft.commands.arguments.coordinates.Vec3Argument;
import net.minecraft.server.permissions.Permissions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mojang.brigadier.arguments.BoolArgumentType;
/**
* A very simple mod that implements the functionality of spawning a player at
* the same location on every join.
*/
public class PersistentSpawn implements ModInitializer {
public static final String MOD_ID = "spawnpointonjoin";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override
public void onInitialize() {
registerCommands();
registerEvents();
PersistentSpawnManager.loadFromDisk();
}
/**
* Register the commands.
*/
private void registerCommands() {
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher
.register(Commands.literal("setpersistentspawn")
.requires(source -> source.permissions().hasPermission(Permissions.COMMANDS_MODERATOR))
.then(Commands.argument("position", Vec3Argument.vec3())
.then(Commands.argument("dimension", DimensionArgument.dimension())
.executes(CommandHandlers::setPersistentSpawn)))));
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher
.register(Commands.literal("setpersistentspawnenabled")
.requires(source -> source.permissions().hasPermission(Permissions.COMMANDS_MODERATOR))
.then(Commands.argument("enable", BoolArgumentType.bool())
.executes(CommandHandlers::enablePersistentSpawn))));
}
/**
* Register the events.
*/
private void registerEvents() {
ServerPlayerEvents.JOIN.register(EventHandlers::onPlayerJoin);
}
}
@@ -0,0 +1,22 @@
package nl.getagripgal.persistentspawn;
/**
* The spawn config as stored on disk.
*/
public class PersistentSpawnConfig {
public int x;
public int y;
public int z;
public String dimension;
public boolean enabled;
public static PersistentSpawnConfig defaultConfig() {
PersistentSpawnConfig config = new PersistentSpawnConfig();
config.x = 0;
config.y = 100;
config.z = 0;
config.dimension = "minecraft:overworld";
config.enabled = false;
return config;
}
}
@@ -0,0 +1,78 @@
package nl.getagripgal.persistentspawn;
import java.io.File;
import com.moandjiezana.toml.Toml;
import com.moandjiezana.toml.TomlWriter;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.Identifier;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
/**
* Manages the persistent spawn point.
*/
public class PersistentSpawnManager {
/**
* The config file path.
*/
public static final String CONFIG_FILE = "config/spawnpointonjoin.toml";
/**
* The currently registered spawn position.
*/
public static Vec3 CurrentSpawn = Vec3.ZERO;
/**
* The dimension of the spawn location.
*/
public static ResourceKey<Level> Dimension = null;
/**
* Whether the persistent spawn is enabled.
*/
public static boolean Enabled = false;
/**
* Load the spawn config from disk.
*/
public static void loadFromDisk() {
try {
Toml toml = new Toml().read(new File(CONFIG_FILE));
PersistentSpawnConfig config = toml.to(PersistentSpawnConfig.class);
CurrentSpawn = new Vec3(config.x, config.y, config.z);
Dimension = ResourceKey.create(Registries.DIMENSION, Identifier.parse(config.dimension));
Enabled = config.enabled;
} catch (Exception e) {
PersistentSpawn.LOGGER.error(
"Failed to load persistent spawn config from disk, using defaults. This means persistent spawn will be disabled.",
e);
PersistentSpawnConfig defaultConfig = PersistentSpawnConfig.defaultConfig();
CurrentSpawn = new Vec3(defaultConfig.x, defaultConfig.y, defaultConfig.z);
Dimension = ResourceKey.create(Registries.DIMENSION, Identifier.parse(defaultConfig.dimension));
Enabled = defaultConfig.enabled;
}
}
/**
* Sync the current spawn config to spawn.
*/
public static void syncToDisk() {
try {
PersistentSpawnConfig config = new PersistentSpawnConfig();
config.x = (int) CurrentSpawn.x;
config.y = (int) CurrentSpawn.y;
config.z = (int) CurrentSpawn.z;
config.dimension = Dimension.identifier().toString();
config.enabled = Enabled;
TomlWriter writer = new TomlWriter();
writer.write(config, new File(CONFIG_FILE));
} catch (Exception e) {
PersistentSpawn.LOGGER.error("Failed to save persistent spawn config to disk.", e);
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

+30
View File
@@ -0,0 +1,30 @@
{
"schemaVersion": 1,
"id": "spawnpointonjoin",
"version": "1.0.0",
"name": "SpawnpointOnJoin",
"description": "A very simple mod that implements the functionality of spawning a player at the same location on every join.",
"authors": [
"GetAGripGal"
],
"contact": {
"homepage": "https://fabricmc.net/",
"sources": "https://github.com/FabricMC/fabric-example-mod"
},
"license": "CC0-1.0",
"icon": "assets/spawnpointonjoin/icon.png",
"environment": "*",
"entrypoints": {
"main": [
"nl.getagripgal.persistentspawn.PersistentSpawn"
],
"client": []
},
"mixins": [],
"depends": {
"fabricloader": ">=0.18.4",
"minecraft": "~1.21.11",
"java": ">=21",
"fabric-api": "*"
}
}
@@ -0,0 +1,12 @@
{
"required": true,
"package": "nl.getagripgal.persistentspawn.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"requireAnnotations": true
}
}