mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2026-11-04 08:52:09 -05:00
Compare commits
44
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79b09acb2a | ||
|
|
186f186e0a | ||
|
|
c4ae9122ce | ||
|
|
738cee2e6a | ||
|
|
d7431b9f1a | ||
|
|
f30dbcfd53 | ||
|
|
b2ef2de409 | ||
|
|
1df4692038 | ||
|
|
d2423c8ef7 | ||
|
|
c42a5f1e26 | ||
|
|
94860bbad0 | ||
|
|
8c61001642 | ||
|
|
ee747010aa | ||
|
|
6250026956 | ||
|
|
d91ec4b61a | ||
|
|
98856a8b9f | ||
|
|
5ec23ef33b | ||
|
|
589ee12e12 | ||
|
|
6cf7c7d8c3 | ||
|
|
3139e82aea | ||
|
|
3385fe664b | ||
|
|
0e267a5f1a | ||
|
|
2d3b3e3363 | ||
|
|
8eeb82f89d | ||
|
|
b0b9b666a7 | ||
|
|
b723ff3351 | ||
|
|
72fd0709b6 | ||
|
|
5a9afed462 | ||
|
|
9404ce32db | ||
|
|
6c6bde522e | ||
|
|
f911ee904c | ||
|
|
22012d3dc9 | ||
|
|
c52b4bb10c | ||
|
|
b9f96469f5 | ||
|
|
e5413ccc5b | ||
|
|
b37a3bcb13 | ||
|
|
19cb81b6ab | ||
|
|
f606cc954d | ||
|
|
774e679571 | ||
|
|
1257506929 | ||
|
|
5773bcbc16 | ||
|
|
468082c9f9 | ||
|
|
a11b403c4b | ||
|
|
aa4fab1632 |
No files matched your search
@@ -1 +1,2 @@
|
||||
* text=auto eol=lf
|
||||
.github/workflows/*.lock.yml linguist-generated=true merge=ours
|
||||
+70
-36
@@ -1,38 +1,72 @@
|
||||
Contributing to ProtocolLib
|
||||
===========================
|
||||
This page will detail specific things that must be done if you intend to contribute to this project.
|
||||
# Contributing to ProtocolLib
|
||||
|
||||
## Updating ProtocolLib to a New Protocol Version
|
||||
#### Before we get started:
|
||||
1. **When do we need to update the protocol version?**
|
||||
_A Minecraft protocol version is a number for each specification of the Minecraft protocol.
|
||||
This means it is incremented when there is a change to the [Protocol Specification](http://wiki.vg/Protocol),
|
||||
but not necessarily for each Minecraft version update. If the latest Minecraft version contains a protocol change,
|
||||
that means ProtocolLib needs to be updated._
|
||||
2. **When do we need to update other parts of ProtocolLib?**
|
||||
_When the package version guard changes. The package version guard is the version string inserted
|
||||
into the package identifier for CraftBukkit and net.minecraft.server (e.g. v1_9_R2). It is incremented
|
||||
by Spigot if there is a major breaking change in the internal server code. This is to encourage plugins
|
||||
that interact directly with CraftBukkit/nms code to update more specifically. However, since most of
|
||||
ProtocolLib uses reflection, and the structure of packet classes is generally static, one will have
|
||||
to go through the code and change imports from nms/CraftBukkit._
|
||||
ProtocolLib supports a wide range of Minecraft versions through reflection and compatibility wrappers. Changes to packet
|
||||
registration, reflection, or public wrappers can affect plugins on versions other than the one currently used for
|
||||
development, so keep changes focused and preserve existing behavior unless a break is unavoidable.
|
||||
|
||||
#### Ready? Let's get started!
|
||||
1. Read the [Protocol Changes](http://wiki.vg/Protocol_History). Always make sure the list is both
|
||||
complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [libera.chat](http://libera.chat)
|
||||
or #spigot on [irc.spi.gt](http://irc.spi.gt) ([webchat](https://irc.spi.gt/iris/?channels=spigot)).
|
||||
2. Search for usages of the now-defunct NMS package guard and change them.
|
||||
3. The class `com.comphenix.protocol.PacketType` contains a list of all the packets. If any packets were added or removed
|
||||
(or had their ID changed), make sure to update this list. If a packet was removed
|
||||
in favor of usage of another packet, instead of removing it, move it to the bottom of the list
|
||||
in its section, add a deprecation warning to it, and redirect it to the packet that replaced it.
|
||||
4. `mvn` in the root directory to build the project.
|
||||
5. If tests fail in the maven build, go through the tests to make sure you removed references to any removed packets
|
||||
and changed the NMS version guards.
|
||||
6. Increment the package version in `com.comphenix.protocol.utility.Constants`.
|
||||
7. `com.comphenix.protocol.ProtocolLibrary` contains several constants that must be updated, including the Minecraft version
|
||||
and the release date.
|
||||
8. `com.comphenix.protocol.utility.MinecraftProtocolVersion` contains a map of all the protocol version integers.
|
||||
If the protocol version has been incremented, add a new line to the map.
|
||||
9. `mvn` in root directory again. If it builds successfully, test on the appropriate version of a Spigot server. If
|
||||
the build fails, debug!
|
||||
## Building ProtocolLib
|
||||
|
||||
Use the Gradle wrapper from the repository root. The build uses the Java 25 toolchain and resolves the current Spigot
|
||||
server dependency from the CodeMC repository.
|
||||
|
||||
```shell
|
||||
./gradlew test
|
||||
./gradlew build shadowJar
|
||||
```
|
||||
|
||||
`shadowJar` produces `build/libs/ProtocolLib.jar` with the required Byte Buddy classes included.
|
||||
|
||||
ProtocolLib uses the Java 25 toolchain to compile against the current server, but production classes target Java 17 for
|
||||
compatibility with older supported servers.
|
||||
|
||||
## Updating ProtocolLib for a Minecraft Release
|
||||
|
||||
Start by reviewing the [Java Edition protocol](https://minecraft.wiki/w/Java_Edition_protocol) and the corresponding
|
||||
server classes. The server packet classes and codecs are authoritative when documentation and implementation differ.
|
||||
|
||||
### 1. Update version metadata
|
||||
|
||||
- Update `mcVersion` in `build.gradle.kts`.
|
||||
- Add the release to `MinecraftVersion` and update `MinecraftVersion.LATEST`.
|
||||
- Update `ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION` and `ProtocolLibrary.MINECRAFT_LAST_RELEASE_DATE`.
|
||||
- Update `MinecraftProtocolVersion` if the release changed the protocol number.
|
||||
|
||||
### 2. Reconcile packet types
|
||||
|
||||
`PacketType` must contain a matching definition for every packet in the current server protocol registries. Compare the
|
||||
serverbound and clientbound packet classes and codecs against every protocol phase, including configuration.
|
||||
|
||||
- Add new, renamed, or split packets and update their current IDs and aliases.
|
||||
- Do not remove an existing public `PacketType` constant. Move removed types to the deprecated section and document their
|
||||
replacement when one exists.
|
||||
- Represent split packets as separate packet types instead of redirecting incompatible packet shapes.
|
||||
- Run the packet registry tests after changing packet definitions. A missing definition can prevent later packets in the
|
||||
same protocol registry from being registered.
|
||||
|
||||
### 3. Update reflection and wrappers
|
||||
|
||||
- Inspect changed fields, constructors, records, nested classes, and stream codecs instead of relying only on class names.
|
||||
- Prefer structural or type-based reflection where names are unstable.
|
||||
- Put version checks at the narrowest compatibility boundary and leave the older path unchanged.
|
||||
- If an NMS concept was removed, report it as unsupported or absent rather than treating a different class as equivalent.
|
||||
- Preserve packet fields that are unrelated to the value being changed.
|
||||
- Keep converters symmetric and preserve wrapper cloning and equality semantics.
|
||||
- A custom `StructureModifier` must maintain the complete modifier contract, including safe reads and writes, field count,
|
||||
metadata, introspection, defaults, and `withTarget()`.
|
||||
|
||||
### 4. Add regression coverage
|
||||
|
||||
- Initialize the test environment with `BukkitInitialization` when tests access CraftBukkit or NMS classes.
|
||||
- Exercise the actual packet structure supplied by the current Spigot dependency.
|
||||
- Cover both sides of a version guard when feasible.
|
||||
- Re-enable previously disabled tests when the underlying incompatibility is fixed.
|
||||
- Run targeted tests while developing, followed by `./gradlew test`.
|
||||
- Before declaring a Minecraft release supported, build the shaded plugin and test it on the corresponding server.
|
||||
|
||||
## Pull Request Expectations
|
||||
|
||||
- Keep the change limited to the reported problem or release update.
|
||||
- Include regression tests for packet, reflection, converter, or wrapper behavior changes.
|
||||
- Preserve public API signatures and binary compatibility where possible.
|
||||
- Clearly document any unavoidable compatibility change.
|
||||
- Do not hide reflection failures with broad exception handling or silent fallbacks.
|
||||
@@ -0,0 +1,123 @@
|
||||
# ProtocolLib Agent Guide
|
||||
|
||||
This file applies to the entire repository. Read `.github/CONTRIBUTING.md` before changing Minecraft support, packet
|
||||
definitions, reflection, or public wrappers.
|
||||
|
||||
## Repository Basics
|
||||
|
||||
- The main project uses the Gradle wrapper. Do not use `TinyProtocol/pom.xml` to build ProtocolLib.
|
||||
- The Java toolchain and current Spigot dependency are defined in `build.gradle.kts`.
|
||||
- Keep the Java 25 build toolchain separate from the Java 17 production bytecode target.
|
||||
- Production code is under `src/main/java`; JUnit tests and NMS test initialization are under `src/test/java`.
|
||||
- Keep changes focused. Do not combine protocol fixes with unrelated cleanup or formatting.
|
||||
- Preserve public API and binary compatibility unless the task explicitly requires a breaking change.
|
||||
|
||||
## Build and Test Commands
|
||||
|
||||
```shell
|
||||
./gradlew test
|
||||
./gradlew build shadowJar
|
||||
```
|
||||
|
||||
Run the smallest relevant test while developing:
|
||||
|
||||
```shell
|
||||
./gradlew test --tests fully.qualified.TestClass
|
||||
./gradlew test --tests fully.qualified.TestClass.testMethod
|
||||
```
|
||||
|
||||
After changing production Java code, run the targeted tests and then the complete test suite. Use `build shadowJar` when
|
||||
the task affects packaging, dependencies, release support, or the final plugin artifact.
|
||||
|
||||
Do not introduce another build system, test runner, formatter, or lint tool unless the repository adopts it separately.
|
||||
|
||||
## Important Code Areas
|
||||
|
||||
- `PacketType.java`: public packet constants, current IDs, aliases, and deprecated packet definitions.
|
||||
- `injector/packet/internal/ProtocolRegistry_1_20_5.java`: current packet discovery and codec registration.
|
||||
- `utility/MinecraftVersion.java`: named Minecraft versions and the latest supported release.
|
||||
- `utility/MinecraftProtocolVersion.java`: Minecraft release to protocol-number mappings.
|
||||
- `ProtocolLibrary.java`: supported version bounds and latest release date.
|
||||
- `utility/MinecraftReflection.java`: centralized NMS and CraftBukkit class discovery.
|
||||
- `reflect/StructureModifier.java`: indexed packet field access and conversion contract.
|
||||
- `wrappers/`: stable public representations of unstable NMS structures.
|
||||
- `events/PacketContainer.java` and `events/AbstractStructure.java`: packet construction and typed field access.
|
||||
- `src/test/java/com/comphenix/protocol/BukkitInitialization.java`: test bootstrap for CraftBukkit and NMS access.
|
||||
|
||||
## Minecraft Release Updates
|
||||
|
||||
Follow the complete checklist in `.github/CONTRIBUTING.md`. In particular:
|
||||
|
||||
- Update all version metadata together; do not bump only the Gradle dependency.
|
||||
- Reconcile every serverbound and clientbound packet in every protocol phase with `PacketType`.
|
||||
- Add packet types for newly split packets instead of forcing incompatible shapes through an older packet constant.
|
||||
- Preserve removed public `PacketType` constants in the deprecated section.
|
||||
- Update `MinecraftProtocolVersion` only when the protocol number actually changed.
|
||||
|
||||
Every packet exposed by the current NMS protocol registries must have a matching `PacketType`. An undefined or incorrectly
|
||||
renamed packet can abort registration of later packets in the same registry.
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
- Put version checks at the narrowest affected boundary.
|
||||
- Keep the pre-change code path intact whenever possible.
|
||||
- Use named `MinecraftVersion` constants with `atOrAbove()` instead of scattered version strings.
|
||||
- A public method should keep the same signature and broad contract across versions.
|
||||
- If Minecraft removed a concept, return an unsupported or absent result consistent with existing APIs. Do not claim an
|
||||
unrelated packet or class is the removed type.
|
||||
- When Minecraft splits one packet into several packets, expose and use the new packet types explicitly.
|
||||
- Preserve unrelated packet fields when adapting or rewriting one logical value.
|
||||
|
||||
The current test dependency exercises the latest supported server. Review older guarded paths carefully because they may
|
||||
not execute in the local test run.
|
||||
|
||||
## Packet and Reflection Rules
|
||||
|
||||
- Treat the current server packet classes, record components, constructors, and codecs as authoritative.
|
||||
- Prefer existing `MinecraftReflection`, `FuzzyReflection`, and accessor helpers over new direct reflection.
|
||||
- Prefer structural and type-based matching where obfuscated names are unstable.
|
||||
- Search for an existing class resolver, converter, or accessor before adding another one.
|
||||
- Cache stable reflective lookups following nearby patterns; do not repeatedly scan classes on packet hot paths.
|
||||
- Do not hide reflection failures with broad catches, silent defaults, or unrelated fallback types.
|
||||
- Account for static fields, inherited fields, records, nested implementations, and duplicate field types when writing
|
||||
fuzzy contracts.
|
||||
|
||||
## `StructureModifier` Contract
|
||||
|
||||
Typed accessors returned from packet APIs must behave like normal `StructureModifier` instances.
|
||||
|
||||
- `size()`, `getFields()`, `getField()`, target metadata, and field metadata must agree.
|
||||
- `readSafely()` returns `null` for an absent index.
|
||||
- `writeSafely()` ignores an absent index without throwing.
|
||||
- `withTarget()` must preserve the modifier's behavior for the new target.
|
||||
- `writeDefaults()` must remain safe.
|
||||
- Converters must be applied symmetrically on reads and writes.
|
||||
|
||||
If a packet no longer contains a real backing field, prefer an empty modifier when compatible. If a virtual field is
|
||||
required for API compatibility, initialize all modifier metadata and test its inherited methods.
|
||||
|
||||
## Wrapper and Converter Rules
|
||||
|
||||
- Wrapper factories, converters, getters, setters, and `deepClone()` must describe the same logical value.
|
||||
- Preserve converter symmetry: converting specific to generic and back must not unexpectedly lose represented state.
|
||||
- If a wrapper handle changes from a nested value to an entire packet, define logical `equals()` and `hashCode()` so
|
||||
unrelated packet metadata does not affect equality.
|
||||
- Clones that represent the same logical value should compare equal.
|
||||
- Do not fabricate legacy states that the modern wire format cannot distinguish; document or surface the limitation.
|
||||
- Record or immutable packet updates must retain entity IDs, flags, and other components not owned by the wrapper.
|
||||
|
||||
## Tests
|
||||
|
||||
- Call `BukkitInitialization.initializeAll()` before tests that resolve CraftBukkit or NMS classes.
|
||||
- Prefer regression tests using the actual Spigot packet classes supplied by the test dependency.
|
||||
- Test reads, writes, safe access, cloning, equality, and preservation of unrelated fields when changing wrappers.
|
||||
- Test modifier metadata and inherited methods when introducing a custom `StructureModifier`.
|
||||
- Re-enable disabled tests when fixing the incompatibility that caused them to be disabled.
|
||||
- Do not weaken assertions or encode known incorrect behavior merely to make a new Minecraft version pass.
|
||||
|
||||
## Documentation and Review
|
||||
|
||||
- Update Javadocs when version support, nullability, or unsupported behavior changes.
|
||||
- Update `.github/CONTRIBUTING.md` when the repository-wide build or release workflow changes.
|
||||
- Keep this file operational and durable; do not add task-specific notes, temporary workarounds, or current PR details.
|
||||
- Before finishing, inspect the complete diff for accidental API changes and unrelated edits.
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -64,7 +64,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
// Packets we have to intercept
|
||||
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getClass("{nms}.PacketLoginInStart", "net.minecraft.network.protocol.login.PacketLoginInStart");
|
||||
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
|
||||
private static final FieldAccessor<String> getPlayerName = new PlayerNameAccessor();
|
||||
|
||||
// Speedup channel lookup
|
||||
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
|
||||
@@ -492,6 +492,59 @@ public abstract class TinyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the player name from the login start packet.
|
||||
* This fixes the issue from 1.19 where the GameProfile field has been removed from this login packet.
|
||||
*
|
||||
* @author gamerover98
|
||||
*/
|
||||
private static class PlayerNameAccessor implements FieldAccessor<String> {
|
||||
|
||||
private FieldAccessor<String> getPlayerName;
|
||||
private FieldAccessor<GameProfile> getGameProfile;
|
||||
|
||||
PlayerNameAccessor() {
|
||||
try {
|
||||
this.getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
|
||||
} catch (IllegalArgumentException illegalArgumentException) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
try {
|
||||
//HOT-FIX for 1.19+
|
||||
this.getPlayerName = Reflection.getField(PACKET_LOGIN_IN_START, String.class, 0);
|
||||
} catch (IllegalArgumentException illegalArgumentException) {
|
||||
// nothing to do.
|
||||
}
|
||||
|
||||
if (getGameProfile == null && getPlayerName == null) {
|
||||
throw new UnsupportedOperationException("The current server version is not supported by TinyProtocol");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(Object target) {
|
||||
if (getPlayerName != null) {
|
||||
String playerName = getPlayerName.get(target);
|
||||
return playerName.substring(0, Math.min(16, playerName.length()));
|
||||
}
|
||||
|
||||
return getGameProfile.get(target).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object target, Object value) {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasField(Object target) {
|
||||
return getPlayerName != null
|
||||
? getPlayerName.hasField(target)
|
||||
: getGameProfile.hasField(target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
|
||||
*
|
||||
@@ -533,8 +586,7 @@ public abstract class TinyProtocol {
|
||||
|
||||
private void handleLoginStart(Channel channel, Object packet) {
|
||||
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
|
||||
GameProfile profile = getGameProfile.get(packet);
|
||||
channelLookup.put(profile.getName(), channel);
|
||||
channelLookup.put(getPlayerName.get(packet), channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+28
-30
@@ -1,21 +1,20 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import io.github.patrick.gradle.remapper.RemapTask
|
||||
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
`signing`
|
||||
id("com.gradleup.shadow") version "9.0.2"
|
||||
id("io.github.patrick.remapper") version "1.4.2"
|
||||
id("com.vanniktech.maven.publish") version "0.34.0"
|
||||
signing
|
||||
id("com.gradleup.shadow") version "9.4.0"
|
||||
id("io.github.patrick.remapper") version "1.4.3"
|
||||
id("com.vanniktech.maven.publish") version "0.36.0"
|
||||
}
|
||||
|
||||
group = "net.dmulloy2"
|
||||
description = "Provides access to the Minecraft protocol"
|
||||
|
||||
val mcVersion = "1.21.8"
|
||||
val mcVersion = "26.2"
|
||||
val isSnapshot = version.toString().endsWith("-SNAPSHOT")
|
||||
val isJitPack = System.getenv("JITPACK")?.equals("true", ignoreCase = true) ?: false
|
||||
val commitHash = System.getenv("COMMIT_SHA") ?: ""
|
||||
val isCI = commitHash.isNotEmpty()
|
||||
|
||||
@@ -45,32 +44,28 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("net.bytebuddy:byte-buddy:1.17.5")
|
||||
implementation("net.bytebuddy:byte-buddy:1.18.2")
|
||||
compileOnly("org.spigotmc:spigot-api:${mcVersion}-R0.1-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
|
||||
compileOnly("io.netty:netty-all:4.0.23.Final")
|
||||
/*
|
||||
* TODO(fix): once you update kyori:adventure-text-serializer-gson please uncomment the TODO in
|
||||
* com.comphenix.protocol.wrappers.WrappedComponentStyleTest if the following issue got fixed:
|
||||
* https://github.com/KyoriPowered/adventure/issues/1194
|
||||
*/
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.21.0")
|
||||
compileOnly("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT")//:remapped-mojang")
|
||||
compileOnly("io.netty:netty-all:4.2.8.Final")
|
||||
compileOnly("net.kyori:adventure-text-serializer-gson:4.25.0")
|
||||
compileOnly("com.googlecode.json-simple:json-simple:1.1.1")
|
||||
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher:1.10.0")
|
||||
testImplementation("org.mockito:mockito-core:5.6.0")
|
||||
testImplementation("io.netty:netty-common:4.1.97.Final")
|
||||
testImplementation("io.netty:netty-transport:4.1.97.Final")
|
||||
testImplementation("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT:remapped-mojang")
|
||||
testImplementation("net.kyori:adventure-text-serializer-gson:4.14.0")
|
||||
testImplementation("net.kyori:adventure-text-serializer-plain:4.14.0")
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:6.0.1")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:6.0.1")
|
||||
testRuntimeOnly("org.junit.platform:junit-platform-launcher:6.0.1")
|
||||
testImplementation("org.mockito:mockito-core:5.21.0")
|
||||
testImplementation("io.netty:netty-common:4.2.8.Final")
|
||||
testImplementation("io.netty:netty-transport:4.2.8.Final")
|
||||
testImplementation("org.spigotmc:spigot:${mcVersion}-R0.1-SNAPSHOT")//:remapped-mojang")
|
||||
testImplementation("net.kyori:adventure-text-serializer-gson:4.25.0")
|
||||
testImplementation("net.kyori:adventure-text-serializer-plain:4.25.0")
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
toolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(25))
|
||||
}
|
||||
}
|
||||
|
||||
tasks {
|
||||
@@ -104,7 +99,7 @@ tasks {
|
||||
archiveFileName = "ProtocolLib.jar"
|
||||
}
|
||||
|
||||
remap {
|
||||
/*remap {
|
||||
dependsOn("shadowJar")
|
||||
|
||||
inputTask.set(getByName<ShadowJar>("shadowJar"))
|
||||
@@ -114,7 +109,7 @@ tasks {
|
||||
|
||||
assemble {
|
||||
dependsOn("remap")
|
||||
}
|
||||
}*/
|
||||
|
||||
javadoc {
|
||||
options.encoding = "UTF-8"
|
||||
@@ -122,12 +117,15 @@ tasks {
|
||||
|
||||
compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
options.release.set(17)
|
||||
}
|
||||
}
|
||||
|
||||
mavenPublishing {
|
||||
publishToMavenCentral()
|
||||
signAllPublications()
|
||||
if (!isSnapshot && !isJitPack) {
|
||||
signAllPublications()
|
||||
}
|
||||
|
||||
coordinates("$group", project.name, "$version")
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
version=5.4.1-SNAPSHOT
|
||||
version=5.5.0-SNAPSHOT
|
||||
mavenCentralUsername=
|
||||
mavenCentralPassword=
|
||||
signing.keyId=
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -84,7 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -112,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -170,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -203,15 +203,14 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
Vendored
+13
-12
@@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
@@ -133,114 +133,121 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType CUSTOM_CHAT_COMPLETIONS = new PacketType(PROTOCOL, SENDER, 0x17, "CustomChatCompletions");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x18, "CustomPayload", "SPacketCustomPayload");
|
||||
public static final PacketType DAMAGE_EVENT = new PacketType(PROTOCOL, SENDER, 0x19, "DamageEvent", "ClientboundDamageEventPacket");
|
||||
public static final PacketType DEBUG_SAMPLE = new PacketType(PROTOCOL, SENDER, 0x1A, "DebugSample");
|
||||
public static final PacketType DELETE_CHAT_MESSAGE = new PacketType(PROTOCOL, SENDER, 0x1B, "DeleteChat");
|
||||
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x1C, "Disconnect", "KickDisconnect", "SPacketDisconnect");
|
||||
public static final PacketType DISGUISED_CHAT = new PacketType(PROTOCOL, SENDER, 0x1D, "DisguisedChat");
|
||||
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1E, "EntityEvent", "EntityStatus", "SPacketEntityStatus");
|
||||
public static final PacketType ENTITY_POSITION_SYNC = new PacketType(PROTOCOL, SENDER, 0x1F, "EntityPositionSync");
|
||||
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x20, "Explode", "Explosion", "SPacketExplosion");
|
||||
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x21, "ForgetLevelChunk", "UnloadChunk", "SPacketUnloadChunk");
|
||||
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x22, "GameEvent", "GameStateChange", "SPacketChangeGameState");
|
||||
public static final PacketType OPEN_WINDOW_HORSE = new PacketType(PROTOCOL, SENDER, 0x23, "HorseScreenOpen", "OpenWindowHorse");
|
||||
public static final PacketType HURT_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x24, "HurtAnimation", "ClientboundHurtAnimationPacket");
|
||||
public static final PacketType INITIALIZE_BORDER = new PacketType(PROTOCOL, SENDER, 0x25, "InitializeBorder");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x26, "KeepAlive", "SPacketKeepAlive");
|
||||
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x27, "LevelChunkWithLight", "MapChunk", "SPacketChunkData");
|
||||
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x28, "LevelEvent", "WorldEvent", "SPacketEffect");
|
||||
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x29, "LevelParticles", "WorldParticles", "SPacketParticles");
|
||||
public static final PacketType LIGHT_UPDATE = new PacketType(PROTOCOL, SENDER, 0x2A, "LightUpdate");
|
||||
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x2B, "Login", "SPacketJoinGame");
|
||||
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x2C, "MapItemData", "Map", "SPacketMaps");
|
||||
public static final PacketType OPEN_WINDOW_MERCHANT = new PacketType(PROTOCOL, SENDER, 0x2D, "MerchantOffers", "OpenWindowMerchant");
|
||||
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x2E, "net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Pos", "Entity$RelEntityMove", "Entity$PacketPlayOutRelEntityMove");
|
||||
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x2F, "net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$PosRot", "Entity$RelEntityMoveLook", "Entity$PacketPlayOutRelEntityMoveLook");
|
||||
public static final PacketType MOVE_MINECART = new PacketType(PROTOCOL, SENDER, 0x30, "MoveMinecart");
|
||||
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x31, "net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot", "Entity$EntityLook", "Entity$PacketPlayOutEntityLook");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x32, "MoveVehicle", "VehicleMove", "SPacketMoveVehicle");
|
||||
public static final PacketType OPEN_BOOK = new PacketType(PROTOCOL, SENDER, 0x33, "OpenBook");
|
||||
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x34, "OpenScreen", "OpenWindow", "SPacketOpenWindow");
|
||||
public static final PacketType OPEN_SIGN_EDITOR = new PacketType(PROTOCOL, SENDER, 0x35, "OpenSignEditor", "SPacketSignEditorOpen");
|
||||
public static final PacketType PING = new PacketType(PROTOCOL, SENDER, 0x36, "Ping");
|
||||
public static final PacketType PONG_RESPONSE = new PacketType(PROTOCOL, SENDER, 0x37, "PongResponse");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x38, "PlaceGhostRecipe", "AutoRecipe", "SPacketPlaceGhostRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x39, "PlayerAbilities", "Abilities", "SPacketPlayerAbilities");
|
||||
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x3A, "PlayerChat", "Chat", "SPacketChat");
|
||||
public static final PacketType PLAYER_COMBAT_END = new PacketType(PROTOCOL, SENDER, 0x3B, "PlayerCombatEnd");
|
||||
public static final PacketType PLAYER_COMBAT_ENTER = new PacketType(PROTOCOL, SENDER, 0x3C, "PlayerCombatEnter");
|
||||
public static final PacketType PLAYER_COMBAT_KILL = new PacketType(PROTOCOL, SENDER, 0x3D, "PlayerCombatKill");
|
||||
public static final PacketType PLAYER_INFO_REMOVE = new PacketType(PROTOCOL, SENDER, 0x3E, "PlayerInfoRemove");
|
||||
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x3F, "PlayerInfoUpdate", "PlayerInfo");
|
||||
public static final PacketType LOOK_AT = new PacketType(PROTOCOL, SENDER, 0x40, "PlayerLookAt", "LookAt", "SPacketPlayerPosLook");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x41, "PlayerPosition", "Position");
|
||||
public static final PacketType PLAYER_ROTATION = new PacketType(PROTOCOL, SENDER, 0x42, "PlayerRotation");
|
||||
public static final PacketType RECIPE_BOOK_ADD = new PacketType(PROTOCOL, SENDER, 0x43, "RecipeBookAdd");
|
||||
public static final PacketType RECIPE_BOOK_REMOVE = new PacketType(PROTOCOL, SENDER, 0x44, "RecipeBookRemove");
|
||||
public static final PacketType RECIPE_BOOK_SETTINGS = new PacketType(PROTOCOL, SENDER, 0x45, "RecipeBookSettings");
|
||||
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x46, "RemoveEntities", "EntityDestroy", "SPacketDestroyEntities");
|
||||
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x47, "RemoveMobEffect", "RemoveEntityEffect", "SPacketRemoveEntityEffect");
|
||||
public static final PacketType RESET_SCORE = new PacketType(PROTOCOL, SENDER, 0x48, "ResetScore", "ResetScorePacket");
|
||||
public static final PacketType REMOVE_RESOURCE_PACK = new PacketType(PROTOCOL, SENDER, 0x49, "ResourcePackPop", "ResourcePackPopPacket");
|
||||
public static final PacketType ADD_RESOURCE_PACK = new PacketType(PROTOCOL, SENDER, 0x4A, "ResourcePackPush", "ResourcePackPushPacket");
|
||||
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x4B, "Respawn", "SPacketRespawn");
|
||||
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x4C, "RotateHead", "EntityHeadRotation", "SPacketEntityHeadLook");
|
||||
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x4D, "SectionBlocksUpdate", "MultiBlockChange", "SPacketMultiBlockChange");
|
||||
public static final PacketType SELECT_ADVANCEMENT_TAB = new PacketType(PROTOCOL, SENDER, 0x4E, "SelectAdvancementsTab", "SelectAdvancementTab", "SPacketSelectAdvancementsTab");
|
||||
public static final PacketType SERVER_DATA = new PacketType(PROTOCOL, SENDER, 0x4F, "ServerData");
|
||||
public static final PacketType SET_ACTION_BAR_TEXT = new PacketType(PROTOCOL, SENDER, 0x50, "SetActionBarText");
|
||||
public static final PacketType SET_BORDER_CENTER = new PacketType(PROTOCOL, SENDER, 0x51, "SetBorderCenter");
|
||||
public static final PacketType SET_BORDER_LERP_SIZE = new PacketType(PROTOCOL, SENDER, 0x52, "SetBorderLerpSize");
|
||||
public static final PacketType SET_BORDER_SIZE = new PacketType(PROTOCOL, SENDER, 0x53, "SetBorderSize");
|
||||
public static final PacketType SET_BORDER_WARNING_DELAY = new PacketType(PROTOCOL, SENDER, 0x54, "SetBorderWarningDelay");
|
||||
public static final PacketType SET_BORDER_WARNING_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x55, "SetBorderWarningDistance");
|
||||
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x56, "SetCamera", "Camera", "SPacketCamera");
|
||||
public static final PacketType VIEW_CENTRE = new PacketType(PROTOCOL, SENDER, 0x57, "SetChunkCacheCenter", "ViewCentre");
|
||||
public static final PacketType VIEW_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x58, "SetChunkCacheRadius", "ViewDistance");
|
||||
public static final PacketType SET_CURSOR_ITEM = new PacketType(PROTOCOL, SENDER, 0x59, "SetCursorItem");
|
||||
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x5A, "SetDefaultSpawnPosition", "SpawnPosition", "SPacketSpawnPosition");
|
||||
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x5B, "SetDisplayObjective", "ScoreboardDisplayObjective", "SPacketDisplayObjective");
|
||||
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x5C, "SetEntityData", "EntityMetadata", "SPacketEntityMetadata");
|
||||
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x5D, "SetEntityLink", "AttachEntity", "SPacketEntityAttach");
|
||||
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x5E, "SetEntityMotion", "EntityVelocity", "SPacketEntityVelocity");
|
||||
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x5F, "SetEquipment", "EntityEquipment", "SPacketEntityEquipment");
|
||||
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x60, "SetExperience", "Experience", "SPacketSetExperience");
|
||||
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x61, "SetHealth", "UpdateHealth", "SPacketUpdateHealth");
|
||||
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x62, "SetHeldSlot", "SetCarriedItem", "HeldItemSlot", "SPacketHeldItemChange");
|
||||
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x63, "SetObjective", "ScoreboardObjective", "SPacketScoreboardObjective");
|
||||
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x64, "SetPassengers", "Mount", "SPacketSetPassengers");
|
||||
public static final PacketType SET_PLAYER_INVENTORY = new PacketType(PROTOCOL, SENDER, 0x65, "SetPlayerInventory");
|
||||
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x66, "SetPlayerTeam", "ScoreboardTeam", "SPacketTeams");
|
||||
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x67, "SetScore", "ScoreboardScore", "SPacketUpdateScore");
|
||||
public static final PacketType UPDATE_SIMULATION_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x68, "SetSimulationDistance");
|
||||
public static final PacketType SET_SUBTITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x69, "SetSubtitleText");
|
||||
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x6A, "SetTime", "UpdateTime", "SPacketTimeUpdate");
|
||||
public static final PacketType SET_TITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x6B, "SetTitleText");
|
||||
public static final PacketType SET_TITLES_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x6C, "SetTitlesAnimation");
|
||||
public static final PacketType ENTITY_SOUND = new PacketType(PROTOCOL, SENDER, 0x6D, "SoundEntity", "EntitySound", "SPacketSoundEffect");
|
||||
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x6E, "Sound", "NamedSoundEffect");
|
||||
public static final PacketType START_CONFIGURATION = new PacketType(PROTOCOL, SENDER, 0x6F, "StartConfiguration");
|
||||
public static final PacketType STOP_SOUND = new PacketType(PROTOCOL, SENDER, 0x70, "StopSound");
|
||||
public static final PacketType STORE_COOKIE = new PacketType(PROTOCOL, SENDER, 0x71, "StoreCookie");
|
||||
public static final PacketType SYSTEM_CHAT = new PacketType(PROTOCOL, SENDER, 0x72, "SystemChat");
|
||||
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x73, "TabList", "PlayerListHeaderFooter", "SPacketPlayerListHeaderFooter");
|
||||
public static final PacketType NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x74, "TagQuery", "NBTQuery");
|
||||
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x75, "TakeItemEntity", "Collect", "SPacketCollectItem");
|
||||
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x76, "TeleportEntity", "EntityTeleport", "SPacketEntityTeleport");
|
||||
public static final PacketType TEST_INSTANCE_BLOCK_STATUS = new PacketType(PROTOCOL, SENDER, 0x77, "ClientboundTestInstanceBlockStatus");
|
||||
public static final PacketType TICKING_STATE = new PacketType(PROTOCOL, SENDER, 0x78, "TickingState", "TickingStatePacket");
|
||||
public static final PacketType TICKING_STEP_STATE = new PacketType(PROTOCOL, SENDER, 0x79, "TickingStep", "TickingStepPacket");
|
||||
public static final PacketType TRANSFER = new PacketType(PROTOCOL, SENDER, 0x7A, "Transfer");
|
||||
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x7B, "UpdateAdvancements", "Advancements", "SPacketAdvancementInfo");
|
||||
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x7C, "UpdateAttributes", "SPacketEntityProperties");
|
||||
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x7D, "UpdateMobEffect", "EntityEffect", "SPacketEntityEffect");
|
||||
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x7E, "UpdateRecipes", "RecipeUpdate");
|
||||
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x7F, "UpdateTags", "Tags");
|
||||
public static final PacketType PROJECTILE_POWER = new PacketType(PROTOCOL, SENDER, 0x80, "ProjectilePower");
|
||||
public static final PacketType REPORT_DETAILS = new PacketType(PROTOCOL, SENDER, 0x81, "CustomReportDetails");
|
||||
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x82, "ServerLinks");
|
||||
public static final PacketType TRACKED_WAYPOINT = new PacketType(PROTOCOL, SENDER, 0x83, "TrackedWaypoint");
|
||||
public static final PacketType CLEAR_DIALOG = new PacketType(PROTOCOL, SENDER, 0x84, "ClearDialog");
|
||||
public static final PacketType SHOW_DIALOG = new PacketType(PROTOCOL, SENDER, 0x85, "ShowDialog");
|
||||
public static final PacketType DEBUG_BLOCK_VALUE = new PacketType(PROTOCOL, SENDER, 0x1A, "DebugBlockValue");
|
||||
public static final PacketType DEBUG_CHUNK_VALUE = new PacketType(PROTOCOL, SENDER, 0x1B, "DebugChunkValue");
|
||||
public static final PacketType DEBUG_ENTITY_VALUE = new PacketType(PROTOCOL, SENDER, 0x1C, "DebugEntityValue");
|
||||
public static final PacketType DEBUG_EVENT = new PacketType(PROTOCOL, SENDER, 0x1D, "DebugEvent");
|
||||
public static final PacketType DEBUG_SAMPLE = new PacketType(PROTOCOL, SENDER, 0x1E, "DebugSample");
|
||||
public static final PacketType DELETE_CHAT_MESSAGE = new PacketType(PROTOCOL, SENDER, 0x1F, "DeleteChat");
|
||||
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x20, "Disconnect", "KickDisconnect", "SPacketDisconnect");
|
||||
public static final PacketType DISGUISED_CHAT = new PacketType(PROTOCOL, SENDER, 0x21, "DisguisedChat");
|
||||
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x22, "EntityEvent", "EntityStatus", "SPacketEntityStatus");
|
||||
public static final PacketType ENTITY_POSITION_SYNC = new PacketType(PROTOCOL, SENDER, 0x23, "EntityPositionSync");
|
||||
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x24, "Explode", "Explosion", "SPacketExplosion");
|
||||
public static final PacketType UNLOAD_CHUNK = new PacketType(PROTOCOL, SENDER, 0x25, "ForgetLevelChunk", "UnloadChunk", "SPacketUnloadChunk");
|
||||
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x26, "GameEvent", "GameStateChange", "SPacketChangeGameState");
|
||||
public static final PacketType GAME_RULE_VALUES = new PacketType(PROTOCOL, SENDER, 0x27, "GameRuleValues");
|
||||
public static final PacketType GAME_TEST_HIGHLIGHT_POS = new PacketType(PROTOCOL, SENDER, 0x28, "GameTestHighlightPos");
|
||||
public static final PacketType OPEN_WINDOW_HORSE = new PacketType(PROTOCOL, SENDER, 0x29, "MountScreenOpen", "HorseScreenOpen", "OpenWindowHorse");
|
||||
public static final PacketType HURT_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x2A, "HurtAnimation", "ClientboundHurtAnimationPacket");
|
||||
public static final PacketType INITIALIZE_BORDER = new PacketType(PROTOCOL, SENDER, 0x2B, "InitializeBorder");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x2C, "KeepAlive", "SPacketKeepAlive");
|
||||
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x2D, "LevelChunkWithLight", "MapChunk", "SPacketChunkData");
|
||||
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x2E, "LevelEvent", "WorldEvent", "SPacketEffect");
|
||||
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x2F, "LevelParticles", "WorldParticles", "SPacketParticles");
|
||||
public static final PacketType LIGHT_UPDATE = new PacketType(PROTOCOL, SENDER, 0x30, "LightUpdate");
|
||||
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x31, "Login", "SPacketJoinGame");
|
||||
public static final PacketType LOW_DISK_SPACE_WARNING = new PacketType(PROTOCOL, SENDER, 0x32, "LowDiskSpaceWarning");
|
||||
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x33, "MapItemData", "Map", "SPacketMaps");
|
||||
public static final PacketType OPEN_WINDOW_MERCHANT = new PacketType(PROTOCOL, SENDER, 0x34, "MerchantOffers", "OpenWindowMerchant");
|
||||
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x35, "net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Pos", "Entity$RelEntityMove", "Entity$PacketPlayOutRelEntityMove");
|
||||
public static final PacketType REL_ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x36, "net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$PosRot", "Entity$RelEntityMoveLook", "Entity$PacketPlayOutRelEntityMoveLook");
|
||||
public static final PacketType MOVE_MINECART = new PacketType(PROTOCOL, SENDER, 0x37, "MoveMinecart");
|
||||
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x38, "net.minecraft.network.protocol.game.ClientboundMoveEntityPacket$Rot", "Entity$EntityLook", "Entity$PacketPlayOutEntityLook");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x39, "MoveVehicle", "VehicleMove", "SPacketMoveVehicle");
|
||||
public static final PacketType OPEN_BOOK = new PacketType(PROTOCOL, SENDER, 0x3A, "OpenBook");
|
||||
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x3B, "OpenScreen", "OpenWindow", "SPacketOpenWindow");
|
||||
public static final PacketType OPEN_SIGN_EDITOR = new PacketType(PROTOCOL, SENDER, 0x3C, "OpenSignEditor", "SPacketSignEditorOpen");
|
||||
public static final PacketType PING = new PacketType(PROTOCOL, SENDER, 0x3D, "Ping");
|
||||
public static final PacketType PONG_RESPONSE = new PacketType(PROTOCOL, SENDER, 0x3E, "PongResponse");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x3F, "PlaceGhostRecipe", "AutoRecipe", "SPacketPlaceGhostRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x40, "PlayerAbilities", "Abilities", "SPacketPlayerAbilities");
|
||||
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x41, "PlayerChat", "Chat", "SPacketChat");
|
||||
public static final PacketType PLAYER_COMBAT_END = new PacketType(PROTOCOL, SENDER, 0x42, "PlayerCombatEnd");
|
||||
public static final PacketType PLAYER_COMBAT_ENTER = new PacketType(PROTOCOL, SENDER, 0x43, "PlayerCombatEnter");
|
||||
public static final PacketType PLAYER_COMBAT_KILL = new PacketType(PROTOCOL, SENDER, 0x44, "PlayerCombatKill");
|
||||
public static final PacketType PLAYER_INFO_REMOVE = new PacketType(PROTOCOL, SENDER, 0x45, "PlayerInfoRemove");
|
||||
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x46, "PlayerInfoUpdate", "PlayerInfo");
|
||||
public static final PacketType LOOK_AT = new PacketType(PROTOCOL, SENDER, 0x47, "PlayerLookAt", "LookAt", "SPacketPlayerPosLook");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x48, "PlayerPosition", "Position");
|
||||
public static final PacketType PLAYER_ROTATION = new PacketType(PROTOCOL, SENDER, 0x49, "PlayerRotation");
|
||||
public static final PacketType RECIPE_BOOK_ADD = new PacketType(PROTOCOL, SENDER, 0x4A, "RecipeBookAdd");
|
||||
public static final PacketType RECIPE_BOOK_REMOVE = new PacketType(PROTOCOL, SENDER, 0x4B, "RecipeBookRemove");
|
||||
public static final PacketType RECIPE_BOOK_SETTINGS = new PacketType(PROTOCOL, SENDER, 0x4C, "RecipeBookSettings");
|
||||
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x4D, "RemoveEntities", "EntityDestroy", "SPacketDestroyEntities");
|
||||
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x4E, "RemoveMobEffect", "RemoveEntityEffect", "SPacketRemoveEntityEffect");
|
||||
public static final PacketType RESET_SCORE = new PacketType(PROTOCOL, SENDER, 0x4F, "ResetScore", "ResetScorePacket");
|
||||
public static final PacketType REMOVE_RESOURCE_PACK = new PacketType(PROTOCOL, SENDER, 0x50, "ResourcePackPop", "ResourcePackPopPacket");
|
||||
public static final PacketType ADD_RESOURCE_PACK = new PacketType(PROTOCOL, SENDER, 0x51, "ResourcePackPush", "ResourcePackPushPacket");
|
||||
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x52, "Respawn", "SPacketRespawn");
|
||||
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x53, "RotateHead", "EntityHeadRotation", "SPacketEntityHeadLook");
|
||||
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x54, "SectionBlocksUpdate", "MultiBlockChange", "SPacketMultiBlockChange");
|
||||
public static final PacketType SELECT_ADVANCEMENT_TAB = new PacketType(PROTOCOL, SENDER, 0x55, "SelectAdvancementsTab", "SelectAdvancementTab", "SPacketSelectAdvancementsTab");
|
||||
public static final PacketType SERVER_DATA = new PacketType(PROTOCOL, SENDER, 0x56, "ServerData");
|
||||
public static final PacketType SET_ACTION_BAR_TEXT = new PacketType(PROTOCOL, SENDER, 0x57, "SetActionBarText");
|
||||
public static final PacketType SET_BORDER_CENTER = new PacketType(PROTOCOL, SENDER, 0x58, "SetBorderCenter");
|
||||
public static final PacketType SET_BORDER_LERP_SIZE = new PacketType(PROTOCOL, SENDER, 0x59, "SetBorderLerpSize");
|
||||
public static final PacketType SET_BORDER_SIZE = new PacketType(PROTOCOL, SENDER, 0x5A, "SetBorderSize");
|
||||
public static final PacketType SET_BORDER_WARNING_DELAY = new PacketType(PROTOCOL, SENDER, 0x5B, "SetBorderWarningDelay");
|
||||
public static final PacketType SET_BORDER_WARNING_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x5C, "SetBorderWarningDistance");
|
||||
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x5D, "SetCamera", "Camera", "SPacketCamera");
|
||||
public static final PacketType VIEW_CENTRE = new PacketType(PROTOCOL, SENDER, 0x5E, "SetChunkCacheCenter", "ViewCentre");
|
||||
public static final PacketType VIEW_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x5F, "SetChunkCacheRadius", "ViewDistance");
|
||||
public static final PacketType SET_CURSOR_ITEM = new PacketType(PROTOCOL, SENDER, 0x60, "SetCursorItem");
|
||||
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x61, "SetDefaultSpawnPosition", "SpawnPosition", "SPacketSpawnPosition");
|
||||
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x62, "SetDisplayObjective", "ScoreboardDisplayObjective", "SPacketDisplayObjective");
|
||||
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x63, "SetEntityData", "EntityMetadata", "SPacketEntityMetadata");
|
||||
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x64, "SetEntityLink", "AttachEntity", "SPacketEntityAttach");
|
||||
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x65, "SetEntityMotion", "EntityVelocity", "SPacketEntityVelocity");
|
||||
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x66, "SetEquipment", "EntityEquipment", "SPacketEntityEquipment");
|
||||
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x67, "SetExperience", "Experience", "SPacketSetExperience");
|
||||
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x68, "SetHealth", "UpdateHealth", "SPacketUpdateHealth");
|
||||
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x69, "SetHeldSlot", "SetCarriedItem", "HeldItemSlot", "SPacketHeldItemChange");
|
||||
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x6A, "SetObjective", "ScoreboardObjective", "SPacketScoreboardObjective");
|
||||
public static final PacketType MOUNT = new PacketType(PROTOCOL, SENDER, 0x6B, "SetPassengers", "Mount", "SPacketSetPassengers");
|
||||
public static final PacketType SET_PLAYER_INVENTORY = new PacketType(PROTOCOL, SENDER, 0x6C, "SetPlayerInventory");
|
||||
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x6D, "SetPlayerTeam", "ScoreboardTeam", "SPacketTeams");
|
||||
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x6E, "SetScore", "ScoreboardScore", "SPacketUpdateScore");
|
||||
public static final PacketType UPDATE_SIMULATION_DISTANCE = new PacketType(PROTOCOL, SENDER, 0x6F, "SetSimulationDistance");
|
||||
public static final PacketType SET_SUBTITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x70, "SetSubtitleText");
|
||||
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x71, "SetTime", "UpdateTime", "SPacketTimeUpdate");
|
||||
public static final PacketType SET_TITLE_TEXT = new PacketType(PROTOCOL, SENDER, 0x72, "SetTitleText");
|
||||
public static final PacketType SET_TITLES_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x73, "SetTitlesAnimation");
|
||||
public static final PacketType ENTITY_SOUND = new PacketType(PROTOCOL, SENDER, 0x74, "SoundEntity", "EntitySound", "SPacketSoundEffect");
|
||||
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x75, "Sound", "NamedSoundEffect");
|
||||
public static final PacketType START_CONFIGURATION = new PacketType(PROTOCOL, SENDER, 0x76, "StartConfiguration");
|
||||
public static final PacketType STOP_SOUND = new PacketType(PROTOCOL, SENDER, 0x77, "StopSound");
|
||||
public static final PacketType STORE_COOKIE = new PacketType(PROTOCOL, SENDER, 0x78, "StoreCookie");
|
||||
public static final PacketType SYSTEM_CHAT = new PacketType(PROTOCOL, SENDER, 0x79, "SystemChat");
|
||||
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x7A, "TabList", "PlayerListHeaderFooter", "SPacketPlayerListHeaderFooter");
|
||||
public static final PacketType NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x7B, "TagQuery", "NBTQuery");
|
||||
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x7C, "TakeItemEntity", "Collect", "SPacketCollectItem");
|
||||
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x7D, "TeleportEntity", "EntityTeleport", "SPacketEntityTeleport");
|
||||
public static final PacketType TEST_INSTANCE_BLOCK_STATUS = new PacketType(PROTOCOL, SENDER, 0x7E, "ClientboundTestInstanceBlockStatus");
|
||||
public static final PacketType TICKING_STATE = new PacketType(PROTOCOL, SENDER, 0x7F, "TickingState", "TickingStatePacket");
|
||||
public static final PacketType TICKING_STEP_STATE = new PacketType(PROTOCOL, SENDER, 0x80, "TickingStep", "TickingStepPacket");
|
||||
public static final PacketType TRANSFER = new PacketType(PROTOCOL, SENDER, 0x81, "Transfer");
|
||||
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x82, "UpdateAdvancements", "Advancements", "SPacketAdvancementInfo");
|
||||
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x83, "UpdateAttributes", "SPacketEntityProperties");
|
||||
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x84, "UpdateMobEffect", "EntityEffect", "SPacketEntityEffect");
|
||||
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x85, "UpdateRecipes", "RecipeUpdate");
|
||||
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x86, "UpdateTags", "Tags");
|
||||
public static final PacketType PROJECTILE_POWER = new PacketType(PROTOCOL, SENDER, 0x87, "ProjectilePower");
|
||||
public static final PacketType REPORT_DETAILS = new PacketType(PROTOCOL, SENDER, 0x88, "CustomReportDetails");
|
||||
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x89, "ServerLinks");
|
||||
public static final PacketType TRACKED_WAYPOINT = new PacketType(PROTOCOL, SENDER, 0x8A, "TrackedWaypoint");
|
||||
public static final PacketType CLEAR_DIALOG = new PacketType(PROTOCOL, SENDER, 0x8B, "ClearDialog");
|
||||
public static final PacketType SHOW_DIALOG = new PacketType(PROTOCOL, SENDER, 0x8C, "ShowDialog");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.9
|
||||
@@ -416,7 +423,6 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType SPAWN_ENTITY_EXPERIENCE_ORB = new PacketType(PROTOCOL, SENDER, 232, "AddExperienceOrb", "SpawnEntityExperienceOrb", "SPacketSpawnExperienceOrb");
|
||||
|
||||
|
||||
private static final Server INSTANCE = new Server();
|
||||
|
||||
@@ -439,71 +445,74 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
private static final Sender SENDER = Sender.CLIENT;
|
||||
|
||||
public static final PacketType TELEPORT_ACCEPT = new PacketType(PROTOCOL, SENDER, 0x00, "AcceptTeleportation", "TeleportAccept", "CPacketConfirmTeleport");
|
||||
public static final PacketType TILE_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x01, "BlockEntityTagQuery", "TileNBTQuery");
|
||||
public static final PacketType SELECT_BUNDLE_ITEM = new PacketType(PROTOCOL, SENDER, 0x02, "SelectBundleItem");
|
||||
public static final PacketType DIFFICULTY_CHANGE = new PacketType(PROTOCOL, SENDER, 0x03, "ChangeDifficulty", "DifficultyChange");
|
||||
public static final PacketType CHANGE_GAME_MODE = new PacketType(PROTOCOL, SENDER, 0x04, "ChangeGameMode");
|
||||
public static final PacketType CHAT_ACK = new PacketType(PROTOCOL, SENDER, 0x05, "ChatAck");
|
||||
public static final PacketType CHAT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x06, "ChatCommand");
|
||||
public static final PacketType CHAT_COMMAND_SIGNED = new PacketType(PROTOCOL, SENDER, 0x07, "ChatCommandSigned");
|
||||
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x08, "Chat", "CPacketChatMessage");
|
||||
public static final PacketType CHAT_SESSION_UPDATE = new PacketType(PROTOCOL, SENDER, 0x09, "ChatSessionUpdate");
|
||||
public static final PacketType CHUNK_BATCH_RECEIVED = new PacketType(PROTOCOL, SENDER, 0x0A, "ChunkBatchReceived");
|
||||
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x0B, "ClientCommand", "CPacketClientStatus");
|
||||
public static final PacketType CLIENT_TICK_END = new PacketType(PROTOCOL, SENDER, 0x0C, "ClientTickEnd");
|
||||
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x0D, "ClientInformation", "Settings", "CPacketClientSettings");
|
||||
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x0E, "CommandSuggestion", "TabComplete", "CPacketTabComplete");
|
||||
public static final PacketType CONFIGURATION_ACK = new PacketType(PROTOCOL, SENDER, 0x0F, "ConfigurationAcknowledged");
|
||||
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x10, "ContainerButtonClick", "EnchantItem", "CPacketEnchantItem");
|
||||
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x11, "ContainerClick", "WindowClick", "CPacketClickWindow");
|
||||
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x12, "ContainerClose", "CloseWindow", "CPacketCloseWindow");
|
||||
public static final PacketType CONTAINER_SLOT_STATE_CHANGED = new PacketType(PROTOCOL, SENDER, 0x13, "ContainerSlotStateChanged", "ContainerSlotStateChangedPacket");
|
||||
public static final PacketType COOKIE_RESPONSE = new PacketType(PROTOCOL, SENDER, 0x14, "CookieResponse");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x15, "CustomPayload", "CPacketCustomPayload");
|
||||
public static final PacketType DEBUG_SAMPLE_SUBSCRIPTION = new PacketType(PROTOCOL, SENDER, 0x16, "DebugSampleSubscription");
|
||||
public static final PacketType B_EDIT = new PacketType(PROTOCOL, SENDER, 0x17, "EditBook", "BEdit");
|
||||
public static final PacketType ENTITY_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x18, "EntityTagQuery", "EntityNBTQuery");
|
||||
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x19, "Interact", "UseEntity", "CPacketUseEntity");
|
||||
public static final PacketType JIGSAW_GENERATE = new PacketType(PROTOCOL, SENDER, 0x1A, "JigsawGenerate");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x1B, "KeepAlive", "CPacketKeepAlive");
|
||||
public static final PacketType DIFFICULTY_LOCK = new PacketType(PROTOCOL, SENDER, 0x1C, "LockDifficulty", "DifficultyLock");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x1D, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos", "Flying$Position", "Flying$PacketPlayInPosition", "CPacketPlayer$Position");
|
||||
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x1E, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot", "Flying$PositionLook", "Flying$PacketPlayInPositionLook", "CPacketPlayer$PositionRotation");
|
||||
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x1F, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot", "Flying$Look", "Flying$PacketPlayInLook", "CPacketPlayer$Rotation");
|
||||
public static final PacketType GROUND = new PacketType(PROTOCOL, SENDER, 0x20, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$StatusOnly", "Flying$d");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x21, "MoveVehicle", "VehicleMove", "CPacketVehicleMove");
|
||||
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x22, "PaddleBoat", "BoatMove", "CPacketSteerBoat");
|
||||
public static final PacketType PICK_ITEM_FROM_BLOCK = new PacketType(PROTOCOL, SENDER, 0x23, "PickItemFromBlock");
|
||||
public static final PacketType PICK_ITEM = new PacketType(PROTOCOL, SENDER, 0x24, "PickItemFromEntity", "PickItem");
|
||||
public static final PacketType PING_REQUEST = new PacketType(PROTOCOL, SENDER, 0x25, "PingRequest");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x26, "PlaceRecipe", "AutoRecipe", "CPacketPlaceRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x27, "PlayerAbilities", "Abilities", "CPacketPlayerAbilities");
|
||||
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x28, "PlayerAction", "BlockDig", "CPacketPlayerDigging");
|
||||
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x29, "PlayerCommand", "EntityAction", "CPacketEntityAction");
|
||||
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x2A, "PlayerInput", "SteerVehicle", "CPacketInput");
|
||||
public static final PacketType PLAYER_LOADED = new PacketType(PROTOCOL, SENDER, 0x2B, "PlayerLoaded");
|
||||
public static final PacketType PONG = new PacketType(PROTOCOL, SENDER, 0x2C, "Pong");
|
||||
public static final PacketType RECIPE_SETTINGS = new PacketType(PROTOCOL, SENDER, 0x2D, "RecipeBookChangeSettings", "RecipeSettings");
|
||||
public static final PacketType RECIPE_DISPLAYED = new PacketType(PROTOCOL, SENDER, 0x2E, "RecipeBookSeenRecipe", "RecipeDisplayed", "CPacketRecipeInfo");
|
||||
public static final PacketType ITEM_NAME = new PacketType(PROTOCOL, SENDER, 0x2F, "RenameItem", "ItemName");
|
||||
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x30, "ResourcePack", "ResourcePackStatus", "CPacketResourcePackStatus");
|
||||
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x31, "SeenAdvancements", "Advancements", "CPacketSeenAdvancements");
|
||||
public static final PacketType TR_SEL = new PacketType(PROTOCOL, SENDER, 0x32, "SelectTrade", "TrSel");
|
||||
public static final PacketType BEACON = new PacketType(PROTOCOL, SENDER, 0x33, "SetBeacon", "Beacon");
|
||||
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x34, "SetCarriedItem", "HeldItemSlot", "CPacketHeldItemChange");
|
||||
public static final PacketType SET_COMMAND_BLOCK = new PacketType(PROTOCOL, SENDER, 0x35, "SetCommandBlock");
|
||||
public static final PacketType SET_COMMAND_MINECART = new PacketType(PROTOCOL, SENDER, 0x36, "SetCommandMinecart");
|
||||
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x37, "SetCreativeModeSlot", "SetCreativeSlot", "CPacketCreativeInventoryAction");
|
||||
public static final PacketType SET_JIGSAW = new PacketType(PROTOCOL, SENDER, 0x38, "SetJigsawBlock", "SetJigsaw");
|
||||
public static final PacketType STRUCT = new PacketType(PROTOCOL, SENDER, 0x39, "SetStructureBlock", "Struct");
|
||||
public static final PacketType SET_TEST_BLOCK = new PacketType(PROTOCOL, SENDER, 0x3A, "SetTestBlock");
|
||||
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x3B, "SignUpdate", "UpdateSign", "CPacketUpdateSign");
|
||||
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x3C, "Swing", "ArmAnimation", "CPacketAnimation");
|
||||
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x3D, "TeleportToEntity", "Spectate", "CPacketSpectate");
|
||||
public static final PacketType TEST_INSTANCE_BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x3E, "TestInstanceBlockAction");
|
||||
public static final PacketType USE_ITEM_ON = new PacketType(PROTOCOL, SENDER, 0x3F, "UseItemOn", "BlockPlace", "CPacketPlayerTryUseItemOnBlock");
|
||||
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x40, "UseItem", "CPacketPlayerTryUseItem");
|
||||
public static final PacketType CUSTOM_CLICK_ACTION = new PacketType(PROTOCOL, SENDER, 0x41, "CustomClickAction");
|
||||
public static final PacketType ATTACK = new PacketType(PROTOCOL, SENDER, 0x01, "Attack");
|
||||
public static final PacketType TILE_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x02, "BlockEntityTagQuery", "TileNBTQuery");
|
||||
public static final PacketType SELECT_BUNDLE_ITEM = new PacketType(PROTOCOL, SENDER, 0x03, "SelectBundleItem");
|
||||
public static final PacketType DIFFICULTY_CHANGE = new PacketType(PROTOCOL, SENDER, 0x04, "ChangeDifficulty", "DifficultyChange");
|
||||
public static final PacketType CHANGE_GAME_MODE = new PacketType(PROTOCOL, SENDER, 0x05, "ChangeGameMode");
|
||||
public static final PacketType CHAT_ACK = new PacketType(PROTOCOL, SENDER, 0x06, "ChatAck");
|
||||
public static final PacketType CHAT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x07, "ChatCommand");
|
||||
public static final PacketType CHAT_COMMAND_SIGNED = new PacketType(PROTOCOL, SENDER, 0x08, "ChatCommandSigned");
|
||||
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x09, "Chat", "CPacketChatMessage");
|
||||
public static final PacketType CHAT_SESSION_UPDATE = new PacketType(PROTOCOL, SENDER, 0x0A, "ChatSessionUpdate");
|
||||
public static final PacketType CHUNK_BATCH_RECEIVED = new PacketType(PROTOCOL, SENDER, 0x0B, "ChunkBatchReceived");
|
||||
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x0C, "ClientCommand", "CPacketClientStatus");
|
||||
public static final PacketType CLIENT_TICK_END = new PacketType(PROTOCOL, SENDER, 0x0D, "ClientTickEnd");
|
||||
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x0E, "ClientInformation", "Settings", "CPacketClientSettings");
|
||||
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x0F, "CommandSuggestion", "TabComplete", "CPacketTabComplete");
|
||||
public static final PacketType CONFIGURATION_ACK = new PacketType(PROTOCOL, SENDER, 0x10, "ConfigurationAcknowledged");
|
||||
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x11, "ContainerButtonClick", "EnchantItem", "CPacketEnchantItem");
|
||||
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x12, "ContainerClick", "WindowClick", "CPacketClickWindow");
|
||||
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x13, "ContainerClose", "CloseWindow", "CPacketCloseWindow");
|
||||
public static final PacketType CONTAINER_SLOT_STATE_CHANGED = new PacketType(PROTOCOL, SENDER, 0x14, "ContainerSlotStateChanged", "ContainerSlotStateChangedPacket");
|
||||
public static final PacketType COOKIE_RESPONSE = new PacketType(PROTOCOL, SENDER, 0x15, "CookieResponse");
|
||||
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x16, "CustomPayload", "CPacketCustomPayload");
|
||||
public static final PacketType DEBUG_SUBSCRIPTION_REQUEST = new PacketType(PROTOCOL, SENDER, 0x17, "DebugSubscriptionRequest");
|
||||
public static final PacketType B_EDIT = new PacketType(PROTOCOL, SENDER, 0x18, "EditBook", "BEdit");
|
||||
public static final PacketType ENTITY_NBT_QUERY = new PacketType(PROTOCOL, SENDER, 0x19, "EntityTagQuery", "EntityNBTQuery");
|
||||
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x1A, "Interact", "UseEntity", "CPacketUseEntity");
|
||||
public static final PacketType JIGSAW_GENERATE = new PacketType(PROTOCOL, SENDER, 0x1B, "JigsawGenerate");
|
||||
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x1C, "KeepAlive", "CPacketKeepAlive");
|
||||
public static final PacketType DIFFICULTY_LOCK = new PacketType(PROTOCOL, SENDER, 0x1D, "LockDifficulty", "DifficultyLock");
|
||||
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x1E, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos", "Flying$Position", "Flying$PacketPlayInPosition", "CPacketPlayer$Position");
|
||||
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x1F, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot", "Flying$PositionLook", "Flying$PacketPlayInPositionLook", "CPacketPlayer$PositionRotation");
|
||||
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x20, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Rot", "Flying$Look", "Flying$PacketPlayInLook", "CPacketPlayer$Rotation");
|
||||
public static final PacketType GROUND = new PacketType(PROTOCOL, SENDER, 0x21, "net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$StatusOnly", "Flying$d");
|
||||
public static final PacketType VEHICLE_MOVE = new PacketType(PROTOCOL, SENDER, 0x22, "MoveVehicle", "VehicleMove", "CPacketVehicleMove");
|
||||
public static final PacketType BOAT_MOVE = new PacketType(PROTOCOL, SENDER, 0x23, "PaddleBoat", "BoatMove", "CPacketSteerBoat");
|
||||
public static final PacketType PICK_ITEM_FROM_BLOCK = new PacketType(PROTOCOL, SENDER, 0x24, "PickItemFromBlock");
|
||||
public static final PacketType PICK_ITEM = new PacketType(PROTOCOL, SENDER, 0x25, "PickItemFromEntity", "PickItem");
|
||||
public static final PacketType PING_REQUEST = new PacketType(PROTOCOL, SENDER, 0x26, "PingRequest");
|
||||
public static final PacketType AUTO_RECIPE = new PacketType(PROTOCOL, SENDER, 0x27, "PlaceRecipe", "AutoRecipe", "CPacketPlaceRecipe");
|
||||
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x28, "PlayerAbilities", "Abilities", "CPacketPlayerAbilities");
|
||||
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x29, "PlayerAction", "BlockDig", "CPacketPlayerDigging");
|
||||
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x2A, "PlayerCommand", "EntityAction", "CPacketEntityAction");
|
||||
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x2B, "PlayerInput", "SteerVehicle", "CPacketInput");
|
||||
public static final PacketType PLAYER_LOADED = new PacketType(PROTOCOL, SENDER, 0x2C, "PlayerLoaded");
|
||||
public static final PacketType PONG = new PacketType(PROTOCOL, SENDER, 0x2D, "Pong");
|
||||
public static final PacketType RECIPE_SETTINGS = new PacketType(PROTOCOL, SENDER, 0x2E, "RecipeBookChangeSettings", "RecipeSettings");
|
||||
public static final PacketType RECIPE_DISPLAYED = new PacketType(PROTOCOL, SENDER, 0x2F, "RecipeBookSeenRecipe", "RecipeDisplayed", "CPacketRecipeInfo");
|
||||
public static final PacketType ITEM_NAME = new PacketType(PROTOCOL, SENDER, 0x30, "RenameItem", "ItemName");
|
||||
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x31, "ResourcePack", "ResourcePackStatus", "CPacketResourcePackStatus");
|
||||
public static final PacketType ADVANCEMENTS = new PacketType(PROTOCOL, SENDER, 0x32, "SeenAdvancements", "Advancements", "CPacketSeenAdvancements");
|
||||
public static final PacketType TR_SEL = new PacketType(PROTOCOL, SENDER, 0x33, "SelectTrade", "TrSel");
|
||||
public static final PacketType BEACON = new PacketType(PROTOCOL, SENDER, 0x34, "SetBeacon", "Beacon");
|
||||
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x35, "SetCarriedItem", "HeldItemSlot", "CPacketHeldItemChange");
|
||||
public static final PacketType SET_COMMAND_BLOCK = new PacketType(PROTOCOL, SENDER, 0x36, "SetCommandBlock");
|
||||
public static final PacketType SET_COMMAND_MINECART = new PacketType(PROTOCOL, SENDER, 0x37, "SetCommandMinecart");
|
||||
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x38, "SetCreativeModeSlot", "SetCreativeSlot", "CPacketCreativeInventoryAction");
|
||||
public static final PacketType SET_GAME_RULE = new PacketType(PROTOCOL, SENDER, 0x39, "SetGameRule");
|
||||
public static final PacketType SET_JIGSAW = new PacketType(PROTOCOL, SENDER, 0x3A, "SetJigsawBlock", "SetJigsaw");
|
||||
public static final PacketType STRUCT = new PacketType(PROTOCOL, SENDER, 0x3B, "SetStructureBlock", "Struct");
|
||||
public static final PacketType SET_TEST_BLOCK = new PacketType(PROTOCOL, SENDER, 0x3C, "SetTestBlock");
|
||||
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x3D, "SignUpdate", "UpdateSign", "CPacketUpdateSign");
|
||||
public static final PacketType SPECTATE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x3E, "SpectatorAction", "SpectateEntity");
|
||||
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x3F, "Swing", "ArmAnimation", "CPacketAnimation");
|
||||
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x40, "TeleportToEntity", "Spectate", "CPacketSpectate");
|
||||
public static final PacketType TEST_INSTANCE_BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x41, "TestInstanceBlockAction");
|
||||
public static final PacketType USE_ITEM_ON = new PacketType(PROTOCOL, SENDER, 0x42, "UseItemOn", "BlockPlace", "CPacketPlayerTryUseItemOnBlock");
|
||||
public static final PacketType USE_ITEM = new PacketType(PROTOCOL, SENDER, 0x43, "UseItem", "CPacketPlayerTryUseItem");
|
||||
public static final PacketType CUSTOM_CLICK_ACTION = new PacketType(PROTOCOL, SENDER, 0x44, "CustomClickAction");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.17
|
||||
@@ -523,6 +532,12 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
@Deprecated
|
||||
public static final PacketType CHAT_PREVIEW = new PacketType(PROTOCOL, SENDER, 253, "ChatPreview");
|
||||
|
||||
/**
|
||||
* deprecated Removed in 1.21.9
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType DEBUG_SAMPLE_SUBSCRIPTION = new PacketType(PROTOCOL, SENDER, 0x16, "DebugSampleSubscription");
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to USE_ITEM_ON
|
||||
*/
|
||||
@@ -713,6 +728,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x10, "ServerLinks");
|
||||
public static final PacketType CLEAR_DIALOG = new PacketType(PROTOCOL, SENDER, 0x11, "ClearDialog");
|
||||
public static final PacketType SHOW_DIALOG = new PacketType(PROTOCOL, SENDER, 0x12, "ShowDialog");
|
||||
public static final PacketType CODE_OF_CONDUCT = new PacketType(PROTOCOL, SENDER, 0x13, "CodeOfConduct");
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 1.20.4: replaced with new packets for removing and sending resource packs
|
||||
@@ -745,6 +761,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
|
||||
public static final PacketType RESOURCE_PACK_ACK = new PacketType(PROTOCOL, SENDER, 0x06, "ResourcePack");
|
||||
public static final PacketType SELECT_KNOWN_PACKS = new PacketType(PROTOCOL, SENDER, 0x07, "ServerboundSelectKnownPacks");
|
||||
public static final PacketType CUSTOM_CLICK_ACTION = new PacketType(PROTOCOL, SENDER, 0x08, "CustomClickAction");
|
||||
public static final PacketType ACCEPT_CODE_OF_CONDUCT = new PacketType(PROTOCOL, SENDER, 0x09, "AcceptCodeOfConduct");
|
||||
|
||||
private static final Client INSTANCE = new Client();
|
||||
|
||||
|
||||
@@ -35,12 +35,12 @@ public class ProtocolLibrary {
|
||||
/**
|
||||
* The maximum version ProtocolLib has been tested with.
|
||||
*/
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.21.8";
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "26.2";
|
||||
|
||||
/**
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.21.8) was released.
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (26.2) was released.
|
||||
*/
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2025-07-17";
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2026-06-16";
|
||||
|
||||
private static Plugin plugin;
|
||||
private static ProtocolConfig config;
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.collection.InboundPacketListenerSet;
|
||||
import com.comphenix.protocol.injector.collection.OutboundPacketListenerSet;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
import com.comphenix.protocol.scheduler.ProtocolScheduler;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -274,7 +275,7 @@ public class AsyncFilterManager implements AsynchronousManager {
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
private boolean onMainThread() {
|
||||
return Thread.currentThread().getId() == mainThread.getId();
|
||||
return Thread.currentThread() == mainThread;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -347,8 +348,8 @@ public class AsyncFilterManager implements AsynchronousManager {
|
||||
* Construct a asynchronous marker with all the default values.
|
||||
* @return Asynchronous marker.
|
||||
*/
|
||||
public AsyncMarker createAsyncMarker() {
|
||||
return createAsyncMarker(AsyncMarker.DEFAULT_TIMEOUT_DELTA);
|
||||
public AsyncMarker createAsyncMarker(Injector injector) {
|
||||
return createAsyncMarker(injector, AsyncMarker.DEFAULT_TIMEOUT_DELTA);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,13 +357,13 @@ public class AsyncFilterManager implements AsynchronousManager {
|
||||
* @param timeoutDelta - how long (in ms) until the packet expire.
|
||||
* @return An async marker.
|
||||
*/
|
||||
public AsyncMarker createAsyncMarker(long timeoutDelta) {
|
||||
return createAsyncMarker(timeoutDelta, currentSendingIndex.incrementAndGet());
|
||||
public AsyncMarker createAsyncMarker(Injector injector, long timeoutDelta) {
|
||||
return createAsyncMarker(injector, timeoutDelta, currentSendingIndex.incrementAndGet());
|
||||
}
|
||||
|
||||
// Helper method
|
||||
private AsyncMarker createAsyncMarker(long timeoutDelta, long sendingIndex) {
|
||||
return new AsyncMarker(manager, sendingIndex, System.currentTimeMillis(), timeoutDelta);
|
||||
private AsyncMarker createAsyncMarker(Injector injector, long timeoutDelta, long sendingIndex) {
|
||||
return new AsyncMarker(injector, sendingIndex, System.currentTimeMillis(), timeoutDelta);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -538,7 +538,7 @@ public class AsyncListenerHandler {
|
||||
*/
|
||||
private void listenerLoop(int workerID) {
|
||||
// Danger, danger!
|
||||
if (Thread.currentThread().getId() == mainThread.getId())
|
||||
if (Thread.currentThread() == mainThread)
|
||||
throw new IllegalStateException("Do not call this method from the main thread.");
|
||||
if (cancelled)
|
||||
throw new IllegalStateException("Listener has been cancelled. Create a new listener instead.");
|
||||
|
||||
@@ -23,14 +23,18 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import com.comphenix.protocol.PacketStream;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolLogger;
|
||||
import com.comphenix.protocol.events.NetworkMarker;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
@@ -64,7 +68,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
/**
|
||||
* The packet stream responsible for transmitting the packet when it's done processing.
|
||||
*/
|
||||
private transient PacketStream packetStream;
|
||||
private final Injector injector;
|
||||
|
||||
/**
|
||||
* Current list of async packet listeners.
|
||||
@@ -86,7 +90,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
private volatile boolean processed;
|
||||
|
||||
// Whether or not the packet has been sent
|
||||
private volatile boolean transmitted;
|
||||
private final AtomicBoolean transmitted = new AtomicBoolean(false);
|
||||
|
||||
// Whether or not the asynchronous processing itself should be cancelled
|
||||
private volatile boolean asyncCancelled;
|
||||
@@ -109,11 +113,8 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
* Create a container for asyncronous packets.
|
||||
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
|
||||
*/
|
||||
AsyncMarker(PacketStream packetStream, long sendingIndex, long initialTime, long timeoutDelta) {
|
||||
if (packetStream == null)
|
||||
throw new IllegalArgumentException("packetStream cannot be NULL");
|
||||
|
||||
this.packetStream = packetStream;
|
||||
AsyncMarker(Injector injector, long sendingIndex, long initialTime, long timeoutDelta) {
|
||||
this.injector = Objects.requireNonNull(injector, "injector is nul");
|
||||
|
||||
// Timeout
|
||||
this.initialTime = initialTime;
|
||||
@@ -180,16 +181,18 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
* Retrieve the packet stream responsible for transmitting this packet.
|
||||
* @return The packet stream.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketStream getPacketStream() {
|
||||
return packetStream;
|
||||
return ProtocolLibrary.getProtocolManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the output packet stream responsible for transmitting this packet.
|
||||
* @param packetStream - new output packet stream.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setPacketStream(PacketStream packetStream) {
|
||||
this.packetStream = packetStream;
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +288,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
* @return TRUE if it has been sent before, FALSE otherwise.
|
||||
*/
|
||||
public boolean isTransmitted() {
|
||||
return transmitted;
|
||||
return transmitted.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -383,13 +386,18 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
||||
* @throws IOException If the packet couldn't be sent.
|
||||
*/
|
||||
void sendPacket(PacketEvent event) throws IOException {
|
||||
if (event.isServerPacket()) {
|
||||
packetStream.sendServerPacket(event.getPlayer(), event.getPacket(), NetworkMarker.getNetworkMarker(event), false);
|
||||
} else {
|
||||
packetStream.receiveClientPacket(event.getPlayer(), event.getPacket(), NetworkMarker.getNetworkMarker(event),
|
||||
false);
|
||||
if (!this.transmitted.compareAndSet(false, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object handle = event.getPacket().getHandle();
|
||||
|
||||
if (event.isServerPacket()) {
|
||||
NetworkMarker marker = NetworkMarker.getNetworkMarker(event);
|
||||
this.injector.sendClientboundPacket(handle, marker, false);
|
||||
} else {
|
||||
this.injector.readServerboundPacket(handle);
|
||||
}
|
||||
transmitted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.comphenix.protocol.wrappers.WrappedLevelChunkData;
|
||||
import com.comphenix.protocol.wrappers.WrappedMessageSignature;
|
||||
import com.comphenix.protocol.wrappers.WrappedNumberFormat;
|
||||
import com.comphenix.protocol.wrappers.WrappedParticle;
|
||||
import com.comphenix.protocol.wrappers.WrappedPositionMoveRotation;
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey;
|
||||
import com.comphenix.protocol.wrappers.WrappedProfilePublicKey.WrappedProfileKeyData;
|
||||
import com.comphenix.protocol.wrappers.WrappedRegistrable;
|
||||
@@ -65,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;
|
||||
@@ -418,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>
|
||||
@@ -597,9 +609,7 @@ public abstract class AbstractStructure {
|
||||
*/
|
||||
public StructureModifier<List<PlayerInfoData>> getPlayerInfoDataLists() {
|
||||
// Convert to and from the ProtocolLib wrapper
|
||||
return structureModifier.withType(
|
||||
Collection.class,
|
||||
BukkitConverters.getListConverter(PlayerInfoData.getConverter()));
|
||||
return getLists(PlayerInfoData.getConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -804,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.
|
||||
@@ -819,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.
|
||||
@@ -1297,6 +1330,20 @@ public abstract class AbstractStructure {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for {@link WrappedPositionMoveRotation} (available since Minecraft 1.21.2).
|
||||
* <p>
|
||||
* This is used in packets such as {@code ENTITY_TELEPORT} and {@code ENTITY_POSITION_SYNC}.
|
||||
*
|
||||
* @return A modifier for PositionMoveRotation fields.
|
||||
*/
|
||||
public StructureModifier<WrappedPositionMoveRotation> getPositionMoveRotation() {
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getPositionMoveRotationClass(),
|
||||
WrappedPositionMoveRotation.getConverter()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an equivalent converter for ItemStack arrays.
|
||||
* @author Kristian
|
||||
|
||||
@@ -232,13 +232,13 @@ public abstract class PacketAdapter implements PacketListener {
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
// Lets prevent some bugs
|
||||
throw new IllegalStateException("Override onPacketReceiving to get notifcations of received packets!");
|
||||
throw new IllegalStateException("Override onPacketReceiving to get notifications of received packets!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
// Lets prevent some bugs
|
||||
throw new IllegalStateException("Override onPacketSending to get notifcations of sent packets!");
|
||||
throw new IllegalStateException("Override onPacketSending to get notifications of sent packets!");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,7 @@ import com.comphenix.protocol.injector.PluginVerifier.VerificationResult;
|
||||
import com.comphenix.protocol.injector.collection.InboundPacketListenerSet;
|
||||
import com.comphenix.protocol.injector.collection.OutboundPacketListenerSet;
|
||||
import com.comphenix.protocol.injector.collection.PacketListenerSet;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.injector.netty.manager.NetworkManagerInjector;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
@@ -151,29 +152,20 @@ public class PacketFilterManager implements ListenerManager, InternalManager {
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) {
|
||||
if (!this.closed) {
|
||||
// if we skip the packet events later when actually writing into the pipeline we at least notify all
|
||||
// monitor listeners before doing so - they will not be able to change the event tho
|
||||
if (!filters) {
|
||||
// ensure we are on the main thread if any listener requires that
|
||||
if (this.hasMainThreadListener(packet.getType()) && !this.server.isPrimaryThread()) {
|
||||
NetworkMarker copy = marker; // okay fine
|
||||
ProtocolLibrary.getScheduler().scheduleSyncDelayedTask(
|
||||
() -> this.sendServerPacket(receiver, packet, copy, false), 1L);
|
||||
return;
|
||||
}
|
||||
|
||||
// construct the event and post to all monitor listeners
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A monitor listener should never modify a packet/event so we can simply invoke monitor listeners
|
||||
// independently of our injector pipeline
|
||||
if (!filters) {
|
||||
this.runMonitorListeners(packet, () -> {
|
||||
PacketEvent event = PacketEvent.fromServer(this, packet, marker, receiver, false);
|
||||
this.outboundListeners.invoke(event, ListenerPriority.MONITOR);
|
||||
|
||||
// update the marker of the event without accidentally constructing it
|
||||
marker = NetworkMarker.getNetworkMarker(event);
|
||||
}
|
||||
|
||||
// process outbound
|
||||
this.networkManagerInjector.getInjector(receiver).sendClientboundPacket(packet.getHandle(), marker, filters);
|
||||
});
|
||||
}
|
||||
|
||||
this.networkManagerInjector.getInjector(receiver).sendClientboundPacket(packet.getHandle(), marker, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -200,34 +192,40 @@ public class PacketFilterManager implements ListenerManager, InternalManager {
|
||||
|
||||
@Override
|
||||
public void receiveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters) {
|
||||
if (!this.closed) {
|
||||
// make sure we are on the main thread if any listener of the packet needs it
|
||||
if (this.hasMainThreadListener(packet.getType()) && !this.server.isPrimaryThread()) {
|
||||
ProtocolLibrary.getScheduler().runTask(
|
||||
() -> this.receiveClientPacket(sender, packet, marker, filters));
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure we are on the main thread if any listener of the packet needs it
|
||||
if (filters && this.requiresMainThread(packet)) {
|
||||
ProtocolLibrary.getScheduler().runTask(
|
||||
() -> this.receiveClientPacket(sender, packet, marker, filters));
|
||||
return;
|
||||
}
|
||||
|
||||
Object nmsPacket = packet.getHandle();
|
||||
|
||||
if (filters) {
|
||||
PacketEvent event = PacketEvent.fromClient(this, packet, marker, sender, false);
|
||||
this.invokeInboundPacketListeners(event);
|
||||
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Object nmsPacket = packet.getHandle();
|
||||
// check to which listeners we need to post the packet
|
||||
if (filters) {
|
||||
// post to all listeners
|
||||
PacketEvent event = PacketEvent.fromClient(this.networkManagerInjector, packet, null, sender);
|
||||
this.invokeInboundPacketListeners(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// prevent possible de-sync
|
||||
nmsPacket = event.getPacket().getHandle();
|
||||
} else {
|
||||
// Prevent possible de-sync if the packet was replaced by a listener.
|
||||
nmsPacket = event.getPacket().getHandle();
|
||||
} else {
|
||||
// A monitor listener should never modify a packet/event so we can simply invoke monitor listeners
|
||||
// independently of our injector pipeline
|
||||
this.runMonitorListeners(packet, () -> {
|
||||
PacketEvent event = PacketEvent.fromClient(this, packet, marker, sender, false);
|
||||
this.inboundListeners.invoke(event, ListenerPriority.MONITOR);
|
||||
}
|
||||
|
||||
// post to the player inject, reset our cancel state change
|
||||
this.networkManagerInjector.getInjector(sender).readServerboundPacket(nmsPacket);
|
||||
});
|
||||
}
|
||||
|
||||
// post to the player inject, reset our cancel state change
|
||||
this.networkManagerInjector.getInjector(sender).readServerboundPacket(nmsPacket);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -516,12 +514,25 @@ public class PacketFilterManager implements ListenerManager, InternalManager {
|
||||
this.postPacketToListeners(this.outboundListeners, event, true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requiresMainThread(PacketContainer packet) {
|
||||
return this.hasMainThreadListener(packet.getType()) && !this.server.isPrimaryThread();
|
||||
}
|
||||
|
||||
private void runMonitorListeners(PacketContainer packet, Runnable notifyMonitor) {
|
||||
if (this.requiresMainThread(packet)) {
|
||||
ProtocolLibrary.getScheduler().runTask(notifyMonitor);
|
||||
} else {
|
||||
notifyMonitor.run();
|
||||
}
|
||||
}
|
||||
|
||||
private void postPacketToListeners(PacketListenerSet listeners, PacketEvent event, boolean outbound) {
|
||||
try {
|
||||
// append async marker if any async listener for the packet was registered
|
||||
if (this.asyncFilterManager.hasAsynchronousListeners(event)) {
|
||||
event.setAsyncMarker(this.asyncFilterManager.createAsyncMarker());
|
||||
Injector injector = this.networkManagerInjector.getInjector(event.getPlayer());
|
||||
event.setAsyncMarker(this.asyncFilterManager.createAsyncMarker(injector));
|
||||
}
|
||||
|
||||
// post to sync listeners
|
||||
|
||||
@@ -287,8 +287,8 @@ public class StructureCache {
|
||||
|
||||
if (registryByteBuf.isPresent()) {
|
||||
ConstructorAccessor accessor = Accessors.getConstructorAccessor(FuzzyReflection.fromClass(serializerBase, true).getConstructor(FuzzyMethodContract.newBuilder()
|
||||
.parameterDerivedOf(ByteBuf.class)
|
||||
.parameterDerivedOf(MinecraftReflection.getRegistryAccessClass())
|
||||
.parameterExactType(ByteBuf.class)
|
||||
.parameterExactType(MinecraftReflection.getRegistryAccessClass())
|
||||
.build()));
|
||||
TRICKED_DATA_SERIALIZER_BASE = (buf) -> accessor.invoke(buf, MinecraftRegistryAccess.get());
|
||||
} else {
|
||||
|
||||
+7
-5
@@ -58,11 +58,13 @@ public class OutboundPacketListenerSet extends PacketListenerSet {
|
||||
}
|
||||
}
|
||||
|
||||
if (packets.iterator().hasNext()) {
|
||||
event.getPacket().getPacketBundles().write(0, outPackets);
|
||||
} else {
|
||||
// cancel entire packet if each individual packet has been cancelled
|
||||
event.setCancelled(true);
|
||||
if (!event.isReadOnly()) {
|
||||
if (packets.iterator().hasNext()) {
|
||||
event.getPacket().getPacketBundles().write(0, outPackets);
|
||||
} else {
|
||||
// cancel entire packet if each individual packet has been cancelled
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -29,6 +29,7 @@ import com.comphenix.protocol.injector.NetworkProcessor;
|
||||
import com.comphenix.protocol.injector.netty.Injector;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.injector.temporary.TemporaryPlayer;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
@@ -242,7 +243,7 @@ public class NettyChannelInjector implements Injector {
|
||||
this.uninject();
|
||||
|
||||
// remove any outgoing references
|
||||
this.channel.attr(INJECTOR).remove();
|
||||
this.channel.attr(INJECTOR).set(null);
|
||||
|
||||
// cleanup
|
||||
this.savedMarkers.clear();
|
||||
@@ -343,14 +344,15 @@ public class NettyChannelInjector implements Injector {
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
// if the player was already resolved there is no need to do further lookups
|
||||
if (this.player != null) {
|
||||
if (this.player != null && !(this.player instanceof TemporaryPlayer)) {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
// check if the name of the player is already known to the injector
|
||||
if (this.playerName != null) {
|
||||
this.player = Bukkit.getPlayerExact(this.playerName);
|
||||
if (this.player != null) {
|
||||
Player bukkitPlayer = Bukkit.getPlayerExact(this.playerName);
|
||||
if (bukkitPlayer != null) {
|
||||
this.player = bukkitPlayer;
|
||||
this.injectionFactory.cacheInjector(this.player, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelConfig;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelId;
|
||||
import io.netty.channel.ChannelMetadata;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.ChannelProgressivePromise;
|
||||
@@ -33,6 +34,11 @@ final class NettyChannelProxy implements Channel {
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelId id() {
|
||||
return this.delegate.id();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventLoop eventLoop() {
|
||||
return this.eventLoop;
|
||||
@@ -238,6 +244,11 @@ final class NettyChannelProxy implements Channel {
|
||||
return this.delegate.attr(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> boolean hasAttr(AttributeKey<T> attributeKey) {
|
||||
return this.delegate.hasAttr(attributeKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull Channel o) {
|
||||
return this.delegate.compareTo(o);
|
||||
|
||||
+18
-1
@@ -10,11 +10,13 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import io.netty.channel.AbstractEventLoop;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.EventLoop;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.util.concurrent.AbstractEventExecutor;
|
||||
import io.netty.util.concurrent.EventExecutor;
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.ProgressivePromise;
|
||||
@@ -25,7 +27,7 @@ import io.netty.util.concurrent.ScheduledFuture;
|
||||
* An abstract event loop implementation which delegates all calls to a given event loop, but proxies all calls which
|
||||
* schedule something on the event loop to methods which decide what should happen to the scheduled task.
|
||||
*/
|
||||
final class NettyEventLoopProxy implements EventLoop {
|
||||
final class NettyEventLoopProxy extends AbstractEventLoop {
|
||||
|
||||
private static final Callable<?> EMPTY_CALLABLE = () -> null;
|
||||
private static final Runnable EMPTY_RUNNABLE = () -> {
|
||||
@@ -236,6 +238,15 @@ final class NettyEventLoopProxy implements EventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
// ShreddedPaper uses this method
|
||||
@Override
|
||||
public void lazyExecute(Runnable command) {
|
||||
Runnable proxied = this.proxyRunnable(command);
|
||||
if (proxied != null) {
|
||||
((AbstractEventExecutor)this.delegate).lazyExecute(proxied);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super EventExecutor> action) {
|
||||
this.delegate.forEach(action);
|
||||
@@ -251,6 +262,12 @@ final class NettyEventLoopProxy implements EventLoop {
|
||||
return this.delegate.register(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChannelFuture register(ChannelPromise channelPromise) {
|
||||
return this.delegate.register(channelPromise);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public ChannelFuture register(Channel channel, ChannelPromise promise) {
|
||||
return this.delegate.register(channel, promise);
|
||||
|
||||
@@ -412,8 +412,8 @@ public class PacketRegistry {
|
||||
private static Class<?> searchForPacket(List<String> classNames) {
|
||||
for (String name : classNames) {
|
||||
try {
|
||||
Class<?> clazz = MinecraftReflection.getMinecraftClass(name);
|
||||
if (MinecraftReflection.getPacketClass().isAssignableFrom(clazz)
|
||||
Class<?> clazz = resolvePacketClassName(name);
|
||||
if (clazz != null && MinecraftReflection.getPacketClass().isAssignableFrom(clazz)
|
||||
&& !Modifier.isAbstract(clazz.getModifiers())) {
|
||||
return clazz;
|
||||
}
|
||||
@@ -424,6 +424,22 @@ public class PacketRegistry {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a single packet class name. Fully-qualified names (those already containing their
|
||||
* package, e.g. {@code net.minecraft.network.protocol.game.XPacket}) are loaded directly, since
|
||||
* {@link MinecraftReflection#getMinecraftClass(String)} would otherwise prepend the Minecraft
|
||||
* package and fail to find them. Relative names continue to be resolved against the Minecraft
|
||||
* package.
|
||||
*/
|
||||
private static Class<?> resolvePacketClassName(String name) {
|
||||
Optional<Class<?>> direct = MinecraftReflection.getOptionalClass(name);
|
||||
if (direct.isPresent()) {
|
||||
return direct.get();
|
||||
}
|
||||
|
||||
return MinecraftReflection.getMinecraftClass(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given type.
|
||||
*
|
||||
|
||||
@@ -88,20 +88,23 @@ final class CachedPackage {
|
||||
* @throws RuntimeException If we are unable to find the given class.
|
||||
*/
|
||||
public Optional<Class<?>> getPackageClass(String className, String... aliases) {
|
||||
return cache.computeIfAbsent(className, x -> {
|
||||
Optional<Class<?>> clazz = resolveClass(className);
|
||||
if (clazz.isPresent()) {
|
||||
return clazz;
|
||||
}
|
||||
Optional<Class<?>> cached = cache.get(className);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
Optional<Class<?>> clazz = resolveClass(className);
|
||||
if (!clazz.isPresent()) {
|
||||
for (String alias : aliases) {
|
||||
clazz = resolveClass(alias);
|
||||
if (clazz.isPresent()) {
|
||||
return clazz;
|
||||
Optional<Class<?>> aliasClazz = resolveClass(alias);
|
||||
if (aliasClazz.isPresent()) {
|
||||
clazz = aliasClazz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
});
|
||||
cache.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
@@ -96,6 +96,11 @@ public final class MinecraftProtocolVersion {
|
||||
map.put(new MinecraftVersion(1, 21, 2), 768);
|
||||
map.put(new MinecraftVersion(1, 21, 6), 771);
|
||||
map.put(new MinecraftVersion(1, 21, 8), 772);
|
||||
map.put(new MinecraftVersion(1, 21, 9), 773);
|
||||
map.put(new MinecraftVersion(1, 21, 11), 774);
|
||||
|
||||
map.put(new MinecraftVersion(26, 1, 0), 775);
|
||||
map.put(new MinecraftVersion(26, 2, 0), 776);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
@@ -553,6 +553,10 @@ public final class MinecraftReflection {
|
||||
return getClass("com.mojang.authlib.GameProfile");
|
||||
}
|
||||
|
||||
public static Class<?> getGameProfilePropertyMapClass() {
|
||||
return getClass("com.mojang.authlib.properties.PropertyMap");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the entity (NMS) class.
|
||||
*
|
||||
@@ -917,15 +921,19 @@ public final class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getMinecraftKeyClass() {
|
||||
return getMinecraftClass("resources.MinecraftKey", "resources.ResourceLocation", "MinecraftKey");
|
||||
return getMinecraftClass("resources.MinecraftKey", "resources.Identifier", "resources.ResourceLocation", "MinecraftKey");
|
||||
}
|
||||
|
||||
public static Class<?> getMobEffectListClass() {
|
||||
return getMinecraftClass("world.effect.MobEffectList", "MobEffectList", "world.effect.MobEffect");
|
||||
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");
|
||||
return getNullableNMS("sounds.SoundEffect", "sounds.SoundEvent", "SoundEffect", "sounds.SoundEvents");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1114,6 +1122,15 @@ public final class MinecraftReflection {
|
||||
return getOptionalNMS("network.chat.numbers.StyledFormat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the NMS TeamColor class, added in 26.2.
|
||||
*
|
||||
* @return The TeamColor class.
|
||||
*/
|
||||
public static Optional<Class<?>> getTeamColorClass() {
|
||||
return getOptionalNMS("world.scores.TeamColor");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Gson class used by Minecraft.
|
||||
*
|
||||
@@ -1476,6 +1493,18 @@ public final class MinecraftReflection {
|
||||
.orElseThrow(() -> new RuntimeException("Cannot find class " + className));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to load a class by its fully-qualified canonical name, without prepending the
|
||||
* Minecraft package. Unlike {@link #getMinecraftClass(String)}, this can resolve names that
|
||||
* already include their package (e.g. {@code net.minecraft.network.protocol.game.XPacket}).
|
||||
*
|
||||
* @param className - the fully-qualified class name.
|
||||
* @return Optional that may contain the class.
|
||||
*/
|
||||
public static Optional<Class<?>> getOptionalClass(String className) {
|
||||
return getClassSource().loadClass(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the class object of a specific CraftBukkit class.
|
||||
*
|
||||
@@ -1680,7 +1709,7 @@ public final class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getEntityTypes() {
|
||||
return getMinecraftClass("world.entity.EntityTypes", "world.entity.EntityType", "EntityTypes");
|
||||
return getMinecraftClass("world.entity.EntityType", "world.entity.EntityTypes", "EntityTypes");
|
||||
}
|
||||
|
||||
public static Class<?> getParticleParam() {
|
||||
@@ -1899,4 +1928,13 @@ public final class MinecraftReflection {
|
||||
|
||||
return isMojangMapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the PositionMoveRotation class (introduced in 1.21.2).
|
||||
*
|
||||
* @return The PositionMoveRotation class.
|
||||
*/
|
||||
public static Class<?> getPositionMoveRotationClass() {
|
||||
return getMinecraftClass("world.entity.PositionMoveRotation");
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,31 @@ import org.bukkit.Server;
|
||||
* @author Kristian
|
||||
*/
|
||||
public final class MinecraftVersion implements Comparable<MinecraftVersion>, Serializable {
|
||||
/**
|
||||
* Version 26.2 - chaos cubed
|
||||
*/
|
||||
public static final MinecraftVersion v26_2 = new MinecraftVersion("26.2");
|
||||
|
||||
/**
|
||||
* Version 26.1 - tiny takeover
|
||||
*/
|
||||
public static final MinecraftVersion v26_1 = new MinecraftVersion("26.1");
|
||||
|
||||
/**
|
||||
* Version 1.21.11 - mounts of mayhem
|
||||
*/
|
||||
public static final MinecraftVersion v1_21_11 = new MinecraftVersion("1.21.11");
|
||||
|
||||
/**
|
||||
* Version 1.21.10 - hotfix for 1.21.9
|
||||
*/
|
||||
public static final MinecraftVersion v1_21_10 = new MinecraftVersion("1.21.10");
|
||||
|
||||
/**
|
||||
* Version 1.21.9 - the copper age drop
|
||||
*/
|
||||
public static final MinecraftVersion v1_21_9 = new MinecraftVersion("1.21.9");
|
||||
|
||||
/**
|
||||
* Version 1.21.6 - chase the skies
|
||||
*/
|
||||
@@ -169,7 +194,7 @@ public final class MinecraftVersion implements Comparable<MinecraftVersion>, Ser
|
||||
/**
|
||||
* The latest release version of minecraft.
|
||||
*/
|
||||
public static final MinecraftVersion LATEST = v1_21_6;
|
||||
public static final MinecraftVersion LATEST = v26_2;
|
||||
|
||||
// used when serializing
|
||||
private static final long serialVersionUID = -8695133558996459770L;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
public record Tuple<A, B>(A first, B second) {}
|
||||
@@ -2,12 +2,14 @@ package com.comphenix.protocol.utility;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.ByteBufProcessor;
|
||||
import io.netty.util.ByteProcessor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.GatheringByteChannel;
|
||||
import java.nio.channels.ScatteringByteChannel;
|
||||
import java.nio.charset.Charset;
|
||||
@@ -54,6 +56,16 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf asReadOnly() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readerIndex() {
|
||||
return 0;
|
||||
@@ -179,36 +191,71 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShortLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedShort(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedShortLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMedium(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMediumLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedMedium(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnsignedMediumLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnsignedInt(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getUnsignedIntLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongLE(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getChar(int i) {
|
||||
return 0;
|
||||
@@ -264,6 +311,16 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBytes(int i, FileChannel fileChannel, long l, int i1) throws IOException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharSequence(int i, int i1, Charset charset) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setBoolean(int i, boolean b) {
|
||||
return null;
|
||||
@@ -279,21 +336,41 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setShortLE(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setMedium(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setMediumLE(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setInt(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setIntLE(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setLong(int i, long l) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setLongLE(int i, long l) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setChar(int i, int i1) {
|
||||
return null;
|
||||
@@ -349,11 +426,21 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setBytes(int i, FileChannel fileChannel, long l, int i1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf setZero(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int setCharSequence(int i, CharSequence charSequence, Charset charset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
return false;
|
||||
@@ -374,36 +461,71 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public short readShortLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedShort() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedShortLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readMedium() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readMediumLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedMedium() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedMediumLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readIntLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedInt() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readUnsignedIntLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLongLE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char readChar() {
|
||||
return 0;
|
||||
@@ -429,6 +551,11 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readRetainedSlice(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf readBytes(ByteBuf byteBuf) {
|
||||
return null;
|
||||
@@ -469,6 +596,16 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence readCharSequence(int i, Charset charset) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readBytes(FileChannel fileChannel, long l, int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf skipBytes(int i) {
|
||||
return null;
|
||||
@@ -489,21 +626,41 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeShortLE(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeMedium(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeMediumLE(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeInt(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeIntLE(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeLong(long l) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeLongLE(long l) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeChar(int i) {
|
||||
return null;
|
||||
@@ -559,11 +716,21 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeBytes(FileChannel fileChannel, long l, int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf writeZero(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int writeCharSequence(CharSequence charSequence, Charset charset) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int indexOf(int i, int i1, byte b) {
|
||||
return 0;
|
||||
@@ -585,22 +752,22 @@ public class ZeroBuffer extends ByteBuf {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(ByteBufProcessor byteBufProcessor) {
|
||||
public int forEachByte(ByteProcessor byteProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByte(int i, int i1, ByteBufProcessor byteBufProcessor) {
|
||||
public int forEachByte(int i, int i1, ByteProcessor byteProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(ByteBufProcessor byteBufProcessor) {
|
||||
public int forEachByteDesc(ByteProcessor byteProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachByteDesc(int i, int i1, ByteBufProcessor byteBufProcessor) {
|
||||
public int forEachByteDesc(int i, int i1, ByteProcessor byteProcessor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -619,16 +786,31 @@ public class ZeroBuffer extends ByteBuf {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retainedSlice() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf slice(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retainedSlice(int i, int i1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf duplicate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf retainedDuplicate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int nioBufferCount() {
|
||||
return 0;
|
||||
@@ -738,4 +920,14 @@ public class ZeroBuffer extends ByteBuf {
|
||||
public ByteBuf retain() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf touch() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuf touch(Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -70,6 +70,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldType;
|
||||
@@ -873,6 +874,13 @@ public class BukkitConverters {
|
||||
return ignoreNull(new EquivalentConverter<EntityType>() {
|
||||
@Override
|
||||
public Object getGeneric(EntityType specific) {
|
||||
if (MinecraftVersion.v26_2.atOrAbove()) {
|
||||
// EntityType.byString was removed in 26.2, resolve through the registry instead
|
||||
WrappedRegistry registry = WrappedRegistry.getRegistry(MinecraftReflection.getEntityTypes());
|
||||
NamespacedKey key = specific.getKey();
|
||||
return registry.get(new MinecraftKey(key.getNamespace(), key.getKey()));
|
||||
}
|
||||
|
||||
if (entityTypeFromName == null) {
|
||||
Class<?> entityTypesClass = MinecraftReflection.getEntityTypes();
|
||||
entityTypeFromName = Accessors.getMethodAccessor(
|
||||
@@ -1428,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,12 @@ public abstract class EnumWrappers {
|
||||
public enum ClientCommand {
|
||||
PERFORM_RESPAWN,
|
||||
REQUEST_STATS,
|
||||
REQUEST_GAMERULE_VALUES,
|
||||
|
||||
/**
|
||||
* @deprecated Removed in 26.1
|
||||
*/
|
||||
@Deprecated
|
||||
OPEN_INVENTORY_ACHIEVEMENT
|
||||
}
|
||||
|
||||
@@ -180,7 +186,8 @@ public abstract class EnumWrappers {
|
||||
DROP_ALL_ITEMS,
|
||||
DROP_ITEM,
|
||||
RELEASE_USE_ITEM,
|
||||
SWAP_HELD_ITEMS("SWAP_ITEM_WITH_OFFHAND");
|
||||
SWAP_HELD_ITEMS("SWAP_ITEM_WITH_OFFHAND"),
|
||||
STAB;
|
||||
|
||||
final String[] aliases;
|
||||
PlayerDigType(String... aliases) {
|
||||
@@ -717,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;
|
||||
@@ -745,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;
|
||||
@@ -805,7 +818,7 @@ public abstract class EnumWrappers {
|
||||
}
|
||||
|
||||
try {
|
||||
SOUND_CATEGORY_CLASS = MinecraftReflection.getMinecraftClass("sounds.SoundCategory");
|
||||
SOUND_CATEGORY_CLASS = MinecraftReflection.getMinecraftClass("sounds.SoundCategory", "sounds.SoundSource");
|
||||
} catch (Exception ex) {
|
||||
SOUND_CATEGORY_CLASS = getEnum(PacketType.Play.Server.NAMED_SOUND_EFFECT.getPacketClass(), 0);
|
||||
}
|
||||
@@ -821,13 +834,17 @@ public abstract class EnumWrappers {
|
||||
if (MinecraftVersion.CAVES_CLIFFS_1.atOrAbove()) {
|
||||
HAND_CLASS = MinecraftReflection.getMinecraftClass("world.EnumHand", "world.InteractionHand");
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getEnumEntityUseActionClass(), true);
|
||||
Method getType = fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(0)
|
||||
.returnTypeMatches(FuzzyMatchers.except(Void.class))
|
||||
.build());
|
||||
if (MinecraftVersion.v26_1.atOrAbove()) {
|
||||
// TODO
|
||||
} else {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getEnumEntityUseActionClass(), true);
|
||||
Method getType = fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterCount(0)
|
||||
.returnTypeMatches(FuzzyMatchers.except(Void.class))
|
||||
.build());
|
||||
|
||||
ENTITY_USE_ACTION_CLASS = getType.getReturnType();
|
||||
ENTITY_USE_ACTION_CLASS = getType.getReturnType();
|
||||
}
|
||||
} else {
|
||||
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
|
||||
ENTITY_USE_ACTION_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 0);
|
||||
@@ -863,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());
|
||||
@@ -890,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());
|
||||
@@ -1079,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);
|
||||
@@ -1188,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,29 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.mojang.authlib.properties.Property;
|
||||
import com.mojang.authlib.properties.PropertyMap;
|
||||
|
||||
/**
|
||||
* Mutable version of PropertyMap
|
||||
* Credit to PaperMC: https://github.com/PaperMC/Paper/blob/main/paper-server/src/main/java/io/papermc/paper/profile/MutablePropertyMap.java
|
||||
*/
|
||||
public class MutablePropertyMap extends PropertyMap {
|
||||
private final Multimap<String, Property> properties = HashMultimap.create();
|
||||
|
||||
public MutablePropertyMap() {
|
||||
super(ImmutableMultimap.of());
|
||||
}
|
||||
|
||||
public MutablePropertyMap(final Multimap<String, Property> properties) {
|
||||
this();
|
||||
this.putAll(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Multimap<String, Property> delegate() {
|
||||
return this.properties;
|
||||
}
|
||||
}
|
||||
@@ -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 + "}";
|
||||
}
|
||||
}
|
||||
@@ -35,18 +35,30 @@ public class WrappedGameProfile extends AbstractWrapper {
|
||||
GAME_PROFILE, String.class, String.class);
|
||||
private static final ConstructorAccessor CREATE_UUID_STRING = Accessors.getConstructorAccessorOrNull(
|
||||
GAME_PROFILE, UUID.class, String.class);
|
||||
private static final ConstructorAccessor CREATE_UUID_STRING_PROPERTIES = Accessors.getConstructorAccessorOrNull(
|
||||
GAME_PROFILE, UUID.class, String.class, MinecraftReflection.getGameProfilePropertyMapClass());
|
||||
|
||||
private static final FieldAccessor GET_UUID_STRING = Accessors.getFieldAccessorOrNull(
|
||||
GAME_PROFILE, "id", String.class);
|
||||
|
||||
private static final MethodAccessor GET_ID = Accessors.getMethodAccessorOrNull(
|
||||
GAME_PROFILE, "getId");
|
||||
private static final MethodAccessor GET_NAME = Accessors.getMethodAccessorOrNull(
|
||||
GAME_PROFILE, "getName");
|
||||
private static final MethodAccessor GET_PROPERTIES = Accessors.getMethodAccessorOrNull(
|
||||
GAME_PROFILE, "getProperties");
|
||||
private static final MethodAccessor IS_COMPLETE = Accessors.getMethodAccessorOrNull(
|
||||
GAME_PROFILE, "isComplete");
|
||||
private static MethodAccessor GET_ID;
|
||||
private static MethodAccessor GET_NAME;
|
||||
private static MethodAccessor GET_PROPERTIES;
|
||||
private static MethodAccessor IS_COMPLETE;
|
||||
|
||||
static {
|
||||
GET_ID = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "getId");
|
||||
if (GET_ID == null) {
|
||||
GET_ID = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "id");
|
||||
GET_NAME = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "name");
|
||||
GET_PROPERTIES = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "properties");
|
||||
IS_COMPLETE = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "complete");
|
||||
} else {
|
||||
GET_NAME = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "getName");
|
||||
GET_PROPERTIES = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "getProperties");
|
||||
IS_COMPLETE = Accessors.getMethodAccessorOrNull(GAME_PROFILE, "isComplete");
|
||||
}
|
||||
}
|
||||
|
||||
// Fetching game profile
|
||||
private static FieldAccessor PLAYER_PROFILE;
|
||||
@@ -117,6 +129,51 @@ public class WrappedGameProfile extends AbstractWrapper {
|
||||
this(parseUUID(id), name);
|
||||
}
|
||||
|
||||
private static Object createHandle(UUID uuid, String name, Multimap<String, WrappedSignedProperty> properties) {
|
||||
if (CREATE_STRING_STRING != null) {
|
||||
return CREATE_STRING_STRING.invoke(uuid != null ? uuid.toString() : null, name);
|
||||
}
|
||||
|
||||
if (CREATE_UUID_STRING == null) {
|
||||
throw new IllegalArgumentException("Unsupported GameProfile constructor.");
|
||||
}
|
||||
|
||||
if (!MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
|
||||
return CREATE_UUID_STRING.invoke(uuid, name);
|
||||
}
|
||||
|
||||
// 1.20.2+ requires all fields to have a value: null uuid -> UUID(0,0), null name -> empty name
|
||||
// it's not allowed to pass null for both, so we need to pre-check that
|
||||
if (uuid == null && (name == null || name.isEmpty())) {
|
||||
throw new IllegalArgumentException("Name and ID cannot both be blank");
|
||||
}
|
||||
|
||||
// 1.21.9+ made PropertyMap's underlying map immutable, so we need to override it with a mutable map
|
||||
if (MinecraftVersion.v1_21_9.atOrAbove()) {
|
||||
return CREATE_UUID_STRING_PROPERTIES.invoke(uuid == null ? MinecraftGenerator.SYS_UUID : uuid, name == null ? "" : name,
|
||||
convertPropertyMap(properties));
|
||||
}
|
||||
|
||||
return CREATE_UUID_STRING.invoke(uuid == null ? MinecraftGenerator.SYS_UUID : uuid, name == null ? "" : name);
|
||||
}
|
||||
|
||||
private static Object convertPropertyMap(Multimap<String, WrappedSignedProperty> properties) {
|
||||
com.comphenix.protocol.wrappers.MutablePropertyMap map =
|
||||
new com.comphenix.protocol.wrappers.MutablePropertyMap();
|
||||
|
||||
if (properties == null || properties.isEmpty()) {
|
||||
return map;
|
||||
}
|
||||
|
||||
for (String key : properties.keySet()) {
|
||||
for (WrappedSignedProperty property : properties.get(key)) {
|
||||
map.put(key, (com.mojang.authlib.properties.Property) property.getHandle());
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new game profile with the given properties.
|
||||
* <p>
|
||||
@@ -127,24 +184,12 @@ public class WrappedGameProfile extends AbstractWrapper {
|
||||
*/
|
||||
public WrappedGameProfile(UUID uuid, String name) {
|
||||
super(GAME_PROFILE);
|
||||
setHandle(createHandle(uuid, name, null));
|
||||
}
|
||||
|
||||
if (CREATE_STRING_STRING != null) {
|
||||
setHandle(CREATE_STRING_STRING.invoke(uuid != null ? uuid.toString() : null, name));
|
||||
} else if (CREATE_UUID_STRING != null) {
|
||||
if (MinecraftVersion.CONFIG_PHASE_PROTOCOL_UPDATE.atOrAbove()) {
|
||||
// 1.20.2+ requires all fields to have a value: null uuid -> UUID(0,0), null name -> empty name
|
||||
// it's not allowed to pass null for both, so we need to pre-check that
|
||||
if (uuid == null && (name == null || name.isEmpty())) {
|
||||
throw new IllegalArgumentException("Name and ID cannot both be blank");
|
||||
}
|
||||
|
||||
setHandle(CREATE_UUID_STRING.invoke(uuid == null ? MinecraftGenerator.SYS_UUID : uuid, name == null ? "" : name));
|
||||
} else {
|
||||
setHandle(CREATE_UUID_STRING.invoke(uuid, name));
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported GameProfile constructor.");
|
||||
}
|
||||
public WrappedGameProfile(UUID uuid, String name, Multimap<String, WrappedSignedProperty> properties) {
|
||||
super(GAME_PROFILE);
|
||||
setHandle(createHandle(uuid, name, properties));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -157,7 +202,12 @@ public class WrappedGameProfile extends AbstractWrapper {
|
||||
if (handle == null)
|
||||
return null;
|
||||
|
||||
return new WrappedGameProfile(handle);
|
||||
WrappedGameProfile delegate = new WrappedGameProfile(handle);
|
||||
if (MinecraftVersion.v1_21_9.atOrAbove()) {
|
||||
return new WrappedGameProfile(delegate.getUUID(), delegate.getName(), delegate.getProperties());
|
||||
} else {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +319,15 @@ public class WrappedGameProfile extends AbstractWrapper {
|
||||
|
||||
if (result == null) {
|
||||
Multimap properties = (Multimap) GET_PROPERTIES.invoke(handle);
|
||||
result = new ConvertedMultimap<String, Object, WrappedSignedProperty>(GuavaWrappers.getBukkitMultimap(properties)) {
|
||||
|
||||
Multimap inner;
|
||||
if (MinecraftVersion.v1_21_9.atOrAbove()) {
|
||||
inner = properties;
|
||||
} else {
|
||||
inner = GuavaWrappers.getBukkitMultimap(properties);
|
||||
}
|
||||
|
||||
result = new ConvertedMultimap<String, Object, WrappedSignedProperty>(inner) {
|
||||
@Override
|
||||
protected Object toInner(WrappedSignedProperty outer) {
|
||||
return outer.handle;
|
||||
|
||||
@@ -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
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
/**
|
||||
* Wrapper around the NMS {@code PositionMoveRotation} record, introduced in Minecraft 1.21.2.
|
||||
* <p>
|
||||
* This type is used in packets such as {@code ENTITY_TELEPORT} and {@code ENTITY_POSITION_SYNC}
|
||||
* to represent combined position, movement delta and rotation.
|
||||
* <p>
|
||||
* Example usage:
|
||||
* <pre>{@code
|
||||
* WrappedPositionMoveRotation posRot = WrappedPositionMoveRotation.create(
|
||||
* new Vector(x, y, z), // position
|
||||
* new Vector(0, 0, 0), // deltaMovement
|
||||
* yaw, // yRot
|
||||
* pitch // xRot
|
||||
* );
|
||||
* packet.getPositionMoveRotation().write(0, posRot);
|
||||
* }</pre>
|
||||
*/
|
||||
public class WrappedPositionMoveRotation extends AbstractWrapper {
|
||||
|
||||
private static Class<?> NMS_CLASS;
|
||||
private static ConstructorAccessor CONSTRUCTOR;
|
||||
private static StructureModifier<Object> BASE_MODIFIER;
|
||||
|
||||
private final StructureModifier<Object> modifier;
|
||||
|
||||
private WrappedPositionMoveRotation(Object handle) {
|
||||
super(getNmsClass());
|
||||
setHandle(handle);
|
||||
this.modifier = getBaseModifier().withTarget(handle);
|
||||
}
|
||||
|
||||
private static Class<?> getNmsClass() {
|
||||
if (NMS_CLASS == null) {
|
||||
NMS_CLASS = MinecraftReflection.getPositionMoveRotationClass();
|
||||
}
|
||||
return NMS_CLASS;
|
||||
}
|
||||
|
||||
private static StructureModifier<Object> getBaseModifier() {
|
||||
if (BASE_MODIFIER == null) {
|
||||
BASE_MODIFIER = new StructureModifier<>(getNmsClass());
|
||||
}
|
||||
return BASE_MODIFIER;
|
||||
}
|
||||
|
||||
private static ConstructorAccessor getConstructor() {
|
||||
if (CONSTRUCTOR == null) {
|
||||
CONSTRUCTOR = Accessors.getConstructorAccessor(
|
||||
getNmsClass(),
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
float.class,
|
||||
float.class
|
||||
);
|
||||
}
|
||||
return CONSTRUCTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code WrappedPositionMoveRotation} from the given NMS handle.
|
||||
*
|
||||
* @param handle - the NMS {@code PositionMoveRotation} instance.
|
||||
* @return the wrapper.
|
||||
*/
|
||||
public static WrappedPositionMoveRotation fromHandle(Object handle) {
|
||||
return new WrappedPositionMoveRotation(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code WrappedPositionMoveRotation} with the given values.
|
||||
*
|
||||
* @param position - the absolute position.
|
||||
* @param deltaMovement - the movement delta (velocity).
|
||||
* @param yRot - the yaw rotation.
|
||||
* @param xRot - the pitch rotation.
|
||||
* @return a new wrapper instance.
|
||||
*/
|
||||
public static WrappedPositionMoveRotation create(Vector position, Vector deltaMovement, float yRot, float xRot) {
|
||||
EquivalentConverter<Vector> conv = BukkitConverters.getVectorConverter();
|
||||
Object handle = getConstructor().invoke(
|
||||
conv.getGeneric(position),
|
||||
conv.getGeneric(deltaMovement),
|
||||
yRot,
|
||||
xRot
|
||||
);
|
||||
return new WrappedPositionMoveRotation(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the absolute position component.
|
||||
*
|
||||
* @return the position as a Bukkit {@link Vector}.
|
||||
*/
|
||||
public Vector getPosition() {
|
||||
return modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the absolute position component.
|
||||
*
|
||||
* @param position - the new position.
|
||||
*/
|
||||
public void setPosition(Vector position) {
|
||||
modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).write(0, position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the movement delta (velocity) component.
|
||||
*
|
||||
* @return the delta movement as a Bukkit {@link Vector}.
|
||||
*/
|
||||
public Vector getDeltaMovement() {
|
||||
return modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).read(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the movement delta (velocity) component.
|
||||
*
|
||||
* @param deltaMovement - the new delta movement.
|
||||
*/
|
||||
public void setDeltaMovement(Vector deltaMovement) {
|
||||
modifier.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter()).write(1, deltaMovement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the yaw rotation (y-axis rotation).
|
||||
*
|
||||
* @return the yaw as a float.
|
||||
*/
|
||||
public float getYRot() {
|
||||
StructureModifier<Float> floats = modifier.withType(float.class);
|
||||
return floats.read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the yaw rotation (y-axis rotation).
|
||||
*
|
||||
* @param yRot - the new yaw value.
|
||||
*/
|
||||
public void setYRot(float yRot) {
|
||||
modifier.withType(float.class).write(0, yRot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the pitch rotation (x-axis rotation).
|
||||
*
|
||||
* @return the pitch as a float.
|
||||
*/
|
||||
public float getXRot() {
|
||||
StructureModifier<Float> floats = modifier.withType(float.class);
|
||||
return floats.read(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pitch rotation (x-axis rotation).
|
||||
*
|
||||
* @param xRot - the new pitch value.
|
||||
*/
|
||||
public void setXRot(float xRot) {
|
||||
modifier.withType(float.class).write(1, xRot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an {@link EquivalentConverter} that converts between {@code WrappedPositionMoveRotation}
|
||||
* and the underlying NMS handle.
|
||||
*
|
||||
* @return the converter.
|
||||
*/
|
||||
public static EquivalentConverter<WrappedPositionMoveRotation> getConverter() {
|
||||
return Converters.handle(AbstractWrapper::getHandle,
|
||||
WrappedPositionMoveRotation::fromHandle, WrappedPositionMoveRotation.class);
|
||||
}
|
||||
}
|
||||
@@ -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 + '}';
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package com.comphenix.protocol.wrappers;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
@@ -90,12 +92,26 @@ public class WrappedTeamParameters extends AbstractWrapper {
|
||||
|
||||
@NotNull
|
||||
public EnumWrappers.ChatFormatting getColor() {
|
||||
if (MinecraftVersion.v26_2.atOrAbove()) {
|
||||
Optional<?> optional = modifier.<Optional<?>>withType(Optional.class).read(0);
|
||||
Object teamColor = optional != null ? optional.orElse(null) : null;
|
||||
if (teamColor == null) {
|
||||
return EnumWrappers.ChatFormatting.RESET;
|
||||
}
|
||||
|
||||
return EnumWrappers.ChatFormatting.valueOf(((Enum<?>) teamColor).name());
|
||||
}
|
||||
|
||||
return modifier
|
||||
.withType(EnumWrappers.getChatFormattingClass(), EnumWrappers.getChatFormattingConverter())
|
||||
.read(0);
|
||||
}
|
||||
|
||||
public int getOptions() {
|
||||
if (MinecraftVersion.v26_2.atOrAbove()) {
|
||||
return (byte) modifier.withType(byte.class).read(0);
|
||||
}
|
||||
|
||||
return (int) modifier.withType(int.class).read(0);
|
||||
}
|
||||
|
||||
@@ -210,9 +226,27 @@ public class WrappedTeamParameters extends AbstractWrapper {
|
||||
wrapped.modifier.withType(String.class).writeSafely(1, collisionRule.toString());
|
||||
}
|
||||
|
||||
wrapped.modifier.withType(EnumWrappers.getChatFormattingClass()).write(0, EnumWrappers.getChatFormattingConverter().getGeneric(color));
|
||||
wrapped.modifier.withType(int.class).write(0, options);
|
||||
if (MinecraftVersion.v26_2.atOrAbove()) {
|
||||
wrapped.modifier.withType(Optional.class).write(0, Optional.ofNullable(toNmsTeamColor(color)));
|
||||
wrapped.modifier.withType(byte.class).write(0, (byte) options);
|
||||
} else {
|
||||
wrapped.modifier.withType(EnumWrappers.getChatFormattingClass()).write(0, EnumWrappers.getChatFormattingConverter().getGeneric(color));
|
||||
wrapped.modifier.withType(int.class).write(0, options);
|
||||
}
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static Object toNmsTeamColor(EnumWrappers.ChatFormatting color) {
|
||||
Class<?> teamColorClass = MinecraftReflection.getTeamColorClass()
|
||||
.orElseThrow(() -> new IllegalStateException("TeamColor class doesn't exist on this server version"));
|
||||
|
||||
try {
|
||||
return Enum.valueOf((Class) teamColorClass, color.name());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// formatting-only values (e.g. RESET) don't map to a team color
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder;
|
||||
import java.util.Base64;
|
||||
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
@@ -23,7 +22,7 @@ public class NbtTextSerializer {
|
||||
* A default instance of this serializer.
|
||||
*/
|
||||
public static final NbtTextSerializer DEFAULT = new NbtTextSerializer();
|
||||
|
||||
|
||||
private NbtBinarySerializer binarySerializer;
|
||||
|
||||
public NbtTextSerializer() {
|
||||
@@ -59,7 +58,7 @@ public class NbtTextSerializer {
|
||||
binarySerializer.serialize(value, dataOutput);
|
||||
|
||||
// Serialize that array
|
||||
return Base64Coder.encodeLines(outputStream.toByteArray());
|
||||
return Base64.getEncoder().encodeToString(outputStream.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,7 +69,7 @@ public class NbtTextSerializer {
|
||||
* @throws IOException If we are unable to parse the input.
|
||||
*/
|
||||
public <TType> NbtWrapper<TType> deserialize(String input) throws IOException {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(input));
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.getDecoder().decode(input));
|
||||
|
||||
return binarySerializer.deserialize(new DataInputStream(inputStream));
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ 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.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.MinecraftGenerator;
|
||||
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
@@ -23,6 +25,7 @@ public final class ServerPingRecord implements ServerPingImpl {
|
||||
private static Class<?> SERVER_PING;
|
||||
private static Class<?> PLAYER_SAMPLE_CLASS;
|
||||
private static Class<?> SERVER_DATA_CLASS;
|
||||
private static Class<?> NAME_AND_ID_CLASS;
|
||||
|
||||
private static Class<?> GSON_CLASS;
|
||||
private static MethodAccessor GSON_TO_JSON;
|
||||
@@ -56,13 +59,37 @@ public final class ServerPingRecord implements ServerPingImpl {
|
||||
PLAYER_SAMPLE_CLASS = MinecraftReflection.getServerPingPlayerSampleClass();
|
||||
SERVER_DATA_CLASS = MinecraftReflection.getServerPingServerDataClass();
|
||||
|
||||
PING_CTOR = Accessors.getConstructorAccessor(SERVER_PING.getConstructors()[0]);
|
||||
PING_CTOR = Accessors.getConstructorAccessor(SERVER_PING, MinecraftReflection.getIChatBaseComponentClass(), Optional.class, Optional.class, Optional.class, boolean.class);
|
||||
|
||||
DATA_WRAPPER = AutoWrapper.wrap(ServerData.class, SERVER_DATA_CLASS);
|
||||
SAMPLE_WRAPPER = AutoWrapper.wrap(PlayerSample.class, PLAYER_SAMPLE_CLASS);
|
||||
FAVICON_WRAPPER = AutoWrapper.wrap(Favicon.class, MinecraftReflection.getMinecraftClass("network.protocol.status.ServerPing$a", "network.protocol.status.ServerStatus$Favicon"));
|
||||
|
||||
PROFILE_LIST_CONVERTER = BukkitConverters.getListConverter(BukkitConverters.getWrappedGameProfileConverter());
|
||||
if (MinecraftVersion.v1_21_10.atOrAbove()) {
|
||||
NAME_AND_ID_CLASS = MinecraftReflection.getMinecraftClass("server.players.NameAndId");
|
||||
NAME_AND_ID_WRAPPER = AutoWrapper.wrap(NameAndId.class, NAME_AND_ID_CLASS);
|
||||
|
||||
PROFILE_LIST_CONVERTER = BukkitConverters.getListConverter(new EquivalentConverter<>() {
|
||||
@Override
|
||||
public Object getGeneric(WrappedGameProfile specific) {
|
||||
NameAndId wrapper = new NameAndId(specific.getUUID(), specific.getName());
|
||||
return NAME_AND_ID_WRAPPER.getGeneric(wrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedGameProfile getSpecific(Object generic) {
|
||||
NameAndId wrapper = NAME_AND_ID_WRAPPER.getSpecific(generic);
|
||||
return new WrappedGameProfile(wrapper.id, wrapper.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedGameProfile> getSpecificType() {
|
||||
return WrappedGameProfile.class;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
PROFILE_LIST_CONVERTER = BukkitConverters.getListConverter(BukkitConverters.getWrappedGameProfileConverter());
|
||||
}
|
||||
|
||||
DEFAULT_DESCRIPTION = WrappedChatComponent.fromLegacyText("A Minecraft Server");
|
||||
|
||||
@@ -124,11 +151,24 @@ public final class ServerPingRecord implements ServerPingImpl {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NameAndId {
|
||||
public UUID id;
|
||||
public String name;
|
||||
|
||||
public NameAndId(UUID id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public NameAndId() {
|
||||
this(MinecraftGenerator.SYS_UUID, "");
|
||||
}
|
||||
}
|
||||
|
||||
private static AutoWrapper<PlayerSample> SAMPLE_WRAPPER;
|
||||
|
||||
private static AutoWrapper<ServerData> DATA_WRAPPER;
|
||||
|
||||
private static AutoWrapper<Favicon> FAVICON_WRAPPER;
|
||||
private static AutoWrapper<NameAndId> NAME_AND_ID_WRAPPER;
|
||||
|
||||
private WrappedChatComponent description;
|
||||
private PlayerSample playerSample;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 556 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user