2021-09-10 01:20:25 +00:00
|
|
|
/*
|
2022-01-01 19:03:05 +00:00
|
|
|
* Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
|
2021-09-10 01:20:25 +00:00
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*
|
|
|
|
* @author GeyserMC
|
|
|
|
* @link https://github.com/GeyserMC/Geyser
|
|
|
|
*/
|
|
|
|
|
2021-11-20 21:34:30 +00:00
|
|
|
package org.geysermc.geyser.platform.spigot.world;
|
2021-09-10 01:20:25 +00:00
|
|
|
|
2021-11-13 03:44:15 +00:00
|
|
|
import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType;
|
2021-09-10 01:20:25 +00:00
|
|
|
import com.nukkitx.math.vector.Vector3i;
|
|
|
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|
|
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.World;
|
|
|
|
import org.bukkit.block.Block;
|
|
|
|
import org.bukkit.entity.Player;
|
|
|
|
import org.bukkit.event.EventHandler;
|
|
|
|
import org.bukkit.event.EventPriority;
|
|
|
|
import org.bukkit.event.Listener;
|
|
|
|
import org.bukkit.event.block.BlockPistonEvent;
|
|
|
|
import org.bukkit.event.block.BlockPistonExtendEvent;
|
|
|
|
import org.bukkit.event.block.BlockPistonRetractEvent;
|
2021-11-20 21:34:30 +00:00
|
|
|
import org.geysermc.geyser.GeyserImpl;
|
2021-11-22 19:52:26 +00:00
|
|
|
import org.geysermc.geyser.session.GeyserSession;
|
2021-11-20 23:29:46 +00:00
|
|
|
import org.geysermc.geyser.session.cache.PistonCache;
|
|
|
|
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
|
|
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
|
|
|
import org.geysermc.geyser.level.physics.Direction;
|
2021-11-20 21:34:30 +00:00
|
|
|
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
2021-09-10 01:20:25 +00:00
|
|
|
|
|
|
|
import java.util.List;
|
2021-11-12 14:02:14 +00:00
|
|
|
import java.util.Map;
|
|
|
|
import java.util.UUID;
|
2021-09-10 01:20:25 +00:00
|
|
|
|
|
|
|
public class GeyserPistonListener implements Listener {
|
2021-11-20 21:34:30 +00:00
|
|
|
private final GeyserImpl geyser;
|
2021-09-10 01:20:25 +00:00
|
|
|
private final GeyserSpigotWorldManager worldManager;
|
|
|
|
|
2021-11-20 21:34:30 +00:00
|
|
|
public GeyserPistonListener(GeyserImpl geyser, GeyserSpigotWorldManager worldManager) {
|
|
|
|
this.geyser = geyser;
|
2021-09-10 01:20:25 +00:00
|
|
|
this.worldManager = worldManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The handlers' parent class cannot be registered
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
|
|
public void onPistonExtend(BlockPistonExtendEvent event) {
|
|
|
|
onPistonAction(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
|
|
public void onPistonRetract(BlockPistonRetractEvent event) {
|
|
|
|
onPistonAction(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onPistonAction(BlockPistonEvent event) {
|
|
|
|
if (event.isCancelled()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
World world = event.getBlock().getWorld();
|
|
|
|
boolean isExtend = event instanceof BlockPistonExtendEvent;
|
|
|
|
|
|
|
|
Location location = event.getBlock().getLocation();
|
|
|
|
Vector3i position = getVector(location);
|
|
|
|
PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
|
|
|
|
boolean sticky = event.isSticky();
|
|
|
|
|
|
|
|
Object2IntMap<Vector3i> attachedBlocks = new Object2IntOpenHashMap<>();
|
|
|
|
boolean blocksFilled = false;
|
|
|
|
|
2021-11-22 19:52:26 +00:00
|
|
|
for (Map.Entry<UUID, GeyserSession> entry : geyser.getSessionManager().getSessions().entrySet()) {
|
2021-11-12 14:02:14 +00:00
|
|
|
Player player = Bukkit.getPlayer(entry.getKey());
|
2021-09-10 01:20:25 +00:00
|
|
|
if (player == null || !player.getWorld().equals(world)) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-11-22 19:52:26 +00:00
|
|
|
GeyserSession session = entry.getValue();
|
2021-09-10 01:20:25 +00:00
|
|
|
|
|
|
|
int dX = Math.abs(location.getBlockX() - player.getLocation().getBlockX()) >> 4;
|
|
|
|
int dZ = Math.abs(location.getBlockZ() - player.getLocation().getBlockZ()) >> 4;
|
2022-01-16 01:32:45 +00:00
|
|
|
if ((dX * dX + dZ * dZ) > session.getServerRenderDistance() * session.getServerRenderDistance()) {
|
2021-09-10 01:20:25 +00:00
|
|
|
// Ignore pistons outside the player's render distance
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trying to grab the blocks from the world like other platforms would result in the moving piston block
|
|
|
|
// being returned instead.
|
|
|
|
if (!blocksFilled) {
|
|
|
|
// Blocks currently require a player for 1.12, so let's just leech off one player to get all blocks
|
|
|
|
// and call it a day for the rest of the sessions (mostly to save on execution time)
|
|
|
|
List<Block> blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
|
|
|
|
for (Block block : blocks) {
|
|
|
|
Location attachedLocation = block.getLocation();
|
2021-11-13 01:36:01 +00:00
|
|
|
int blockId = worldManager.getBlockNetworkId(player, block,
|
|
|
|
attachedLocation.getBlockX(), attachedLocation.getBlockY(), attachedLocation.getBlockZ());
|
|
|
|
// Ignore blocks that will be destroyed
|
|
|
|
if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) {
|
|
|
|
attachedBlocks.put(getVector(attachedLocation), blockId);
|
|
|
|
}
|
2021-09-10 01:20:25 +00:00
|
|
|
}
|
|
|
|
blocksFilled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int pistonBlockId = worldManager.getBlockNetworkId(player, event.getBlock(), location.getBlockX(), location.getBlockY(), location.getBlockZ());
|
|
|
|
// event.getDirection() is unreliable
|
|
|
|
Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId);
|
|
|
|
|
|
|
|
session.executeInEventLoop(() -> {
|
|
|
|
PistonCache pistonCache = session.getPistonCache();
|
|
|
|
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos ->
|
|
|
|
new PistonBlockEntity(session, position, orientation, sticky, !isExtend));
|
|
|
|
blockEntity.setAction(type, attachedBlocks);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Vector3i getVector(Location location) {
|
|
|
|
return Vector3i.from(location.getX(), location.getY(), location.getZ());
|
|
|
|
}
|
|
|
|
}
|