backrooms update 1

This commit is contained in:
2026-03-18 09:37:44 +01:00
parent 08f5f7fa58
commit 0d6f6a4fd8
14 changed files with 300 additions and 54 deletions

View File

@@ -6,7 +6,7 @@ minecraft_version=1.20.1
yarn_mappings=1.20.1+build.10
loader_version=0.18.3
# Mod Properties
mod_version=26.3.17.4
mod_version=26.3.18
maven_group=dev.tggamesyt
archives_base_name=szar
# Dependencies

View File

@@ -42,12 +42,12 @@ public class PortalBlock extends Block {
@Override
public void onEntityCollision(BlockState state, World world, BlockPos pos, Entity entity) {
if (world.isClient) return;
if (!(entity instanceof ServerPlayerEntity player)) return;
// Cooldown check
long now = world.getTime();
Long last = cooldowns.get(player.getUuid());
Long last = cooldowns.get(entity.getUuid());
if (last != null && now - last < 60) return;
cooldowns.put(player.getUuid(), now);
cooldowns.put(entity.getUuid(), now);
TrackerBlockEntity tracker = findTrackerAbove(world, pos);
if (tracker == null) return;
@@ -55,12 +55,52 @@ public class PortalBlock extends Block {
MinecraftServer server = world.getServer();
if (server == null) return;
// Detect dimension instead of reading isNetherSide
if (entity instanceof ServerPlayerEntity player) {
// Full player handling — inventory save, tracker registration, etc.
if (world.getRegistryKey() == World.OVERWORLD) {
teleportToNether(player, tracker, server, pos);
} 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());
}
}
}
}
private void teleportToNether(ServerPlayerEntity player, TrackerBlockEntity tracker,
@@ -74,6 +114,11 @@ public class PortalBlock extends Block {
tag.putInt("OwnerTrackerY", tracker.getPos().getY());
tag.putInt("OwnerTrackerZ", tracker.getPos().getZ());
tracker.returnX = player.getX();
tracker.returnY = player.getY() + 6;
tracker.returnZ = player.getZ();
tracker.markDirty();
// Save inventory
NbtList savedInventory = saveInventory(player);
saveInventoryToPlayer(player, savedInventory);
@@ -94,6 +139,20 @@ public class PortalBlock extends Block {
player.teleport(nether, netherX, netherY, netherZ,
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,
@@ -103,7 +162,6 @@ public class PortalBlock extends Block {
double returnY = tag.getDouble("EntryY");
double returnZ = tag.getDouble("EntryZ");
// Read overworld tracker pos
BlockPos owTrackerPos = null;
if (tag.contains("OwnerTrackerX")) {
owTrackerPos = new BlockPos(
@@ -117,23 +175,37 @@ public class PortalBlock extends Block {
netherTracker.removePlayer(player.getUuid());
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 (overworld.getBlockEntity(owTrackerPos) instanceof TrackerBlockEntity owTracker) {
owTracker.removePlayer(player.getUuid());
if (!owTracker.hasPlayers()) {
TrackerBlock.restoreAndCleanup(overworld, owTrackerPos, owTracker, server);
// Resolve to root of the overworld group
TrackerBlockEntity root = owTracker.getRoot(overworld);
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;
player.teleport(overworld, returnX, returnY, returnZ,
@@ -147,7 +219,8 @@ public class PortalBlock extends Block {
BlockPos check = portalPos.up(i);
if (world.getBlockState(check).getBlock() instanceof TrackerBlock) {
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());
}
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);
}
}

View File

@@ -355,8 +355,6 @@ public class Szar implements ModInitializer {
// random ahh silly stuff
entries.add(Szar.POPTART);
entries.add(Szar.NYAN_SPAWNEGG);
entries.add(Szar.EPSTEIN_FILES);
entries.add(Szar.EPSTEIN_SPAWNEGG);
entries.add(Szar.BAITER_DISC);
entries.add(Szar.MERL_SPAWNEGG);
entries.add(Szar.EFN_DISK);
@@ -416,6 +414,8 @@ public class Szar implements ModInitializer {
entries.add(Szar.NIGGERITE_BOOTS);
entries.add(Szar.NIGGERITE_BLOCK);
// nsfw
entries.add(Szar.EPSTEIN_FILES);
entries.add(Szar.EPSTEIN_SPAWNEGG);
entries.add(Szar.FASZITEM);
entries.add(Szar.CNDM);
entries.add(Szar.LATEX);

View File

@@ -10,15 +10,14 @@ import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.shape.VoxelShape;
import net.minecraft.util.shape.VoxelShapes;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.*;
public class TrackerBlock extends Block implements BlockEntityProvider {
@@ -71,24 +70,67 @@ public class TrackerBlock extends Block implements BlockEntityProvider {
@Nullable LivingEntity placer, ItemStack itemStack) {
if (world.isClient) return;
if (!(world.getBlockEntity(pos) instanceof TrackerBlockEntity tracker)) return;
// Only auto-place portal if a player placed this tracker
if (!tracker.placedByPlayer) return;
BlockPos portalPos = pos.down(4);
// Check all 6 neighbors for an existing tracker
TrackerBlockEntity parentTracker = findNeighborTracker(world, pos);
// Save the original block before replacing it
tracker.originalPortalBlock = world.getBlockState(portalPos);
BlockPos portalPos = pos.down(4);
BlockState originalBlock = world.getBlockState(portalPos);
if (parentTracker != null) {
// Merge — this becomes a child
tracker.parentTrackerPos = parentTracker.getPos();
tracker.originalPortalBlock = originalBlock;
tracker.markDirty();
// 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
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) {
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);
}
@@ -97,32 +139,60 @@ public class TrackerBlock extends Block implements BlockEntityProvider {
TrackerBlockEntity tracker, MinecraftServer server) {
if (server == null) return;
// Kick all players tracked here back to overworld
Set<UUID> players = new HashSet<>(tracker.getPlayersInside());
for (UUID uuid : players) {
ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid);
if (player == null) continue;
PortalBlock.restoreInventory(player, server);
ServerWorld overworld = server.getWorld(World.OVERWORLD);
if (overworld != null) {
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());
}
}
// Restore original block at portal position
BlockPos portalPos = trackerPos.down(4);
if (world.getBlockState(portalPos).getBlock() instanceof PortalBlock) {
world.setBlockState(portalPos, tracker.originalPortalBlock);
}
// Remove the tracker itself
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);
}
}
}

View File

@@ -8,10 +8,10 @@ import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtString;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.*;
public class TrackerBlockEntity extends BlockEntity {
// Add these fields
@@ -72,6 +72,21 @@ public class TrackerBlockEntity extends BlockEntity {
.ifPresent(nbt1 -> originalBlock.put("State", nbt1));
nbt.put("OriginalPortalBlock", originalBlock);
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
@@ -103,5 +118,63 @@ public class TrackerBlockEntity extends BlockEntity {
}
}
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;
}
}

View File

@@ -27,9 +27,6 @@ public class NoClipMixin {
private void szar_noClipBelowTracker(BlockView world, BlockPos pos,
ShapeContext ctx,
CallbackInfoReturnable<VoxelShape> cir) {
if (!(ctx instanceof EntityShapeContext esc)) return;
if (!(esc.getEntity() instanceof PlayerEntity)) return;
for (int i = 1; i <= 5; i++) {
BlockPos above = pos.up(i);
if (world.getBlockState(above).getBlock() instanceof TrackerBlock) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 KiB

After

Width:  |  Height:  |  Size: 552 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 94 KiB