mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Smooth Pistons (#1542)
With proper piston collision for players as well.
This commit is contained in:
parent
1199d50338
commit
8461cf76b7
24 changed files with 1911 additions and 142 deletions
|
@ -48,6 +48,7 @@ import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
|
|||
import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor;
|
||||
import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager;
|
||||
import org.geysermc.platform.spigot.command.SpigotCommandSender;
|
||||
import org.geysermc.platform.spigot.world.GeyserPistonListener;
|
||||
import org.geysermc.platform.spigot.world.GeyserSpigot1_11CraftingListener;
|
||||
import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener;
|
||||
import org.geysermc.platform.spigot.world.manager.*;
|
||||
|
@ -227,6 +228,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
|
|||
GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, this.geyserWorldManager);
|
||||
Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this);
|
||||
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(connector, this.geyserWorldManager), this);
|
||||
|
||||
if (isPre1_12) {
|
||||
// Register events needed to send all recipes to the client
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new GeyserSpigot1_11CraftingListener(connector), this);
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
package org.geysermc.platform.spigot.world;
|
||||
|
||||
import com.github.steveice10.mc.protocol.data.game.world.block.value.PistonValueType;
|
||||
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;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
import org.geysermc.connector.network.session.GeyserSession;
|
||||
import org.geysermc.connector.network.session.cache.PistonCache;
|
||||
import org.geysermc.connector.network.translators.world.block.BlockStateValues;
|
||||
import org.geysermc.connector.network.translators.world.block.entity.PistonBlockEntity;
|
||||
import org.geysermc.connector.utils.Direction;
|
||||
import org.geysermc.platform.spigot.world.manager.GeyserSpigotWorldManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GeyserPistonListener implements Listener {
|
||||
private final GeyserConnector connector;
|
||||
private final GeyserSpigotWorldManager worldManager;
|
||||
|
||||
public GeyserPistonListener(GeyserConnector connector, GeyserSpigotWorldManager worldManager) {
|
||||
this.connector = connector;
|
||||
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;
|
||||
|
||||
for (GeyserSession session : connector.getPlayers()) {
|
||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUuid());
|
||||
if (player == null || !player.getWorld().equals(world)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int dX = Math.abs(location.getBlockX() - player.getLocation().getBlockX()) >> 4;
|
||||
int dZ = Math.abs(location.getBlockZ() - player.getLocation().getBlockZ()) >> 4;
|
||||
if ((dX * dX + dZ * dZ) > session.getRenderDistance() * session.getRenderDistance()) {
|
||||
// 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();
|
||||
attachedBlocks.put(getVector(attachedLocation), worldManager.getBlockNetworkId(player, block,
|
||||
attachedLocation.getBlockX(), attachedLocation.getBlockY(), attachedLocation.getBlockZ()));
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -66,7 +66,6 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public int getBlockAt(GeyserSession session, int x, int y, int z) {
|
||||
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
|
||||
if (player == null) {
|
||||
|
@ -76,12 +75,19 @@ public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager {
|
|||
// Prevent nasty async errors if a player is loading in
|
||||
return BlockStateValues.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
Block block = player.getWorld().getBlockAt(x, y, z);
|
||||
return getBlockNetworkId(player, block, x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public int getBlockNetworkId(Player player, Block block, int x, int y, int z) {
|
||||
// Get block entity storage
|
||||
BlockStorage storage = Via.getManager().getConnectionManager().getConnectedClient(player.getUniqueId()).get(BlockStorage.class);
|
||||
Block block = player.getWorld().getBlockAt(x, y, z);
|
||||
// Black magic that gets the old block state ID
|
||||
int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
return getLegacyBlock(storage, blockId, x, y, z);
|
||||
int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF);
|
||||
return getLegacyBlock(storage, oldBlockId, x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -77,7 +77,11 @@ public class GeyserSpigotWorldManager extends GeyserWorldManager {
|
|||
return BlockStateValues.JAVA_AIR_ID;
|
||||
}
|
||||
|
||||
return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
||||
return getBlockNetworkId(bukkitPlayer, world.getBlockAt(x, y, z), x, y, z);
|
||||
}
|
||||
|
||||
public int getBlockNetworkId(Player player, Block block, int x, int y, int z) {
|
||||
return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue