Skip to content

Commit 841cb68

Browse files
authored
Merge branch 'master' into feature/1.21.20
2 parents 4eb3438 + ca0f377 commit 841cb68

File tree

8 files changed

+155
-20
lines changed

8 files changed

+155
-20
lines changed

README.md

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,15 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
1414

1515
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
1616

17-
### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.20 and Minecraft Java 1.21
17+
## Supported Versions
18+
Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.20 and Minecraft Java Server 1.21. For more info please see [here](https://geysermc.org/wiki/geyser/supported-versions/).
1819

1920
## Setting Up
20-
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
21-
22-
[![YouTube Video](https://img.youtube.com/vi/U7dZZ8w7Gi4/0.jpg)](https://www.youtube.com/watch?v=U7dZZ8w7Gi4)
21+
Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser.
2322

2423
## Links:
2524
- Website: https://geysermc.org
26-
- Docs: https://wiki.geysermc.org/geyser/
25+
- Docs: https://geysermc.org/wiki/geyser/
2726
- Download: https://geysermc.org/download
2827
- Discord: https://discord.gg/geysermc
2928
- Donate: https://opencollective.com/geysermc
@@ -34,7 +33,7 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge
3433
- Some Entity Flags
3534

3635
## What can't be fixed
37-
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page.
36+
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://geysermc.org/wiki/geyser/current-limitations/) page.
3837

3938
## Compiling
4039
1. Clone the repo to your computer
@@ -47,7 +46,7 @@ you're interested in helping out with Geyser.
4746

4847
## Libraries Used:
4948
- [Adventure Text Library](https://github.com/KyoriPowered/adventure)
50-
- [NukkitX Bedrock Protocol Library](https://github.com/NukkitX/Protocol)
51-
- [Steveice10's Java Protocol Library](https://github.com/Steveice10/MCProtocolLib)
49+
- [CloudburstMC Bedrock Protocol Library](https://github.com/CloudburstMC/Protocol)
50+
- [GeyserMC's Java Protocol Library](https://github.com/GeyserMC/MCProtocolLib)
5251
- [TerminalConsoleAppender](https://github.com/Minecrell/TerminalConsoleAppender)
5352
- [Simple Logging Facade for Java (slf4j)](https://github.com/qos-ch/slf4j)

bootstrap/mod/build.gradle.kts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ afterEvaluate {
1616
dependencies {
1717
api(projects.core)
1818
compileOnly(libs.mixin)
19+
compileOnly(libs.mixinextras)
1920

2021
// Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
2122
compileOnly(libs.fabric.loader)
22-
}
23+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
* Copyright (c) 2024 GeyserMC. http://geysermc.org
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
* THE SOFTWARE.
21+
*
22+
* @author GeyserMC
23+
* @link https://github.com/GeyserMC/Geyser
24+
*/
25+
26+
package org.geysermc.geyser.platform.mod.mixin.server;
27+
28+
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
29+
import com.llamalad7.mixinextras.sugar.Share;
30+
import com.llamalad7.mixinextras.sugar.ref.LocalRef;
31+
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
32+
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
33+
import net.minecraft.core.BlockPos;
34+
import net.minecraft.core.Direction;
35+
import net.minecraft.world.entity.player.Player;
36+
import net.minecraft.world.level.Level;
37+
import net.minecraft.world.level.block.Block;
38+
import net.minecraft.world.level.block.piston.PistonBaseBlock;
39+
import net.minecraft.world.level.block.state.BlockState;
40+
import org.cloudburstmc.math.vector.Vector3i;
41+
import org.geysermc.geyser.GeyserImpl;
42+
import org.geysermc.geyser.session.GeyserSession;
43+
import org.geysermc.geyser.session.cache.PistonCache;
44+
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
45+
import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
46+
import org.spongepowered.asm.mixin.Final;
47+
import org.spongepowered.asm.mixin.Mixin;
48+
import org.spongepowered.asm.mixin.Shadow;
49+
import org.spongepowered.asm.mixin.Unique;
50+
import org.spongepowered.asm.mixin.injection.At;
51+
import org.spongepowered.asm.mixin.injection.Inject;
52+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
53+
54+
import java.util.HashMap;
55+
import java.util.Map;
56+
import java.util.UUID;
57+
58+
@Mixin(PistonBaseBlock.class)
59+
public class PistonBaseBlockMixin {
60+
61+
@Shadow
62+
@Final
63+
private boolean isSticky;
64+
65+
@ModifyExpressionValue(method = "moveBlocks",
66+
at = @At(value = "INVOKE", target = "Lcom/google/common/collect/Maps;newHashMap()Ljava/util/HashMap;")
67+
)
68+
private HashMap<BlockPos, BlockState> geyser$onMapCreate(HashMap<BlockPos, BlockState> original, @Share("pushBlocks") LocalRef<Map<BlockPos, BlockState>> localRef) {
69+
localRef.set(original);
70+
return original;
71+
}
72+
73+
@Inject(method = "moveBlocks",
74+
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/piston/PistonStructureResolver;getToDestroy()Ljava/util/List;")
75+
)
76+
private void geyser$onBlocksMove(Level level, BlockPos blockPos, Direction direction, boolean isExtending, CallbackInfoReturnable<Boolean> cir, @Share("pushBlocks") LocalRef<Map<BlockPos, BlockState>> localRef) {
77+
PistonValueType type = isExtending ? PistonValueType.PUSHING : PistonValueType.PULLING;
78+
boolean sticky = this.isSticky;
79+
80+
Object2ObjectMap<Vector3i, org.geysermc.geyser.level.block.type.BlockState> attachedBlocks = new Object2ObjectArrayMap<>();
81+
boolean blocksFilled = false;
82+
83+
for (Map.Entry<UUID, GeyserSession> entry : GeyserImpl.getInstance().getSessionManager().getSessions().entrySet()) {
84+
Player player = level.getPlayerByUUID(entry.getKey());
85+
//noinspection resource
86+
if (player == null || !player.level().equals(level)) {
87+
continue;
88+
}
89+
GeyserSession session = entry.getValue();
90+
91+
int dX = Math.abs(blockPos.getX() - player.getBlockX()) >> 4;
92+
int dZ = Math.abs(blockPos.getZ() - player.getBlockZ()) >> 4;
93+
if ((dX * dX + dZ * dZ) > session.getServerRenderDistance() * session.getServerRenderDistance()) {
94+
// Ignore pistons outside the player's render distance
95+
continue;
96+
}
97+
98+
// Trying to grab the blocks from the world like other platforms would result in the moving piston block
99+
// being returned instead.
100+
if (!blocksFilled) {
101+
Map<BlockPos, net.minecraft.world.level.block.state.BlockState> blocks = localRef.get();
102+
for (Map.Entry<BlockPos, BlockState> blockStateEntry : blocks.entrySet()) {
103+
int blockStateId = Block.BLOCK_STATE_REGISTRY.getId(blockStateEntry.getValue());
104+
org.geysermc.geyser.level.block.type.BlockState state = org.geysermc.geyser.level.block.type.BlockState.of(blockStateId);
105+
attachedBlocks.put(geyser$fromBlockPos(blockStateEntry.getKey()), state);
106+
}
107+
blocksFilled = true;
108+
}
109+
110+
org.geysermc.geyser.level.physics.Direction orientation = org.geysermc.geyser.level.physics.Direction.VALUES[direction.ordinal()];
111+
112+
Vector3i position = geyser$fromBlockPos(blockPos);
113+
session.executeInEventLoop(() -> {
114+
PistonCache pistonCache = session.getPistonCache();
115+
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos ->
116+
new PistonBlockEntity(session, position, orientation, sticky, !isExtending));
117+
blockEntity.setAction(type, attachedBlocks);
118+
});
119+
}
120+
}
121+
122+
@Unique
123+
private static Vector3i geyser$fromBlockPos(BlockPos pos) {
124+
return Vector3i.from(pos.getX(), pos.getY(), pos.getZ());
125+
}
126+
127+
}

bootstrap/mod/src/main/resources/geyser.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"compatibilityLevel": "JAVA_17",
66
"mixins": [
77
"server.BlockPlaceMixin",
8+
"server.PistonBaseBlockMixin",
89
"server.ServerConnectionListenerMixin"
910
],
1011
"server": [

core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ private static void registerBedrockBlocks() {
131131
NbtMapBuilder builder = vanillaBlockStates.get(i).toBuilder();
132132
builder.remove("version"); // Remove all nbt tags which are not needed for differentiating states
133133
builder.remove("name_hash"); // Quick workaround - was added in 1.19.20
134-
builder.remove("network_id"); // Added in 1.19.80 - ????
134+
builder.remove("network_id"); // Added in 1.19.80
135135
builder.remove("block_id"); // Added in 1.20.60
136136
//noinspection UnstableApiUsage
137137
builder.putCompound("states", statesInterner.intern((NbtMap) builder.remove("states")));

core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@
3737
import org.cloudburstmc.nbt.NbtMap;
3838
import org.cloudburstmc.nbt.NbtMapBuilder;
3939
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
40-
import org.geysermc.geyser.api.util.PlatformType;
4140
import org.geysermc.geyser.level.block.BlockStateValues;
4241
import org.geysermc.geyser.level.block.Blocks;
4342
import org.geysermc.geyser.level.block.property.Properties;
@@ -230,8 +229,8 @@ private void removePistonHead() {
230229
BlockState state = session.getGeyser().getWorldManager().blockAt(session, blockInFront);
231230
if (state.is(Blocks.PISTON_HEAD)) {
232231
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
233-
} else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) {
234-
// Spigot removes the piston head from the cache, but we need to send the block update ourselves
232+
} else if ((session.getGeyser().getWorldManager().hasOwnChunkCache() || session.getErosionHandler().isActive()) && state.is(Blocks.AIR)) {
233+
// The platform removes the piston head from the cache, but we need to send the block update ourselves
235234
ChunkUtils.updateBlock(session, Block.JAVA_AIR_ID, blockInFront);
236235
}
237236
}

core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,24 +82,30 @@ public void translate(GeyserSession session, ClientboundBlockEventPacket packet)
8282
Direction direction = Direction.fromPistonValue(pistonValue.getDirection());
8383
PistonCache pistonCache = session.getPistonCache();
8484

85-
if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) {
86-
// Mostly handled in the GeyserPistonEvents class
87-
// Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
88-
// See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch
85+
if (session.getGeyser().getWorldManager().hasOwnChunkCache() || session.getErosionHandler().isActive()) {
86+
// Mostly handled in the GeyserPistonEvents class (Spigot) / the PistonBlockBaseMixin (Mod platforms)
87+
// However, the retracting event is not fully covered. (Spigot)
88+
// Mod platforms only handle pistons moving blocks; not the retracting of pistons.
8989
if (action == PistonValueType.PULLING || action == PistonValueType.CANCELLED_MID_PUSH) {
9090
BlockState pistonBlock = session.getGeyser().getWorldManager().blockAt(session, position);
91-
if (!isSticky(pistonBlock)) {
91+
92+
// Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1
93+
// See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch
94+
boolean isSticky = isSticky(pistonBlock);
95+
if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT && !isSticky) {
9296
return;
9397
}
94-
if (action != PistonValueType.CANCELLED_MID_PUSH) {
98+
99+
// Only sticky pistons that don't pull any blocks are affected
100+
if (action != PistonValueType.CANCELLED_MID_PUSH && isSticky) {
95101
Vector3i blockInFrontPos = position.add(direction.getUnitVector());
96102
int blockInFront = session.getGeyser().getWorldManager().getBlockAt(session, blockInFrontPos);
97103
if (blockInFront != Block.JAVA_AIR_ID) {
98104
// Piston pulled something
99105
return;
100106
}
101107
}
102-
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> new PistonBlockEntity(session, pos, direction, true, true));
108+
PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> new PistonBlockEntity(session, pos, direction, isSticky, true));
103109
if (blockEntity.getAction() != action) {
104110
blockEntity.setAction(action, Object2ObjectMaps.emptyMap());
105111
}

gradle/libs.versions.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ fabric-api = "0.100.1+1.21"
3333
fabric-permissions = "0.2-SNAPSHOT"
3434
neoforge-minecraft = "21.0.0-beta"
3535
mixin = "0.8.5"
36+
mixinextras = "0.3.5"
3637
minecraft = "1.21"
3738

3839
# plugin versions
@@ -89,6 +90,7 @@ folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" }
8990
paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" }
9091

9192
mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" }
93+
mixinextras = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinextras" }
9294

9395
minecraft = { group = "com.mojang", name = "minecraft", version.ref = "minecraft" }
9496

0 commit comments

Comments
 (0)