-
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
330 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="http://maven.apache.org/POM/4.0.0" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>dev.cerus.maps</groupId> | ||
<artifactId>parent</artifactId> | ||
<version>3.5.1</version> | ||
</parent> | ||
|
||
<artifactId>bukkit-19_R3</artifactId> | ||
|
||
<properties> | ||
<maven.compiler.source>17</maven.compiler.source> | ||
<maven.compiler.target>17</maven.compiler.target> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>dev.cerus.maps</groupId> | ||
<artifactId>common</artifactId> | ||
<version>${parent.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.bukkit</groupId> | ||
<artifactId>craftbukkit</artifactId> | ||
<version>1.19.4-R0.1-SNAPSHOT</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
</project> |
112 changes: 112 additions & 0 deletions
112
bukkit-19_R3/src/main/java/dev/cerus/maps/version/PacketHandler19R3.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package dev.cerus.maps.version; | ||
|
||
import dev.cerus.maps.api.version.PacketListener; | ||
import io.netty.channel.ChannelDuplexHandler; | ||
import io.netty.channel.ChannelHandlerContext; | ||
import java.lang.reflect.Field; | ||
import java.util.Arrays; | ||
import net.minecraft.network.protocol.game.ClientboundBlockChangedAckPacket; | ||
import net.minecraft.network.protocol.game.PacketPlayInBlockDig; | ||
import net.minecraft.network.protocol.game.PacketPlayInBlockPlace; | ||
import net.minecraft.network.protocol.game.PacketPlayInUseEntity; | ||
import net.minecraft.network.protocol.game.PacketPlayInUseItem; | ||
import net.minecraft.world.EnumHand; | ||
import net.minecraft.world.phys.MovingObjectPositionBlock; | ||
import org.bukkit.Bukkit; | ||
import org.bukkit.Location; | ||
import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; | ||
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; | ||
import org.bukkit.entity.Player; | ||
import org.bukkit.plugin.java.JavaPlugin; | ||
|
||
public class PacketHandler19R3 extends ChannelDuplexHandler { | ||
|
||
private static final Field actionField; | ||
private static final Object attackAction; | ||
|
||
static { | ||
try { | ||
actionField = PacketPlayInUseEntity.class.getDeclaredField("b"); | ||
actionField.setAccessible(true); | ||
final Field attackActionField = PacketPlayInUseEntity.class.getDeclaredField("d"); | ||
attackActionField.setAccessible(true); | ||
attackAction = attackActionField.get(null); | ||
} catch (final NoSuchFieldException | IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private final Player player; | ||
private final PacketListener listener; | ||
private final JavaPlugin plugin; | ||
|
||
public PacketHandler19R3(final Player player, final PacketListener listener, final JavaPlugin plugin) { | ||
this.player = player; | ||
this.listener = listener; | ||
this.plugin = plugin; | ||
} | ||
|
||
private static Object getAction(final PacketPlayInUseEntity packet) { | ||
try { | ||
return actionField.get(packet); | ||
} catch (final IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
private static EnumHand getHand(final PacketPlayInUseEntity packet) { | ||
try { | ||
final Object action = getAction(packet); | ||
final Field handField = Arrays.stream(action.getClass().getDeclaredFields()) | ||
.filter(field -> field.getType() == EnumHand.class) | ||
.findAny().orElse(null); | ||
if (handField == null) { | ||
return null; | ||
} | ||
handField.setAccessible(true); | ||
return (EnumHand) handField.get(action); | ||
} catch (final IllegalAccessException e) { | ||
throw new RuntimeException(e); | ||
} | ||
} | ||
|
||
@Override | ||
public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception { | ||
if ((((msg instanceof PacketPlayInUseItem useItem && useItem.a() != EnumHand.b) || msg instanceof PacketPlayInBlockPlace) | ||
&& this.listener.handlePlayerRightClick(this.player)) || (msg instanceof PacketPlayInUseEntity useEntity && getHand(useEntity) != EnumHand.b | ||
&& (getAction(useEntity) == attackAction ? this.listener.handlePlayerLeftClick(this.player) | ||
: this.listener.handlePlayerRightClick(this.player))) || (msg instanceof PacketPlayInBlockDig | ||
&& this.listener.handlePlayerLeftClick(this.player))) { | ||
if (msg instanceof PacketPlayInBlockDig dig) { | ||
// To prevent de-syncs we need to tell the client that the block has not changed | ||
final Location location = new Location( | ||
this.player.getWorld(), | ||
dig.a().u(), | ||
dig.a().v(), | ||
dig.a().w() | ||
); | ||
// If we don't acknowledge the client's block change it won't accept further block change packets | ||
((CraftPlayer) this.player).getHandle().b.a(new ClientboundBlockChangedAckPacket(dig.e())); | ||
Bukkit.getScheduler().runTask(this.plugin, () -> this.player.sendBlockChange(location, location.getBlock().getBlockData())); | ||
} | ||
if (msg instanceof PacketPlayInUseItem useItem) { | ||
// To prevent de-syncs we need to tell the client that the block has not changed | ||
final MovingObjectPositionBlock pos = useItem.c(); | ||
if (pos != null && pos.a() != null) { | ||
final Location location = new Location( | ||
this.player.getWorld(), | ||
pos.a().u(), | ||
pos.a().v(), | ||
pos.a().w() | ||
).getBlock().getRelative(CraftBlock.notchToBlockFace(pos.b())).getLocation(); | ||
// If we don't acknowledge the client's block change it won't accept further block change packets | ||
((CraftPlayer) this.player).getHandle().b.a(new ClientboundBlockChangedAckPacket(useItem.d())); | ||
Bukkit.getScheduler().runTask(this.plugin, () -> this.player.sendBlockChange(location, location.getBlock().getBlockData())); | ||
} | ||
} | ||
return; | ||
} | ||
super.channelRead(ctx, msg); | ||
} | ||
|
||
} |
159 changes: 159 additions & 0 deletions
159
bukkit-19_R3/src/main/java/dev/cerus/maps/version/VersionAdapter19R3.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package dev.cerus.maps.version; | ||
|
||
import dev.cerus.maps.api.ClientsideMap; | ||
import dev.cerus.maps.api.Frame; | ||
import dev.cerus.maps.api.version.PacketListener; | ||
import dev.cerus.maps.api.version.VersionAdapter; | ||
import java.lang.reflect.Field; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.UUID; | ||
import java.util.logging.Level; | ||
import java.util.stream.Collectors; | ||
import net.minecraft.network.NetworkManager; | ||
import net.minecraft.network.chat.IChatBaseComponent; | ||
import net.minecraft.network.protocol.Packet; | ||
import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy; | ||
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; | ||
import net.minecraft.network.protocol.game.PacketPlayOutMap; | ||
import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity; | ||
import net.minecraft.network.syncher.DataWatcher; | ||
import net.minecraft.network.syncher.DataWatcherRegistry; | ||
import net.minecraft.server.network.PlayerConnection; | ||
import net.minecraft.world.entity.EntityTypes; | ||
import net.minecraft.world.level.saveddata.maps.MapIcon; | ||
import net.minecraft.world.level.saveddata.maps.WorldMap; | ||
import net.minecraft.world.phys.Vec3D; | ||
import org.bukkit.Material; | ||
import org.bukkit.block.BlockFace; | ||
import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; | ||
import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; | ||
import org.bukkit.entity.Player; | ||
import org.bukkit.inventory.meta.MapMeta; | ||
import org.bukkit.plugin.java.JavaPlugin; | ||
|
||
public class VersionAdapter19R3 implements VersionAdapter { | ||
|
||
private Field netManField; | ||
|
||
@Override | ||
public Object makeMapPacket(final boolean ignoreBounds, final ClientsideMap map) { | ||
final int x = ignoreBounds ? 0 : map.getX(); | ||
final int y = ignoreBounds ? 0 : map.getY(); | ||
final int w = ignoreBounds ? 128 : Math.max(1, map.getWidth()); | ||
final int h = ignoreBounds ? 128 : Math.max(1, map.getHeight()); | ||
|
||
final byte[] data; | ||
if (ignoreBounds) { | ||
data = map.getData(); | ||
} else { | ||
data = new byte[w * h]; | ||
for (int xx = 0; xx < w; ++xx) { | ||
for (int yy = 0; yy < h; ++yy) { | ||
data[xx + yy * w] = map.getData()[x + xx + (y + yy) * 128]; | ||
} | ||
} | ||
} | ||
|
||
return new PacketPlayOutMap( | ||
map.getId(), | ||
(byte) 0, | ||
true, | ||
map.getMarkers().stream() | ||
.map(cursor -> new MapIcon( | ||
MapIcon.Type.a(cursor.getType()), | ||
cursor.getCompressedX(), | ||
cursor.getCompressedY(), | ||
cursor.getDirection(), | ||
!cursor.hasCaption() ? null : IChatBaseComponent.ChatSerializer.a(cursor.getCaptionString()) | ||
)) | ||
.collect(Collectors.toList()), | ||
new WorldMap.b( | ||
x, | ||
y, | ||
w, | ||
h, | ||
data | ||
) | ||
); | ||
} | ||
|
||
@Override | ||
public Object makeFramePacket(final int frameId, final boolean visible, final ClientsideMap map) { | ||
final org.bukkit.inventory.ItemStack mapItem = new org.bukkit.inventory.ItemStack(Material.FILLED_MAP, 1); | ||
final MapMeta mapMeta = (MapMeta) mapItem.getItemMeta(); | ||
mapMeta.setMapId(map.getId()); | ||
mapItem.setItemMeta(mapMeta); | ||
|
||
final List<DataWatcher.b<?>> dwItems = Arrays.asList( | ||
new DataWatcher.b<>(8, DataWatcherRegistry.h, CraftItemStack.asNMSCopy(mapItem)), | ||
new DataWatcher.b<>(0, DataWatcherRegistry.a, (byte) (visible ? 0 : 0x20)) | ||
); | ||
return new PacketPlayOutEntityMetadata(frameId, dwItems); | ||
} | ||
|
||
@Override | ||
public Object makeFrameSpawnPacket(final Frame frame) { | ||
return new PacketPlayOutSpawnEntity( | ||
frame.getEntityId(), | ||
UUID.randomUUID(), | ||
frame.getPosX(), | ||
frame.getPosY(), | ||
frame.getPosZ(), | ||
frame.getFacing() == BlockFace.DOWN ? 90 : frame.getFacing() == BlockFace.UP ? -90 : 0, | ||
switch (frame.getFacing()) { | ||
case NORTH -> -180; | ||
case EAST -> -90; | ||
case WEST -> 90; | ||
default -> 0; | ||
}, | ||
EntityTypes.af, | ||
switch (frame.getFacing()) { | ||
case UP -> 1; | ||
case NORTH -> 2; | ||
case SOUTH -> 3; | ||
case WEST -> 4; | ||
case EAST -> 5; | ||
default -> 0; | ||
}, | ||
new Vec3D(0, 0, 0), | ||
switch (frame.getFacing()) { | ||
case NORTH -> -180; | ||
case EAST -> -90; | ||
case WEST -> 90; | ||
default -> 0; | ||
} | ||
); | ||
} | ||
|
||
@Override | ||
public Object makeFrameDespawnPacket(final Frame frame) { | ||
return new PacketPlayOutEntityDestroy(frame.getEntityId()); | ||
} | ||
|
||
@Override | ||
public void sendPacket(final Player player, final Object packet) { | ||
((CraftPlayer) player).getHandle().b.a((Packet<?>) packet); | ||
} | ||
|
||
@Override | ||
public void inject(final Player player, final PacketListener listener, final JavaPlugin plugin) { | ||
final NetworkManager networkManager; | ||
try { | ||
networkManager = this.getNetworkManager(((CraftPlayer) player).getHandle().b); | ||
} catch (final IllegalAccessException | NoSuchFieldException e) { | ||
plugin.getLogger().log(Level.WARNING, "Failed to inject packet handler into player %s".formatted(player.getName()), e); | ||
return; | ||
} | ||
networkManager.m.pipeline().addBefore("packet_handler", "maps_listener", new PacketHandler19R3(player, listener, plugin)); | ||
} | ||
|
||
private NetworkManager getNetworkManager(final PlayerConnection b) throws IllegalAccessException, NoSuchFieldException { | ||
if (this.netManField == null) { | ||
this.netManField = PlayerConnection.class.getDeclaredField("h"); | ||
this.netManField.setAccessible(true); | ||
} | ||
return (NetworkManager) this.netManField.get(b); | ||
} | ||
|
||
} |
Oops, something went wrong.