mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2026-11-04 17:00:19 -05:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79b09acb2a | ||
|
|
186f186e0a | ||
|
|
c4ae9122ce | ||
|
|
738cee2e6a | ||
|
|
d7431b9f1a | ||
|
|
f30dbcfd53 | ||
|
|
b2ef2de409 | ||
|
|
1df4692038 | ||
|
|
d2423c8ef7 | ||
|
|
c42a5f1e26 | ||
|
|
94860bbad0 | ||
|
|
8c61001642 | ||
|
|
ee747010aa | ||
|
|
6250026956 | ||
|
|
d91ec4b61a |
No files matched your search
@@ -0,0 +1,368 @@
|
||||
# Packet Wrappers
|
||||
|
||||
Type-safe wrappers around ProtocolLib `PacketContainer` objects.
|
||||
Each wrapper lives under `net.dmulloy2.protocol.wrappers`, organized by protocol phase then direction.
|
||||
|
||||
---
|
||||
|
||||
## Package layout
|
||||
|
||||
```
|
||||
net.dmulloy2.protocol/
|
||||
AbstractPacket.java # base class for all wrappers
|
||||
|
||||
wrappers/
|
||||
game/
|
||||
clientbound/
|
||||
WrappedClientbound<PacketName>Packet.java
|
||||
serverbound/
|
||||
WrappedServerbound<PacketName>Packet.java
|
||||
login/
|
||||
clientbound/ …
|
||||
serverbound/ …
|
||||
status/
|
||||
clientbound/ …
|
||||
serverbound/ …
|
||||
```
|
||||
|
||||
New NMS types that are reusable across multiple packets belong in the core ProtocolLib packages, not here:
|
||||
|
||||
| What | Where |
|
||||
|---|---------------------------------------------------------------------------------------|
|
||||
| New enum wrapper | inner enum + registration in `com.comphenix.protocol.wrappers.EnumWrappers |
|
||||
| New structure wrapper | `com.comphenix.protocol.wrappers.Wrapped<Name>.java` + getter in `AbstractStructure` |
|
||||
| Packet wrapper | `net.dmulloy2.protocol.wrappers.<phase>.<direction>.Wrapped<NMSPacketName>` |
|
||||
|
||||
---
|
||||
|
||||
## Class Structure
|
||||
|
||||
* Every wrapper extends `AbstractPacket`
|
||||
* There should be 3 constructors: no-args (create new packet with default values), all-args (create new packet with specified values), and from-container (wrap existing packet)
|
||||
* Then create getters and setters for each field in the packet, using the appropriate `StructureModifier` methods from `AbstractStructure`.
|
||||
|
||||
```java
|
||||
package net.dmulloy2.protocol.wrappers.game.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.PacketConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
public class WrappedServerboundAcceptTeleportationPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Client.TELEPORT_ACCEPT;
|
||||
|
||||
public WrappedServerboundAcceptTeleportationPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
handle.getModifier().writeDefaults();
|
||||
}
|
||||
|
||||
public WrappedServerboundAcceptTeleportationPacket(int id) {
|
||||
this(PacketConstructor.DEFAULT.withPacket(TYPE, new Class<?>[] { int.class }).createPacket(id));
|
||||
}
|
||||
|
||||
public WrappedServerboundAcceptTeleportationPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// getters and setters for packet fields
|
||||
}
|
||||
```
|
||||
|
||||
`AbstractPacket` validates the type and exposes `getHandle()`, `sendPacket(Player)`, and `receivePacket(Player)`.
|
||||
|
||||
---
|
||||
|
||||
## Reading and writing packet fields
|
||||
|
||||
Always go through `AbstractStructure`'s typed getters. Never touch `getModifier()` directly or read raw field indices without a type-checked accessor.
|
||||
|
||||
### Primitives
|
||||
|
||||
```java
|
||||
handle.getIntegers().read(0) // int
|
||||
handle.getIntegers().write(0, value)
|
||||
|
||||
handle.getBooleans().read(0) // boolean
|
||||
handle.getBooleans().write(0, value)
|
||||
|
||||
handle.getFloat().read(0) // float (note: singular, not getFloats)
|
||||
handle.getFloat().write(0, value)
|
||||
|
||||
handle.getLongs() / getDoubles() / getBytes() / getShorts() / getStrings() …
|
||||
```
|
||||
|
||||
Field indices within a type are zero-based and ordered by their declaration order in the NMS class.
|
||||
|
||||
### Bukkit / ProtocolLib wrapper types
|
||||
|
||||
```java
|
||||
handle.getVectors().read(0) // org.bukkit.util.Vector ↔ Vec3
|
||||
handle.getPositionMoveRotations().read(0) // WrappedPositionMoveRotation ↔ PositionMoveRotation
|
||||
handle.getEntityModifier(world).read(0) // org.bukkit.entity.Entity
|
||||
handle.getItemModifier().read(0) // org.bukkit.inventory.ItemStack
|
||||
handle.getBlockPositionModifier().read(0) // BlockPosition
|
||||
handle.getNbtModifier().read(0) // NbtBase<?>
|
||||
handle.getDataWatcherModifier().read(0) // WrappedDataWatcher
|
||||
// …see AbstractStructure for the full list
|
||||
```
|
||||
|
||||
### Enums
|
||||
|
||||
Use `EnumWrappers.get<Name>Converter()` with the appropriate accessor:
|
||||
|
||||
```java
|
||||
// Single enum field
|
||||
handle.getEnumModifier(EnumWrappers.Hand.class, EnumWrappers.getHandClass()).read(0)
|
||||
|
||||
// Set of enum values (e.g. RelativeArgument)
|
||||
handle.getSets(EnumWrappers.getRelativeArgumentConverter()).read(0)
|
||||
handle.getSets(EnumWrappers.getRelativeArgumentConverter()).write(0, set)
|
||||
```
|
||||
|
||||
### Nested structures (InternalStructure)
|
||||
|
||||
Only use `getStructures()` when you genuinely need to inspect a sub-structure that has no dedicated typed wrapper yet. Once you have written a `Wrapped<Name>` class, add a getter to `AbstractStructure` and use that instead.
|
||||
|
||||
---
|
||||
|
||||
## Adding a new NMS enum wrapper
|
||||
|
||||
1. **Declare** the enum as an inner class of `EnumWrappers`, matching NMS constant names exactly:
|
||||
|
||||
```java
|
||||
// EnumWrappers.java
|
||||
public enum RelativeArgument {
|
||||
X, Y, Z, Y_ROT, X_ROT, DELTA_X, DELTA_Y, DELTA_Z, ROTATE_DELTA
|
||||
}
|
||||
```
|
||||
|
||||
2. **Register** the NMS class, class getter, converter, and `associate()` call — all following the same pattern as `Hand`, `Direction`, etc.:
|
||||
|
||||
```java
|
||||
// static field
|
||||
private static Class<?> RELATIVE_CLASS = null;
|
||||
|
||||
// inside initialize() — class loading
|
||||
RELATIVE_CLASS = MinecraftReflection.getMinecraftClass("world.entity.Relative");
|
||||
|
||||
// inside initialize() — association
|
||||
associate(RELATIVE_CLASS, RelativeArgument.class, getRelativeArgumentConverter());
|
||||
|
||||
// public API
|
||||
public static Class<?> getRelativeArgumentClass() {
|
||||
initialize();
|
||||
return RELATIVE_CLASS;
|
||||
}
|
||||
|
||||
public static EquivalentConverter<RelativeArgument> getRelativeArgumentConverter() {
|
||||
return new EnumConverter<>(getRelativeArgumentClass(), RelativeArgument.class);
|
||||
}
|
||||
```
|
||||
|
||||
`EnumConverter` maps by constant name (`Enum.valueOf`). Use it whenever the NMS class **is** a real Java enum and the constant names match. Use `FauxEnumConverter` only for NMS classes that are enum-like but not `java.lang.Enum`.
|
||||
|
||||
---
|
||||
|
||||
## Adding a new NMS structure wrapper
|
||||
|
||||
`PositionMoveRotation` is the reference example.
|
||||
|
||||
### 1 — Create `com.comphenix.protocol.wrappers.Wrapped<Name>.java`
|
||||
|
||||
```java
|
||||
public class WrappedPositionMoveRotation {
|
||||
|
||||
// mutable fields matching the NMS record
|
||||
|
||||
/** Read from a live InternalStructure using AbstractStructure typed getters. */
|
||||
public static WrappedPositionMoveRotation fromHandle(InternalStructure handle) {
|
||||
WrappedPositionMoveRotation w = new WrappedPositionMoveRotation();
|
||||
Vector pos = handle.getVectors().read(0);
|
||||
Vector delta = handle.getVectors().read(1);
|
||||
w.x = pos.getX(); w.y = pos.getY(); w.z = pos.getZ();
|
||||
w.deltaX = delta.getX(); …
|
||||
w.yaw = handle.getFloat().read(0);
|
||||
w.pitch = handle.getFloat().read(1);
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an EquivalentConverter for use in StructureModifier.withType().
|
||||
*
|
||||
* getSpecific — delegates to fromHandle(InternalStructure)
|
||||
* getGeneric — constructs a new NMS record via its public constructor
|
||||
*/
|
||||
public static EquivalentConverter<WrappedPositionMoveRotation> getConverter() {
|
||||
return new EquivalentConverter<>() {
|
||||
@Override
|
||||
public WrappedPositionMoveRotation getSpecific(Object generic) {
|
||||
return fromHandle(InternalStructure.getConverter().getSpecific(generic));
|
||||
}
|
||||
@Override
|
||||
public Object getGeneric(WrappedPositionMoveRotation s) {
|
||||
try {
|
||||
Class<?> vec3 = MinecraftReflection.getVec3DClass();
|
||||
Class<?> pmr = MinecraftReflection.getMinecraftClass("world.entity.PositionMoveRotation");
|
||||
Constructor<?> v = vec3.getDeclaredConstructor(double.class, double.class, double.class);
|
||||
Constructor<?> p = pmr.getDeclaredConstructor(vec3, vec3, float.class, float.class);
|
||||
return p.newInstance(v.newInstance(s.x, s.y, s.z),
|
||||
v.newInstance(s.deltaX, s.deltaY, s.deltaZ),
|
||||
s.yaw, s.pitch);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@Override public Class<WrappedPositionMoveRotation> getSpecificType() {
|
||||
return WrappedPositionMoveRotation.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Reading** always goes through `AbstractStructure` getters (`getVectors()`, `getFloat()`, …) — never raw field accessors.
|
||||
**Writing** must construct a fresh NMS instance when the NMS type is an immutable record (final fields). Mutable NMS classes can be modified via their own `InternalStructure` instead.
|
||||
|
||||
### 2 — Add a getter to `AbstractStructure`
|
||||
|
||||
```java
|
||||
// AbstractStructure.java — alongside getVectors(), getIntegers(), etc.
|
||||
public StructureModifier<WrappedPositionMoveRotation> getPositionMoveRotations() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getMinecraftClass("world.entity.PositionMoveRotation"),
|
||||
WrappedPositionMoveRotation.getConverter());
|
||||
}
|
||||
```
|
||||
|
||||
### 3 — Use it in the packet wrapper
|
||||
|
||||
```java
|
||||
public WrappedPositionMoveRotation getChange() {
|
||||
return handle.getPositionMoveRotations().read(0);
|
||||
}
|
||||
|
||||
public void setChange(WrappedPositionMoveRotation change) {
|
||||
handle.getPositionMoveRotations().write(0, change);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Unit tests
|
||||
|
||||
Each wrapper class gets its own test file named `<WrapperClassName>Test.java`, co-located with the wrapper under `src/test/java/net/dmulloy2/protocol/wrappers/<phase>/<direction>/`. Do not combine tests for multiple wrappers in a single file.
|
||||
|
||||
Every test class must call `BukkitInitialization.initializeAll()` in a `@BeforeAll` method — this bootstraps the Minecraft registry and mocked Bukkit server required for `PacketContainer` and NMS reflection to work.
|
||||
|
||||
Cover these scenarios for each wrapper:
|
||||
|
||||
* testAllArgsCreate
|
||||
* Construct a fresh wrapper using the all-args constructor with known test values
|
||||
* Get the NMS handle packet via `getHandle()`
|
||||
* Assert that all fields in the NMS handle match the known test values
|
||||
* testNoArgsCreate
|
||||
* Construct a fresh wrapper using the no-args constructor
|
||||
* Get the NMS handle packet via `getHandle()`
|
||||
* Assert that all fields in the NMS handle are not null
|
||||
* testModifyExistingPacket
|
||||
* Create the NMS handle packet directly from its constructor, passing known test values
|
||||
* Create a packet container from the NMS handle via `PacketContainer.fromPacket()`
|
||||
* Construct the wrapper using the packet container
|
||||
* Assert that all fields in the wrapper match the known test values
|
||||
* Change all fields in the wrapper to new test values
|
||||
* Verify that the NMS handle packet reflects the new test values
|
||||
* testWrongPacketTypeThrows
|
||||
* Create a packet container for a different packet type
|
||||
* Attempt to construct the wrapper using this incorrect packet container
|
||||
* Assert that an appropriate exception is thrown (e.g. IllegalArgumentException)
|
||||
|
||||
### Appropriate test values
|
||||
|
||||
* For numeric fields, use a mix of positive, negative, and zero values (e.g. -5, 0, 3)
|
||||
* For enum fields, prefer the 2nd or 3rd constant rather than the first, to ensure the wrapper correctly handles non-default enum values
|
||||
* Additionally, if the enum constant is @Deprecated, do not use it
|
||||
|
||||
Here's a good example of a complete test class for `WrappedClientboundSetExperiencePacket`:
|
||||
|
||||
```java
|
||||
class WrappedClientboundSetExperiencePacketTest {
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
BukkitInitialization.initializeAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAllArgsCreate() {
|
||||
WrappedClientboundSetExperiencePacket w = new WrappedClientboundSetExperiencePacket(0.75f, 350, 12);
|
||||
|
||||
assertEquals(PacketType.Play.Server.EXPERIENCE, w.getHandle().getType());
|
||||
|
||||
ClientboundSetExperiencePacket p = (ClientboundSetExperiencePacket) w.getHandle().getHandle();
|
||||
|
||||
assertEquals(0.75f, p.getExperienceProgress(), 1e-4f);
|
||||
assertEquals(350, p.getTotalExperience());
|
||||
assertEquals(12, p.getExperienceLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoArgsCreate() {
|
||||
WrappedClientboundSetExperiencePacket w = new WrappedClientboundSetExperiencePacket();
|
||||
|
||||
assertEquals(PacketType.Play.Server.EXPERIENCE, w.getHandle().getType());
|
||||
|
||||
ClientboundSetExperiencePacket p = (ClientboundSetExperiencePacket) w.getHandle().getHandle();
|
||||
|
||||
assertEquals(0.0f, p.getExperienceProgress(), 1e-4f);
|
||||
assertEquals(0, p.getTotalExperience());
|
||||
assertEquals(0, p.getExperienceLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testModifyExistingPacket() {
|
||||
ClientboundSetExperiencePacket nmsPacket = new ClientboundSetExperiencePacket(
|
||||
0.5f, 100, 5
|
||||
);
|
||||
|
||||
PacketContainer container = PacketContainer.fromPacket(nmsPacket);
|
||||
WrappedClientboundSetExperiencePacket wrapper = new WrappedClientboundSetExperiencePacket(container);
|
||||
|
||||
assertEquals(0.5f, wrapper.getExperienceProgress(), 1e-4f);
|
||||
assertEquals(100, wrapper.getTotalExperience());
|
||||
assertEquals(5, wrapper.getExperienceLevel());
|
||||
|
||||
wrapper.setExperienceProgress(0.25f);
|
||||
wrapper.setTotalExperience(200);
|
||||
wrapper.setExperienceLevel(10);
|
||||
|
||||
assertEquals(0.25f, nmsPacket.getExperienceProgress(), 1e-4f);
|
||||
assertEquals(200, nmsPacket.getTotalExperience());
|
||||
assertEquals(10, nmsPacket.getExperienceLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testModifyExistingPacket() {
|
||||
ClientboundSetExperiencePacket nmsPacket = new ClientboundSetExperiencePacket(
|
||||
0.5f, 100, 5
|
||||
);
|
||||
|
||||
PacketContainer container = PacketContainer.fromPacket(nmsPacket);
|
||||
WrappedClientboundSetExperiencePacket wrapper = new WrappedClientboundSetExperiencePacket(container);
|
||||
|
||||
wrapper.setTotalExperience(200);
|
||||
|
||||
assertEquals(0.5f, wrapper.getExperienceProgress(), 1e-4f);
|
||||
assertEquals(200, wrapper.getTotalExperience());
|
||||
assertEquals(5, wrapper.getExperienceLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWrongPacketTypeThrows() {
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> new WrappedClientboundSetExperiencePacket(
|
||||
new PacketContainer(PacketType.Play.Server.CHAT)));
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -66,6 +66,7 @@ import com.comphenix.protocol.wrappers.WrappedServerPing;
|
||||
import com.comphenix.protocol.wrappers.WrappedStatistic;
|
||||
import com.comphenix.protocol.wrappers.WrappedTeamParameters;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.WrappedWeightedList;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
@@ -419,6 +420,16 @@ public abstract class AbstractStructure {
|
||||
BukkitConverters.getVectorConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for PositionMoveRotation fields.
|
||||
* @return A modifier for PositionMoveRotation fields.
|
||||
*/
|
||||
public StructureModifier<WrappedPositionMoveRotation> getPositionMoveRotations() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getMinecraftClass("world.entity.PositionMoveRotation"),
|
||||
WrappedPositionMoveRotation.getConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of attribute snapshots.
|
||||
* <p>
|
||||
@@ -803,6 +814,20 @@ public abstract class AbstractStructure {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for WeightedList fields.
|
||||
*
|
||||
* @param elementConverter converter for the element type inside each weighted entry
|
||||
* @param <T> the Bukkit-side element type
|
||||
* @return A modifier for WeightedList fields.
|
||||
*/
|
||||
public <T> StructureModifier<WrappedWeightedList<T>> getWeightedLists(
|
||||
EquivalentConverter<T> elementConverter) {
|
||||
return structureModifier.withType(
|
||||
WrappedWeightedList.getNmsClass(),
|
||||
WrappedWeightedList.getConverter(elementConverter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the MobEffectList class in 1.9.
|
||||
* @return A modifier for MobEffectList fields.
|
||||
@@ -818,6 +843,15 @@ public abstract class AbstractStructure {
|
||||
BukkitConverters.getEffectTypeConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for Bukkit {@code DamageType} values
|
||||
* stored in NMS {@code Holder<DamageType>} fields.
|
||||
* @return A modifier for Bukkit DamageType values.
|
||||
*/
|
||||
public StructureModifier<org.bukkit.damage.DamageType> getDamageTypes() {
|
||||
return getHolders(MinecraftReflection.getDamageTypeClass(), BukkitConverters.getDamageTypeConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the SoundCategory enum in 1.9.
|
||||
* @return A modifier for SoundCategory enum fields.
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.Tuple;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EquivalentConstructor {
|
||||
private final PacketType packetType;
|
||||
private final List<Tuple<Class<?>, Object>> converters = new ArrayList<>();
|
||||
|
||||
private volatile ConstructorAccessor constructorAccessor;
|
||||
|
||||
public EquivalentConstructor(PacketType packetType) {
|
||||
this.packetType = packetType;
|
||||
}
|
||||
|
||||
public EquivalentConstructor withParam(Class<?> param, EquivalentConverter<?> converter) {
|
||||
converters.add(new Tuple<>(param, converter));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EquivalentConstructor withParam(Class<?> param, PacketConstructor.Unwrapper unwrapper) {
|
||||
converters.add(new Tuple<>(param, unwrapper));
|
||||
return this;
|
||||
}
|
||||
|
||||
public EquivalentConstructor withParam(Class<?> param) {
|
||||
converters.add(new Tuple<>(param, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public Object create(Object... args) {
|
||||
if (args.length != converters.size()) {
|
||||
throw new IllegalArgumentException("Expected " + converters.size() + " args, got " + args.length);
|
||||
}
|
||||
|
||||
ConstructorAccessor accessor = getConstructorAccessor();
|
||||
Object[] convertedArgs = new Object[converters.size()];
|
||||
|
||||
int i = 0;
|
||||
for (Tuple<Class<?>, Object> entry : converters) {
|
||||
Object rawConverter = entry.second();
|
||||
if (rawConverter == null) {
|
||||
convertedArgs[i] = args[i];
|
||||
} else if (rawConverter instanceof EquivalentConverter converter) {
|
||||
convertedArgs[i] = converter.getGeneric(args[i]);
|
||||
} else if (rawConverter instanceof PacketConstructor.Unwrapper unwrapper) {
|
||||
convertedArgs[i] = unwrapper.unwrapItem(args[i]);
|
||||
} else {
|
||||
throw new IllegalStateException("Invalid converter type: " + rawConverter.getClass());
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return accessor.invoke(convertedArgs);
|
||||
}
|
||||
|
||||
private ConstructorAccessor getConstructorAccessor() {
|
||||
ConstructorAccessor accessor = constructorAccessor;
|
||||
if (accessor == null) {
|
||||
synchronized (this) {
|
||||
accessor = constructorAccessor;
|
||||
if (accessor != null) {
|
||||
return accessor;
|
||||
}
|
||||
|
||||
constructorAccessor = accessor = createConstructorAccessor();
|
||||
}
|
||||
}
|
||||
return accessor;
|
||||
}
|
||||
|
||||
private ConstructorAccessor createConstructorAccessor() {
|
||||
Class<?>[] params = new Class<?>[converters.size()];
|
||||
for (int i = 0; i < converters.size(); i++) {
|
||||
params[i] = converters.get(i).first();
|
||||
}
|
||||
|
||||
Constructor<?> ctor = FuzzyReflection.fromClass(packetType.getPacketClass(), true)
|
||||
.getConstructor(FuzzyMethodContract.newBuilder().parameterExactArray(params).build());
|
||||
return Accessors.getConstructorAccessor(ctor);
|
||||
}
|
||||
}
|
||||
@@ -928,6 +928,10 @@ public final class MinecraftReflection {
|
||||
return getMinecraftClass("world.effect.MobEffectList", "MobEffectList", "world.effect.MobEffect", "world.effect.MobEffects");
|
||||
}
|
||||
|
||||
public static Class<?> getDamageTypeClass() {
|
||||
return getMinecraftClass("world.damagesource.DamageType");
|
||||
}
|
||||
|
||||
public static Class<?> getSoundEffectClass() {
|
||||
return getNullableNMS("sounds.SoundEffect", "sounds.SoundEvent", "SoundEffect", "sounds.SoundEvents");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
public record Tuple<A, B>(A first, B second) {}
|
||||
@@ -22,6 +22,7 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.google.common.base.Defaults;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -165,16 +166,67 @@ public class AutoWrapper<T> implements EquivalentConverter<T> {
|
||||
nmsInstanceCreator = noArgs;
|
||||
nmsDefaultArgs = NO_ARGS;
|
||||
} else {
|
||||
// use the first constructor of the class
|
||||
nmsInstanceCreator = Accessors.getConstructorAccessor(nmsClass.getDeclaredConstructors()[0]);
|
||||
nmsDefaultArgs = Arrays
|
||||
.stream(nmsInstanceCreator.getConstructor().getParameterTypes())
|
||||
.map(type -> type.isPrimitive() ? Defaults.defaultValue(type) : null)
|
||||
.toArray(Object[]::new);
|
||||
// No no-arg constructor. For records (and most NMS data classes) the canonical
|
||||
// constructor has one parameter per non-static field; that's the one we want.
|
||||
// Other constructors (e.g. FriendlyByteBuf decoders) take a single network-buffer
|
||||
// argument and would call methods on it during construction, so they're unsafe to
|
||||
// invoke with default values.
|
||||
Constructor<?>[] ctors = nmsClass.getDeclaredConstructors();
|
||||
Constructor<?> chosen = selectConstructor(ctors);
|
||||
nmsInstanceCreator = Accessors.getConstructorAccessor(chosen);
|
||||
Class<?>[] paramTypes = chosen.getParameterTypes();
|
||||
nmsDefaultArgs = new Object[paramTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i++) {
|
||||
nmsDefaultArgs[i] = paramTypes[i].isPrimitive()
|
||||
? Defaults.defaultValue(paramTypes[i])
|
||||
: null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Constructor<?> selectConstructor(Constructor<?>[] ctors) {
|
||||
Constructor<?> fallback = null;
|
||||
for (Constructor<?> ctor : ctors) {
|
||||
if (isNetworkBufferConstructor(ctor)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ctor.getParameterCount() == nmsAccessors.length) {
|
||||
return ctor;
|
||||
}
|
||||
|
||||
if (fallback == null || ctor.getParameterCount() > fallback.getParameterCount()) {
|
||||
fallback = ctor;
|
||||
}
|
||||
}
|
||||
|
||||
if (fallback != null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
throw new InvalidWrapperException(nmsClass.getSimpleName()
|
||||
+ " has no safe constructor for default instantiation", null);
|
||||
}
|
||||
|
||||
private boolean isNetworkBufferConstructor(Constructor<?> ctor) {
|
||||
Class<?> packetDataSerializer = MinecraftReflection.getPacketDataSerializerClass();
|
||||
Class<?> registryByteBuf = MinecraftReflection.getRegistryFriendlyByteBufClass().orElse(null);
|
||||
for (Class<?> param : ctor.getParameterTypes()) {
|
||||
// Only treat the parameter as a network buffer if it's the buffer type itself or a subtype.
|
||||
// Using the reverse direction (param.isAssignableFrom(...)) would also exclude legitimate
|
||||
// ctors taking ByteBuf / Object / etc. as record components.
|
||||
if (packetDataSerializer.isAssignableFrom(param)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (registryByteBuf != null && registryByteBuf.isAssignableFrom(param)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ---- Equivalent conversion
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1436,6 +1436,67 @@ public class BukkitConverters {
|
||||
});
|
||||
}
|
||||
|
||||
// Lazily-resolved CraftDamageType reflection. volatile + DCL keeps the publish safe
|
||||
// and avoids re-running fuzzy lookups in concurrent injection paths.
|
||||
private static volatile MethodAccessor damageTypeToNms = null;
|
||||
private static volatile MethodAccessor damageTypeFromNms = null;
|
||||
|
||||
private static FuzzyReflection craftDamageTypeFuzzy() {
|
||||
return FuzzyReflection.fromClass(getCraftBukkitClass("damage.CraftDamageType"), false);
|
||||
}
|
||||
|
||||
private static MethodAccessor resolveDamageTypeToNms() {
|
||||
MethodAccessor accessor = damageTypeToNms;
|
||||
if (accessor != null) return accessor;
|
||||
synchronized (BukkitConverters.class) {
|
||||
accessor = damageTypeToNms;
|
||||
if (accessor != null) return accessor;
|
||||
accessor = Accessors.getMethodAccessor(craftDamageTypeFuzzy().getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactArray(org.bukkit.damage.DamageType.class)
|
||||
.returnTypeExact(MinecraftReflection.getDamageTypeClass())
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
damageTypeToNms = accessor;
|
||||
return accessor;
|
||||
}
|
||||
}
|
||||
|
||||
private static MethodAccessor resolveDamageTypeFromNms() {
|
||||
MethodAccessor accessor = damageTypeFromNms;
|
||||
if (accessor != null) return accessor;
|
||||
synchronized (BukkitConverters.class) {
|
||||
accessor = damageTypeFromNms;
|
||||
if (accessor != null) return accessor;
|
||||
accessor = Accessors.getMethodAccessor(craftDamageTypeFuzzy().getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactArray(MinecraftReflection.getDamageTypeClass())
|
||||
.returnTypeExact(org.bukkit.damage.DamageType.class)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.build()));
|
||||
damageTypeFromNms = accessor;
|
||||
return accessor;
|
||||
}
|
||||
}
|
||||
|
||||
public static EquivalentConverter<org.bukkit.damage.DamageType> getDamageTypeConverter() {
|
||||
return ignoreNull(new EquivalentConverter<org.bukkit.damage.DamageType>() {
|
||||
|
||||
@Override
|
||||
public Class<org.bukkit.damage.DamageType> getSpecificType() {
|
||||
return org.bukkit.damage.DamageType.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(org.bukkit.damage.DamageType specific) {
|
||||
return resolveDamageTypeToNms().invoke(null, specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.bukkit.damage.DamageType getSpecific(Object generic) {
|
||||
return (org.bukkit.damage.DamageType) resolveDamageTypeFromNms().invoke(null, generic);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Class<?> dimensionManager;
|
||||
private static FauxEnumConverter<Dimension> dimensionConverter;
|
||||
private static FauxEnumConverter<DimensionImpl> dimensionImplConverter;
|
||||
|
||||
@@ -46,8 +46,13 @@ public final class CustomPacketPayloadWrapper {
|
||||
private static final ConstructorAccessor PAYLOAD_WRAPPER_CONSTRUCTOR;
|
||||
|
||||
private static final MethodAccessor GET_ID_PAYLOAD_METHOD;
|
||||
private static final MethodAccessor GET_TYPE_PAYLOAD_METHOD;
|
||||
private static final MethodAccessor GET_ID_PAYLOAD_TYPE_METHOD;
|
||||
private static final MethodAccessor SERIALIZE_PAYLOAD_METHOD;
|
||||
|
||||
/** True when running on MC 1.21.5+ where DiscardedPayload is used instead of the ByteBuddy proxy. */
|
||||
private static final boolean USE_DISCARDED_PAYLOAD;
|
||||
|
||||
private static final EquivalentConverter<CustomPacketPayloadWrapper> CONVERTER;
|
||||
|
||||
static {
|
||||
@@ -55,22 +60,54 @@ public final class CustomPacketPayloadWrapper {
|
||||
MINECRAFT_KEY_CLASS = MinecraftReflection.getMinecraftKeyClass();
|
||||
CUSTOM_PACKET_PAYLOAD_CLASS = MinecraftReflection.getMinecraftClass("network.protocol.common.custom.CustomPacketPayload");
|
||||
|
||||
Method getPayloadId = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MINECRAFT_KEY_CLASS)
|
||||
.parameterCount(0)
|
||||
.build());
|
||||
GET_ID_PAYLOAD_METHOD = Accessors.getMethodAccessor(getPayloadId);
|
||||
// MC 1.21.5+: CustomPacketPayload no longer has id(); DiscardedPayload is the fallback payload
|
||||
// MC < 1.21.5: CustomPacketPayload.id() returns Identifier directly
|
||||
Method getPayloadId = null;
|
||||
Method getPayloadType = null;
|
||||
Method getPayloadTypeId = null;
|
||||
boolean useDiscardedPayload = false;
|
||||
try {
|
||||
getPayloadId = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeExact(MINECRAFT_KEY_CLASS)
|
||||
.parameterCount(0)
|
||||
.build());
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// New API: CustomPacketPayload.type().id() exposes the identifier for every payload type.
|
||||
getPayloadType = CUSTOM_PACKET_PAYLOAD_CLASS.getMethod("type");
|
||||
getPayloadTypeId = getPayloadType.getReturnType().getMethod("id");
|
||||
useDiscardedPayload = true;
|
||||
}
|
||||
GET_ID_PAYLOAD_METHOD = getPayloadId != null ? Accessors.getMethodAccessor(getPayloadId) : null;
|
||||
GET_TYPE_PAYLOAD_METHOD = getPayloadType != null ? Accessors.getMethodAccessor(getPayloadType) : null;
|
||||
GET_ID_PAYLOAD_TYPE_METHOD = getPayloadTypeId != null ? Accessors.getMethodAccessor(getPayloadTypeId) : null;
|
||||
USE_DISCARDED_PAYLOAD = useDiscardedPayload;
|
||||
|
||||
Method serializePayloadData = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeVoid()
|
||||
.parameterCount(1)
|
||||
.parameterDerivedOf(ByteBuf.class, 0)
|
||||
.build());
|
||||
SERIALIZE_PAYLOAD_METHOD = Accessors.getMethodAccessor(serializePayloadData);
|
||||
// serialize method may not exist in new API
|
||||
Method serializePayloadData = null;
|
||||
try {
|
||||
serializePayloadData = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeVoid()
|
||||
.parameterCount(1)
|
||||
.parameterDerivedOf(ByteBuf.class, 0)
|
||||
.build());
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
// Not present in new API
|
||||
}
|
||||
SERIALIZE_PAYLOAD_METHOD = serializePayloadData != null
|
||||
? Accessors.getMethodAccessor(serializePayloadData) : null;
|
||||
|
||||
Constructor<?> payloadWrapperConstructor = makePayloadWrapper();
|
||||
Constructor<?> payloadWrapperConstructor;
|
||||
if (useDiscardedPayload) {
|
||||
// New API: use DiscardedPayload(Identifier, ByteBuf) as the payload handle
|
||||
Class<?> discardedPayloadClass = MinecraftReflection.getMinecraftClass(
|
||||
"network.protocol.common.custom.DiscardedPayload");
|
||||
payloadWrapperConstructor = discardedPayloadClass.getConstructor(
|
||||
MINECRAFT_KEY_CLASS, ByteBuf.class);
|
||||
} else {
|
||||
payloadWrapperConstructor = makePayloadWrapper();
|
||||
}
|
||||
PAYLOAD_WRAPPER_CONSTRUCTOR = Accessors.getConstructorAccessor(payloadWrapperConstructor);
|
||||
|
||||
CONVERTER = new EquivalentConverter<CustomPacketPayloadWrapper>() {
|
||||
@@ -171,8 +208,7 @@ public final class CustomPacketPayloadWrapper {
|
||||
* @return a wrapper holding the minecraft key and payload of the given custom payload instance.
|
||||
*/
|
||||
public static CustomPacketPayloadWrapper fromUnknownPayload(Object payload) {
|
||||
Object messageId = GET_ID_PAYLOAD_METHOD.invoke(payload);
|
||||
MinecraftKey id = MinecraftKey.getConverter().getSpecific(messageId);
|
||||
MinecraftKey id = getPayloadId(payload);
|
||||
|
||||
// we read and retain the underlying buffer in case the class uses a buffer to store the data
|
||||
// this way, when passing the packet to further handling, the buffer is not released and can be re-used
|
||||
@@ -185,6 +221,12 @@ public final class CustomPacketPayloadWrapper {
|
||||
return data;
|
||||
})
|
||||
.orElseGet(() -> {
|
||||
if (SERIALIZE_PAYLOAD_METHOD == null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Cannot extract raw custom payload bytes from " + payload.getClass().getName()
|
||||
+ ": payload has no ByteBuf field and this Minecraft version does not "
|
||||
+ "expose CustomPacketPayload serialization");
|
||||
}
|
||||
ByteBuf buffer = Unpooled.buffer();
|
||||
Object serializer = MinecraftReflection.getPacketDataSerializer(buffer);
|
||||
SERIALIZE_PAYLOAD_METHOD.invoke(payload, serializer);
|
||||
@@ -194,6 +236,17 @@ public final class CustomPacketPayloadWrapper {
|
||||
return new CustomPacketPayloadWrapper(messagePayload, id);
|
||||
}
|
||||
|
||||
private static MinecraftKey getPayloadId(Object payload) {
|
||||
Object messageId;
|
||||
if (GET_ID_PAYLOAD_METHOD != null) {
|
||||
messageId = GET_ID_PAYLOAD_METHOD.invoke(payload);
|
||||
} else {
|
||||
Object payloadType = GET_TYPE_PAYLOAD_METHOD.invoke(payload);
|
||||
messageId = GET_ID_PAYLOAD_TYPE_METHOD.invoke(payloadType);
|
||||
}
|
||||
return MinecraftKey.getConverter().getSpecific(messageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generic id of the wrapped message id.
|
||||
*
|
||||
@@ -230,6 +283,11 @@ public final class CustomPacketPayloadWrapper {
|
||||
* @return a new payload wrapper instance using the provided message id and payload.
|
||||
*/
|
||||
public Object newHandle() {
|
||||
if (USE_DISCARDED_PAYLOAD) {
|
||||
// New API: DiscardedPayload(Identifier, ByteBuf)
|
||||
ByteBuf buf = Unpooled.copiedBuffer(this.payload);
|
||||
return PAYLOAD_WRAPPER_CONSTRUCTOR.invoke(this.getGenericId(), buf);
|
||||
}
|
||||
return PAYLOAD_WRAPPER_CONSTRUCTOR.invoke(this.getGenericId(), this.payload);
|
||||
}
|
||||
|
||||
|
||||
@@ -724,6 +724,11 @@ public abstract class EnumWrappers {
|
||||
MOTION_BLOCKING_NO_LEAVES,
|
||||
}
|
||||
|
||||
public enum RelativeArgument {
|
||||
// Order must match the NMS Relative enum exactly.
|
||||
X, Y, Z, Y_ROT, X_ROT, DELTA_X, DELTA_Y, DELTA_Z, ROTATE_DELTA
|
||||
}
|
||||
|
||||
private static Class<?> PROTOCOL_CLASS = null;
|
||||
private static Class<?> CLIENT_COMMAND_CLASS = null;
|
||||
private static Class<?> CHAT_VISIBILITY_CLASS = null;
|
||||
@@ -752,6 +757,7 @@ public abstract class EnumWrappers {
|
||||
private static Class<?> TEAM_COLLISION_RULE_CLASS = null;
|
||||
private static Class<?> TEAM_VISIBILITY_CLASS = null;
|
||||
private static Class<?> HEIGHTMAP_TYPE_CLASS = null;
|
||||
private static Class<?> RELATIVE_CLASS = null;
|
||||
|
||||
private static boolean INITIALIZING = false;
|
||||
private static boolean INITIALIZED = false;
|
||||
@@ -874,6 +880,8 @@ public abstract class EnumWrappers {
|
||||
"world.level.levelgen.HeightMap$Type" /* Spigot Mapping */,
|
||||
"world.level.levelgen.Heightmap$Types" /* Mojang Mapping */);
|
||||
|
||||
RELATIVE_CLASS = MinecraftReflection.getMinecraftClass("world.entity.Relative");
|
||||
|
||||
associate(PROTOCOL_CLASS, Protocol.class, getProtocolConverter());
|
||||
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
|
||||
associate(CHAT_VISIBILITY_CLASS, ChatVisibility.class, getChatVisibilityConverter());
|
||||
@@ -901,6 +909,7 @@ public abstract class EnumWrappers {
|
||||
associate(TEAM_COLLISION_RULE_CLASS, TeamCollisionRule.class, getTeamCollisionRuleConverter());
|
||||
associate(TEAM_VISIBILITY_CLASS, TeamVisibility.class, getTeamVisibilityConverter());
|
||||
associate(HEIGHTMAP_TYPE_CLASS, HeightmapType.class, getHeightmapTypeConverter());
|
||||
associate(RELATIVE_CLASS, RelativeArgument.class, getRelativeArgumentConverter());
|
||||
|
||||
if (ENTITY_POSE_CLASS != null) {
|
||||
associate(ENTITY_POSE_CLASS, EntityPose.class, getEntityPoseConverter());
|
||||
@@ -1090,6 +1099,11 @@ public abstract class EnumWrappers {
|
||||
return HEIGHTMAP_TYPE_CLASS;
|
||||
}
|
||||
|
||||
public static Class<?> getRelativeArgumentClass() {
|
||||
initialize();
|
||||
return RELATIVE_CLASS;
|
||||
}
|
||||
|
||||
// Get the converters
|
||||
public static EquivalentConverter<Protocol> getProtocolConverter() {
|
||||
return new EnumConverter<>(getProtocolClass(), Protocol.class);
|
||||
@@ -1199,6 +1213,10 @@ public abstract class EnumWrappers {
|
||||
return new EnumConverter<>(getHeightmapTypeClass(), HeightmapType.class);
|
||||
}
|
||||
|
||||
public static EquivalentConverter<RelativeArgument> getRelativeArgumentConverter() {
|
||||
return new EnumConverter<>(getRelativeArgumentClass(), RelativeArgument.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 1.13+
|
||||
* @return {@link EnumConverter} or null (if bellow 1.13 / nms EnumPose class cannot be found)
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ChatType.Bound}.
|
||||
*/
|
||||
public final class WrappedChatTypeBound {
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getMinecraftClass("network.chat.ChatType$Bound");
|
||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
HANDLE_TYPE,
|
||||
MinecraftReflection.getHolderClass(),
|
||||
MinecraftReflection.getIChatBaseComponentClass(),
|
||||
Optional.class);
|
||||
private static final MethodAccessor GET_CHAT_TYPE = Accessors.getMethodAccessor(HANDLE_TYPE, "chatType");
|
||||
private static final MethodAccessor GET_NAME = Accessors.getMethodAccessor(HANDLE_TYPE, "name");
|
||||
private static final MethodAccessor GET_TARGET_NAME = Accessors.getMethodAccessor(HANDLE_TYPE, "targetName");
|
||||
|
||||
private static final EquivalentConverter<MinecraftKey> CHAT_TYPE_HOLDER_CONVERTER =
|
||||
new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(MinecraftKey specific) {
|
||||
return chatTypeHolderConverter().getGeneric(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftKey getSpecific(Object generic) {
|
||||
return chatTypeHolderConverter().getSpecific(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MinecraftKey> getSpecificType() {
|
||||
return MinecraftKey.class;
|
||||
}
|
||||
};
|
||||
|
||||
public static final EquivalentConverter<WrappedChatTypeBound> CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedChatTypeBound specific) {
|
||||
return CONSTRUCTOR.invoke(
|
||||
CHAT_TYPE_HOLDER_CONVERTER.getGeneric(specific.chatType),
|
||||
BukkitConverters.getWrappedChatComponentConverter().getGeneric(specific.name),
|
||||
Converters.optional(BukkitConverters.getWrappedChatComponentConverter())
|
||||
.getGeneric(specific.targetName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedChatTypeBound getSpecific(Object generic) {
|
||||
return new WrappedChatTypeBound(
|
||||
CHAT_TYPE_HOLDER_CONVERTER.getSpecific(GET_CHAT_TYPE.invoke(generic)),
|
||||
BukkitConverters.getWrappedChatComponentConverter().getSpecific(GET_NAME.invoke(generic)),
|
||||
Converters.optional(BukkitConverters.getWrappedChatComponentConverter())
|
||||
.getSpecific(GET_TARGET_NAME.invoke(generic)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedChatTypeBound> getSpecificType() {
|
||||
return WrappedChatTypeBound.class;
|
||||
}
|
||||
});
|
||||
|
||||
private final MinecraftKey chatType;
|
||||
private final WrappedChatComponent name;
|
||||
private final Optional<WrappedChatComponent> targetName;
|
||||
|
||||
public WrappedChatTypeBound(MinecraftKey chatType, WrappedChatComponent name,
|
||||
Optional<WrappedChatComponent> targetName) {
|
||||
this.chatType = chatType;
|
||||
this.name = name;
|
||||
this.targetName = targetName;
|
||||
}
|
||||
|
||||
public MinecraftKey getChatType() {
|
||||
return chatType;
|
||||
}
|
||||
|
||||
public WrappedChatComponent getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Optional<WrappedChatComponent> getTargetName() {
|
||||
return targetName;
|
||||
}
|
||||
|
||||
private static EquivalentConverter<MinecraftKey> chatTypeHolderConverter() {
|
||||
WrappedRegistry registry = WrappedRegistry.getRegistryByNmsKey("core.registries.Registries", "CHAT_TYPE");
|
||||
if (registry == null) {
|
||||
throw new IllegalStateException("ChatType registry is not available");
|
||||
}
|
||||
return Converters.holder(registry.valueConverter(), registry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedChatTypeBound that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(chatType, that.chatType)
|
||||
&& Objects.equals(name, that.name)
|
||||
&& Objects.equals(targetName, that.targetName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(chatType, name, targetName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundChunksBiomesPacket.ChunkBiomeData}.
|
||||
*/
|
||||
public final class WrappedChunkBiomeData {
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getMinecraftClass(
|
||||
"network.protocol.game.ClientboundChunksBiomesPacket$ChunkBiomeData");
|
||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
HANDLE_TYPE,
|
||||
MinecraftReflection.getChunkCoordIntPair(),
|
||||
byte[].class);
|
||||
private static final MethodAccessor GET_POS = Accessors.getMethodAccessor(HANDLE_TYPE, "pos");
|
||||
private static final MethodAccessor GET_BUFFER = Accessors.getMethodAccessor(HANDLE_TYPE, "buffer");
|
||||
|
||||
public static final EquivalentConverter<WrappedChunkBiomeData> CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedChunkBiomeData specific) {
|
||||
return CONSTRUCTOR.invoke(
|
||||
ChunkCoordIntPair.getConverter().getGeneric(specific.position),
|
||||
specific.buffer.clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedChunkBiomeData getSpecific(Object generic) {
|
||||
return new WrappedChunkBiomeData(
|
||||
ChunkCoordIntPair.getConverter().getSpecific(GET_POS.invoke(generic)),
|
||||
((byte[]) GET_BUFFER.invoke(generic)).clone());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedChunkBiomeData> getSpecificType() {
|
||||
return WrappedChunkBiomeData.class;
|
||||
}
|
||||
});
|
||||
|
||||
private final ChunkCoordIntPair position;
|
||||
private final byte[] buffer;
|
||||
|
||||
public WrappedChunkBiomeData(ChunkCoordIntPair position, byte[] buffer) {
|
||||
this.position = position;
|
||||
this.buffer = buffer.clone();
|
||||
}
|
||||
|
||||
public ChunkCoordIntPair getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public byte[] getBuffer() {
|
||||
return buffer.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedChunkBiomeData that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(position, that.position) && Arrays.equals(buffer, that.buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(position);
|
||||
result = 31 * result + Arrays.hashCode(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedChunkBiomeData{position=" + position + ", buffer=" + Arrays.toString(buffer) + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.comphenix.protocol.events.InternalStructure;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Wraps the NMS {@code ExplosionParticleInfo} record, which pairs a
|
||||
* {@link WrappedParticle} with scaling and speed float values.
|
||||
*
|
||||
* <p>NMS record: {@code ExplosionParticleInfo(ParticleOptions particle, float scaling, float speed)}
|
||||
*/
|
||||
public class WrappedExplosionParticleInfo {
|
||||
|
||||
private static final Class<?> NMS_CLASS;
|
||||
private static final ConstructorAccessor NMS_CTOR;
|
||||
|
||||
static {
|
||||
NMS_CLASS = MinecraftReflection.getMinecraftClass("core.particles.ExplosionParticleInfo");
|
||||
NMS_CTOR = Accessors.getConstructorAccessor(
|
||||
NMS_CLASS,
|
||||
MinecraftReflection.getParticleParam(),
|
||||
float.class,
|
||||
float.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NMS {@code ExplosionParticleInfo} class.
|
||||
*/
|
||||
public static Class<?> getNmsClass() {
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
// ── Instance data ────────────────────────────────────────────────────
|
||||
|
||||
private WrappedParticle<?> particle;
|
||||
private float scaling;
|
||||
private float speed;
|
||||
|
||||
public WrappedExplosionParticleInfo() {
|
||||
this.scaling = 1.0f;
|
||||
this.speed = 1.0f;
|
||||
}
|
||||
|
||||
public WrappedExplosionParticleInfo(WrappedParticle<?> particle, float scaling, float speed) {
|
||||
this.particle = particle;
|
||||
this.scaling = scaling;
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public WrappedParticle<?> getParticle() {
|
||||
return particle;
|
||||
}
|
||||
|
||||
public void setParticle(WrappedParticle<?> particle) {
|
||||
this.particle = particle;
|
||||
}
|
||||
|
||||
public float getScaling() {
|
||||
return scaling;
|
||||
}
|
||||
|
||||
public void setScaling(float scaling) {
|
||||
this.scaling = scaling;
|
||||
}
|
||||
|
||||
public float getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
public void setSpeed(float speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
// ── Converter ────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Reads an NMS {@code ExplosionParticleInfo} into this wrapper via
|
||||
* {@link InternalStructure} typed getters.
|
||||
*/
|
||||
public static WrappedExplosionParticleInfo fromHandle(InternalStructure handle) {
|
||||
WrappedParticle<?> particle = handle.getNewParticles().read(0);
|
||||
float scaling = handle.getFloat().read(0);
|
||||
float speed = handle.getFloat().read(1);
|
||||
return new WrappedExplosionParticleInfo(particle, scaling, speed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link EquivalentConverter} between {@code WrappedExplosionParticleInfo}
|
||||
* and the NMS {@code ExplosionParticleInfo} record.
|
||||
*/
|
||||
public static EquivalentConverter<WrappedExplosionParticleInfo> getConverter() {
|
||||
return new EquivalentConverter<>() {
|
||||
|
||||
@Override
|
||||
public WrappedExplosionParticleInfo getSpecific(Object generic) {
|
||||
InternalStructure structure = InternalStructure.getConverter().getSpecific(generic);
|
||||
return fromHandle(structure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(WrappedExplosionParticleInfo specific) {
|
||||
EquivalentConverter<WrappedParticle> particleConverter = BukkitConverters.getParticleConverter();
|
||||
Object nmsParticle = particleConverter.getGeneric(specific.particle);
|
||||
return NMS_CTOR.invoke(nmsParticle, specific.scaling, specific.speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedExplosionParticleInfo> getSpecificType() {
|
||||
return WrappedExplosionParticleInfo.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ── Object methods ───────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof WrappedExplosionParticleInfo that)) return false;
|
||||
return Float.compare(scaling, that.scaling) == 0
|
||||
&& Float.compare(speed, that.speed) == 0
|
||||
&& Objects.equals(particle, that.particle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(particle, scaling, speed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedExplosionParticleInfo{particle=" + particle
|
||||
+ ", scaling=" + scaling + ", speed=" + speed + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code net.minecraft.server.packs.repository.KnownPack}.
|
||||
*/
|
||||
public final class WrappedKnownPack {
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getMinecraftClass("server.packs.repository.KnownPack");
|
||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
HANDLE_TYPE,
|
||||
String.class,
|
||||
String.class,
|
||||
String.class);
|
||||
private static final MethodAccessor GET_NAMESPACE = Accessors.getMethodAccessor(HANDLE_TYPE, "namespace");
|
||||
private static final MethodAccessor GET_ID = Accessors.getMethodAccessor(HANDLE_TYPE, "id");
|
||||
private static final MethodAccessor GET_VERSION = Accessors.getMethodAccessor(HANDLE_TYPE, "version");
|
||||
|
||||
public static final EquivalentConverter<WrappedKnownPack> CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedKnownPack specific) {
|
||||
return CONSTRUCTOR.invoke(specific.namespace, specific.id, specific.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedKnownPack getSpecific(Object generic) {
|
||||
return new WrappedKnownPack(
|
||||
(String) GET_NAMESPACE.invoke(generic),
|
||||
(String) GET_ID.invoke(generic),
|
||||
(String) GET_VERSION.invoke(generic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedKnownPack> getSpecificType() {
|
||||
return WrappedKnownPack.class;
|
||||
}
|
||||
});
|
||||
|
||||
private final String namespace;
|
||||
private final String id;
|
||||
private final String version;
|
||||
|
||||
public WrappedKnownPack(String namespace, String id, String version) {
|
||||
this.namespace = namespace;
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getNamespace() {
|
||||
return namespace;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedKnownPack that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(namespace, that.namespace)
|
||||
&& Objects.equals(id, that.id)
|
||||
&& Objects.equals(version, that.version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(namespace, id, version);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedKnownPack{"
|
||||
+ "namespace='" + namespace + '\''
|
||||
+ ", id='" + id + '\''
|
||||
+ ", version='" + version + '\''
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code LastSeenMessages.Update}.
|
||||
*/
|
||||
public final class WrappedLastSeenMessagesUpdate {
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getMinecraftClass("network.chat.LastSeenMessages$Update");
|
||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
HANDLE_TYPE,
|
||||
int.class,
|
||||
BitSet.class,
|
||||
byte.class);
|
||||
private static final MethodAccessor GET_OFFSET = Accessors.getMethodAccessor(HANDLE_TYPE, "offset");
|
||||
private static final MethodAccessor GET_ACKNOWLEDGED = Accessors.getMethodAccessor(HANDLE_TYPE, "acknowledged");
|
||||
private static final MethodAccessor GET_CHECKSUM = Accessors.getMethodAccessor(HANDLE_TYPE, "checksum");
|
||||
|
||||
public static final EquivalentConverter<WrappedLastSeenMessagesUpdate> CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedLastSeenMessagesUpdate specific) {
|
||||
return CONSTRUCTOR.invoke(specific.offset, specific.getAcknowledged(), specific.checksum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedLastSeenMessagesUpdate getSpecific(Object generic) {
|
||||
return new WrappedLastSeenMessagesUpdate(
|
||||
(int) GET_OFFSET.invoke(generic),
|
||||
(BitSet) GET_ACKNOWLEDGED.invoke(generic),
|
||||
(byte) GET_CHECKSUM.invoke(generic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedLastSeenMessagesUpdate> getSpecificType() {
|
||||
return WrappedLastSeenMessagesUpdate.class;
|
||||
}
|
||||
});
|
||||
|
||||
private final int offset;
|
||||
private final BitSet acknowledged;
|
||||
private final byte checksum;
|
||||
|
||||
public WrappedLastSeenMessagesUpdate(int offset, BitSet acknowledged, byte checksum) {
|
||||
this.offset = offset;
|
||||
this.acknowledged = (BitSet) acknowledged.clone();
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
public BitSet getAcknowledged() {
|
||||
return (BitSet) acknowledged.clone();
|
||||
}
|
||||
|
||||
public byte getChecksum() {
|
||||
return checksum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedLastSeenMessagesUpdate that)) {
|
||||
return false;
|
||||
}
|
||||
return offset == that.offset
|
||||
&& checksum == that.checksum
|
||||
&& Objects.equals(acknowledged, that.acknowledged);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(offset, acknowledged, checksum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedLastSeenMessagesUpdate{"
|
||||
+ "offset=" + offset
|
||||
+ ", acknowledged=" + acknowledged
|
||||
+ ", checksum=" + checksum
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code NewMinecartBehavior.MinecartStep}.
|
||||
*/
|
||||
public final class WrappedMinecartStep {
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getMinecraftClass(
|
||||
"world.entity.vehicle.minecart.NewMinecartBehavior$MinecartStep");
|
||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
HANDLE_TYPE,
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
float.class,
|
||||
float.class,
|
||||
float.class);
|
||||
private static final MethodAccessor GET_POSITION = Accessors.getMethodAccessor(HANDLE_TYPE, "position");
|
||||
private static final MethodAccessor GET_MOVEMENT = Accessors.getMethodAccessor(HANDLE_TYPE, "movement");
|
||||
private static final MethodAccessor GET_Y_ROT = Accessors.getMethodAccessor(HANDLE_TYPE, "yRot");
|
||||
private static final MethodAccessor GET_X_ROT = Accessors.getMethodAccessor(HANDLE_TYPE, "xRot");
|
||||
private static final MethodAccessor GET_WEIGHT = Accessors.getMethodAccessor(HANDLE_TYPE, "weight");
|
||||
|
||||
public static final EquivalentConverter<WrappedMinecartStep> CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedMinecartStep specific) {
|
||||
EquivalentConverter<Vector> vectorConverter = BukkitConverters.getVectorConverter();
|
||||
return CONSTRUCTOR.invoke(
|
||||
vectorConverter.getGeneric(specific.position),
|
||||
vectorConverter.getGeneric(specific.movement),
|
||||
specific.yRot,
|
||||
specific.xRot,
|
||||
specific.weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedMinecartStep getSpecific(Object generic) {
|
||||
EquivalentConverter<Vector> vectorConverter = BukkitConverters.getVectorConverter();
|
||||
return new WrappedMinecartStep(
|
||||
vectorConverter.getSpecific(GET_POSITION.invoke(generic)),
|
||||
vectorConverter.getSpecific(GET_MOVEMENT.invoke(generic)),
|
||||
(float) GET_Y_ROT.invoke(generic),
|
||||
(float) GET_X_ROT.invoke(generic),
|
||||
(float) GET_WEIGHT.invoke(generic));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedMinecartStep> getSpecificType() {
|
||||
return WrappedMinecartStep.class;
|
||||
}
|
||||
});
|
||||
|
||||
private final Vector position;
|
||||
private final Vector movement;
|
||||
private final float yRot;
|
||||
private final float xRot;
|
||||
private final float weight;
|
||||
|
||||
public WrappedMinecartStep(Vector position, Vector movement, float yRot, float xRot, float weight) {
|
||||
this.position = position.clone();
|
||||
this.movement = movement.clone();
|
||||
this.yRot = yRot;
|
||||
this.xRot = xRot;
|
||||
this.weight = weight;
|
||||
}
|
||||
|
||||
public Vector getPosition() {
|
||||
return position.clone();
|
||||
}
|
||||
|
||||
public Vector getMovement() {
|
||||
return movement.clone();
|
||||
}
|
||||
|
||||
public float getYRot() {
|
||||
return yRot;
|
||||
}
|
||||
|
||||
public float getXRot() {
|
||||
return xRot;
|
||||
}
|
||||
|
||||
public float getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedMinecartStep that)) {
|
||||
return false;
|
||||
}
|
||||
return Float.compare(yRot, that.yRot) == 0
|
||||
&& Float.compare(xRot, that.xRot) == 0
|
||||
&& Float.compare(weight, that.weight) == 0
|
||||
&& Objects.equals(position, that.position)
|
||||
&& Objects.equals(movement, that.movement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(position, movement, yRot, xRot, weight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedMinecartStep{"
|
||||
+ "position=" + position
|
||||
+ ", movement=" + movement
|
||||
+ ", yRot=" + yRot
|
||||
+ ", xRot=" + xRot
|
||||
+ ", weight=" + weight
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,48 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftRegistryAccess;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class WrappedRegistry {
|
||||
// map of NMS class to registry instance
|
||||
// map of NMS class to registry instance (static/built-in registries)
|
||||
private static final Map<Class<?>, WrappedRegistry> REGISTRY;
|
||||
|
||||
// map of NMS class to ResourceKey for dynamic (datapack) registries
|
||||
private static final Map<Class<?>, Object> DYNAMIC_REGISTRY_KEYS;
|
||||
|
||||
// ResourceKeys to try when generic metadata is unavailable or incomplete
|
||||
private static final Set<Object> DYNAMIC_REGISTRY_FALLBACK_KEYS;
|
||||
|
||||
// cache of dynamically resolved registries
|
||||
private static final Map<Class<?>, WrappedRegistry> DYNAMIC_REGISTRY_CACHE = new ConcurrentHashMap<>();
|
||||
private static final Map<Object, WrappedRegistry> DYNAMIC_REGISTRY_KEY_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
// RegistryAccess.lookup(ResourceKey) -> Optional<Registry>
|
||||
private static final MethodAccessor REGISTRY_ACCESS_LOOKUP;
|
||||
|
||||
private static final MethodAccessor GET;
|
||||
private static final MethodAccessor GET_ID;
|
||||
private static final MethodAccessor GET_KEY;
|
||||
@@ -78,13 +98,69 @@ public class WrappedRegistry {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException ignored) {
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
ProtocolLogger.debug("Failed to inspect built-in registry field " + field, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTRY = ImmutableMap.copyOf(regMap);
|
||||
|
||||
// Build dynamic registry key map from Registries class (ResourceKey<Registry<T>> fields)
|
||||
// These cover datapack registries like DamageType that are not in BuiltInRegistries
|
||||
Map<Class<?>, Object> dynKeyMap = new HashMap<>();
|
||||
// LinkedHashSet so the generics-stripped fallback iterates in declaration order
|
||||
// on Registries, giving deterministic resolution across JVM runs.
|
||||
Set<Object> dynKeyFallbacks = new LinkedHashSet<>();
|
||||
try {
|
||||
Class<?> registriesClass = MinecraftReflection.getNullableNMS("core.registries.Registries");
|
||||
Class<?> resourceKeyClass = MinecraftReflection.getResourceKey();
|
||||
if (registriesClass != null) {
|
||||
for (Field field : registriesClass.getFields()) {
|
||||
if (!Modifier.isStatic(field.getModifiers())) continue;
|
||||
if (!resourceKeyClass.isAssignableFrom(field.getType())) continue;
|
||||
|
||||
Object registryKey;
|
||||
try {
|
||||
registryKey = field.get(null);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
ProtocolLogger.debug("Failed to read dynamic registry key field " + field, ex);
|
||||
continue;
|
||||
}
|
||||
dynKeyFallbacks.add(registryKey);
|
||||
|
||||
// looking for ResourceKey<Registry<T>> fields
|
||||
Class<?> entryClass = getRegistryEntryClass(field, iRegistry);
|
||||
if (entryClass != null && !regMap.containsKey(entryClass)) {
|
||||
dynKeyMap.put(entryClass, registryKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ProtocolLogger.debug("Failed to inspect dynamic registry keys", ex);
|
||||
}
|
||||
DYNAMIC_REGISTRY_KEYS = ImmutableMap.copyOf(dynKeyMap);
|
||||
DYNAMIC_REGISTRY_FALLBACK_KEYS = Collections.unmodifiableSet(dynKeyFallbacks);
|
||||
|
||||
// Set up RegistryAccess.lookup(ResourceKey) -> Optional<Registry>
|
||||
MethodAccessor registryAccessLookup = null;
|
||||
try {
|
||||
Class<?> registryAccessClass = MinecraftReflection.getRegistryAccessClass();
|
||||
if (registryAccessClass != null) {
|
||||
registryAccessLookup = Accessors.getMethodAccessor(
|
||||
FuzzyReflection.fromClass(registryAccessClass, false).getMethod(
|
||||
FuzzyMethodContract.newBuilder()
|
||||
.parameterExactArray(MinecraftReflection.getResourceKey())
|
||||
.returnTypeExact(Optional.class)
|
||||
.build()
|
||||
)
|
||||
);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ProtocolLogger.debug("Failed to find RegistryAccess.lookup(ResourceKey)", ex);
|
||||
}
|
||||
REGISTRY_ACCESS_LOOKUP = registryAccessLookup;
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(iRegistry, false);
|
||||
GET = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract
|
||||
.newBuilder()
|
||||
@@ -117,17 +193,53 @@ public class WrappedRegistry {
|
||||
.returnTypeExact(MinecraftReflection.getHolderClass())
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.build()));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
} catch (IllegalArgumentException ex) {
|
||||
ProtocolLogger.debug("Failed to find Registry.getHolder method", ex);
|
||||
}
|
||||
}
|
||||
|
||||
GET_HOLDER = getHolder;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Class<?> getRegistryEntryClass(Field field, Class<?> iRegistry) {
|
||||
Type genType = field.getGenericType();
|
||||
if (!(genType instanceof ParameterizedType)) return null;
|
||||
ParameterizedType outer = (ParameterizedType) genType;
|
||||
if (outer.getActualTypeArguments().length != 1) return null;
|
||||
|
||||
Type innerType = outer.getActualTypeArguments()[0];
|
||||
if (!(innerType instanceof ParameterizedType)) return null;
|
||||
ParameterizedType registryType = (ParameterizedType) innerType;
|
||||
if (!(registryType.getRawType() instanceof Class<?>)) return null;
|
||||
|
||||
Class<?> rawRegistry = (Class<?>) registryType.getRawType();
|
||||
if (iRegistry != null && !iRegistry.isAssignableFrom(rawRegistry)) return null;
|
||||
if (registryType.getActualTypeArguments().length != 1) return null;
|
||||
|
||||
Type entryType = registryType.getActualTypeArguments()[0];
|
||||
if (entryType instanceof Class<?>) {
|
||||
return (Class<?>) entryType;
|
||||
} else if (entryType instanceof ParameterizedType) {
|
||||
Type raw = ((ParameterizedType) entryType).getRawType();
|
||||
if (raw instanceof Class<?>) return (Class<?>) raw;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private final Object handle;
|
||||
|
||||
/** The NMS {@code ResourceKey<Registry<T>>} for this registry, if known. */
|
||||
@Nullable
|
||||
private final Object registryKey;
|
||||
|
||||
private WrappedRegistry(Object handle) {
|
||||
this(handle, null);
|
||||
}
|
||||
|
||||
private WrappedRegistry(Object handle, @Nullable Object registryKey) {
|
||||
this.handle = handle;
|
||||
this.registryKey = registryKey;
|
||||
}
|
||||
|
||||
public Object get(MinecraftKey key) {
|
||||
@@ -155,6 +267,10 @@ public class WrappedRegistry {
|
||||
}
|
||||
|
||||
public Object getHolder(Object generic) {
|
||||
if (GET_HOLDER == null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Registry holder conversion is not available on this Minecraft version");
|
||||
}
|
||||
return GET_HOLDER.invoke(handle, generic);
|
||||
}
|
||||
|
||||
@@ -170,7 +286,193 @@ public class WrappedRegistry {
|
||||
return getRegistry(MinecraftReflection.getSoundEffectClass());
|
||||
}
|
||||
|
||||
// Sentinel for negative dynamic-registry lookups. ConcurrentHashMap forbids null
|
||||
// values, so we cache this to avoid re-walking every fallback registry on every miss.
|
||||
private static final WrappedRegistry MISS_SENTINEL = new WrappedRegistry(new Object());
|
||||
|
||||
public static WrappedRegistry getRegistry(Class<?> type) {
|
||||
return REGISTRY.get(type);
|
||||
WrappedRegistry registry = REGISTRY.get(type);
|
||||
if (registry != null) {
|
||||
return registry;
|
||||
}
|
||||
|
||||
// Fall back to dynamic (datapack) registry lookup via RegistryAccess
|
||||
WrappedRegistry cached = DYNAMIC_REGISTRY_CACHE.computeIfAbsent(type, t -> {
|
||||
Object resourceKey = DYNAMIC_REGISTRY_KEYS.get(t);
|
||||
WrappedRegistry dynamicRegistry = lookupDynamicRegistry(resourceKey);
|
||||
if (dynamicRegistry != null) {
|
||||
return dynamicRegistry;
|
||||
}
|
||||
|
||||
WrappedRegistry byValueType = findDynamicRegistryByValueType(t);
|
||||
return byValueType != null ? byValueType : MISS_SENTINEL;
|
||||
});
|
||||
return cached == MISS_SENTINEL ? null : cached;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static WrappedRegistry findDynamicRegistryByValueType(Class<?> type) {
|
||||
for (Object resourceKey : DYNAMIC_REGISTRY_FALLBACK_KEYS) {
|
||||
WrappedRegistry registry = lookupDynamicRegistry(resourceKey);
|
||||
if (registry != null && registryContainsValueType(registry.handle, type)) {
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean registryContainsValueType(Object registryHandle, Class<?> type) {
|
||||
if (!(registryHandle instanceof Iterable<?> iterable)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Object entry : iterable) {
|
||||
if (type.isInstance(entry)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static WrappedRegistry lookupDynamicRegistry(@Nullable Object resourceKey) {
|
||||
if (resourceKey == null || REGISTRY_ACCESS_LOOKUP == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return DYNAMIC_REGISTRY_KEY_CACHE.computeIfAbsent(resourceKey, key -> {
|
||||
Object registryAccess = MinecraftRegistryAccess.get();
|
||||
if (registryAccess == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Optional<?> optRegistry = (Optional<?>) REGISTRY_ACCESS_LOOKUP.invoke(registryAccess, key);
|
||||
if (optRegistry == null || optRegistry.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new WrappedRegistry(optRegistry.get(), key);
|
||||
});
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// ResourceKey helpers
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the NMS {@code ResourceKey<Registry<T>>} that identifies this registry,
|
||||
* or {@code null} if it is not known (e.g. for built-in registries resolved only
|
||||
* by type scanning).
|
||||
*/
|
||||
@Nullable
|
||||
public Object getRegistryKey() {
|
||||
return registryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link MinecraftKey} entry location to the corresponding NMS
|
||||
* {@code ResourceKey<T>} scoped to this registry.
|
||||
*
|
||||
* @param key the entry identifier (e.g. {@code minecraft:diamond})
|
||||
* @return the NMS {@code ResourceKey<T>} handle
|
||||
* @throws IllegalStateException if this registry's own key is not known
|
||||
*/
|
||||
public Object toResourceKey(MinecraftKey key) {
|
||||
if (registryKey == null) {
|
||||
throw new IllegalStateException("Registry key is not known for this WrappedRegistry instance");
|
||||
}
|
||||
return WrappedResourceKey.of(registryKey, key).getHandle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a NMS {@code ResourceKey<T>} back to the {@link MinecraftKey}
|
||||
* representing the entry location.
|
||||
*
|
||||
* @param nmsResourceKey the NMS {@code ResourceKey} object
|
||||
* @return the entry identifier
|
||||
*/
|
||||
public static MinecraftKey fromResourceKey(Object nmsResourceKey) {
|
||||
return WrappedResourceKey.fromHandle(nmsResourceKey).getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link EquivalentConverter} between
|
||||
* {@link MinecraftKey} and NMS {@code ResourceKey<T>} for this registry.
|
||||
*
|
||||
* @throws IllegalStateException if this registry's own key is not known
|
||||
*/
|
||||
public EquivalentConverter<MinecraftKey> resourceKeyConverter() {
|
||||
if (registryKey == null) {
|
||||
throw new IllegalStateException("Registry key is not known for this WrappedRegistry instance");
|
||||
}
|
||||
return WrappedResourceKey.converterFor(registryKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link EquivalentConverter} between
|
||||
* {@link MinecraftKey} and the NMS registry value type {@code T} (e.g. {@code MenuType<?>},
|
||||
* {@code SoundEvent}). The converter resolves both directions through this registry's
|
||||
* {@code get(ResourceLocation)} / {@code getKey(value)} methods.
|
||||
*
|
||||
* <p>Use this for fields whose declared NMS type is the registry value itself, as opposed
|
||||
* to {@code ResourceKey<T>} (use {@link #resourceKeyConverter()}) or {@code Holder<T>}
|
||||
* (use {@link Converters#holder}).
|
||||
*/
|
||||
public EquivalentConverter<MinecraftKey> valueConverter() {
|
||||
final WrappedRegistry self = this;
|
||||
return new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(MinecraftKey specific) {
|
||||
return specific == null ? null : self.get(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftKey getSpecific(Object generic) {
|
||||
return generic == null ? null : self.getKey(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MinecraftKey> getSpecificType() {
|
||||
return MinecraftKey.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Named registry accessors
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a {@link WrappedRegistry} backed by the NMS {@code GameRule} registry
|
||||
* ({@code Registries.GAME_RULE}). The returned instance supports
|
||||
* {@link #toResourceKey(MinecraftKey)} and {@link #resourceKeyConverter()}.
|
||||
*
|
||||
* @return the game-rule registry, or {@code null} if unavailable at this time
|
||||
*/
|
||||
@Nullable
|
||||
public static WrappedRegistry getGameRuleRegistry() {
|
||||
return getRegistryByNmsKey("core.registries.Registries", "GAME_RULE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up a registry by the name of a static {@code ResourceKey<Registry<T>>}
|
||||
* field on the NMS {@code Registries} class.
|
||||
*
|
||||
* @param registriesClassName the NMS class name (e.g. {@code "core.registries.Registries"})
|
||||
* @param fieldName the field name on that class (e.g. {@code "GAME_RULE"})
|
||||
* @return a {@link WrappedRegistry} with both the handle and the registry key set,
|
||||
* or {@code null} if the lookup fails
|
||||
*/
|
||||
@Nullable
|
||||
public static WrappedRegistry getRegistryByNmsKey(String registriesClassName, String fieldName) {
|
||||
try {
|
||||
Class<?> registriesClass = MinecraftReflection.getMinecraftClass(registriesClassName);
|
||||
Object regKey = registriesClass.getField(fieldName).get(null);
|
||||
|
||||
return lookupDynamicRegistry(regKey);
|
||||
} catch (Exception ex) {
|
||||
ProtocolLogger.debug("Failed to resolve registry key " + registriesClassName + "." + fieldName, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Wrapper around the NMS {@code ResourceKey<T>} class.
|
||||
*
|
||||
* <p>A {@code ResourceKey} pairs a registry identifier (e.g. {@code minecraft:item})
|
||||
* with an entry location (e.g. {@code minecraft:diamond}) to form a fully-qualified
|
||||
* reference into a Minecraft registry.
|
||||
*
|
||||
* <p>All reflective lookups are done with {@link FuzzyReflection} so they are
|
||||
* independent of Mojang vs. Yarn/intermediary method names.
|
||||
*/
|
||||
public final class WrappedResourceKey {
|
||||
|
||||
// ResourceKey#location() / ResourceKey#identifier() → ResourceLocation
|
||||
private static final MethodAccessor GET_LOCATION;
|
||||
|
||||
// static ResourceKey#create(ResourceKey<Registry<T>>, ResourceLocation) → ResourceKey<T>
|
||||
private static final MethodAccessor CREATE;
|
||||
|
||||
static {
|
||||
Class<?> resourceKeyClass = MinecraftReflection.getResourceKey();
|
||||
Class<?> resourceLocClass = MinecraftReflection.getMinecraftKeyClass();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(resourceKeyClass, false);
|
||||
|
||||
// Resolve location() / identifier() by name first (mapping-specific names are known),
|
||||
// then fall back to fuzzy if neither exists. We must NOT pick registry() by accident —
|
||||
// that also returns ResourceLocation but is the registry namespace, not the entry path.
|
||||
MethodAccessor getLocation = null;
|
||||
for (String candidate : new String[]{"location", "identifier", "getLocation"}) {
|
||||
try {
|
||||
Method m = resourceKeyClass.getMethod(candidate);
|
||||
if (m.getReturnType().equals(resourceLocClass)) {
|
||||
getLocation = Accessors.getMethodAccessor(m);
|
||||
break;
|
||||
}
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
}
|
||||
if (getLocation == null) {
|
||||
// Last-resort fuzzy: pick the method whose simple name contains "location" or "identifier"
|
||||
getLocation = Accessors.getMethodAccessor(
|
||||
fuzzy.getMethodList(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(0)
|
||||
.banModifier(Modifier.STATIC)
|
||||
.returnTypeExact(resourceLocClass)
|
||||
.build())
|
||||
.stream()
|
||||
.filter(m -> {
|
||||
String n = m.getName().toLowerCase();
|
||||
return n.contains("location") || n.contains("identifier");
|
||||
})
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot find ResourceKey#location() method"))
|
||||
);
|
||||
}
|
||||
GET_LOCATION = getLocation;
|
||||
|
||||
// Find the static two-arg factory: create(ResourceKey<Registry<T>>, ResourceLocation)
|
||||
CREATE = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(2)
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.parameterExactArray(resourceKeyClass, resourceLocClass)
|
||||
.returnTypeExact(resourceKeyClass)
|
||||
.build()));
|
||||
}
|
||||
|
||||
private final Object handle;
|
||||
|
||||
private WrappedResourceKey(Object handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Factory / unwrap
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Wraps an existing NMS {@code ResourceKey} handle.
|
||||
*
|
||||
* @param handle the NMS object; must be an instance of {@code ResourceKey}
|
||||
* @return a new wrapper
|
||||
*/
|
||||
public static WrappedResourceKey fromHandle(Object handle) {
|
||||
if (handle == null) throw new NullPointerException("handle");
|
||||
return new WrappedResourceKey(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code ResourceKey<T>} pointing into the given registry.
|
||||
*
|
||||
* @param registryKey the NMS {@code ResourceKey<Registry<T>>} that identifies the registry
|
||||
* (e.g. the value of {@code Registries.ITEM})
|
||||
* @param location the entry identifier within that registry
|
||||
* @return a wrapper around the newly created {@code ResourceKey<T>}
|
||||
*/
|
||||
public static WrappedResourceKey of(Object registryKey, MinecraftKey location) {
|
||||
Object resourceLocation = MinecraftKey.getConverter().getGeneric(location);
|
||||
return new WrappedResourceKey(CREATE.invoke(null, registryKey, resourceLocation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw NMS {@code ResourceKey} handle.
|
||||
*/
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Accessors
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the entry location part of this key (e.g. {@code minecraft:diamond}).
|
||||
* This is the {@code ResourceLocation} / {@code Identifier} component, NOT the
|
||||
* registry identifier.
|
||||
*/
|
||||
public MinecraftKey getLocation() {
|
||||
Object resourceLocation = GET_LOCATION.invoke(handle);
|
||||
return MinecraftKey.getConverter().getSpecific(resourceLocation);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// EquivalentConverter factory
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns an {@link EquivalentConverter} that converts
|
||||
* between {@link MinecraftKey} (the entry location) and a NMS
|
||||
* {@code ResourceKey<T>} belonging to the supplied registry key.
|
||||
*
|
||||
* @param registryKey the NMS {@code ResourceKey<Registry<T>>} (e.g. {@code Registries.ITEM})
|
||||
*/
|
||||
public static EquivalentConverter<MinecraftKey> converterFor(Object registryKey) {
|
||||
return new EquivalentConverter<MinecraftKey>() {
|
||||
@Override
|
||||
public MinecraftKey getSpecific(Object generic) {
|
||||
return WrappedResourceKey.fromHandle(generic).getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(MinecraftKey specific) {
|
||||
return WrappedResourceKey.of(registryKey, specific).getHandle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MinecraftKey> getSpecificType() {
|
||||
return MinecraftKey.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedResourceKey{" + handle + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code TagNetworkSerialization.NetworkPayload}.
|
||||
*/
|
||||
public final class WrappedTagPayload {
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getMinecraftClass(
|
||||
"tags.TagNetworkSerialization$NetworkPayload");
|
||||
private static final ConstructorAccessor CONSTRUCTOR = Accessors.getConstructorAccessor(HANDLE_TYPE, Map.class);
|
||||
private static final FieldAccessor TAGS = Accessors.getFieldAccessor(HANDLE_TYPE, Map.class, true);
|
||||
private static final ConstructorAccessor INT_ARRAY_LIST_CONSTRUCTOR =
|
||||
Accessors.getConstructorAccessor(MinecraftReflection.getIntArrayListClass(), Collection.class);
|
||||
private static final MethodAccessor CREATE_REGISTRY_KEY = Accessors.getMethodAccessor(
|
||||
MinecraftReflection.getResourceKey(),
|
||||
"createRegistryKey",
|
||||
MinecraftReflection.getMinecraftKeyClass());
|
||||
|
||||
public static final EquivalentConverter<MinecraftKey> REGISTRY_KEY_CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(MinecraftKey specific) {
|
||||
return CREATE_REGISTRY_KEY.invoke(null, MinecraftKey.getConverter().getGeneric(specific));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftKey getSpecific(Object generic) {
|
||||
return WrappedResourceKey.fromHandle(generic).getLocation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<MinecraftKey> getSpecificType() {
|
||||
return MinecraftKey.class;
|
||||
}
|
||||
});
|
||||
|
||||
public static final EquivalentConverter<WrappedTagPayload> CONVERTER =
|
||||
Converters.ignoreNull(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedTagPayload specific) {
|
||||
Map<Object, Object> tags = new HashMap<>();
|
||||
for (Map.Entry<MinecraftKey, List<Integer>> entry : specific.tags.entrySet()) {
|
||||
tags.put(
|
||||
MinecraftKey.getConverter().getGeneric(entry.getKey()),
|
||||
INT_ARRAY_LIST_CONSTRUCTOR.invoke(entry.getValue()));
|
||||
}
|
||||
return CONSTRUCTOR.invoke(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedTagPayload getSpecific(Object generic) {
|
||||
Map<?, ?> genericTags = (Map<?, ?>) TAGS.get(generic);
|
||||
Map<MinecraftKey, List<Integer>> tags = new HashMap<>();
|
||||
for (Map.Entry<?, ?> entry : genericTags.entrySet()) {
|
||||
List<Integer> ids = new ArrayList<>();
|
||||
for (Object id : (Iterable<?>) entry.getValue()) {
|
||||
ids.add((Integer) id);
|
||||
}
|
||||
tags.put(MinecraftKey.getConverter().getSpecific(entry.getKey()), ids);
|
||||
}
|
||||
return new WrappedTagPayload(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedTagPayload> getSpecificType() {
|
||||
return WrappedTagPayload.class;
|
||||
}
|
||||
});
|
||||
|
||||
private final Map<MinecraftKey, List<Integer>> tags;
|
||||
|
||||
public WrappedTagPayload(Map<MinecraftKey, List<Integer>> tags) {
|
||||
this.tags = copy(tags);
|
||||
}
|
||||
|
||||
public Map<MinecraftKey, List<Integer>> getTags() {
|
||||
return copy(tags);
|
||||
}
|
||||
|
||||
private static Map<MinecraftKey, List<Integer>> copy(Map<MinecraftKey, List<Integer>> tags) {
|
||||
Map<MinecraftKey, List<Integer>> copy = new HashMap<>();
|
||||
for (Map.Entry<MinecraftKey, List<Integer>> entry : tags.entrySet()) {
|
||||
copy.put(entry.getKey(), List.copyOf(entry.getValue()));
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof WrappedTagPayload that)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(tags, that.tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedTagPayload{tags=" + tags + '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
/**
|
||||
* Wraps the NMS {@code WeightedList<E>} type, representing a list of weighted
|
||||
* entries where each entry has a value and an integer weight.
|
||||
*
|
||||
* <p>The element type {@code T} is the <em>Bukkit / ProtocolLib</em> representation
|
||||
* of the NMS element type, converted via the supplied {@link EquivalentConverter}.
|
||||
*
|
||||
* @param <T> the Bukkit-side element type
|
||||
*/
|
||||
public class WrappedWeightedList<T> {
|
||||
|
||||
// ── NMS reflection handles (eagerly resolved at class load) ──────────
|
||||
|
||||
private static final Class<?> WEIGHTED_LIST_CLASS;
|
||||
private static final Class<?> WEIGHTED_CLASS;
|
||||
|
||||
private static final MethodAccessor WEIGHTED_LIST_OF; // static WeightedList.of(List<Weighted>)
|
||||
private static final MethodAccessor WEIGHTED_LIST_UNWRAP; // WeightedList.unwrap() → List<Weighted>
|
||||
private static final ConstructorAccessor WEIGHTED_CTOR; // new Weighted(Object value, int weight)
|
||||
private static final MethodAccessor WEIGHTED_VALUE; // Weighted.value()
|
||||
private static final MethodAccessor WEIGHTED_WEIGHT; // Weighted.weight()
|
||||
|
||||
static {
|
||||
WEIGHTED_LIST_CLASS = MinecraftReflection.getMinecraftClass("util.random.WeightedList");
|
||||
WEIGHTED_CLASS = MinecraftReflection.getMinecraftClass("util.random.Weighted");
|
||||
|
||||
WEIGHTED_LIST_OF = Accessors.getMethodAccessor(WEIGHTED_LIST_CLASS, "of", List.class);
|
||||
WEIGHTED_LIST_UNWRAP = Accessors.getMethodAccessor(WEIGHTED_LIST_CLASS, "unwrap");
|
||||
|
||||
WEIGHTED_CTOR = Accessors.getConstructorAccessor(WEIGHTED_CLASS, Object.class, int.class);
|
||||
WEIGHTED_VALUE = Accessors.getMethodAccessor(WEIGHTED_CLASS, "value");
|
||||
WEIGHTED_WEIGHT = Accessors.getMethodAccessor(WEIGHTED_CLASS, "weight");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NMS {@code WeightedList} class.
|
||||
*/
|
||||
public static Class<?> getNmsClass() {
|
||||
return WEIGHTED_LIST_CLASS;
|
||||
}
|
||||
|
||||
// ── Instance data ────────────────────────────────────────────────────
|
||||
|
||||
private final List<Entry<T>> entries;
|
||||
|
||||
public WrappedWeightedList() {
|
||||
this.entries = new ArrayList<>();
|
||||
}
|
||||
|
||||
public WrappedWeightedList(List<Entry<T>> entries) {
|
||||
this.entries = new ArrayList<>(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mutable view of the entries in this weighted list. Mutations are
|
||||
* reflected on this wrapper.
|
||||
*/
|
||||
public List<Entry<T>> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all entries with the given list. The argument is copied; subsequent
|
||||
* modifications to it are not reflected on this wrapper.
|
||||
*/
|
||||
public void setEntries(List<Entry<T>> entries) {
|
||||
this.entries.clear();
|
||||
this.entries.addAll(entries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a single entry.
|
||||
*/
|
||||
public void addEntry(Entry<T> entry) {
|
||||
this.entries.add(entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a single value/weight entry.
|
||||
*/
|
||||
public void addEntry(T value, int weight) {
|
||||
this.entries.add(new Entry<>(value, weight));
|
||||
}
|
||||
|
||||
// ── Entry record ─────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* A single weighted entry pairing a value with an integer weight.
|
||||
*
|
||||
* @param <T> the Bukkit-side element type
|
||||
*/
|
||||
public record Entry<T>(T value, int weight) {
|
||||
/** Backwards-compatible accessor for callers that used {@code getValue()}. */
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Backwards-compatible accessor for callers that used {@code getWeight()}. */
|
||||
public int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Converter factory ────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Creates an {@link EquivalentConverter} that converts between
|
||||
* {@code WrappedWeightedList<T>} and the NMS {@code WeightedList<E>}.
|
||||
*
|
||||
* @param elementConverter converter between the Bukkit type {@code T}
|
||||
* and the NMS element type {@code E}
|
||||
* @param <T> Bukkit-side element type
|
||||
* @return the converter
|
||||
*/
|
||||
public static <T> EquivalentConverter<WrappedWeightedList<T>> getConverter(
|
||||
EquivalentConverter<T> elementConverter) {
|
||||
return new EquivalentConverter<>() {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public WrappedWeightedList<T> getSpecific(Object generic) {
|
||||
List<Object> nmsWeightedEntries = (List<Object>) WEIGHTED_LIST_UNWRAP.invoke(generic);
|
||||
List<Entry<T>> entries = new ArrayList<>(nmsWeightedEntries.size());
|
||||
for (Object nmsWeighted : nmsWeightedEntries) {
|
||||
Object nmsValue = WEIGHTED_VALUE.invoke(nmsWeighted);
|
||||
int weight = (int) WEIGHTED_WEIGHT.invoke(nmsWeighted);
|
||||
T value = elementConverter.getSpecific(nmsValue);
|
||||
entries.add(new Entry<>(value, weight));
|
||||
}
|
||||
return new WrappedWeightedList<>(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(WrappedWeightedList<T> specific) {
|
||||
|
||||
List<Object> nmsWeightedEntries = new ArrayList<>(specific.entries.size());
|
||||
for (Entry<T> entry : specific.entries) {
|
||||
Object nmsValue = elementConverter.getGeneric(entry.getValue());
|
||||
Object nmsWeighted = WEIGHTED_CTOR.invoke(nmsValue, entry.getWeight());
|
||||
nmsWeightedEntries.add(nmsWeighted);
|
||||
}
|
||||
return WEIGHTED_LIST_OF.invoke(null, nmsWeightedEntries);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Class<WrappedWeightedList<T>> getSpecificType() {
|
||||
return (Class<WrappedWeightedList<T>>) (Class<?>) WrappedWeightedList.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// ── Convenience factories ────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Creates an empty weighted list.
|
||||
*/
|
||||
public static <T> WrappedWeightedList<T> empty() {
|
||||
return new WrappedWeightedList<>(Collections.emptyList());
|
||||
}
|
||||
|
||||
// ── Object methods ───────────────────────────────────────────────────
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof WrappedWeightedList<?> that)) return false;
|
||||
return Objects.equals(entries, that.entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(entries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedWeightedList{entries=" + entries + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package net.dmulloy2.protocol;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import java.util.Objects;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/**
|
||||
* Base class for all packet wrappers. Provides access to the underlying
|
||||
* {@link PacketContainer} and convenience methods for sending/receiving.
|
||||
*/
|
||||
public abstract class AbstractPacket {
|
||||
|
||||
protected final PacketContainer handle;
|
||||
|
||||
protected AbstractPacket(PacketContainer handle, PacketType type) {
|
||||
if (handle == null) {
|
||||
throw new IllegalArgumentException("Packet handle cannot be null");
|
||||
}
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("Packet type cannot be null");
|
||||
}
|
||||
if (!handle.getType().equals(type)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid packet type: expected " + type + ", got " + handle.getType());
|
||||
}
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying {@link PacketContainer}.
|
||||
*/
|
||||
public PacketContainer getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this packet to a player (server → client).
|
||||
*/
|
||||
public void sendPacket(Player receiver) {
|
||||
ProtocolLibrary.getProtocolManager().sendServerPacket(receiver, getHandle());
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulates receiving this packet from a player (client → server).
|
||||
*/
|
||||
public void receivePacket(Player player) {
|
||||
ProtocolLibrary.getProtocolManager().receiveClientPacket(player, getHandle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AbstractPacket other = (AbstractPacket) o;
|
||||
return Objects.equals(handle, other.handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName() + "{handle=" + handle + "}";
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCodeOfConductPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundCodeOfConductPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.CODE_OF_CONDUCT;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(String.class);
|
||||
|
||||
public WrappedClientboundCodeOfConductPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCodeOfConductPacket(String codeOfConduct) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(codeOfConduct)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCodeOfConductPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public String getCodeOfConduct() {
|
||||
return handle.getStrings().read(0);
|
||||
}
|
||||
|
||||
public void setCodeOfConduct(String codeOfConduct) {
|
||||
handle.getStrings().write(0, codeOfConduct);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCookieRequestPacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Identifier key} – namespaced key identifying the cookie to request</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCookieRequestPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.COOKIE_REQUEST;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getMinecraftKeyClass(), MinecraftKey.getConverter());
|
||||
|
||||
public WrappedClientboundCookieRequestPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCookieRequestPacket(MinecraftKey key) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(key)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCookieRequestPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public MinecraftKey getKey() {
|
||||
return handle.getMinecraftKeys().read(0);
|
||||
}
|
||||
|
||||
public void setKey(MinecraftKey key) {
|
||||
handle.getMinecraftKeys().write(0, key);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.CustomPacketPayloadWrapper;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCustomPayloadPacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code CustomPacketPayload payload} – channel-specific payload</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCustomPayloadPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.CUSTOM_PAYLOAD;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(CustomPacketPayloadWrapper.getCustomPacketPayloadClass(), CustomPacketPayloadWrapper.getConverter());
|
||||
|
||||
public WrappedClientboundCustomPayloadPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomPayloadPacket(CustomPacketPayloadWrapper payload) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(payload)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomPayloadPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public CustomPacketPayloadWrapper getPayload() {
|
||||
return handle.getCustomPacketPayloads().read(0);
|
||||
}
|
||||
|
||||
public void setPayload(CustomPacketPayloadWrapper payload) {
|
||||
handle.getCustomPacketPayloads().write(0, payload);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import java.util.Map;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCustomReportDetailsPacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Map<String, String> details} – custom crash report detail entries</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCustomReportDetailsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.REPORT_DETAILS;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(Map.class);
|
||||
|
||||
public WrappedClientboundCustomReportDetailsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomReportDetailsPacket(Map<String, String> details) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(details)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomReportDetailsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return handle.getMaps(
|
||||
Converters.passthrough(String.class),
|
||||
Converters.passthrough(String.class)).readSafely(0);
|
||||
}
|
||||
|
||||
public void setDetails(Map<String, String> details) {
|
||||
handle.getMaps(
|
||||
Converters.passthrough(String.class),
|
||||
Converters.passthrough(String.class)).writeSafely(0, details);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDisconnectPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundDisconnectPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.DISCONNECT;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
|
||||
|
||||
public WrappedClientboundDisconnectPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDisconnectPacket(WrappedChatComponent reason) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(reason)));
|
||||
}
|
||||
|
||||
public WrappedClientboundDisconnectPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public WrappedChatComponent getReason() {
|
||||
return handle.getChatComponents().read(0);
|
||||
}
|
||||
|
||||
public void setReason(WrappedChatComponent reason) {
|
||||
handle.getChatComponents().write(0, reason);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundKeepAlivePacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundKeepAlivePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.KEEP_ALIVE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(long.class);
|
||||
|
||||
public WrappedClientboundKeepAlivePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundKeepAlivePacket(long id) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id)));
|
||||
}
|
||||
|
||||
public WrappedClientboundKeepAlivePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return handle.getLongs().read(0);
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
handle.getLongs().write(0, id);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundPingPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundPingPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.PING;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundPingPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundPingPacket(int id) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id)));
|
||||
}
|
||||
|
||||
public WrappedClientboundPingPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
handle.getIntegers().write(0, id);
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundRegistryDataPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundRegistryDataPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.REGISTRY_DATA;
|
||||
|
||||
public WrappedClientboundRegistryDataPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundRegistryDataPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// TODO: missing field 'registry' (NMS type: ResourceKey<? extends Registry<?>>)
|
||||
// Use getMinecraftKeys().read(0) for the registry key identifier, or getSpecificModifier(ResourceKey.class).read(0).
|
||||
// TODO: missing field 'entries' (NMS type: List<RegistrySynchronization.PackedRegistryEntry>)
|
||||
// Each entry has an id (Identifier) and an optional NBT tag. Use handle.getModifier().read(1)
|
||||
// for the raw List, or add a dedicated WrappedPackedRegistryEntry class.
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundResourcePackPopPacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Optional<UUID> id} – UUID of the resource pack to remove, or empty to remove all</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundResourcePackPopPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.REMOVE_RESOURCE_PACK;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(Optional.class);
|
||||
|
||||
public WrappedClientboundResourcePackPopPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundResourcePackPopPacket(Optional<UUID> id) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id)));
|
||||
}
|
||||
|
||||
public WrappedClientboundResourcePackPopPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Optional<UUID> getId() {
|
||||
return handle.getOptionals(Converters.passthrough(UUID.class)).readSafely(0);
|
||||
}
|
||||
|
||||
public void setId(Optional<UUID> id) {
|
||||
handle.getOptionals(Converters.passthrough(UUID.class)).writeSafely(0, id);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundResourcePackPushPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundResourcePackPushPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.ADD_RESOURCE_PACK;
|
||||
|
||||
// NMS constructor order: (UUID id, String url, String hash, boolean required, Optional<Component> prompt)
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(UUID.class)
|
||||
.withParam(String.class)
|
||||
.withParam(String.class)
|
||||
.withParam(boolean.class)
|
||||
.withParam(Optional.class, Converters.optional(BukkitConverters.getWrappedChatComponentConverter()));
|
||||
|
||||
public WrappedClientboundResourcePackPushPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundResourcePackPushPacket(String url, String hash, boolean required, UUID id, Optional<WrappedChatComponent> prompt) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id, url, hash, required, prompt)));
|
||||
}
|
||||
|
||||
public WrappedClientboundResourcePackPushPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return handle.getStrings().read(0);
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
handle.getStrings().write(0, url);
|
||||
}
|
||||
|
||||
public String getHash() {
|
||||
return handle.getStrings().read(1);
|
||||
}
|
||||
|
||||
public void setHash(String hash) {
|
||||
handle.getStrings().write(1, hash);
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setRequired(boolean required) {
|
||||
handle.getBooleans().write(0, required);
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return handle.getUUIDs().read(0);
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
handle.getUUIDs().write(0, id);
|
||||
}
|
||||
|
||||
public Optional<WrappedChatComponent> getPrompt() {
|
||||
return handle.getOptionals(BukkitConverters.getWrappedChatComponentConverter()).read(0);
|
||||
}
|
||||
|
||||
public void setPrompt(Optional<WrappedChatComponent> prompt) {
|
||||
handle.getOptionals(BukkitConverters.getWrappedChatComponentConverter()).write(0, prompt);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedKnownPack;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundSelectKnownPacks} (configuration phase, clientbound).
|
||||
* Selects known packs.
|
||||
*/
|
||||
public class WrappedClientboundSelectKnownPacksPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.SELECT_KNOWN_PACKS;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(List.class, BukkitConverters.getListConverter(WrappedKnownPack.CONVERTER));
|
||||
|
||||
public WrappedClientboundSelectKnownPacksPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundSelectKnownPacksPacket(List<WrappedKnownPack> knownPacks) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(knownPacks)));
|
||||
}
|
||||
|
||||
public WrappedClientboundSelectKnownPacksPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public List<WrappedKnownPack> getKnownPacks() {
|
||||
return handle.getLists(WrappedKnownPack.CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public void setKnownPacks(List<WrappedKnownPack> knownPacks) {
|
||||
handle.getLists(WrappedKnownPack.CONVERTER).write(0, knownPacks);
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.AutoWrapper;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Either;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundServerLinksPacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Fields:
|
||||
* <ul>
|
||||
* <li>{@code List<ServerLinks.UntrustedEntry> links} – server-provided links</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>NMS: {@code record UntrustedEntry(Either<KnownLinkType, Component> type, String link)}
|
||||
*/
|
||||
public class WrappedClientboundServerLinksPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.SERVER_LINKS;
|
||||
|
||||
/** Mirrors NMS {@code ServerLinks.KnownLinkType}; constant order must match. */
|
||||
public enum KnownLinkType {
|
||||
BUG_REPORT, COMMUNITY_GUIDELINES, SUPPORT, STATUS, FEEDBACK,
|
||||
COMMUNITY, WEBSITE, FORUMS, NEWS, ANNOUNCEMENTS
|
||||
}
|
||||
|
||||
private static final Class<?> NMS_KNOWN_LINK_TYPE_CLASS =
|
||||
MinecraftReflection.getMinecraftClass("server.ServerLinks$KnownLinkType");
|
||||
|
||||
private static final EquivalentConverter<Either<KnownLinkType, WrappedChatComponent>> TYPE_CONVERTER =
|
||||
BukkitConverters.getEitherConverter(
|
||||
EnumWrappers.getGenericConverter(NMS_KNOWN_LINK_TYPE_CLASS, KnownLinkType.class),
|
||||
BukkitConverters.getWrappedChatComponentConverter());
|
||||
|
||||
private static final AutoWrapper<WrappedUntrustedEntry> ENTRY_WRAPPER =
|
||||
AutoWrapper.wrap(WrappedUntrustedEntry.class, "server.ServerLinks$UntrustedEntry")
|
||||
.field(0, TYPE_CONVERTER);
|
||||
|
||||
public WrappedClientboundServerLinksPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundServerLinksPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of server links.
|
||||
*/
|
||||
public List<WrappedUntrustedEntry> getLinks() {
|
||||
List<WrappedUntrustedEntry> links = handle.getLists(ENTRY_WRAPPER).read(0);
|
||||
return links != null ? links : List.of();
|
||||
}
|
||||
|
||||
public void setLinks(List<WrappedUntrustedEntry> links) {
|
||||
handle.getLists(ENTRY_WRAPPER).write(0, links);
|
||||
}
|
||||
|
||||
/**
|
||||
* POJO mirroring {@code record ServerLinks.UntrustedEntry(Either<KnownLinkType, Component> type, String link)}.
|
||||
*/
|
||||
public static final class WrappedUntrustedEntry {
|
||||
/** Either a {@link KnownLinkType} (left) or a custom {@link WrappedChatComponent} display name (right). */
|
||||
public Either<KnownLinkType, WrappedChatComponent> type;
|
||||
/** The URL string. */
|
||||
public String link;
|
||||
|
||||
public WrappedUntrustedEntry() {}
|
||||
|
||||
public WrappedUntrustedEntry(Either<KnownLinkType, WrappedChatComponent> type, String link) {
|
||||
this.type = type;
|
||||
this.link = link;
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundShowDialogPacket} (configuration phase, clientbound).
|
||||
* Sends a dialog to the client.
|
||||
*/
|
||||
public class WrappedClientboundShowDialogPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.SHOW_DIALOG;
|
||||
|
||||
public WrappedClientboundShowDialogPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundShowDialogPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// TODO: missing field 'dialog' (NMS type: Holder<Dialog> — registry-backed dialog definition)
|
||||
// Same as the game-phase ShowDialog packet. Use handle.getModifier().read(0) for the raw Holder<Dialog>.
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundStoreCookiePacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Identifier key} – namespaced key identifying the cookie</li>
|
||||
* <li>{@code byte[] payload} – cookie data (max 5120 bytes)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundStoreCookiePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.STORE_COOKIE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getMinecraftKeyClass(), MinecraftKey.getConverter())
|
||||
.withParam(byte[].class);
|
||||
|
||||
public WrappedClientboundStoreCookiePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundStoreCookiePacket(MinecraftKey key, byte[] payload) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(key, payload)));
|
||||
}
|
||||
|
||||
public WrappedClientboundStoreCookiePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public MinecraftKey getKey() {
|
||||
return handle.getMinecraftKeys().read(0);
|
||||
}
|
||||
|
||||
public void setKey(MinecraftKey key) {
|
||||
handle.getMinecraftKeys().write(0, key);
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return handle.getByteArrays().read(0);
|
||||
}
|
||||
|
||||
public void setPayload(byte[] payload) {
|
||||
handle.getByteArrays().write(0, payload);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundTransferPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundTransferPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.TRANSFER;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(String.class)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundTransferPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundTransferPacket(String host, int port) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(host, port)));
|
||||
}
|
||||
|
||||
public WrappedClientboundTransferPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return handle.getStrings().read(0);
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
handle.getStrings().write(0, host);
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
handle.getIntegers().write(0, port);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import java.util.Set;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundUpdateEnabledFeaturesPacket} (configuration phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Set<ResourceLocation> features} – set of enabled feature flag identifiers</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundUpdateEnabledFeaturesPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.UPDATE_ENABLED_FEATURES;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(Set.class, BukkitConverters.getSetConverter(MinecraftKey.getConverter()));
|
||||
|
||||
public WrappedClientboundUpdateEnabledFeaturesPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundUpdateEnabledFeaturesPacket(Set<MinecraftKey> features) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(features)));
|
||||
}
|
||||
|
||||
public WrappedClientboundUpdateEnabledFeaturesPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Set<MinecraftKey> getFeatures() {
|
||||
return handle.getSets(MinecraftKey.getConverter()).readSafely(0);
|
||||
}
|
||||
|
||||
public void setFeatures(Set<MinecraftKey> features) {
|
||||
handle.getSets(MinecraftKey.getConverter()).writeSafely(0, features);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import com.comphenix.protocol.wrappers.WrappedTagPayload;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundUpdateTagsPacket} (configuration phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundUpdateTagsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Server.UPDATE_TAGS;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(Map.class, BukkitConverters.getMapConverter(
|
||||
WrappedTagPayload.REGISTRY_KEY_CONVERTER,
|
||||
WrappedTagPayload.CONVERTER));
|
||||
|
||||
public WrappedClientboundUpdateTagsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundUpdateTagsPacket(Map<MinecraftKey, WrappedTagPayload> tags) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(tags)));
|
||||
}
|
||||
|
||||
public WrappedClientboundUpdateTagsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Map<MinecraftKey, WrappedTagPayload> getTags() {
|
||||
return handle.getMaps(WrappedTagPayload.REGISTRY_KEY_CONVERTER, WrappedTagPayload.CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public void setTags(Map<MinecraftKey, WrappedTagPayload> tags) {
|
||||
handle.getMaps(WrappedTagPayload.REGISTRY_KEY_CONVERTER, WrappedTagPayload.CONVERTER).write(0, tags);
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.AutoWrapper;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundClientInformationPacket} (configuration phase, serverbound).
|
||||
*
|
||||
* <p>The packet wraps a single {@code ClientInformation} record, exposed via
|
||||
* {@link #getInformation()} / {@link #setInformation(WrappedClientInformation)}.
|
||||
*
|
||||
* <p>NMS: {@code record ClientInformation(String language, int viewDistance,
|
||||
* ChatVisiblity chatVisibility, boolean chatColors, int modelCustomisation,
|
||||
* HumanoidArm mainHand, boolean textFilteringEnabled, boolean allowsListing,
|
||||
* ParticleStatus particleStatus)}
|
||||
*/
|
||||
public class WrappedServerboundClientInformationPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.CLIENT_INFORMATION;
|
||||
|
||||
private static final Class<?> CLIENT_INFORMATION_CLASS =
|
||||
MinecraftReflection.getMinecraftClass("server.level.ClientInformation");
|
||||
private static final Class<?> HUMANOID_ARM_CLASS =
|
||||
MinecraftReflection.getMinecraftClass("world.entity.HumanoidArm");
|
||||
private static final Class<?> PARTICLE_STATUS_CLASS =
|
||||
MinecraftReflection.getMinecraftClass("server.level.ParticleStatus");
|
||||
|
||||
private static final EnumWrappers.EnumConverter<MainHand> MAIN_HAND_CONVERTER =
|
||||
new EnumWrappers.EnumConverter<>(HUMANOID_ARM_CLASS, MainHand.class);
|
||||
|
||||
private static final AutoWrapper<WrappedClientInformation> INFORMATION_WRAPPER =
|
||||
AutoWrapper.wrap(WrappedClientInformation.class, CLIENT_INFORMATION_CLASS)
|
||||
.field(2, EnumWrappers.getChatVisibilityConverter())
|
||||
.field(5, MAIN_HAND_CONVERTER)
|
||||
.field(8, EnumWrappers.getGenericConverter(PARTICLE_STATUS_CLASS, ParticleStatus.class));
|
||||
|
||||
public WrappedServerboundClientInformationPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundClientInformationPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
/** Returns the client settings, read from the underlying NMS {@code ClientInformation} record. */
|
||||
public WrappedClientInformation getInformation() {
|
||||
return handle.getModifier().withType(CLIENT_INFORMATION_CLASS, INFORMATION_WRAPPER).read(0);
|
||||
}
|
||||
|
||||
/** Writes the client settings back to the underlying NMS {@code ClientInformation} record. */
|
||||
public void setInformation(WrappedClientInformation info) {
|
||||
handle.getModifier().withType(CLIENT_INFORMATION_CLASS, INFORMATION_WRAPPER).write(0, info);
|
||||
}
|
||||
|
||||
/** POJO mirroring {@code record ClientInformation(...)}. */
|
||||
public static final class WrappedClientInformation {
|
||||
public String language;
|
||||
public int viewDistance;
|
||||
/** ProtocolLib {@link EnumWrappers.ChatVisibility}. */
|
||||
public EnumWrappers.ChatVisibility chatVisibility;
|
||||
public boolean chatColors;
|
||||
public int modelCustomisation;
|
||||
/** Dominant arm: {@link MainHand#LEFT} or {@link MainHand#RIGHT}. */
|
||||
public MainHand mainHand;
|
||||
public boolean textFilteringEnabled;
|
||||
public boolean allowsListing;
|
||||
public ParticleStatus particleStatus;
|
||||
|
||||
public WrappedClientInformation() {}
|
||||
}
|
||||
|
||||
/** Mirrors {@code HumanoidArm}: the player's dominant arm setting. */
|
||||
public enum MainHand { LEFT, RIGHT }
|
||||
|
||||
/** Mirrors NMS {@code ParticleStatus}; constant order must match. */
|
||||
public enum ParticleStatus { ALL, DECREASED, MINIMAL }
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundCookieResponsePacket} (configuration phase, serverbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Identifier key} – namespaced key identifying the cookie</li>
|
||||
* <li>{@code byte[] payload} – cookie bytes, or {@code null} if the client has no value</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedServerboundCookieResponsePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.COOKIE_RESPONSE;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getMinecraftKeyClass(), MinecraftKey.getConverter())
|
||||
.withParam(byte[].class);
|
||||
|
||||
public WrappedServerboundCookieResponsePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundCookieResponsePacket(MinecraftKey key, byte[] payload) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(key, payload)));
|
||||
}
|
||||
|
||||
public WrappedServerboundCookieResponsePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public MinecraftKey getKey() {
|
||||
return handle.getMinecraftKeys().readSafely(0);
|
||||
}
|
||||
|
||||
public void setKey(MinecraftKey key) {
|
||||
handle.getMinecraftKeys().writeSafely(0, key);
|
||||
}
|
||||
|
||||
public byte[] getPayload() {
|
||||
return handle.getByteArrays().readSafely(0);
|
||||
}
|
||||
|
||||
public void setPayload(byte[] payload) {
|
||||
handle.getByteArrays().writeSafely(0, payload);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundCustomClickActionPacket} (configuration phase, serverbound).
|
||||
*
|
||||
* <p>Sent when the client clicks a custom button identified by a resource-location key.
|
||||
*/
|
||||
public class WrappedServerboundCustomClickActionPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.CUSTOM_CLICK_ACTION;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getMinecraftKeyClass(), MinecraftKey.getConverter())
|
||||
.withParam(Optional.class, Converters.optional(BukkitConverters.getNbtConverter()));
|
||||
|
||||
public WrappedServerboundCustomClickActionPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundCustomClickActionPacket(MinecraftKey id, Optional<NbtBase<?>> payload) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id, payload)));
|
||||
}
|
||||
|
||||
public WrappedServerboundCustomClickActionPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public MinecraftKey getId() {
|
||||
return handle.getMinecraftKeys().read(0);
|
||||
}
|
||||
|
||||
public void setId(MinecraftKey id) {
|
||||
handle.getMinecraftKeys().write(0, id);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.CustomPacketPayloadWrapper;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundCustomPayloadPacket} (configuration phase, serverbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code CustomPacketPayload payload} – channel-specific payload data</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedServerboundCustomPayloadPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.CUSTOM_PAYLOAD;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(CustomPacketPayloadWrapper.getCustomPacketPayloadClass(), CustomPacketPayloadWrapper.getConverter());
|
||||
|
||||
public WrappedServerboundCustomPayloadPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundCustomPayloadPacket(CustomPacketPayloadWrapper payload) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(payload)));
|
||||
}
|
||||
|
||||
public WrappedServerboundCustomPayloadPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public CustomPacketPayloadWrapper getPayload() {
|
||||
return handle.getCustomPacketPayloads().read(0);
|
||||
}
|
||||
|
||||
public void setPayload(CustomPacketPayloadWrapper payload) {
|
||||
handle.getCustomPacketPayloads().write(0, payload);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundKeepAlivePacket} (configuration phase, serverbound).
|
||||
*/
|
||||
public class WrappedServerboundKeepAlivePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.KEEP_ALIVE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(long.class);
|
||||
|
||||
public WrappedServerboundKeepAlivePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundKeepAlivePacket(long id) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id)));
|
||||
}
|
||||
|
||||
public WrappedServerboundKeepAlivePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return handle.getLongs().read(0);
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
handle.getLongs().write(0, id);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundPongPacket} (configuration phase, serverbound).
|
||||
*/
|
||||
public class WrappedServerboundPongPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.PONG;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedServerboundPongPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundPongPacket(int id) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id)));
|
||||
}
|
||||
|
||||
public WrappedServerboundPongPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
handle.getIntegers().write(0, id);
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import java.util.UUID;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundResourcePackPacket} (configuration phase, serverbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code UUID id} – unique identifier of the resource pack</li>
|
||||
* <li>{@code ResourcePackStatusAction action} – the client's response status</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedServerboundResourcePackPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.RESOURCE_PACK_ACK;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(UUID.class)
|
||||
.withParam(EnumWrappers.getResourcePackStatusClass(), EnumWrappers.getResourcePackStatusConverter());
|
||||
|
||||
public WrappedServerboundResourcePackPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundResourcePackPacket(UUID id, EnumWrappers.ResourcePackStatus action) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(id, action)));
|
||||
}
|
||||
|
||||
public WrappedServerboundResourcePackPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return handle.getUUIDs().read(0);
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
handle.getUUIDs().write(0, id);
|
||||
}
|
||||
|
||||
public EnumWrappers.ResourcePackStatus getAction() {
|
||||
return handle.getResourcePackStatus().read(0);
|
||||
}
|
||||
|
||||
public void setAction(EnumWrappers.ResourcePackStatus action) {
|
||||
handle.getResourcePackStatus().write(0, action);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package net.dmulloy2.protocol.wrappers.configuration.serverbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedKnownPack;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ServerboundSelectKnownPacks} (configuration phase, serverbound).
|
||||
* Selects known packs.
|
||||
*/
|
||||
public class WrappedServerboundSelectKnownPacksPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Configuration.Client.SELECT_KNOWN_PACKS;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(List.class, BukkitConverters.getListConverter(WrappedKnownPack.CONVERTER));
|
||||
|
||||
public WrappedServerboundSelectKnownPacksPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedServerboundSelectKnownPacksPacket(List<WrappedKnownPack> knownPacks) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(knownPacks)));
|
||||
}
|
||||
|
||||
public WrappedServerboundSelectKnownPacksPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public List<WrappedKnownPack> getKnownPacks() {
|
||||
return handle.getLists(WrappedKnownPack.CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public void setKnownPacks(List<WrappedKnownPack> knownPacks) {
|
||||
handle.getLists(WrappedKnownPack.CONVERTER).write(0, knownPacks);
|
||||
}
|
||||
}
|
||||
+200
@@ -0,0 +1,200 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import java.util.UUID;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundAddEntityPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>The all-args constructor invokes the canonical NMS constructor through
|
||||
* {@link EquivalentConstructor}, so values are populated by NMS exactly as if
|
||||
* the server had constructed the packet itself.
|
||||
*
|
||||
* <p>The wrapper accepts pitch/yaw/head-yaw as <em>packed bytes</em> (the on-the-wire
|
||||
* representation, 256 units = 360°) for parity with the field-level getters/setters;
|
||||
* NMS internally stores them the same way and we round-trip through
|
||||
* {@link #byteToAngle(byte)} on the way in. Use {@link #byteToAngle(byte)} /
|
||||
* {@link #angleToByte(float)} when you need degrees.
|
||||
*
|
||||
* <p>Packet fields (NMS declaration order):
|
||||
* <ul>
|
||||
* <li>{@code int id} – entity ID</li>
|
||||
* <li>{@code UUID uuid} – entity UUID</li>
|
||||
* <li>{@code EntityType<?> type} – entity type</li>
|
||||
* <li>{@code double x, y, z} – spawn position</li>
|
||||
* <li>{@code Vec3 movement} – initial velocity</li>
|
||||
* <li>{@code byte xRot} – pitch, packed (256 units = 360°)</li>
|
||||
* <li>{@code byte yRot} – yaw, packed</li>
|
||||
* <li>{@code byte yHeadRot} – head yaw, packed</li>
|
||||
* <li>{@code int data} – optional type-specific data</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundAddEntityPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.SPAWN_ENTITY;
|
||||
|
||||
// NMS canonical ctor on Spigot 26.1:
|
||||
// ClientboundAddEntityPacket(int id, UUID uuid, double x, double y, double z,
|
||||
// float xRot, float yRot, EntityType<?> type, int data, Vec3 movement, double yHeadRot)
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(UUID.class)
|
||||
.withParam(double.class)
|
||||
.withParam(double.class)
|
||||
.withParam(double.class)
|
||||
.withParam(float.class)
|
||||
.withParam(float.class)
|
||||
.withParam(MinecraftReflection.getMinecraftClass("world.entity.EntityType"),
|
||||
BukkitConverters.getEntityTypeConverter())
|
||||
.withParam(int.class)
|
||||
.withParam(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter())
|
||||
.withParam(double.class);
|
||||
|
||||
public WrappedClientboundAddEntityPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundAddEntityPacket(int entityId, UUID entityUUID, EntityType entityType,
|
||||
double x, double y, double z, Vector velocity,
|
||||
byte pitchByte, byte yawByte, byte headYawByte, int data) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(
|
||||
entityId, entityUUID, x, y, z,
|
||||
byteToAngle(pitchByte), byteToAngle(yawByte),
|
||||
entityType, data, velocity,
|
||||
(double) byteToAngle(headYawByte))));
|
||||
}
|
||||
|
||||
public WrappedClientboundAddEntityPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Entity ID
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(0, entityId);
|
||||
}
|
||||
|
||||
/** Resolves the live entity in the given world via entity ID. */
|
||||
public Entity getEntity(World world) {
|
||||
return handle.getEntityModifier(world).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience setter that copies both the entity ID and UUID from a Bukkit entity.
|
||||
* Does not set the entity type, position, velocity, or rotations — set those separately.
|
||||
*/
|
||||
public void setEntity(Entity entity) {
|
||||
setEntityId(entity.getEntityId());
|
||||
setEntityUUID(entity.getUniqueId());
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// UUID
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public UUID getEntityUUID() {
|
||||
return handle.getUUIDs().read(0);
|
||||
}
|
||||
|
||||
public void setEntityUUID(UUID uuid) {
|
||||
handle.getUUIDs().write(0, uuid);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Entity type
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public EntityType getEntityType() {
|
||||
return handle.getEntityTypeModifier().read(0);
|
||||
}
|
||||
|
||||
public void setEntityType(EntityType type) {
|
||||
handle.getEntityTypeModifier().write(0, type);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Position
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public double getX() { return handle.getDoubles().read(0); }
|
||||
public void setX(double x) { handle.getDoubles().write(0, x); }
|
||||
|
||||
public double getY() { return handle.getDoubles().read(1); }
|
||||
public void setY(double y) { handle.getDoubles().write(1, y); }
|
||||
|
||||
public double getZ() { return handle.getDoubles().read(2); }
|
||||
public void setZ(double z) { handle.getDoubles().write(2, z); }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Initial velocity (Vec3)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public Vector getVelocity() {
|
||||
return handle.getVectors().read(0);
|
||||
}
|
||||
|
||||
public void setVelocity(Vector velocity) {
|
||||
handle.getVectors().write(0, velocity);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Packed rotation bytes (256 units = 360°)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Pitch (xRot) as a packed byte. Convert with {@link #byteToAngle(byte)}. */
|
||||
public byte getPitchByte() { return handle.getBytes().read(0); }
|
||||
public void setPitchByte(byte xRot) { handle.getBytes().write(0, xRot); }
|
||||
|
||||
/** Yaw (yRot) as a packed byte. Convert with {@link #byteToAngle(byte)}. */
|
||||
public byte getYawByte() { return handle.getBytes().read(1); }
|
||||
public void setYawByte(byte yRot) { handle.getBytes().write(1, yRot); }
|
||||
|
||||
/** Head yaw (yHeadRot) as a packed byte. Convert with {@link #byteToAngle(byte)}. */
|
||||
public byte getHeadYawByte() { return handle.getBytes().read(2); }
|
||||
public void setHeadYawByte(byte yHeadRot) { handle.getBytes().write(2, yHeadRot); }
|
||||
|
||||
/**
|
||||
* Converts a packed byte angle to degrees, matching NMS {@code Mth.unpackDegrees}.
|
||||
* Treats {@code packed} as a signed byte: {@code (byte * 360) / 256.0f}.
|
||||
*/
|
||||
public static float byteToAngle(byte packed) {
|
||||
return (packed * 360) / 256.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts degrees to a packed byte angle, matching NMS {@code Mth.packDegrees}.
|
||||
* Uses {@code Math.floor} (not int truncation) so negative angles round toward
|
||||
* negative infinity, matching NMS exactly.
|
||||
*/
|
||||
public static byte angleToByte(float degrees) {
|
||||
return (byte) (int) Math.floor(degrees * 256.0f / 360.0f);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Extra data
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Type-specific extra data (e.g. projectile type, falling-block state ID). */
|
||||
public int getData() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setData(int data) {
|
||||
handle.getIntegers().write(1, data);
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundAnimatePacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – entity ID performing the animation</li>
|
||||
* <li>{@code int animationId} – animation ID:
|
||||
* <ul>
|
||||
* <li>0 = swing main arm</li>
|
||||
* <li>1 = hurt</li>
|
||||
* <li>2 = wake up</li>
|
||||
* <li>3 = swing off hand</li>
|
||||
* <li>4 = critical hit</li>
|
||||
* <li>5 = magic critical hit</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundAnimatePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.ANIMATION;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getEntityClass(), BukkitUnwrapper.getInstance())
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundAnimatePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundAnimatePacket(int entityId, int animationId) {
|
||||
this();
|
||||
setEntityId(entityId);
|
||||
setAnimationId(animationId);
|
||||
}
|
||||
|
||||
public WrappedClientboundAnimatePacket(Entity entity, int animationId) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(entity, animationId)));
|
||||
}
|
||||
|
||||
public WrappedClientboundAnimatePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Entity getEntity(World world) {
|
||||
return handle.getEntityModifier(world).readSafely(0);
|
||||
}
|
||||
|
||||
public void setEntity(Entity entity) {
|
||||
handle.getEntityModifier(entity.getWorld()).writeSafely(0, entity);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().readSafely(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().writeSafely(0, entityId);
|
||||
}
|
||||
|
||||
public int getAnimationId() {
|
||||
return handle.getIntegers().readSafely(1);
|
||||
}
|
||||
|
||||
public void setAnimationId(int animationId) {
|
||||
handle.getIntegers().writeSafely(1, animationId);
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedStatistic;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundAwardStatsPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Object2IntMap<Stat<?>> stats} – statistic → value map to award to the player</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundAwardStatsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.STATISTIC;
|
||||
|
||||
/** The NMS field type is {@code Object2IntMap} – obtained lazily from the modifier. */
|
||||
private static final Class<?> STATS_FIELD_TYPE;
|
||||
/** NMS constructor accessor: {@code ClientboundAwardStatsPacket(Object2IntMap)}. */
|
||||
private static final EquivalentConstructor CONSTRUCTOR;
|
||||
|
||||
static {
|
||||
Class<?> fieldType = new PacketContainer(TYPE).getModifier().getField(0).getType();
|
||||
STATS_FIELD_TYPE = fieldType;
|
||||
CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(fieldType, createStatsConverter(fieldType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a converter that produces an Object2IntOpenHashMap (implementing Object2IntMap)
|
||||
* from a {@code Map<WrappedStatistic, Integer>}, so it can be passed to the NMS constructor.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static EquivalentConverter<Map<WrappedStatistic, Integer>> createStatsConverter(Class<?> nmsMapClass) {
|
||||
// reuse the ProtocolLib statistic converter for individual entries
|
||||
EquivalentConverter<WrappedStatistic> statConverter =
|
||||
com.comphenix.protocol.wrappers.BukkitConverters.getWrappedStatisticConverter();
|
||||
|
||||
return new EquivalentConverter<Map<WrappedStatistic, Integer>>() {
|
||||
@Override
|
||||
public Object getGeneric(Map<WrappedStatistic, Integer> specific) {
|
||||
try {
|
||||
// Create an Object2IntOpenHashMap (implements Object2IntMap)
|
||||
Class<?> openHashMapClass = Class.forName(
|
||||
"it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap");
|
||||
Object nmsMap = openHashMapClass.getDeclaredConstructor().newInstance();
|
||||
java.lang.reflect.Method put = openHashMapClass.getMethod(
|
||||
"put", Object.class, int.class);
|
||||
for (Map.Entry<WrappedStatistic, Integer> entry : specific.entrySet()) {
|
||||
put.invoke(nmsMap, statConverter.getGeneric(entry.getKey()), (int) entry.getValue());
|
||||
}
|
||||
return nmsMap;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to convert stats map", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<WrappedStatistic, Integer> getSpecific(Object generic) {
|
||||
Map<Object, Object> nmsMap = (Map<Object, Object>) generic;
|
||||
Map<WrappedStatistic, Integer> result = new HashMap<>();
|
||||
for (Map.Entry<Object, Object> entry : nmsMap.entrySet()) {
|
||||
result.put(statConverter.getSpecific(entry.getKey()),
|
||||
((Number) entry.getValue()).intValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Map<WrappedStatistic, Integer>> getSpecificType() {
|
||||
return (Class) Map.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public WrappedClientboundAwardStatsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundAwardStatsPacket(Map<WrappedStatistic, Integer> stats) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(stats)));
|
||||
}
|
||||
|
||||
public WrappedClientboundAwardStatsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Map<WrappedStatistic, Integer> getStats() {
|
||||
return handle.getStatisticMaps().read(0);
|
||||
}
|
||||
|
||||
public void setStats(Map<WrappedStatistic, Integer> stats) {
|
||||
// ProtocolLib's getStatisticMaps() converter writes a plain HashMap back to the NMS field,
|
||||
// but the field type is Object2IntMap (a fastutil interface) – the cast fails.
|
||||
// Create the correct Object2IntOpenHashMap via our custom converter and write to the raw modifier.
|
||||
Object nmsMap = createStatsConverter(STATS_FIELD_TYPE).getGeneric(stats);
|
||||
handle.getModifier().write(0, nmsMap);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundBlockChangedAckPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int sequence} – sequence number of the block change acknowledgement</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundBlockChangedAckPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.BLOCK_CHANGED_ACK;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundBlockChangedAckPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockChangedAckPacket(int sequence) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(sequence)));
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockChangedAckPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getSequence() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setSequence(int sequence) {
|
||||
handle.getIntegers().write(0, sequence);
|
||||
}
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundBlockDestructionPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Controls the cracking/break-progress animation overlay on a block.
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int id} – unique ID for this break action (used to track multiple simultaneous breakers)</li>
|
||||
* <li>{@code BlockPos pos} – position of the block being broken</li>
|
||||
* <li>{@code int destroyStage} – break progress stage (0–9; 10+ removes the overlay)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundBlockDestructionPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.BLOCK_BREAK_ANIMATION;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class) // id
|
||||
.withParam(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter()) // pos
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundBlockDestructionPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockDestructionPacket(int id, BlockPosition pos, int destroyStage) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(id, pos, destroyStage)));
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockDestructionPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
/** Returns the unique action ID used to differentiate concurrent break animations. */
|
||||
public int getId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
handle.getIntegers().write(0, id);
|
||||
}
|
||||
|
||||
public BlockPosition getPos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setPos(BlockPosition pos) {
|
||||
handle.getBlockPositionModifier().write(0, pos);
|
||||
}
|
||||
|
||||
/** Returns the destroy stage (0–9). Values ≥ 10 remove the animation overlay. */
|
||||
public int getDestroyStage() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setDestroyStage(int destroyStage) {
|
||||
handle.getIntegers().write(1, destroyStage);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistrable;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundBlockEntityDataPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundBlockEntityDataPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.TILE_ENTITY_DATA;
|
||||
|
||||
public WrappedClientboundBlockEntityDataPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockEntityDataPacket(BlockPosition pos, WrappedRegistrable blockEntityType, NbtBase tag) {
|
||||
this();
|
||||
setPos(pos);
|
||||
setBlockEntityType(blockEntityType);
|
||||
setTag(tag);
|
||||
}
|
||||
|
||||
|
||||
public WrappedClientboundBlockEntityDataPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public BlockPosition getPos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setPos(BlockPosition pos) {
|
||||
handle.getBlockPositionModifier().write(0, pos);
|
||||
}
|
||||
|
||||
public WrappedRegistrable getBlockEntityType() {
|
||||
return handle.getBlockEntityTypeModifier().read(0);
|
||||
}
|
||||
|
||||
public void setBlockEntityType(WrappedRegistrable type) {
|
||||
handle.getBlockEntityTypeModifier().write(0, type);
|
||||
}
|
||||
|
||||
public NbtBase getTag() {
|
||||
return handle.getNbtModifier().read(0);
|
||||
}
|
||||
|
||||
public void setTag(NbtBase tag) {
|
||||
handle.getNbtModifier().write(0, tag);
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.Material;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundBlockEventPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code BlockPosition pos} – position of the block</li>
|
||||
* <li>{@code int actionId} – block action ID (block-type dependent)</li>
|
||||
* <li>{@code int actionParam} – block action parameter (block-type dependent)</li>
|
||||
* <li>{@code Material blockType} – type of block at the position</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundBlockEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.BLOCK_ACTION;
|
||||
|
||||
// NMS constructor order: (BlockPos pos, Block block, int b0, int b1)
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter())
|
||||
.withParam(MinecraftReflection.getBlockClass(), BukkitConverters.getBlockConverter())
|
||||
.withParam(int.class)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundBlockEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockEventPacket(BlockPosition pos, int actionId, int actionParam, Material blockType) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(pos, blockType, actionId, actionParam)));
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public BlockPosition getPos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setPos(BlockPosition pos) {
|
||||
handle.getBlockPositionModifier().write(0, pos);
|
||||
}
|
||||
|
||||
public int getActionId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setActionId(int actionId) {
|
||||
handle.getIntegers().write(0, actionId);
|
||||
}
|
||||
|
||||
public int getActionParam() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setActionParam(int actionParam) {
|
||||
handle.getIntegers().write(1, actionParam);
|
||||
}
|
||||
|
||||
public Material getBlockType() {
|
||||
return handle.getBlocks().read(0);
|
||||
}
|
||||
|
||||
public void setBlockType(Material blockType) {
|
||||
handle.getBlocks().write(0, blockType);
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedBlockData;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundBlockUpdatePacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code BlockPosition pos} – position of the changed block</li>
|
||||
* <li>{@code WrappedBlockData blockData} – new block state</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundBlockUpdatePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.BLOCK_CHANGE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter())
|
||||
.withParam(MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter());
|
||||
|
||||
public WrappedClientboundBlockUpdatePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockUpdatePacket(BlockPosition pos, WrappedBlockData blockData) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(pos, blockData)));
|
||||
}
|
||||
|
||||
public WrappedClientboundBlockUpdatePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public BlockPosition getPos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setPos(BlockPosition pos) {
|
||||
handle.getBlockPositionModifier().write(0, pos);
|
||||
}
|
||||
|
||||
public WrappedBlockData getBlockData() {
|
||||
return handle.getBlockData().read(0);
|
||||
}
|
||||
|
||||
public void setBlockData(WrappedBlockData blockData) {
|
||||
handle.getBlockData().write(0, blockData);
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.boss.BossBar;
|
||||
import org.bukkit.craftbukkit.boss.CraftBossBar;
|
||||
|
||||
public class WrappedClientboundBossEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.BOSS;
|
||||
|
||||
private static final MethodAccessor CREATE_ADD_PACKET;
|
||||
private static final MethodAccessor CREATE_REMOVE_PACKET;
|
||||
private static final MethodAccessor CREATE_UPDATE_PROGRESS_PACKET;
|
||||
private static final MethodAccessor CREATE_UPDATE_NAME_PACKET;
|
||||
private static final MethodAccessor CREATE_UPDATE_STYLE_PACKET;
|
||||
private static final MethodAccessor CREATE_UPDATE_PROPERTIES_PACKET;
|
||||
private static final FieldAccessor BOSS_BAR_HANDLE;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> packetClass = MinecraftReflection.getMinecraftClass(
|
||||
"network.protocol.game.ClientboundBossEventPacket");
|
||||
Class<?> bossEventClass = MinecraftReflection.getMinecraftClass("world.BossEvent");
|
||||
|
||||
CREATE_ADD_PACKET = Accessors.getMethodAccessor(packetClass, "createAddPacket", bossEventClass);
|
||||
CREATE_REMOVE_PACKET = Accessors.getMethodAccessor(packetClass, "createRemovePacket", UUID.class);
|
||||
CREATE_UPDATE_PROGRESS_PACKET = Accessors.getMethodAccessor(packetClass, "createUpdateProgressPacket", bossEventClass);
|
||||
CREATE_UPDATE_NAME_PACKET = Accessors.getMethodAccessor(packetClass, "createUpdateNamePacket", bossEventClass);
|
||||
CREATE_UPDATE_STYLE_PACKET = Accessors.getMethodAccessor(packetClass, "createUpdateStylePacket", bossEventClass);
|
||||
CREATE_UPDATE_PROPERTIES_PACKET = Accessors.getMethodAccessor(packetClass, "createUpdatePropertiesPacket", bossEventClass);
|
||||
|
||||
BOSS_BAR_HANDLE = Accessors.getFieldAccessorOrNull(CraftBossBar.class, "handle", bossEventClass);
|
||||
if (BOSS_BAR_HANDLE == null) {
|
||||
throw new FieldAccessException("Unable to find CraftBossBar.handle field of type " + bossEventClass.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new ExceptionInInitializerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public WrappedClientboundBossEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBossEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public static WrappedClientboundBossEventPacket createAddPacket(BossBar bossBar) {
|
||||
Object event = getBossEvent(bossBar);
|
||||
return new WrappedClientboundBossEventPacket(PacketContainer.fromPacket(
|
||||
CREATE_ADD_PACKET.invoke(null, event)));
|
||||
}
|
||||
|
||||
public static WrappedClientboundBossEventPacket createRemovePacket(UUID id) {
|
||||
return new WrappedClientboundBossEventPacket(PacketContainer.fromPacket(
|
||||
CREATE_REMOVE_PACKET.invoke(null, id)));
|
||||
}
|
||||
|
||||
public static WrappedClientboundBossEventPacket createUpdateProgressPacket(BossBar bossBar) {
|
||||
Object event = getBossEvent(bossBar);
|
||||
return new WrappedClientboundBossEventPacket(PacketContainer.fromPacket(
|
||||
CREATE_UPDATE_PROGRESS_PACKET.invoke(null, event)));
|
||||
}
|
||||
|
||||
public static WrappedClientboundBossEventPacket createUpdateNamePacket(BossBar bossBar) {
|
||||
Object event = getBossEvent(bossBar);
|
||||
return new WrappedClientboundBossEventPacket(PacketContainer.fromPacket(
|
||||
CREATE_UPDATE_NAME_PACKET.invoke(null, event)));
|
||||
}
|
||||
|
||||
public static WrappedClientboundBossEventPacket createUpdateStylePacket(BossBar bossBar) {
|
||||
Object event = getBossEvent(bossBar);
|
||||
return new WrappedClientboundBossEventPacket(PacketContainer.fromPacket(
|
||||
CREATE_UPDATE_STYLE_PACKET.invoke(null, event)));
|
||||
}
|
||||
|
||||
public static WrappedClientboundBossEventPacket createUpdatePropertiesPacket(BossBar bossBar) {
|
||||
Object event = getBossEvent(bossBar);
|
||||
return new WrappedClientboundBossEventPacket(PacketContainer.fromPacket(
|
||||
CREATE_UPDATE_PROPERTIES_PACKET.invoke(null, event)));
|
||||
}
|
||||
|
||||
private static Object getBossEvent(BossBar bossBar) {
|
||||
Objects.requireNonNull(bossBar, "bossBar");
|
||||
if (!(bossBar instanceof CraftBossBar)) {
|
||||
throw new IllegalArgumentException("BossBar must be a CraftBossBar: " + bossBar.getClass().getName());
|
||||
}
|
||||
return BOSS_BAR_HANDLE.get(bossBar);
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return handle.getUUIDs().read(0);
|
||||
}
|
||||
|
||||
public void setId(UUID id) {
|
||||
handle.getUUIDs().write(0, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw NMS {@code BossEvent$Operation} object describing what this packet
|
||||
* does (add / remove / update progress / update name / update style / update properties).
|
||||
*
|
||||
* @apiNote This is an escape hatch that exposes the unwrapped NMS handle. Prefer the
|
||||
* typed {@code createXxxPacket(BossBar)} factories above when constructing a packet;
|
||||
* this accessor is provided only for inspecting packets received via
|
||||
* {@link com.comphenix.protocol.events.PacketAdapter}.
|
||||
*/
|
||||
public Object getOperation() {
|
||||
return handle.getModifier().read(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the raw NMS {@code BossEvent$Operation} object on this packet.
|
||||
*
|
||||
* @apiNote This is an escape hatch — callers must construct an NMS-internal
|
||||
* {@code BossEvent$Operation} subtype (e.g. {@code AddOperation}, {@code UpdateProgressOperation}).
|
||||
* Prefer the typed {@code createXxxPacket(BossBar)} factories above for normal use.
|
||||
*/
|
||||
public void setOperation(Object operation) {
|
||||
handle.getModifier().write(1, operation);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundBundlePacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Iterable<Packet<?>> subPackets} - bundled packets sent together</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundBundlePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.BUNDLE;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(Iterable.class, Converters.iterable(
|
||||
BukkitConverters.getPacketContainerConverter(), ArrayList::new, ArrayList::new));
|
||||
|
||||
public WrappedClientboundBundlePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundBundlePacket(Iterable<PacketContainer> subPackets) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(subPackets)));
|
||||
}
|
||||
|
||||
public WrappedClientboundBundlePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Iterable<PacketContainer> getSubPackets() {
|
||||
return handle.getPacketBundles().read(0);
|
||||
}
|
||||
|
||||
public void setSubPackets(Iterable<PacketContainer> subPackets) {
|
||||
handle.getPacketBundles().write(0, subPackets);
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundChangeDifficultyPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Difficulty difficulty} – the current difficulty level</li>
|
||||
* <li>{@code boolean locked} – whether the difficulty is locked by the server</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundChangeDifficultyPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.SERVER_DIFFICULTY;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(EnumWrappers.getDifficultyClass(), EnumWrappers.getDifficultyConverter())
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundChangeDifficultyPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundChangeDifficultyPacket(EnumWrappers.Difficulty difficulty, boolean locked) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(difficulty, locked)));
|
||||
}
|
||||
|
||||
public WrappedClientboundChangeDifficultyPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public EnumWrappers.Difficulty getDifficulty() {
|
||||
return handle.getDifficulties().read(0);
|
||||
}
|
||||
|
||||
public void setDifficulty(EnumWrappers.Difficulty difficulty) {
|
||||
handle.getDifficulties().write(0, difficulty);
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
handle.getBooleans().write(0, locked);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundChunkBatchFinishedPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int batchSize} – number of chunks in the completed batch</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundChunkBatchFinishedPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.CHUNK_BATCH_FINISHED;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundChunkBatchFinishedPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundChunkBatchFinishedPacket(int batchSize) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(batchSize)));
|
||||
}
|
||||
|
||||
public WrappedClientboundChunkBatchFinishedPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setBatchSize(int batchSize) {
|
||||
handle.getIntegers().write(0, batchSize);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChunkBiomeData;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundChunksBiomesPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundChunksBiomesPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.CHUNKS_BIOMES;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(List.class, BukkitConverters.getListConverter(WrappedChunkBiomeData.CONVERTER));
|
||||
|
||||
public WrappedClientboundChunksBiomesPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundChunksBiomesPacket(List<WrappedChunkBiomeData> chunkBiomeData) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(chunkBiomeData)));
|
||||
}
|
||||
|
||||
public WrappedClientboundChunksBiomesPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public List<WrappedChunkBiomeData> getChunkBiomeData() {
|
||||
return handle.getLists(WrappedChunkBiomeData.CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public void setChunkBiomeData(List<WrappedChunkBiomeData> chunkBiomeData) {
|
||||
handle.getLists(WrappedChunkBiomeData.CONVERTER).write(0, chunkBiomeData);
|
||||
}
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundClearTitlesPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code boolean resetTimes} – if {@code true}, also resets fade-in/stay/fade-out times</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundClearTitlesPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.CLEAR_TITLES;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundClearTitlesPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundClearTitlesPacket(boolean resetTimes) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(resetTimes)));
|
||||
}
|
||||
|
||||
public WrappedClientboundClearTitlesPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public boolean isResetTimes() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setResetTimes(boolean resetTimes) {
|
||||
handle.getBooleans().write(0, resetTimes);
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCommandSuggestionsPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundCommandSuggestionsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.TAB_COMPLETE;
|
||||
|
||||
public WrappedClientboundCommandSuggestionsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCommandSuggestionsPacket(int id, int start, int length) {
|
||||
this();
|
||||
setId(id);
|
||||
setStart(start);
|
||||
setLength(length);
|
||||
}
|
||||
|
||||
public WrappedClientboundCommandSuggestionsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
handle.getIntegers().write(0, id);
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
handle.getIntegers().write(1, start);
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setLength(int length) {
|
||||
handle.getIntegers().write(2, length);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCommandsPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundCommandsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.COMMANDS;
|
||||
|
||||
public WrappedClientboundCommandsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCommandsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// TODO: missing field — Brigadier command tree (RootCommandNode<SharedSuggestionProvider>)
|
||||
// No ProtocolLib accessor exists for the serialised command tree.
|
||||
// Use handle.getModifier().read(0) to access the raw RootCommandNode object.
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundContainerClosePacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Instructs the client to close the given container window.
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int windowId} – ID of the window to close (0 = player inventory)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundContainerClosePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.CLOSE_WINDOW;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundContainerClosePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerClosePacket(int windowId) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(windowId)));
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerClosePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getWindowId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setWindowId(int windowId) {
|
||||
handle.getIntegers().write(0, windowId);
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import java.util.List;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundContainerSetContentPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int containerId} – ID of the container whose contents are being set</li>
|
||||
* <li>{@code int stateId} – state ID used for sync with the server</li>
|
||||
* <li>{@code List<ItemStack> items} – full slot contents</li>
|
||||
* <li>{@code ItemStack carriedItem} – item currently held on the cursor</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundContainerSetContentPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.WINDOW_ITEMS;
|
||||
|
||||
public WrappedClientboundContainerSetContentPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerSetContentPacket(int containerId, int stateId, List<ItemStack> items, ItemStack carriedItem) {
|
||||
this();
|
||||
setContainerId(containerId);
|
||||
setStateId(stateId);
|
||||
setItems(items);
|
||||
setCarriedItem(carriedItem);
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerSetContentPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getContainerId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setContainerId(int containerId) {
|
||||
handle.getIntegers().write(0, containerId);
|
||||
}
|
||||
|
||||
public int getStateId() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setStateId(int stateId) {
|
||||
handle.getIntegers().write(1, stateId);
|
||||
}
|
||||
|
||||
public List<ItemStack> getItems() {
|
||||
return handle.getItemListModifier().read(0);
|
||||
}
|
||||
|
||||
public void setItems(List<ItemStack> items) {
|
||||
handle.getItemListModifier().write(0, items);
|
||||
}
|
||||
|
||||
public ItemStack getCarriedItem() {
|
||||
return handle.getItemModifier().read(0);
|
||||
}
|
||||
|
||||
public void setCarriedItem(ItemStack carriedItem) {
|
||||
handle.getItemModifier().write(0, carriedItem);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundContainerSetDataPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int windowId} – container window ID</li>
|
||||
* <li>{@code int property} – property index (container-type dependent)</li>
|
||||
* <li>{@code int value} – new value of the property</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundContainerSetDataPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.WINDOW_DATA;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(int.class)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundContainerSetDataPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerSetDataPacket(int windowId, int property, int value) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(windowId, property, value)));
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerSetDataPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getWindowId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setWindowId(int windowId) {
|
||||
handle.getIntegers().write(0, windowId);
|
||||
}
|
||||
|
||||
public int getProperty() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setProperty(int property) {
|
||||
handle.getIntegers().write(1, property);
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setValue(int value) {
|
||||
handle.getIntegers().write(2, value);
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundContainerSetSlotPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int windowId} – container window ID; 0 = player inventory, -1 = cursor slot,
|
||||
* -2 = all slots</li>
|
||||
* <li>{@code int stateId} – container state ID for synchronisation</li>
|
||||
* <li>{@code int slot} – slot index within the container</li>
|
||||
* <li>{@code ItemStack item} – item to place in the slot</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundContainerSetSlotPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.SET_SLOT;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(int.class)
|
||||
.withParam(int.class)
|
||||
.withParam(MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter());
|
||||
|
||||
public WrappedClientboundContainerSetSlotPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerSetSlotPacket(int windowId, int stateId, int slot, ItemStack item) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(windowId, stateId, slot, item)));
|
||||
}
|
||||
|
||||
public WrappedClientboundContainerSetSlotPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getWindowId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setWindowId(int windowId) {
|
||||
handle.getIntegers().write(0, windowId);
|
||||
}
|
||||
|
||||
public int getStateId() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setStateId(int stateId) {
|
||||
handle.getIntegers().write(1, stateId);
|
||||
}
|
||||
|
||||
public int getSlot() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setSlot(int slot) {
|
||||
handle.getIntegers().write(2, slot);
|
||||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
return handle.getItemModifier().read(0);
|
||||
}
|
||||
|
||||
public void setItem(ItemStack item) {
|
||||
handle.getItemModifier().write(0, item);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCookieRequestPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Identifier key} – namespaced key identifying the cookie to request</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCookieRequestPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.COOKIE_REQUEST;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getMinecraftKeyClass(), MinecraftKey.getConverter());
|
||||
|
||||
public WrappedClientboundCookieRequestPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCookieRequestPacket(MinecraftKey key) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(key)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCookieRequestPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public MinecraftKey getKey() {
|
||||
return handle.getMinecraftKeys().read(0);
|
||||
}
|
||||
|
||||
public void setKey(MinecraftKey key) {
|
||||
handle.getMinecraftKeys().write(0, key);
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCooldownPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code MinecraftKey item} – namespaced item key the cooldown applies to</li>
|
||||
* <li>{@code int ticks} – cooldown duration in ticks; 0 to clear the cooldown</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCooldownPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.SET_COOLDOWN;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getMinecraftKeyClass(), MinecraftKey.getConverter())
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundCooldownPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCooldownPacket(MinecraftKey item, int ticks) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(item, ticks)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCooldownPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public MinecraftKey getItem() {
|
||||
return handle.getMinecraftKeys().read(0);
|
||||
}
|
||||
|
||||
public void setItem(MinecraftKey item) {
|
||||
handle.getMinecraftKeys().write(0, item);
|
||||
}
|
||||
|
||||
public int getTicks() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setTicks(int ticks) {
|
||||
handle.getIntegers().write(0, ticks);
|
||||
}
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCustomChatCompletionsPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>NMS field order: {@code action (global 0), entries (global 1)}
|
||||
*/
|
||||
public class WrappedClientboundCustomChatCompletionsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.CUSTOM_CHAT_COMPLETIONS;
|
||||
|
||||
/**
|
||||
* Mirrors {@code ClientboundCustomChatCompletionsPacket.Action}.
|
||||
* Global field index 0 — constants must match NMS names exactly.
|
||||
*/
|
||||
public enum Action { ADD, REMOVE, SET }
|
||||
|
||||
private static final Class<?> ACTION_NMS_CLASS = Arrays.stream(TYPE.getPacketClass().getDeclaredClasses())
|
||||
.filter(Class::isEnum)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(ACTION_NMS_CLASS, new EnumWrappers.EnumConverter<>(ACTION_NMS_CLASS, Action.class))
|
||||
.withParam(List.class);
|
||||
|
||||
public WrappedClientboundCustomChatCompletionsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomChatCompletionsPacket(Action action, List<String> entries) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(action, entries)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomChatCompletionsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
/** Returns the completion action (ADD, REMOVE, or SET). Global field index 0. */
|
||||
public Action getAction() {
|
||||
return handle.getEnumModifier(Action.class, 0).readSafely(0);
|
||||
}
|
||||
|
||||
public void setAction(Action action) {
|
||||
handle.getEnumModifier(Action.class, 0).writeSafely(0, action);
|
||||
}
|
||||
|
||||
public List<String> getEntries() {
|
||||
return handle.getLists(Converters.passthrough(String.class)).readSafely(0);
|
||||
}
|
||||
|
||||
public void setEntries(List<String> entries) {
|
||||
handle.getLists(Converters.passthrough(String.class)).writeSafely(0, entries);
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.CustomPacketPayloadWrapper;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCustomPayloadPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code CustomPacketPayload payload} – channel-specific payload</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCustomPayloadPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.CUSTOM_PAYLOAD;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(CustomPacketPayloadWrapper.getCustomPacketPayloadClass(), CustomPacketPayloadWrapper.getConverter());
|
||||
|
||||
public WrappedClientboundCustomPayloadPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomPayloadPacket(CustomPacketPayloadWrapper payload) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(payload)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomPayloadPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public CustomPacketPayloadWrapper getPayload() {
|
||||
return handle.getCustomPacketPayloads().read(0);
|
||||
}
|
||||
|
||||
public void setPayload(CustomPacketPayloadWrapper payload) {
|
||||
handle.getCustomPacketPayloads().write(0, payload);
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import java.util.Map;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundCustomReportDetailsPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code Map<String, String> details} – custom crash report detail entries</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundCustomReportDetailsPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.REPORT_DETAILS;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(Map.class);
|
||||
|
||||
public WrappedClientboundCustomReportDetailsPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomReportDetailsPacket(Map<String, String> details) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(details)));
|
||||
}
|
||||
|
||||
public WrappedClientboundCustomReportDetailsPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public Map<String, String> getDetails() {
|
||||
return handle.getMaps(
|
||||
Converters.passthrough(String.class),
|
||||
Converters.passthrough(String.class)).readSafely(0);
|
||||
}
|
||||
|
||||
public void setDetails(Map<String, String> details) {
|
||||
handle.getMaps(
|
||||
Converters.passthrough(String.class),
|
||||
Converters.passthrough(String.class)).writeSafely(0, details);
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.damage.DamageType;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDamageEventPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – entity that received the damage</li>
|
||||
* <li>{@code Holder<DamageType> sourceType} – damage type</li>
|
||||
* <li>{@code int sourceCauseId} – entity ID of the damage cause, or {@code -1} if absent</li>
|
||||
* <li>{@code int sourceDirectId} – entity ID of the direct source, or {@code -1} if absent</li>
|
||||
* <li>{@code Optional<Vector> sourcePosition} – world position of the damage source, if any</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundDamageEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DAMAGE_EVENT;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(MinecraftReflection.getHolderClass(),
|
||||
Converters.holder(BukkitConverters.getDamageTypeConverter(),
|
||||
WrappedRegistry.getRegistry(MinecraftReflection.getDamageTypeClass())))
|
||||
.withParam(int.class)
|
||||
.withParam(int.class)
|
||||
.withParam(Optional.class, Converters.optional(BukkitConverters.getVectorConverter()));
|
||||
|
||||
public WrappedClientboundDamageEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDamageEventPacket(int entityId, DamageType sourceType, int sourceCauseId, int sourceDirectId, Optional<Vector> sourcePosition) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(entityId, sourceType, sourceCauseId, sourceDirectId, sourcePosition)));
|
||||
}
|
||||
|
||||
public WrappedClientboundDamageEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().readSafely(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().writeSafely(0, entityId);
|
||||
}
|
||||
|
||||
/** Returns the damage type, unwrapped from its registry {@code Holder}. */
|
||||
public DamageType getSourceType() {
|
||||
return handle.getDamageTypes().readSafely(0);
|
||||
}
|
||||
|
||||
public void setSourceType(DamageType sourceType) {
|
||||
handle.getDamageTypes().writeSafely(0, sourceType);
|
||||
}
|
||||
|
||||
public int getSourceCauseId() {
|
||||
return handle.getIntegers().readSafely(1);
|
||||
}
|
||||
|
||||
public void setSourceCauseId(int sourceCauseId) {
|
||||
handle.getIntegers().writeSafely(1, sourceCauseId);
|
||||
}
|
||||
|
||||
public int getSourceDirectId() {
|
||||
return handle.getIntegers().readSafely(2);
|
||||
}
|
||||
|
||||
public void setSourceDirectId(int sourceDirectId) {
|
||||
handle.getIntegers().writeSafely(2, sourceDirectId);
|
||||
}
|
||||
|
||||
public Optional<Vector> getSourcePosition() {
|
||||
return handle.getOptionals(BukkitConverters.getVectorConverter()).readSafely(0);
|
||||
}
|
||||
|
||||
public void setSourcePosition(Optional<Vector> sourcePosition) {
|
||||
handle.getOptionals(BukkitConverters.getVectorConverter()).writeSafely(0, sourcePosition);
|
||||
}
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDebugBlockValuePacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Fields:
|
||||
* <ul>
|
||||
* <li>{@code BlockPos blockPos} – the block position associated with this debug value</li>
|
||||
* <li>{@code DebugSubscription.Update<?> update} – the debug update data (opaque, no ProtocolLib accessor)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundDebugBlockValuePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DEBUG_BLOCK_VALUE;
|
||||
|
||||
public WrappedClientboundDebugBlockValuePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDebugBlockValuePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public BlockPosition getBlockPos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setBlockPos(BlockPosition blockPos) {
|
||||
handle.getBlockPositionModifier().write(0, blockPos);
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDebugChunkValuePacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Fields:
|
||||
* <ul>
|
||||
* <li>{@code ChunkPos chunkPos} – the chunk position associated with this debug value</li>
|
||||
* <li>{@code DebugSubscription.Update<?> update} – the debug update data (opaque, no ProtocolLib accessor)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundDebugChunkValuePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DEBUG_CHUNK_VALUE;
|
||||
|
||||
public WrappedClientboundDebugChunkValuePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDebugChunkValuePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public ChunkCoordIntPair getChunkPos() {
|
||||
return handle.getChunkCoordIntPairs().read(0);
|
||||
}
|
||||
|
||||
public void setChunkPos(ChunkCoordIntPair chunkPos) {
|
||||
handle.getChunkCoordIntPairs().write(0, chunkPos);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDebugEntityValuePacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Fields:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – the entity ID</li>
|
||||
* <li>{@code DebugSubscription.Update<?> update} – the debug update data (opaque, no ProtocolLib accessor)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundDebugEntityValuePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DEBUG_ENTITY_VALUE;
|
||||
|
||||
public WrappedClientboundDebugEntityValuePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDebugEntityValuePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(0, entityId);
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDebugEventPacket} (game phase, clientbound).
|
||||
* Sends a debug event. The event field has no ProtocolLib accessor.
|
||||
*/
|
||||
public class WrappedClientboundDebugEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DEBUG_EVENT;
|
||||
|
||||
public WrappedClientboundDebugEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDebugEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// TODO: missing field 'event' (NMS type: DebugSubscription.Event<?> — registry-backed debug event)
|
||||
// No ProtocolLib accessor exists. Use handle.getModifier().read(0) for the raw event object.
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDebugSamplePacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code long[] sample} – array of debug timing samples</li>
|
||||
* <li>{@code DebugSampleType debugSampleType} – the type of debug data being sampled</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundDebugSamplePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DEBUG_SAMPLE;
|
||||
|
||||
/**
|
||||
* The type of debug sample data being sent.
|
||||
* Matches {@code net.minecraft.util.debugchart.RemoteDebugSampleType}.
|
||||
*/
|
||||
public enum DebugSampleType {
|
||||
TICK_TIME
|
||||
}
|
||||
|
||||
private static final Class<?> REMOTE_DEBUG_SAMPLE_TYPE_CLASS =
|
||||
MinecraftReflection.getMinecraftClass("util.debugchart.RemoteDebugSampleType");
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(long[].class)
|
||||
.withParam(REMOTE_DEBUG_SAMPLE_TYPE_CLASS,
|
||||
new EnumWrappers.EnumConverter<>(REMOTE_DEBUG_SAMPLE_TYPE_CLASS, DebugSampleType.class));
|
||||
|
||||
public WrappedClientboundDebugSamplePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDebugSamplePacket(long[] sample, DebugSampleType debugSampleType) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(sample, debugSampleType)));
|
||||
}
|
||||
|
||||
public WrappedClientboundDebugSamplePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public long[] getSample() {
|
||||
return handle.getSpecificModifier(long[].class).readSafely(0);
|
||||
}
|
||||
|
||||
public void setSample(long[] sample) {
|
||||
handle.getSpecificModifier(long[].class).writeSafely(0, sample);
|
||||
}
|
||||
|
||||
public DebugSampleType getDebugSampleType() {
|
||||
return handle.getEnumModifier(DebugSampleType.class, 1).readSafely(0);
|
||||
}
|
||||
|
||||
public void setDebugSampleType(DebugSampleType debugSampleType) {
|
||||
handle.getEnumModifier(DebugSampleType.class, 1).writeSafely(0, debugSampleType);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedMessageSignature;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDeleteChatPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code MessageSignature.Packed messageSignature} – identifies the message to delete</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: The NMS field is {@code MessageSignature.Packed} (an inner record), which differs from
|
||||
* the plain {@code MessageSignature} class used by {@code getMessageSignatures()}. As a result,
|
||||
* the {@code messageSignature} field is not accessible via the standard modifier; getter/setter
|
||||
* operate as no-ops and always return {@code null}.
|
||||
*/
|
||||
public class WrappedClientboundDeleteChatPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DELETE_CHAT_MESSAGE;
|
||||
|
||||
public WrappedClientboundDeleteChatPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDeleteChatPacket(WrappedMessageSignature messageSignature) {
|
||||
this();
|
||||
setMessageSignature(messageSignature);
|
||||
}
|
||||
|
||||
public WrappedClientboundDeleteChatPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public WrappedMessageSignature getMessageSignature() {
|
||||
return handle.getMessageSignatures().readSafely(0);
|
||||
}
|
||||
|
||||
public void setMessageSignature(WrappedMessageSignature messageSignature) {
|
||||
handle.getMessageSignatures().writeSafely(0, messageSignature);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDisconnectPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code WrappedChatComponent reason} – disconnect reason shown to the player</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundDisconnectPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.KICK_DISCONNECT;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
|
||||
|
||||
public WrappedClientboundDisconnectPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDisconnectPacket(WrappedChatComponent reason) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(reason)));
|
||||
}
|
||||
|
||||
public WrappedClientboundDisconnectPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public WrappedChatComponent getReason() {
|
||||
return handle.getChatComponents().read(0);
|
||||
}
|
||||
|
||||
public void setReason(WrappedChatComponent reason) {
|
||||
handle.getChatComponents().write(0, reason);
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatTypeBound;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundDisguisedChatPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundDisguisedChatPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.DISGUISED_CHAT;
|
||||
|
||||
private static final Class<?> CHAT_TYPE_BOUND_CLASS =
|
||||
MinecraftReflection.getMinecraftClass("network.chat.ChatType$Bound");
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter())
|
||||
.withParam(CHAT_TYPE_BOUND_CLASS, WrappedChatTypeBound.CONVERTER);
|
||||
|
||||
public WrappedClientboundDisguisedChatPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundDisguisedChatPacket(WrappedChatComponent message) {
|
||||
this(message, new WrappedChatTypeBound(
|
||||
new com.comphenix.protocol.wrappers.MinecraftKey("chat"),
|
||||
WrappedChatComponent.fromText(""),
|
||||
Optional.empty()));
|
||||
}
|
||||
|
||||
public WrappedClientboundDisguisedChatPacket(WrappedChatComponent message, WrappedChatTypeBound chatType) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(message, chatType)));
|
||||
}
|
||||
|
||||
public WrappedClientboundDisguisedChatPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public WrappedChatComponent getMessage() {
|
||||
return handle.getChatComponents().read(0);
|
||||
}
|
||||
|
||||
public void setMessage(WrappedChatComponent message) {
|
||||
handle.getChatComponents().write(0, message);
|
||||
}
|
||||
|
||||
public WrappedChatTypeBound getChatType() {
|
||||
return handle.getModifier().withType(CHAT_TYPE_BOUND_CLASS, WrappedChatTypeBound.CONVERTER).read(0);
|
||||
}
|
||||
|
||||
public void setChatType(WrappedChatTypeBound chatType) {
|
||||
handle.getModifier().withType(CHAT_TYPE_BOUND_CLASS, WrappedChatTypeBound.CONVERTER).write(0, chatType);
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundEntityEventPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Triggers a status/animation on an entity (e.g. hurt flash, death
|
||||
* animation, taming success/failure).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – the affected entity's ID</li>
|
||||
* <li>{@code byte status} – event/status code (see Minecraft protocol wiki)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundEntityEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_STATUS;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getEntityClass(), BukkitUnwrapper.getInstance())
|
||||
.withParam(byte.class);
|
||||
|
||||
public WrappedClientboundEntityEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundEntityEventPacket(int entityId, byte status) {
|
||||
this();
|
||||
setEntityId(entityId);
|
||||
setStatus(status);
|
||||
}
|
||||
|
||||
public WrappedClientboundEntityEventPacket(Entity entity, byte status) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(entity, status)));
|
||||
}
|
||||
|
||||
public WrappedClientboundEntityEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().readSafely(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().writeSafely(0, entityId);
|
||||
}
|
||||
|
||||
public Entity getEntity(World world) {
|
||||
return handle.getEntityModifier(world).readSafely(0);
|
||||
}
|
||||
|
||||
public void setEntity(Entity entity) {
|
||||
handle.getEntityModifier(entity.getWorld()).writeSafely(0, entity);
|
||||
}
|
||||
|
||||
public byte getStatus() {
|
||||
return handle.getBytes().readSafely(0);
|
||||
}
|
||||
|
||||
public void setStatus(byte status) {
|
||||
handle.getBytes().writeSafely(0, status);
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedPositionMoveRotation;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundEntityPositionSyncPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundEntityPositionSyncPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_POSITION_SYNC;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(MinecraftReflection.getMinecraftClass("world.entity.PositionMoveRotation"),
|
||||
WrappedPositionMoveRotation.getConverter())
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundEntityPositionSyncPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundEntityPositionSyncPacket(int id, WrappedPositionMoveRotation values, boolean onGround) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(id, values, onGround)));
|
||||
}
|
||||
|
||||
public WrappedClientboundEntityPositionSyncPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
handle.getIntegers().write(0, id);
|
||||
}
|
||||
|
||||
public WrappedPositionMoveRotation getValues() {
|
||||
return handle.getPositionMoveRotations().read(0);
|
||||
}
|
||||
|
||||
public void setValues(WrappedPositionMoveRotation values) {
|
||||
handle.getPositionMoveRotations().write(0, values);
|
||||
}
|
||||
|
||||
public boolean isOnGround() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setOnGround(boolean onGround) {
|
||||
handle.getBooleans().write(0, onGround);
|
||||
}
|
||||
}
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.WrappedExplosionParticleInfo;
|
||||
import com.comphenix.protocol.wrappers.WrappedParticle;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
||||
import com.comphenix.protocol.wrappers.WrappedWeightedList;
|
||||
import java.util.Optional;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundExplodePacket} (game phase, clientbound).
|
||||
* <p>
|
||||
* NMS record fields (declaration order):
|
||||
* <ol>
|
||||
* <li>{@code Vec3 center}</li>
|
||||
* <li>{@code float radius}</li>
|
||||
* <li>{@code int blockCount}</li>
|
||||
* <li>{@code Optional<Vec3> playerKnockback}</li>
|
||||
* <li>{@code ParticleOptions explosionParticle}</li>
|
||||
* <li>{@code Holder<SoundEvent> explosionSound}</li>
|
||||
* <li>{@code WeightedList<ExplosionParticleInfo> blockParticles}</li>
|
||||
* </ol>
|
||||
*/
|
||||
public class WrappedClientboundExplodePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.EXPLOSION;
|
||||
|
||||
public WrappedClientboundExplodePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundExplodePacket(Vector center, float radius, int blockCount, Optional<Vector> playerKnockback, WrappedParticle<?> explosionParticle, Sound explosionSound, WrappedWeightedList<WrappedExplosionParticleInfo> blockParticles) {
|
||||
this();
|
||||
setCenter(center);
|
||||
setRadius(radius);
|
||||
setBlockCount(blockCount);
|
||||
setPlayerKnockback(playerKnockback);
|
||||
setExplosionParticle(explosionParticle);
|
||||
setExplosionSound(explosionSound);
|
||||
setBlockParticles(blockParticles);
|
||||
}
|
||||
|
||||
public WrappedClientboundExplodePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// ── center (Vec3) ────────────────────────────────────────────────────
|
||||
|
||||
public Vector getCenter() {
|
||||
return handle.getVectors().read(0);
|
||||
}
|
||||
|
||||
public void setCenter(Vector center) {
|
||||
handle.getVectors().write(0, center);
|
||||
}
|
||||
|
||||
// ── radius (float) ──────────────────────────────────────────────────
|
||||
|
||||
public float getRadius() {
|
||||
return handle.getFloat().read(0);
|
||||
}
|
||||
|
||||
public void setRadius(float radius) {
|
||||
handle.getFloat().write(0, radius);
|
||||
}
|
||||
|
||||
// ── blockCount (int) ────────────────────────────────────────────────
|
||||
|
||||
public int getBlockCount() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setBlockCount(int blockCount) {
|
||||
handle.getIntegers().write(0, blockCount);
|
||||
}
|
||||
|
||||
// ── playerKnockback (Optional<Vec3>) ────────────────────────────────
|
||||
|
||||
public Optional<Vector> getPlayerKnockback() {
|
||||
return handle.getOptionals(BukkitConverters.getVectorConverter()).read(0);
|
||||
}
|
||||
|
||||
public void setPlayerKnockback(Optional<Vector> playerKnockback) {
|
||||
handle.getOptionals(BukkitConverters.getVectorConverter()).write(0, playerKnockback);
|
||||
}
|
||||
|
||||
// ── explosionParticle (ParticleOptions) ─────────────────────────────
|
||||
|
||||
public WrappedParticle<?> getExplosionParticle() {
|
||||
return handle.getNewParticles().read(0);
|
||||
}
|
||||
|
||||
public void setExplosionParticle(WrappedParticle<?> explosionParticle) {
|
||||
handle.getNewParticles().write(0, explosionParticle);
|
||||
}
|
||||
|
||||
// ── explosionSound (Holder<SoundEvent>) ─────────────────────────────
|
||||
|
||||
public Sound getExplosionSound() {
|
||||
return handle.getSoundEffects().read(0);
|
||||
}
|
||||
|
||||
public void setExplosionSound(Sound explosionSound) {
|
||||
handle.getSoundEffects().write(0, explosionSound);
|
||||
}
|
||||
|
||||
// ── blockParticles (WeightedList<ExplosionParticleInfo>) ────────────
|
||||
|
||||
public WrappedWeightedList<WrappedExplosionParticleInfo> getBlockParticles() {
|
||||
return handle.getWeightedLists(WrappedExplosionParticleInfo.getConverter()).read(0);
|
||||
}
|
||||
|
||||
public void setBlockParticles(WrappedWeightedList<WrappedExplosionParticleInfo> blockParticles) {
|
||||
handle.getWeightedLists(WrappedExplosionParticleInfo.getConverter()).write(0, blockParticles);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundForgetLevelChunkPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Tells the client to unload the specified chunk column.
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code ChunkPos pos} – chunk coordinates of the column to unload</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundForgetLevelChunkPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.UNLOAD_CHUNK;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getChunkCoordIntPair(), ChunkCoordIntPair.getConverter());
|
||||
|
||||
public WrappedClientboundForgetLevelChunkPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundForgetLevelChunkPacket(ChunkCoordIntPair pos) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(pos)));
|
||||
}
|
||||
|
||||
public WrappedClientboundForgetLevelChunkPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public ChunkCoordIntPair getPos() {
|
||||
return handle.getChunkCoordIntPairs().read(0);
|
||||
}
|
||||
|
||||
public void setPos(ChunkCoordIntPair pos) {
|
||||
handle.getChunkCoordIntPairs().write(0, pos);
|
||||
}
|
||||
|
||||
public int getChunkX() {
|
||||
return getPos().getChunkX();
|
||||
}
|
||||
|
||||
public void setChunkX(int x) {
|
||||
setPos(new ChunkCoordIntPair(x, getChunkZ()));
|
||||
}
|
||||
|
||||
public int getChunkZ() {
|
||||
return getPos().getChunkZ();
|
||||
}
|
||||
|
||||
public void setChunkZ(int z) {
|
||||
setPos(new ChunkCoordIntPair(getChunkX(), z));
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundGameEventPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Notifies the client of a game-state change such as starting rain, changing
|
||||
* game mode, or ending the game.
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int event} – the game-event/reason ID (see Minecraft protocol wiki)</li>
|
||||
* <li>{@code float value} – numeric parameter for the event</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundGameEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.GAME_STATE_CHANGE;
|
||||
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getGameStateClass(), BukkitConverters.getGameStateConverter())
|
||||
.withParam(float.class);
|
||||
|
||||
public WrappedClientboundGameEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundGameEventPacket(int event, float value) {
|
||||
this(new PacketContainer(TYPE, CONSTRUCTOR.create(event, value)));
|
||||
}
|
||||
|
||||
public WrappedClientboundGameEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
/** Returns the game-event ID (reason code). */
|
||||
public int getEvent() {
|
||||
return handle.getGameStateIDs().readSafely(0);
|
||||
}
|
||||
|
||||
public void setEvent(int event) {
|
||||
handle.getGameStateIDs().writeSafely(0, event);
|
||||
}
|
||||
|
||||
/** Returns the float parameter associated with the event. */
|
||||
public float getValue() {
|
||||
return handle.getFloat().readSafely(0);
|
||||
}
|
||||
|
||||
public void setValue(float value) {
|
||||
handle.getFloat().writeSafely(0, value);
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.wrappers.Converters;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistry;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundGameRuleValuesPacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>Fields:
|
||||
* <ul>
|
||||
* <li>{@code Map<ResourceKey<GameRule<?>>, String> values} – current game-rule values by key</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundGameRuleValuesPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.GAME_RULE_VALUES;
|
||||
|
||||
/** Converter between NMS {@code ResourceKey<GameRule<?>>} and {@link MinecraftKey}. */
|
||||
private static final EquivalentConverter<MinecraftKey> GAME_RULE_KEY_CONVERTER =
|
||||
WrappedRegistry.getGameRuleRegistry().resourceKeyConverter();
|
||||
|
||||
public WrappedClientboundGameRuleValuesPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundGameRuleValuesPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the game-rule values as a {@code Map<MinecraftKey, String>}.
|
||||
* Each key is the game rule's identifier (e.g. {@code minecraft:doFireTick}).
|
||||
*/
|
||||
public Map<MinecraftKey, String> getValues() {
|
||||
Map<MinecraftKey, String> values = handle.getMaps(GAME_RULE_KEY_CONVERTER, Converters.passthrough(String.class)).read(0);
|
||||
return values != null ? values : Map.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the game-rule values from a {@code Map<MinecraftKey, String>}.
|
||||
* Each key is converted to a {@code ResourceKey<GameRule<?>>} in the {@code game_rule} registry.
|
||||
*/
|
||||
public void setValues(Map<MinecraftKey, String> values) {
|
||||
handle.getMaps(GAME_RULE_KEY_CONVERTER, Converters.passthrough(String.class)).write(0, values);
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundGameTestHighlightPosPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundGameTestHighlightPosPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.GAME_TEST_HIGHLIGHT_POS;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter())
|
||||
.withParam(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter());
|
||||
|
||||
public WrappedClientboundGameTestHighlightPosPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundGameTestHighlightPosPacket(BlockPosition absolutePos, BlockPosition relativePos) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(absolutePos, relativePos)));
|
||||
}
|
||||
|
||||
public WrappedClientboundGameTestHighlightPosPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public BlockPosition getAbsolutePos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setAbsolutePos(BlockPosition absolutePos) {
|
||||
handle.getBlockPositionModifier().write(0, absolutePos);
|
||||
}
|
||||
|
||||
public BlockPosition getRelativePos() {
|
||||
return handle.getBlockPositionModifier().read(1);
|
||||
}
|
||||
|
||||
public void setRelativePos(BlockPosition relativePos) {
|
||||
handle.getBlockPositionModifier().write(1, relativePos);
|
||||
}
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundHurtAnimationPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Triggers the hurt/damage animation on an entity. The {@code yaw} field
|
||||
* controls the direction the hurt animation originates from, in degrees.
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int id} – entity ID</li>
|
||||
* <li>{@code float yaw} – yaw angle of the damage source (degrees)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundHurtAnimationPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.HURT_ANIMATION;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(float.class);
|
||||
|
||||
public WrappedClientboundHurtAnimationPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundHurtAnimationPacket(int entityId, float yaw) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(entityId, yaw)));
|
||||
}
|
||||
|
||||
public WrappedClientboundHurtAnimationPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Entity ID
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(0, entityId);
|
||||
}
|
||||
|
||||
public Entity getEntity(World world) {
|
||||
return handle.getEntityModifier(world).read(0);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Damage source yaw
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** Yaw angle (degrees) of the incoming damage direction. */
|
||||
public float getYaw() {
|
||||
return handle.getFloat().read(0);
|
||||
}
|
||||
|
||||
public void setYaw(float yaw) {
|
||||
handle.getFloat().write(0, yaw);
|
||||
}
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundInitializeBorderPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code double newCenterX}</li>
|
||||
* <li>{@code double newCenterZ}</li>
|
||||
* <li>{@code double oldSize}</li>
|
||||
* <li>{@code double newSize}</li>
|
||||
* <li>{@code long lerpTime}</li>
|
||||
* <li>{@code int newAbsoluteMaxSize}</li>
|
||||
* <li>{@code int warningBlocks}</li>
|
||||
* <li>{@code int warningTime}</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundInitializeBorderPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.INITIALIZE_BORDER;
|
||||
|
||||
public WrappedClientboundInitializeBorderPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundInitializeBorderPacket(double newCenterX, double newCenterZ, double oldSize, double newSize, long lerpTime, int newAbsoluteMaxSize, int warningBlocks, int warningTime) {
|
||||
this();
|
||||
setNewCenterX(newCenterX);
|
||||
setNewCenterZ(newCenterZ);
|
||||
setOldSize(oldSize);
|
||||
setNewSize(newSize);
|
||||
setLerpTime(lerpTime);
|
||||
setNewAbsoluteMaxSize(newAbsoluteMaxSize);
|
||||
setWarningBlocks(warningBlocks);
|
||||
setWarningTime(warningTime);
|
||||
}
|
||||
|
||||
public WrappedClientboundInitializeBorderPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public double getNewCenterX() {
|
||||
return handle.getDoubles().read(0);
|
||||
}
|
||||
|
||||
public void setNewCenterX(double newCenterX) {
|
||||
handle.getDoubles().write(0, newCenterX);
|
||||
}
|
||||
|
||||
public double getNewCenterZ() {
|
||||
return handle.getDoubles().read(1);
|
||||
}
|
||||
|
||||
public void setNewCenterZ(double newCenterZ) {
|
||||
handle.getDoubles().write(1, newCenterZ);
|
||||
}
|
||||
|
||||
public double getOldSize() {
|
||||
return handle.getDoubles().read(2);
|
||||
}
|
||||
|
||||
public void setOldSize(double oldSize) {
|
||||
handle.getDoubles().write(2, oldSize);
|
||||
}
|
||||
|
||||
public double getNewSize() {
|
||||
return handle.getDoubles().read(3);
|
||||
}
|
||||
|
||||
public void setNewSize(double newSize) {
|
||||
handle.getDoubles().write(3, newSize);
|
||||
}
|
||||
|
||||
public long getLerpTime() {
|
||||
return handle.getLongs().read(0);
|
||||
}
|
||||
|
||||
public void setLerpTime(long lerpTime) {
|
||||
handle.getLongs().write(0, lerpTime);
|
||||
}
|
||||
|
||||
public int getNewAbsoluteMaxSize() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setNewAbsoluteMaxSize(int newAbsoluteMaxSize) {
|
||||
handle.getIntegers().write(0, newAbsoluteMaxSize);
|
||||
}
|
||||
|
||||
public int getWarningBlocks() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setWarningBlocks(int warningBlocks) {
|
||||
handle.getIntegers().write(1, warningBlocks);
|
||||
}
|
||||
|
||||
public int getWarningTime() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setWarningTime(int warningTime) {
|
||||
handle.getIntegers().write(2, warningTime);
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundKeepAlivePacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Sent by the server to verify the client connection. The client must
|
||||
* respond with a matching {@code ServerboundKeepAlivePacket}.
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code long id} – keep-alive token to echo back</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundKeepAlivePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.KEEP_ALIVE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(long.class);
|
||||
|
||||
public WrappedClientboundKeepAlivePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundKeepAlivePacket(long id) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(id)));
|
||||
}
|
||||
|
||||
public WrappedClientboundKeepAlivePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return handle.getLongs().read(0);
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
handle.getLongs().write(0, id);
|
||||
}
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundLevelChunkWithLightPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundLevelChunkWithLightPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.MAP_CHUNK;
|
||||
|
||||
public WrappedClientboundLevelChunkWithLightPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundLevelChunkWithLightPacket(int x, int z) {
|
||||
this();
|
||||
setX(x);
|
||||
setZ(z);
|
||||
}
|
||||
|
||||
public WrappedClientboundLevelChunkWithLightPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
handle.getIntegers().write(0, x);
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setZ(int z) {
|
||||
handle.getIntegers().write(1, z);
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundLevelEventPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int type} – event type ID</li>
|
||||
* <li>{@code BlockPosition pos} – position of the event</li>
|
||||
* <li>{@code int data} – event-specific data</li>
|
||||
* <li>{@code boolean broadcastToAll} – if {@code true}, the event is broadcast to all nearby players</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundLevelEventPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.WORLD_EVENT;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(MinecraftReflection.getBlockPositionClass(), BlockPosition.getConverter())
|
||||
.withParam(int.class)
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundLevelEventPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundLevelEventPacket(int type, BlockPosition pos, int data, boolean broadcastToAll) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(type, pos, data, broadcastToAll)));
|
||||
}
|
||||
|
||||
public WrappedClientboundLevelEventPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
handle.getIntegers().write(0, type);
|
||||
}
|
||||
|
||||
public BlockPosition getPos() {
|
||||
return handle.getBlockPositionModifier().read(0);
|
||||
}
|
||||
|
||||
public void setPos(BlockPosition pos) {
|
||||
handle.getBlockPositionModifier().write(0, pos);
|
||||
}
|
||||
|
||||
public int getData() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setData(int data) {
|
||||
handle.getIntegers().write(1, data);
|
||||
}
|
||||
|
||||
public boolean isBroadcastToAll() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setBroadcastToAll(boolean broadcastToAll) {
|
||||
handle.getBooleans().write(0, broadcastToAll);
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.WrappedParticle;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundLevelParticlesPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundLevelParticlesPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.WORLD_PARTICLES;
|
||||
|
||||
public WrappedClientboundLevelParticlesPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundLevelParticlesPacket(boolean overrideLimiter, boolean alwaysShow, double x, double y, double z, float xDist, float yDist, float zDist, float maxSpeed, int count, WrappedParticle<?> particle) {
|
||||
this();
|
||||
setOverrideLimiter(overrideLimiter);
|
||||
setAlwaysShow(alwaysShow);
|
||||
setX(x);
|
||||
setY(y);
|
||||
setZ(z);
|
||||
setXDist(xDist);
|
||||
setYDist(yDist);
|
||||
setZDist(zDist);
|
||||
setMaxSpeed(maxSpeed);
|
||||
setCount(count);
|
||||
setParticle(particle);
|
||||
}
|
||||
|
||||
public WrappedClientboundLevelParticlesPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public boolean isOverrideLimiter() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setOverrideLimiter(boolean overrideLimiter) {
|
||||
handle.getBooleans().write(0, overrideLimiter);
|
||||
}
|
||||
|
||||
public boolean isAlwaysShow() {
|
||||
return handle.getBooleans().read(1);
|
||||
}
|
||||
|
||||
public void setAlwaysShow(boolean alwaysShow) {
|
||||
handle.getBooleans().write(1, alwaysShow);
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return handle.getDoubles().read(0);
|
||||
}
|
||||
|
||||
public void setX(double x) {
|
||||
handle.getDoubles().write(0, x);
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return handle.getDoubles().read(1);
|
||||
}
|
||||
|
||||
public void setY(double y) {
|
||||
handle.getDoubles().write(1, y);
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return handle.getDoubles().read(2);
|
||||
}
|
||||
|
||||
public void setZ(double z) {
|
||||
handle.getDoubles().write(2, z);
|
||||
}
|
||||
|
||||
public float getXDist() {
|
||||
return handle.getFloat().read(0);
|
||||
}
|
||||
|
||||
public void setXDist(float xDist) {
|
||||
handle.getFloat().write(0, xDist);
|
||||
}
|
||||
|
||||
public float getYDist() {
|
||||
return handle.getFloat().read(1);
|
||||
}
|
||||
|
||||
public void setYDist(float yDist) {
|
||||
handle.getFloat().write(1, yDist);
|
||||
}
|
||||
|
||||
public float getZDist() {
|
||||
return handle.getFloat().read(2);
|
||||
}
|
||||
|
||||
public void setZDist(float zDist) {
|
||||
handle.getFloat().write(2, zDist);
|
||||
}
|
||||
|
||||
public float getMaxSpeed() {
|
||||
return handle.getFloat().read(3);
|
||||
}
|
||||
|
||||
public void setMaxSpeed(float maxSpeed) {
|
||||
handle.getFloat().write(3, maxSpeed);
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setCount(int count) {
|
||||
handle.getIntegers().write(0, count);
|
||||
}
|
||||
|
||||
public WrappedParticle<?> getParticle() {
|
||||
return handle.getNewParticles().read(0);
|
||||
}
|
||||
|
||||
public void setParticle(WrappedParticle<?> particle) {
|
||||
handle.getNewParticles().write(0, particle);
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.WrappedLevelChunkData;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundLightUpdatePacket} (game phase, clientbound).
|
||||
*
|
||||
* <p>NMS record: {@code ClientboundLightUpdatePacket(int x, int z, ClientboundLightUpdatePacketData lightData)}
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int x} – chunk section X coordinate</li>
|
||||
* <li>{@code int z} – chunk section Z coordinate</li>
|
||||
* <li>{@code WrappedLevelChunkData.LightData lightData} – light engine data for the section</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Note: the NMS canonical constructor is not used because {@code ClientboundLightUpdatePacketData}
|
||||
* may not be present in all supported server versions; all fields are set via ProtocolLib's
|
||||
* {@code StructureModifier} after creating a default packet container.
|
||||
*/
|
||||
public class WrappedClientboundLightUpdatePacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.LIGHT_UPDATE;
|
||||
|
||||
public WrappedClientboundLightUpdatePacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundLightUpdatePacket(int x, int z, WrappedLevelChunkData.LightData lightData) {
|
||||
this();
|
||||
setX(x);
|
||||
setZ(z);
|
||||
setLightData(lightData);
|
||||
}
|
||||
|
||||
public WrappedClientboundLightUpdatePacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
handle.getIntegers().write(0, x);
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setZ(int z) {
|
||||
handle.getIntegers().write(1, z);
|
||||
}
|
||||
|
||||
/** Returns the light engine data for the section, or {@code null} if not set. */
|
||||
public WrappedLevelChunkData.LightData getLightData() {
|
||||
Object raw = handle.getModifier().read(2);
|
||||
return raw != null ? BukkitConverters.getWrappedLightDataConverter().getSpecific(raw) : null;
|
||||
}
|
||||
|
||||
public void setLightData(WrappedLevelChunkData.LightData lightData) {
|
||||
handle.getModifier().write(2,
|
||||
lightData != null ? BukkitConverters.getWrappedLightDataConverter().getGeneric(lightData) : null);
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import java.util.Set;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.World;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundLoginPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundLoginPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.LOGIN;
|
||||
|
||||
public WrappedClientboundLoginPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundLoginPacket(int playerId, boolean hardcore, int maxPlayers, int chunkRadius, int simulationDistance, boolean reducedDebugInfo, boolean showDeathScreen, boolean doLimitedCrafting, boolean enforcesSecureChat, Set<World> levels) {
|
||||
this();
|
||||
setPlayerId(playerId);
|
||||
setHardcore(hardcore);
|
||||
setMaxPlayers(maxPlayers);
|
||||
setChunkRadius(chunkRadius);
|
||||
setSimulationDistance(simulationDistance);
|
||||
setReducedDebugInfo(reducedDebugInfo);
|
||||
setShowDeathScreen(showDeathScreen);
|
||||
setDoLimitedCrafting(doLimitedCrafting);
|
||||
setEnforcesSecureChat(enforcesSecureChat);
|
||||
setLevels(levels);
|
||||
}
|
||||
|
||||
public WrappedClientboundLoginPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getPlayerId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setPlayerId(int playerId) {
|
||||
handle.getIntegers().write(0, playerId);
|
||||
}
|
||||
|
||||
public boolean isHardcore() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setHardcore(boolean hardcore) {
|
||||
handle.getBooleans().write(0, hardcore);
|
||||
}
|
||||
|
||||
public int getMaxPlayers() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setMaxPlayers(int maxPlayers) {
|
||||
handle.getIntegers().write(1, maxPlayers);
|
||||
}
|
||||
|
||||
public int getChunkRadius() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setChunkRadius(int chunkRadius) {
|
||||
handle.getIntegers().write(2, chunkRadius);
|
||||
}
|
||||
|
||||
public int getSimulationDistance() {
|
||||
return handle.getIntegers().read(3);
|
||||
}
|
||||
|
||||
public void setSimulationDistance(int simulationDistance) {
|
||||
handle.getIntegers().write(3, simulationDistance);
|
||||
}
|
||||
|
||||
public boolean isReducedDebugInfo() {
|
||||
return handle.getBooleans().read(1);
|
||||
}
|
||||
|
||||
public void setReducedDebugInfo(boolean reducedDebugInfo) {
|
||||
handle.getBooleans().write(1, reducedDebugInfo);
|
||||
}
|
||||
|
||||
public boolean isShowDeathScreen() {
|
||||
return handle.getBooleans().read(2);
|
||||
}
|
||||
|
||||
public void setShowDeathScreen(boolean showDeathScreen) {
|
||||
handle.getBooleans().write(2, showDeathScreen);
|
||||
}
|
||||
|
||||
public boolean isDoLimitedCrafting() {
|
||||
return handle.getBooleans().read(3);
|
||||
}
|
||||
|
||||
public void setDoLimitedCrafting(boolean doLimitedCrafting) {
|
||||
handle.getBooleans().write(3, doLimitedCrafting);
|
||||
}
|
||||
|
||||
public boolean isEnforcesSecureChat() {
|
||||
return handle.getBooleans().read(4);
|
||||
}
|
||||
|
||||
public void setEnforcesSecureChat(boolean enforcesSecureChat) {
|
||||
handle.getBooleans().write(4, enforcesSecureChat);
|
||||
}
|
||||
|
||||
/** Returns the set of all dimension levels/worlds the client is allowed to enter. */
|
||||
public Set<World> getLevels() {
|
||||
return handle.getSets(BukkitConverters.getWorldKeyConverter()).read(0);
|
||||
}
|
||||
|
||||
public void setLevels(Set<World> levels) {
|
||||
handle.getSets(BukkitConverters.getWorldKeyConverter()).write(0, levels);
|
||||
}
|
||||
|
||||
// TODO: missing field 'commonPlayerSpawnInfo' (NMS type: CommonPlayerSpawnInfo)
|
||||
// CommonPlayerSpawnInfo holds: Holder<DimensionType> dimensionType, ResourceKey<Level> dimension,
|
||||
// long seed, GameType gameType, @Nullable GameType previousGameType, boolean isDebug,
|
||||
// boolean isFlat, Optional<GlobalPos> lastDeathLocation, int portalCooldown, int seaLevel.
|
||||
// This is a shared type used by both Login and Respawn packets.
|
||||
// Add a WrappedCommonPlayerSpawnInfo wrapper class and a getCommonPlayerSpawnInfos() accessor
|
||||
// in AbstractStructure, then expose it here.
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.wrappers.AutoWrapper;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundMapItemDataPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>NMS structure (1.21+):
|
||||
* <pre>
|
||||
* record ClientboundMapItemDataPacket(
|
||||
* MapId mapId, // field 0
|
||||
* byte scale, // field 1
|
||||
* boolean locked, // field 2
|
||||
* Optional<List<MapDecoration>> decorations, // field 3
|
||||
* Optional<MapItemSavedData.MapPatch> colorPatch) // field 4
|
||||
*
|
||||
* record MapId(int id)
|
||||
* record MapDecoration(Holder<MapDecorationType> type, byte x, byte y, byte rot, Optional<Component> name)
|
||||
* record MapItemSavedData.MapPatch(int startX, int startY, int width, int height, byte[] mapColors)
|
||||
* </pre>
|
||||
*
|
||||
* <p>All five fields are accessed via {@link AutoWrapper} POJOs using the raw
|
||||
* {@link PacketContainer#getModifier()} accessor (global field indices 0–4).
|
||||
* {@link WrappedMapDecoration#type} ({@code Holder<MapDecorationType>}) and
|
||||
* {@link WrappedMapDecoration#name} ({@code Optional<Component>}) are kept as raw
|
||||
* {@link Object} pass-throughs to avoid NMS compile-time dependencies.
|
||||
*/
|
||||
public class WrappedClientboundMapItemDataPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.MAP;
|
||||
|
||||
// AutoWrappers for the nested NMS record types.
|
||||
private static final AutoWrapper<WrappedMapId> MAP_ID_WRAPPER =
|
||||
AutoWrapper.wrap(WrappedMapId.class, "world.level.saveddata.maps.MapId");
|
||||
private static final AutoWrapper<WrappedMapDecoration> MAP_DECORATION_WRAPPER =
|
||||
AutoWrapper.wrap(WrappedMapDecoration.class, "world.level.saveddata.maps.MapDecoration");
|
||||
private static final AutoWrapper<WrappedMapPatch> MAP_PATCH_WRAPPER =
|
||||
AutoWrapper.wrap(WrappedMapPatch.class, "world.level.saveddata.maps.MapItemSavedData$MapPatch");
|
||||
|
||||
public WrappedClientboundMapItemDataPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundMapItemDataPacket(int mapId, byte scale, boolean locked, Optional<List<WrappedMapDecoration>> decorations, Optional<WrappedMapPatch> colorPatch) {
|
||||
this();
|
||||
setMapId(mapId);
|
||||
setScale(scale);
|
||||
setLocked(locked);
|
||||
setDecorations(decorations);
|
||||
setColorPatch(colorPatch);
|
||||
}
|
||||
|
||||
public WrappedClientboundMapItemDataPacket(int mapId, byte scale, boolean locked) {
|
||||
this(mapId, scale, locked, Optional.empty(), Optional.empty());
|
||||
}
|
||||
|
||||
public WrappedClientboundMapItemDataPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
// ---- mapId (global field 0) ---------------------------------------------
|
||||
|
||||
/** Returns the map id from the wrapped {@code MapId} record. */
|
||||
public int getMapId() {
|
||||
return MAP_ID_WRAPPER.getSpecific(handle.getModifier().read(0)).id;
|
||||
}
|
||||
|
||||
public void setMapId(int mapId) {
|
||||
WrappedMapId w = new WrappedMapId();
|
||||
w.id = mapId;
|
||||
handle.getModifier().write(0, MAP_ID_WRAPPER.getGeneric(w));
|
||||
}
|
||||
|
||||
// ---- scale (global field 1) ---------------------------------------------
|
||||
|
||||
public byte getScale() {
|
||||
return handle.getBytes().read(0);
|
||||
}
|
||||
|
||||
public void setScale(byte scale) {
|
||||
handle.getBytes().write(0, scale);
|
||||
}
|
||||
|
||||
// ---- locked (global field 2) --------------------------------------------
|
||||
|
||||
public boolean isLocked() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setLocked(boolean locked) {
|
||||
handle.getBooleans().write(0, locked);
|
||||
}
|
||||
|
||||
// ---- decorations (global field 3) ---------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the map decorations.
|
||||
* The {@link WrappedMapDecoration#type} and {@link WrappedMapDecoration#name} fields
|
||||
* are raw NMS objects ({@code Holder<MapDecorationType>} and {@code Optional<Component>}
|
||||
* respectively) — pass them through unchanged when writing back.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Optional<List<WrappedMapDecoration>> getDecorations() {
|
||||
Optional<List<Object>> raw = (Optional<List<Object>>) handle.getModifier().read(3);
|
||||
if (raw == null) return Optional.empty();
|
||||
return raw.map(list -> list.stream()
|
||||
.map(MAP_DECORATION_WRAPPER::getSpecific)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public void setDecorations(Optional<List<WrappedMapDecoration>> decorations) {
|
||||
Optional<List<Object>> nms = decorations.map(list -> list.stream()
|
||||
.map(MAP_DECORATION_WRAPPER::getGeneric)
|
||||
.collect(Collectors.toList()));
|
||||
handle.getModifier().write(3, nms);
|
||||
}
|
||||
|
||||
// ---- colorPatch (global field 4) ----------------------------------------
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Optional<WrappedMapPatch> getColorPatch() {
|
||||
Optional<Object> raw = (Optional<Object>) handle.getModifier().read(4);
|
||||
if (raw == null) return Optional.empty();
|
||||
return raw.map(MAP_PATCH_WRAPPER::getSpecific);
|
||||
}
|
||||
|
||||
public void setColorPatch(Optional<WrappedMapPatch> colorPatch) {
|
||||
Optional<Object> nms = colorPatch.map(MAP_PATCH_WRAPPER::getGeneric);
|
||||
handle.getModifier().write(4, nms);
|
||||
}
|
||||
|
||||
// ---- inner POJOs --------------------------------------------------------
|
||||
|
||||
/**
|
||||
* POJO mirroring {@code record MapId(int id)}.
|
||||
* Field {@code id} must be declared first (and only) to match the NMS record layout.
|
||||
*/
|
||||
public static final class WrappedMapId {
|
||||
public int id;
|
||||
|
||||
public WrappedMapId() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POJO mirroring
|
||||
* {@code record MapDecoration(Holder<MapDecorationType> type, byte x, byte y, byte rot, Optional<Component> name)}.
|
||||
*
|
||||
* <p>Fields must be declared in the same order as the NMS record.
|
||||
* {@code type} ({@code Holder<MapDecorationType>}) and {@code name} ({@code Optional<Component>})
|
||||
* are typed as {@link Object} — they are passed through the AutoWrapper without conversion.
|
||||
*/
|
||||
public static final class WrappedMapDecoration {
|
||||
/** NMS {@code Holder<MapDecorationType>} — pass-through as raw {@link Object}. */
|
||||
public Object type;
|
||||
public byte x;
|
||||
public byte y;
|
||||
public byte rot;
|
||||
/** NMS {@code Optional<Component>} — pass-through as raw {@link Object}. */
|
||||
public Object name;
|
||||
|
||||
public WrappedMapDecoration() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POJO mirroring
|
||||
* {@code record MapItemSavedData.MapPatch(int startX, int startY, int width, int height, byte[] mapColors)}.
|
||||
*
|
||||
* <p>Fields must be declared in the same order as the NMS record.
|
||||
*/
|
||||
public static final class WrappedMapPatch {
|
||||
public int startX;
|
||||
public int startY;
|
||||
public int width;
|
||||
public int height;
|
||||
public byte[] mapColors;
|
||||
|
||||
public WrappedMapPatch() {
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import java.util.List;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
import org.bukkit.inventory.MerchantRecipe;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundMerchantOffersPacket} (game phase, clientbound).
|
||||
*/
|
||||
public class WrappedClientboundMerchantOffersPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.OPEN_WINDOW_MERCHANT;
|
||||
|
||||
public WrappedClientboundMerchantOffersPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundMerchantOffersPacket(int containerId, List<MerchantRecipe> offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) {
|
||||
this();
|
||||
setContainerId(containerId);
|
||||
setOffers(offers);
|
||||
setVillagerLevel(villagerLevel);
|
||||
setVillagerXp(villagerXp);
|
||||
setShowProgress(showProgress);
|
||||
setCanRestock(canRestock);
|
||||
}
|
||||
|
||||
public WrappedClientboundMerchantOffersPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getContainerId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setContainerId(int containerId) {
|
||||
handle.getIntegers().write(0, containerId);
|
||||
}
|
||||
|
||||
public List<MerchantRecipe> getOffers() {
|
||||
return handle.getMerchantRecipeLists().read(0);
|
||||
}
|
||||
|
||||
public void setOffers(List<MerchantRecipe> offers) {
|
||||
handle.getMerchantRecipeLists().write(0, offers);
|
||||
}
|
||||
|
||||
public int getVillagerLevel() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setVillagerLevel(int villagerLevel) {
|
||||
handle.getIntegers().write(1, villagerLevel);
|
||||
}
|
||||
|
||||
public int getVillagerXp() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setVillagerXp(int villagerXp) {
|
||||
handle.getIntegers().write(2, villagerXp);
|
||||
}
|
||||
|
||||
public boolean isShowProgress() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setShowProgress(boolean showProgress) {
|
||||
handle.getBooleans().write(0, showProgress);
|
||||
}
|
||||
|
||||
public boolean isCanRestock() {
|
||||
return handle.getBooleans().read(1);
|
||||
}
|
||||
|
||||
public void setCanRestock(boolean canRestock) {
|
||||
handle.getBooleans().write(1, canRestock);
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundMountScreenOpenPacket} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int windowId} – window ID for the horse inventory</li>
|
||||
* <li>{@code int containerSize} – number of slots in the horse container</li>
|
||||
* <li>{@code int entityId} – entity ID of the horse</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundMountScreenOpenPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.OPEN_WINDOW_HORSE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(int.class)
|
||||
.withParam(int.class);
|
||||
|
||||
public WrappedClientboundMountScreenOpenPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundMountScreenOpenPacket(int windowId, int containerSize, int entityId) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(windowId, containerSize, entityId)));
|
||||
}
|
||||
|
||||
public WrappedClientboundMountScreenOpenPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getWindowId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setWindowId(int windowId) {
|
||||
handle.getIntegers().write(0, windowId);
|
||||
}
|
||||
|
||||
public int getContainerSize() {
|
||||
return handle.getIntegers().read(1);
|
||||
}
|
||||
|
||||
public void setContainerSize(int containerSize) {
|
||||
handle.getIntegers().write(1, containerSize);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(2);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(2, entityId);
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundMoveEntityPacket.Pos} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – entity ID</li>
|
||||
* <li>{@code short dx} – delta X in units of 1/4096 of a block</li>
|
||||
* <li>{@code short dy} – delta Y in units of 1/4096 of a block</li>
|
||||
* <li>{@code short dz} – delta Z in units of 1/4096 of a block</li>
|
||||
* <li>{@code boolean onGround} – whether the entity is on the ground</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>To convert from blocks: {@code (short)(deltaBlocks * 4096)}.
|
||||
*/
|
||||
public class WrappedClientboundMoveEntityPosPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.REL_ENTITY_MOVE;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(short.class)
|
||||
.withParam(short.class)
|
||||
.withParam(short.class)
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundMoveEntityPosPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundMoveEntityPosPacket(int entityId, short dx, short dy, short dz, boolean onGround) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(entityId, dx, dy, dz, onGround)));
|
||||
}
|
||||
|
||||
public WrappedClientboundMoveEntityPosPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(0, entityId);
|
||||
}
|
||||
|
||||
/** @return delta X in units of 1/4096 of a block */
|
||||
public short getDx() {
|
||||
return handle.getShorts().read(0);
|
||||
}
|
||||
|
||||
/** @param dx delta X in units of 1/4096 of a block */
|
||||
public void setDx(short dx) {
|
||||
handle.getShorts().write(0, dx);
|
||||
}
|
||||
|
||||
/** @return delta Y in units of 1/4096 of a block */
|
||||
public short getDy() {
|
||||
return handle.getShorts().read(1);
|
||||
}
|
||||
|
||||
/** @param dy delta Y in units of 1/4096 of a block */
|
||||
public void setDy(short dy) {
|
||||
handle.getShorts().write(1, dy);
|
||||
}
|
||||
|
||||
/** @return delta Z in units of 1/4096 of a block */
|
||||
public short getDz() {
|
||||
return handle.getShorts().read(2);
|
||||
}
|
||||
|
||||
/** @param dz delta Z in units of 1/4096 of a block */
|
||||
public void setDz(short dz) {
|
||||
handle.getShorts().write(2, dz);
|
||||
}
|
||||
|
||||
public boolean isOnGround() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setOnGround(boolean onGround) {
|
||||
handle.getBooleans().write(0, onGround);
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundMoveEntityPacket.PosRot} (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – entity ID</li>
|
||||
* <li>{@code short dx} – delta X in units of 1/4096 of a block</li>
|
||||
* <li>{@code short dy} – delta Y in units of 1/4096 of a block</li>
|
||||
* <li>{@code short dz} – delta Z in units of 1/4096 of a block</li>
|
||||
* <li>{@code byte yaw} – packed yaw angle</li>
|
||||
* <li>{@code byte pitch} – packed pitch angle</li>
|
||||
* <li>{@code boolean onGround} – whether the entity is on the ground</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundMoveEntityPosRotPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.REL_ENTITY_MOVE_LOOK;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(short.class)
|
||||
.withParam(short.class)
|
||||
.withParam(short.class)
|
||||
.withParam(byte.class)
|
||||
.withParam(byte.class)
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundMoveEntityPosRotPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundMoveEntityPosRotPacket(int entityId, short dx, short dy, short dz, byte yaw, byte pitch, boolean onGround) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(entityId, dx, dy, dz, yaw, pitch, onGround)));
|
||||
}
|
||||
|
||||
public WrappedClientboundMoveEntityPosRotPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(0, entityId);
|
||||
}
|
||||
|
||||
/** @return delta X in units of 1/4096 of a block */
|
||||
public short getDx() {
|
||||
return handle.getShorts().read(0);
|
||||
}
|
||||
|
||||
/** @param dx delta X in units of 1/4096 of a block */
|
||||
public void setDx(short dx) {
|
||||
handle.getShorts().write(0, dx);
|
||||
}
|
||||
|
||||
/** @return delta Y in units of 1/4096 of a block */
|
||||
public short getDy() {
|
||||
return handle.getShorts().read(1);
|
||||
}
|
||||
|
||||
/** @param dy delta Y in units of 1/4096 of a block */
|
||||
public void setDy(short dy) {
|
||||
handle.getShorts().write(1, dy);
|
||||
}
|
||||
|
||||
/** @return delta Z in units of 1/4096 of a block */
|
||||
public short getDz() {
|
||||
return handle.getShorts().read(2);
|
||||
}
|
||||
|
||||
/** @param dz delta Z in units of 1/4096 of a block */
|
||||
public void setDz(short dz) {
|
||||
handle.getShorts().write(2, dz);
|
||||
}
|
||||
|
||||
public byte getYaw() {
|
||||
return handle.getBytes().read(0);
|
||||
}
|
||||
|
||||
public void setYaw(byte yaw) {
|
||||
handle.getBytes().write(0, yaw);
|
||||
}
|
||||
|
||||
public byte getPitch() {
|
||||
return handle.getBytes().read(1);
|
||||
}
|
||||
|
||||
public void setPitch(byte pitch) {
|
||||
handle.getBytes().write(1, pitch);
|
||||
}
|
||||
|
||||
public boolean isOnGround() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setOnGround(boolean onGround) {
|
||||
handle.getBooleans().write(0, onGround);
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
package net.dmulloy2.protocol.wrappers.game.clientbound;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.EquivalentConstructor;
|
||||
import net.dmulloy2.protocol.AbstractPacket;
|
||||
|
||||
/**
|
||||
* Wrapper for {@code ClientboundRotateHeadPacket} / entity look packet
|
||||
* (Play phase, clientbound).
|
||||
*
|
||||
* <p>Packet structure:
|
||||
* <ul>
|
||||
* <li>{@code int entityId} – entity ID</li>
|
||||
* <li>{@code byte yaw} – packed yaw (use {@link WrappedClientboundAddEntityPacket#angleToByte}
|
||||
* / {@link WrappedClientboundAddEntityPacket#byteToAngle} for conversion)</li>
|
||||
* <li>{@code byte pitch} – packed pitch</li>
|
||||
* <li>{@code boolean onGround} – whether the entity is on the ground</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class WrappedClientboundMoveEntityRotPacket extends AbstractPacket {
|
||||
|
||||
public static final PacketType TYPE = PacketType.Play.Server.ENTITY_LOOK;
|
||||
private static final EquivalentConstructor CONSTRUCTOR = new EquivalentConstructor(TYPE)
|
||||
.withParam(int.class)
|
||||
.withParam(byte.class)
|
||||
.withParam(byte.class)
|
||||
.withParam(boolean.class);
|
||||
|
||||
public WrappedClientboundMoveEntityRotPacket() {
|
||||
super(new PacketContainer(TYPE), TYPE);
|
||||
}
|
||||
|
||||
public WrappedClientboundMoveEntityRotPacket(int entityId, byte yaw, byte pitch, boolean onGround) {
|
||||
this(PacketContainer.fromPacket(CONSTRUCTOR.create(entityId, yaw, pitch, onGround)));
|
||||
}
|
||||
|
||||
public WrappedClientboundMoveEntityRotPacket(PacketContainer packet) {
|
||||
super(packet, TYPE);
|
||||
}
|
||||
|
||||
public int getEntityId() {
|
||||
return handle.getIntegers().read(0);
|
||||
}
|
||||
|
||||
public void setEntityId(int entityId) {
|
||||
handle.getIntegers().write(0, entityId);
|
||||
}
|
||||
|
||||
public byte getYaw() {
|
||||
return handle.getBytes().read(0);
|
||||
}
|
||||
|
||||
public void setYaw(byte yaw) {
|
||||
handle.getBytes().write(0, yaw);
|
||||
}
|
||||
|
||||
public byte getPitch() {
|
||||
return handle.getBytes().read(1);
|
||||
}
|
||||
|
||||
public void setPitch(byte pitch) {
|
||||
handle.getBytes().write(1, pitch);
|
||||
}
|
||||
|
||||
public boolean isOnGround() {
|
||||
return handle.getBooleans().read(0);
|
||||
}
|
||||
|
||||
public void setOnGround(boolean onGround) {
|
||||
handle.getBooleans().write(0, onGround);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 507 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user