backrooms update 1
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
|||||||
yarn_mappings=1.20.1+build.10
|
yarn_mappings=1.20.1+build.10
|
||||||
loader_version=0.18.3
|
loader_version=0.18.3
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=26.3.17.4
|
mod_version=26.3.18
|
||||||
maven_group=dev.tggamesyt
|
maven_group=dev.tggamesyt
|
||||||
archives_base_name=szar
|
archives_base_name=szar
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ public class PortalBlock extends Block {
|
|||||||
@Override
|
@Override
|
||||||
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
|
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
|
||||||
if (world.isClient) return;
|
if (world.isClient) return;
|
||||||
if (!(entity instanceof ServerPlayerEntity player)) return;
|
|
||||||
|
|
||||||
|
// Cooldown check
|
||||||
long now = world.getTime();
|
long now = world.getTime();
|
||||||
Long last = cooldowns.get(player.getUuid());
|
Long last = cooldowns.get(entity.getUuid());
|
||||||
if (last != null && now - last < 60) return;
|
if (last != null && now - last < 60) return;
|
||||||
cooldowns.put(player.getUuid(), now);
|
cooldowns.put(entity.getUuid(), now);
|
||||||
|
|
||||||
TrackerBlockEntity tracker = findTrackerAbove(world, pos);
|
TrackerBlockEntity tracker = findTrackerAbove(world, pos);
|
||||||
if (tracker == null) return;
|
if (tracker == null) return;
|
||||||
@@ -55,11 +55,51 @@ public class PortalBlock extends Block {
|
|||||||
MinecraftServer server = world.getServer();
|
MinecraftServer server = world.getServer();
|
||||||
if (server == null) return;
|
if (server == null) return;
|
||||||
|
|
||||||
// Detect dimension instead of reading isNetherSide
|
if (entity instanceof ServerPlayerEntity player) {
|
||||||
if (world.getRegistryKey() == World.OVERWORLD) {
|
// Full player handling — inventory save, tracker registration, etc.
|
||||||
teleportToNether(player, tracker, server, pos);
|
if (world.getRegistryKey() == World.OVERWORLD) {
|
||||||
} else if (world.getRegistryKey() == Szar.BACKROOMS_KEY) {
|
teleportToNether(player, tracker, server, pos);
|
||||||
teleportToOverworld(player, tracker, server);
|
} else if (world.getRegistryKey() == Szar.BACKROOMS_KEY) {
|
||||||
|
teleportToOverworld(player, tracker, server);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Non-player entity — just teleport, no inventory or tracker registration
|
||||||
|
if (world.getRegistryKey() == World.OVERWORLD) {
|
||||||
|
ServerWorld backrooms = server.getWorld(Szar.BACKROOMS_KEY);
|
||||||
|
if (backrooms == null) return;
|
||||||
|
double safeY = findSafeY(backrooms, (int) entity.getX(), (int) entity.getZ());
|
||||||
|
entity.teleport(backrooms, entity.getX(), safeY, entity.getZ(),
|
||||||
|
java.util.Set.of(), entity.getYaw(), entity.getPitch());
|
||||||
|
} else {
|
||||||
|
// Non-player entity — just teleport, no inventory or tracker registration
|
||||||
|
if (world.getRegistryKey() == World.OVERWORLD) {
|
||||||
|
ServerWorld backrooms = server.getWorld(Szar.BACKROOMS_KEY);
|
||||||
|
if (backrooms == null) return;
|
||||||
|
double safeY = findSafeY(backrooms, (int) entity.getX(), (int) entity.getZ());
|
||||||
|
entity.teleport(backrooms, entity.getX(), safeY, entity.getZ(),
|
||||||
|
java.util.Set.of(), entity.getYaw(), entity.getPitch());
|
||||||
|
} else if (world.getRegistryKey() == Szar.BACKROOMS_KEY) {
|
||||||
|
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||||
|
if (overworld == null) return;
|
||||||
|
|
||||||
|
double baseX = tracker.returnX;
|
||||||
|
double baseY = tracker.returnY;
|
||||||
|
double baseZ = tracker.returnZ;
|
||||||
|
|
||||||
|
// If no player has used this portal yet, fallback
|
||||||
|
if (baseX == 0 && baseY == 0 && baseZ == 0) {
|
||||||
|
double safeY = findSafeY(overworld, (int) entity.getX(), (int) entity.getZ());
|
||||||
|
entity.teleport(overworld, entity.getX(), safeY, entity.getZ(),
|
||||||
|
java.util.Set.of(), entity.getYaw(), entity.getPitch());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search up to 10 blocks offset in XZ and Y for a safe spot not above a portal
|
||||||
|
BlockPos safePos = findSafeSpotNearEntry(overworld, baseX, baseY, baseZ);
|
||||||
|
entity.teleport(overworld, safePos.getX() + 0.5, safePos.getY(), safePos.getZ() + 0.5,
|
||||||
|
java.util.Set.of(), entity.getYaw(), entity.getPitch());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +114,11 @@ public class PortalBlock extends Block {
|
|||||||
tag.putInt("OwnerTrackerY", tracker.getPos().getY());
|
tag.putInt("OwnerTrackerY", tracker.getPos().getY());
|
||||||
tag.putInt("OwnerTrackerZ", tracker.getPos().getZ());
|
tag.putInt("OwnerTrackerZ", tracker.getPos().getZ());
|
||||||
|
|
||||||
|
tracker.returnX = player.getX();
|
||||||
|
tracker.returnY = player.getY() + 6;
|
||||||
|
tracker.returnZ = player.getZ();
|
||||||
|
tracker.markDirty();
|
||||||
|
|
||||||
// Save inventory
|
// Save inventory
|
||||||
NbtList savedInventory = saveInventory(player);
|
NbtList savedInventory = saveInventory(player);
|
||||||
saveInventoryToPlayer(player, savedInventory);
|
saveInventoryToPlayer(player, savedInventory);
|
||||||
@@ -94,6 +139,20 @@ public class PortalBlock extends Block {
|
|||||||
|
|
||||||
player.teleport(nether, netherX, netherY, netherZ,
|
player.teleport(nether, netherX, netherY, netherZ,
|
||||||
player.getYaw(), player.getPitch());
|
player.getYaw(), player.getPitch());
|
||||||
|
|
||||||
|
BlockPos destPortalPos = new BlockPos((int) netherX, (int) netherY, (int) netherZ);
|
||||||
|
for (int i = 1; i <= 5; i++) {
|
||||||
|
BlockPos check = destPortalPos.up(i);
|
||||||
|
if (nether.getBlockState(check).getBlock() instanceof TrackerBlock) {
|
||||||
|
if (nether.getBlockEntity(check) instanceof TrackerBlockEntity backroomsTracker) {
|
||||||
|
backroomsTracker.returnX = player.getX();
|
||||||
|
backroomsTracker.returnY = player.getY() + 6;
|
||||||
|
backroomsTracker.returnZ = player.getZ();
|
||||||
|
backroomsTracker.markDirty();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void teleportToOverworld(ServerPlayerEntity player, TrackerBlockEntity netherTracker,
|
private void teleportToOverworld(ServerPlayerEntity player, TrackerBlockEntity netherTracker,
|
||||||
@@ -103,7 +162,6 @@ public class PortalBlock extends Block {
|
|||||||
double returnY = tag.getDouble("EntryY");
|
double returnY = tag.getDouble("EntryY");
|
||||||
double returnZ = tag.getDouble("EntryZ");
|
double returnZ = tag.getDouble("EntryZ");
|
||||||
|
|
||||||
// Read overworld tracker pos
|
|
||||||
BlockPos owTrackerPos = null;
|
BlockPos owTrackerPos = null;
|
||||||
if (tag.contains("OwnerTrackerX")) {
|
if (tag.contains("OwnerTrackerX")) {
|
||||||
owTrackerPos = new BlockPos(
|
owTrackerPos = new BlockPos(
|
||||||
@@ -117,24 +175,38 @@ public class PortalBlock extends Block {
|
|||||||
netherTracker.removePlayer(player.getUuid());
|
netherTracker.removePlayer(player.getUuid());
|
||||||
|
|
||||||
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||||
ServerWorld nether = server.getWorld(Szar.BACKROOMS_KEY);
|
ServerWorld backrooms = server.getWorld(Szar.BACKROOMS_KEY);
|
||||||
|
|
||||||
// Clean up nether side if empty
|
|
||||||
if (!netherTracker.hasPlayers() && nether != null) {
|
|
||||||
TrackerBlock.restoreAndCleanup(nether,
|
|
||||||
netherTracker.getPos(), netherTracker, server);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up overworld tracker too
|
|
||||||
if (owTrackerPos != null && overworld != null) {
|
if (owTrackerPos != null && overworld != null) {
|
||||||
if (overworld.getBlockEntity(owTrackerPos) instanceof TrackerBlockEntity owTracker) {
|
if (overworld.getBlockEntity(owTrackerPos) instanceof TrackerBlockEntity owTracker) {
|
||||||
owTracker.removePlayer(player.getUuid());
|
// Resolve to root of the overworld group
|
||||||
if (!owTracker.hasPlayers()) {
|
TrackerBlockEntity root = owTracker.getRoot(overworld);
|
||||||
TrackerBlock.restoreAndCleanup(overworld, owTrackerPos, owTracker, server);
|
root.removePlayer(player.getUuid());
|
||||||
|
|
||||||
|
if (!root.hasPlayers()) {
|
||||||
|
// Collect and clean up all connected trackers
|
||||||
|
List<BlockPos> allTrackers = new ArrayList<>();
|
||||||
|
allTrackers.add(root.getPos());
|
||||||
|
for (BlockPos childPortal : root.getControlledPortals()) {
|
||||||
|
allTrackers.add(childPortal.up(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BlockPos trackerPos : allTrackers) {
|
||||||
|
if (overworld.getBlockEntity(trackerPos)
|
||||||
|
instanceof TrackerBlockEntity te) {
|
||||||
|
TrackerBlock.restoreAndCleanup(overworld, trackerPos, te, server);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clean up backrooms tracker too
|
||||||
|
if (!netherTracker.hasPlayers() && backrooms != null) {
|
||||||
|
TrackerBlock.restoreAndCleanup(backrooms,
|
||||||
|
netherTracker.getPos(), netherTracker, server);
|
||||||
|
}
|
||||||
|
|
||||||
if (overworld == null) return;
|
if (overworld == null) return;
|
||||||
player.teleport(overworld, returnX, returnY, returnZ,
|
player.teleport(overworld, returnX, returnY, returnZ,
|
||||||
player.getYaw(), player.getPitch());
|
player.getYaw(), player.getPitch());
|
||||||
@@ -147,7 +219,8 @@ public class PortalBlock extends Block {
|
|||||||
BlockPos check = portalPos.up(i);
|
BlockPos check = portalPos.up(i);
|
||||||
if (world.getBlockState(check).getBlock() instanceof TrackerBlock) {
|
if (world.getBlockState(check).getBlock() instanceof TrackerBlock) {
|
||||||
if (world.getBlockEntity(check) instanceof TrackerBlockEntity te) {
|
if (world.getBlockEntity(check) instanceof TrackerBlockEntity te) {
|
||||||
return te;
|
// Always delegate to root
|
||||||
|
return te.getRoot(world);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -263,4 +336,37 @@ public class PortalBlock extends Block {
|
|||||||
|
|
||||||
state.removePlayerData(player.getUuid());
|
state.removePlayerData(player.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BlockPos findSafeSpotNearEntry(ServerWorld world, double baseX, double baseY, double baseZ) {
|
||||||
|
System.out.println(baseX + ", " + baseY + ", " + baseZ);
|
||||||
|
int bx = (int) baseX;
|
||||||
|
int by = (int) baseY;
|
||||||
|
int bz = (int) baseZ;
|
||||||
|
|
||||||
|
// First try exact position
|
||||||
|
BlockPos exact = new BlockPos(bx, by, bz);
|
||||||
|
if (isSafeAndNotPortal(world, exact)) return exact;
|
||||||
|
|
||||||
|
// Spiral outward in XZ only, keep Y fixed to entry Y
|
||||||
|
for (int radius = 1; radius <= 10; radius++) {
|
||||||
|
for (int dx = -radius; dx <= radius; dx++) {
|
||||||
|
for (int dz = -radius; dz <= radius; dz++) {
|
||||||
|
if (Math.abs(dx) != radius && Math.abs(dz) != radius) continue;
|
||||||
|
BlockPos candidate = new BlockPos(bx + dx, by, bz + dz);
|
||||||
|
if (isSafeAndNotPortal(world, candidate)) return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exact; // fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSafeAndNotPortal(ServerWorld world, BlockPos feet) {
|
||||||
|
BlockPos head = feet.up();
|
||||||
|
BlockPos ground = feet.down();
|
||||||
|
return !world.getBlockState(feet).isSolidBlock(world, feet)
|
||||||
|
&& !world.getBlockState(head).isSolidBlock(world, head)
|
||||||
|
&& world.getBlockState(ground).isSolidBlock(world, ground)
|
||||||
|
&& !(world.getBlockState(ground).getBlock() instanceof PortalBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -355,8 +355,6 @@ public class Szar implements ModInitializer {
|
|||||||
// random ahh silly stuff
|
// random ahh silly stuff
|
||||||
entries.add(Szar.POPTART);
|
entries.add(Szar.POPTART);
|
||||||
entries.add(Szar.NYAN_SPAWNEGG);
|
entries.add(Szar.NYAN_SPAWNEGG);
|
||||||
entries.add(Szar.EPSTEIN_FILES);
|
|
||||||
entries.add(Szar.EPSTEIN_SPAWNEGG);
|
|
||||||
entries.add(Szar.BAITER_DISC);
|
entries.add(Szar.BAITER_DISC);
|
||||||
entries.add(Szar.MERL_SPAWNEGG);
|
entries.add(Szar.MERL_SPAWNEGG);
|
||||||
entries.add(Szar.EFN_DISK);
|
entries.add(Szar.EFN_DISK);
|
||||||
@@ -416,6 +414,8 @@ public class Szar implements ModInitializer {
|
|||||||
entries.add(Szar.NIGGERITE_BOOTS);
|
entries.add(Szar.NIGGERITE_BOOTS);
|
||||||
entries.add(Szar.NIGGERITE_BLOCK);
|
entries.add(Szar.NIGGERITE_BLOCK);
|
||||||
// nsfw
|
// nsfw
|
||||||
|
entries.add(Szar.EPSTEIN_FILES);
|
||||||
|
entries.add(Szar.EPSTEIN_SPAWNEGG);
|
||||||
entries.add(Szar.FASZITEM);
|
entries.add(Szar.FASZITEM);
|
||||||
entries.add(Szar.CNDM);
|
entries.add(Szar.CNDM);
|
||||||
entries.add(Szar.LATEX);
|
entries.add(Szar.LATEX);
|
||||||
|
|||||||
@@ -10,15 +10,14 @@ import net.minecraft.server.MinecraftServer;
|
|||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.server.world.ServerWorld;
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class TrackerBlock extends Block implements BlockEntityProvider {
|
public class TrackerBlock extends Block implements BlockEntityProvider {
|
||||||
|
|
||||||
@@ -71,24 +70,67 @@ public class TrackerBlock extends Block implements BlockEntityProvider {
|
|||||||
@Nullable LivingEntity placer, ItemStack itemStack) {
|
@Nullable LivingEntity placer, ItemStack itemStack) {
|
||||||
if (world.isClient) return;
|
if (world.isClient) return;
|
||||||
if (!(world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker)) return;
|
if (!(world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker)) return;
|
||||||
|
|
||||||
// Only auto-place portal if a player placed this tracker
|
|
||||||
if (!tracker.placedByPlayer) return;
|
if (!tracker.placedByPlayer) return;
|
||||||
|
|
||||||
|
// Check all 6 neighbors for an existing tracker
|
||||||
|
TrackerBlockEntity parentTracker = findNeighborTracker(world, pos);
|
||||||
|
|
||||||
BlockPos portalPos = pos.down(4);
|
BlockPos portalPos = pos.down(4);
|
||||||
|
BlockState originalBlock = world.getBlockState(portalPos);
|
||||||
|
|
||||||
// Save the original block before replacing it
|
if (parentTracker != null) {
|
||||||
tracker.originalPortalBlock = world.getBlockState(portalPos);
|
// Merge — this becomes a child
|
||||||
tracker.markDirty();
|
tracker.parentTrackerPos = parentTracker.getPos();
|
||||||
|
tracker.originalPortalBlock = originalBlock;
|
||||||
|
tracker.markDirty();
|
||||||
|
|
||||||
world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState());
|
// Register portal with parent
|
||||||
|
parentTracker.addPortal(portalPos);
|
||||||
|
|
||||||
|
// Place portal block
|
||||||
|
world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState());
|
||||||
|
} else {
|
||||||
|
// Standalone — normal behavior
|
||||||
|
tracker.originalPortalBlock = originalBlock;
|
||||||
|
tracker.markDirty();
|
||||||
|
world.setBlockState(portalPos, Szar.PORTAL_BLOCK.getDefaultState());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private TrackerBlockEntity findNeighborTracker(World world, BlockPos pos) {
|
||||||
|
for (Direction dir : Direction.values()) {
|
||||||
|
BlockPos neighbor = pos.offset(dir);
|
||||||
|
if (world.getBlockState(neighbor).getBlock() instanceof TrackerBlock) {
|
||||||
|
if (world.getBlockEntity(neighbor) instanceof TrackerBlockEntity te) {
|
||||||
|
// Always return the root of the neighbor
|
||||||
|
return te.getRoot(world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) {
|
||||||
// In survival, only break if holding the special item
|
|
||||||
|
|
||||||
if (!world.isClient && world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker) {
|
if (!world.isClient && world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker) {
|
||||||
restoreAndCleanup(world, pos, tracker, world.getServer());
|
// Resolve to root
|
||||||
|
TrackerBlockEntity root = tracker.getRoot(world);
|
||||||
|
BlockPos rootPos = root.getPos();
|
||||||
|
|
||||||
|
// Collect all connected tracker positions (root + all children)
|
||||||
|
List<BlockPos> allTrackers = new ArrayList<>();
|
||||||
|
allTrackers.add(rootPos);
|
||||||
|
for (BlockPos childPortal : root.getControlledPortals()) {
|
||||||
|
allTrackers.add(childPortal.up(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up each tracker and its portal
|
||||||
|
for (BlockPos trackerPos : allTrackers) {
|
||||||
|
if (world.getBlockEntity(trackerPos) instanceof TrackerBlockEntity te) {
|
||||||
|
cleanupPortalOnly(world, trackerPos, te, world.getServer());
|
||||||
|
world.removeBlock(trackerPos, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.onBreak(world, pos, state, player);
|
super.onBreak(world, pos, state, player);
|
||||||
}
|
}
|
||||||
@@ -97,32 +139,60 @@ public class TrackerBlock extends Block implements BlockEntityProvider {
|
|||||||
TrackerBlockEntity tracker, MinecraftServer server) {
|
TrackerBlockEntity tracker, MinecraftServer server) {
|
||||||
if (server == null) return;
|
if (server == null) return;
|
||||||
|
|
||||||
// Kick all players tracked here back to overworld
|
|
||||||
Set<UUID> players = new HashSet<>(tracker.getPlayersInside());
|
Set<UUID> players = new HashSet<>(tracker.getPlayersInside());
|
||||||
for (UUID uuid : players) {
|
for (UUID uuid : players) {
|
||||||
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
if (player == null) continue;
|
if (player == null) continue;
|
||||||
|
|
||||||
|
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||||
|
if (overworld == null) continue;
|
||||||
|
|
||||||
|
// Read coords BEFORE restoreInventory wipes the state
|
||||||
|
NbtCompound tag = PortalDataState.getOrCreate(overworld)
|
||||||
|
.getOrCreatePlayerData(uuid);
|
||||||
|
double rx = tag.getDouble("EntryX");
|
||||||
|
double ry = tag.getDouble("EntryY");
|
||||||
|
double rz = tag.getDouble("EntryZ");
|
||||||
|
|
||||||
PortalBlock.restoreInventory(player, server);
|
PortalBlock.restoreInventory(player, server);
|
||||||
|
|
||||||
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
player.teleport(overworld, rx, ry, rz, player.getYaw(), player.getPitch());
|
||||||
if (overworld != null) {
|
|
||||||
NbtCompound tag = PortalDataState.getOrCreate(overworld)
|
|
||||||
.getOrCreatePlayerData(uuid);
|
|
||||||
double rx = tag.getDouble("EntryX");
|
|
||||||
double ry = tag.getDouble("EntryY");
|
|
||||||
double rz = tag.getDouble("EntryZ");
|
|
||||||
player.teleport(overworld, rx, ry, rz, player.getYaw(), player.getPitch());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore original block at portal position
|
|
||||||
BlockPos portalPos = trackerPos.down(4);
|
BlockPos portalPos = trackerPos.down(4);
|
||||||
if (world.getBlockState(portalPos).getBlock() instanceof PortalBlock) {
|
if (world.getBlockState(portalPos).getBlock() instanceof PortalBlock) {
|
||||||
world.setBlockState(portalPos, tracker.originalPortalBlock);
|
world.setBlockState(portalPos, tracker.originalPortalBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the tracker itself
|
|
||||||
world.removeBlock(trackerPos, false);
|
world.removeBlock(trackerPos, false);
|
||||||
}
|
}
|
||||||
|
public static void cleanupPortalOnly(World world, BlockPos trackerPos,
|
||||||
|
TrackerBlockEntity tracker, MinecraftServer server) {
|
||||||
|
if (server == null) return;
|
||||||
|
|
||||||
|
Set<UUID> players = new HashSet<>(tracker.getPlayersInside());
|
||||||
|
for (UUID uuid : players) {
|
||||||
|
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
|
||||||
|
if (player == null) continue;
|
||||||
|
|
||||||
|
ServerWorld overworld = server.getWorld(World.OVERWORLD);
|
||||||
|
if (overworld == null) continue;
|
||||||
|
|
||||||
|
// Read coords BEFORE restoreInventory wipes the state
|
||||||
|
NbtCompound tag = PortalDataState.getOrCreate(overworld)
|
||||||
|
.getOrCreatePlayerData(uuid);
|
||||||
|
double rx = tag.getDouble("EntryX");
|
||||||
|
double ry = tag.getDouble("EntryY");
|
||||||
|
double rz = tag.getDouble("EntryZ");
|
||||||
|
|
||||||
|
PortalBlock.restoreInventory(player, server);
|
||||||
|
|
||||||
|
player.teleport(overworld, rx, ry, rz, player.getYaw(), player.getPitch());
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockPos portalPos = trackerPos.down(4);
|
||||||
|
if (world.getBlockState(portalPos).getBlock() instanceof PortalBlock) {
|
||||||
|
world.setBlockState(portalPos, tracker.originalPortalBlock);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,10 +8,10 @@ import net.minecraft.nbt.NbtList;
|
|||||||
import net.minecraft.nbt.NbtOps;
|
import net.minecraft.nbt.NbtOps;
|
||||||
import net.minecraft.nbt.NbtString;
|
import net.minecraft.nbt.NbtString;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class TrackerBlockEntity extends BlockEntity {
|
public class TrackerBlockEntity extends BlockEntity {
|
||||||
// Add these fields
|
// Add these fields
|
||||||
@@ -72,6 +72,21 @@ public class TrackerBlockEntity extends BlockEntity {
|
|||||||
.ifPresent(nbt1 -> originalBlock.put("State", nbt1));
|
.ifPresent(nbt1 -> originalBlock.put("State", nbt1));
|
||||||
nbt.put("OriginalPortalBlock", originalBlock);
|
nbt.put("OriginalPortalBlock", originalBlock);
|
||||||
nbt.putBoolean("PlacedByPlayer", placedByPlayer);
|
nbt.putBoolean("PlacedByPlayer", placedByPlayer);
|
||||||
|
if (parentTrackerPos != null) {
|
||||||
|
nbt.putInt("ParentX", parentTrackerPos.getX());
|
||||||
|
nbt.putInt("ParentY", parentTrackerPos.getY());
|
||||||
|
nbt.putInt("ParentZ", parentTrackerPos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
NbtList portalList = new NbtList();
|
||||||
|
for (BlockPos p : controlledPortals) {
|
||||||
|
NbtCompound entry = new NbtCompound();
|
||||||
|
entry.putInt("X", p.getX());
|
||||||
|
entry.putInt("Y", p.getY());
|
||||||
|
entry.putInt("Z", p.getZ());
|
||||||
|
portalList.add(entry);
|
||||||
|
}
|
||||||
|
nbt.put("ControlledPortals", portalList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -103,5 +118,63 @@ public class TrackerBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
placedByPlayer = nbt.getBoolean("PlacedByPlayer");
|
placedByPlayer = nbt.getBoolean("PlacedByPlayer");
|
||||||
|
if (nbt.contains("ParentX")) {
|
||||||
|
parentTrackerPos = new BlockPos(
|
||||||
|
nbt.getInt("ParentX"),
|
||||||
|
nbt.getInt("ParentY"),
|
||||||
|
nbt.getInt("ParentZ")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
parentTrackerPos = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
controlledPortals.clear();
|
||||||
|
NbtList portalList = nbt.getList("ControlledPortals", 10);
|
||||||
|
for (int i = 0; i < portalList.size(); i++) {
|
||||||
|
NbtCompound entry = portalList.getCompound(i);
|
||||||
|
controlledPortals.add(new BlockPos(
|
||||||
|
entry.getInt("X"), entry.getInt("Y"), entry.getInt("Z")
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// null = this is a root/parent tracker
|
||||||
|
// non-null = this is a child, delegate to parent
|
||||||
|
@Nullable
|
||||||
|
public BlockPos parentTrackerPos = null;
|
||||||
|
|
||||||
|
// List of portal positions this tracker controls (only used by parent)
|
||||||
|
private final List<BlockPos> controlledPortals = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addPortal(BlockPos portalPos) {
|
||||||
|
if (!controlledPortals.contains(portalPos)) {
|
||||||
|
controlledPortals.add(portalPos);
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePortal(BlockPos portalPos) {
|
||||||
|
controlledPortals.remove(portalPos);
|
||||||
|
markDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BlockPos> getControlledPortals() {
|
||||||
|
return controlledPortals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isChild() {
|
||||||
|
return parentTrackerPos != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolves to the root parent, following chain if needed
|
||||||
|
public TrackerBlockEntity getRoot(World world) {
|
||||||
|
if (parentTrackerPos == null) return this;
|
||||||
|
if (world.getBlockEntity(parentTrackerPos) instanceof TrackerBlockEntity parent) {
|
||||||
|
return parent.getRoot(world);
|
||||||
|
}
|
||||||
|
// Parent is gone — become root
|
||||||
|
parentTrackerPos = null;
|
||||||
|
markDirty();
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,9 +27,6 @@ public class NoClipMixin {
|
|||||||
private void szar_noClipBelowTracker(BlockView world, BlockPos pos,
|
private void szar_noClipBelowTracker(BlockView world, BlockPos pos,
|
||||||
ShapeContext ctx,
|
ShapeContext ctx,
|
||||||
CallbackInfoReturnable<VoxelShape> cir) {
|
CallbackInfoReturnable<VoxelShape> cir) {
|
||||||
if (!(ctx instanceof EntityShapeContext esc)) return;
|
|
||||||
if (!(esc.getEntity() instanceof PlayerEntity)) return;
|
|
||||||
|
|
||||||
for (int i = 1; i <= 5; i++) {
|
for (int i = 1; i <= 5; i++) {
|
||||||
BlockPos above = pos.up(i);
|
BlockPos above = pos.up(i);
|
||||||
if (world.getBlockState(above).getBlock() instanceof TrackerBlock) {
|
if (world.getBlockState(above).getBlock() instanceof TrackerBlock) {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 420 KiB After Width: | Height: | Size: 552 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 420 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 94 KiB |