Compare commits
40
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7f99503d9 | ||
|
|
52adfbae8a | ||
|
|
a861066cab | ||
|
|
1acec02bfb | ||
|
|
b88857386a | ||
|
|
4c48d4c1df | ||
|
|
68f8fd3d03 | ||
|
|
2d625c6e7a | ||
|
|
83fe2cce0d | ||
|
|
73bfaebab6 | ||
|
|
2ac61fd5cb | ||
|
|
7d31150b35 | ||
|
|
11e4033ec6 | ||
|
|
a6a8866727 | ||
|
|
ce61c3ef52 | ||
|
|
4602ea8107 | ||
|
|
5fb1a6c85e | ||
|
|
7e2ac525ac | ||
|
|
7590d6f7de | ||
|
|
d7c2284ccb | ||
|
|
84a0759288 | ||
|
|
0ca8e27fc8 | ||
|
|
5e30aef0a1 | ||
|
|
9e53791fef | ||
|
|
8346918e86 | ||
|
|
7714c6253a | ||
|
|
0a00e970d7 | ||
|
|
d0dd8dc4cd | ||
|
|
bc01609828 | ||
|
|
c6e7bcb980 | ||
|
|
8987194030 | ||
|
|
4495db796d | ||
|
|
e1a29a20a7 | ||
|
|
bd5ef7cb30 | ||
|
|
36363c885c | ||
|
|
a198f0e8d6 | ||
|
|
28c4fdc7ce | ||
|
|
83720c6a81 | ||
|
|
c95acffab6 | ||
|
|
c2beb331f1 |
No files matched your search
@@ -0,0 +1,51 @@
|
||||
name: Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Publish Release
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Validate gradle wrapper
|
||||
uses: gradle/actions/wrapper-validation@v4
|
||||
|
||||
- name: Setup java 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 21
|
||||
distribution: temurin
|
||||
|
||||
- name: Prepare gradle
|
||||
run: ./gradlew printVersion --no-daemon
|
||||
|
||||
- name: Extract changelog
|
||||
id: changelog
|
||||
run: |
|
||||
OUTPUT_DELIMITER="$(uuidgen)"
|
||||
echo "changelog<<$OUTPUT_DELIMITER" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# extract tag name and use it to get changelog section
|
||||
TAG_NAME="v$(./gradlew -q --no-daemon printVersion)"
|
||||
awk -v tag="${TAG_NAME}" '
|
||||
$1 == "!!!!!" && $2 == tag {found=1; next}
|
||||
$1 == "!!!!!" && found {exit}
|
||||
found
|
||||
' CHANGELOG.md >> "$GITHUB_OUTPUT"
|
||||
|
||||
# end output
|
||||
echo "$OUTPUT_DELIMITER" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Publish plugin
|
||||
env:
|
||||
GITHUB_API_TOKEN: ${{ github.token }}
|
||||
MODRINTH_API_TOKEN: ${{ secrets.MODRINTH_PUBLISH_TOKEN }}
|
||||
CHANGELOG: ${{ steps.changelog.outputs.changelog }}
|
||||
run: ./gradlew publishMods --no-daemon -PnoDryPublish
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
!!!!! v2.9.1
|
||||
|
||||
# PacketEvents 2.9.1 is out now! 🎉
|
||||
|
||||
This is a hotfix patch update to fix issues with 2.9.0 release assets. See below for the 2.9.0 changelog.
|
||||
|
||||
### New update now supports Minecraft version 1.21.6 & 1.21.7. We suggest that you update, as numerous bugs have been fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our very own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* Added 1.21.6 support
|
||||
* Added 1.21.7 support
|
||||
* Bug fixes
|
||||
|
||||
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.8.0...v2.9.1
|
||||
|
||||
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
|
||||
!!!!! v2.9.0
|
||||
|
||||
# PacketEvents 2.9.0 is out now! 🎉
|
||||
|
||||
### New update now supports Minecraft version 1.21.6 & 1.21.7. We suggest that you update, as numerous bugs have been fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our very own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* Added 1.21.6 support
|
||||
* Added 1.21.7 support
|
||||
* Bug fixes
|
||||
|
||||
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.8.0...v2.9.0
|
||||
|
||||
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
|
||||
!!!!! v2.8.0
|
||||
|
||||
# PacketEvents 2.8.0 is out now! 🎉
|
||||
|
||||
### New update now supports Minecraft version 1.21.5. Please update, as numerous bugs have been fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our very own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* Added 1.21.5 support
|
||||
* Various bugs fixed
|
||||
|
||||
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.7.0...v2.8.0
|
||||
|
||||
## Contributors 🏅
|
||||
|
||||
This update wouldn't be possible without these contributors ❤️: @booky10, @Axionize, @Bram1903, @ManInMyVan, @ytnoos,
|
||||
@AoElite, @HaHaWTH, @divinepablo, @scienziatopazzo, @bridgelol, @MachineBreaker, @Luuzzi, @Beaness, @Rubenicos, @Loyisa
|
||||
|
||||
## New Contributors
|
||||
|
||||
* @HaHaWTH made their first contribution in https://github.com/retrooper/packetevents/pull/1097
|
||||
* @divinepablo made their first contribution in https://github.com/retrooper/packetevents/pull/1098
|
||||
* @scienziatopazzo made their first contribution in https://github.com/retrooper/packetevents/pull/1105
|
||||
* @bridgelol made their first contribution in https://github.com/retrooper/packetevents/pull/1199
|
||||
* @Luuzzi made their first contribution in https://github.com/retrooper/packetevents/pull/1197
|
||||
* @Beaness made their first contribution in https://github.com/retrooper/packetevents/pull/1212
|
||||
* @Rubenicos made their first contribution in https://github.com/retrooper/packetevents/pull/1162
|
||||
* @Loyisa made their first contribution in https://github.com/retrooper/packetevents/pull/1220
|
||||
|
||||
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
!!!!! v2.9.0
|
||||
|
||||
# PacketEvents 2.9.0 is out now! 🎉
|
||||
|
||||
### New update now supports Minecraft version 1.21.6 & 1.21.7. We suggest that you update, as numerous bugs have been fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our very own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* Added 1.21.6 support
|
||||
* Added 1.21.7 support
|
||||
* Bug fixes
|
||||
|
||||
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.8.0...v2.9.0
|
||||
|
||||
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
|
||||
!!!!! v2.8.0
|
||||
|
||||
# PacketEvents 2.8.0 is out now! 🎉
|
||||
|
||||
### New update now supports Minecraft version 1.21.5. Please update, as numerous bugs have been fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our very own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* Added 1.21.5 support
|
||||
* Various bugs fixed
|
||||
|
||||
**View Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.7.0...v2.8.0
|
||||
|
||||
## Contributors 🏅
|
||||
|
||||
This update wouldn't be possible without these contributors ❤️: @booky10, @Axionize, @Bram1903, @ManInMyVan, @ytnoos,
|
||||
@AoElite, @HaHaWTH, @divinepablo, @scienziatopazzo, @bridgelol, @MachineBreaker, @Luuzzi, @Beaness, @Rubenicos, @Loyisa
|
||||
|
||||
## New Contributors
|
||||
|
||||
* @HaHaWTH made their first contribution in https://github.com/retrooper/packetevents/pull/1097
|
||||
* @divinepablo made their first contribution in https://github.com/retrooper/packetevents/pull/1098
|
||||
* @scienziatopazzo made their first contribution in https://github.com/retrooper/packetevents/pull/1105
|
||||
* @bridgelol made their first contribution in https://github.com/retrooper/packetevents/pull/1199
|
||||
* @Luuzzi made their first contribution in https://github.com/retrooper/packetevents/pull/1197
|
||||
* @Beaness made their first contribution in https://github.com/retrooper/packetevents/pull/1212
|
||||
* @Rubenicos made their first contribution in https://github.com/retrooper/packetevents/pull/1162
|
||||
* @Loyisa made their first contribution in https://github.com/retrooper/packetevents/pull/1220
|
||||
|
||||
## If you want to support PacketEvents, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
|
||||
!!!!! v2.7.0
|
||||
|
||||
# PacketEvents v2.7.0 is out now! 🎉
|
||||
|
||||
### New update with support of the latest Minecraft version. In addition to that, countless bugs were fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* Added 1.21.4 support
|
||||
* Fix: Potion contents item component for 1.21.2/1.21.3
|
||||
* Fix: NPC objects to have unique server team names
|
||||
* Add missing ServerVersion#V_1_9_1
|
||||
* Validation checks added for window click type
|
||||
|
||||
**Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.6.0...v2.7.0
|
||||
|
||||
## New Contributors
|
||||
|
||||
* @Axionize made their first contribution in https://github.com/retrooper/packetevents/pull/1048
|
||||
* @ShreyasAyyengar made their first contribution in https://github.com/retrooper/packetevents/pull/1044
|
||||
* @mfnalex made their first contribution in https://github.com/retrooper/packetevents/pull/1076
|
||||
|
||||
## Contributors 🏅
|
||||
|
||||
This update wouldn't be possible without these contributors ❤️: @booky10, @rafi67000, @ShreyasAyyengar, @AoElite,
|
||||
@Tecnio, @Axionize, @mfnalex
|
||||
|
||||
### If you want to support PacketEvents, and any upcoming events we plan for the future, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
|
||||
!!!!! v2.6.0
|
||||
|
||||
# PacketEvents v2.6.0 is out now! 🎉
|
||||
|
||||
### New update with support of new platforms & the latest Minecraft version. In addition to that, countless bugs were fixed.
|
||||
|
||||
# Brief Announcement 📢⚠️
|
||||
|
||||
### We have our own website: https://packetevents.com
|
||||
|
||||
### Documentation: https://docs.packetevents.com
|
||||
|
||||
### JavaDocs: https://javadocs.packetevents.com
|
||||
|
||||
## What's Changed? (Summary)
|
||||
|
||||
* 1.21.2 and 1.21.3 Minecraft support
|
||||
* Sponge support added
|
||||
* Fabric support added (also server-side)
|
||||
* Utilizing the proper bStats API
|
||||
* Registry element issues fixed
|
||||
* Mappings issues fixed
|
||||
* AdvancedSlimePaper issues fixed
|
||||
* BungeeCord issues fixed
|
||||
|
||||
### **Full Changelog**: https://github.com/retrooper/packetevents/compare/v2.5.0...v2.6.0
|
||||
|
||||
## Contributors 🏅
|
||||
|
||||
This update wouldn't be possible without these contributors ❤️: @booky10, @ManInMyVan, @SamB440, @rafi67000, @Bram1903,
|
||||
@AbhigyaKrishna
|
||||
|
||||
### If you want to support PacketEvents, and any upcoming events we plan for the future, consider sponsoring us on [GitHub Sponsors](https://github.com/sponsors/retrooper)
|
||||
|
||||
## Maven/Gradle Dependency
|
||||
|
||||
### **Check out**: https://docs.packetevents.com/getting-started
|
||||
|
||||
!!!!!
|
||||
@@ -32,6 +32,7 @@ import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -44,7 +45,7 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
|
||||
private final Object channel;
|
||||
private final ConnectionState connectionState;
|
||||
private final User user;
|
||||
private final Object player;
|
||||
private Object player;
|
||||
private Object byteBuf;
|
||||
private final int packetID;
|
||||
private final PacketTypeCommon packetType;
|
||||
@@ -145,6 +146,12 @@ public abstract class ProtocolPacketEvent extends PacketEvent implements PlayerE
|
||||
return (T) player;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ApiStatus.Internal
|
||||
public void setPlayer(Object player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the connection state this packet has been sent/received in.
|
||||
*/
|
||||
|
||||
+5
-1
@@ -37,7 +37,9 @@ import com.github.retrooper.packetevents.wrapper.handshaking.client.WrapperHands
|
||||
import com.github.retrooper.packetevents.wrapper.login.server.WrapperLoginServerLoginSuccess;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerJoinGame;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerRespawn;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class InternalPacketListener extends PacketListenerAbstract {
|
||||
|
||||
public InternalPacketListener() {
|
||||
@@ -68,7 +70,9 @@ public class InternalPacketListener extends PacketListenerAbstract {
|
||||
PacketEvents.getAPI().getProtocolManager().setChannel(profile.getUUID(), channel);
|
||||
}
|
||||
|
||||
PacketEvents.getAPI().getLogManager().debug("Mapped player UUID with their channel.");
|
||||
if (PacketEvents.getAPI().getLogManager().isDebug()) {
|
||||
PacketEvents.getAPI().getLogManager().debug("Mapped player UUID with their channel " + profile.getUUID() + " " + channel);
|
||||
}
|
||||
|
||||
// Switch the user's connection state to new state, but the variable event.getConnectionState() remains LOGIN
|
||||
// We switch user state immediately to remain in sync with vanilla, allowing you to encode packets immediately
|
||||
|
||||
+16
-5
@@ -19,6 +19,8 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat.clickevent;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.dialog.Dialog;
|
||||
import com.github.retrooper.packetevents.protocol.dialog.Dialogs;
|
||||
import com.github.retrooper.packetevents.protocol.mapper.MappedEntityRef;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTCompound;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -26,19 +28,24 @@ import org.jspecify.annotations.NullMarked;
|
||||
@NullMarked
|
||||
public class ShowDialogClickEvent implements ClickEvent {
|
||||
|
||||
private final Dialog dialog;
|
||||
private final MappedEntityRef<Dialog> dialog;
|
||||
|
||||
public ShowDialogClickEvent(Dialog dialog) {
|
||||
this(new MappedEntityRef.Static<>(dialog));
|
||||
}
|
||||
|
||||
public ShowDialogClickEvent(MappedEntityRef<Dialog> dialog) {
|
||||
this.dialog = dialog;
|
||||
}
|
||||
|
||||
public static ShowDialogClickEvent decode(NBTCompound compound, PacketWrapper<?> wrapper) {
|
||||
Dialog dialog = compound.getOrThrow("dialog", Dialog::decode, wrapper);
|
||||
MappedEntityRef<Dialog> dialog = MappedEntityRef.decode(compound.getTagOrThrow("dialog"),
|
||||
Dialogs.getRegistry(), Dialog::decode, wrapper);
|
||||
return new ShowDialogClickEvent(dialog);
|
||||
}
|
||||
|
||||
public static void encode(NBTCompound compound, PacketWrapper<?> wrapper, ShowDialogClickEvent clickEvent) {
|
||||
compound.set("dialog", clickEvent.dialog, Dialog::encode, wrapper);
|
||||
compound.setTag("dialog", MappedEntityRef.encode(wrapper, Dialog::encode, clickEvent.dialog));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,10 +55,14 @@ public class ShowDialogClickEvent implements ClickEvent {
|
||||
|
||||
@Override
|
||||
public net.kyori.adventure.text.event.ClickEvent asAdventure() {
|
||||
return net.kyori.adventure.text.event.ClickEvent.showDialog(this.dialog);
|
||||
return net.kyori.adventure.text.event.ClickEvent.showDialog(this.dialog.get());
|
||||
}
|
||||
|
||||
public MappedEntityRef<Dialog> getDialogRef() {
|
||||
return this.dialog;
|
||||
}
|
||||
|
||||
public Dialog getDialog() {
|
||||
return this.dialog;
|
||||
return this.dialog.get();
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -19,15 +19,14 @@
|
||||
package com.github.retrooper.packetevents.protocol.chat.message;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.chat.ChatType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.util.adventure.AdventureSerializer;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
public class ChatMessage {
|
||||
private Component chatContent;
|
||||
private ChatType type;
|
||||
|
||||
private final GsonComponentSerializer gson = GsonComponentSerializer.gson();
|
||||
|
||||
protected ChatMessage(Component chatContent, ChatType type) {
|
||||
this.chatContent = chatContent;
|
||||
this.type = type;
|
||||
@@ -37,16 +36,16 @@ public class ChatMessage {
|
||||
return chatContent;
|
||||
}
|
||||
|
||||
public String getChatContentJson() {
|
||||
return gson.serialize(chatContent);
|
||||
public String getChatContentJson(ClientVersion version) {
|
||||
return AdventureSerializer.serializer(version).asJson(this.getChatContent());
|
||||
}
|
||||
|
||||
public void setChatContent(Component chatContent) {
|
||||
this.chatContent = chatContent;
|
||||
}
|
||||
|
||||
public void setChatContentJson(String jsonContent) {
|
||||
this.chatContent = gson.deserialize(jsonContent);
|
||||
public void setChatContentJson(ClientVersion version, String json) {
|
||||
this.setChatContent(AdventureSerializer.serializer(version).fromJson(json));
|
||||
}
|
||||
|
||||
public ChatType getType() {
|
||||
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2025 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.protocol.mapper;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBT;
|
||||
import com.github.retrooper.packetevents.protocol.nbt.NBTString;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtDecoder;
|
||||
import com.github.retrooper.packetevents.protocol.util.NbtEncoder;
|
||||
import com.github.retrooper.packetevents.resources.ResourceLocation;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistry;
|
||||
import com.github.retrooper.packetevents.util.mappings.IRegistryHolder;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@NullMarked
|
||||
public interface MappedEntityRef<T extends MappedEntity> extends Supplier<T> {
|
||||
|
||||
T get();
|
||||
|
||||
static <T extends MappedEntity> MappedEntityRef<T> decode(
|
||||
NBT tag, IRegistry<T> registry, NbtDecoder<T> decoder, PacketWrapper<?> wrapper
|
||||
) {
|
||||
if (tag instanceof NBTString) {
|
||||
ResourceLocation name = new ResourceLocation(((NBTString) tag).getValue());
|
||||
return new Named<>(wrapper, registry, name);
|
||||
}
|
||||
return new Static<>(decoder.decode(tag, wrapper));
|
||||
}
|
||||
|
||||
static <T extends MappedEntity> NBT encode(PacketWrapper<?> wrapper, NbtEncoder<T> encoder, MappedEntityRef<T> ref) {
|
||||
if (ref instanceof Named) {
|
||||
return new NBTString(((Named<T>) ref).name.toString());
|
||||
} else if (ref instanceof Static) {
|
||||
return encoder.encode(wrapper, ((Static<T>) ref).entity);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Unsupported MappedEntityRef implementation: " + ref);
|
||||
}
|
||||
}
|
||||
|
||||
final class Static<T extends MappedEntity> implements MappedEntityRef<T> {
|
||||
|
||||
private final T entity;
|
||||
|
||||
public Static(T entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return this.entity;
|
||||
}
|
||||
}
|
||||
|
||||
final class Named<T extends MappedEntity> implements MappedEntityRef<T> {
|
||||
|
||||
private final WeakReference<IRegistryHolder> registryHolder;
|
||||
private final ClientVersion version;
|
||||
private final IRegistry<T> registry;
|
||||
private final ResourceLocation name;
|
||||
private volatile @Nullable T entity;
|
||||
|
||||
public Named(PacketWrapper<?> wrapper, IRegistry<T> registry, ResourceLocation name) {
|
||||
this(wrapper.getRegistryHolder(), wrapper.getServerVersion().toClientVersion(), registry, name);
|
||||
}
|
||||
|
||||
public Named(IRegistryHolder registryHolder, ClientVersion version, IRegistry<T> registry, ResourceLocation name) {
|
||||
this.registryHolder = new WeakReference<>(registryHolder);
|
||||
this.version = version;
|
||||
this.registry = registry;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
T entity = this.entity;
|
||||
if (entity == null) {
|
||||
synchronized (this) {
|
||||
entity = this.entity;
|
||||
if (entity == null) {
|
||||
// registry holder may be a user object, so ensure no user objects get leaked accidentally
|
||||
IRegistryHolder registryHolder = this.registryHolder.get();
|
||||
if (registryHolder == null) {
|
||||
throw new IllegalStateException("Registry holder for " + this.registry
|
||||
+ "/" + this.version + "/" + this.name + "has disappeared");
|
||||
}
|
||||
// replace registry and lookup entity
|
||||
IRegistry<T> registry = registryHolder.getRegistryOr(this.registry, this.version);
|
||||
entity = registry.getByNameOrThrow(this.name);
|
||||
this.entity = entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1075,7 +1075,7 @@ public final class PacketType {
|
||||
USE_BED(WrapperPlayServerUseBed.class),
|
||||
SPAWN_WEATHER_ENTITY(WrapperPlayServerSpawnWeatherEntity.class),
|
||||
TITLE(WrapperPlayServerSetTitleSubtitle.class),
|
||||
WORLD_BORDER(WrapperPlayServerInitializeWorldBorder.class),
|
||||
WORLD_BORDER(WrapperPlayServerWorldBorder.class),
|
||||
COMBAT_EVENT(WrapperPlayServerCombatEvent.class),
|
||||
ENTITY_MOVEMENT(WrapperPlayServerEntityMovement.class),
|
||||
SPAWN_LIVING_ENTITY(WrapperPlayServerSpawnLivingEntity.class),
|
||||
@@ -1125,7 +1125,7 @@ public final class PacketType {
|
||||
INITIALIZE_WORLD_BORDER(WrapperPlayServerInitializeWorldBorder.class),
|
||||
KEEP_ALIVE(WrapperPlayServerKeepAlive.class),
|
||||
CHUNK_DATA(WrapperPlayServerChunkData.class),
|
||||
EFFECT(null),
|
||||
EFFECT(WrapperPlayServerEffect.class),
|
||||
PARTICLE(WrapperPlayServerParticle.class),
|
||||
UPDATE_LIGHT(WrapperPlayServerUpdateLight.class),
|
||||
JOIN_GAME(WrapperPlayServerJoinGame.class),
|
||||
|
||||
+2
-1
@@ -329,7 +329,8 @@ public class WrapperPlayServerChunkData extends PacketWrapper<WrapperPlayServerC
|
||||
this.buffer = originalBuffer;
|
||||
|
||||
// write the same amount of zero bytes mojang also writes
|
||||
if (this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
|
||||
if (this.serverVersion.isOlderThan(ServerVersion.V_1_21_6)
|
||||
&& this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_21_5)) {
|
||||
int zeroBytes = ChunkReader_v1_18.getMojangZeroByteSuffixLength(chunks);
|
||||
int newWriterIndex = ByteBufHelper.writerIndex(dataBuffer) + zeroBytes;
|
||||
// allocate enough space for the zeros
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2025 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.github.retrooper.packetevents.wrapper.play.server;
|
||||
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
/**
|
||||
* Mojang name: ClientboundLevelEventPacket
|
||||
*/
|
||||
public class WrapperPlayServerEffect extends PacketWrapper<WrapperPlayServerEffect> {
|
||||
|
||||
private int type;
|
||||
private Vector3i position;
|
||||
private int data;
|
||||
private boolean globalEvent;
|
||||
|
||||
public WrapperPlayServerEffect(PacketSendEvent type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
public WrapperPlayServerEffect(int type, Vector3i position, int data, boolean globalEvent) {
|
||||
super(PacketType.Play.Server.EFFECT);
|
||||
this.type = type;
|
||||
this.position = position;
|
||||
this.data = data;
|
||||
this.globalEvent = globalEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read() {
|
||||
this.type = this.readInt();
|
||||
if (this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_8)) {
|
||||
this.position = this.readBlockPosition();
|
||||
} else {
|
||||
this.position = new Vector3i(this.readInt(), this.readByte() & 0xFF, this.readInt());
|
||||
}
|
||||
this.data = this.readInt();
|
||||
this.globalEvent = this.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
this.writeInt(this.type);
|
||||
if (this.serverVersion.isNewerThanOrEquals(ServerVersion.V_1_8)) {
|
||||
this.writeBlockPosition(this.position);
|
||||
} else {
|
||||
this.writeInt(this.position.x);
|
||||
this.writeByte(this.position.y & 0xFF);
|
||||
this.writeInt(this.position.z);
|
||||
}
|
||||
this.writeInt(this.data);
|
||||
this.writeBoolean(this.globalEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(WrapperPlayServerEffect wrapper) {
|
||||
this.type = wrapper.type;
|
||||
this.position = wrapper.position;
|
||||
this.data = wrapper.data;
|
||||
this.globalEvent = wrapper.globalEvent;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Vector3i getPosition() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public void setPosition(Vector3i position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public int getData() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
public void setData(int data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public boolean isGlobalEvent() {
|
||||
return this.globalEvent;
|
||||
}
|
||||
|
||||
public void setGlobalEvent(boolean globalEvent) {
|
||||
this.globalEvent = globalEvent;
|
||||
}
|
||||
}
|
||||
+82
-11
@@ -19,10 +19,11 @@
|
||||
package com.github.retrooper.packetevents.wrapper.play.server;
|
||||
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
|
||||
// Thanks MCProtocolLib, this is taken entirely from them
|
||||
public class WrapperPlayServerWorldBorder extends PacketWrapper<WrapperPlayServerWorldBorder> {
|
||||
private WorldBorderAction action;
|
||||
|
||||
@@ -92,7 +93,9 @@ public class WrapperPlayServerWorldBorder extends PacketWrapper<WrapperPlayServe
|
||||
|
||||
@Override
|
||||
public void read() {
|
||||
this.action = WorldBorderAction.values()[this.readVarInt()];
|
||||
int actionId = readVarInt();
|
||||
action = serverVersion.isNewerThanOrEquals(ServerVersion.V_1_12) ? WorldBorderAction.fromId(actionId)
|
||||
: WorldBorderAction.fromLegacyId(actionId);
|
||||
if (this.action == WorldBorderAction.SET_SIZE) {
|
||||
this.radius = readDouble();
|
||||
} else if (this.action == WorldBorderAction.LERP_SIZE) {
|
||||
@@ -120,7 +123,8 @@ public class WrapperPlayServerWorldBorder extends PacketWrapper<WrapperPlayServe
|
||||
|
||||
@Override
|
||||
public void write() {
|
||||
writeVarInt(this.action.ordinal());
|
||||
int actionId = serverVersion.isNewerThanOrEquals(ServerVersion.V_1_12) ? action.getId() : action.getLegacyId();
|
||||
writeVarInt(actionId);
|
||||
if (this.action == WorldBorderAction.SET_SIZE) {
|
||||
writeDouble(this.radius);
|
||||
} else if (this.action == WorldBorderAction.LERP_SIZE) {
|
||||
@@ -200,12 +204,79 @@ public class WrapperPlayServerWorldBorder extends PacketWrapper<WrapperPlayServe
|
||||
return this.warningBlocks;
|
||||
}
|
||||
|
||||
public enum WorldBorderAction {
|
||||
SET_SIZE,
|
||||
LERP_SIZE,
|
||||
SET_CENTER,
|
||||
INITIALIZE,
|
||||
SET_WARNING_TIME,
|
||||
SET_WARNING_BLOCKS;
|
||||
public void setAction(WorldBorderAction action) {
|
||||
this.action = action;
|
||||
}
|
||||
}
|
||||
|
||||
public void setRadius(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public void setOldRadius(double oldRadius) {
|
||||
this.oldRadius = oldRadius;
|
||||
}
|
||||
|
||||
public void setNewRadius(double newRadius) {
|
||||
this.newRadius = newRadius;
|
||||
}
|
||||
|
||||
public void setSpeed(long speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public void setCenterX(double centerX) {
|
||||
this.centerX = centerX;
|
||||
}
|
||||
|
||||
public void setCenterZ(double centerZ) {
|
||||
this.centerZ = centerZ;
|
||||
}
|
||||
|
||||
public void setPortalTeleportBoundary(int portalTeleportBoundary) {
|
||||
this.portalTeleportBoundary = portalTeleportBoundary;
|
||||
}
|
||||
|
||||
public void setWarningTime(int warningTime) {
|
||||
this.warningTime = warningTime;
|
||||
}
|
||||
|
||||
public void setWarningBlocks(int warningBlocks) {
|
||||
this.warningBlocks = warningBlocks;
|
||||
}
|
||||
|
||||
public enum WorldBorderAction {
|
||||
SET_SIZE(1),
|
||||
LERP_SIZE(2),
|
||||
SET_CENTER(3),
|
||||
INITIALIZE(6),
|
||||
SET_WARNING_TIME(5),
|
||||
SET_WARNING_BLOCKS(4);
|
||||
|
||||
private final int legacyId;
|
||||
|
||||
WorldBorderAction(int legacyId) {
|
||||
this.legacyId = legacyId;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return ordinal();
|
||||
}
|
||||
|
||||
public int getLegacyId() {
|
||||
return legacyId;
|
||||
}
|
||||
|
||||
public static WorldBorderAction fromId(int id) {
|
||||
return WorldBorderAction.values()[id];
|
||||
}
|
||||
|
||||
public static WorldBorderAction fromLegacyId(int legacyId) {
|
||||
for (WorldBorderAction action : WorldBorderAction.values()) {
|
||||
if (action.legacyId == legacyId) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-44
@@ -1,29 +1,20 @@
|
||||
import java.io.ByteArrayOutputStream
|
||||
plugins {
|
||||
packetevents.`publish-conventions`
|
||||
}
|
||||
|
||||
// TODO UPDATE
|
||||
val fullVersion = "2.9.0"
|
||||
val snapshot = true
|
||||
// properties are all set as string, convert to boolean
|
||||
ext["snapshot"] = ext["snapshot"].toString().toBooleanStrict()
|
||||
|
||||
ext["commitHash"] = providers.exec {
|
||||
commandLine("git", "rev-parse", "--short", "HEAD")
|
||||
}.standardOutput.asText.map { it.trim() }.getOrElse("unknown")
|
||||
ext["versionMeta"] = if (ext["snapshot"] == true) "-SNAPSHOT" else ""
|
||||
ext["versionMetaWithHash"] = "+${ext["commitHash"]}${ext["versionMeta"]}"
|
||||
ext["versionNoHash"] = "${ext["fullVersion"]}${ext["versionMeta"]}"
|
||||
|
||||
group = "com.github.retrooper"
|
||||
description = rootProject.name
|
||||
|
||||
fun getVersionMeta(includeHash: Boolean): String {
|
||||
if (!snapshot) {
|
||||
return ""
|
||||
}
|
||||
var commitHash = ""
|
||||
if (includeHash && file(".git").isDirectory) {
|
||||
val stdout = ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine("git", "rev-parse", "--short", "HEAD")
|
||||
standardOutput = stdout
|
||||
}
|
||||
commitHash = "+${stdout.toString().trim()}"
|
||||
}
|
||||
return "$commitHash-SNAPSHOT"
|
||||
}
|
||||
version = "$fullVersion${getVersionMeta(true)}"
|
||||
ext["versionNoHash"] = "$fullVersion${getVersionMeta(false)}"
|
||||
version = "${ext["fullVersion"]}${ext[if (ext["snapshot"] == true) "versionMetaWithHash" else "versionMeta"]}"
|
||||
|
||||
tasks {
|
||||
wrapper {
|
||||
@@ -35,39 +26,22 @@ tasks {
|
||||
subprojects.filterNot { it.path == ":patch" }.map { it.tasks[task] }.toTypedArray()
|
||||
}
|
||||
|
||||
register("build") {
|
||||
dependsOn(*taskSubModules("build"))
|
||||
group = "build"
|
||||
|
||||
doLast {
|
||||
val buildOut = project.layout.buildDirectory.dir("libs").get().asFile
|
||||
if (!buildOut.exists())
|
||||
buildOut.mkdirs()
|
||||
|
||||
for (subproject in subprojects) {
|
||||
if (subproject.path.startsWith(":patch")) continue
|
||||
val subIn = subproject.layout.buildDirectory.dir("libs").get()
|
||||
|
||||
copy {
|
||||
from(subIn)
|
||||
into(buildOut)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
register<Delete>("clean") {
|
||||
dependsOn(*taskSubModules("clean"))
|
||||
group = "build"
|
||||
delete(rootProject.layout.buildDirectory)
|
||||
}
|
||||
|
||||
register("printVersion") {
|
||||
println(project.version)
|
||||
}
|
||||
|
||||
defaultTasks("build")
|
||||
}
|
||||
|
||||
allprojects {
|
||||
tasks {
|
||||
withType<Jar> {
|
||||
archiveBaseName = "${rootProject.name}-${project.name}"
|
||||
archiveVersion = rootProject.ext["versionNoHash"] as String
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,4 +21,5 @@ dependencies {
|
||||
implementation(libs.fast.util)
|
||||
implementation(libs.gson)
|
||||
implementation(libs.java.diff.utils)
|
||||
implementation(libs.mod.publish)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ via-nbt = "4.1.0"
|
||||
fast-util = "8.5.6"
|
||||
gson = "2.8.9"
|
||||
java-diff-utils = "4.12"
|
||||
mod-publish = "0.8.4"
|
||||
|
||||
[libraries]
|
||||
shadow = { group = "com.gradleup.shadow", name = "shadow-gradle-plugin", version.ref = "shadow" }
|
||||
@@ -12,4 +13,5 @@ jetbrains-annotations = { group = "org.jetbrains", name = "annotations", version
|
||||
via-nbt = { group = "com.viaversion", name = "nbt", version.ref = "via-nbt" }
|
||||
fast-util = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fast-util" }
|
||||
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" }
|
||||
java-diff-utils = { group = "io.github.java-diff-utils", name = "java-diff-utils", version.ref = "java-diff-utils" }
|
||||
java-diff-utils = { group = "io.github.java-diff-utils", name = "java-diff-utils", version.ref = "java-diff-utils" }
|
||||
mod-publish = { group = "me.modmuss50", name = "mod-publish-plugin", version.ref = "mod-publish" }
|
||||
@@ -0,0 +1,77 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import me.modmuss50.mpp.ModPublishExtension
|
||||
import me.modmuss50.mpp.PublishModTask
|
||||
|
||||
plugins {
|
||||
me.modmuss50.`mod-publish-plugin`
|
||||
}
|
||||
|
||||
configure<ModPublishExtension> {
|
||||
changelog = providers.environmentVariable("CHANGELOG")
|
||||
.map { it.trim() }
|
||||
.getOrElse("No changelog provided")
|
||||
type = if (rootProject.ext["snapshot"] == true) BETA else STABLE
|
||||
dryRun = !hasProperty("noDryPublish")
|
||||
|
||||
// if there is no publishing platform set, assume this is the root task
|
||||
// which is used to support github releases properly
|
||||
if (!hasProperty("publishing.platform")) {
|
||||
github {
|
||||
accessToken = providers.environmentVariable("GITHUB_API_TOKEN")
|
||||
repository = providers.environmentVariable("GITHUB_REPOSITORY")
|
||||
commitish = providers.environmentVariable("GITHUB_REF_NAME")
|
||||
tagName = version.map { "v${it}" }
|
||||
displayName = version
|
||||
|
||||
// won't be empty, just so the publishing plugin won't complain
|
||||
allowEmptyFiles = true
|
||||
}
|
||||
|
||||
// iterate through all subprojects and search for configured release files
|
||||
subprojects.filter { it.hasProperty("publishing.platform") }.forEach {
|
||||
// add main platform publishing file after project has finished evaluating
|
||||
it.afterEvaluate {
|
||||
additionalFiles.from(publishMods.file)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!hasProperty("publishing.skip_files")) {
|
||||
// setup files for this platform
|
||||
file = tasks.named<ShadowJar>("shadowJar").flatMap { it.archiveFile }
|
||||
additionalFiles.from(tasks.named<Jar>("sourcesJar").flatMap { it.archiveFile })
|
||||
}
|
||||
|
||||
val platform = property("publishing.platform").toString()
|
||||
val fancyPlatform = platform.replaceFirstChar { it.titlecaseChar() }
|
||||
|
||||
// setup per-platform modrinth publishing
|
||||
modrinth {
|
||||
accessToken = providers.environmentVariable("MODRINTH_API_TOKEN")
|
||||
var versionBob = "${rootProject.ext["fullVersion"]}+${platform}"
|
||||
if (rootProject.ext["snapshot"] == true) {
|
||||
// e.g. "0.0.0+platform.abcdefg"
|
||||
version = "${versionBob}.${rootProject.ext["commitHash"]}"
|
||||
} else {
|
||||
// e.g. "0.0.0+platform"
|
||||
version = versionBob
|
||||
}
|
||||
displayName = "${rootProject.ext["publishing.display_name"]} ${rootProject.version} ${fancyPlatform}"
|
||||
projectId = property("publishing.modrinth.project").toString()
|
||||
minecraftVersionRange {
|
||||
start = property("publishing.modrinth.version.start").toString()
|
||||
end = property("publishing.modrinth.version.end").toString()
|
||||
}
|
||||
val loadersStr = property("publishing.modrinth.loaders").toString()
|
||||
modLoaders.addAll(loadersStr.split(","))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasProperty("publishing.platform")
|
||||
&& !hasProperty("publishing.skip_files")
|
||||
) {
|
||||
tasks.withType<PublishModTask> {
|
||||
dependsOn(tasks.named<ShadowJar>("shadowJar"))
|
||||
dependsOn(tasks.named<Jar>("sourcesJar"))
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ tasks {
|
||||
shadowJar {
|
||||
configurations.add(compileShadowOnly)
|
||||
|
||||
destinationDirectory = rootProject.layout.buildDirectory.dir("libs")
|
||||
archiveFileName = "packetevents-${project.name}-${rootProject.ext["versionNoHash"]}.jar"
|
||||
archiveClassifier = null
|
||||
|
||||
@@ -72,8 +73,14 @@ tasks {
|
||||
|
||||
configurations.implementation.get().extendsFrom(configurations.shadow.get())
|
||||
|
||||
// TODO properly publish correct shadow references instead of this mess
|
||||
gradle.taskGraph.whenReady {
|
||||
if (gradle.startParameter.taskNames.any { it.contains("publish") }) {
|
||||
if (gradle.startParameter.taskNames.any {
|
||||
it.contains("publish") && !it.equals(
|
||||
"publishMods",
|
||||
ignoreCase = true
|
||||
)
|
||||
}) {
|
||||
logger.info("Adding shadow configuration to shadowJar tasks in module ${project.name}.")
|
||||
tasks.withType<ShadowJar> {
|
||||
dependencies {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
packetevents.`shadow-conventions`
|
||||
packetevents.`library-conventions`
|
||||
packetevents.`publish-conventions`
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
publishing.platform=bungeecord
|
||||
publishing.modrinth.loaders=bungeecord,waterfall
|
||||
publishing.modrinth.version.start=1.8.8
|
||||
publishing.modrinth.version.end=latest
|
||||
+19
-1
@@ -1,5 +1,11 @@
|
||||
import me.modmuss50.mpp.ModPublishExtension
|
||||
import me.modmuss50.mpp.PublishModTask
|
||||
import net.fabricmc.loom.task.RemapJarTask
|
||||
import net.fabricmc.loom.task.RemapSourcesJarTask
|
||||
|
||||
plugins {
|
||||
packetevents.`library-conventions`
|
||||
packetevents.`publish-conventions`
|
||||
alias(libs.plugins.fabric.loom)
|
||||
}
|
||||
|
||||
@@ -44,13 +50,20 @@ tasks {
|
||||
}
|
||||
|
||||
remapJar {
|
||||
archiveBaseName = "${rootProject.name}-fabric"
|
||||
destinationDirectory = rootProject.layout.buildDirectory.dir("libs")
|
||||
archiveBaseName = "${rootProject.name}-${project.name}"
|
||||
archiveVersion = rootProject.ext["versionNoHash"] as String
|
||||
}
|
||||
|
||||
remapSourcesJar {
|
||||
archiveBaseName = "${rootProject.name}-${project.name}"
|
||||
archiveVersion = rootProject.ext["versionNoHash"] as String
|
||||
}
|
||||
|
||||
withType<PublishModTask> {
|
||||
dependsOn(named<RemapJarTask>("remapJar"))
|
||||
dependsOn(named<RemapSourcesJarTask>("remapSourcesJar"))
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
@@ -64,3 +77,8 @@ loom {
|
||||
accessWidenerPath = sourceSets.main.get().resources.srcDirs.single()
|
||||
.resolve("${rootProject.name}.accesswidener")
|
||||
}
|
||||
|
||||
configure<ModPublishExtension> {
|
||||
file = tasks.named<RemapJarTask>("remapJar").flatMap { it.archiveFile }
|
||||
additionalFiles.from(tasks.named<RemapSourcesJarTask>("remapSourcesJar").flatMap { it.archiveFile })
|
||||
}
|
||||
@@ -8,3 +8,9 @@ minecraft_version=1.21.6
|
||||
parchment_mappings=2025.06.01
|
||||
parchment_minecraft_version=1.21.5
|
||||
loader_version=0.16.14
|
||||
|
||||
publishing.skip_files=true
|
||||
publishing.platform=fabric
|
||||
publishing.modrinth.loaders=fabric
|
||||
publishing.modrinth.version.start=1.21
|
||||
publishing.modrinth.version.end=latest
|
||||
@@ -1 +1,8 @@
|
||||
org.gradle.jvmargs=-Xmx2000m
|
||||
|
||||
# TODO UPDATE
|
||||
fullVersion=2.9.1
|
||||
snapshot=false
|
||||
|
||||
publishing.display_name=PacketEvents
|
||||
publishing.modrinth.project=HYKaKraK
|
||||
+2
-2
@@ -38,8 +38,8 @@ velocity = { group = "com.velocitypowered", name = "velocity-api", version.ref =
|
||||
classgraph = { group = "io.github.classgraph", name = "classgraph", version.ref = "classgraph" }
|
||||
|
||||
[bundles]
|
||||
adventure = [ "adventure-api", "adventure-nbt", "adventure-key", "adventure-examination-api", "adventure-examination-string" ]
|
||||
adventure-serializers = [ "adventure-text-serializer-gson", "adventure-text-serializer-json-legacy", "adventure-text-serializer-legacy" ]
|
||||
adventure = ["adventure-api", "adventure-nbt", "adventure-key", "adventure-examination-api", "adventure-examination-string"]
|
||||
adventure-serializers = ["adventure-text-serializer-gson", "adventure-text-serializer-json-legacy", "adventure-text-serializer-legacy"]
|
||||
|
||||
[plugins]
|
||||
run-paper = { id = "xyz.jpenilla.run-paper", version.ref = "run-paper" }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
packetevents.`shadow-conventions`
|
||||
packetevents.`library-conventions`
|
||||
packetevents.`publish-conventions`
|
||||
alias(libs.plugins.run.paper)
|
||||
}
|
||||
|
||||
@@ -34,7 +35,7 @@ tasks {
|
||||
// 1.17 = Java 16
|
||||
// 1.18 - 1.20.4 = Java 17
|
||||
// 1.20.5+ = Java 21
|
||||
val version = "1.21.6"
|
||||
val version = "1.21.7"
|
||||
val javaVersion = JavaLanguageVersion.of(21)
|
||||
|
||||
val jvmArgsExternal = listOf(
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
publishing.platform=spigot
|
||||
publishing.modrinth.loaders=bukkit,spigot,paper,folia,purpur
|
||||
publishing.modrinth.version.start=1.8.8
|
||||
publishing.modrinth.version.end=latest
|
||||
+62
-42
@@ -19,73 +19,93 @@
|
||||
package io.github.retrooper.packetevents.bukkit;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.FakeChannelUtil;
|
||||
import io.github.retrooper.packetevents.injector.SpigotChannelInjector;
|
||||
import io.github.retrooper.packetevents.manager.player.PlayerManagerImpl;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.spigotmc.event.player.PlayerSpawnLocationEvent;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Used on Paper/Spigot before 1.20.5
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Internal
|
||||
public class InternalBukkitListener implements Listener {
|
||||
|
||||
static final String KICK_MESSAGE = "PacketEvents failed to inject into a channel";
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public InternalBukkitListener(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onSpawnInGame(PlayerSpawnLocationEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
SpigotChannelInjector injector = (SpigotChannelInjector) PacketEvents.getAPI().getInjector();
|
||||
User user = PacketEvents.getAPI().getPlayerManager().getUser(player);
|
||||
if (user == null) {
|
||||
//We did not inject this user
|
||||
Object channel = PacketEvents.getAPI().getPlayerManager().getChannel(player);
|
||||
if (channel == null) {
|
||||
return;
|
||||
}
|
||||
//Check if it is a fake connection...
|
||||
if (!FakeChannelUtil.isFakeChannel(channel) && (!PacketEvents.getAPI().isTerminated() || PacketEvents.getAPI().getSettings().isKickIfTerminated())) {
|
||||
//Kick them, if they are not a fake player.
|
||||
FoliaScheduler.getEntityScheduler().runDelayed(player, plugin, (o) -> {
|
||||
player.kickPlayer("PacketEvents failed to inject into a channel.");
|
||||
}, null, 0);
|
||||
}
|
||||
return;
|
||||
// this is the first event which is called after the player object has been created;
|
||||
// note that we can't extract the reference to the player's connection yet
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onLogin(PlayerLoginEvent event) {
|
||||
if (event.getResult() == PlayerLoginEvent.Result.ALLOWED) {
|
||||
this.onPreJoin(event.getPlayer());
|
||||
}
|
||||
|
||||
// Set bukkit player object in the injectors
|
||||
injector.updatePlayer(user, player);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.HIGHEST)
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
Object channel = PacketEvents.getAPI().getPlayerManager().getChannel(player);
|
||||
SpigotChannelInjector injector = (SpigotChannelInjector) PacketEvents.getAPI().getInjector();
|
||||
User user = PacketEvents.getAPI().getPlayerManager().getUser(player);
|
||||
if (user == null) {
|
||||
//We did not inject this user
|
||||
//Check if it is a fake connection...
|
||||
if (channel == null || !FakeChannelUtil.isFakeChannel(channel) && (!PacketEvents.getAPI().isTerminated() || PacketEvents.getAPI().getSettings().isKickIfTerminated())) {
|
||||
//Kick them, if they are not a fake player.
|
||||
FoliaScheduler.getEntityScheduler().runDelayed(player, plugin, (o) -> {
|
||||
player.kickPlayer("PacketEvents failed to inject into a channel.");
|
||||
}, null, 0);
|
||||
}
|
||||
// Set bukkit player object in the injectors
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
this.onPostJoin(event.getPlayer());
|
||||
}
|
||||
|
||||
void onPreJoin(Player player) {
|
||||
// save player in map for packet handler to consume
|
||||
PacketEventsAPI<?> api = PacketEvents.getAPI();
|
||||
Map<UUID, WeakReference<Player>> map = ((PlayerManagerImpl) api.getPlayerManager()).joiningPlayers;
|
||||
map.put(player.getUniqueId(), new WeakReference<>(player));
|
||||
}
|
||||
|
||||
void onPostJoin(Player player) {
|
||||
PacketEventsAPI<?> api = PacketEvents.getAPI();
|
||||
User user = api.getPlayerManager().getUser(player);
|
||||
if (user != null) {
|
||||
// update player reference in encoder/decoder (doesn't matter if this was already done)
|
||||
SpigotChannelInjector injector = (SpigotChannelInjector) PacketEvents.getAPI().getInjector();
|
||||
injector.setPlayer(user.getChannel(), player);
|
||||
// remove from map; this is probably already removed anyway, but just make sure
|
||||
((PlayerManagerImpl) api.getPlayerManager()).joiningPlayers.remove(player.getUniqueId());
|
||||
return;
|
||||
}
|
||||
|
||||
// It's possible that the player reference was set in the prior event.
|
||||
if (!injector.isPlayerSet(channel)) {
|
||||
injector.updatePlayer(user, player);
|
||||
// if this case occurs, we can't extract the connection from a fully joined player
|
||||
// or have internal connection for this player; this should not occur, kick them
|
||||
|
||||
// remove from map just to be sure
|
||||
((PlayerManagerImpl) api.getPlayerManager()).joiningPlayers.remove(player.getUniqueId());
|
||||
|
||||
Object channel = api.getPlayerManager().getChannel(player);
|
||||
if (channel != null && FakeChannelUtil.isFakeChannel(channel)
|
||||
|| (api.isTerminated() && !api.getSettings().isKickIfTerminated())) {
|
||||
// either fake channel or api terminated (and we don't kick)
|
||||
return;
|
||||
}
|
||||
|
||||
// delay by a tick
|
||||
FoliaScheduler.getEntityScheduler().runDelayed(player, this.plugin, __ -> {
|
||||
// only kick if the player is actually still connected
|
||||
if (player.isConnected()) {
|
||||
player.kickPlayer(KICK_MESSAGE);
|
||||
}
|
||||
}, null, 0);
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2025 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.retrooper.packetevents.bukkit;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.FakeChannelUtil;
|
||||
import io.github.retrooper.packetevents.injector.SpigotChannelInjector;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerLoginEvent;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import static io.github.retrooper.packetevents.bukkit.InternalBukkitListener.KICK_MESSAGE;
|
||||
|
||||
/**
|
||||
* Used on Paper 1.20.5-1.21.6 or Spigot 1.20.5+
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
public class InternalBukkitLoginListener implements Listener {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onLogin(PlayerLoginEvent event) {
|
||||
PacketEventsAPI<?> api = PacketEvents.getAPI();
|
||||
User user = api.getPlayerManager().getUser(event.getPlayer());
|
||||
if (user != null) {
|
||||
// if the user can be resolved from this player, save in encoder/decoder
|
||||
SpigotChannelInjector injector = (SpigotChannelInjector) api.getInjector();
|
||||
injector.updatePlayer(user, event.getPlayer());
|
||||
return; // we're done
|
||||
}
|
||||
Object channel = api.getPlayerManager().getChannel(event.getPlayer());
|
||||
if (channel != null && FakeChannelUtil.isFakeChannel(channel)
|
||||
|| (api.isTerminated() && !api.getSettings().isKickIfTerminated())) {
|
||||
// either fake channel or api terminated (and we don't kick)
|
||||
return;
|
||||
}
|
||||
// since 1.20.5 and cookie packets, CraftBukkit associates the login listener with the player
|
||||
// before calling the login event; if this fails on 1.20.5+, something broke a lot
|
||||
event.disallow(PlayerLoginEvent.Result.KICK_OTHER, KICK_MESSAGE);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of packetevents - https://github.com/retrooper/packetevents
|
||||
* Copyright (C) 2025 retrooper and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package io.github.retrooper.packetevents.bukkit;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.spigotmc.event.player.PlayerSpawnLocationEvent;
|
||||
|
||||
/**
|
||||
* Used on Paper 1.21.7+ because of changes due to their Configuration API;
|
||||
* This is a variant of the pre-1.20.5 {@link InternalBukkitListener}, as Paper
|
||||
* no longer creates a {@link Player} object during the configuration phase to align with vanilla.
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Internal
|
||||
public class InternalPaperListener implements Listener {
|
||||
|
||||
private final InternalBukkitListener delegate;
|
||||
|
||||
public InternalPaperListener(Plugin plugin) {
|
||||
this.delegate = new InternalBukkitListener(plugin);
|
||||
}
|
||||
|
||||
// this may seem like a random event to choose, but this is the first event which
|
||||
// is called after the player object has been created; note that we can't extract
|
||||
// the reference to the player's connection yet, like before 1.20.5
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onSpawnLocation(PlayerSpawnLocationEvent event) {
|
||||
this.delegate.onPreJoin(event.getPlayer());
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
this.delegate.onPostJoin(event.getPlayer());
|
||||
}
|
||||
}
|
||||
+16
-4
@@ -33,6 +33,8 @@ import com.github.retrooper.packetevents.settings.PacketEventsSettings;
|
||||
import com.github.retrooper.packetevents.util.LogManager;
|
||||
import com.github.retrooper.packetevents.util.PEVersion;
|
||||
import io.github.retrooper.packetevents.bukkit.InternalBukkitListener;
|
||||
import io.github.retrooper.packetevents.bukkit.InternalBukkitLoginListener;
|
||||
import io.github.retrooper.packetevents.bukkit.InternalPaperListener;
|
||||
import io.github.retrooper.packetevents.injector.SpigotChannelInjector;
|
||||
import io.github.retrooper.packetevents.injector.connection.ServerConnectionInitializer;
|
||||
import io.github.retrooper.packetevents.manager.InternalBukkitPacketListener;
|
||||
@@ -41,8 +43,8 @@ import io.github.retrooper.packetevents.manager.protocol.ProtocolManagerImpl;
|
||||
import io.github.retrooper.packetevents.manager.server.ServerManagerImpl;
|
||||
import io.github.retrooper.packetevents.netty.NettyManagerImpl;
|
||||
import io.github.retrooper.packetevents.util.BukkitLogManager;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import io.github.retrooper.packetevents.util.protocolsupport.ProtocolSupportUtil;
|
||||
import io.github.retrooper.packetevents.util.viaversion.CustomPipelineUtil;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
@@ -156,12 +158,22 @@ public class SpigotPacketEventsBuilder {
|
||||
getUpdateChecker().handleUpdateCheck();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Metrics metrics = new Metrics(plugin, 11327);
|
||||
//Just to have an idea of which versions of packetevents people use
|
||||
metrics.addCustomChart(new SimplePie("packetevents_version", () -> getVersion().toStringWithoutSnapshot()));
|
||||
Bukkit.getPluginManager().registerEvents(new InternalBukkitListener(plugin), plugin);
|
||||
|
||||
try {
|
||||
// register paper listener to support 1.21.7+ configuration api
|
||||
Class.forName("io.papermc.paper.connection.PlayerConnection");
|
||||
Bukkit.getPluginManager().registerEvents(new InternalPaperListener(plugin), plugin);
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
if (this.serverManager.getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
|
||||
// register instant-login listener for 1.20.5+
|
||||
Bukkit.getPluginManager().registerEvents(new InternalBukkitLoginListener(), plugin);
|
||||
} else {
|
||||
Bukkit.getPluginManager().registerEvents(new InternalBukkitListener(plugin), plugin);
|
||||
}
|
||||
}
|
||||
|
||||
if (lateBind) {
|
||||
//If late-bind is enabled, we still need to inject (after all plugins enabled).
|
||||
|
||||
+44
@@ -1,18 +1,62 @@
|
||||
package io.github.retrooper.packetevents.manager;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.protocol.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.LogManager;
|
||||
import com.github.retrooper.packetevents.wrapper.handshaking.client.WrapperHandshakingClientHandshake;
|
||||
import com.github.retrooper.packetevents.wrapper.login.server.WrapperLoginServerLoginSuccess;
|
||||
import io.github.retrooper.packetevents.injector.SpigotChannelInjector;
|
||||
import io.github.retrooper.packetevents.manager.player.PlayerManagerImpl;
|
||||
import io.github.retrooper.packetevents.util.protocolsupport.ProtocolSupportUtil;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public class InternalBukkitPacketListener extends com.github.retrooper.packetevents.manager.InternalPacketListener {
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
super.onPacketSend(event);
|
||||
|
||||
// process after generic internal listener has processed this packet
|
||||
if (event.getPacketType() == PacketType.Login.Server.LOGIN_SUCCESS) {
|
||||
WrapperLoginServerLoginSuccess packet = new WrapperLoginServerLoginSuccess(event);
|
||||
this.tryUpdatePlayerReference(event, event.getUser(), packet.getUserProfile().getUUID());
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.JOIN_GAME) {
|
||||
// try to update player reference again
|
||||
this.tryUpdatePlayerReference(event, event.getUser(), event.getUser().getUUID());
|
||||
}
|
||||
}
|
||||
|
||||
private void tryUpdatePlayerReference(PacketSendEvent event, User user, UUID playerId) {
|
||||
PacketEventsAPI<?> api = PacketEvents.getAPI();
|
||||
Map<UUID, WeakReference<Player>> map = ((PlayerManagerImpl) api.getPlayerManager()).joiningPlayers;
|
||||
WeakReference<Player> playerRef = map.remove(playerId);
|
||||
Player player = playerRef != null ? playerRef.get() : null;
|
||||
|
||||
// we don't care whether this player is null or not; if it is null,
|
||||
// our bukkit listener may have already handled everything or will be handling it
|
||||
if (player != null) {
|
||||
((SpigotChannelInjector) api.getInjector()).updatePlayer(user, player);
|
||||
if (api.getLogManager().isDebug()) {
|
||||
api.getLogManager().debug("Updated player reference on packet handling for " + player.getUniqueId());
|
||||
}
|
||||
// update player object in current packet event
|
||||
event.setPlayer(player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() == PacketType.Handshaking.Client.HANDSHAKE) {
|
||||
|
||||
+18
@@ -29,11 +29,29 @@ import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import io.github.retrooper.packetevents.util.protocolsupport.ProtocolSupportUtil;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class PlayerManagerImpl implements PlayerManager {
|
||||
|
||||
// we associate the user object with a UUID upon receiving the ClientboundGameProfilePacket;
|
||||
// but, as packets are send asynchronously, this causes a race condition between the packet being sent
|
||||
// and the main thread login logic; if the packet gets processed by packetevents before the main thread login
|
||||
// logic reaches the event where we process things, everything is fine; if not, the event won't know what
|
||||
// to do with the player and will kick them
|
||||
//
|
||||
// this map gets used early on in the login/join process, were we can't extract
|
||||
// a reference to the player's connection from the player;
|
||||
// this player reference may then get used by the packet handler to associate the user with a player
|
||||
// from inside the packet handler, ensuring consistent results regardless of which thread is faster
|
||||
@ApiStatus.Internal
|
||||
public final Map<UUID, WeakReference<Player>> joiningPlayers = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public int getPing(@NotNull Object player) {
|
||||
//Yay, we contributed this to Spigot and now we can use it on 1.17+ servers.
|
||||
|
||||
+3
-3
@@ -173,10 +173,10 @@ public class SpigotConversionUtil {
|
||||
Object nbt = SpigotReflectionUtil.convertWorldServerDimensionToNMSNbt(serverLevel);
|
||||
|
||||
NBTCompound peNbt = SpigotReflectionUtil.fromMinecraftNBT(nbt);
|
||||
ResourceLocation dimensionName = new ResourceLocation(SpigotReflectionUtil.getDimensionKey(serverLevel));
|
||||
int dimensionId = SpigotReflectionUtil.getDimensionId(serverLevel);
|
||||
ResourceLocation dimensionTypeName = new ResourceLocation(SpigotReflectionUtil.getDimensionKey(serverLevel));
|
||||
int dimensionTypeId = SpigotReflectionUtil.getDimensionId(serverLevel);
|
||||
return DimensionType.decode(peNbt, version.toClientVersion(),
|
||||
new SimpleTypesBuilderData(dimensionName, dimensionId));
|
||||
new SimpleTypesBuilderData(dimensionTypeName, dimensionTypeId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+39
-15
@@ -33,19 +33,35 @@ import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.MapMaker;
|
||||
import io.netty.buffer.PooledByteBufAllocator;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -79,7 +95,7 @@ public final class SpigotReflectionUtil {
|
||||
//Minecraft classes
|
||||
public static Class<?> MINECRAFT_SERVER_CLASS, NMS_PACKET_DATA_SERIALIZER_CLASS, NMS_ITEM_STACK_CLASS,
|
||||
NMS_IMATERIAL_CLASS, NMS_ENTITY_CLASS, ENTITY_PLAYER_CLASS, BOUNDING_BOX_CLASS, NMS_MINECRAFT_KEY_CLASS,
|
||||
ENTITY_HUMAN_CLASS, PLAYER_CONNECTION_CLASS, SERVER_COMMON_PACKETLISTENER_IMPL_CLASS, SERVER_CONNECTION_CLASS, NETWORK_MANAGER_CLASS, NMS_ENUM_PARTICLE_CLASS,
|
||||
ENTITY_HUMAN_CLASS, PLAYER_CONNECTION_CLASS, TRANSFER_COOKIE_CONNECTION_CLASS, SERVER_LOGIN_PACKET_LISTENER_IMPL_CLASS, SERVER_COMMON_PACKETLISTENER_IMPL_CLASS, SERVER_CONNECTION_CLASS, NETWORK_MANAGER_CLASS, NMS_ENUM_PARTICLE_CLASS,
|
||||
MOB_EFFECT_LIST_CLASS, NMS_ITEM_CLASS, DEDICATED_SERVER_CLASS, LEVEL_CLASS, SERVER_LEVEL_CLASS, ENUM_PROTOCOL_DIRECTION_CLASS,
|
||||
GAME_PROFILE_CLASS, CRAFT_WORLD_CLASS, CRAFT_SERVER_CLASS, CRAFT_PLAYER_CLASS, CRAFT_ENTITY_CLASS, CRAFT_ITEM_STACK_CLASS, CRAFT_PARTICLE_CLASS,
|
||||
LEVEL_ENTITY_GETTER_CLASS, ENTITY_ACCESS_CLASS, PERSISTENT_ENTITY_SECTION_MANAGER_CLASS, PAPER_ENTITY_LOOKUP_CLASS, CRAFT_MAGIC_NUMBERS_CLASS, IBLOCK_DATA_CLASS,
|
||||
@@ -95,7 +111,7 @@ public final class SpigotReflectionUtil {
|
||||
//Fields
|
||||
public static Field ENTITY_PLAYER_PING_FIELD, ENTITY_BOUNDING_BOX_FIELD, BYTE_BUF_IN_PACKET_DATA_SERIALIZER, DIMENSION_CODEC_FIELD,
|
||||
DYNAMIC_OPS_NBT_INSTANCE_FIELD, CHUNK_PROVIDER_SERVER_FIELD, CRAFT_PARTICLE_PARTICLES_FIELD, NMS_MK_KEY_FIELD, LEGACY_NMS_PARTICLE_KEY_FIELD, LEGACY_NMS_KEY_TO_NMS_PARTICLE,
|
||||
REMOTE_CHAT_SESSION_FIELD;
|
||||
REMOTE_CHAT_SESSION_FIELD, REGISTRY_KEY_LOCATION_FIELD;
|
||||
|
||||
//Methods
|
||||
public static Method IS_DEBUGGING, GET_CRAFT_PLAYER_HANDLE_METHOD, GET_CRAFT_ENTITY_HANDLE_METHOD, GET_CRAFT_WORLD_HANDLE_METHOD,
|
||||
@@ -108,7 +124,7 @@ public final class SpigotReflectionUtil {
|
||||
GET_DIMENSION_MANAGER, GET_DIMENSION_ID, GET_DIMENSION_KEY, CODEC_ENCODE_METHOD, DATA_RESULT_GET_METHOD,
|
||||
READ_NBT_FROM_STREAM_METHOD, WRITE_NBT_TO_STREAM_METHOD, STREAM_DECODER_DECODE, STREAM_ENCODER_ENCODE,
|
||||
CREATE_REGISTRY_RESOURCE_KEY, GET_REGISTRY_OR_THROW, GET_DIMENSION_TYPES, GET_REGISTRY_ID,
|
||||
NBT_ACCOUNTER_UNLIMITED_HEAP, GET_REGISTRY_KEY_LOCATION, CHUNK_CACHE_GET_IBLOCKACCESS, CHUNK_CACHE_GET_ICHUNKACCESS,
|
||||
NBT_ACCOUNTER_UNLIMITED_HEAP, CHUNK_CACHE_GET_IBLOCKACCESS, CHUNK_CACHE_GET_ICHUNKACCESS,
|
||||
IBLOCKACCESS_GET_BLOCK_DATA, CHUNK_GET_BLOCK_DATA, PLAYER_CHUNK_MAP_GET_PLAYER_CHUNK, PLAYER_CHUNK_GET_CHUNK;
|
||||
|
||||
//Constructors
|
||||
@@ -166,10 +182,7 @@ public final class SpigotReflectionUtil {
|
||||
GET_ENTITY_BY_ID_LEVEL_ENTITY_GETTER_METHOD = Reflection.getMethod(LEVEL_ENTITY_GETTER_CLASS, ENTITY_ACCESS_CLASS, 0, int.class);
|
||||
}
|
||||
if (DIMENSION_MANAGER_CLASS != null) {
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion() == ServerVersion.V_1_16
|
||||
|| PacketEvents.getAPI().getServerManager().getVersion() == ServerVersion.V_1_16_1) {
|
||||
GET_DIMENSION_KEY = Reflection.getMethod(LEVEL_CLASS, "getTypeKey", 0);
|
||||
}
|
||||
GET_DIMENSION_KEY = Reflection.getMethod(LEVEL_CLASS, "getTypeKey", 0);
|
||||
GET_DIMENSION_MANAGER = Reflection.getMethod(LEVEL_CLASS, DIMENSION_MANAGER_CLASS, 0);
|
||||
GET_DIMENSION_ID = Reflection.getMethod(DIMENSION_MANAGER_CLASS, int.class, 0);
|
||||
}
|
||||
@@ -243,7 +256,6 @@ public final class SpigotReflectionUtil {
|
||||
0, RESOURCE_KEY);
|
||||
GET_DIMENSION_TYPES = Reflection.getMethod(REGISTRY_ACCESS_FROZEN, REGISTRY, 0);
|
||||
GET_REGISTRY_ID = Reflection.getMethod(REGISTRY, int.class, 0, Object.class);
|
||||
GET_REGISTRY_KEY_LOCATION = Reflection.getMethod(RESOURCE_KEY, NMS_MINECRAFT_KEY_CLASS, 0);
|
||||
//Only need to check if the arguments are null. The lookup class being null is handled in the method.
|
||||
//Not checking if the arguments passed are null could lead to unintended behavior.
|
||||
if (IBLOCKACCESS_CLASS != null) {
|
||||
@@ -289,6 +301,7 @@ public final class SpigotReflectionUtil {
|
||||
}
|
||||
|
||||
REMOTE_CHAT_SESSION_FIELD = Reflection.getField(ENTITY_PLAYER_CLASS, REMOTE_CHAT_SESSION_CLASS, 0);
|
||||
REGISTRY_KEY_LOCATION_FIELD = Reflection.getField(RESOURCE_KEY, NMS_MINECRAFT_KEY_CLASS, 1);
|
||||
}
|
||||
|
||||
private static void initClasses() {
|
||||
@@ -305,9 +318,12 @@ public final class SpigotReflectionUtil {
|
||||
NMS_MINECRAFT_KEY_CLASS = getServerClass(IS_OBFUSCATED ? "resources.MinecraftKey" : "resources.ResourceLocation", "MinecraftKey");
|
||||
ENTITY_HUMAN_CLASS = getServerClass(IS_OBFUSCATED ? "world.entity.player.EntityHuman" : "world.entity.player.Player", "EntityHuman");
|
||||
PLAYER_CONNECTION_CLASS = getServerClass(IS_OBFUSCATED ? "server.network.PlayerConnection" : "server.network.ServerGamePacketListenerImpl", "PlayerConnection");
|
||||
SERVER_LOGIN_PACKET_LISTENER_IMPL_CLASS = getServerClass(IS_OBFUSCATED ? "server.network.LoginListener" : "server.network.ServerLoginPacketListenerImpl", "LoginListener");
|
||||
|
||||
//Only on 1.20.2
|
||||
// 1.20.2+
|
||||
SERVER_COMMON_PACKETLISTENER_IMPL_CLASS = getServerClass("server.network.ServerCommonPacketListenerImpl", "ServerCommonPacketListenerImpl");
|
||||
// 1.20.5+
|
||||
TRANSFER_COOKIE_CONNECTION_CLASS = getOBCClass("entity.CraftPlayer$TransferCookieConnection");
|
||||
|
||||
SERVER_CONNECTION_CLASS = getServerClass(IS_OBFUSCATED ? "server.network.ServerConnection" : "server.network.ServerConnectionListener", "ServerConnection");
|
||||
NETWORK_MANAGER_CLASS = getServerClass(IS_OBFUSCATED ? "network.NetworkManager" : "network.Connection", "NetworkManager");
|
||||
@@ -530,6 +546,9 @@ public final class SpigotReflectionUtil {
|
||||
return null;
|
||||
}
|
||||
ReflectionObject wrappedEntityPlayer = new ReflectionObject(entityPlayer, ENTITY_PLAYER_CLASS);
|
||||
if (TRANSFER_COOKIE_CONNECTION_CLASS != null) {
|
||||
return wrappedEntityPlayer.readObject(0, TRANSFER_COOKIE_CONNECTION_CLASS);
|
||||
}
|
||||
return wrappedEntityPlayer.readObject(0, SpigotReflectionUtil.PLAYER_CONNECTION_CLASS);
|
||||
}
|
||||
|
||||
@@ -579,8 +598,13 @@ public final class SpigotReflectionUtil {
|
||||
if (playerConnection == null) {
|
||||
return null;
|
||||
}
|
||||
Class<?> playerConnectionClass = SERVER_COMMON_PACKETLISTENER_IMPL_CLASS != null ?
|
||||
SERVER_COMMON_PACKETLISTENER_IMPL_CLASS : PLAYER_CONNECTION_CLASS;
|
||||
Class<?> playerConnectionClass;
|
||||
if (SERVER_COMMON_PACKETLISTENER_IMPL_CLASS != null) {
|
||||
playerConnectionClass = playerConnection.getClass() == SERVER_LOGIN_PACKET_LISTENER_IMPL_CLASS
|
||||
? SERVER_LOGIN_PACKET_LISTENER_IMPL_CLASS : SERVER_COMMON_PACKETLISTENER_IMPL_CLASS;
|
||||
} else {
|
||||
playerConnectionClass = PLAYER_CONNECTION_CLASS;
|
||||
}
|
||||
ReflectionObject wrapper = new ReflectionObject(playerConnection, playerConnectionClass);
|
||||
try {
|
||||
return wrapper.readObject(0, NETWORK_MANAGER_CLASS);
|
||||
@@ -707,7 +731,7 @@ public final class SpigotReflectionUtil {
|
||||
public static String getDimensionKey(Object worldServer) {
|
||||
try {
|
||||
Object resourceKey = GET_DIMENSION_KEY.invoke(worldServer);
|
||||
return GET_REGISTRY_KEY_LOCATION.invoke(resourceKey).toString();
|
||||
return REGISTRY_KEY_LOCATION_FIELD.get(resourceKey).toString();
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.spongepowered.plugin.metadata.model.PluginDependency
|
||||
plugins {
|
||||
packetevents.`shadow-conventions`
|
||||
packetevents.`library-conventions`
|
||||
packetevents.`publish-conventions`
|
||||
alias(libs.plugins.spongeGradle)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
publishing.platform=sponge
|
||||
publishing.modrinth.loaders=sponge
|
||||
publishing.modrinth.version.start=1.21
|
||||
publishing.modrinth.version.end=latest
|
||||
@@ -1,6 +1,7 @@
|
||||
plugins {
|
||||
packetevents.`shadow-conventions`
|
||||
packetevents.`library-conventions`
|
||||
packetevents.`publish-conventions`
|
||||
alias(libs.plugins.run.velocity)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
publishing.platform=velocity
|
||||
publishing.modrinth.loaders=velocity
|
||||
publishing.modrinth.version.start=1.7.10
|
||||
publishing.modrinth.version.end=latest
|
||||
Reference in new issue
Block a user