2025-05-10 15:35:30 -04:00
|
|
|
package io.lampnet.travelerssuitcase.block.entity;
|
|
|
|
|
|
|
|
|
|
import io.lampnet.travelerssuitcase.block.PocketPortalBlock;
|
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
|
|
|
import net.minecraft.nbt.CompoundTag;
|
|
|
|
|
import net.minecraft.nbt.ListTag;
|
|
|
|
|
import net.minecraft.nbt.Tag;
|
|
|
|
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
|
|
|
|
import net.minecraft.server.level.ServerPlayer;
|
|
|
|
|
import net.minecraft.world.level.Level;
|
|
|
|
|
import net.minecraft.world.level.block.Block;
|
|
|
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
|
|
|
import net.minecraft.world.level.block.state.BlockState;
|
2025-05-10 16:52:22 -04:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2025-05-10 15:35:30 -04:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
|
|
|
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
|
|
public class SuitcaseBlockEntity extends BlockEntity {
|
|
|
|
|
private String boundKeystoneName;
|
|
|
|
|
private boolean isLocked = false;
|
|
|
|
|
private boolean dimensionLocked = true;
|
|
|
|
|
private final List<EnteredPlayerData> enteredPlayers = new ArrayList<>();
|
|
|
|
|
|
2025-05-10 16:52:22 -04:00
|
|
|
public record EnteredPlayerData(String uuid, double x, double y, double z, float pitch, float yaw,
|
|
|
|
|
BlockPos suitcasePos) {
|
2025-05-10 15:35:30 -04:00
|
|
|
|
|
|
|
|
public CompoundTag toNbt() {
|
2025-05-10 16:52:22 -04:00
|
|
|
CompoundTag nbt = new CompoundTag();
|
|
|
|
|
nbt.putString("UUID", uuid);
|
|
|
|
|
nbt.putDouble("X", x);
|
|
|
|
|
nbt.putDouble("Y", y);
|
|
|
|
|
nbt.putDouble("Z", z);
|
|
|
|
|
nbt.putFloat("Pitch", pitch);
|
|
|
|
|
nbt.putFloat("Yaw", yaw);
|
|
|
|
|
if (suitcasePos != null) {
|
|
|
|
|
nbt.putInt("SuitcaseX", suitcasePos.getX());
|
|
|
|
|
nbt.putInt("SuitcaseY", suitcasePos.getY());
|
|
|
|
|
nbt.putInt("SuitcaseZ", suitcasePos.getZ());
|
|
|
|
|
}
|
|
|
|
|
return nbt;
|
2025-05-10 15:35:30 -04:00
|
|
|
}
|
|
|
|
|
|
2025-05-10 16:52:22 -04:00
|
|
|
public static EnteredPlayerData fromNbt(CompoundTag nbt) {
|
|
|
|
|
BlockPos sPos = null;
|
|
|
|
|
if (nbt.contains("SuitcaseX") && nbt.contains("SuitcaseY") && nbt.contains("SuitcaseZ")) {
|
|
|
|
|
sPos = new BlockPos(nbt.getInt("SuitcaseX"), nbt.getInt("SuitcaseY"), nbt.getInt("SuitcaseZ"));
|
|
|
|
|
}
|
|
|
|
|
return new EnteredPlayerData(
|
|
|
|
|
nbt.getString("UUID"),
|
|
|
|
|
nbt.getDouble("X"), nbt.getDouble("Y"), nbt.getDouble("Z"),
|
|
|
|
|
nbt.getFloat("Pitch"), nbt.getFloat("Yaw"),
|
|
|
|
|
sPos
|
|
|
|
|
);
|
2025-05-10 15:35:30 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public SuitcaseBlockEntity(BlockPos pos, BlockState state) {
|
|
|
|
|
super(ModBlockEntities.SUITCASE_BLOCK_ENTITY.get(), pos, state);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean canOpenInDimension(Level level) {
|
|
|
|
|
if (!dimensionLocked) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return level.dimension() == Level.OVERWORLD;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isDimensionLocked() {
|
|
|
|
|
return dimensionLocked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void playerEntered(ServerPlayer player) {
|
|
|
|
|
enteredPlayers.removeIf(data -> data.uuid.equals(player.getUUID().toString()));
|
|
|
|
|
EnteredPlayerData data = new EnteredPlayerData(
|
|
|
|
|
player.getUUID().toString(),
|
|
|
|
|
player.getX(), player.getY(), player.getZ(),
|
|
|
|
|
player.getXRot(), player.getYRot(),
|
|
|
|
|
this.worldPosition
|
|
|
|
|
);
|
|
|
|
|
enteredPlayers.add(data);
|
|
|
|
|
if (boundKeystoneName != null) {
|
|
|
|
|
Map<String, BlockPos> suitcases = SUITCASE_REGISTRY.computeIfAbsent(
|
|
|
|
|
boundKeystoneName, k -> new HashMap<>()
|
|
|
|
|
);
|
|
|
|
|
suitcases.put(player.getUUID().toString(), this.worldPosition);
|
|
|
|
|
}
|
|
|
|
|
PocketPortalBlock.storePlayerPosition(player);
|
|
|
|
|
setChangedAndNotify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public EnteredPlayerData getExitPosition(String playerUuid) {
|
|
|
|
|
for (int i = 0; i < enteredPlayers.size(); i++) {
|
|
|
|
|
EnteredPlayerData data = enteredPlayers.get(i);
|
|
|
|
|
if (data.uuid.equals(playerUuid)) {
|
|
|
|
|
EnteredPlayerData exitData = new EnteredPlayerData(
|
|
|
|
|
data.uuid,
|
|
|
|
|
this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 1.0, this.worldPosition.getZ() + 0.5,
|
|
|
|
|
data.pitch, data.yaw,
|
|
|
|
|
this.worldPosition
|
|
|
|
|
);
|
|
|
|
|
enteredPlayers.remove(i);
|
|
|
|
|
setChangedAndNotify();
|
|
|
|
|
return exitData;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void bindKeystone(String keystoneName) {
|
|
|
|
|
this.boundKeystoneName = keystoneName;
|
|
|
|
|
setChangedAndNotify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getBoundKeystoneName() {
|
|
|
|
|
return boundKeystoneName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setLocked(boolean locked) {
|
|
|
|
|
this.isLocked = locked;
|
|
|
|
|
setChangedAndNotify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isLocked() {
|
|
|
|
|
return isLocked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-05-10 16:52:22 -04:00
|
|
|
public void saveAdditional(@NotNull CompoundTag nbt) {
|
2025-05-10 15:35:30 -04:00
|
|
|
super.saveAdditional(nbt);
|
|
|
|
|
if (boundKeystoneName != null) {
|
|
|
|
|
nbt.putString("BoundKeystone", boundKeystoneName);
|
|
|
|
|
}
|
|
|
|
|
nbt.putBoolean("Locked", isLocked);
|
|
|
|
|
nbt.putBoolean("DimensionLocked", dimensionLocked);
|
|
|
|
|
|
|
|
|
|
ListTag playersListTag = new ListTag();
|
|
|
|
|
for (EnteredPlayerData data : enteredPlayers) {
|
|
|
|
|
playersListTag.add(data.toNbt());
|
|
|
|
|
}
|
|
|
|
|
if (!playersListTag.isEmpty()) {
|
|
|
|
|
nbt.put("EnteredPlayers", playersListTag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-05-10 16:52:22 -04:00
|
|
|
public void load(@NotNull CompoundTag nbt) {
|
2025-05-10 15:35:30 -04:00
|
|
|
super.load(nbt);
|
|
|
|
|
if (nbt.contains("BoundKeystone", Tag.TAG_STRING)) {
|
|
|
|
|
boundKeystoneName = nbt.getString("BoundKeystone");
|
|
|
|
|
} else {
|
|
|
|
|
boundKeystoneName = null;
|
|
|
|
|
}
|
|
|
|
|
isLocked = nbt.getBoolean("Locked");
|
|
|
|
|
dimensionLocked = !nbt.contains("DimensionLocked") || nbt.getBoolean("DimensionLocked");
|
|
|
|
|
enteredPlayers.clear();
|
|
|
|
|
if (nbt.contains("EnteredPlayers", Tag.TAG_LIST)) {
|
|
|
|
|
ListTag playersListTag = nbt.getList("EnteredPlayers", Tag.TAG_COMPOUND);
|
|
|
|
|
for (int i = 0; i < playersListTag.size(); i++) {
|
|
|
|
|
enteredPlayers.add(EnteredPlayerData.fromNbt(playersListTag.getCompound(i)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
|
@Override
|
|
|
|
|
public ClientboundBlockEntityDataPacket getUpdatePacket() {
|
|
|
|
|
return ClientboundBlockEntityDataPacket.create(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-05-10 16:52:22 -04:00
|
|
|
public @NotNull CompoundTag getUpdateTag() {
|
2025-05-10 15:35:30 -04:00
|
|
|
CompoundTag nbt = new CompoundTag();
|
|
|
|
|
this.saveAdditional(nbt);
|
|
|
|
|
return nbt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static final Map<String, Map<String, BlockPos>> SUITCASE_REGISTRY = Collections.synchronizedMap(new HashMap<>());
|
|
|
|
|
|
|
|
|
|
public static BlockPos findSuitcasePosition(String keystoneName, String playerUuid) {
|
|
|
|
|
Map<String, BlockPos> suitcases = SUITCASE_REGISTRY.get(keystoneName);
|
|
|
|
|
return (suitcases != null) ? suitcases.get(playerUuid) : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void removeSuitcaseEntry(String keystoneName, String playerUuid) {
|
|
|
|
|
Map<String, BlockPos> suitcases = SUITCASE_REGISTRY.get(keystoneName);
|
|
|
|
|
if (suitcases != null) {
|
|
|
|
|
suitcases.remove(playerUuid);
|
|
|
|
|
if (suitcases.isEmpty()) {
|
|
|
|
|
SUITCASE_REGISTRY.remove(keystoneName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<EnteredPlayerData> getEnteredPlayers() {
|
|
|
|
|
return Collections.unmodifiableList(enteredPlayers);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void initializeSuitcaseRegistry(Map<String, Map<String, BlockPos>> savedRegistry) {
|
|
|
|
|
SUITCASE_REGISTRY.clear();
|
|
|
|
|
if (savedRegistry != null) {
|
|
|
|
|
savedRegistry.forEach((key, value) -> {
|
|
|
|
|
Map<String, BlockPos> players = SUITCASE_REGISTRY.computeIfAbsent(key, k -> Collections.synchronizedMap(new HashMap<>()));
|
|
|
|
|
players.putAll(value);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void saveSuitcaseRegistryTo(Map<String, Map<String, BlockPos>> destination) {
|
|
|
|
|
destination.clear();
|
|
|
|
|
SUITCASE_REGISTRY.forEach((key, value) -> {
|
2025-05-10 16:52:22 -04:00
|
|
|
Map<String, BlockPos> players = destination.computeIfAbsent(key, k -> new HashMap<>());
|
|
|
|
|
players.putAll(value);
|
2025-05-10 15:35:30 -04:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void updatePlayerSuitcasePosition(String playerUuid, BlockPos newPos) {
|
|
|
|
|
boolean updated = false;
|
|
|
|
|
for (int i = 0; i < enteredPlayers.size(); i++) {
|
|
|
|
|
EnteredPlayerData data = enteredPlayers.get(i);
|
|
|
|
|
if (data.uuid.equals(playerUuid)) {
|
|
|
|
|
enteredPlayers.set(i, new EnteredPlayerData(data.uuid, data.x, data.y, data.z, data.pitch, data.yaw, newPos));
|
|
|
|
|
updated = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (updated && boundKeystoneName != null) {
|
|
|
|
|
Map<String, BlockPos> suitcases = SUITCASE_REGISTRY.computeIfAbsent(boundKeystoneName, k -> new HashMap<>());
|
|
|
|
|
suitcases.put(playerUuid, newPos);
|
|
|
|
|
}
|
|
|
|
|
if(updated) setChangedAndNotify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setChangedAndNotify() {
|
|
|
|
|
setChanged();
|
|
|
|
|
if (level != null && !level.isClientSide()) {
|
|
|
|
|
level.sendBlockUpdated(worldPosition, getBlockState(), getBlockState(), Block.UPDATE_ALL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|