/* * WorldEdit, a Minecraft world manipulation toolkit * Copyright (C) sk89q * Copyright (C) WorldEdit team and contributors * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_19_R3; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.world.block.BlockState; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.chunk.LevelChunk; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.event.block.BlockPhysicsEvent; import java.lang.ref.WeakReference; import java.util.Objects; import javax.annotation.Nullable; public class PaperweightWorldNativeAccess implements WorldNativeAccess { private static final int UPDATE = 1; private static final int NOTIFY = 2; private final PaperweightAdapter adapter; private final WeakReference world; private SideEffectSet sideEffectSet; public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference world) { this.adapter = adapter; this.world = world; } private ServerLevel getWorld() { return Objects.requireNonNull(world.get(), "The reference to the world was lost"); } @Override public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) { this.sideEffectSet = sideEffectSet; } @Override public LevelChunk getChunk(int x, int z) { return getWorld().getChunk(x, z); } @Override public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { int stateId = BlockStateIdAccess.getBlockStateId(state); return BlockStateIdAccess.isValidInternalId(stateId) ? Block.stateById(stateId) : ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); } @Override public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) { return chunk.getBlockState(position); } @Nullable @Override public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) { return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE)); } @Override public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) { return Block.updateFromNeighbourShapes(block, getWorld(), position); } @Override public BlockPos getPosition(int x, int y, int z) { return new BlockPos(x, y, z); } @Override public void updateLightingForBlock(BlockPos position) { getWorld().getChunkSource().getLightEngine().checkBlock(position); } @Override public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { return false; } @Override public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY); } } @Override public boolean isChunkTicking(LevelChunk chunk) { return chunk.getFullStatus().isOrAfter(ChunkHolder.FullChunkStatus.TICKING); } @Override public void markBlockChanged(LevelChunk chunk, BlockPos position) { if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) { getWorld().getChunkSource().blockChanged(position); } } @Override public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { ServerLevel world = getWorld(); if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { world.updateNeighborsAt(pos, oldState.getBlock()); } else { // When we don't want events, manually run the physics without them. Block block = oldState.getBlock(); fireNeighborChanged(pos, world, block, pos.west()); fireNeighborChanged(pos, world, block, pos.east()); fireNeighborChanged(pos, world, block, pos.below()); fireNeighborChanged(pos, world, block, pos.above()); fireNeighborChanged(pos, world, block, pos.north()); fireNeighborChanged(pos, world, block, pos.south()); } if (newState.hasAnalogOutputSignal()) { world.updateNeighbourForOutputSignal(pos, newState.getBlock()); } } // Not sure why neighborChanged is deprecated @SuppressWarnings("deprecation") private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { world.getBlockState(neighborPos).neighborChanged(world, neighborPos, block, pos, false); } @Override public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { ServerLevel world = getWorld(); // a == updateNeighbors // b == updateDiagonalNeighbors oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { CraftWorld craftWorld = world.getWorld(); BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState)); world.getCraftServer().getPluginManager().callEvent(event); if (event.isCancelled()) { return; } } newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit); newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); } @Override public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) { getWorld().onBlockStateChange(pos, oldState, newState); } @Override public void flush() { } }