mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Initial attempt: Mod piston listener
This commit is contained in:
parent
797d282435
commit
b40df1e346
7 changed files with 135 additions and 2 deletions
|
|
@ -16,7 +16,8 @@ afterEvaluate {
|
||||||
dependencies {
|
dependencies {
|
||||||
api(projects.core)
|
api(projects.core)
|
||||||
compileOnly(libs.mixin)
|
compileOnly(libs.mixin)
|
||||||
|
compileOnly(libs.mixinextras)
|
||||||
|
|
||||||
// Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
|
// Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
|
||||||
compileOnly(libs.fabric.loader)
|
compileOnly(libs.fabric.loader)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 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.geyser.platform.mod.mixin.server;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||||
|
import com.llamalad7.mixinextras.sugar.Share;
|
||||||
|
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.piston.PistonBaseBlock;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import org.cloudburstmc.math.vector.Vector3i;
|
||||||
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
import org.geysermc.geyser.session.cache.PistonCache;
|
||||||
|
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Mixin(PistonBaseBlock.class)
|
||||||
|
public class PistonBaseBlockMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private boolean isSticky;
|
||||||
|
|
||||||
|
@ModifyExpressionValue(method = "moveBlocks",
|
||||||
|
at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;")
|
||||||
|
)
|
||||||
|
private HashMap<BlockPos, BlockState> geyser$onMapCreate(HashMap<BlockPos, BlockState> original, @Share("pushBlocks") LocalRef<Map<BlockPos, BlockState>> localRef) {
|
||||||
|
localRef.set(original);
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "moveBlocks",
|
||||||
|
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/piston/PistonStructureResolver;getToDestroy()Ljava/util/List;")
|
||||||
|
)
|
||||||
|
private void geyser$onBlocksMove(Level level, BlockPos blockPos, Direction direction, boolean isExtending, CallbackInfoReturnable<Boolean> cir, @Share("pushBlocks") LocalRef<Map<BlockPos, BlockState>> localRef) {
|
||||||
|
PistonValueType type = isExtending ? PistonValueType.PUSHING : PistonValueType.PULLING;
|
||||||
|
boolean sticky = this.isSticky;
|
||||||
|
|
||||||
|
Object2ObjectMap<Vector3i, org.geysermc.geyser.level.block.type.BlockState> attachedBlocks = new Object2ObjectArrayMap<>();
|
||||||
|
boolean blocksFilled = false;
|
||||||
|
|
||||||
|
for (Map.Entry<UUID, GeyserSession> entry : GeyserImpl.getInstance().getSessionManager().getSessions().entrySet()) {
|
||||||
|
Player player = level.getPlayerByUUID(entry.getKey());
|
||||||
|
if (player == null || !player.level().equals(level)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
GeyserSession session = entry.getValue();
|
||||||
|
|
||||||
|
int dX = Math.abs(blockPos.getX() - player.getBlockX()) >> 4;
|
||||||
|
int dZ = Math.abs(blockPos.getZ() - player.getBlockZ()) >> 4;
|
||||||
|
if ((dX * dX + dZ * dZ) > session.getServerRenderDistance() * session.getServerRenderDistance()) {
|
||||||
|
// 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) {
|
||||||
|
Map<BlockPos, net.minecraft.world.level.block.state.BlockState> blocks = localRef.get();
|
||||||
|
for (Map.Entry<BlockPos, BlockState> blockStateEntry : blocks.entrySet()) {
|
||||||
|
int blockStateId = Block.BLOCK_STATE_REGISTRY.getId(blockStateEntry.getValue());
|
||||||
|
org.geysermc.geyser.level.block.type.BlockState state = org.geysermc.geyser.level.block.type.BlockState.of(blockStateId);
|
||||||
|
attachedBlocks.put(geyser$fromBlockPos(blockStateEntry.getKey()), state);
|
||||||
|
}
|
||||||
|
blocksFilled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
org.geysermc.geyser.level.physics.Direction orientation = org.geysermc.geyser.level.physics.Direction.VALUES[direction.ordinal()];
|
||||||
|
|
||||||
|
Vector3i position = geyser$fromBlockPos(blockPos);
|
||||||
|
session.executeInEventLoop(() -> {
|
||||||
|
PistonCache pistonCache = session.getPistonCache();
|
||||||
|
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos ->
|
||||||
|
new PistonBlockEntity(session, position, orientation, sticky, !isExtending));
|
||||||
|
blockEntity.setAction(type, attachedBlocks);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static Vector3i geyser$fromBlockPos(BlockPos pos) {
|
||||||
|
return Vector3i.from(pos.getX(), pos.getY(), pos.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
"compatibilityLevel": "JAVA_17",
|
"compatibilityLevel": "JAVA_17",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"server.BlockPlaceMixin",
|
"server.BlockPlaceMixin",
|
||||||
|
"server.PistonBaseBlockMixin",
|
||||||
"server.ServerConnectionListenerMixin"
|
"server.ServerConnectionListenerMixin"
|
||||||
],
|
],
|
||||||
"server": [
|
"server": [
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ public final class BlockRegistryPopulator {
|
||||||
NbtMapBuilder builder = vanillaBlockStates.get(i).toBuilder();
|
NbtMapBuilder builder = vanillaBlockStates.get(i).toBuilder();
|
||||||
builder.remove("version"); // Remove all nbt tags which are not needed for differentiating states
|
builder.remove("version"); // Remove all nbt tags which are not needed for differentiating states
|
||||||
builder.remove("name_hash"); // Quick workaround - was added in 1.19.20
|
builder.remove("name_hash"); // Quick workaround - was added in 1.19.20
|
||||||
builder.remove("network_id"); // Added in 1.19.80 - ????
|
builder.remove("network_id"); // Added in 1.19.80
|
||||||
builder.remove("block_id"); // Added in 1.20.60
|
builder.remove("block_id"); // Added in 1.20.60
|
||||||
//noinspection UnstableApiUsage
|
//noinspection UnstableApiUsage
|
||||||
builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states")));
|
builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states")));
|
||||||
|
|
@ -162,6 +162,7 @@ public final class BlockRegistryPopulator {
|
||||||
// as we no longer send a block palette
|
// as we no longer send a block palette
|
||||||
Object2ObjectMap<NbtMap, GeyserBedrockBlock> blockStateOrderedMap = new Object2ObjectOpenHashMap<>(blockStates.size());
|
Object2ObjectMap<NbtMap, GeyserBedrockBlock> blockStateOrderedMap = new Object2ObjectOpenHashMap<>(blockStates.size());
|
||||||
GeyserBedrockBlock[] bedrockRuntimeMap = new GeyserBedrockBlock[blockStates.size()];
|
GeyserBedrockBlock[] bedrockRuntimeMap = new GeyserBedrockBlock[blockStates.size()];
|
||||||
|
GeyserImpl.getInstance().getLogger().info(blockStates.size() + " block states found");
|
||||||
for (int i = 0; i < blockStates.size(); i++) {
|
for (int i = 0; i < blockStates.size(); i++) {
|
||||||
NbtMap tag = blockStates.get(i);
|
NbtMap tag = blockStates.get(i);
|
||||||
if (blockStateOrderedMap.containsKey(tag)) {
|
if (blockStateOrderedMap.containsKey(tag)) {
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ public class PistonBlockEntity {
|
||||||
if (state.is(Blocks.PISTON_HEAD)) {
|
if (state.is(Blocks.PISTON_HEAD)) {
|
||||||
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
|
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
|
||||||
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) {
|
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) {
|
||||||
|
// TODO pistons fabric????
|
||||||
// Spigot removes the piston head from the cache, but we need to send the block update ourselves
|
// Spigot removes the piston head from the cache, but we need to send the block update ourselves
|
||||||
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
|
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ public class JavaBlockEventTranslator extends PacketTranslator<ClientboundBlockE
|
||||||
Direction direction = Direction.fromPistonValue(pistonValue.getDirection());
|
Direction direction = Direction.fromPistonValue(pistonValue.getDirection());
|
||||||
PistonCache pistonCache = session.getPistonCache();
|
PistonCache pistonCache = session.getPistonCache();
|
||||||
|
|
||||||
|
// TODO pistons modded
|
||||||
if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) {
|
if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) {
|
||||||
// Mostly handled in the GeyserPistonEvents class
|
// Mostly handled in the GeyserPistonEvents class
|
||||||
// Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
|
// Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ fabric-api = "0.100.1+1.21"
|
||||||
fabric-permissions = "0.2-SNAPSHOT"
|
fabric-permissions = "0.2-SNAPSHOT"
|
||||||
neoforge-minecraft = "21.0.0-beta"
|
neoforge-minecraft = "21.0.0-beta"
|
||||||
mixin = "0.8.5"
|
mixin = "0.8.5"
|
||||||
|
mixinextras = "0.3.5"
|
||||||
minecraft = "1.21"
|
minecraft = "1.21"
|
||||||
|
|
||||||
# plugin versions
|
# plugin versions
|
||||||
|
|
@ -89,6 +90,7 @@ folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" }
|
||||||
paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" }
|
paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" }
|
||||||
|
|
||||||
mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" }
|
mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" }
|
||||||
|
mixinextras = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinextras" }
|
||||||
|
|
||||||
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue