Compare commits
No commits in common. "57f0f340a912665be5152da549ea0f61d32227c2" and "54c9024615910eb54a5b000ac147b70f9045a719" have entirely different histories.
57f0f340a9
...
54c9024615
@ -57,7 +57,6 @@ 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;
|
||||||
|
|
||||||
@ -122,14 +121,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)
|
||||||
@ -205,52 +196,6 @@ public class TravelersSuitcase {
|
|||||||
), false);
|
), false);
|
||||||
return 1;
|
return 1;
|
||||||
}))
|
}))
|
||||||
.then(Commands.literal("getPlayerEntry")
|
|
||||||
.executes(ctx -> {
|
|
||||||
var src = ctx.getSource();
|
|
||||||
var world = src.getLevel();
|
|
||||||
var id = world.dimension().location();
|
|
||||||
if (!id.getNamespace().equals(MODID)
|
|
||||||
|| !id.getPath().startsWith("pocket_dimension_")) {
|
|
||||||
src.sendFailure(Component.literal("§cNot in a pocket dimension"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerEntryData data = PlayerEntryData.get(world);
|
|
||||||
Vec3 pos = data.getEntryPos();
|
|
||||||
float yaw = data.getEntryYaw();
|
|
||||||
float pitch = data.getEntryPitch();
|
|
||||||
|
|
||||||
src.sendSuccess(() -> Component.literal(
|
|
||||||
String.format("§aPlayer entry: %.2f, %.2f, %.2f (yaw: %.1f, pitch: %.1f)",
|
|
||||||
pos.x(), pos.y(), pos.z(), yaw, pitch)
|
|
||||||
), false);
|
|
||||||
return 1;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(Commands.literal("getMobEntry")
|
|
||||||
.executes(ctx -> {
|
|
||||||
var src = ctx.getSource();
|
|
||||||
var world = src.getLevel();
|
|
||||||
var id = world.dimension().location();
|
|
||||||
if (!id.getNamespace().equals(MODID)
|
|
||||||
|| !id.getPath().startsWith("pocket_dimension_")) {
|
|
||||||
src.sendFailure(Component.literal("§cNot in a pocket dimension"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MobEntryData data = MobEntryData.get(world);
|
|
||||||
Vec3 pos = data.getEntryPos();
|
|
||||||
float yaw = data.getEntryYaw();
|
|
||||||
float pitch = data.getEntryPitch();
|
|
||||||
|
|
||||||
src.sendSuccess(() -> Component.literal(
|
|
||||||
String.format("§aMob entry: %.2f, %.2f, %.2f (yaw: %.1f, pitch: %.1f)",
|
|
||||||
pos.x(), pos.y(), pos.z(), yaw, pitch)
|
|
||||||
), false);
|
|
||||||
return 1;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(Commands.literal("resetPlayerEntry")
|
.then(Commands.literal("resetPlayerEntry")
|
||||||
.then(Commands.argument("dimension", StringArgumentType.word())
|
.then(Commands.argument("dimension", StringArgumentType.word())
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
@ -268,7 +213,7 @@ public class TravelersSuitcase {
|
|||||||
|
|
||||||
// Reset player entry to default position
|
// Reset player entry to default position
|
||||||
PlayerEntryData playerData = PlayerEntryData.get(targetWorld);
|
PlayerEntryData playerData = PlayerEntryData.get(targetWorld);
|
||||||
playerData.resetToDefault();
|
playerData.setEntry(new Vec3(17.5, 97.0, 9.5), 0f, 0f);
|
||||||
|
|
||||||
src.sendSuccess(() -> Component.literal(
|
src.sendSuccess(() -> Component.literal(
|
||||||
"§aPlayer entry reset for pocket dimension '" + dimSuffix + "'"
|
"§aPlayer entry reset for pocket dimension '" + dimSuffix + "'"
|
||||||
@ -277,32 +222,6 @@ public class TravelersSuitcase {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.then(Commands.literal("resetMobEntry")
|
|
||||||
.then(Commands.argument("dimension", StringArgumentType.word())
|
|
||||||
.executes(ctx -> {
|
|
||||||
var src = ctx.getSource();
|
|
||||||
String dimSuffix = StringArgumentType.getString(ctx, "dimension");
|
|
||||||
|
|
||||||
ResourceLocation dimId = ResourceLocation.fromNamespaceAndPath(MODID, "pocket_dimension_" + dimSuffix);
|
|
||||||
ResourceKey<Level> worldKey = ResourceKey.create(Registries.DIMENSION, dimId);
|
|
||||||
ServerLevel targetWorld = src.getServer().getLevel(worldKey);
|
|
||||||
|
|
||||||
if (targetWorld == null) {
|
|
||||||
src.sendFailure(Component.literal("§cPocket dimension '" + dimSuffix + "' not found"));
|
|
||||||
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);
|
|
||||||
|
|
||||||
src.sendSuccess(() -> Component.literal(
|
|
||||||
"§aMob entry reset for pocket dimension '" + dimSuffix + "'"
|
|
||||||
), false);
|
|
||||||
return 1;
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(Commands.literal("listDimensions")
|
.then(Commands.literal("listDimensions")
|
||||||
.requires(src -> src.hasPermission(2))
|
.requires(src -> src.hasPermission(2))
|
||||||
.executes(ctx -> {
|
.executes(ctx -> {
|
||||||
@ -423,120 +342,10 @@ public class TravelersSuitcase {
|
|||||||
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) {
|
||||||
Level world = event.getLevel();
|
Level world = event.getLevel();
|
||||||
@ -593,6 +402,8 @@ public class TravelersSuitcase {
|
|||||||
}
|
}
|
||||||
MobEntryData data = MobEntryData.get(targetWorld);
|
MobEntryData data = MobEntryData.get(targetWorld);
|
||||||
Vec3 dest = data.getEntryPos();
|
Vec3 dest = data.getEntryPos();
|
||||||
|
float yaw = data.getEntryYaw();
|
||||||
|
float pitch = data.getEntryPitch();
|
||||||
mob.changeDimension(targetWorld, new net.minecraftforge.common.util.ITeleporter() {
|
mob.changeDimension(targetWorld, new net.minecraftforge.common.util.ITeleporter() {
|
||||||
@Override
|
@Override
|
||||||
public Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float yaw, java.util.function.Function<Boolean, Entity> repositionEntity) {
|
public Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float yaw, java.util.function.Function<Boolean, Entity> repositionEntity) {
|
||||||
|
|||||||
@ -4,7 +4,12 @@ import io.lampnet.travelerssuitcase.block.entity.SuitcaseBlockEntity;
|
|||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.entity.item.ItemEntity;
|
||||||
|
import net.minecraft.world.item.BlockItem;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.StringTag;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@ -12,20 +17,43 @@ import net.minecraft.sounds.SoundSource;
|
|||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import net.minecraft.world.level.storage.loot.LootParams;
|
import net.minecraft.world.level.storage.loot.LootParams;
|
||||||
|
|
||||||
public class PocketPortalBlock extends Block {
|
public class PocketPortalBlock extends Block {
|
||||||
|
private static final Map<String, PlayerPositionData> LAST_KNOWN_POSITIONS = new HashMap<>();
|
||||||
|
private static final int SEARCH_RADIUS_CHUNKS = 12;
|
||||||
|
public static class PlayerPositionData {
|
||||||
|
public final double x;
|
||||||
|
public final double y;
|
||||||
|
public final double z;
|
||||||
|
public final float yaw;
|
||||||
|
public final float pitch;
|
||||||
|
public final long timestamp;
|
||||||
|
public PlayerPositionData(double x, double y, double z, float yaw, float pitch) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public PocketPortalBlock(BlockBehaviour.Properties properties) {
|
public PocketPortalBlock(BlockBehaviour.Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
@ -37,9 +65,76 @@ public class PocketPortalBlock extends Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void storePlayerPosition(ServerPlayer player) {
|
||||||
|
LAST_KNOWN_POSITIONS.put(
|
||||||
|
player.getUUID().toString(),
|
||||||
|
new PlayerPositionData(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean attemptPlayerInventorySuitcaseTeleport(Level world, ServerLevel overworld, ServerPlayer player, String keystoneName) {
|
||||||
|
for (ServerPlayer serverPlayer : Objects.requireNonNull(world.getServer()).getPlayerList().getPlayers()) {
|
||||||
|
if (scanPlayerInventoryForSuitcase(serverPlayer, player, keystoneName, world, overworld)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean scanPlayerInventoryForSuitcase(ServerPlayer inventoryOwner, ServerPlayer exitingPlayer,
|
||||||
|
String keystoneName, Level world, ServerLevel overworld) {
|
||||||
|
for (int i = 0; i < inventoryOwner.getInventory().getContainerSize(); i++) {
|
||||||
|
ItemStack stack = inventoryOwner.getInventory().getItem(i);
|
||||||
|
if (isSuitcaseItemWithKeystone(stack, keystoneName)) {
|
||||||
|
cleanUpSuitcaseItemNbt(stack, exitingPlayer, keystoneName);
|
||||||
|
inventoryOwner.getInventory().setItem(i, stack);
|
||||||
|
teleportToPosition(world, exitingPlayer, overworld,
|
||||||
|
inventoryOwner.getX(), inventoryOwner.getY() + 1.0, inventoryOwner.getZ(),
|
||||||
|
exitingPlayer.getYRot(), exitingPlayer.getXRot());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSuitcaseItemWithKeystone(ItemStack stack, String keystoneName) {
|
||||||
|
if (stack.isEmpty() || !(stack.getItem() instanceof BlockItem) ||
|
||||||
|
!(((BlockItem) stack.getItem()).getBlock() instanceof SuitcaseBlock)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stack.hasTag()) return false;
|
||||||
|
CompoundTag beTag = BlockItem.getBlockEntityData(stack);
|
||||||
|
if (beTag == null) return false;
|
||||||
|
|
||||||
|
return beTag.contains("BoundKeystone") && keystoneName.equals(beTag.getString("BoundKeystone"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanUpSuitcaseItemNbt(ItemStack stack, ServerPlayer player, String keystoneName) {
|
||||||
|
if (!stack.hasTag()) return;
|
||||||
|
CompoundTag beTag = BlockItem.getBlockEntityData(stack);
|
||||||
|
if (beTag == null) return;
|
||||||
|
if (beTag.contains("EnteredPlayers", Tag.TAG_LIST)) {
|
||||||
|
ListTag playersList = beTag.getList("EnteredPlayers", Tag.TAG_COMPOUND);
|
||||||
|
ListTag newPlayersList = new ListTag();
|
||||||
|
boolean playerFound = false;
|
||||||
|
for (int i = 0; i < playersList.size(); i++) {
|
||||||
|
CompoundTag playerData = playersList.getCompound(i);
|
||||||
|
if (!player.getUUID().toString().equals(playerData.getString("UUID"))) {
|
||||||
|
newPlayersList.add(playerData);
|
||||||
|
} else {
|
||||||
|
playerFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (playerFound) {
|
||||||
|
beTag.put("EnteredPlayers", newPlayersList);
|
||||||
|
int remainingPlayers = newPlayersList.size();
|
||||||
|
updateItemLore(stack, remainingPlayers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SuitcaseBlockEntity.removeSuitcaseEntry(keystoneName, player.getUUID().toString(), player.getServer());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void entityInside(@NotNull BlockState state, Level world, @NotNull BlockPos pos, @NotNull Entity entity) {
|
public void entityInside(@NotNull BlockState state, Level world, @NotNull BlockPos pos, @NotNull Entity entity) {
|
||||||
@ -53,9 +148,28 @@ public class PocketPortalBlock extends Block {
|
|||||||
ServerLevel overworld = Objects.requireNonNull(world.getServer()).getLevel(Level.OVERWORLD);
|
ServerLevel overworld = Objects.requireNonNull(world.getServer()).getLevel(Level.OVERWORLD);
|
||||||
if (overworld == null) return;
|
if (overworld == null) return;
|
||||||
|
|
||||||
// Primary method: Try to teleport to the suitcase block they entered from
|
boolean teleported = false;
|
||||||
if (!attemptSuitcaseTeleport(world, overworld, player, keystoneName)) {
|
|
||||||
// Fallback: Take them to spawn if suitcase block cannot be found
|
// Method 1: Try to teleport to the original suitcase block entity
|
||||||
|
teleported = attemptSuitcaseTeleport(world, overworld, player, keystoneName);
|
||||||
|
|
||||||
|
// Method 2: Try to find suitcase in a player's inventory (new method)
|
||||||
|
if (!teleported) {
|
||||||
|
teleported = attemptPlayerInventorySuitcaseTeleport(world, overworld, player, keystoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 3: Try to find the suitcase as an item entity in the world
|
||||||
|
if (!teleported) {
|
||||||
|
teleported = attemptSuitcaseItemTeleport(world, overworld, player, keystoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 4: Try to use player's last known position
|
||||||
|
if (!teleported) {
|
||||||
|
teleported = attemptLastKnownPositionTeleport(world, overworld, player);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: Take them to spawn
|
||||||
|
if (!teleported) {
|
||||||
player.displayClientMessage(Component.literal("§c...").withStyle(ChatFormatting.RED), false);
|
player.displayClientMessage(Component.literal("§c...").withStyle(ChatFormatting.RED), false);
|
||||||
teleportToPosition(world, player, overworld,
|
teleportToPosition(world, player, overworld,
|
||||||
overworld.getSharedSpawnPos().getX() + 0.5,
|
overworld.getSharedSpawnPos().getX() + 0.5,
|
||||||
@ -63,6 +177,7 @@ public class PocketPortalBlock extends Block {
|
|||||||
overworld.getSharedSpawnPos().getZ() + 0.5, 0, 0);
|
overworld.getSharedSpawnPos().getZ() + 0.5, 0, 0);
|
||||||
}
|
}
|
||||||
SuitcaseBlockEntity.removeSuitcaseEntry(keystoneName, player.getUUID().toString(), world.getServer());
|
SuitcaseBlockEntity.removeSuitcaseEntry(keystoneName, player.getUUID().toString(), world.getServer());
|
||||||
|
LAST_KNOWN_POSITIONS.remove(player.getUUID().toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,11 +188,10 @@ public class PocketPortalBlock extends Block {
|
|||||||
player.fallDistance = 0f;
|
player.fallDistance = 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Teleport to the suitcase block coordinates they entered from
|
// Method 1: Try to teleport to the original suitcase block entity
|
||||||
private boolean attemptSuitcaseTeleport(Level world, ServerLevel overworld, ServerPlayer player, String keystoneName) {
|
private boolean attemptSuitcaseTeleport(Level world, ServerLevel overworld, ServerPlayer player, String keystoneName) {
|
||||||
BlockPos suitcasePos = SuitcaseBlockEntity.findSuitcasePosition(keystoneName, player.getUUID().toString());
|
BlockPos suitcasePos = SuitcaseBlockEntity.findSuitcasePosition(keystoneName, player.getUUID().toString());
|
||||||
if (suitcasePos == null) return false;
|
if (suitcasePos == null) return false;
|
||||||
|
|
||||||
ChunkPos suitcaseChunkPos = new ChunkPos(suitcasePos);
|
ChunkPos suitcaseChunkPos = new ChunkPos(suitcasePos);
|
||||||
overworld.setChunkForced(suitcaseChunkPos.x, suitcaseChunkPos.z, true);
|
overworld.setChunkForced(suitcaseChunkPos.x, suitcaseChunkPos.z, true);
|
||||||
try {
|
try {
|
||||||
@ -85,10 +199,7 @@ public class PocketPortalBlock extends Block {
|
|||||||
if (targetEntity instanceof SuitcaseBlockEntity suitcase) {
|
if (targetEntity instanceof SuitcaseBlockEntity suitcase) {
|
||||||
SuitcaseBlockEntity.EnteredPlayerData exitData = suitcase.getExitPosition(player.getUUID().toString());
|
SuitcaseBlockEntity.EnteredPlayerData exitData = suitcase.getExitPosition(player.getUUID().toString());
|
||||||
if (exitData != null) {
|
if (exitData != null) {
|
||||||
// Teleport to the suitcase block position (not the original player position)
|
teleportToPosition(world, player, overworld, exitData.x(), exitData.y(), exitData.z(), exitData.yaw(), player.getXRot());
|
||||||
teleportToPosition(world, player, overworld,
|
|
||||||
suitcasePos.getX() + 0.5, suitcasePos.getY() + 1.0, suitcasePos.getZ() + 0.5,
|
|
||||||
exitData.yaw(), player.getXRot());
|
|
||||||
Objects.requireNonNull(world.getServer()).execute(() -> {
|
Objects.requireNonNull(world.getServer()).execute(() -> {
|
||||||
overworld.setChunkForced(suitcaseChunkPos.x, suitcaseChunkPos.z, false);
|
overworld.setChunkForced(suitcaseChunkPos.x, suitcaseChunkPos.z, false);
|
||||||
});
|
});
|
||||||
@ -101,24 +212,118 @@ public class PocketPortalBlock extends Block {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method 2: Try to find the suitcase as an item entity in the world
|
||||||
|
private boolean attemptSuitcaseItemTeleport(Level world, ServerLevel overworld, ServerPlayer player, String keystoneName) {
|
||||||
|
BlockPos searchCenter;
|
||||||
|
BlockPos suitcasePos = SuitcaseBlockEntity.findSuitcasePosition(keystoneName, player.getUUID().toString());
|
||||||
|
if (suitcasePos != null) {
|
||||||
|
searchCenter = suitcasePos;
|
||||||
|
} else {
|
||||||
|
PlayerPositionData lastPos = LAST_KNOWN_POSITIONS.get(player.getUUID().toString());
|
||||||
|
if (lastPos != null) {
|
||||||
|
searchCenter = new BlockPos((int)lastPos.x, (int)lastPos.y, (int)lastPos.z);
|
||||||
|
} else {
|
||||||
|
searchCenter = overworld.getSharedSpawnPos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int centerX = searchCenter.getX() >> 4;
|
||||||
|
int centerZ = searchCenter.getZ() >> 4;
|
||||||
|
for (int radius = 0; radius <= SEARCH_RADIUS_CHUNKS; radius++) {
|
||||||
|
for (int x = centerX - radius; x <= centerX + radius; x++) {
|
||||||
|
for (int z = centerZ - radius; z <= centerZ + radius; z++) {
|
||||||
|
if (radius > 0 && x > centerX - radius && x < centerX + radius &&
|
||||||
|
z > centerZ - radius && z < centerZ + radius) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!overworld.hasChunk(x, z)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LevelChunk chunk = overworld.getChunk(x, z);
|
||||||
|
List<ItemEntity> itemEntities = overworld.getEntitiesOfClass(
|
||||||
|
ItemEntity.class,
|
||||||
|
new AABB(chunk.getPos().getMinBlockX(), overworld.getMinBuildHeight(), chunk.getPos().getMinBlockZ(),
|
||||||
|
chunk.getPos().getMaxBlockX(), overworld.getMaxBuildHeight(), chunk.getPos().getMaxBlockZ()),
|
||||||
|
itemEntity -> {
|
||||||
|
ItemStack stack = itemEntity.getItem();
|
||||||
|
CompoundTag beTag = BlockItem.getBlockEntityData(stack);
|
||||||
|
if (beTag == null) return false;
|
||||||
|
|
||||||
|
return beTag.contains("BoundKeystone") &&
|
||||||
|
keystoneName.equals(beTag.getString("BoundKeystone"));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!itemEntities.isEmpty()) {
|
||||||
|
ItemEntity suitcaseItemEntity = itemEntities.get(0);
|
||||||
|
cleanUpSuitcaseItemNbt(suitcaseItemEntity.getItem(), player, keystoneName);
|
||||||
|
suitcaseItemEntity.setItem(suitcaseItemEntity.getItem());
|
||||||
|
teleportToPosition(world, player, overworld,
|
||||||
|
suitcaseItemEntity.getX(), suitcaseItemEntity.getY() + 1.0, suitcaseItemEntity.getZ(),
|
||||||
|
player.getYRot(), player.getXRot());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method 3: Try to use player's last known position
|
||||||
|
private boolean attemptLastKnownPositionTeleport(Level world, ServerLevel overworld, ServerPlayer player) {
|
||||||
|
PlayerPositionData lastPos = LAST_KNOWN_POSITIONS.get(player.getUUID().toString());
|
||||||
|
if (lastPos != null) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (currentTime - lastPos.timestamp > 10 * 60 * 1000) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
player.displayClientMessage(Component.literal("§6Returning to your last known position."), false);
|
||||||
|
teleportToPosition(world, player, overworld,
|
||||||
|
lastPos.x, lastPos.y, lastPos.z,
|
||||||
|
lastPos.yaw, lastPos.pitch);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void teleportToPosition(Level world, ServerPlayer player, ServerLevel targetWorld,
|
private void teleportToPosition(Level world, ServerPlayer player, ServerLevel targetWorld,
|
||||||
double x, double y, double z, float yaw, float pitch) {
|
double x, double y, double z, float yaw, float pitch) {
|
||||||
if (!world.isClientSide) {
|
if (!world.isClientSide) {
|
||||||
// Use changeDimension instead of teleportTo to avoid "Player moved wrongly" errors
|
player.teleportTo(targetWorld, x, y, z, yaw, pitch);
|
||||||
player.changeDimension(targetWorld, new net.minecraftforge.common.util.ITeleporter() {
|
|
||||||
@Override
|
|
||||||
public Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float placementYaw, java.util.function.Function<Boolean, Entity> repositionEntity) {
|
|
||||||
Entity e = repositionEntity.apply(false);
|
|
||||||
e.teleportTo(x, y, z);
|
|
||||||
e.setYRot(yaw);
|
|
||||||
e.setXRot(pitch);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateItemLore(ItemStack stack, int playerCount) {
|
||||||
|
if (stack.hasTag()) {
|
||||||
|
assert stack.getTag() != null;
|
||||||
|
if (stack.getTag().contains("display")) {
|
||||||
|
CompoundTag display = stack.getTag().getCompound("display");
|
||||||
|
if (display.contains("Lore", Tag.TAG_LIST)) {
|
||||||
|
ListTag lore = display.getList("Lore", Tag.TAG_STRING);
|
||||||
|
ListTag newLore = new ListTag();
|
||||||
|
for (int i = 0; i < lore.size(); i++) {
|
||||||
|
String loreStr = lore.getString(i);
|
||||||
|
if (!loreStr.contains("traveler")) {
|
||||||
|
newLore.add(lore.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (playerCount > 0) {
|
||||||
|
Component warningText = Component.literal("§c⚠ Contains " + playerCount + " traveler(s)!")
|
||||||
|
.withStyle(ChatFormatting.RED);
|
||||||
|
newLore.add(0, StringTag.valueOf(Component.Serializer.toJson(warningText)));
|
||||||
|
}
|
||||||
|
display.put("Lore", newLore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (playerCount > 0) {
|
||||||
|
Component lore = Component.literal(playerCount + " player" + (playerCount > 1 ? "s" : "") + " inside").withStyle(ChatFormatting.GRAY);
|
||||||
|
CompoundTag displayTag = stack.getOrCreateTagElement("display");
|
||||||
|
ListTag loreList = new ListTag();
|
||||||
|
loreList.add(StringTag.valueOf(Component.Serializer.toJson(lore)));
|
||||||
|
displayTag.put("Lore", loreList);
|
||||||
|
} else {
|
||||||
|
if (stack.hasTag() && stack.getTag().contains("display")) {
|
||||||
|
stack.getTag().getCompound("display").remove("Lore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -45,11 +45,13 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.Containers;
|
||||||
import net.minecraft.world.item.DyeColor;
|
import net.minecraft.world.item.DyeColor;
|
||||||
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundStopSoundPacket;
|
import net.minecraft.network.protocol.game.ClientboundStopSoundPacket;
|
||||||
|
import net.minecraft.sounds.SoundSource;
|
||||||
|
import net.minecraft.sounds.SoundEvents;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@ -65,8 +67,6 @@ public class SuitcaseBlock extends BaseEntityBlock {
|
|||||||
private final static VoxelShape SHAPE_E = Block.box(2, 0, 0, 14, 4, 16);
|
private final static VoxelShape SHAPE_E = Block.box(2, 0, 0, 14, 4, 16);
|
||||||
private final static VoxelShape SHAPE_W = Block.box(2, 0, 0, 14, 4, 16);
|
private final static VoxelShape SHAPE_W = Block.box(2, 0, 0, 14, 4, 16);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public SuitcaseBlock(BlockBehaviour.Properties properties) {
|
public SuitcaseBlock(BlockBehaviour.Properties properties) {
|
||||||
super(properties);
|
super(properties);
|
||||||
this.registerDefaultState(this.stateDefinition.any()
|
this.registerDefaultState(this.stateDefinition.any()
|
||||||
@ -119,6 +119,42 @@ public class SuitcaseBlock extends BaseEntityBlock {
|
|||||||
@Override
|
@Override
|
||||||
public void onRemove(BlockState state, @NotNull Level world, @NotNull BlockPos pos, BlockState newState, boolean isMoving) {
|
public void onRemove(BlockState state, @NotNull Level world, @NotNull BlockPos pos, BlockState newState, boolean isMoving) {
|
||||||
if (!state.is(newState.getBlock())) {
|
if (!state.is(newState.getBlock())) {
|
||||||
|
BlockEntity blockEntity = world.getBlockEntity(pos);
|
||||||
|
if (blockEntity instanceof SuitcaseBlockEntity suitcase) {
|
||||||
|
ItemStack itemStack = new ItemStack(this);
|
||||||
|
String boundKeystone = suitcase.getBoundKeystoneName();
|
||||||
|
if (boundKeystone != null) {
|
||||||
|
CompoundTag beNbt = new CompoundTag();
|
||||||
|
suitcase.saveAdditional(beNbt);
|
||||||
|
|
||||||
|
if (!beNbt.isEmpty()) {
|
||||||
|
BlockItem.setBlockEntityData(itemStack, ModBlockEntities.SUITCASE_BLOCK_ENTITY.get(), beNbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompoundTag display = itemStack.getOrCreateTagElement("display");
|
||||||
|
ListTag lore = new ListTag();
|
||||||
|
String displayName = boundKeystone.replace("_", " ");
|
||||||
|
Component boundText;
|
||||||
|
if (suitcase.isLocked()) {
|
||||||
|
boundText = Component.literal("Bound to: §k" + displayName)
|
||||||
|
.withStyle(ChatFormatting.GRAY);
|
||||||
|
} else {
|
||||||
|
boundText = Component.literal("Bound to: " + displayName)
|
||||||
|
.withStyle(ChatFormatting.GRAY);
|
||||||
|
}
|
||||||
|
Component lockText = Component.literal(suitcase.isLocked() ? "§cLocked" : "§aUnlocked")
|
||||||
|
.withStyle(ChatFormatting.GRAY);
|
||||||
|
if (!suitcase.getEnteredPlayers().isEmpty()) {
|
||||||
|
Component warningText = Component.literal("§c⚠ Contains " + suitcase.getEnteredPlayers().size() + " Traveler's!")
|
||||||
|
.withStyle(ChatFormatting.RED);
|
||||||
|
lore.add(StringTag.valueOf(Component.Serializer.toJson(warningText)));
|
||||||
|
}
|
||||||
|
lore.add(StringTag.valueOf(Component.Serializer.toJson(boundText)));
|
||||||
|
lore.add(StringTag.valueOf(Component.Serializer.toJson(lockText)));
|
||||||
|
display.put("Lore", lore);
|
||||||
|
}
|
||||||
|
Containers.dropItemStack(world, pos.getX(), pos.getY(), pos.getZ(), itemStack);
|
||||||
|
}
|
||||||
super.onRemove(state, world, pos, newState, isMoving);
|
super.onRemove(state, world, pos, newState, isMoving);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,41 +263,12 @@ public class SuitcaseBlock extends BaseEntityBlock {
|
|||||||
player.fallDistance = 0f;
|
player.fallDistance = 0f;
|
||||||
|
|
||||||
PlayerEntryData ped = PlayerEntryData.get(targetWorld);
|
PlayerEntryData ped = PlayerEntryData.get(targetWorld);
|
||||||
|
|
||||||
// Use default position (17, 97, 9) unless manually configured
|
|
||||||
if (!ped.isManuallySet()) {
|
|
||||||
ped.setEntryAutomatic(new Vec3(17.5, 97.0, 9.5), 0f, 0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 dest = ped.getEntryPos();
|
Vec3 dest = ped.getEntryPos();
|
||||||
float entryYaw = ped.getEntryYaw();
|
|
||||||
|
float yaw = ped.getEntryYaw();
|
||||||
float pitch = player.getXRot();
|
float pitch = player.getXRot();
|
||||||
|
|
||||||
// Ensure destination chunk is loaded before teleportation
|
player.teleportTo(targetWorld, dest.x, dest.y, dest.z, yaw, pitch);
|
||||||
ChunkPos destChunkPos = new ChunkPos(BlockPos.containing(dest));
|
|
||||||
targetWorld.setChunkForced(destChunkPos.x, destChunkPos.z, true);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Use changeDimension instead of teleportTo to avoid "Player moved wrongly" errors
|
|
||||||
player.changeDimension(targetWorld, new net.minecraftforge.common.util.ITeleporter() {
|
|
||||||
@Override
|
|
||||||
public Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float placementYaw, java.util.function.Function<Boolean, Entity> repositionEntity) {
|
|
||||||
Entity e = repositionEntity.apply(false);
|
|
||||||
e.teleportTo(dest.x, dest.y, dest.z);
|
|
||||||
e.setYRot(entryYaw);
|
|
||||||
e.setXRot(pitch);
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Schedule chunk unforcing on next tick to allow proper entity placement
|
|
||||||
Objects.requireNonNull(world.getServer()).execute(() -> {
|
|
||||||
targetWorld.setChunkForced(destChunkPos.x, destChunkPos.z, false);
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
// Ensure chunk is unforced even if teleportation fails
|
|
||||||
targetWorld.setChunkForced(destChunkPos.x, destChunkPos.z, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
player.connection.send(new ClientboundStopSoundPacket(null, null));
|
player.connection.send(new ClientboundStopSoundPacket(null, null));
|
||||||
|
|
||||||
@ -276,8 +283,6 @@ public class SuitcaseBlock extends BaseEntityBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull VoxelShape getShape(BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos, @NotNull CollisionContext context) {
|
public @NotNull VoxelShape getShape(BlockState state, @NotNull BlockGetter world, @NotNull BlockPos pos, @NotNull CollisionContext context) {
|
||||||
return switch (state.getValue(FACING)) {
|
return switch (state.getValue(FACING)) {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
package io.lampnet.travelerssuitcase.block.entity;
|
package io.lampnet.travelerssuitcase.block.entity;
|
||||||
|
|
||||||
|
import io.lampnet.travelerssuitcase.block.PocketPortalBlock;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.ListTag;
|
import net.minecraft.nbt.ListTag;
|
||||||
@ -96,7 +96,7 @@ public class SuitcaseBlockEntity extends BlockEntity {
|
|||||||
);
|
);
|
||||||
suitcases.put(player.getUUID().toString(), this.worldPosition);
|
suitcases.put(player.getUUID().toString(), this.worldPosition);
|
||||||
}
|
}
|
||||||
|
PocketPortalBlock.storePlayerPosition(player);
|
||||||
setChangedAndNotify();
|
setChangedAndNotify();
|
||||||
|
|
||||||
MinecraftServer server = player.getServer();
|
MinecraftServer server = player.getServer();
|
||||||
@ -111,9 +111,9 @@ public class SuitcaseBlockEntity extends BlockEntity {
|
|||||||
if (data.uuid.equals(playerUuid)) {
|
if (data.uuid.equals(playerUuid)) {
|
||||||
EnteredPlayerData exitData = new EnteredPlayerData(
|
EnteredPlayerData exitData = new EnteredPlayerData(
|
||||||
data.uuid,
|
data.uuid,
|
||||||
data.x, data.y, data.z,
|
this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 1.0, this.worldPosition.getZ() + 0.5,
|
||||||
data.pitch, data.yaw,
|
data.pitch, data.yaw,
|
||||||
data.suitcasePos != null ? data.suitcasePos : this.worldPosition
|
this.worldPosition
|
||||||
);
|
);
|
||||||
enteredPlayers.remove(i);
|
enteredPlayers.remove(i);
|
||||||
setChangedAndNotify();
|
setChangedAndNotify();
|
||||||
@ -187,13 +187,7 @@ 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
|
this.saveAdditional(nbt);
|
||||||
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;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ public class PlayerEntryData extends SavedData {
|
|||||||
|
|
||||||
private Vec3 entryPos = Vec3.ZERO;
|
private Vec3 entryPos = Vec3.ZERO;
|
||||||
private float entryYaw = 0f, entryPitch = 0f;
|
private float entryYaw = 0f, entryPitch = 0f;
|
||||||
private boolean isManuallySet = false;
|
|
||||||
|
|
||||||
public PlayerEntryData() {
|
public PlayerEntryData() {
|
||||||
super();
|
super();
|
||||||
@ -28,7 +27,6 @@ public class PlayerEntryData extends SavedData {
|
|||||||
);
|
);
|
||||||
data.entryYaw = nbt.getFloat("pyaw");
|
data.entryYaw = nbt.getFloat("pyaw");
|
||||||
data.entryPitch = nbt.getFloat("ppitch");
|
data.entryPitch = nbt.getFloat("ppitch");
|
||||||
data.isManuallySet = nbt.getBoolean("manually_set");
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +41,6 @@ public class PlayerEntryData extends SavedData {
|
|||||||
nbt.putDouble("pz", entryPos.z);
|
nbt.putDouble("pz", entryPos.z);
|
||||||
nbt.putFloat( "pyaw", entryYaw);
|
nbt.putFloat( "pyaw", entryYaw);
|
||||||
nbt.putFloat( "ppitch", entryPitch);
|
nbt.putFloat( "ppitch", entryPitch);
|
||||||
nbt.putBoolean("manually_set", isManuallySet);
|
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,27 +48,10 @@ public class PlayerEntryData extends SavedData {
|
|||||||
this.entryPos = pos;
|
this.entryPos = pos;
|
||||||
this.entryYaw = yaw;
|
this.entryYaw = yaw;
|
||||||
this.entryPitch = pitch;
|
this.entryPitch = pitch;
|
||||||
this.isManuallySet = true;
|
|
||||||
this.setDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setEntryAutomatic(Vec3 pos, float yaw, float pitch) {
|
|
||||||
this.entryPos = pos;
|
|
||||||
this.entryYaw = yaw;
|
|
||||||
this.entryPitch = pitch;
|
|
||||||
this.setDirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void resetToDefault() {
|
|
||||||
this.entryPos = new Vec3(17.5, 97.0, 9.5);
|
|
||||||
this.entryYaw = 0f;
|
|
||||||
this.entryPitch = 0f;
|
|
||||||
this.isManuallySet = false;
|
|
||||||
this.setDirty();
|
this.setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getEntryPos() { return entryPos; }
|
public Vec3 getEntryPos() { return entryPos; }
|
||||||
public float getEntryYaw() { return entryYaw; }
|
public float getEntryYaw() { return entryYaw; }
|
||||||
public float getEntryPitch() { return entryPitch; }
|
public float getEntryPitch() { return entryPitch; }
|
||||||
public boolean isManuallySet() { return isManuallySet; }
|
|
||||||
}
|
}
|
||||||
@ -21,15 +21,10 @@ public class ServerChunkManagerMixin {
|
|||||||
private void onRunDistanceManagerUpdates(CallbackInfoReturnable<Boolean> cir) {
|
private void onRunDistanceManagerUpdates(CallbackInfoReturnable<Boolean> cir) {
|
||||||
// Only apply special chunk processing logic to RuntimeWorld instances (fantasy dimensions)
|
// 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;
|
if (!((FantasyWorldAccess) this.level).fantasy$shouldTick()) {
|
||||||
// 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);
|
cir.setReturnValue(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Regular worlds (overworld, nether, end) process chunks normally without interference
|
// Regular worlds (overworld, nether, end) process chunks normally without interference
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user