{"id":48202975,"url":"https://github.com/saicone/rtag","last_synced_at":"2026-04-04T18:29:18.531Z","repository":{"id":123210363,"uuid":"450954125","full_name":"saicone/rtag","owner":"saicone","description":"A Bukkit library to read/edit/write NBT objects as if they were known objects","archived":false,"fork":false,"pushed_at":"2026-03-25T01:02:54.000Z","size":1444,"stargazers_count":54,"open_issues_count":2,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-26T05:08:55.417Z","etag":null,"topics":["api","bukkit","library","minecraft","nbt","nms","paper","spigot"],"latest_commit_sha":null,"homepage":"https://docs.saicone.com/rtag","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/saicone.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"Rubenicos"}},"created_at":"2022-01-22T22:50:21.000Z","updated_at":"2026-03-25T01:02:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"df185028-fd6e-412d-98dd-318de5117dc6","html_url":"https://github.com/saicone/rtag","commit_stats":null,"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"purl":"pkg:github/saicone/rtag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saicone%2Frtag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saicone%2Frtag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saicone%2Frtag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saicone%2Frtag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saicone","download_url":"https://codeload.github.com/saicone/rtag/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saicone%2Frtag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31408594,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["api","bukkit","library","minecraft","nbt","nms","paper","spigot"],"created_at":"2026-04-04T18:29:16.205Z","updated_at":"2026-04-04T18:29:18.510Z","avatar_url":"https://github.com/saicone.png","language":"Java","funding_links":["https://github.com/sponsors/Rubenicos"],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eRtag\u003c/h1\u003e\n\n\u003ch4 align=\"center\"\u003eThe \"readable tag\" library, an easy way to handle minecraft data.\u003c/h4\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://saic.one/discord\"\u003e\n        \u003cimg src=\"https://img.shields.io/discord/974288218839191612.svg?style=flat-square\u0026label=discord\u0026logo=discord\u0026logoColor=white\u0026color=7289da\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://www.codefactor.io/repository/github/saicone/rtag\"\u003e\n        \u003cimg src=\"https://www.codefactor.io/repository/github/saicone/rtag/badge?style=flat-square\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/saicone/rtag\"\u003e\n        \u003cimg src=\"https://img.shields.io/github/languages/code-size/saicone/rtag?logo=github\u0026logoColor=white\u0026style=flat-square\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://jitpack.io/#com.saicone/rtag\"\u003e\n        \u003cimg src=\"https://jitpack.io/v/com.saicone/rtag.svg?style=flat-square\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://javadoc.saicone.com/rtag/\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/JavaDoc-Online-green?style=flat-square\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://docs.saicone.com/rtag/\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Saicone-Rtag%20Wiki-3b3bb0?logo=github\u0026logoColor=white\u0026style=flat-square\"/\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nRtag convert NBT tags to known objects and viceversa for better readability.\n\n```java\n// Using Item\nRtagItem tag = new RtagItem(item);\n// Using Entity\nRtagEntity tag = new RtagEntity(entity);\n// Using block\nRtagBlock tag = new RtagBlock(block);\n\n\n// --- Put values\n// Set the value \"Custom Text\" at \"display.Name\" path\ntag.set(\"Custom Text\", \"display\", \"Name\");\n// Or set an integer at \"someKey\" path\ntag.set(40, \"someKey\");\n// Including compatibility with any type of object like MyObject\nMyObject myobject = new MyObject();\ntag.set(myobject, \"any\", \"path\");\n// Merge values into tag\ntag.merge(Map.of(\"asd\", 123, \"someKey\", 41), true);\n\n// So you can add lists\ntag.set(new ArrayList(), \"list\", \"path\");\n// And add values into list\ntag.add((short) 3, \"list\", \"path\");\n// Or replace the values of existing list\ntag.set((short) 5, \"list\", \"path\", 0); // index 0\n\n// --- Get values\n// Value from path \"display\" -\u003e \"Name\"\nString name = tag.get(\"display\", \"Name\");\n// Safe value get from path \"someKey\", or -1 by default\nint intValue = tag.getOptional(\"someKey\").or(-1);\nint sameValue = tag.getOptional(\"someKey\").asInt(-1); // This method try to convert any type to int\n// Explicit value get for custom objects\nMyObject sameobject = tag.getOptional(\"any\", \"path\").as(MyObject.class);\n\n// Get lists\nList\u003cShort\u003e list = tag.get(\"list\", \"path\");\n// Get list value from index\nshort listValue = tag.get(\"list\", \"path\", 0); // index 0\n\n// Get the entire object tag as Map of Java objects\nMap\u003cString, Object\u003e map = tag.get();\n\n// --- Load changes into object\n// Load changes into original object\ntag.load();\n// RtagItem as the option to create an item copy with changes loaded\nItemStack itemCopy = tag.loadCopy();\n\n// --- Update current tag if the original object was edited\ntag.update();\n```\n\n## Get Rtag\n\n### Requirements\n*  **At least Minecraft 1.8.8:** Rtag is made to be used in last Minecraft versions, old versions support is only for commercial purposes.\n*  Minimum Java 11\n\n### Project build\nFor Gradle Groovy project (build.gradle)\n```groovy\nrepositories {\n    maven { url 'https://jitpack.io' }\n}\n\ndependencies {\n    compileOnly 'com.saicone.rtag:rtag:VERSION'\n    // Other modules\n    compileOnly 'com.saicone.rtag:rtag-block:VERSION'\n    compileOnly 'com.saicone.rtag:rtag-entity:VERSION'\n    compileOnly 'com.saicone.rtag:rtag-item:VERSION'\n}\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eFor Gradle Kotlin project (build.gradle.kts)\u003c/summary\u003e\n  \n  ```kotlin\n  repositories {\n      maven(\"https://jitpack.io\")\n  }\n\n  dependencies {\n      compileOnly(\"com.saicone.rtag:rtag:VERSION\")\n      // Other modules\n      compileOnly(\"com.saicone.rtag:rtag-block:VERSION\")\n      compileOnly(\"com.saicone.rtag:rtag-entity:VERSION\")\n      compileOnly(\"com.saicone.rtag:rtag-item:VERSION\")\n  }\n  ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eFor Maven project (pom.xml)\u003c/summary\u003e\n  \n  ```xml\n  \u003crepositories\u003e\n      \u003crepository\u003e\n          \u003cid\u003eJitpack\u003c/id\u003e\n          \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\n      \u003c/repository\u003e\n  \u003c/repositories\u003e\n    \n  \u003cdependencies\u003e\n      \u003cdependency\u003e\n          \u003cgroupId\u003ecom.saicone.rtag\u003c/groupId\u003e\n          \u003cartifactId\u003ertag\u003c/artifactId\u003e\n          \u003cversion\u003eVERSION\u003c/version\u003e\n          \u003cscope\u003eprovided\u003c/scope\u003e\n      \u003c/dependency\u003e\n      \u003c!-- Other modules --\u003e\n      \u003cdependency\u003e\n          \u003cgroupId\u003ecom.saicone.rtag\u003c/groupId\u003e\n          \u003cartifactId\u003ertag-block\u003c/artifactId\u003e\n          \u003cversion\u003eVERSION\u003c/version\u003e\n          \u003cscope\u003eprovided\u003c/scope\u003e\n      \u003c/dependency\u003e\n      \u003cdependency\u003e\n          \u003cgroupId\u003ecom.saicone.rtag\u003c/groupId\u003e\n          \u003cartifactId\u003ertag-entity\u003c/artifactId\u003e\n          \u003cversion\u003eVERSION\u003c/version\u003e\n          \u003cscope\u003eprovided\u003c/scope\u003e\n      \u003c/dependency\u003e\n      \u003cdependency\u003e\n          \u003cgroupId\u003ecom.saicone.rtag\u003c/groupId\u003e\n          \u003cartifactId\u003ertag-item\u003c/artifactId\u003e\n          \u003cversion\u003eVERSION\u003c/version\u003e\n          \u003cscope\u003eprovided\u003c/scope\u003e\n      \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n  ```\n\u003c/details\u003e\n\n\n# Why Rtag\nThere are other libraries to edit NBT tags, why should Rtag be used over the others?\n\n## Really fast\nRtag abuses of static final MethodHandles to convert the use of reflected methods as if they were direct calls, so it works to edit NBT tags in non-async operations without producing a bad performance impact on big servers.\n\n## Easy to understand\n\n### Simple methods\nYou don't need to be an expert with NBT tags, just with simple methods you can set and get normal Java objects.\n```java\nRtag rtag = new Rtag();\nrtag.set(compound, \"Normal string\", \"CustomTagPath\");\nString string = rtag.get(compound, \"CustomTagPath\");\n```\n\n### Compatibility methods\nThe main RtagEditor instances have methods to make tag editing easier.\n```java\nRtagItem tag = new RtagItem(item);\ntag.setUnbreakable(true);\ntag.setRepairCost(20);\nint level = tag.getEnchantmentLevel(\"unbreaking\"); // Enchantment enum, name or id\n\nRtagEntity tag = new RtagEntity(entity);\ntag.setAttributeBase(\"generic.attackDamage\", 0.5);\n\nRtagBlock tag = new RtagBlock(block);\ntag.setCustomName(\"§eColored name\");\n```\n\n### Functional methods\nYou can edit objects using functions inside RtagEditor instances and return any type of object.\n```java\nItemStack item = ...;\n// Edit original\nRtagItem.edit(item, tag -\u003e {\n    tag.set(\"Custom Text\", \"display\", \"name\");\n    tag.set(30, \"someKey\");\n});\n// Return a copy\nItemStack copy = RtagItem.edit(item, tag -\u003e {\n    tag.set(30, \"someKey\");\n    return tag.loadCopy();\n});\n```\n\n## Store custom objects\n\n### Using default method\nBy default, Rtag uses the Gson library inside Bukkit to (de)serialize custom objects, but you need to get them using explicit conversion.\n```java\nRtag rtag = new Rtag();\nMyObject myObject = new MyObject();\n\nrtag.set(compound, myObject, \"CustomTagPath\");\nMyObject sameObject = rtag.getOptional(compound, \"CustomTagPath\").as(MyObject.class);\n```\n\n### Using your own method\nYou can register (de)serializers in Rtag instance to set and get custom objects with automatic conversion.\n\nThis conversion put an additional key into your saved tag to detect it using the provided ID.\n```java\npublic class MyObjectSerializer implements RtagSerializer\u003cMyObject\u003e, RtagDeserializer\u003cMyObject\u003e {\n    \n    public MyObjectSerializer(Rtag rtag) {\n        rtag.putSerializer(MyObject.class, this);\n        rtag.putDeserializer(this);\n    }\n    \n    // MyObject -\u003e Map\n    @Override\n    public String getInID() {\n        // It's suggested to use a unique namespaced key\n        return \"myplugin:MyObject\";\n    }\n    \n    // Map -\u003e MyObject\n    @Override\n    public String getOutID() {\n        return \"myplugin:MyObject\";\n    }\n\n    @Override\n    public Map\u003cString, Object\u003e serialize(MyObject object) {\n        // Convert your custom object into map\n    }\n    \n    @Override\n    public MyObject deserialize(Map\u003cString, Object\u003e compound) {\n        // Convert compound into you custom object\n    }\n}\n```\nThen you can get your custom object without explicit conversion.\n```java\nRtag rtag = new Rtag();\nnew MyObjectSerializer(rtag);\nMyObject myObject = new MyObject();\n\nrtag.set(compound, myObject, \"CustomTagPath\");\nMyObject sameObject = rtag.get(compound, \"CustomTagPath\");\n```\n\n## TagStream instances\n\n### ItemTagStream\nWith ItemTagStream instance you can convert items into Base64|File|Bytes|Map|String and viceversa.\n\nIncluding **cross-version support**! Save an item on any version and get on any version without compatibility problems. Materials, enchantments, potions... etc, all will be converted!\n```java\nItemTagStream tag = ItemTagStream.INSTANCE;\n\nString string = tag.toBase64(item);\nItemStack sameItem = tag.fromBase64(string)[0];\n```\n\n## Additional utilities\n\n### Textured heads\nWith SkullTexture class you can get textured heads from base64, url, texture ID, player name or uuid.\n```java\n// Base64\nItemStack head = SkullTexture.getTexturedHead(\"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmVkZmEyZTBmZGVhMGMwNDIzODA0Y2RiNWI2MmFkMDVhNmU5MTRjMDQ2YzRhM2I3ZTM1NWJmODEyNjkxMjVmZCJ9fQ==\");\n// URL\nItemStack head = SkullTexture.getTexturedHead(\"http://textures.minecraft.net/texture/fedfa2e0fdea0c0423804cdb5b62ad05a6e914c046c4a3b7e355bf81269125fd\");\n// Texture ID\nItemStack head = SkullTexture.getTexturedHead(\"fedfa2e0fdea0c0423804cdb5b62ad05a6e914c046c4a3b7e355bf81269125fd\");\n// Player name\nItemStack head = SkullTexture.getTexturedHead(\"Rubenicos\");\n// Player UUID\nItemStack head = SkullTexture.getTexturedHead(\"7ca003dc-175f-4f1f-b490-5651045311ad\");\n```\n\n### Chat Component\nWith ChatComponent class you can convert (json) strings into chat components and viceversa.\n```java\n// To component\nObject component = ChatComponent.fromJson(\"{\\\"bold\\\":true,\\\"italic\\\":false,\\\"color\\\":\\\"dark_purple\\\",\\\"text\\\":\\\"Colored text!\\\"}\");\nObject sameComponent = ChatComponent.fromString(\"§5§lColored text!\");\n\n// From component\nString json = ChatComponent.toJson(component);\nString string = ChatComponent.toString(component);\n\n// Cross-compatibility\nString json = ChatComponent.toJson(\"§5§lColored text!\");\nString string = ChatComponent.toString(\"{\\\"bold\\\":true,\\\"italic\\\":false,\\\"color\\\":\\\"dark_purple\\\",\\\"text\\\":\\\"Colored text!\\\"}\");\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaicone%2Frtag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaicone%2Frtag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaicone%2Frtag/lists"}