cleaning
This commit is contained in:
parent
57f0f340a9
commit
120ab466aa
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ run/
|
||||
run-data/
|
||||
.idea/
|
||||
.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.
|
||||
mod_license=MIT
|
||||
# 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.
|
||||
# This should match the base package used for the mod sources.
|
||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
package io.lampnet.travelerssuitcase;
|
||||
|
||||
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.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
@ -10,20 +11,210 @@ import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = TravelersSuitcase.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class Config {
|
||||
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) {
|
||||
return obj instanceof final String itemName && ForgeRegistries.ITEMS.containsKey(ResourceLocation.parse(itemName));
|
||||
public static final ForgeConfigSpec.LongValue DEFAULT_TIME_OF_DAY;
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
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.event.lifecycle.FMLCommonSetupEvent;
|
||||
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.Logger;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashSet;
|
||||
|
||||
import java.util.Set;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
|
||||
import io.lampnet.travelerssuitcase.world.RuntimeWorldHandle;
|
||||
|
||||
@ -67,36 +69,16 @@ public class TravelersSuitcase {
|
||||
public static final Logger LOGGER = LogManager.getLogger(MODID);
|
||||
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() {
|
||||
return canCaptureHostile;
|
||||
}
|
||||
|
||||
public static void setCanCaptureHostile(boolean value) {
|
||||
canCaptureHostile = value;
|
||||
return Config.canCaptureHostile();
|
||||
}
|
||||
|
||||
public static Set<EntityType<?>> getEntityBlacklist() {
|
||||
return new HashSet<>(entityBlacklist);
|
||||
}
|
||||
|
||||
public static void addToBlacklist(EntityType<?> entityType) {
|
||||
entityBlacklist.add(entityType);
|
||||
}
|
||||
|
||||
public static boolean removeFromBlacklist(EntityType<?> entityType) {
|
||||
return entityBlacklist.remove(entityType);
|
||||
return Config.getEntityBlacklist();
|
||||
}
|
||||
|
||||
public static boolean isBlacklisted(EntityType<?> entityType) {
|
||||
return entityBlacklist.contains(entityType);
|
||||
}
|
||||
|
||||
public static void clearBlacklist() {
|
||||
entityBlacklist.clear();
|
||||
return Config.isEntityBlacklisted(entityType);
|
||||
}
|
||||
|
||||
public TravelersSuitcase() {
|
||||
@ -106,29 +88,24 @@ public class TravelersSuitcase {
|
||||
ModBlocks.register(modEventBus);
|
||||
ModItemGroups.register(modEventBus);
|
||||
ModBlockEntities.register(modEventBus);
|
||||
FantasyInitializer.register(modEventBus);
|
||||
|
||||
// Register configuration
|
||||
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, Config.SPEC);
|
||||
|
||||
modEventBus.addListener(this::commonSetup);
|
||||
|
||||
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) {
|
||||
// Register chunk generators during setup phase
|
||||
new FantasyInitializer().onInitialize();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerStarting(ServerStartingEvent event) {
|
||||
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)
|
||||
.resolve("data")
|
||||
@ -153,8 +130,7 @@ public class TravelersSuitcase {
|
||||
.setSeed(seed);
|
||||
RuntimeWorldHandle handle = Fantasy.get(event.getServer()).getOrOpenPersistentWorld(worldId, cfg);
|
||||
|
||||
// Ensure the pocket dimension ticks even when empty to prevent entity tick issues
|
||||
handle.setTickWhenEmpty(true);
|
||||
handle.setTickWhenEmpty(Config.tickWhenEmpty());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
TravelersSuitcase.LOGGER.error("Failed to reload pocket dimensions", e);
|
||||
@ -266,7 +242,6 @@ public class TravelersSuitcase {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset player entry to default position
|
||||
PlayerEntryData playerData = PlayerEntryData.get(targetWorld);
|
||||
playerData.resetToDefault();
|
||||
|
||||
@ -292,7 +267,6 @@ public class TravelersSuitcase {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Reset mob entry to default position
|
||||
MobEntryData mobData = MobEntryData.get(targetWorld);
|
||||
mobData.setEntry(new Vec3(35.5, 85.0, 16.5), 0f, 0f);
|
||||
|
||||
@ -329,19 +303,11 @@ public class TravelersSuitcase {
|
||||
)
|
||||
.then(Commands.literal("canCaptureHostile")
|
||||
.requires(src -> src.hasPermission(2))
|
||||
.then(Commands.argument("value", BoolArgumentType.bool())
|
||||
.executes(ctx -> {
|
||||
boolean value = BoolArgumentType.getBool(ctx, "value");
|
||||
canCaptureHostile = value;
|
||||
ctx.getSource().sendSuccess(() -> Component.literal(
|
||||
value ? "§aHostile mob capture enabled" : "§cHostile mob capture disabled"
|
||||
), false);
|
||||
return 1;
|
||||
})
|
||||
)
|
||||
.executes(ctx -> {
|
||||
.executes(ctx -> {
|
||||
boolean enabled = Config.canCaptureHostile();
|
||||
ctx.getSource().sendSuccess(() -> Component.literal(
|
||||
"§7Hostile mob capture is currently: " + (canCaptureHostile ? "§aEnabled" : "§cDisabled")
|
||||
"§7Hostile mob capture is currently: " + (enabled ? "§aEnabled" : "§cDisabled") +
|
||||
"\n§7(Configure in config file)"
|
||||
), false);
|
||||
return 1;
|
||||
})
|
||||
@ -356,7 +322,7 @@ public class TravelersSuitcase {
|
||||
try {
|
||||
ResourceLocation entityId = ResourceLocation.parse(entityString);
|
||||
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));
|
||||
return 0;
|
||||
}
|
||||
@ -364,7 +330,6 @@ public class TravelersSuitcase {
|
||||
src.sendFailure(Component.literal("§cCannot blacklist players"));
|
||||
return 0;
|
||||
}
|
||||
entityBlacklist.add(entityType);
|
||||
src.sendSuccess(() -> Component.literal("§aAdded " + entityId + " to blacklist"), false);
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
@ -386,11 +351,7 @@ public class TravelersSuitcase {
|
||||
src.sendFailure(Component.literal("§cUnknown entity type: " + entityString));
|
||||
return 0;
|
||||
}
|
||||
if (entityBlacklist.remove(entityType)) {
|
||||
src.sendSuccess(() -> Component.literal("§aRemoved " + entityId + " from blacklist"), false);
|
||||
} else {
|
||||
src.sendSuccess(() -> Component.literal("§7" + entityId + " was not in blacklist"), false);
|
||||
}
|
||||
src.sendSuccess(() -> Component.literal("§eEntity blacklist is managed through configuration files"), false);
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
src.sendFailure(Component.literal("§cInvalid entity identifier: " + entityString));
|
||||
@ -402,11 +363,12 @@ public class TravelersSuitcase {
|
||||
.then(Commands.literal("list")
|
||||
.executes(ctx -> {
|
||||
var src = ctx.getSource();
|
||||
if (entityBlacklist.isEmpty()) {
|
||||
Set<EntityType<?>> blacklist = Config.getEntityBlacklist();
|
||||
if (blacklist.isEmpty()) {
|
||||
src.sendSuccess(() -> Component.literal("§7No entities are blacklisted"), false);
|
||||
} else {
|
||||
src.sendSuccess(() -> Component.literal("§aBlacklisted entities:"), false);
|
||||
entityBlacklist.forEach(entityType -> {
|
||||
blacklist.forEach(entityType -> {
|
||||
var id = BuiltInRegistries.ENTITY_TYPE.getKey(entityType);
|
||||
src.sendSuccess(() -> Component.literal(" " + id), false);
|
||||
});
|
||||
@ -415,127 +377,17 @@ public class TravelersSuitcase {
|
||||
})
|
||||
)
|
||||
.then(Commands.literal("clear")
|
||||
.executes(ctx -> {
|
||||
.executes(ctx -> {
|
||||
var src = ctx.getSource();
|
||||
int count = entityBlacklist.size();
|
||||
entityBlacklist.clear();
|
||||
src.sendSuccess(() -> Component.literal("§aCleared blacklist (removed " + count + " entities)"), false);
|
||||
src.sendSuccess(() -> Component.literal("§eEntity blacklist is managed through configuration files"), false);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
public void onUseEntity(PlayerInteractEvent.EntityInteract event) {
|
||||
@ -576,7 +428,7 @@ public class TravelersSuitcase {
|
||||
if (!(entity instanceof LivingEntity mob)) {
|
||||
return;
|
||||
}
|
||||
if (entityBlacklist.contains(mob.getType())) {
|
||||
if (Config.isEntityBlacklisted(mob.getType())) {
|
||||
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);
|
||||
event.setCancellationResult(InteractionResult.FAIL);
|
||||
@ -584,7 +436,7 @@ public class TravelersSuitcase {
|
||||
return;
|
||||
}
|
||||
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);
|
||||
world.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.ZOMBIE_ATTACK_WOODEN_DOOR, SoundSource.PLAYERS, 0.3f, 1.5f);
|
||||
event.setCancellationResult(InteractionResult.FAIL);
|
||||
@ -607,8 +459,7 @@ public class TravelersSuitcase {
|
||||
event.setCanceled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Key rescue mob
|
||||
|
||||
if (stack.getItem() instanceof KeystoneItem) {
|
||||
ResourceLocation dimId = world.dimension().location();
|
||||
String namespace = dimId.getNamespace();
|
||||
|
||||
@ -312,7 +312,7 @@ public class SuitcaseBlock extends BaseEntityBlock {
|
||||
CompoundTag display = stack.getOrCreateTagElement("display");
|
||||
ListTag lore = new ListTag();
|
||||
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);
|
||||
lore.add(StringTag.valueOf(Component.Serializer.toJson(warningText)));
|
||||
}
|
||||
|
||||
@ -187,13 +187,11 @@ public class SuitcaseBlockEntity extends BlockEntity {
|
||||
@Override
|
||||
public @NotNull CompoundTag getUpdateTag() {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
// Only sync essential data to client, not player entry data which could cause position conflicts
|
||||
if (boundKeystoneName != null) {
|
||||
nbt.putString("BoundKeystone", boundKeystoneName);
|
||||
}
|
||||
nbt.putBoolean("Locked", isLocked);
|
||||
nbt.putBoolean("DimensionLocked", dimensionLocked);
|
||||
// Deliberately exclude EnteredPlayers from client sync to prevent coordinate conflicts
|
||||
return nbt;
|
||||
}
|
||||
|
||||
|
||||
@ -7,8 +7,8 @@ import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class MobEntryData extends SavedData {
|
||||
private static final String DATA_KEY = "pocket_entry_data";
|
||||
private Vec3 entryPos = Vec3.ZERO;
|
||||
private float entryYaw = 0f, entryPitch = 0f;
|
||||
private Vec3 entryPos;
|
||||
private float entryYaw, entryPitch;
|
||||
|
||||
public MobEntryData() {
|
||||
super();
|
||||
|
||||
@ -8,8 +8,8 @@ import net.minecraft.world.phys.Vec3;
|
||||
public class PlayerEntryData extends SavedData {
|
||||
private static final String DATA_KEY = "pocket_player_entry";
|
||||
|
||||
private Vec3 entryPos = Vec3.ZERO;
|
||||
private float entryYaw = 0f, entryPitch = 0f;
|
||||
private Vec3 entryPos;
|
||||
private float entryYaw, entryPitch;
|
||||
private boolean isManuallySet = false;
|
||||
|
||||
public PlayerEntryData() {
|
||||
|
||||
@ -56,22 +56,14 @@ public class KeystoneItem extends Item {
|
||||
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level world, Player player, @NotNull InteractionHand hand) {
|
||||
ItemStack stack = player.getItemInHand(hand);
|
||||
|
||||
// If already enchanted, do nothing
|
||||
if (stack.isEnchanted()) {
|
||||
return InteractionResultHolder.pass(stack);
|
||||
}
|
||||
|
||||
// If no valid custom name, do nothing
|
||||
if (!isValidKeystone(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);
|
||||
}
|
||||
|
||||
@ -84,18 +76,15 @@ public class KeystoneItem extends Item {
|
||||
.resolve(dimensionName);
|
||||
boolean dimensionExists = Files.exists(worldSavePath);
|
||||
|
||||
// Get biome registry - if this fails, the server isn't ready yet
|
||||
var biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
|
||||
|
||||
RuntimeWorldConfig config = new RuntimeWorldConfig()
|
||||
.setGenerator(new PortalChunkGenerator(biomeRegistry))
|
||||
.setSeed(server.overworld().getSeed())
|
||||
.setShouldTickTime(true);
|
||||
.setSeed(server.overworld().getSeed());
|
||||
|
||||
RuntimeWorldHandle handle = Fantasy.get(server)
|
||||
.getOrOpenPersistentWorld(worldId, config);
|
||||
|
||||
// Ensure the pocket dimension ticks even when empty to prevent entity tick issues
|
||||
handle.setTickWhenEmpty(true);
|
||||
|
||||
TravelersSuitcase.LOGGER.info("Created/loaded pocket dimension '{}', ticking enabled: {}",
|
||||
@ -105,7 +94,6 @@ public class KeystoneItem extends Item {
|
||||
|
||||
if (!dimensionExists) {
|
||||
ServerLevel world = handle.asWorld();
|
||||
// Schedule structure placement for next tick to ensure world is fully initialized
|
||||
server.execute(() -> placeStructureDelayed(server, world, dimensionName));
|
||||
}
|
||||
}
|
||||
@ -119,29 +107,10 @@ public class KeystoneItem extends Item {
|
||||
if (template != null) {
|
||||
BlockPos pos = new BlockPos(0, 64, 0);
|
||||
|
||||
// Ensure the chunk is fully loaded and ready
|
||||
ChunkPos chunkPos = new ChunkPos(pos);
|
||||
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);
|
||||
|
||||
// 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(
|
||||
world,
|
||||
pos,
|
||||
@ -151,10 +120,11 @@ public class KeystoneItem extends Item {
|
||||
.setRotation(Rotation.NONE)
|
||||
.setIgnoreEntities(false),
|
||||
world.getRandom(),
|
||||
Block.UPDATE_NEIGHBORS // Only update neighbors, don't replace existing blocks
|
||||
Block.UPDATE_ALL
|
||||
);
|
||||
|
||||
world.setChunkForced(pos.getX() >> 4, pos.getZ() >> 4, true);
|
||||
|
||||
// Force a save to ensure the forced chunk data is properly loaded for ticking
|
||||
world.save(null, true, false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -172,13 +142,11 @@ public class KeystoneItem extends Item {
|
||||
Files.createDirectories(registryDir);
|
||||
Path registryFile = registryDir.resolve("registry.txt");
|
||||
|
||||
// load existing lines
|
||||
Set<String> dims = new HashSet<>();
|
||||
if (Files.exists(registryFile)) {
|
||||
dims.addAll(Files.readAllLines(registryFile));
|
||||
}
|
||||
|
||||
// add + save only if new
|
||||
if (dims.add(dimensionName)) {
|
||||
Files.write(registryFile, dims);
|
||||
}
|
||||
@ -217,7 +185,6 @@ public class KeystoneItem extends Item {
|
||||
stack.getTag().remove("CustomModelData");
|
||||
}
|
||||
|
||||
// Auto-enchant and create dimension when item gets a valid custom name
|
||||
if (!world.isClientSide() && hasValidName && !stack.isEnchanted()) {
|
||||
String dimensionName = "pocket_dimension_" + keystoneName.replaceAll("[^a-z0-9_]", "");
|
||||
createOrLoadPersistentDimension(world.getServer(), dimensionName);
|
||||
@ -226,17 +193,19 @@ public class KeystoneItem extends Item {
|
||||
CompoundTag nbt = stack.getOrCreateTag();
|
||||
nbt.putInt("RepairCost", 32767);
|
||||
|
||||
// Play sound effect if entity is a player
|
||||
if (entity instanceof Player player) {
|
||||
world.playSound(null, player.getX(), player.getY(), player.getZ(),
|
||||
SoundEvents.AMETHYST_CLUSTER_FALL, SoundSource.PLAYERS, 2.0F, 2.0F);
|
||||
}
|
||||
}
|
||||
|
||||
if (!world.isClientSide() && stack.hasTag() && stack.getTag().contains("Enchantments")) {
|
||||
CompoundTag nbt = stack.getOrCreateTag();
|
||||
if (nbt.getInt("RepairCost") < 32767) {
|
||||
nbt.putInt("RepairCost", 32767);
|
||||
if (!world.isClientSide() && stack.hasTag()) {
|
||||
assert stack.getTag() != null;
|
||||
if (stack.getTag().contains("Enchantments")) {
|
||||
CompoundTag nbt = stack.getOrCreateTag();
|
||||
if (nbt.getInt("RepairCost") < 32767) {
|
||||
nbt.putInt("RepairCost", 32767);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,25 +17,21 @@ public abstract class MappedRegistryMixin<T> implements RemoveFromRegistry<T> {
|
||||
|
||||
@Override
|
||||
public boolean fantasy$remove(T value) {
|
||||
// Implementation depends on access to private fields
|
||||
// For now, return false as removal is complex
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fantasy$remove(ResourceLocation key) {
|
||||
// Implementation depends on access to private fields
|
||||
// For now, return false as removal is complex
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fantasy$setFrozen(boolean value) {
|
||||
// Store the original frozen state so we can restore it later
|
||||
if (!value && this.frozen) {
|
||||
this.fantasy$originalFrozenState = true;
|
||||
}
|
||||
// Actually modify the registry's frozen state
|
||||
this.frozen = value;
|
||||
}
|
||||
|
||||
|
||||
@ -15,21 +15,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
public class ServerChunkManagerMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private ServerLevel level;
|
||||
public ServerLevel level;
|
||||
|
||||
@Inject(method = "runDistanceManagerUpdates", at = @At("HEAD"), cancellable = true)
|
||||
private void onRunDistanceManagerUpdates(CallbackInfoReturnable<Boolean> cir) {
|
||||
// Only apply special chunk processing logic to RuntimeWorld instances (fantasy dimensions)
|
||||
if (this.level instanceof RuntimeWorld) {
|
||||
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()) {
|
||||
// Allow distance manager to run - this is critical for entity systems
|
||||
return;
|
||||
}
|
||||
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)
|
||||
public abstract class ServerWorldMixin implements FantasyWorldAccess {
|
||||
@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)
|
||||
private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) {
|
||||
// Only apply special tick logic to RuntimeWorld instances (fantasy dimensions)
|
||||
if ((Object) this instanceof RuntimeWorld) {
|
||||
if (!this.fantasy$shouldTick()) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
// Regular worlds (overworld, nether, end) tick normally without interference
|
||||
}
|
||||
|
||||
@Shadow
|
||||
@ -43,16 +41,14 @@ public abstract class ServerWorldMixin implements FantasyWorldAccess {
|
||||
|
||||
@Override
|
||||
public boolean fantasy$shouldTick() {
|
||||
// For RuntimeWorld instances, use the configured behavior
|
||||
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;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean isWorldEmpty() {
|
||||
private boolean travelerssuitcase$isWorldEmpty() {
|
||||
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);
|
||||
}
|
||||
|
||||
public boolean contains(GameRules.Key<?> key) {
|
||||
return this.booleanRules.containsKey(key) || this.intRules.containsKey(key);
|
||||
}
|
||||
|
||||
public void applyTo(GameRules rules, @Nullable MinecraftServer server) {
|
||||
for (Map.Entry<GameRules.Key<GameRules.BooleanValue>, Boolean> entry : this.booleanRules.entrySet()) {
|
||||
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<>();
|
||||
|
||||
static {
|
||||
// We need to register the event listener on the bus.
|
||||
MinecraftForge.EVENT_BUS.register(Fantasy.class);
|
||||
}
|
||||
|
||||
|
||||
@ -1,15 +1,25 @@
|
||||
package io.lampnet.travelerssuitcase.world;
|
||||
|
||||
import io.lampnet.travelerssuitcase.util.VoidChunkGenerator;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import static io.lampnet.travelerssuitcase.TravelersSuitcase.MODID;
|
||||
import com.mojang.serialization.Codec;
|
||||
import io.lampnet.travelerssuitcase.TravelersSuitcase;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.registries.DeferredRegister;
|
||||
import net.minecraftforge.registries.RegistryObject;
|
||||
|
||||
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() {
|
||||
Registry.register(BuiltInRegistries.CHUNK_GENERATOR, ResourceLocation.fromNamespaceAndPath(MODID, "void"), VoidChunkGenerator.CODEC);
|
||||
Registry.register(BuiltInRegistries.CHUNK_GENERATOR, ResourceLocation.fromNamespaceAndPath(MODID, "portal"), PortalChunkGenerator.CODEC);
|
||||
// Registration now handled by DeferredRegister
|
||||
}
|
||||
}
|
||||
@ -24,6 +24,7 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@ -92,9 +93,7 @@ public class PortalChunkGenerator extends ChunkGenerator {
|
||||
@Override
|
||||
public NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor level, RandomState randomState) {
|
||||
BlockState[] column = new BlockState[level.getHeight()];
|
||||
for (int i = 0; i < column.length; i++) {
|
||||
column[i] = Blocks.AIR.defaultBlockState();
|
||||
}
|
||||
Arrays.fill(column, Blocks.AIR.defaultBlockState());
|
||||
return new NoiseColumn(level.getMinBuildHeight(), column);
|
||||
}
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ public class RuntimeWorld extends ServerLevel {
|
||||
server,
|
||||
Util.backgroundExecutor(),
|
||||
((MinecraftServerAccess) server).getSession(),
|
||||
new RuntimeWorldProperties(server.getWorldData().overworldData(), config),
|
||||
new RuntimeWorldProperties(server.getWorldData().overworldData(), config, server),
|
||||
registryKey,
|
||||
new LevelStem(
|
||||
server.registryAccess().registryOrThrow(net.minecraft.core.registries.Registries.DIMENSION_TYPE)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package io.lampnet.travelerssuitcase.world;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.lampnet.travelerssuitcase.Config;
|
||||
import io.lampnet.travelerssuitcase.util.GameRuleStore;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
@ -17,20 +18,19 @@ public final class RuntimeWorldConfig {
|
||||
private ResourceKey<LevelStem> dimensionTypeKey = Fantasy.DEFAULT_DIM_TYPE;
|
||||
private Holder<LevelStem> dimensionType;
|
||||
private ChunkGenerator generator = null;
|
||||
private boolean shouldTickTime = false;
|
||||
private long timeOfDay = 6000;
|
||||
private Difficulty difficulty = Difficulty.NORMAL;
|
||||
private boolean shouldTickTime = Config.shouldTickTime();
|
||||
private long timeOfDay = Config.getDefaultTimeOfDay();
|
||||
private Difficulty difficulty = null; // Will use server difficulty
|
||||
private final GameRuleStore gameRules = new GameRuleStore();
|
||||
private RuntimeWorld.Constructor worldConstructor = RuntimeWorld::new;
|
||||
|
||||
private int sunnyTime = Integer.MAX_VALUE;
|
||||
private boolean raining;
|
||||
private int rainTime;
|
||||
private boolean thundering;
|
||||
private int thunderTime;
|
||||
private int sunnyTime = Config.getDefaultSunnyTime();
|
||||
private boolean raining = Config.isDefaultRaining();
|
||||
private int rainTime = Config.getDefaultRainTime();
|
||||
private boolean thundering = Config.isDefaultThundering();
|
||||
private int thunderTime = Config.getDefaultThunderTime();
|
||||
private TriState flat = TriState.DEFAULT;
|
||||
|
||||
// Simple TriState implementation
|
||||
public enum TriState {
|
||||
DEFAULT,
|
||||
TRUE,
|
||||
@ -165,8 +165,8 @@ public final class RuntimeWorldConfig {
|
||||
return this.timeOfDay;
|
||||
}
|
||||
|
||||
public Difficulty getDifficulty() {
|
||||
return this.difficulty;
|
||||
public Difficulty getDifficulty(MinecraftServer server) {
|
||||
return this.difficulty != null ? this.difficulty : server.getWorldData().getDifficulty();
|
||||
}
|
||||
|
||||
public GameRuleStore getGameRules() {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package io.lampnet.travelerssuitcase.world;
|
||||
|
||||
import net.minecraft.CrashReportCategory;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.Difficulty;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
@ -16,10 +16,12 @@ import java.util.UUID;
|
||||
public class RuntimeWorldProperties implements ServerLevelData {
|
||||
private final ServerLevelData parent;
|
||||
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.config = config;
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,7 +152,7 @@ public class RuntimeWorldProperties implements ServerLevelData {
|
||||
|
||||
@Override
|
||||
public @NotNull Difficulty getDifficulty() {
|
||||
return this.config.getDifficulty();
|
||||
return this.config.getDifficulty(this.server);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user