CraftBukkit/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java

170 lines
5.6 KiB
Java

package org.bukkit.craftbukkit.block;
import net.minecraft.core.IRegistryCustom;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.PacketListenerPlayOut;
import net.minecraft.network.protocol.game.PacketPlayOutTileEntityData;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GeneratorAccess;
import net.minecraft.world.level.block.entity.TileEntity;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.TileState;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.persistence.PersistentDataContainer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CraftBlockEntityState<T extends TileEntity> extends CraftBlockState implements TileState {
private final T tileEntity;
private final T snapshot;
public CraftBlockEntityState(World world, T tileEntity) {
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
this.tileEntity = tileEntity;
// copy tile entity data:
this.snapshot = this.createSnapshot(tileEntity);
this.load(snapshot);
}
protected CraftBlockEntityState(CraftBlockEntityState<T> state, Location location) {
super(state, location);
this.tileEntity = createSnapshot(state.snapshot);
this.snapshot = tileEntity;
loadData(state.getSnapshotNBT());
}
public void refreshSnapshot() {
this.load(tileEntity);
}
private IRegistryCustom getRegistryAccess() {
GeneratorAccess worldHandle = getWorldHandle();
return (worldHandle != null) ? worldHandle.registryAccess() : MinecraftServer.getDefaultRegistryAccess();
}
private T createSnapshot(T tileEntity) {
if (tileEntity == null) {
return null;
}
NBTTagCompound nbtTagCompound = tileEntity.saveWithFullMetadata(getRegistryAccess());
T snapshot = (T) TileEntity.loadStatic(getPosition(), getHandle(), nbtTagCompound, getRegistryAccess());
return snapshot;
}
public void applyComponents(DataComponentMap datacomponentmap, DataComponentPatch datacomponentpatch) {
snapshot.applyComponents(datacomponentmap, datacomponentpatch);
load(snapshot);
}
public DataComponentMap collectComponents() {
return snapshot.collectComponents();
}
// Loads the specified data into the snapshot TileEntity.
public void loadData(NBTTagCompound nbtTagCompound) {
snapshot.loadWithComponents(nbtTagCompound, getRegistryAccess());
load(snapshot);
}
// copies the TileEntity-specific data, retains the position
private void copyData(T from, T to) {
NBTTagCompound nbtTagCompound = from.saveWithFullMetadata(getRegistryAccess());
to.loadWithComponents(nbtTagCompound, getRegistryAccess());
}
// gets the wrapped TileEntity
protected T getTileEntity() {
return tileEntity;
}
// gets the cloned TileEntity which is used to store the captured data
protected T getSnapshot() {
return snapshot;
}
// gets the current TileEntity from the world at this position
protected TileEntity getTileEntityFromWorld() {
requirePlaced();
return getWorldHandle().getBlockEntity(this.getPosition());
}
// gets the NBT data of the TileEntity represented by this block state
public NBTTagCompound getSnapshotNBT() {
// update snapshot
applyTo(snapshot);
return snapshot.saveWithFullMetadata(getRegistryAccess());
}
public NBTTagCompound getSnapshotNBTWithoutComponents() {
NBTTagCompound nbt = getSnapshotNBT();
snapshot.removeComponentsFromTag(nbt);
return nbt;
}
// copies the data of the given tile entity to this block state
protected void load(T tileEntity) {
if (tileEntity != null && tileEntity != snapshot) {
copyData(tileEntity, snapshot);
}
}
// applies the TileEntity data of this block state to the given TileEntity
protected void applyTo(T tileEntity) {
if (tileEntity != null && tileEntity != snapshot) {
copyData(snapshot, tileEntity);
}
}
protected boolean isApplicable(TileEntity tileEntity) {
return tileEntity != null && this.tileEntity.getClass() == tileEntity.getClass();
}
@Override
public boolean update(boolean force, boolean applyPhysics) {
boolean result = super.update(force, applyPhysics);
if (result && this.isPlaced()) {
TileEntity tile = getTileEntityFromWorld();
if (isApplicable(tile)) {
applyTo((T) tile);
tile.setChanged();
}
}
return result;
}
@Override
public PersistentDataContainer getPersistentDataContainer() {
return this.getSnapshot().persistentDataContainer;
}
@Nullable
public Packet<PacketListenerPlayOut> getUpdatePacket(@NotNull Location location) {
T vanillaTileEntitiy = (T) TileEntity.loadStatic(CraftLocation.toBlockPosition(location), getHandle(), getSnapshotNBT(), getRegistryAccess());
return PacketPlayOutTileEntityData.create(vanillaTileEntitiy);
}
@Override
public CraftBlockEntityState<T> copy() {
return new CraftBlockEntityState<>(this, null);
}
@Override
public CraftBlockEntityState<T> copy(Location location) {
return new CraftBlockEntityState<>(this, location);
}
}