{"id":29674014,"url":"https://github.com/nlr-devteam/payloadlib","last_synced_at":"2025-07-22T22:39:38.839Z","repository":{"id":304141825,"uuid":"1017737847","full_name":"NLR-DevTeam/PayloadLib","owner":"NLR-DevTeam","description":"Easier approach for Bukkit to send \u0026 handle custom payloads, simple \u0026 powerful.","archived":false,"fork":false,"pushed_at":"2025-07-11T09:26:36.000Z","size":58,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-11T12:33:51.971Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NLR-DevTeam.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-11T02:58:58.000Z","updated_at":"2025-07-11T09:26:39.000Z","dependencies_parsed_at":"2025-07-11T12:33:55.533Z","dependency_job_id":"99b19327-d49a-4524-ad24-c307774a0fa0","html_url":"https://github.com/NLR-DevTeam/PayloadLib","commit_stats":null,"previous_names":["nlr-devteam/payloadlib"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/NLR-DevTeam/PayloadLib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NLR-DevTeam%2FPayloadLib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NLR-DevTeam%2FPayloadLib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NLR-DevTeam%2FPayloadLib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NLR-DevTeam%2FPayloadLib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NLR-DevTeam","download_url":"https://codeload.github.com/NLR-DevTeam/PayloadLib/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NLR-DevTeam%2FPayloadLib/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266586572,"owners_count":23952173,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-07-22T22:39:37.921Z","updated_at":"2025-07-22T22:39:38.830Z","avatar_url":"https://github.com/NLR-DevTeam.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PayloadLib\n\nEasier approach for **Paper** servers to send \u0026 handle custom payloads, simple \u0026 powerful.\n\nWe support a wide range of types, please see [Supported Data Types](#supported-data-types).\n\n| [Supported Versions](#supported-versions) | [Basic Usage](#usage) | [Advanced Usage](#advanced-usage) | [Examples](#examples) |\n\n\u003e [!WARNING]\n\u003e CraftBukkit and Spigot servers are not supported, and this plugin is likely to crash when running on them.\n\n## Importing\n\n\u003e [!NOTE]\n\u003e PayloadLib hasn't been published to the maven central yet, but you can use the snapshot repository.\n\nTo access the snapshot version of PayloadLib, please add this in your `build.gradle`:\n\n```groovy\nrepositories {\n  maven {\n    name = 'Central Portal Snapshots'\n    url = 'https://central.sonatype.com/repository/maven-snapshots/'\n  }\n}\n\ndependencies {\n    implementation 'top.nlrdev:payloadlib:0.0.2-SNAPSHOT'\n\n    // Optional dependency, providing ByteBuf\n    implementation 'io.netty:netty-buffer:4.2.2.Final'\n}\n```\n\n\u003c!--\nPlease add this in your `build.gradle` (remember to replace `\u003cVERSION\u003e` with the latest release):\n\n```groovy\ndependencies {\n    // ...\n    implementation 'top.nlrdev:payloadlib:\u003cVERSION\u003e'\n}\n```\n--\u003e\n\nEmbedding this plugin within other plugin JARs is not recommended, as it can lead to various issues.\n\n## Supported Versions\n\nBukkit's API has an annoying limit, so we use NMS to send payloads directly.\n\nPlease notice that we do only support recent versions of Minecraft (excluding some versions that nobody cares).\n\n| NMS Target | Compatible With            |\n| ---------- | -------------------------- |\n| 1.21.4     | 1.21.4, _1.21.5_, _1.21.7_ |\n| 1.21.1     | _1.21_, 1.21.1             |\n| 1.20.6     | _1.20.5_, 1.20.6           |\n| 1.20.4     | _1.20.3_, 1.20.4           |\n| 1.20.1     | _1.20_, 1.20.1             |\n\nNote: _Italic_ means the version is **not fully tested**, but **may** be usable.\n\n## Usage\n\nFirst, add `PayloadLib` in the `plugin.yml` as an dependency:\n\n```yml\n# ...\ndepend: [PayloadLib]\n```\n\nThen, declare your payload like this:\n\n```java\nimport top.nlrdev.payloadlib.Payload;\nimport top.nlrdev.payloadlib.types.Identifier;\n\npublic record MyPayload(int id, String data) implements Payload {\n    public static final Identifier ID = Identifier.of(\"namespace\", \"path\");\n    // Or: public static final Identifier ID = Identifier.parse(\"namespace:path\");\n\n    @Override\n    public Identifier getId() {\n        return ID;\n    }\n}\n```\n\nNext, register your packets as follows:\n\n\u003e [!NOTE]\n\u003e Both C2S (Serverbound) and S2C (Clientbound) payloads must be registered for serialization.\n\n```java\nimport top.nlrdev.payloadlib.PayloadLib;\n\n// In your JavaPlugin implementation\n@Override\npublic void onEnable() {\n    // ...\n    PayloadLib.registerPayload(MyPayload.ID, MyPayload.class);\n}\n```\n\nIf this is a C2S (Serverbound) payload, you can register a handler like this:\n\n```java\nPayloadLib.\u003cMyPayload\u003eregisterGlobalReceiver(MyPayload.ID, (/* Bukkit Player */ sender, /* MyPayload */ payload) -\u003e {\n    sender.sendMessage(\"ID: %s, Data: %s\".formatted(payload.id(), payload.data()));\n});\n```\n\nElse, if this is a S2C (Clientbound) payload, you can send it in two methods:\n\n```java\nPayload payload = new MyPayload(1234, \"some-data\");\npayload.sendTo(player1, player2, player3, ...);\n\n// Or\nPayloadLib.sendPayload(payload, player1, player2, player3, ...);\n```\n\n## Supported Data Types\n\n\u003e [!NOTE]\n\u003e We only support types with a `PacketCodec` in vanilla Minecraft.\n\nPlease refer to [SerializationImpl.java](/core/src/main/java/top/nlrdev/payloadlib/serialization/SerializationImpl.java) for more details.\n\n### Primitive\n\n| Primitive | Packaged  | Array         | Unsigned Implementation                     |\n| --------- | --------- | ------------- | ------------------------------------------- |\n| boolean   | Boolean   | _Unsupported_ | _None_                                      |\n| byte      | Byte      | byte[]        | _None_                                      |\n| short     | Short     | _Unsupported_ | `top.nlrdev.payloadlib.types.UnsignedShort` |\n| char      | Character | _Unsupported_ | _None_                                      |\n| int       | Integer   | _Unsupported_ | _None_                                      |\n| long      | Long      | _Unsupported_ | _None_                                      |\n| float     | Float     | _Unsupported_ | _None_                                      |\n| double    | Double    | _Unsupported_ | _None_                                      |\n\n### Non-Primitive\n\n| Type                   | PayloadLib  |\n| ---------------------- | ----------- |\n| String                 | _Unchanged_ |\n| UUID                   | _Unchanged_ |\n| `org.joml.Vector3f`    | _Unchanged_ |\n| `org.joml.Quaternionf` | _Unchanged_ |\n\n| Minecraft (Official)                       | Minecraft (Yarn)                    | PayloadLib                               |\n| ------------------------------------------ | ----------------------------------- | ---------------------------------------- |\n| `net.minecraft.resources.ResourceLocation` | `net.minecraft.util.Identifier`     | `top.nlrdev.payloadlib.types.Identifier` |\n| `ByteBufCodecs#VAR_INT`                    | `PacketCodecs#VAR_INT`              | `top.nlrdev.payloadlib.types.VarInt`     |\n| `ByteBufCodecs#VAR_LONG`                   | `PacketCodecs#VAR_LONG`             | `top.nlrdev.payloadlib.types.VarLong`    |\n| `net.minecraft.world.phys.Vec3`            | `net.minecraft.util.math.Vec3d`     | `org.joml.Vector3d`                      |\n| `net.minecraft.core.BlockPos`              | `net.minecraft.util.math.BlockPos`  | `top.nlrdev.payloadlib.types.BlockPos`   |\n| `net.minecraft.core.GlobalPos`             | `net.minecraft.util.math.GlobalPos` | `org.bukkit.Location`                    |\n\n\u003e [!TIP]\n\u003e Mojang's `RegistryKey\u003cT\u003e` (or `ResourceKey\u003cT\u003e` in official mappings) sends only its value in the registry to the server, which means:\n\u003e\n\u003e - It is impossible to read the registry root\n\u003e - You should use `Identifier` for serialization\n\n\u003e [!NOTE]\n\u003e When the world provided in `GlobalPos` can't be found, the deserializer will simply return `null`.\n\u003e\n\u003e Besides, `GlobalPos` can only save block positions, so there's a precision loss, and the deserialized `yaw`, `pitch` will always be zero.\n\n## Advanced Usage\n\n### Handling ByteBuf Directly\n\nThere's a high-level API called `registerRawReceiver`, here's its usage:\n\n```java\nimport top.nlrdev.payloadlib.encoding.StringEncoding;\n\nPayloadLib.registerRawReceiver(MyPayload.ID, (/* Bukkit Player */ sender, /* ByteBuf */ buf) -\u003e {\n    int id = buf.readInt();\n    String data = StringEncoding.decode(buf, /* Max Length */ 65535);\n\n    sender.sendMessage(\"ID: %s, Data: %s\".formatted(id, data));\n});\n```\n\n### Declaring Custom (De)Serializer\n\n\u003e [!WARNING]\n\u003e This is a dangerous operation, if your requirement is quite simple, please refer to [Registering Custom Data Type](#registering-custom-data-type).\n\nYou need to use annotations to implement custom serializer / deserialzer, here's an example.\n\nThe type is a Bukkit Player, and we will use its UUID for serialization.\n\n```java\nimport io.netty.Buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport top.nlrdev.payloadlib.Payload;\nimport top.nlrdev.payloadlib.types.Identifier;\nimport top.nlrdev.payloadlib.serialization.PayloadSerializer;\nimport top.nlrdev.payloadlib.serialization.PayloadDeserializer;\nimport top.nlrdev.payloadlib.serialization.SerializationImpl;\n\nimport java.util.UUID;\n\npublic record MyPayloadTwo(Player player) implements Payload {\n    public static final Identifier ID = Identifier.of(\"namespace\", \"path\");\n\n    @Override\n    public Identifier getId() {\n        return ID;\n    }\n\n    @PayloadSerializer\n    public static ByteBuf serialize(MyPayloadTwo instance) {\n        ByteBuf buf = Unpooled.buffer();\n        SerializationImpl.getInternalSerializer(UUID.class).accept(buf, instance.player.getUniqueId());\n        return buf;\n    }\n\n    @PayloadDeserializer\n    public static MyPayloadTwo deserialize(ByteBuf buf) {\n        UUID uuid = SerializationImpl.getInternalDeserializer(UUID.class).apply(buf);\n        Player player = Bukkit.getPlayer(uuid);\n        assert player != null;\n\n        return new MyPayloadTwo(player);\n    }\n}\n```\n\n### Registering Custom Data Type\n\nOverwriting the (de)serializer is dangerous, and registering custom data type is more convenient. Here's an instance:\n\n```java\nimport org.bukkit.Bukkit;\nimport org.bukkit.entity.Player;\nimport top.nlrdev.payloadlib.serialization.SerializationImpl;\n\nimport java.util.UUID;\n\nSerializationImpl.registerType(\n    Player.class,\n    /* Serializer */ (/* ByteBuf */ buf, player) -\u003e SerializationImpl.getInternalSerializer(UUID.class).accept(buf, player.getUniqueId()),\n    /* Deserializer */ buf -\u003e {\n        UUID uuid = SerializationImpl.getInternalDeserializer(UUID.class).apply(buf);\n        return Bukkit.getPlayer(uuid);\n    }\n);\n```\n\n## Building\n\nThanks to paperweight-userdev, building this plugin will cost a lot of RAM. You need about `8 GiB` of free RAM to complete the whole compiling process.\n\nTo build, run:\n\n```shell\n./gradlew build --no-daemon\n```\n\nAnd you'll see the plugin JAR inside the folder `build/libs`.\n\n## Examples\n\nYou can refer to these live examples to get inspiration:\n\n- [XIAYM-gh/SittingPlus-uwu-Bukkit](https://github.com/XIAYM-gh/SittingPlus-uwu-Bukkit)\n\n## Contributing\n\nWe welcome your contributions!\n\nPlease feel free to open an Issue or a Pull Request.\n\n## License\n\nThis mod is licensed under [MIT License](/LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnlr-devteam%2Fpayloadlib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnlr-devteam%2Fpayloadlib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnlr-devteam%2Fpayloadlib/lists"}