cleaning
This commit is contained in:
parent
57f0f340a9
commit
120ab466aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ run/
|
|||||||
run-data/
|
run-data/
|
||||||
.idea/
|
.idea/
|
||||||
.gradle/
|
.gradle/
|
||||||
|
.c*
|
||||||
|
|||||||
@ -38,7 +38,7 @@ mod_name=TravelersSuitcase
|
|||||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
||||||
mod_license=MIT
|
mod_license=MIT
|
||||||
# The mod version. See https://semver.org/
|
# The mod version. See https://semver.org/
|
||||||
mod_version=1.2.7-SNAPSHOT
|
mod_version=1.2.7-SNAPSHOTv2
|
||||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
||||||
# This should match the base package used for the mod sources.
|
# This should match the base package used for the mod sources.
|
||||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
package io.lampnet.travelerssuitcase;
|
package io.lampnet.travelerssuitcase;
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.Item;
|
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraftforge.common.ForgeConfigSpec;
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
@ -10,20 +11,210 @@ import net.minecraftforge.registries.ForgeRegistries;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Mod.EventBusSubscriber(modid = TravelersSuitcase.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
@Mod.EventBusSubscriber(modid = TravelersSuitcase.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||||
public class Config {
|
public class Config {
|
||||||
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
private static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||||
|
|
||||||
static final ForgeConfigSpec SPEC = BUILDER.build();
|
public static final ForgeConfigSpec.BooleanValue CAN_CAPTURE_HOSTILE;
|
||||||
|
public static final ForgeConfigSpec.ConfigValue<List<? extends String>> ENTITY_BLACKLIST;
|
||||||
|
|
||||||
private static boolean validateItemName(final Object obj) {
|
public static final ForgeConfigSpec.LongValue DEFAULT_TIME_OF_DAY;
|
||||||
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(ResourceLocation.parse(itemName));
|
|
||||||
|
public static final ForgeConfigSpec.BooleanValue SHOULD_TICK_TIME;
|
||||||
|
public static final ForgeConfigSpec.BooleanValue TICK_WHEN_EMPTY;
|
||||||
|
|
||||||
|
public static final ForgeConfigSpec.IntValue DEFAULT_SUNNY_TIME;
|
||||||
|
public static final ForgeConfigSpec.BooleanValue DEFAULT_RAINING;
|
||||||
|
public static final ForgeConfigSpec.IntValue DEFAULT_RAIN_TIME;
|
||||||
|
public static final ForgeConfigSpec.BooleanValue DEFAULT_THUNDERING;
|
||||||
|
public static final ForgeConfigSpec.IntValue DEFAULT_THUNDER_TIME;
|
||||||
|
|
||||||
|
public static final ForgeConfigSpec.IntValue DIMENSION_HEIGHT;
|
||||||
|
public static final ForgeConfigSpec.IntValue DIMENSION_MIN_Y;
|
||||||
|
public static final ForgeConfigSpec.DoubleValue COORDINATE_SCALE;
|
||||||
|
public static final ForgeConfigSpec.DoubleValue AMBIENT_LIGHT;
|
||||||
|
|
||||||
|
static final ForgeConfigSpec SPEC;
|
||||||
|
|
||||||
|
static {
|
||||||
|
BUILDER.comment("Entity Configuration").push("entities");
|
||||||
|
|
||||||
|
CAN_CAPTURE_HOSTILE = BUILDER
|
||||||
|
.comment("Whether hostile entities can be captured in suitcases")
|
||||||
|
.define("canCaptureHostile", false);
|
||||||
|
|
||||||
|
ENTITY_BLACKLIST = BUILDER
|
||||||
|
.comment("List of entity types that cannot be captured (e.g., minecraft:ender_dragon)")
|
||||||
|
.defineListAllowEmpty("blacklistedEntities",
|
||||||
|
List.of("minecraft:ender_dragon", "minecraft:wither"),
|
||||||
|
Config::validateEntityName);
|
||||||
|
|
||||||
|
BUILDER.pop();
|
||||||
|
|
||||||
|
BUILDER.comment("Pocket Dimension Configuration").push("pocket_dimensions");
|
||||||
|
|
||||||
|
DEFAULT_TIME_OF_DAY = BUILDER
|
||||||
|
.comment("Default time of day in pocket dimensions (0-24000, where 6000 is noon)")
|
||||||
|
.defineInRange("defaultTimeOfDay", 6000L, 0L, 24000L);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SHOULD_TICK_TIME = BUILDER
|
||||||
|
.comment("Whether time should advance in pocket dimensions")
|
||||||
|
.define("shouldTickTime", true);
|
||||||
|
|
||||||
|
TICK_WHEN_EMPTY = BUILDER
|
||||||
|
.comment("Whether pocket dimensions should tick when no players are present")
|
||||||
|
.define("tickWhenEmpty", true);
|
||||||
|
|
||||||
|
BUILDER.pop();
|
||||||
|
|
||||||
|
BUILDER.comment("Weather Configuration").push("weather");
|
||||||
|
|
||||||
|
DEFAULT_SUNNY_TIME = BUILDER
|
||||||
|
.comment("Default duration of sunny weather in pocket dimensions (ticks)")
|
||||||
|
.defineInRange("defaultSunnyTime", Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
DEFAULT_RAINING = BUILDER
|
||||||
|
.comment("Whether pocket dimensions should start with rain")
|
||||||
|
.define("defaultRaining", false);
|
||||||
|
|
||||||
|
DEFAULT_RAIN_TIME = BUILDER
|
||||||
|
.comment("Default rain duration in pocket dimensions (ticks)")
|
||||||
|
.defineInRange("defaultRainTime", 0, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
DEFAULT_THUNDERING = BUILDER
|
||||||
|
.comment("Whether pocket dimensions should start with thunder")
|
||||||
|
.define("defaultThundering", false);
|
||||||
|
|
||||||
|
DEFAULT_THUNDER_TIME = BUILDER
|
||||||
|
.comment("Default thunder duration in pocket dimensions (ticks)")
|
||||||
|
.defineInRange("defaultThunderTime", 0, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
BUILDER.pop();
|
||||||
|
|
||||||
|
BUILDER.comment("Dimension Properties").push("dimension_properties");
|
||||||
|
|
||||||
|
DIMENSION_HEIGHT = BUILDER
|
||||||
|
.comment("Height of pocket dimensions (must be multiple of 16)")
|
||||||
|
.defineInRange("dimensionHeight", 384, 64, 4064);
|
||||||
|
|
||||||
|
DIMENSION_MIN_Y = BUILDER
|
||||||
|
.comment("Minimum Y level for pocket dimensions")
|
||||||
|
.defineInRange("dimensionMinY", -64, -2032, 2016);
|
||||||
|
|
||||||
|
COORDINATE_SCALE = BUILDER
|
||||||
|
.comment("Coordinate scale for pocket dimensions")
|
||||||
|
.defineInRange("coordinateScale", 1.0, 0.00001, 30000000.0);
|
||||||
|
|
||||||
|
AMBIENT_LIGHT = BUILDER
|
||||||
|
.comment("Ambient light level in pocket dimensions (0.0 - 1.0)")
|
||||||
|
.defineInRange("ambientLight", 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
BUILDER.pop();
|
||||||
|
|
||||||
|
SPEC = BUILDER.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean validateEntityName(final Object obj) {
|
||||||
|
if (!(obj instanceof String entityName)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
ResourceLocation location = ResourceLocation.parse(entityName);
|
||||||
|
return ForgeRegistries.ENTITY_TYPES.containsKey(location);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<EntityType<?>> cachedEntityBlacklist = new HashSet<>();
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
static void onLoad(final ModConfigEvent event) {
|
static void onLoad(final ModConfigEvent event) {
|
||||||
|
if (event.getConfig().getSpec() == SPEC) {
|
||||||
|
updateCachedValues();
|
||||||
|
TravelersSuitcase.LOGGER.info("Configuration loaded");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateCachedValues() {
|
||||||
|
cachedEntityBlacklist = ENTITY_BLACKLIST.get().stream()
|
||||||
|
.map(entityName -> {
|
||||||
|
try {
|
||||||
|
ResourceLocation location = ResourceLocation.parse(entityName);
|
||||||
|
return ForgeRegistries.ENTITY_TYPES.getValue(location);
|
||||||
|
} catch (Exception e) {
|
||||||
|
TravelersSuitcase.LOGGER.warn("Invalid entity name in blacklist: {}", entityName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(entityType -> entityType != null)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canCaptureHostile() {
|
||||||
|
return CAN_CAPTURE_HOSTILE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<EntityType<?>> getEntityBlacklist() {
|
||||||
|
return new HashSet<>(cachedEntityBlacklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEntityBlacklisted(EntityType<?> entityType) {
|
||||||
|
return cachedEntityBlacklist.contains(entityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getDefaultTimeOfDay() {
|
||||||
|
return DEFAULT_TIME_OF_DAY.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static boolean shouldTickTime() {
|
||||||
|
return SHOULD_TICK_TIME.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean tickWhenEmpty() {
|
||||||
|
return TICK_WHEN_EMPTY.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDefaultSunnyTime() {
|
||||||
|
return DEFAULT_SUNNY_TIME.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDefaultRaining() {
|
||||||
|
return DEFAULT_RAINING.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDefaultRainTime() {
|
||||||
|
return DEFAULT_RAIN_TIME.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDefaultThundering() {
|
||||||
|
return DEFAULT_THUNDERING.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDefaultThunderTime() {
|
||||||
|
return DEFAULT_THUNDER_TIME.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDimensionHeight() {
|
||||||
|
return DIMENSION_HEIGHT.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getDimensionMinY() {
|
||||||
|
return DIMENSION_MIN_Y.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getCoordinateScale() {
|
||||||
|
return COORDINATE_SCALE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getAmbientLight() {
|
||||||
|
return AMBIENT_LIGHT.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
package io.lampnet.travelerssuitcase;
|
package io.lampnet.travelerssuitcase;
|
||||||
|
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import io.lampnet.travelerssuitcase.block.ModBlocks;
|
import io.lampnet.travelerssuitcase.block.ModBlocks;
|
||||||
@ -48,16 +48,18 @@ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||||
|
import net.minecraftforge.fml.ModLoadingContext;
|
||||||
|
import net.minecraftforge.fml.config.ModConfig;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
|
|
||||||
import io.lampnet.travelerssuitcase.world.RuntimeWorldHandle;
|
import io.lampnet.travelerssuitcase.world.RuntimeWorldHandle;
|
||||||
|
|
||||||
@ -67,36 +69,16 @@ public class TravelersSuitcase {
|
|||||||
public static final Logger LOGGER = LogManager.getLogger(MODID);
|
public static final Logger LOGGER = LogManager.getLogger(MODID);
|
||||||
public static final EnterPocketDimensionCriterion ENTER_POCKET_DIMENSION = CriteriaTriggers.register(new EnterPocketDimensionCriterion());
|
public static final EnterPocketDimensionCriterion ENTER_POCKET_DIMENSION = CriteriaTriggers.register(new EnterPocketDimensionCriterion());
|
||||||
|
|
||||||
private static boolean canCaptureHostile = false;
|
|
||||||
private static final Set<EntityType<?>> entityBlacklist = new HashSet<>();
|
|
||||||
|
|
||||||
// Public accessor methods for the configuration
|
|
||||||
public static boolean getCanCaptureHostile() {
|
public static boolean getCanCaptureHostile() {
|
||||||
return canCaptureHostile;
|
return Config.canCaptureHostile();
|
||||||
}
|
|
||||||
|
|
||||||
public static void setCanCaptureHostile(boolean value) {
|
|
||||||
canCaptureHostile = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<EntityType<?>> getEntityBlacklist() {
|
public static Set<EntityType<?>> getEntityBlacklist() {
|
||||||
return new HashSet<>(entityBlacklist);
|
return Config.getEntityBlacklist();
|
||||||
}
|
|
||||||
|
|
||||||
public static void addToBlacklist(EntityType<?> entityType) {
|
|
||||||
entityBlacklist.add(entityType);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean removeFromBlacklist(EntityType<?> entityType) {
|
|
||||||
return entityBlacklist.remove(entityType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBlacklisted(EntityType<?> entityType) {
|
public static boolean isBlacklisted(EntityType<?> entityType) {
|
||||||
return entityBlacklist.contains(entityType);
|
return Config.isEntityBlacklisted(entityType);
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearBlacklist() {
|
|
||||||
entityBlacklist.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TravelersSuitcase() {
|
public TravelersSuitcase() {
|
||||||
@ -106,15 +88,18 @@ public class TravelersSuitcase {
|
|||||||
ModBlocks.register(modEventBus);
|
ModBlocks.register(modEventBus);
|
||||||
ModItemGroups.register(modEventBus);
|
ModItemGroups.register(modEventBus);
|
||||||
ModBlockEntities.register(modEventBus);
|
ModBlockEntities.register(modEventBus);
|
||||||
|
FantasyInitializer.register(modEventBus);
|
||||||
|
|
||||||
|
// Register configuration
|
||||||
|
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
||||||
|
|
||||||
modEventBus.addListener(this::commonSetup);
|
modEventBus.addListener(this::commonSetup);
|
||||||
|
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
MinecraftForge.EVENT_BUS.register(TravelersSuitcase.class); // Register static methods
|
MinecraftForge.EVENT_BUS.register(TravelersSuitcase.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void commonSetup(final FMLCommonSetupEvent event) {
|
private void commonSetup(final FMLCommonSetupEvent event) {
|
||||||
// Register chunk generators during setup phase
|
|
||||||
new FantasyInitializer().onInitialize();
|
new FantasyInitializer().onInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,14 +107,6 @@ public class TravelersSuitcase {
|
|||||||
public static void onServerStarting(ServerStartingEvent event) {
|
public static void onServerStarting(ServerStartingEvent event) {
|
||||||
SuitcaseRegistryState.onServerStart(event.getServer());
|
SuitcaseRegistryState.onServerStart(event.getServer());
|
||||||
|
|
||||||
// Load configuration
|
|
||||||
try {
|
|
||||||
loadConfig(event.getServer());
|
|
||||||
LOGGER.info("Configuration loaded successfully");
|
|
||||||
} catch (IOException e) {
|
|
||||||
LOGGER.warn("Failed to load configuration, using defaults", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path registryFile = event.getServer().getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT)
|
Path registryFile = event.getServer().getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT)
|
||||||
.resolve("data")
|
.resolve("data")
|
||||||
.resolve(MODID)
|
.resolve(MODID)
|
||||||
@ -153,8 +130,7 @@ public class TravelersSuitcase {
|
|||||||
.setSeed(seed);
|
.setSeed(seed);
|
||||||
RuntimeWorldHandle handle = Fantasy.get(event.getServer()).getOrOpenPersistentWorld(worldId, cfg);
|
RuntimeWorldHandle handle = Fantasy.get(event.getServer()).getOrOpenPersistentWorld(worldId, cfg);
|
||||||
|
|
||||||
// Ensure the pocket dimension ticks even when empty to prevent entity tick issues
|
handle.setTickWhenEmpty(Config.tickWhenEmpty());
|
||||||
handle.setTickWhenEmpty(true);
|
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
TravelersSuitcase.LOGGER.error("Failed to reload pocket dimensions", e);
|
TravelersSuitcase.LOGGER.error("Failed to reload pocket dimensions", e);
|
||||||
@ -266,7 +242,6 @@ public class TravelersSuitcase {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset player entry to default position
|
|
||||||
PlayerEntryData playerData = PlayerEntryData.get(targetWorld);
|
PlayerEntryData playerData = PlayerEntryData.get(targetWorld);
|
||||||
playerData.resetToDefault();
|
playerData.resetToDefault();
|
||||||
|
|
||||||
@ -292,7 +267,6 @@ public class TravelersSuitcase {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset mob entry to default position
|
|
||||||
MobEntryData mobData = MobEntryData.get(targetWorld);
|
MobEntryData mobData = MobEntryData.get(targetWorld);
|
||||||
mobData.setEntry(new Vec3(35.5, 85.0, 16.5), 0f, 0f);
|
mobData.setEntry(new Vec3(35.5, 85.0, 16.5), 0f, 0f);
|
||||||
|
|
||||||
@ -329,19 +303,11 @@ public class TravelersSuitcase {
|
|||||||
)
|
)
|
||||||
.then(Commands.literal("canCaptureHostile")
|
.then(Commands.literal("canCaptureHostile")
|
||||||
.requires(src -> src.hasPermission(2))
|
.requires(src -> src.hasPermission(2))
|
||||||
.then(Commands.argument("value", BoolArgumentType.bool())
|
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
boolean value = BoolArgumentType.getBool(ctx, "value");
|
boolean enabled = Config.canCaptureHostile();
|
||||||
canCaptureHostile = value;
|
|
||||||
ctx.getSource().sendSuccess(() -> Component.literal(
|
ctx.getSource().sendSuccess(() -> Component.literal(
|
||||||
value ? "§aHostile mob capture enabled" : "§cHostile mob capture disabled"
|
"§7Hostile mob capture is currently: " + (enabled ? "§aEnabled" : "§cDisabled") +
|
||||||
), false);
|
"\n§7(Configure in config file)"
|
||||||
return 1;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.executes(ctx -> {
|
|
||||||
ctx.getSource().sendSuccess(() -> Component.literal(
|
|
||||||
"§7Hostile mob capture is currently: " + (canCaptureHostile ? "§aEnabled" : "§cDisabled")
|
|
||||||
), false);
|
), false);
|
||||||
return 1;
|
return 1;
|
||||||
})
|
})
|
||||||
@ -356,7 +322,7 @@ public class TravelersSuitcase {
|
|||||||
try {
|
try {
|
||||||
ResourceLocation entityId = ResourceLocation.parse(entityString);
|
ResourceLocation entityId = ResourceLocation.parse(entityString);
|
||||||
EntityType<?> entityType = BuiltInRegistries.ENTITY_TYPE.get(entityId);
|
EntityType<?> entityType = BuiltInRegistries.ENTITY_TYPE.get(entityId);
|
||||||
if (entityType == EntityType.PIG && !entityString.equals("minecraft:pig")) { // Default fallback
|
if (entityType == EntityType.PIG && !entityString.equals("minecraft:pig")) {
|
||||||
src.sendFailure(Component.literal("§cUnknown entity type: " + entityString));
|
src.sendFailure(Component.literal("§cUnknown entity type: " + entityString));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -364,7 +330,6 @@ public class TravelersSuitcase {
|
|||||||
src.sendFailure(Component.literal("§cCannot blacklist players"));
|
src.sendFailure(Component.literal("§cCannot blacklist players"));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
entityBlacklist.add(entityType);
|
|
||||||
src.sendSuccess(() -> Component.literal("§aAdded " + entityId + " to blacklist"), false);
|
src.sendSuccess(() -> Component.literal("§aAdded " + entityId + " to blacklist"), false);
|
||||||
return 1;
|
return 1;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -386,11 +351,7 @@ public class TravelersSuitcase {
|
|||||||
src.sendFailure(Component.literal("§cUnknown entity type: " + entityString));
|
src.sendFailure(Component.literal("§cUnknown entity type: " + entityString));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (entityBlacklist.remove(entityType)) {
|
src.sendSuccess(() -> Component.literal("§eEntity blacklist is managed through configuration files"), false);
|
||||||
src.sendSuccess(() -> Component.literal("§aRemoved " + entityId + " from blacklist"), false);
|
|
||||||
} else {
|
|
||||||
src.sendSuccess(() -> Component.literal("§7" + entityId + " was not in blacklist"), false);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
src.sendFailure(Component.literal("§cInvalid entity identifier: " + entityString));
|
src.sendFailure(Component.literal("§cInvalid entity identifier: " + entityString));
|
||||||
@ -402,11 +363,12 @@ public class TravelersSuitcase {
|
|||||||
.then(Commands.literal("list")
|
.then(Commands.literal("list")
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
var src = ctx.getSource();
|
var src = ctx.getSource();
|
||||||
if (entityBlacklist.isEmpty()) {
|
Set<EntityType<?>> blacklist = Config.getEntityBlacklist();
|
||||||
|
if (blacklist.isEmpty()) {
|
||||||
src.sendSuccess(() -> Component.literal("§7No entities are blacklisted"), false);
|
src.sendSuccess(() -> Component.literal("§7No entities are blacklisted"), false);
|
||||||
} else {
|
} else {
|
||||||
src.sendSuccess(() -> Component.literal("§aBlacklisted entities:"), false);
|
src.sendSuccess(() -> Component.literal("§aBlacklisted entities:"), false);
|
||||||
entityBlacklist.forEach(entityType -> {
|
blacklist.forEach(entityType -> {
|
||||||
var id = BuiltInRegistries.ENTITY_TYPE.getKey(entityType);
|
var id = BuiltInRegistries.ENTITY_TYPE.getKey(entityType);
|
||||||
src.sendSuccess(() -> Component.literal(" " + id), false);
|
src.sendSuccess(() -> Component.literal(" " + id), false);
|
||||||
});
|
});
|
||||||
@ -417,125 +379,15 @@ public class TravelersSuitcase {
|
|||||||
.then(Commands.literal("clear")
|
.then(Commands.literal("clear")
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
var src = ctx.getSource();
|
var src = ctx.getSource();
|
||||||
int count = entityBlacklist.size();
|
src.sendSuccess(() -> Component.literal("§eEntity blacklist is managed through configuration files"), false);
|
||||||
entityBlacklist.clear();
|
|
||||||
src.sendSuccess(() -> Component.literal("§aCleared blacklist (removed " + count + " entities)"), false);
|
|
||||||
return 1;
|
return 1;
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
|
||||||
.then(Commands.literal("config")
|
|
||||||
.requires(src -> src.hasPermission(2))
|
|
||||||
.then(Commands.literal("save")
|
|
||||||
.executes(ctx -> {
|
|
||||||
var src = ctx.getSource();
|
|
||||||
try {
|
|
||||||
saveConfig(src.getServer());
|
|
||||||
src.sendSuccess(() -> Component.literal("§aConfiguration saved successfully"), false);
|
|
||||||
return 1;
|
|
||||||
} catch (Exception e) {
|
|
||||||
src.sendFailure(Component.literal("§cFailed to save configuration: " + e.getMessage()));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(Commands.literal("load")
|
|
||||||
.executes(ctx -> {
|
|
||||||
var src = ctx.getSource();
|
|
||||||
try {
|
|
||||||
loadConfig(src.getServer());
|
|
||||||
src.sendSuccess(() -> Component.literal("§aConfiguration loaded successfully"), false);
|
|
||||||
return 1;
|
|
||||||
} catch (Exception e) {
|
|
||||||
src.sendFailure(Component.literal("§cFailed to load configuration: " + e.getMessage()));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(Commands.literal("reload")
|
|
||||||
.executes(ctx -> {
|
|
||||||
var src = ctx.getSource();
|
|
||||||
try {
|
|
||||||
loadConfig(src.getServer());
|
|
||||||
src.sendSuccess(() -> Component.literal("§aConfiguration reloaded successfully"), false);
|
|
||||||
return 1;
|
|
||||||
} catch (Exception e) {
|
|
||||||
src.sendFailure(Component.literal("§cFailed to reload configuration: " + e.getMessage()));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
event.getDispatcher().register(builder);
|
event.getDispatcher().register(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void saveConfig(MinecraftServer server) throws IOException {
|
|
||||||
Path configDir = server.getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT)
|
|
||||||
.resolve("data")
|
|
||||||
.resolve(MODID);
|
|
||||||
|
|
||||||
Files.createDirectories(configDir);
|
|
||||||
|
|
||||||
Path configFile = configDir.resolve("config.properties");
|
|
||||||
|
|
||||||
StringBuilder content = new StringBuilder();
|
|
||||||
content.append("canCaptureHostile=").append(canCaptureHostile).append("\n");
|
|
||||||
content.append("blacklistedEntities=");
|
|
||||||
|
|
||||||
boolean first = true;
|
|
||||||
for (EntityType<?> entityType : entityBlacklist) {
|
|
||||||
if (!first) {
|
|
||||||
content.append(",");
|
|
||||||
}
|
|
||||||
content.append(BuiltInRegistries.ENTITY_TYPE.getKey(entityType));
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
content.append("\n");
|
|
||||||
|
|
||||||
Files.writeString(configFile, content.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void loadConfig(MinecraftServer server) throws IOException {
|
|
||||||
Path configFile = server.getWorldPath(net.minecraft.world.level.storage.LevelResource.ROOT)
|
|
||||||
.resolve("data")
|
|
||||||
.resolve(MODID)
|
|
||||||
.resolve("config.properties");
|
|
||||||
|
|
||||||
if (!Files.exists(configFile)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entityBlacklist.clear();
|
|
||||||
|
|
||||||
for (String line : Files.readAllLines(configFile)) {
|
|
||||||
String[] parts = line.split("=", 2);
|
|
||||||
if (parts.length != 2) continue;
|
|
||||||
|
|
||||||
String key = parts[0].trim();
|
|
||||||
String value = parts[1].trim();
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case "canCaptureHostile":
|
|
||||||
canCaptureHostile = Boolean.parseBoolean(value);
|
|
||||||
break;
|
|
||||||
case "blacklistedEntities":
|
|
||||||
if (!value.isEmpty()) {
|
|
||||||
for (String entityId : value.split(",")) {
|
|
||||||
try {
|
|
||||||
ResourceLocation id = ResourceLocation.parse(entityId.trim());
|
|
||||||
EntityType<?> entityType = BuiltInRegistries.ENTITY_TYPE.get(id);
|
|
||||||
if (entityType != EntityType.PIG || entityId.trim().equals("minecraft:pig")) {
|
|
||||||
entityBlacklist.add(entityType);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.warn("Failed to parse entity ID from config: " + entityId, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public void onUseEntity(PlayerInteractEvent.EntityInteract event) {
|
public void onUseEntity(PlayerInteractEvent.EntityInteract event) {
|
||||||
@ -576,7 +428,7 @@ public class TravelersSuitcase {
|
|||||||
if (!(entity instanceof LivingEntity mob)) {
|
if (!(entity instanceof LivingEntity mob)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (entityBlacklist.contains(mob.getType())) {
|
if (Config.isEntityBlacklisted(mob.getType())) {
|
||||||
player.displayClientMessage(Component.literal("§c☒"), true);
|
player.displayClientMessage(Component.literal("§c☒"), true);
|
||||||
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f);
|
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f);
|
||||||
event.setCancellationResult(InteractionResult.FAIL);
|
event.setCancellationResult(InteractionResult.FAIL);
|
||||||
@ -584,7 +436,7 @@ public class TravelersSuitcase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean isHostile = mob instanceof Enemy || (mob instanceof Wolf wolf && wolf.isAngryAtAllPlayers(world));
|
boolean isHostile = mob instanceof Enemy || (mob instanceof Wolf wolf && wolf.isAngryAtAllPlayers(world));
|
||||||
if (!canCaptureHostile && isHostile) {
|
if (!Config.canCaptureHostile() && isHostile) {
|
||||||
player.displayClientMessage(Component.literal("§c☒"), true);
|
player.displayClientMessage(Component.literal("§c☒"), true);
|
||||||
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f);
|
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f);
|
||||||
event.setCancellationResult(InteractionResult.FAIL);
|
event.setCancellationResult(InteractionResult.FAIL);
|
||||||
@ -608,7 +460,6 @@ public class TravelersSuitcase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key rescue mob
|
|
||||||
if (stack.getItem() instanceof KeystoneItem) {
|
if (stack.getItem() instanceof KeystoneItem) {
|
||||||
ResourceLocation dimId = world.dimension().location();
|
ResourceLocation dimId = world.dimension().location();
|
||||||
String namespace = dimId.getNamespace();
|
String namespace = dimId.getNamespace();
|
||||||
|
|||||||
@ -312,7 +312,7 @@ public class SuitcaseBlock extends BaseEntityBlock {
|
|||||||
CompoundTag display = stack.getOrCreateTagElement("display");
|
CompoundTag display = stack.getOrCreateTagElement("display");
|
||||||
ListTag lore = new ListTag();
|
ListTag lore = new ListTag();
|
||||||
if (!suitcase.getEnteredPlayers().isEmpty()) {
|
if (!suitcase.getEnteredPlayers().isEmpty()) {
|
||||||
Component warningText = Component.literal("§c⚠ Contains " + suitcase.getEnteredPlayers().size() + " Traveler's!")
|
Component warningText = Component.literal("§c⚠ Contains " + suitcase.getEnteredPlayers().size() + " Travelers!")
|
||||||
.withStyle(ChatFormatting.RED);
|
.withStyle(ChatFormatting.RED);
|
||||||
lore.add(StringTag.valueOf(Component.Serializer.toJson(warningText)));
|
lore.add(StringTag.valueOf(Component.Serializer.toJson(warningText)));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -187,13 +187,11 @@ public class SuitcaseBlockEntity extends BlockEntity {
|
|||||||
@Override
|
@Override
|
||||||
public @NotNull CompoundTag getUpdateTag() {
|
public @NotNull CompoundTag getUpdateTag() {
|
||||||
CompoundTag nbt = new CompoundTag();
|
CompoundTag nbt = new CompoundTag();
|
||||||
// Only sync essential data to client, not player entry data which could cause position conflicts
|
|
||||||
if (boundKeystoneName != null) {
|
if (boundKeystoneName != null) {
|
||||||
nbt.putString("BoundKeystone", boundKeystoneName);
|
nbt.putString("BoundKeystone", boundKeystoneName);
|
||||||
}
|
}
|
||||||
nbt.putBoolean("Locked", isLocked);
|
nbt.putBoolean("Locked", isLocked);
|
||||||
nbt.putBoolean("DimensionLocked", dimensionLocked);
|
nbt.putBoolean("DimensionLocked", dimensionLocked);
|
||||||
// Deliberately exclude EnteredPlayers from client sync to prevent coordinate conflicts
|
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,8 +7,8 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
|
|
||||||
public class MobEntryData extends SavedData {
|
public class MobEntryData extends SavedData {
|
||||||
private static final String DATA_KEY = "pocket_entry_data";
|
private static final String DATA_KEY = "pocket_entry_data";
|
||||||
private Vec3 entryPos = Vec3.ZERO;
|
private Vec3 entryPos;
|
||||||
private float entryYaw = 0f, entryPitch = 0f;
|
private float entryYaw, entryPitch;
|
||||||
|
|
||||||
public MobEntryData() {
|
public MobEntryData() {
|
||||||
super();
|
super();
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
public class PlayerEntryData extends SavedData {
|
public class PlayerEntryData extends SavedData {
|
||||||
private static final String DATA_KEY = "pocket_player_entry";
|
private static final String DATA_KEY = "pocket_player_entry";
|
||||||
|
|
||||||
private Vec3 entryPos = Vec3.ZERO;
|
private Vec3 entryPos;
|
||||||
private float entryYaw = 0f, entryPitch = 0f;
|
private float entryYaw, entryPitch;
|
||||||
private boolean isManuallySet = false;
|
private boolean isManuallySet = false;
|
||||||
|
|
||||||
public PlayerEntryData() {
|
public PlayerEntryData() {
|
||||||
|
|||||||
@ -56,22 +56,14 @@ public class KeystoneItem extends Item {
|
|||||||
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level world, Player player, @NotNull InteractionHand hand) {
|
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level world, Player player, @NotNull InteractionHand hand) {
|
||||||
ItemStack stack = player.getItemInHand(hand);
|
ItemStack stack = player.getItemInHand(hand);
|
||||||
|
|
||||||
// If already enchanted, do nothing
|
|
||||||
if (stack.isEnchanted()) {
|
if (stack.isEnchanted()) {
|
||||||
return InteractionResultHolder.pass(stack);
|
return InteractionResultHolder.pass(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no valid custom name, do nothing
|
|
||||||
if (!isValidKeystone(stack)) {
|
if (!isValidKeystone(stack)) {
|
||||||
return InteractionResultHolder.pass(stack);
|
return InteractionResultHolder.pass(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On client side, just return success
|
|
||||||
if (world.isClientSide) {
|
|
||||||
return InteractionResultHolder.success(stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The actual enchantment and dimension creation now happens in inventoryTick
|
|
||||||
return InteractionResultHolder.success(stack);
|
return InteractionResultHolder.success(stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,18 +76,15 @@ public class KeystoneItem extends Item {
|
|||||||
.resolve(dimensionName);
|
.resolve(dimensionName);
|
||||||
boolean dimensionExists = Files.exists(worldSavePath);
|
boolean dimensionExists = Files.exists(worldSavePath);
|
||||||
|
|
||||||
// Get biome registry - if this fails, the server isn't ready yet
|
|
||||||
var biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
|
var biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
|
||||||
|
|
||||||
RuntimeWorldConfig config = new RuntimeWorldConfig()
|
RuntimeWorldConfig config = new RuntimeWorldConfig()
|
||||||
.setGenerator(new PortalChunkGenerator(biomeRegistry))
|
.setGenerator(new PortalChunkGenerator(biomeRegistry))
|
||||||
.setSeed(server.overworld().getSeed())
|
.setSeed(server.overworld().getSeed());
|
||||||
.setShouldTickTime(true);
|
|
||||||
|
|
||||||
RuntimeWorldHandle handle = Fantasy.get(server)
|
RuntimeWorldHandle handle = Fantasy.get(server)
|
||||||
.getOrOpenPersistentWorld(worldId, config);
|
.getOrOpenPersistentWorld(worldId, config);
|
||||||
|
|
||||||
// Ensure the pocket dimension ticks even when empty to prevent entity tick issues
|
|
||||||
handle.setTickWhenEmpty(true);
|
handle.setTickWhenEmpty(true);
|
||||||
|
|
||||||
TravelersSuitcase.LOGGER.info("Created/loaded pocket dimension '{}', ticking enabled: {}",
|
TravelersSuitcase.LOGGER.info("Created/loaded pocket dimension '{}', ticking enabled: {}",
|
||||||
@ -105,7 +94,6 @@ public class KeystoneItem extends Item {
|
|||||||
|
|
||||||
if (!dimensionExists) {
|
if (!dimensionExists) {
|
||||||
ServerLevel world = handle.asWorld();
|
ServerLevel world = handle.asWorld();
|
||||||
// Schedule structure placement for next tick to ensure world is fully initialized
|
|
||||||
server.execute(() -> placeStructureDelayed(server, world, dimensionName));
|
server.execute(() -> placeStructureDelayed(server, world, dimensionName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,29 +107,10 @@ public class KeystoneItem extends Item {
|
|||||||
if (template != null) {
|
if (template != null) {
|
||||||
BlockPos pos = new BlockPos(0, 64, 0);
|
BlockPos pos = new BlockPos(0, 64, 0);
|
||||||
|
|
||||||
// Ensure the chunk is fully loaded and ready
|
|
||||||
ChunkPos chunkPos = new ChunkPos(pos);
|
ChunkPos chunkPos = new ChunkPos(pos);
|
||||||
world.getChunkSource().addRegionTicket(TicketType.UNKNOWN, chunkPos, 2, chunkPos);
|
world.getChunkSource().addRegionTicket(TicketType.UNKNOWN, chunkPos, 2, chunkPos);
|
||||||
|
|
||||||
// Force chunk to be fully loaded with all features
|
|
||||||
world.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true);
|
world.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.FULL, true);
|
||||||
|
|
||||||
// Place blocks first without entities to ensure support blocks exist
|
|
||||||
template.placeInWorld(
|
|
||||||
world,
|
|
||||||
pos,
|
|
||||||
pos,
|
|
||||||
new StructurePlaceSettings()
|
|
||||||
.setMirror(Mirror.NONE)
|
|
||||||
.setRotation(Rotation.NONE)
|
|
||||||
.setIgnoreEntities(true), // Skip entities first
|
|
||||||
world.getRandom(),
|
|
||||||
Block.UPDATE_ALL
|
|
||||||
);
|
|
||||||
|
|
||||||
world.setChunkForced(pos.getX() >> 4, pos.getZ() >> 4, true);
|
|
||||||
|
|
||||||
// Now place the structure again with entities, blocks won't replace since they're already there
|
|
||||||
template.placeInWorld(
|
template.placeInWorld(
|
||||||
world,
|
world,
|
||||||
pos,
|
pos,
|
||||||
@ -151,10 +120,11 @@ public class KeystoneItem extends Item {
|
|||||||
.setRotation(Rotation.NONE)
|
.setRotation(Rotation.NONE)
|
||||||
.setIgnoreEntities(false),
|
.setIgnoreEntities(false),
|
||||||
world.getRandom(),
|
world.getRandom(),
|
||||||
Block.UPDATE_NEIGHBORS // Only update neighbors, don't replace existing blocks
|
Block.UPDATE_ALL
|
||||||
);
|
);
|
||||||
|
|
||||||
// Force a save to ensure the forced chunk data is properly loaded for ticking
|
world.setChunkForced(pos.getX() >> 4, pos.getZ() >> 4, true);
|
||||||
|
|
||||||
world.save(null, true, false);
|
world.save(null, true, false);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -172,13 +142,11 @@ public class KeystoneItem extends Item {
|
|||||||
Files.createDirectories(registryDir);
|
Files.createDirectories(registryDir);
|
||||||
Path registryFile = registryDir.resolve("registry.txt");
|
Path registryFile = registryDir.resolve("registry.txt");
|
||||||
|
|
||||||
// load existing lines
|
|
||||||
Set<String> dims = new HashSet<>();
|
Set<String> dims = new HashSet<>();
|
||||||
if (Files.exists(registryFile)) {
|
if (Files.exists(registryFile)) {
|
||||||
dims.addAll(Files.readAllLines(registryFile));
|
dims.addAll(Files.readAllLines(registryFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add + save only if new
|
|
||||||
if (dims.add(dimensionName)) {
|
if (dims.add(dimensionName)) {
|
||||||
Files.write(registryFile, dims);
|
Files.write(registryFile, dims);
|
||||||
}
|
}
|
||||||
@ -217,7 +185,6 @@ public class KeystoneItem extends Item {
|
|||||||
stack.getTag().remove("CustomModelData");
|
stack.getTag().remove("CustomModelData");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-enchant and create dimension when item gets a valid custom name
|
|
||||||
if (!world.isClientSide() && hasValidName && !stack.isEnchanted()) {
|
if (!world.isClientSide() && hasValidName && !stack.isEnchanted()) {
|
||||||
String dimensionName = "pocket_dimension_" + keystoneName.replaceAll("[^a-z0-9_]", "");
|
String dimensionName = "pocket_dimension_" + keystoneName.replaceAll("[^a-z0-9_]", "");
|
||||||
createOrLoadPersistentDimension(world.getServer(), dimensionName);
|
createOrLoadPersistentDimension(world.getServer(), dimensionName);
|
||||||
@ -226,14 +193,15 @@ public class KeystoneItem extends Item {
|
|||||||
CompoundTag nbt = stack.getOrCreateTag();
|
CompoundTag nbt = stack.getOrCreateTag();
|
||||||
nbt.putInt("RepairCost", 32767);
|
nbt.putInt("RepairCost", 32767);
|
||||||
|
|
||||||
// Play sound effect if entity is a player
|
|
||||||
if (entity instanceof Player player) {
|
if (entity instanceof Player player) {
|
||||||
world.playSound(null, player.getX(), player.getY(), player.getZ(),
|
world.playSound(null, player.getX(), player.getY(), player.getZ(),
|
||||||
SoundEvents.AMETHYST_CLUSTER_FALL, SoundSource.PLAYERS, 2.0F, 2.0F);
|
SoundEvents.AMETHYST_CLUSTER_FALL, SoundSource.PLAYERS, 2.0F, 2.0F);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!world.isClientSide() && stack.hasTag() && stack.getTag().contains("Enchantments")) {
|
if (!world.isClientSide() && stack.hasTag()) {
|
||||||
|
assert stack.getTag() != null;
|
||||||
|
if (stack.getTag().contains("Enchantments")) {
|
||||||
CompoundTag nbt = stack.getOrCreateTag();
|
CompoundTag nbt = stack.getOrCreateTag();
|
||||||
if (nbt.getInt("RepairCost") < 32767) {
|
if (nbt.getInt("RepairCost") < 32767) {
|
||||||
nbt.putInt("RepairCost", 32767);
|
nbt.putInt("RepairCost", 32767);
|
||||||
@ -241,3 +209,4 @@ public class KeystoneItem extends Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@ -17,25 +17,21 @@ public abstract class MappedRegistryMixin<T> implements RemoveFromRegistry<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean fantasy$remove(T value) {
|
public boolean fantasy$remove(T value) {
|
||||||
// Implementation depends on access to private fields
|
|
||||||
// For now, return false as removal is complex
|
// For now, return false as removal is complex
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean fantasy$remove(ResourceLocation key) {
|
public boolean fantasy$remove(ResourceLocation key) {
|
||||||
// Implementation depends on access to private fields
|
|
||||||
// For now, return false as removal is complex
|
// For now, return false as removal is complex
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fantasy$setFrozen(boolean value) {
|
public void fantasy$setFrozen(boolean value) {
|
||||||
// Store the original frozen state so we can restore it later
|
|
||||||
if (!value && this.frozen) {
|
if (!value && this.frozen) {
|
||||||
this.fantasy$originalFrozenState = true;
|
this.fantasy$originalFrozenState = true;
|
||||||
}
|
}
|
||||||
// Actually modify the registry's frozen state
|
|
||||||
this.frozen = value;
|
this.frozen = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,21 +15,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||||||
public class ServerChunkManagerMixin {
|
public class ServerChunkManagerMixin {
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private ServerLevel level;
|
public ServerLevel level;
|
||||||
|
|
||||||
@Inject(method = "runDistanceManagerUpdates", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "runDistanceManagerUpdates", at = @At("HEAD"), cancellable = true)
|
||||||
private void onRunDistanceManagerUpdates(CallbackInfoReturnable<Boolean> cir) {
|
private void onRunDistanceManagerUpdates(CallbackInfoReturnable<Boolean> cir) {
|
||||||
// Only apply special chunk processing logic to RuntimeWorld instances (fantasy dimensions)
|
|
||||||
if (this.level instanceof RuntimeWorld) {
|
if (this.level instanceof RuntimeWorld) {
|
||||||
FantasyWorldAccess worldAccess = (FantasyWorldAccess) this.level;
|
FantasyWorldAccess worldAccess = (FantasyWorldAccess) this.level;
|
||||||
// Always allow distance manager updates if chunks are loaded (prevents breaking entity initialization)
|
|
||||||
// Only block when world is truly empty AND configured not to tick when empty
|
|
||||||
if (this.level.getChunkSource().getLoadedChunksCount() > 0 || worldAccess.fantasy$shouldTick()) {
|
if (this.level.getChunkSource().getLoadedChunksCount() > 0 || worldAccess.fantasy$shouldTick()) {
|
||||||
// Allow distance manager to run - this is critical for entity systems
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cir.setReturnValue(false);
|
cir.setReturnValue(false);
|
||||||
}
|
}
|
||||||
// Regular worlds (overworld, nether, end) process chunks normally without interference
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -17,17 +17,15 @@ import java.util.function.BooleanSupplier;
|
|||||||
@Mixin(ServerLevel.class)
|
@Mixin(ServerLevel.class)
|
||||||
public abstract class ServerWorldMixin implements FantasyWorldAccess {
|
public abstract class ServerWorldMixin implements FantasyWorldAccess {
|
||||||
@Unique
|
@Unique
|
||||||
private boolean fantasy$tickWhenEmpty = false; // Default to false, will be set to true for fantasy worlds
|
private boolean fantasy$tickWhenEmpty = false;
|
||||||
|
|
||||||
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "tick", at = @At("HEAD"), cancellable = true)
|
||||||
private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) {
|
private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) {
|
||||||
// Only apply special tick logic to RuntimeWorld instances (fantasy dimensions)
|
|
||||||
if ((Object) this instanceof RuntimeWorld) {
|
if ((Object) this instanceof RuntimeWorld) {
|
||||||
if (!this.fantasy$shouldTick()) {
|
if (!this.fantasy$shouldTick()) {
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Regular worlds (overworld, nether, end) tick normally without interference
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@ -43,16 +41,14 @@ public abstract class ServerWorldMixin implements FantasyWorldAccess {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean fantasy$shouldTick() {
|
public boolean fantasy$shouldTick() {
|
||||||
// For RuntimeWorld instances, use the configured behavior
|
|
||||||
if ((Object) this instanceof RuntimeWorld) {
|
if ((Object) this instanceof RuntimeWorld) {
|
||||||
return this.fantasy$tickWhenEmpty || !this.isWorldEmpty();
|
return this.fantasy$tickWhenEmpty || !this.travelerssuitcase$isWorldEmpty();
|
||||||
}
|
}
|
||||||
// For regular worlds, always tick (normal behavior)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private boolean isWorldEmpty() {
|
private boolean travelerssuitcase$isWorldEmpty() {
|
||||||
return this.players().isEmpty() && this.getChunkSource().getLoadedChunksCount() <= 0;
|
return this.players().isEmpty() && this.getChunkSource().getLoadedChunksCount() <= 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,144 +0,0 @@
|
|||||||
package io.lampnet.travelerssuitcase.util;
|
|
||||||
|
|
||||||
import com.google.common.collect.Iterators;
|
|
||||||
import com.mojang.serialization.Lifecycle;
|
|
||||||
import net.minecraft.core.Holder;
|
|
||||||
import net.minecraft.core.MappedRegistry;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class FilteredRegistry<T> extends MappedRegistry<T> {
|
|
||||||
private final Registry<T> source;
|
|
||||||
private final Predicate<T> check;
|
|
||||||
|
|
||||||
public FilteredRegistry(Registry<T> source, Predicate<T> check) {
|
|
||||||
super(source.key(), source.registryLifecycle(), false);
|
|
||||||
this.source = source;
|
|
||||||
this.check = check;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Registry<T> getSource() {
|
|
||||||
return this.source;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public ResourceLocation getKey(T value) {
|
|
||||||
return check.test(value) ? this.source.getKey(value) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<ResourceKey<T>> getResourceKey(T entry) {
|
|
||||||
return check.test(entry) ? this.source.getResourceKey(entry) : Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getId(@Nullable T value) {
|
|
||||||
return check.test(value) ? this.source.getId(value) : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T get(int index) {
|
|
||||||
return this.source.byId(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return (int) this.source.stream().filter(check).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public T get(@Nullable ResourceKey<T> key) {
|
|
||||||
T value = this.source.get(key);
|
|
||||||
return (value != null && check.test(value)) ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public T get(@Nullable ResourceLocation id) {
|
|
||||||
T value = this.source.get(id);
|
|
||||||
return (value != null && check.test(value)) ? value : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Lifecycle lifecycle(T entry) {
|
|
||||||
return this.source.lifecycle(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull Set<ResourceLocation> keySet() {
|
|
||||||
Set<ResourceLocation> keys = new HashSet<>();
|
|
||||||
this.source.keySet().forEach(key -> {
|
|
||||||
T value = this.source.get(key);
|
|
||||||
if(value != null && check.test(value)) {
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull Set<Map.Entry<ResourceKey<T>, T>> entrySet() {
|
|
||||||
Set<Map.Entry<ResourceKey<T>, T>> set = new HashSet<>();
|
|
||||||
for (Map.Entry<ResourceKey<T>, T> e : this.source.entrySet()) {
|
|
||||||
if (this.check.test(e.getValue())) {
|
|
||||||
set.add(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(ResourceLocation id) {
|
|
||||||
T value = this.source.get(id);
|
|
||||||
return value != null && check.test(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean containsKey(ResourceKey<T> key) {
|
|
||||||
T value = this.source.get(key);
|
|
||||||
return value != null && check.test(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull Iterator<T> iterator() {
|
|
||||||
return Iterators.filter(this.source.iterator(), e -> this.check.test(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Methods below are for WritableRegistry, we don't support writing to a filtered registry
|
|
||||||
@Override
|
|
||||||
public Holder.Reference<T> register(ResourceKey<T> resourceKey, T object, Lifecycle lifecycle) {
|
|
||||||
throw new UnsupportedOperationException("Cannot register to a filtered registry");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Holder.Reference<T> registerOrNah(ResourceKey<T> resourceKey, T object, Lifecycle lifecycle) {
|
|
||||||
throw new UnsupportedOperationException("Cannot register to a filtered registry");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Holder.Reference<T> registerMapping(int i, ResourceKey<T> resourceKey, T object, Lifecycle lifecycle) {
|
|
||||||
throw new UnsupportedOperationException("Cannot register to a filtered registry");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Holder.Reference<T> getHolderOrThrow(ResourceKey<T> resourceKey) {
|
|
||||||
return this.source.getHolderOrThrow(resourceKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Holder.Reference<T>> getHolder(ResourceKey<T> resourceKey) {
|
|
||||||
return this.source.getHolder(resourceKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<Holder.Reference<T>> holders() {
|
|
||||||
return this.source.holders().filter(h -> check.test(h.value()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -19,10 +19,6 @@ public final class GameRuleStore {
|
|||||||
this.intRules.put(key, value);
|
this.intRules.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean contains(GameRules.Key<?> key) {
|
|
||||||
return this.booleanRules.containsKey(key) || this.intRules.containsKey(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyTo(GameRules rules, @Nullable MinecraftServer server) {
|
public void applyTo(GameRules rules, @Nullable MinecraftServer server) {
|
||||||
for (Map.Entry<GameRules.Key<GameRules.BooleanValue>, Boolean> entry : this.booleanRules.entrySet()) {
|
for (Map.Entry<GameRules.Key<GameRules.BooleanValue>, Boolean> entry : this.booleanRules.entrySet()) {
|
||||||
GameRules.BooleanValue rule = rules.getRule(entry.getKey());
|
GameRules.BooleanValue rule = rules.getRule(entry.getKey());
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
package io.lampnet.travelerssuitcase.util;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
public final class SafeIterator<T> implements Iterator<T> {
|
|
||||||
private final Object[] values;
|
|
||||||
private int index = 0;
|
|
||||||
|
|
||||||
public SafeIterator(Collection<T> source) {
|
|
||||||
this.values = source.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasNext() {
|
|
||||||
return this.values.length > this.index;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T next() {
|
|
||||||
return (T) this.values[this.index++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,90 +0,0 @@
|
|||||||
package io.lampnet.travelerssuitcase.util;
|
|
||||||
|
|
||||||
import com.mojang.serialization.Codec;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
import net.minecraft.server.level.WorldGenRegion;
|
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
|
||||||
import net.minecraft.world.level.NoiseColumn;
|
|
||||||
import net.minecraft.world.level.StructureManager;
|
|
||||||
import net.minecraft.world.level.biome.Biome;
|
|
||||||
import net.minecraft.world.level.biome.BiomeManager;
|
|
||||||
import net.minecraft.world.level.biome.Biomes;
|
|
||||||
import net.minecraft.world.level.biome.FixedBiomeSource;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
|
||||||
import net.minecraft.world.level.levelgen.GenerationStep;
|
|
||||||
import net.minecraft.world.level.levelgen.Heightmap;
|
|
||||||
import net.minecraft.world.level.levelgen.RandomState;
|
|
||||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
public class VoidChunkGenerator extends ChunkGenerator {
|
|
||||||
public static final Codec<VoidChunkGenerator> CODEC = Codec.unit(VoidChunkGenerator::new);
|
|
||||||
|
|
||||||
public VoidChunkGenerator(Registry<Biome> biomeRegistry) {
|
|
||||||
super(new FixedBiomeSource(biomeRegistry.getHolderOrThrow(Biomes.THE_VOID)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public VoidChunkGenerator() {
|
|
||||||
super(new FixedBiomeSource(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull Codec<? extends ChunkGenerator> codec() {
|
|
||||||
return CODEC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void applyCarvers(WorldGenRegion worldGenRegion, long seed, RandomState randomState, BiomeManager biomeManager, StructureManager structureManager, ChunkAccess chunkAccess, GenerationStep.Carving carving) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawnOriginalMobs(WorldGenRegion worldGenRegion) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getGenDepth() {
|
|
||||||
return 384;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(Executor executor, Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunkAccess) {
|
|
||||||
return CompletableFuture.completedFuture(chunkAccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSeaLevel() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMinY() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getBaseHeight(int i, int j, Heightmap.Types types, LevelHeightAccessor levelHeightAccessor, RandomState randomState) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelHeightAccessor, RandomState randomState) {
|
|
||||||
return new NoiseColumn(0, new BlockState[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addDebugScreenInfo(List<String> list, RandomState randomState, BlockPos blockPos) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void buildSurface(WorldGenRegion worldGenRegion, StructureManager structureManager, RandomState randomState,
|
|
||||||
ChunkAccess chunkAccess) {
|
|
||||||
// No surface to build for void chunks
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -43,7 +43,6 @@ public final class Fantasy {
|
|||||||
private final Set<ServerLevel> unloadingQueue = new ReferenceOpenHashSet<>();
|
private final Set<ServerLevel> unloadingQueue = new ReferenceOpenHashSet<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// We need to register the event listener on the bus.
|
|
||||||
MinecraftForge.EVENT_BUS.register(Fantasy.class);
|
MinecraftForge.EVENT_BUS.register(Fantasy.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,15 +1,25 @@
|
|||||||
package io.lampnet.travelerssuitcase.world;
|
package io.lampnet.travelerssuitcase.world;
|
||||||
|
|
||||||
import io.lampnet.travelerssuitcase.util.VoidChunkGenerator;
|
import com.mojang.serialization.Codec;
|
||||||
import net.minecraft.core.Registry;
|
import io.lampnet.travelerssuitcase.TravelersSuitcase;
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.Registries;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
import static io.lampnet.travelerssuitcase.TravelersSuitcase.MODID;
|
import net.minecraftforge.registries.DeferredRegister;
|
||||||
|
import net.minecraftforge.registries.RegistryObject;
|
||||||
|
|
||||||
public final class FantasyInitializer {
|
public final class FantasyInitializer {
|
||||||
|
public static final DeferredRegister<Codec<? extends ChunkGenerator>> CHUNK_GENERATORS =
|
||||||
|
DeferredRegister.create(Registries.CHUNK_GENERATOR, TravelersSuitcase.MODID);
|
||||||
|
|
||||||
|
public static final RegistryObject<Codec<PortalChunkGenerator>> PORTAL_GENERATOR =
|
||||||
|
CHUNK_GENERATORS.register("portal", () -> PortalChunkGenerator.CODEC);
|
||||||
|
|
||||||
|
public static void register(IEventBus eventBus) {
|
||||||
|
CHUNK_GENERATORS.register(eventBus);
|
||||||
|
}
|
||||||
|
|
||||||
public void onInitialize() {
|
public void onInitialize() {
|
||||||
Registry.register(BuiltInRegistries.CHUNK_GENERATOR, ResourceLocation.fromNamespaceAndPath(MODID, "void"), VoidChunkGenerator.CODEC);
|
// Registration now handled by DeferredRegister
|
||||||
Registry.register(BuiltInRegistries.CHUNK_GENERATOR, ResourceLocation.fromNamespaceAndPath(MODID, "portal"), PortalChunkGenerator.CODEC);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -24,6 +24,7 @@ import net.minecraft.core.registries.Registries;
|
|||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@ -92,9 +93,7 @@ public class PortalChunkGenerator extends ChunkGenerator {
|
|||||||
@Override
|
@Override
|
||||||
public NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor level, RandomState randomState) {
|
public NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor level, RandomState randomState) {
|
||||||
BlockState[] column = new BlockState[level.getHeight()];
|
BlockState[] column = new BlockState[level.getHeight()];
|
||||||
for (int i = 0; i < column.length; i++) {
|
Arrays.fill(column, Blocks.AIR.defaultBlockState());
|
||||||
column[i] = Blocks.AIR.defaultBlockState();
|
|
||||||
}
|
|
||||||
return new NoiseColumn(level.getMinBuildHeight(), column);
|
return new NoiseColumn(level.getMinBuildHeight(), column);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class RuntimeWorld extends ServerLevel {
|
|||||||
server,
|
server,
|
||||||
Util.backgroundExecutor(),
|
Util.backgroundExecutor(),
|
||||||
((MinecraftServerAccess) server).getSession(),
|
((MinecraftServerAccess) server).getSession(),
|
||||||
new RuntimeWorldProperties(server.getWorldData().overworldData(), config),
|
new RuntimeWorldProperties(server.getWorldData().overworldData(), config, server),
|
||||||
registryKey,
|
registryKey,
|
||||||
new LevelStem(
|
new LevelStem(
|
||||||
server.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.DIMENSION_TYPE)
|
server.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.DIMENSION_TYPE)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package io.lampnet.travelerssuitcase.world;
|
package io.lampnet.travelerssuitcase.world;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import io.lampnet.travelerssuitcase.Config;
|
||||||
import io.lampnet.travelerssuitcase.util.GameRuleStore;
|
import io.lampnet.travelerssuitcase.util.GameRuleStore;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.registries.Registries;
|
||||||
@ -17,20 +18,19 @@ public final class RuntimeWorldConfig {
|
|||||||
private ResourceKey<LevelStem> dimensionTypeKey = Fantasy.DEFAULT_DIM_TYPE;
|
private ResourceKey<LevelStem> dimensionTypeKey = Fantasy.DEFAULT_DIM_TYPE;
|
||||||
private Holder<LevelStem> dimensionType;
|
private Holder<LevelStem> dimensionType;
|
||||||
private ChunkGenerator generator = null;
|
private ChunkGenerator generator = null;
|
||||||
private boolean shouldTickTime = false;
|
private boolean shouldTickTime = Config.shouldTickTime();
|
||||||
private long timeOfDay = 6000;
|
private long timeOfDay = Config.getDefaultTimeOfDay();
|
||||||
private Difficulty difficulty = Difficulty.NORMAL;
|
private Difficulty difficulty = null; // Will use server difficulty
|
||||||
private final GameRuleStore gameRules = new GameRuleStore();
|
private final GameRuleStore gameRules = new GameRuleStore();
|
||||||
private RuntimeWorld.Constructor worldConstructor = RuntimeWorld::new;
|
private RuntimeWorld.Constructor worldConstructor = RuntimeWorld::new;
|
||||||
|
|
||||||
private int sunnyTime = Integer.MAX_VALUE;
|
private int sunnyTime = Config.getDefaultSunnyTime();
|
||||||
private boolean raining;
|
private boolean raining = Config.isDefaultRaining();
|
||||||
private int rainTime;
|
private int rainTime = Config.getDefaultRainTime();
|
||||||
private boolean thundering;
|
private boolean thundering = Config.isDefaultThundering();
|
||||||
private int thunderTime;
|
private int thunderTime = Config.getDefaultThunderTime();
|
||||||
private TriState flat = TriState.DEFAULT;
|
private TriState flat = TriState.DEFAULT;
|
||||||
|
|
||||||
// Simple TriState implementation
|
|
||||||
public enum TriState {
|
public enum TriState {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
TRUE,
|
TRUE,
|
||||||
@ -165,8 +165,8 @@ public final class RuntimeWorldConfig {
|
|||||||
return this.timeOfDay;
|
return this.timeOfDay;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Difficulty getDifficulty() {
|
public Difficulty getDifficulty(MinecraftServer server) {
|
||||||
return this.difficulty;
|
return this.difficulty != null ? this.difficulty : server.getWorldData().getDifficulty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameRuleStore getGameRules() {
|
public GameRuleStore getGameRules() {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package io.lampnet.travelerssuitcase.world;
|
package io.lampnet.travelerssuitcase.world;
|
||||||
|
|
||||||
import net.minecraft.CrashReportCategory;
|
import net.minecraft.CrashReportCategory;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.world.Difficulty;
|
import net.minecraft.world.Difficulty;
|
||||||
import net.minecraft.world.level.GameRules;
|
import net.minecraft.world.level.GameRules;
|
||||||
@ -16,10 +16,12 @@ import java.util.UUID;
|
|||||||
public class RuntimeWorldProperties implements ServerLevelData {
|
public class RuntimeWorldProperties implements ServerLevelData {
|
||||||
private final ServerLevelData parent;
|
private final ServerLevelData parent;
|
||||||
final RuntimeWorldConfig config;
|
final RuntimeWorldConfig config;
|
||||||
|
private final MinecraftServer server;
|
||||||
|
|
||||||
public RuntimeWorldProperties(ServerLevelData parent, RuntimeWorldConfig config) {
|
public RuntimeWorldProperties(ServerLevelData parent, RuntimeWorldConfig config, MinecraftServer server) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -150,7 +152,7 @@ public class RuntimeWorldProperties implements ServerLevelData {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Difficulty getDifficulty() {
|
public @NotNull Difficulty getDifficulty() {
|
||||||
return this.config.getDifficulty();
|
return this.config.getDifficulty(this.server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user