├── .github └── workflows │ └── gradle.yml ├── .gitignore ├── .gitmodules ├── CHANGELOG.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts └── src ├── main └── kotlin │ └── br │ └── com │ └── gamemods │ └── nbtmanipulator │ ├── ComplexNbtStringParser.kt │ ├── LittleEndianDataInputStream.kt │ ├── LittleEndianDataOutputStream.kt │ ├── NbtByte.kt │ ├── NbtByteArray.kt │ ├── NbtCompound.kt │ ├── NbtCompoundStringParser.kt │ ├── NbtDouble.kt │ ├── NbtEnd.kt │ ├── NbtFile.kt │ ├── NbtFloat.kt │ ├── NbtIO.kt │ ├── NbtInt.kt │ ├── NbtIntArray.kt │ ├── NbtList.kt │ ├── NbtListStringParser.kt │ ├── NbtLong.kt │ ├── NbtLongArray.kt │ ├── NbtShort.kt │ ├── NbtString.kt │ ├── NbtTag.kt │ ├── NbtUtil-add.kt │ ├── NbtUtil-contains.kt │ ├── NbtUtil-minusAssign.kt │ ├── NbtUtil-plusAssign.kt │ ├── NbtUtil-remove.kt │ ├── NbtUtil-toNbtList.kt │ └── NbtUtil.kt ├── pages ├── _config.yml └── assets │ └── css │ └── style.scss └── test ├── java └── test │ └── JavaUsage.java ├── kotlin └── br │ └── com │ └── gamemods │ └── nbtmanipulator │ ├── CompoundStringParserTest.kt │ ├── KotlinUsage.kt │ ├── LevelDatTest.kt │ ├── ListStringParserTest.kt │ ├── SimpleStringParserTest.kt │ ├── StringValueWithStringConstructorTest.kt │ └── ToStringTest.kt └── resources ├── level-bedrock-edition.dat └── level-java-edition.dat /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: 4 | pull_request: 5 | branches-ignore: 'gh-pages' 6 | push: 7 | branches-ignore: 'gh-pages' 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - uses: actions/cache@v1 17 | with: 18 | path: ~/.gradle/caches 19 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 20 | restore-keys: | 21 | ${{ runner.os }}-gradle- 22 | - name: Set up JDK 1.8 23 | uses: actions/setup-java@v1 24 | with: 25 | java-version: 1.8 26 | - name: Build with Gradle 27 | run: ./gradlew build 28 | - name: Rename artifacts 29 | run: mv build/libs/nbt-manipulator-*.jar build/libs/nbt-manipulator.jar 30 | - name: Archive artifacts 31 | uses: actions/upload-artifact@v1 32 | if: success() 33 | with: 34 | name: NBT-Manipulator 35 | path: build/libs/nbt-manipulator.jar 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build 3 | *.iws 4 | *.ipr 5 | .idea 6 | nukkit-*.jar 7 | /out 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gh-pages"] 2 | path = gh-pages 3 | url = https://github.com/GameModsBR/NBT-Manipulator.git 4 | branch = gh-pages 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6 | 7 | ## [Unreleased] 8 | Click the link above to see the future. 9 | 10 | ## [3.1.0] - 2021-10-28 11 | [Downloads from maven central.][Download 3.1.0] 12 | 13 | [Kotlin Documentation][KDoc 3.1.0] 14 | 15 | ### Added 16 | - Automatic Java Jigsaw Module named `br.com.gamemods.nbtmanipulator` 17 | - `NbtIO.writeNbtTagDirectly()` and `NbtIO.readNbtTagDirectly()` allowing reading and writing arbitrary tags. 18 | 19 | ### Changed 20 | - Updated to Kotlin `1.5.31` 21 | - The source code was split in multiple files and now uses the explicit API feature 22 | 23 | ## [3.0.0] - 2021-08-12 24 | [Downloads from maven central.][Download 3.0.0] 25 | 26 | [Kotlin Documentation][KDoc 3.0.0] 27 | 28 | ### Fixed 29 | - Made a micro-optimization to the `NbtCompound` constructor. 30 | 31 | ### Added 32 | - Empty constructor for the array tag types. It may break old method references like `::NbtByteArray` **(Breaking Change)** 33 | - A constructor which accepts `Iterable` to `NbtCompound` 34 | - Constructors which accepts `String` to all `NbtTag` types 35 | - `stringValue` property to `NbtTag` 36 | - `unsiged` property to `NbtByte` 37 | - A static function `NbtByte.unsigned(String)` to a create `NbtByte` from unsigned strings. 38 | - Little endian `DataInput` and `DataOutput` implementations 39 | - Support to read and write Bedrock Edition NBT files using `NbtIO` 40 | 41 | ### Changed 42 | - `NbtByte`'s `Int` constructor now throws `NumberFormatException` if the number is outside the `0..255` range. **(Breaking Change)** 43 | - Improved the `toString()` methods of all `NbtTag` types **(Breaking Change)** 44 | - `NbtList` now enforces the contents to have the same type on modifications **(Breaking Change)** 45 | - `NbtCompound` now implements `equals` and `hashCode` as described by the `Map` interface **(Breaking Change)** 46 | - `NbtList` now implements `equals` and `hashCode` as described by the `List` interface **(Breaking Change)** 47 | - Renamed `NbtByte.value` to `NbtByte.signed`. `NbtByte.value` is still usable but it is deprecated, 48 | is being replaced in byte-code and will be removed in a future version. 49 | - `NbtList` and the returned sub-lists now implements `RandomAccess` 50 | 51 | ## [2.0.0] - 2020-01-24 52 | [Downloads from maven central.][Download 2.0.0] 53 | 54 | [Kotlin Documentation][KDoc 2.0.0] 55 | 56 | ### Changed 57 | - Upgraded to Kotlin 1.3.61 58 | - `NbtIO.writeNbtFile` and `NbtIO.readNbtFile` now throws `IOException` in Java **(Breaking Change)** 59 | 60 | ## [1.1.0] - 2019-06-02 61 | [Downloads from maven central.][Download 1.1.0] 62 | 63 | [Kotlin Documentation][KDoc 1.1.0] 64 | 65 | ### Added 66 | - New constructor to `NbtList` which accepts an other `NbtList` to resolve an ambiguity call in this scenario. 67 | - `toNbtList()` extension function to many combinations of `Iterable` and `Array` which contains valid values for `NbtList`, including list of list. 68 | - `NbtList.create` and it's sublist flavours to simplify list creations for Java users 69 | - `add`, `remove`, `contains`, `minusAssign` and `plusAssign` extension functions to many possible `NbtList` for easy usage by Kotlin users 70 | 71 | ## [1.0.1] - 2019-05-27 72 | [Downloads from maven central.][Download 1.0.1] 73 | 74 | [Kotlin Documentation][KDoc 1.0.1] 75 | 76 | ### Fixes 77 | - StackOverflowException on `NbtCompound.set(String, NbtTag)` 78 | 79 | ## [1.0.0] - 2019-05-27 80 | [Downloads from maven central.][Download 1.0.0] 81 | 82 | [Kotlin Documentation][KDoc 1.0.0] 83 | ### Added 84 | - `deepClone` method to all tags 85 | - `require` method to `NbtCompound` 86 | 87 | ### Changed 88 | - `NbtList` is now a `MutableList` and not a `data class` anymore. This completely changes how API users interacts with them. 89 | - `NbtCompound` is now a `MutableMap` and not a `data class` anymore. This completely changes how API users interacts with them. 90 | - Renamed the parameter `name` to `key` in all methods of `NbtCompound` 91 | - Renamed the parameter `tagName` to `tagKey` in all copy methods of `NbtCompound` 92 | - All get methods from `NbtCompound` will now throw `NoSuchElementException` if the requested key does not exists in the compound 93 | - All methods which throws exceptions now have the exception which is thrown registered in the binary files. 94 | Useful for Java users and who couldn't get the sources or javadoc. 95 | 96 | 97 | ## [0.0.2] - 2019-05-27 98 | [Downloads from maven central.][Download 0.0.2] 99 | ### Added 100 | - Static methods for java users calling `NbtIO` 101 | - Documentation to all public types, functions and properties 102 | - The methods `NbtCompound.remove(String)`, `NbtCompound.remove(String, NbtTag)` and `NbtCompound.minusAssign(String)` 103 | 104 | ### Changed 105 | - JavaDoc will not generate when building on Java 9+ due to a dokka issue 106 | - The targetCompatibility to Java 8 107 | 108 | ## [0.0.1] - 2019-05-23 109 | [Downloads from maven central.][Download 0.0.1] 110 | ### Added 111 | - API to read and write to/from NBT files/streams using `NbtIO` 112 | - API to freely manipulate NBT data loaded in memory 113 | 114 | [Unreleased]: https://github.com/GameModsBR/NBT-Manipulator/compare/v3.1.0...HEAD 115 | [3.1.0]: https://github.com/GameModsBR/NBT-Manipulator/compare/v3.0.0...v3.1.0 116 | [3.0.0]: https://github.com/GameModsBR/NBT-Manipulator/compare/v2.0.0...v3.0.0 117 | [2.0.0]: https://github.com/GameModsBR/NBT-Manipulator/compare/v2.0.0...v3.0.0 118 | [2.0.0]: https://github.com/GameModsBR/NBT-Manipulator/compare/v1.1.1...v2.0.0 119 | [1.1.0]: https://github.com/GameModsBR/NBT-Manipulator/compare/v1.0.1...v1.1.0 120 | [1.0.1]: https://github.com/GameModsBR/NBT-Manipulator/compare/v1.0.0...v1.0.1 121 | [1.0.0]: https://github.com/GameModsBR/NBT-Manipulator/compare/v0.0.2...v1.0.0 122 | [0.0.2]: https://github.com/GameModsBR/NBT-Manipulator/compare/v0.0.1...v0.0.2 123 | [0.0.1]: https://github.com/GameModsBR/NBT-Manipulator/compare/v0.0.0...v0.0.1 124 | 125 | [Download 3.1.0]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/3.1.0/jar 126 | [Download 3.0.0]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/3.0.0/jar 127 | [Download 2.0.0]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/2.0.0/jar 128 | [Download 1.1.0]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/1.1.0/jar 129 | [Download 1.0.1]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/1.0.1/jar 130 | [Download 1.0.0]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/1.0.0/jar 131 | [Download 0.0.2]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/0.0.2/jar 132 | [Download 0.0.1]: https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator/0.0.1/jar 133 | 134 | [KDoc 3.1.0]: https://github.com/GameModsBR/NBT-Manipulator/blob/5ec17b901033d589bce5b613420aa2682df50c9a/kdoc/br.com.gamemods.nbtmanipulator/index.md 135 | [KDoc 3.0.0]: https://github.com/GameModsBR/NBT-Manipulator/blob/e4b3e63039419ce9d927dbf2d283f5b56ab762c7/kdoc/br.com.gamemods.nbtmanipulator/index.md 136 | [KDoc 2.0.0]: https://github.com/GameModsBR/NBT-Manipulator/blob/144c1aec6b9fbb2ce7996e200a9637f9b868c8d9/kdoc/br.com.gamemods.nbtmanipulator/index.md 137 | [KDoc 1.1.0]: https://github.com/GameModsBR/NBT-Manipulator/blob/f188707e1d9a5616db1ccd45e892171349ee5a62/kdoc/br.com.gamemods.nbtmanipulator/index.md 138 | [KDoc 1.0.1]: https://github.com/GameModsBR/NBT-Manipulator/blob/51f0f36511b8d4979d5d3e322f2fb766095a174c/kdoc/br.com.gamemods.nbtmanipulator/index.md 139 | [KDoc 1.0.0]: https://github.com/GameModsBR/NBT-Manipulator/blob/0ef42323681f9960cb2c9698d7b8b1d02632691b/kdoc/br.com.gamemods.nbtmanipulator/index.md 140 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2019 José Roberto de Araújo Júnior 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NBT Manipulator 2 | 3 | This is a Kotlin/Java library that allows you to read and write NBT files and data in a clean and simple way. 4 | 5 | Can be used both for Minecraft Java and Minecraft Bedrock Edition NBT structures. 6 | 7 | Here you can find the library documentation: 8 | * [Java Documentation](https://powernukkit.github.io/NBT-Manipulator/javadoc/br/com/gamemods/nbtmanipulator/package-summary.html) 9 | * [Kotlin Documentation](https://powernukkit.github.io/NBT-Manipulator/kdoc/br.com.gamemods.nbtmanipulator/index.html) 10 | 11 | You may also want to see the [changelog](CHANGELOG.md) file to be aware of all changes in the tool that may impact you. 12 | 13 | **TIP:** If you are using `NbtList` with Kotlin, add a `import br.com.gamemods.nbtmanipulator.*` for easy list management. 14 | 15 | For example: 16 | ```kotlin 17 | val list = listOf(2,3,4,5,6).toNbtList() 18 | list += 7 19 | check(7 in list) 20 | list -= 7 21 | check(7 !in list) 22 | ``` 23 | 24 | ## Adding to your project 25 | 26 | The library is shared in the maven center, so you don't need to declare any custom repository. 27 | 28 | ### Gradle 29 | 30 | #### Kotlin DSL 31 | ```kotlin 32 | repositories { 33 | mavenCentral() 34 | } 35 | 36 | dependencies { 37 | implementation("br.com.gamemods:nbt-manipulator:3.1.0") 38 | } 39 | ``` 40 | 41 | #### Groovy DSL 42 | ```groovy 43 | repositories { 44 | mavenCentral() 45 | } 46 | 47 | dependencies { 48 | implementation 'br.com.gamemods:nbt-manipulator:3.1.0' 49 | } 50 | ``` 51 | 52 | ### Maven 53 | 54 | ```xml 55 | 56 | 57 | br.com.gamemods 58 | nbt-manipulator 59 | 3.1.0 60 | 61 | 62 | ``` 63 | 64 | ### Ivy 65 | 66 | ```xml 67 | 68 | ``` 69 | 70 | ### Direct JAR 71 | Download it from [maven central](https://search.maven.org/artifact/br.com.gamemods/nbt-manipulator). 72 | 73 | ## Examples 74 | 75 | ```kotlin 76 | val compound = NbtCompound() 77 | compound["A string tag"] = "The string tag value" 78 | compound["An int tag"] = 2 79 | val byteValue: Byte = 3 80 | compound["An byte tag"] = byteValue 81 | 82 | println(compound.getString("A string tag")) 83 | println(compound.getInt("A string tag")) 84 | println(compound.getInt("An int tag")) 85 | println(compound.getNullableByte("An byte tag")) 86 | 87 | println(compound.getNullableStringList("This is missing..")) 88 | 89 | val otherConstructor = NbtCompound( 90 | "a" to NbtString("string"), 91 | "b" to NbtList(listOf(NbtDouble(0.0), NbtDouble(1.1))) 92 | ) 93 | println(otherConstructor["a"]) 94 | println(otherConstructor.getDoubleList("b")) 95 | ``` 96 | 97 | ```kotlin 98 | internal fun convertLevelFile(from: File, to: File) { 99 | val input = NbtIO.readNbtFile(from) 100 | val inputData = input.compound.getCompound("Data") 101 | 102 | val outputData = NbtCompound() 103 | outputData.copyFrom(inputData, "GameRules") 104 | outputData.copyFrom(inputData, "DayTime") 105 | outputData.copyFrom(inputData, "GameType") 106 | outputData.copyFrom(inputData, "generatorName") 107 | outputData.copyFrom(inputData, "generatorVersion") 108 | outputData.copyFrom(inputData, "generatorVersion") 109 | outputData.copyFrom(inputData, "generatorOptions", NbtString("")) 110 | outputData["hardcore"] = false 111 | outputData["initialized"] = false 112 | outputData.copyFrom(inputData, "LastPlayed") 113 | outputData.copyFrom(inputData, "LevelName") 114 | outputData.copyFrom(inputData, "raining") 115 | outputData.copyFrom(inputData, "rainTime") 116 | outputData.copyFrom(inputData, "RandomSeed") 117 | outputData.copyFrom(inputData, "SizeOnDisk") 118 | outputData.copyFrom(inputData, "SpawnX") 119 | outputData.copyFrom(inputData, "SpawnY") 120 | outputData.copyFrom(inputData, "SpawnZ") 121 | outputData.copyFrom(inputData, "thundering") 122 | outputData.copyFrom(inputData, "thunderTime") 123 | outputData.copyFrom(inputData, "Time") 124 | outputData.copyFrom(inputData, "version") 125 | 126 | val output = NbtCompound("Data" to outputData) 127 | val file = NbtFile("", output) 128 | NbtIO.writeNbtFile(to, file) 129 | } 130 | ``` 131 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.nio.file.Files 2 | import java.nio.file.StandardCopyOption 3 | 4 | plugins { 5 | java 6 | id("org.jetbrains.kotlin.jvm") version "1.5.31" 7 | maven 8 | signing 9 | id("org.jetbrains.dokka") version "1.5.30" 10 | id("org.ajoberstar.git-publish") version "3.0.0" 11 | } 12 | val kotlinVersion = "1.5.31" 13 | val ossrhUsername: String by project 14 | val ossrhPassword: String by project 15 | 16 | group = "br.com.gamemods" 17 | version = "3.1.0" 18 | base { 19 | archivesBaseName = name 20 | } 21 | 22 | sourceSets.main { 23 | java { 24 | srcDirs("src/main/kotlin") 25 | } 26 | } 27 | 28 | java { 29 | sourceCompatibility = JavaVersion.VERSION_1_8 30 | targetCompatibility = sourceCompatibility 31 | } 32 | 33 | kotlin { 34 | explicitApi() 35 | } 36 | 37 | repositories { 38 | mavenCentral() 39 | } 40 | 41 | dependencies { 42 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion") 43 | implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion") 44 | testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion") 45 | testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlinVersion") 46 | } 47 | 48 | tasks { 49 | compileKotlin { 50 | kotlinOptions.jvmTarget = "1.8" 51 | } 52 | compileTestKotlin { 53 | kotlinOptions.jvmTarget = "1.8" 54 | } 55 | 56 | jar { 57 | manifest { 58 | attributes["Automatic-Module-Name"] = "br.com.gamemods.nbtmanipulator" 59 | } 60 | } 61 | 62 | "uploadArchives"(Upload::class) { 63 | repositories { 64 | withConvention(MavenRepositoryHandlerConvention::class) { 65 | mavenDeployer { 66 | if (findProperty("signing.secretKeyRingFile") != "undefined") { 67 | beforeDeployment { 68 | @Suppress("DEPRECATION") 69 | signing.signPom(this) 70 | } 71 | } 72 | withGroovyBuilder { 73 | "repository"("url" to uri("https://oss.sonatype.org/service/local/staging/deploy/maven2/")) { 74 | "authentication"("userName" to ossrhUsername, "password" to ossrhPassword) 75 | } 76 | "snapshotRepository"("url" to uri("https://oss.sonatype.org/content/repositories/snapshots/")) { 77 | "authentication"("userName" to ossrhUsername, "password" to ossrhPassword) 78 | } 79 | } 80 | 81 | pom.project { 82 | withGroovyBuilder { 83 | "packaging"("jar") 84 | "groupId"(project.group) 85 | "artifactId"(project.name) 86 | "version"(project.version) 87 | "name"(project.name) 88 | "description"("A kotlin/java lib that allows you to read and write NBT data in a clean way") 89 | "url"("https://github.com/PowerNukkit/NBT-Manipulator") 90 | "inceptionYear"("2020") 91 | "licenses" { 92 | "license" { 93 | "name"("MIT") 94 | "url"("https://raw.githubusercontent.com/PowerNukkit/NBT-Manipulator/master/LICENSE") 95 | "distribution"("repo") 96 | } 97 | } 98 | "developers" { 99 | "developer" { 100 | "id"("joserobjr") 101 | "name"("José Roberto de Araújo Júnior") 102 | "email"("joserobjr@powernukkit.org") 103 | } 104 | } 105 | "scm" { 106 | "connection"("https://github.com/PowerNukkit/NBT-Manipulator.git") 107 | "developerConnection"("https://github.com/PowerNukkit/NBT-Manipulator.git") 108 | "url"("https://github.com/PowerNukkit/NBT-Manipulator") 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | tasks.dokkaJavadoc.configure { 119 | outputDirectory.set(File(buildDir, "javadoc")) 120 | } 121 | 122 | tasks.dokkaGfm.configure { 123 | outputDirectory.set(File(buildDir, "kdoc")) 124 | } 125 | 126 | val createReadmeFiles: Task by tasks.creating { 127 | dependsOn(tasks.dokkaGfm) 128 | doFirst { 129 | Files.copy(projectDir.toPath().resolve("README.md"), tasks.dokkaGfm.get().outputDirectory.get().toPath().resolve("nbt-manipulator/index.md"), StandardCopyOption.REPLACE_EXISTING) 130 | } 131 | } 132 | 133 | val createIndexMd = tasks.create("createIndexMd") { 134 | from(File(projectDir, "README.md")) 135 | into(File(buildDir, "pages")) 136 | rename("README.md", "index.md") 137 | } 138 | 139 | val javadocJar = tasks.create("javadocJar") { 140 | dependsOn(tasks.dokkaJavadoc) 141 | archiveClassifier.set("javadoc") 142 | from(tasks.dokkaJavadoc.get().outputDirectory) 143 | from(File(projectDir, "LICENSE")) 144 | from(File(projectDir, "README.md")) 145 | from(File(projectDir, "CHANGELOG.md")) 146 | } 147 | 148 | val sourcesJar = tasks.create("sourcesJar") { 149 | from(sourceSets.main.get().java.srcDirs) 150 | from(File(projectDir, "build.gradle")) 151 | from(File(projectDir, "gradle.properties")) 152 | from(File(projectDir, "settings.gradle.kts")) 153 | from(File(projectDir, "LICENSE")) 154 | from(File(projectDir, "README.md")) 155 | from(File(projectDir, "CHANGELOG.md")) 156 | archiveClassifier.set("sources") 157 | } 158 | 159 | tasks.jar { 160 | from(File(projectDir, "LICENSE")) 161 | from(File(projectDir, "README.md")) 162 | from(File(projectDir, "CHANGELOG.md")) 163 | } 164 | 165 | artifacts { 166 | archives(sourcesJar) 167 | archives(javadocJar) 168 | } 169 | 170 | if (findProperty("signing.secretKeyRingFile") != "undefined") { 171 | signing { 172 | sign(configurations.archives.get()) 173 | } 174 | } 175 | 176 | if (ext.has("org.ajoberstar.grgit.auth.username")) { 177 | System.setProperty("org.ajoberstar.grgit.auth.username", ext["org.ajoberstar.grgit.auth.username"].toString()) 178 | System.setProperty("org.ajoberstar.grgit.auth.password", ext["org.ajoberstar.grgit.auth.password"].toString()) 179 | } 180 | 181 | gitPublish { 182 | // where to publish to (repo must exist) 183 | repoUri.set("https://github.com/PowerNukkit/NBT-Manipulator.git") 184 | 185 | // where to fetch from prior to fetching from the remote (i.e. a local repo to save time) 186 | //referenceRepoUri = file("$projectDir/gh-pages").toURI().toString() 187 | 188 | // branch will be created if it doesn't exist 189 | branch.set("gh-pages") 190 | 191 | // generally, you don't need to touch this 192 | repoDir.set(File(buildDir, "gh-pages-repo")) // defaults to $buildDir/gitPublish 193 | 194 | // what to publish, this is a standard CopySpec 195 | contents { 196 | from(File(buildDir, "javadoc")) { 197 | into("javadoc") 198 | } 199 | from(File(buildDir, "kdoc").resolve("nbt-manipulator")) { 200 | into("kdoc") 201 | } 202 | from(File(buildDir, "pages")) 203 | from(File("src", "pages")) 204 | from("README.md") 205 | from("CHANGELOG.md") 206 | } 207 | 208 | // what to keep in the existing branch (include=keep) 209 | preserve { 210 | include("1.0.0/**") 211 | exclude("1.0.0/temp.txt") 212 | } 213 | 214 | sign.set(false) 215 | 216 | // message used when committing changes 217 | commitMessage.set("Github Pages update") // defaults to 'Generated by gradle-git-publish' 218 | } 219 | 220 | tasks { 221 | gitPublishCopy { 222 | dependsOn(dokkaJavadoc) 223 | dependsOn(createReadmeFiles) 224 | dependsOn(createIndexMd) 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | org.gradle.jvmargs=-Xmx2048m 3 | 4 | signing.keyId=undefined 5 | signing.password=undefined 6 | signing.secretKeyRingFile=undefined 7 | 8 | ossrhUsername=undefined 9 | ossrhPassword=undefined 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerNukkit/NBT-Manipulator/b63a1bd4a406310097e314ef911650026dd812cb/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "nbt-manipulator" 2 | 3 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/ComplexNbtStringParser.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | internal abstract class ComplexNbtStringParser(fatherOpenChar: Char, fatherCloseChar: Char, input: String) { 4 | protected val input = input.let { 5 | require(it.isNotEmpty() && it.first() == fatherOpenChar && it.last() == fatherCloseChar) { 6 | "Invalid input. Missing open and close chars." 7 | } 8 | it.removeSurrounding(fatherOpenChar.toString(), fatherCloseChar.toString()) 9 | } 10 | 11 | protected var startIndex = 0 12 | protected lateinit var type: String 13 | protected lateinit var constructor: (String) -> NbtTag 14 | protected var openChar = '\u0000' 15 | protected var closeChar = '\u0000' 16 | protected var endIndex = -2 17 | 18 | private var openBlocks = 0 19 | private var openString = false 20 | private val scanChars = charArrayOf('"', openChar, closeChar) 21 | 22 | protected fun parseBeginning() { 23 | val startingAt = startIndex 24 | startIndex = input.indexOfAny(charArrayOf('(', '[', '{'), startingAt).also { 25 | require(it > 0) { "Invalid input. Unable to determine the beginning of the next tag" } 26 | } 27 | 28 | type = input.substring(startingAt, startIndex) 29 | constructor = 30 | requireNotNull(constructors[type]) { 31 | "Invalid input. Unexpected children tag type: $type" 32 | } 33 | 34 | openChar = 35 | if (type == "NbtList" || type.endsWith("Array")) '[' 36 | else if (type == "NbtCompound") '{' 37 | else '(' 38 | 39 | closeChar = 40 | if (type == "NbtList" || type.endsWith("Array")) ']' 41 | else if (type == "NbtCompound") '}' 42 | else ')' 43 | 44 | scanChars[1] = openChar 45 | scanChars[2] = closeChar 46 | } 47 | 48 | protected fun parseTag(): NbtTag { 49 | parseBeginning() 50 | 51 | return when(type) { 52 | "NbtByteArray", "NbtIntArray", "NbtLongArray" -> parseTag(includeSurrounding = true) 53 | "NbtString" -> parseStringTag() 54 | "NbtList", "NbtCompound" -> parseTag(includeSurrounding = true, father = true) 55 | else -> parseTag(includeSurrounding = false) 56 | } 57 | } 58 | 59 | protected tailrec fun findClosingQuote(closingQuote: String, startIndex: Int = this.startIndex): String { 60 | endIndex = input.indexOf(closingQuote, startIndex) 61 | require(endIndex >= startIndex) { "Invalid input. Wrong string format." } 62 | if (input[endIndex - 1] == '\\') { 63 | val newStart = endIndex + closingQuote.length 64 | require(newStart < input.length) { "Invalid input. A string is not closed." } 65 | return findClosingQuote(closingQuote, newStart) 66 | } 67 | return input.substring(this.startIndex, endIndex) 68 | .replace("\\\"", "\"") 69 | .replace("\\\\", "\\") 70 | } 71 | 72 | protected fun parseStringTag(): NbtString { 73 | startIndex += 2 74 | return NbtString(findClosingQuote("\")")) 75 | } 76 | 77 | protected fun parseTag(includeSurrounding: Boolean, father: Boolean = false): NbtTag { 78 | if (includeSurrounding) { 79 | if (father) { 80 | openBlocks++ 81 | endIndex = startIndex 82 | require(endIndex + 1 < input.length) { "Invalid input. Unexpected ending." } 83 | findTheCloseBracket() 84 | } else { 85 | endIndex = input.indexOf(closeChar, startIndex + 1) 86 | } 87 | require(endIndex >= startIndex + 1) { "Invalid input. Unexpected ending." } 88 | endIndex++ 89 | } else { 90 | startIndex++ 91 | endIndex = input.indexOf(closeChar, startIndex) 92 | require(endIndex > startIndex) { "Invalid input. Unexpected ending." } 93 | } 94 | try { 95 | return constructor(input.substring(startIndex, endIndex)) 96 | } catch (e: Exception) { 97 | throw IllegalArgumentException("Invalid input. Failed to create an instance of a child tag.", e) 98 | } 99 | } 100 | 101 | private tailrec fun findTheCloseBracket() { 102 | val index = input.indexOfAny(scanChars, endIndex + 1) 103 | require(index > endIndex) { "Invalid input. Could not find the close bracket." } 104 | endIndex = index 105 | when (input[index]) { 106 | openChar -> { 107 | if (!openString) { 108 | openBlocks++ 109 | } 110 | } 111 | closeChar -> { 112 | if (!openString && --openBlocks == 0) { 113 | return 114 | } 115 | } 116 | '"' -> { 117 | when(input[index - 1]) { 118 | '(' -> { 119 | require(!openString) { "Invalid input. Unbalanced string tag." } 120 | openString = true 121 | } 122 | '\\' -> { 123 | require(openString) { "Invalid input. Unexpected escaped quotes." } 124 | } 125 | else -> { 126 | require(index + 1 < input.length) { "Invalid input. Premature input ending." } 127 | when (input[index + 1]) { 128 | ')', '=' -> { 129 | require(openString) { "Invalid input. Unbalanced string tag." } 130 | openString = false 131 | endIndex++ 132 | } 133 | else -> { 134 | require(!openString) { "Invalid input. Unbalanced string tag." } 135 | openString = true 136 | } 137 | } 138 | } 139 | } 140 | } 141 | } 142 | findTheCloseBracket() 143 | } 144 | 145 | private companion object { 146 | private val constructors: Map NbtTag> = mapOf( 147 | "NbtByte" to ::NbtByte, 148 | "NbtShort" to ::NbtShort, 149 | "NbtInt" to ::NbtInt, 150 | "NbtLong" to ::NbtLong, 151 | "NbtFloat" to ::NbtFloat, 152 | "NbtDouble" to ::NbtDouble, 153 | "NbtByteArray" to ::NbtByteArray, 154 | "NbtString" to ::NbtString, 155 | "NbtList" to { value: String -> NbtList(value) }, 156 | "NbtCompound" to ::NbtCompound, 157 | "NbtIntArray" to ::NbtIntArray, 158 | "NbtLongArray" to ::NbtLongArray, 159 | ) 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/LittleEndianDataInputStream.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import java.io.* 4 | import java.lang.Double.longBitsToDouble 5 | import java.lang.Float.intBitsToFloat 6 | import java.lang.UnsupportedOperationException 7 | 8 | /** 9 | * Implementation of [DataInput] that reads data from an [InputStream] using little endian byte order. 10 | * @param in the underlying input stream. 11 | * @author joserobjr 12 | * @since 2020-10-20 13 | */ 14 | public class LittleEndianDataInputStream(`in`: InputStream) : FilterInputStream(`in`), DataInput { 15 | override fun readFully(b: ByteArray) { 16 | readFully(b, 0, b.size) 17 | } 18 | 19 | override fun readFully(b: ByteArray, off: Int, len: Int) { 20 | if (len < 0) { 21 | throw IndexOutOfBoundsException() 22 | } 23 | var n = 0 24 | while (n < len) { 25 | val count = `in`.read(b, off + n, len - n) 26 | if (count < 0) { 27 | throw EOFException() 28 | } 29 | n += count 30 | } 31 | } 32 | 33 | override fun skipBytes(n: Int): Int { 34 | if (n <= 0) { 35 | return 0 36 | } 37 | 38 | val toSkip = n.toLong() 39 | 40 | var total = 0L 41 | var cur: Long 42 | 43 | do { 44 | cur = `in`.skip(toSkip - total) 45 | if (cur <= 0) { 46 | break 47 | } 48 | total += cur 49 | } while (total < toSkip) 50 | 51 | return total.toInt() 52 | } 53 | 54 | override fun readBoolean(): Boolean { 55 | return readUnsignedByte() != 0 56 | } 57 | 58 | override fun readByte(): Byte { 59 | return readUnsignedByte().toByte() 60 | } 61 | 62 | override fun readUnsignedByte(): Int { 63 | val b1 = `in`.read() 64 | if (b1 < 0) { 65 | throw EOFException() 66 | } 67 | return b1 68 | } 69 | 70 | override fun readShort(): Short { 71 | return readUnsignedShort().toShort() 72 | } 73 | 74 | override fun readUnsignedShort(): Int { 75 | val b1 = `in`.read() 76 | val b2 = `in`.read() 77 | if (b1 or b2 < 0) { 78 | throw EOFException() 79 | } 80 | return (b2 shl 8) or b1 81 | } 82 | 83 | override fun readChar(): Char { 84 | return readUnsignedShort().toChar() 85 | } 86 | 87 | override fun readInt(): Int { 88 | val b1 = `in`.read() 89 | val b2 = `in`.read() 90 | val b3 = `in`.read() 91 | val b4 = `in`.read() 92 | if (b1 or b2 or b3 or b4 < 0) { 93 | throw EOFException() 94 | } 95 | return (b4 shl 24) or (b3 shl 16) or (b2 shl 8) or b1 96 | } 97 | 98 | override fun readLong(): Long { 99 | val b1 = `in`.read().toLong() 100 | val b2 = `in`.read().toLong() 101 | val b3 = `in`.read().toLong() 102 | val b4 = `in`.read().toLong() 103 | val b5 = `in`.read().toLong() 104 | val b6 = `in`.read().toLong() 105 | val b7 = `in`.read().toLong() 106 | val b8 = `in`.read().toLong() 107 | if (b1 or b2 or b3 or b4 or b5 or b6 or b7 or b8 < 0) { 108 | throw EOFException() 109 | } 110 | return (b8 shl 56) or (b7 shl 48) or (b6 shl 40) or (b5 shl 32) or 111 | (b4 shl 24) or (b3 shl 16) or (b2 shl 8) or b1 112 | } 113 | 114 | override fun readFloat(): Float { 115 | return intBitsToFloat(readInt()) 116 | } 117 | 118 | override fun readDouble(): Double { 119 | return longBitsToDouble(readLong()) 120 | } 121 | 122 | override fun readLine(): String { 123 | throw UnsupportedOperationException() 124 | } 125 | 126 | override fun readUTF(): String { 127 | return DataInputStream.readUTF(this) 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/LittleEndianDataOutputStream.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import java.io.* 4 | import java.lang.Double.doubleToLongBits 5 | import java.lang.Float.floatToIntBits 6 | import java.lang.Long.reverseBytes 7 | 8 | /** 9 | * Implementation of [DataOutput] that writes data to an [OutputStream] using little endian byte order. 10 | * @param out the underlying output stream. 11 | * @author joserobjr 12 | * @since 2020-10-20 13 | */ 14 | public class LittleEndianDataOutputStream(out: OutputStream) : FilterOutputStream(DataOutputStream(out)), DataOutput { 15 | private val data = out as DataOutputStream 16 | override fun writeBoolean(v: Boolean) { 17 | data.writeBoolean(v) 18 | } 19 | 20 | override fun writeByte(v: Int) { 21 | data.writeByte(v) 22 | } 23 | 24 | override fun writeShort(v: Int) { 25 | out.write(v and 0xFF) 26 | out.write((v ushr 8) and 0xFF) 27 | } 28 | 29 | override fun writeChar(v: Int) { 30 | writeShort(v) 31 | } 32 | 33 | override fun writeInt(v: Int) { 34 | out.write(v and 0xFF) 35 | out.write((v ushr 8) and 0xFF) 36 | out.write((v ushr 16) and 0xFF) 37 | out.write((v ushr 24) and 0xFF) 38 | } 39 | 40 | override fun writeLong(v: Long) { 41 | data.writeLong(reverseBytes(v)) 42 | } 43 | 44 | override fun writeFloat(v: Float) { 45 | writeInt(floatToIntBits(v)) 46 | } 47 | 48 | override fun writeDouble(v: Double) { 49 | writeLong(doubleToLongBits(v)) 50 | } 51 | 52 | override fun writeBytes(s: String) { 53 | data.writeBytes(s) 54 | } 55 | 56 | override fun writeChars(s: String) { 57 | s.forEach { char -> 58 | writeChar(char.code) 59 | } 60 | } 61 | 62 | override fun writeUTF(s: String) { 63 | val length = s.length 64 | if (length > 65535) { 65 | throw UTFDataFormatException("encoded string too long: $length bytes") 66 | } 67 | writeShort(length) 68 | write(s.toByteArray(Charsets.UTF_8)) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtByte.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a byte value. 5 | * @property signed A signed byte from `-128` to `127` 6 | */ 7 | public data class NbtByte(var signed: Byte) : NbtTag() { 8 | /** 9 | * Read or write the [signed] as a signed byte from `0` to `255`. 10 | */ 11 | var unsigned: Int 12 | get() = signed.toInt() and 0xFF 13 | set(value) { 14 | this.signed = (value and 0xFF).toByte() 15 | } 16 | 17 | /** 18 | * A signed byte from `-128` to `127`. 19 | */ 20 | @Deprecated( 21 | "Deprecated in favor of signed and unsigned flavours. Replace with the signed property.", 22 | ReplaceWith("signed") 23 | ) 24 | inline var value: Byte 25 | get() = signed 26 | set(value) { 27 | signed = value 28 | } 29 | 30 | /** 31 | * Returns a string representation of the tag's signed value. 32 | * 33 | * The returned string is compatible with string constructors of the same type. 34 | */ 35 | override val stringValue: String 36 | get() = signed.toString() 37 | 38 | /** 39 | * Wraps a byte `1` if the value is `true` and `0` otherwise. 40 | * @param value The value to be checked 41 | */ 42 | public constructor(value: Boolean): this(if (value) BYTE_TRUE else 0) 43 | 44 | /** 45 | * Converts the int value to an unsigned byte and wraps it. 46 | * @param unsigned Unsigned value from `0` to `255`. 47 | * @throws NumberFormatException if the number is not within the 0..255 range 48 | */ 49 | @Throws(NumberFormatException::class) 50 | public constructor(unsigned: Int): this(unsigned.let { 51 | if(it < 0 || it > 255) { 52 | throw NumberFormatException("Expected an unsigned byte of range 0 to 255. Got $it.") 53 | } 54 | it.toByte() 55 | }) 56 | 57 | /** 58 | * Parses the string value as a signed byte and wraps it. 59 | * @param signed Signed value from `-128` to `127`. 60 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 61 | */ 62 | @Throws(NumberFormatException::class) 63 | public constructor(signed: String): this(signed.toByte()) 64 | 65 | /** 66 | * Returns a new wrapper with the current value. 67 | */ 68 | override fun deepCopy(): NbtByte = copy() 69 | 70 | /** 71 | * A technical string representation of this tag, containing the tag type, and it's [signed] value, 72 | * appropriated for developer inspections. 73 | */ 74 | override fun toTechnicalString(): String { 75 | return "NbtByte($signed)" 76 | } 77 | 78 | public companion object { 79 | /** 80 | * Parses the string value as an unsigned byte and wraps it. 81 | * @param unsigned Unsigned value from `0` to `255`. 82 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 83 | */ 84 | @JvmStatic 85 | public fun unsigned(unsigned: String): NbtByte = NbtByte(unsigned = unsigned.toInt()) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtByteArray.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a mutable byte array. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtByteArray(var value: ByteArray): NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value with a structure similar to a normal [List]. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | * 13 | * Like [NbtByte], the bytes returned are signed, ranging from `-128` to `127`. 14 | * 15 | * Be aware that this may be a slow operation on big arrays. 16 | */ 17 | override val stringValue: String 18 | get() = value.takeIf { it.isNotEmpty() }?.joinToString(prefix = "[", postfix = "]") ?: "[]" 19 | 20 | /** 21 | * Creates a new tag with an empty array. 22 | */ 23 | public constructor(): this(byteArrayOf()) 24 | 25 | /** 26 | * Parses the string using the same structure which is returned by [stringValue]. 27 | * 28 | * The bytes should be signed, ranging from `-127` to `127`. 29 | * 30 | * @param value A string with a structure like `[0, -32, 48, 127]` 31 | * 32 | * @throws IllegalArgumentException if the string does not have the exact format outputted by [stringValue] 33 | */ 34 | @Throws(IllegalArgumentException::class) 35 | public constructor(value: String): this(value 36 | .removeSurrounding("[", "]") 37 | .split(", ") 38 | .takeIf { it.size > 1 || it.firstOrNull()?.isNotEmpty() == true } 39 | ?.map { it.toByte() } 40 | ?.toByteArray() 41 | ?: byteArrayOf() 42 | ) 43 | 44 | override fun toTechnicalString(): String { 45 | return "NbtByteArray$stringValue" 46 | } 47 | 48 | /** 49 | * Properly checks the equality of the array. 50 | */ 51 | override fun equals(other: Any?): Boolean { 52 | if (this === other) return true 53 | if (javaClass != other?.javaClass) return false 54 | 55 | other as NbtByteArray 56 | 57 | if (!value.contentEquals(other.value)) return false 58 | 59 | return true 60 | } 61 | 62 | /** 63 | * Properly calculates the hashcode of the array. 64 | */ 65 | override fun hashCode(): Int { 66 | return value.contentHashCode() 67 | } 68 | 69 | /** 70 | * Returns a new wrapper with a copy of the current value. 71 | */ 72 | override fun deepCopy(): NbtByteArray = copy(value = value.copyOf()) 73 | } 74 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtCompound.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which contains a [MutableMap] structure associating [String]s to [NbtTag]s. 5 | * 6 | * It's the main heart of NBT files and usually contains complex structures. 7 | * 8 | * The returned tags by this class will be linked, so modifications to it will also affect the compound value. 9 | * 10 | * All get functions which are not prefixed with `Nullable` and `get` will throw a [ClassCastException] 11 | * if the tag is mapped to a different class then the method used. For example if a given compound 12 | * have an example=NbtInt(2) and you try to read it using [NbtCompound.getShort], an exception will be thrown. 13 | * 14 | * All get functions which are not prefixed with `Nullable` and `get` will throw [NoSuchElementException] 15 | * if no value is mapped to the given name. This will change in the future. 16 | * 17 | * All get list functions which returns lists of specific types will throw [IllegalStateException] if the list content 18 | * does not match the requested type. 19 | * 20 | * @param value A [Map] which contains all key-value mappings. 21 | */ 22 | public class NbtCompound private constructor(private val value: LinkedHashMap) : NbtTag(), MutableMap by value { 23 | /** 24 | * Returns a string representation of the tag's value. 25 | * 26 | * The output will be similar to a normal [Map]. 27 | * 28 | * The class names of the children will expose. 29 | * 30 | * The returned string is compatible with string constructors of the same type. 31 | * 32 | * Be aware that this may be a slow operation on compounds. 33 | */ 34 | override val stringValue: String 35 | get() = value.takeIf { it.isNotEmpty() }?.entries?.joinToString(prefix = "{", postfix = "}") { (key, tag) -> 36 | '"' + key.replace("\\", "\\\\").replace("\"", "\\\"") + "\"=" + tag 37 | } ?: "{}" 38 | 39 | /** 40 | * Creates a new compound containing the same mappings as the given [Map]. 41 | * 42 | * The tags in the map will be linked so any modification will also change this tag contents. 43 | */ 44 | public constructor(value: Map): this(LinkedHashMap(value)) 45 | 46 | /** 47 | * Creates an empty compound. 48 | */ 49 | public constructor(): this(emptyMap()) 50 | 51 | /** 52 | * Creates a compound which maps the [Pair.first] value to the [Pair.second] tag initially. 53 | * 54 | * The given tags will be linked, so modifications to them will also affect the compound value. 55 | */ 56 | public constructor(vararg tags: Pair): this(mapOf(*tags)) 57 | 58 | /** 59 | * Creates a compound which maps the [Pair.first] value to the [Pair.second] tag initially. 60 | * 61 | * The given tags will be linked, so modifications to them will also affect the compound value. 62 | */ 63 | public constructor(tags: Iterable>): this(tags.toMap()) 64 | 65 | /** 66 | * @throws IllegalArgumentException if the string does not have the exact format outputted by [stringValue] 67 | */ 68 | @Throws(IllegalArgumentException::class) 69 | public constructor(value: String): this(NbtCompoundStringParser(value).parseCompound()) 70 | 71 | /** 72 | * Directly maps a [NbtTag] to a key. The value must not be [NbtEnd]. 73 | * The given tag will be linked, so modifications to it will also affect the compound value. 74 | */ 75 | public operator fun set(key: String, value: NbtTag) { 76 | put(key, value) 77 | } 78 | 79 | /** 80 | * Maps a [NbtByte] `1` if the value is `true` and `0` otherwise. 81 | */ 82 | public operator fun set(key: String, value: Boolean): Unit = set(key, if (value) BYTE_TRUE else 0) 83 | /** 84 | * Maps a [NbtByte] with the given value. 85 | */ 86 | public operator fun set(key: String, value: Byte): Unit = set(key, NbtByte(value)) 87 | /** 88 | * Maps a [NbtShort] with the given value. 89 | */ 90 | public operator fun set(key: String, value: Short): Unit = set(key, NbtShort(value)) 91 | /** 92 | * Maps a [NbtInt] with the given value. 93 | */ 94 | public operator fun set(key: String, value: Int): Unit = set(key, NbtInt(value)) 95 | /** 96 | * Maps a [NbtLong] with the given value. 97 | */ 98 | public operator fun set(key: String, value: Long): Unit = set(key, NbtLong(value)) 99 | /** 100 | * Maps a [NbtFloat] with the given value. 101 | */ 102 | public operator fun set(key: String, value: Float): Unit = set(key, NbtFloat(value)) 103 | /** 104 | * Maps a [NbtDouble] with the given value. 105 | */ 106 | public operator fun set(key: String, value: Double): Unit = set(key, NbtDouble(value)) 107 | /** 108 | * Maps a [NbtByteArray] with the given value. The array instance will be linked so any modification will also 109 | * change the tag value. 110 | */ 111 | public operator fun set(key: String, value: ByteArray): Unit = set(key, NbtByteArray(value)) 112 | /** 113 | * Maps a [NbtDouble] with the given value. 114 | */ 115 | public operator fun set(key: String, value: String): Unit = set(key, NbtString(value)) 116 | /** 117 | * Maps a [NbtByteArray] with the given value. The array instance will be linked so any modification will also 118 | * change the tag value. 119 | */ 120 | public operator fun set(key: String, value: IntArray): Unit = set(key, NbtIntArray(value)) 121 | /** 122 | * Maps a [NbtByteArray] with the given value. The array instance will be linked so any modification will also 123 | * change the tag value. 124 | */ 125 | public operator fun set(key: String, value: LongArray): Unit = set(key, NbtLongArray(value)) 126 | 127 | /** 128 | * Returns `true` if [getByte] returns `1`, `false` otherwise. 129 | * Will also return `false` if the value is not mapped. 130 | * @throws ClassCastException If the [NbtTag] is not a [NbtByte] 131 | */ 132 | @Throws(ClassCastException::class) 133 | public fun getNullableBooleanByte(key: String): Boolean = getNullableByte(key) == BYTE_TRUE 134 | /** 135 | * Returns `true` if [getByte] returns `1`, `false` otherwise. 136 | * @throws ClassCastException If the [NbtTag] is not a [NbtByte] 137 | * @throws NoSuchElementException If the key is not present on the compound 138 | */ 139 | @Throws(ClassCastException::class, NoSuchElementException::class) 140 | public fun getBooleanByte(key: String): Boolean = getByte(key) == BYTE_TRUE 141 | 142 | /** 143 | * Returns the value corresponding to the given [key], or throw an exception if such a key is not present in the compound. 144 | * @throws NoSuchElementException If the key is not present on the compound 145 | */ 146 | @Throws(NoSuchElementException::class) 147 | public fun require(key: String): NbtTag = get(key) ?: throw NoSuchElementException(key) 148 | 149 | /** 150 | * Returns the unwrapped byte value. 151 | * @throws ClassCastException If the [NbtTag] is not a [NbtByte] 152 | * @throws NoSuchElementException If the key is not present on the compound 153 | */ 154 | @Throws(ClassCastException::class, NoSuchElementException::class) 155 | public fun getByte(key: String): Byte = (require(key) as NbtByte).signed 156 | /** 157 | * Returns the unwrapped short value. 158 | * @throws ClassCastException If the [NbtTag] is not a [NbtShort] 159 | * @throws NoSuchElementException If the key is not present on the compound 160 | */ 161 | @Throws(ClassCastException::class, NoSuchElementException::class) 162 | public fun getShort(key: String): Short = (require(key) as NbtShort).value 163 | /** 164 | * Returns the unwrapped int value. 165 | * @throws ClassCastException If the [NbtTag] is not a [NbtInt] 166 | * @throws NoSuchElementException If the key is not present on the compound 167 | */ 168 | @Throws(ClassCastException::class, NoSuchElementException::class) 169 | public fun getInt(key: String): Int = (require(key) as NbtInt).value 170 | /** 171 | * Returns the unwrapped long value. 172 | * @throws ClassCastException If the [NbtTag] is not a [NbtLongArray] 173 | * @throws NoSuchElementException If the key is not present on the compound 174 | */ 175 | @Throws(ClassCastException::class, NoSuchElementException::class) 176 | public fun getLong(key: String): Long = (require(key) as NbtLong).value 177 | /** 178 | * Returns the unwrapped float value. 179 | * @throws ClassCastException If the [NbtTag] is not a [NbtFloat] 180 | * @throws NoSuchElementException If the key is not present on the compound 181 | */ 182 | @Throws(ClassCastException::class, NoSuchElementException::class) 183 | public fun getFloat(key: String): Float = (require(key) as NbtFloat).value 184 | /** 185 | * Returns the unwrapped double value. 186 | * @throws ClassCastException If the [NbtTag] is not a [NbtDouble] 187 | * @throws NoSuchElementException If the key is not present on the compound 188 | */ 189 | @Throws(ClassCastException::class, NoSuchElementException::class) 190 | public fun getDouble(key: String): Double = (require(key) as NbtDouble).value 191 | /** 192 | * Returns the unwrapped byte array value. The array will be linked and any modification will 193 | * also change wrapper and the mapped value. 194 | * @throws ClassCastException If the [NbtTag] is not a [NbtByteArray] 195 | * @throws NoSuchElementException If the key is not present on the compound 196 | */ 197 | @Throws(ClassCastException::class, NoSuchElementException::class) 198 | public fun getByteArray(key: String): ByteArray = (require(key) as NbtByteArray).value 199 | /** 200 | * Returns the unwrapped string value. 201 | * @throws ClassCastException If the [NbtTag] is not a [NbtString] 202 | * @throws NoSuchElementException If the key is not present on the compound 203 | */ 204 | @Throws(ClassCastException::class, NoSuchElementException::class) 205 | public fun getString(key: String): String = (require(key) as NbtString).value 206 | /** 207 | * Returns the unwrapped int array value. The array will be linked and any modification will 208 | * also change wrapper and the mapped value. 209 | * @throws ClassCastException If the [NbtTag] is not a [NbtIntArray] 210 | * @throws NoSuchElementException If the key is not present on the compound 211 | */ 212 | @Throws(ClassCastException::class, NoSuchElementException::class) 213 | public fun getIntArray(key: String): IntArray = (require(key) as NbtIntArray).value 214 | /** 215 | * Returns the unwrapped long array value. The array will be linked and any modification will 216 | * also change wrapper and the mapped value. 217 | * @throws ClassCastException If the [NbtTag] is not a [NbtLongArray] 218 | * @throws NoSuchElementException If the key is not present on the compound 219 | */ 220 | @Throws(ClassCastException::class, NoSuchElementException::class) 221 | public fun getLongArray(key: String): LongArray = (require(key) as NbtLongArray).value 222 | /** 223 | * Returns the [NbtCompound] mapped to that key. The tag will be linked and any modification will 224 | * also change the mapped value. 225 | * @throws ClassCastException If the [NbtTag] is not a [NbtCompound] 226 | * @throws NoSuchElementException If the key is not present on the compound 227 | */ 228 | @Throws(ClassCastException::class, NoSuchElementException::class) 229 | public fun getCompound(key: String): NbtCompound = require(key) as NbtCompound 230 | /** 231 | * Returns the [NbtList] mapped to that key. The tag will be linked and any modification will 232 | * also change the mapped value. 233 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 234 | * @throws NoSuchElementException If the key is not present on the compound 235 | */ 236 | @Throws(ClassCastException::class, NoSuchElementException::class) 237 | public fun getList(key: String): NbtList<*> = require(key) as NbtList<*> 238 | 239 | /** 240 | * Returns the [NbtList] of bytes mapped to that key. The tag will be linked and any modification will 241 | * also change the mapped value. 242 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 243 | * @throws NoSuchElementException If the key is not present on the compound 244 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtByte] 245 | */ 246 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 247 | public fun getByteList(key: String): NbtList = getList(key).cast() 248 | /** 249 | * Returns the [NbtList] of shorts mapped to that key. The tag will be linked and any modification will 250 | * also change the mapped value. 251 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 252 | * @throws NoSuchElementException If the key is not present on the compound 253 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtShort] 254 | */ 255 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 256 | public fun getShortList(key: String): NbtList = getList(key).cast() 257 | /** 258 | * Returns the [NbtList] of integers mapped to that key. The tag will be linked and any modification will 259 | * also change the mapped value. 260 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 261 | * @throws NoSuchElementException If the key is not present on the compound 262 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtIntArray] 263 | */ 264 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 265 | public fun getIntList(key: String): NbtList = getList(key).cast() 266 | /** 267 | * Returns the [NbtList] of longs mapped to that key. The tag will be linked and any modification will 268 | * also change the mapped value. 269 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 270 | * @throws NoSuchElementException If the key is not present on the compound 271 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtLong] 272 | */ 273 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 274 | public fun getLongList(key: String): NbtList = getList(key).cast() 275 | /** 276 | * Returns the [NbtList] of floats mapped to that key. The tag will be linked and any modification will 277 | * also change the mapped value. 278 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 279 | * @throws NoSuchElementException If the key is not present on the compound 280 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtFloat] 281 | */ 282 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 283 | public fun getFloatList(key: String): NbtList = getList(key).cast() 284 | /** 285 | * Returns the [NbtList] of doubles mapped to that key. The tag will be linked and any modification will 286 | * also change the mapped value. 287 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 288 | * @throws NoSuchElementException If the key is not present on the compound 289 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtDouble] 290 | */ 291 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 292 | public fun getDoubleList(key: String): NbtList = getList(key).cast() 293 | /** 294 | * Returns the [NbtList] of byte arrays mapped to that key. The tag and it's value will be linked and any modification will 295 | * also change the mapped value. 296 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 297 | * @throws NoSuchElementException If the key is not present on the compound 298 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtByteArray] 299 | */ 300 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 301 | public fun getByteArrayList(key: String): NbtList = getList(key).cast() 302 | /** 303 | * Returns the [NbtList] of strings mapped to that key. The tag will be linked and any modification will 304 | * also change the mapped value. 305 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 306 | * @throws NoSuchElementException If the key is not present on the compound 307 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtString] 308 | */ 309 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 310 | public fun getStringList(key: String): NbtList = getList(key).cast() 311 | /** 312 | * Returns the [NbtList] of int arrays mapped to that key. The tag and it's value will be linked and any modification will 313 | * also change the mapped value. 314 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 315 | * @throws NoSuchElementException If the key is not present on the compound 316 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtIntArray] 317 | */ 318 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 319 | public fun getIntArrayList(key: String): NbtList = getList(key).cast() 320 | /** 321 | * Returns the [NbtList] of long arrays mapped to that key. The tag and it's values will be linked and any modification will 322 | * also change the mapped value. 323 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 324 | * @throws NoSuchElementException If the key is not present on the compound 325 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtLongArray] 326 | */ 327 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 328 | public fun getLongArrayList(key: String): NbtList = getList(key).cast() 329 | /** 330 | * Returns the [NbtList] of compounds mapped to that key. The tag and it's values will be linked and any modification will 331 | * also change the mapped value. 332 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 333 | * @throws NoSuchElementException If the key is not present on the compound 334 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtCompound] 335 | */ 336 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 337 | public fun getCompoundList(key: String): NbtList = getList(key).cast() 338 | /** 339 | * Returns the [NbtList] of lists mapped to that key. The tag and it's values will be linked and any modification will 340 | * also change the mapped value. 341 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 342 | * @throws NoSuchElementException If the key is not present on the compound 343 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtList] 344 | */ 345 | @Throws(ClassCastException::class, NoSuchElementException::class, IllegalStateException::class) 346 | public fun getListOfList(key: String): NbtList> = getList(key).cast() 347 | 348 | /** 349 | * Returns the unwrapped byte value or null if no value is mapped, or it is mapped to another type tag. 350 | * @throws ClassCastException If the [NbtTag] is not a [NbtByte] 351 | */ 352 | @Throws(ClassCastException::class) 353 | public fun getNullableByte(key: String): Byte? = this[key]?.let { it as NbtByte }?.signed 354 | /** 355 | * Returns the unwrapped short value or null if no value is mapped, or it is mapped to another type tag. 356 | * @throws ClassCastException If the [NbtTag] is not a [NbtShort] 357 | */ 358 | @Throws(ClassCastException::class) 359 | public fun getNullableShort(key: String): Short? = this[key]?.let { it as NbtShort }?.value 360 | /** 361 | * Returns the unwrapped int value or null if no value is mapped, or it is mapped to another type tag. 362 | * @throws ClassCastException If the [NbtTag] is not a [NbtInt] 363 | */ 364 | @Throws(ClassCastException::class) 365 | public fun getNullableInt(key: String): Int? = this[key]?.let { it as NbtInt }?.value 366 | /** 367 | * Returns the unwrapped long value or null if no value is mapped, or it is mapped to another type tag. 368 | * @throws ClassCastException If the [NbtTag] is not a [NbtLong] 369 | */ 370 | @Throws(ClassCastException::class) 371 | public fun getNullableLong(key: String): Long? = this[key]?.let { it as NbtLong }?.value 372 | /** 373 | * Returns the unwrapped float value or null if no value is mapped, or it is mapped to another type tag. 374 | * @throws ClassCastException If the [NbtTag] is not a [NbtFloat] 375 | */ 376 | @Throws(ClassCastException::class) 377 | public fun getNullableFloat(key: String): Float? = this[key]?.let { it as NbtFloat }?.value 378 | /** 379 | * Returns the unwrapped double value or null if no value is mapped, or it is mapped to another type tag. 380 | * @throws ClassCastException If the [NbtTag] is not a [NbtDouble] 381 | */ 382 | @Throws(ClassCastException::class) 383 | public fun getNullableDouble(key: String): Double? = this[key]?.let { it as NbtDouble }?.value 384 | /** 385 | * Returns the unwrapped byte array value. The array will be linked and any modification will 386 | * also change wrapper and the mapped value. 387 | * 388 | * Will return null if no value is mapped, or it is mapped to another type tag. 389 | * @throws ClassCastException If the [NbtTag] is not a [NbtByteArray] 390 | */ 391 | @Throws(ClassCastException::class) 392 | public fun getNullableByteArray(key: String): ByteArray? = this[key]?.let { it as NbtByteArray }?.value 393 | /** 394 | * Returns the unwrapped string value or null if no value is mapped, or it is mapped to another type tag. 395 | * @throws ClassCastException If the [NbtTag] is not a [NbtString] 396 | */ 397 | @Throws(ClassCastException::class) 398 | public fun getNullableString(key: String): String? = this[key]?.let { it as NbtString }?.value 399 | /** 400 | * Returns the unwrapped int array value. The array will be linked and any modification will 401 | * also change wrapper and the mapped value. 402 | * 403 | * Will return null if no value is mapped, or it is mapped to another type tag. 404 | * @throws ClassCastException If the [NbtTag] is not a [NbtIntArray] 405 | */ 406 | @Throws(ClassCastException::class) 407 | public fun getNullableIntArray(key: String): IntArray? = this[key]?.let { it as NbtIntArray }?.value 408 | /** 409 | * Returns the unwrapped long array value. The array will be linked and any modification will 410 | * also change wrapper and the mapped value. 411 | * 412 | * Will return null if no value is mapped, or it is mapped to another type tag. 413 | * @throws ClassCastException If the [NbtTag] is not a [NbtLongArray] 414 | */ 415 | @Throws(ClassCastException::class) 416 | public fun getNullableLongArray(key: String): LongArray? = this[key]?.let { it as NbtLongArray }?.value 417 | /** 418 | * Returns the [NbtCompound] mapped to that key. The tag will be linked and any modification will 419 | * also change the mapped value. 420 | * 421 | * Will return null if no value is mapped, or it is mapped to another type tag. 422 | * @throws ClassCastException If the [NbtTag] is not a [NbtCompound] 423 | */ 424 | @Throws(ClassCastException::class) 425 | public fun getNullableCompound(key: String): NbtCompound? = this[key]?.let { it as NbtCompound } 426 | /** 427 | * Returns the [NbtList] mapped to that key. The tag will be linked and any modification will 428 | * also change the mapped value. 429 | * 430 | * Will return null if no value is mapped, or it is mapped to another type tag. 431 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 432 | */ 433 | @Throws(ClassCastException::class) 434 | public fun getNullableList(key: String): NbtList<*>? = this[key]?.let { it as NbtList<*> } 435 | 436 | /** 437 | * Returns the [NbtList] of bytes mapped to that key. The tag will be linked and any modification will 438 | * also change the mapped value. 439 | * 440 | * Will return null if no value is mapped, or it is mapped to another type tag. 441 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 442 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtByte] 443 | */ 444 | @Throws(ClassCastException::class, IllegalStateException::class) 445 | public fun getNullableByteList(key: String): NbtList? = getNullableList(key)?.cast() 446 | /** 447 | * Returns the [NbtList] of shorts mapped to that key. The tag will be linked and any modification will 448 | * also change the mapped value. 449 | * 450 | * Will return null if no value is mapped, or it is mapped to another type tag. 451 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 452 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtShort] 453 | */ 454 | @Throws(ClassCastException::class, IllegalStateException::class) 455 | public fun getNullableShortList(key: String): NbtList? = getNullableList(key)?.cast() 456 | /** 457 | * Returns the [NbtList] of integers mapped to that key. The tag will be linked and any modification will 458 | * also change the mapped value. 459 | * 460 | * Will return null if no value is mapped, or it is mapped to another type tag. 461 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 462 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtIntArray] 463 | */ 464 | @Throws(ClassCastException::class, IllegalStateException::class) 465 | public fun getNullableIntList(key: String): NbtList? = getNullableList(key)?.cast() 466 | /** 467 | * Returns the [NbtList] of longs mapped to that key. The tag will be linked and any modification will 468 | * also change the mapped value. 469 | * 470 | * Will return null if no value is mapped, or it is mapped to another type tag. 471 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 472 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtLong] 473 | */ 474 | @Throws(ClassCastException::class, IllegalStateException::class) 475 | public fun getNullableLongList(key: String): NbtList? = getNullableList(key)?.cast() 476 | /** 477 | * Returns the [NbtList] of floats mapped to that key. The tag will be linked and any modification will 478 | * also change the mapped value. 479 | * 480 | * Will return null if no value is mapped, or it is mapped to another type tag. 481 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 482 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtFloat] 483 | */ 484 | @Throws(ClassCastException::class, IllegalStateException::class) 485 | public fun getNullableFloatList(key: String): NbtList? = getNullableList(key)?.cast() 486 | /** 487 | * Returns the [NbtList] of doubles mapped to that key. The tag will be linked and any modification will 488 | * also change the mapped value. 489 | * 490 | * Will return null if no value is mapped, or it is mapped to another type tag. 491 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 492 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtDouble] 493 | */ 494 | @Throws(ClassCastException::class, IllegalStateException::class) 495 | public fun getNullableDoubleList(key: String): NbtList? = getNullableList(key)?.cast() 496 | /** 497 | * Returns the [NbtList] of byte arrays mapped to that key. The tag and it's value will be linked and any modification will 498 | * also change the mapped value. 499 | * 500 | * Will return null if no value is mapped, or it is mapped to another type tag. 501 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 502 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtByteArray] 503 | */ 504 | @Throws(ClassCastException::class, IllegalStateException::class) 505 | public fun getNullableByteArrayList(key: String): NbtList? = getNullableList(key)?.cast() 506 | /** 507 | * Returns the [NbtList] of strings mapped to that key. The tag will be linked and any modification will 508 | * also change the mapped value. 509 | * 510 | * Will return null if no value is mapped, or it is mapped to another type tag. 511 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 512 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtString] 513 | */ 514 | @Throws(ClassCastException::class, IllegalStateException::class) 515 | public fun getNullableStringList(key: String): NbtList? = getNullableList(key)?.cast() 516 | /** 517 | * Returns the [NbtList] of int arrays mapped to that key. The tag and it's value will be linked and any modification will 518 | * also change the mapped value. 519 | * 520 | * Will return null if no value is mapped, or it is mapped to another type tag. 521 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 522 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtIntArray] 523 | */ 524 | @Throws(ClassCastException::class, IllegalStateException::class) 525 | public fun getNullableIntArrayList(key: String): NbtList? = getNullableList(key)?.cast() 526 | /** 527 | * Returns the [NbtList] of long arrays mapped to that key. The tag and it's values will be linked and any modification will 528 | * also change the mapped value. 529 | * 530 | * Will return null if no value is mapped, or it is mapped to another type tag. 531 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 532 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtLongArray] 533 | */ 534 | @Throws(ClassCastException::class, IllegalStateException::class) 535 | public fun getNullableLongArrayList(key: String): NbtList? = getNullableList(key)?.cast() 536 | /** 537 | * Returns the [NbtList] of compounds mapped to that key. The tag and it's values will be linked and any modification will 538 | * also change the mapped value. 539 | * 540 | * Will return null if no value is mapped, or it is mapped to another type tag. 541 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 542 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtCompound] 543 | */ 544 | @Throws(ClassCastException::class, IllegalStateException::class) 545 | public fun getNullableCompoundList(key: String): NbtList? = getNullableList(key)?.cast() 546 | /** 547 | * Returns the [NbtList] of lists mapped to that key. The tag and it's values will be linked and any modification will 548 | * also change the mapped value. 549 | * 550 | * Will return null if no value is mapped, or it is mapped to another type tag. 551 | * @throws ClassCastException If the [NbtTag] is not a [NbtList] 552 | * @throws IllegalStateException If the list is not empty and contains any tag with class different then [NbtList] 553 | */ 554 | @Throws(ClassCastException::class, IllegalStateException::class) 555 | public fun getNullableListOfList(key: String): NbtList>? = getNullableList(key)?.cast() 556 | 557 | /** 558 | * Checks if the other compound have a given tag, if it has been placed it in this compound. 559 | * 560 | * The tag will be linked, so any change in the tag will also affect both compounds. 561 | * @param other The compound that will be checked 562 | * @param tagKey The name of the tag that will be mapped 563 | * @param default If the other compound doesn't have the tag then this parameter will be used. 564 | */ 565 | public fun copyFrom(other: NbtCompound, tagKey: String, default: NbtTag? = null) { 566 | val tag = other[tagKey] ?: default 567 | if (tag != null) { 568 | this[tagKey] = tag 569 | } 570 | } 571 | 572 | /** 573 | * Checks if the compound have a given tag, if it has been placed it in the other compound. 574 | * 575 | * The tag will be linked, so any change in the tag will also affect both compounds. 576 | * @param other The compound that will be modified 577 | * @param tagKey The name of the tag that will be mapped 578 | * @param default If the compound doesn't have the tag then this parameter will be used. 579 | */ 580 | public fun copyTo(other: NbtCompound, tagKey: String, default: NbtTag? = null) { 581 | val tag = this[tagKey] ?: default 582 | if (tag != null) { 583 | other[tagKey] = tag 584 | } 585 | } 586 | 587 | /** 588 | * Returns a new NbtCompound with all nested values copied deeply. 589 | */ 590 | override fun deepCopy(): NbtCompound = NbtCompound(mapValues { it.value.deepCopy() }) 591 | 592 | /** 593 | * A technical string representation of this tag, containing the tag type, and it's value, 594 | * appropriated for developer inspections. 595 | * 596 | * The output will be similar to a normal [Map]. 597 | * 598 | * Be aware that this may be a slow operation on compounds. 599 | */ 600 | override fun toTechnicalString(): String { 601 | if (value.isEmpty()) { 602 | return "NbtCompound{}" 603 | } 604 | return "NbtCompound$stringValue" 605 | /*return buildString { 606 | append("NbtCompound{") 607 | val iterator = value.iterator() 608 | while (iterator.hasNext()) { 609 | val (key, tag) = iterator.next() 610 | append(key).append('=').append(tag) 611 | if (iterator.hasNext()) { 612 | append(", ") 613 | } 614 | } 615 | append('}') 616 | }*/ 617 | } 618 | 619 | override fun equals(other: Any?): Boolean { 620 | return value == other 621 | } 622 | 623 | override fun hashCode(): Int { 624 | return value.hashCode() 625 | } 626 | 627 | } 628 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtCompoundStringParser.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | internal class NbtCompoundStringParser(value: String): ComplexNbtStringParser('{', '}', value) { 4 | 5 | private val result = LinkedHashMap() 6 | 7 | internal fun parseCompound(): LinkedHashMap { 8 | if (input.isEmpty()) { 9 | return result 10 | } 11 | 12 | check(endIndex == -2) { 13 | "Already processed." 14 | } 15 | 16 | endIndex = 0 17 | 18 | parseEntries() 19 | return result 20 | } 21 | 22 | private tailrec fun parseEntries() { 23 | require(input[endIndex] == '"') { "Invalid input. Expected an open quote." } 24 | startIndex = endIndex 25 | val key = parseKey() 26 | startIndex = endIndex + 2 27 | require(startIndex < input.length) { "Invalid input. Expected entry value." } 28 | val tag = parseTag() 29 | result[key] = tag 30 | if (tag.javaClass == NbtString::class.java) { 31 | endIndex += 2 32 | } else if (closeChar == ')') { 33 | endIndex++ 34 | } 35 | if (endIndex < input.length) { 36 | require(endIndex + 3 < input.length) { "Invalid input. Expected more entries." } 37 | require(input.substring(endIndex, endIndex + 2) == ", ") { "Invalid input. Incorrect entry separator." } 38 | endIndex += 2 39 | parseEntries() 40 | } 41 | } 42 | 43 | private fun parseKey(): String { 44 | startIndex++ 45 | return findClosingQuote("\"=") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtDouble.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a double value. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtDouble(var value: Double) : NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | */ 13 | override val stringValue: String 14 | get() = value.toString() 15 | 16 | /** 17 | * Parses the string value as a signed double and wraps it. 18 | * @param signed Signed value from `4.9e-324` to `1.7976931348623157e+308`. NaN and Infinity are also accepted. 19 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 20 | */ 21 | @Throws(NumberFormatException::class) 22 | public constructor(signed: String): this(signed.toDouble()) 23 | 24 | /** 25 | * Returns a new wrapper with the current value. 26 | */ 27 | override fun deepCopy(): NbtDouble = copy() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtEnd.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A special tag which indicates the end of a compound stream or empty lists. 5 | * 6 | * Should not be used directly. 7 | */ 8 | public object NbtEnd : NbtTag() { 9 | /** 10 | * Returns an empty string. 11 | */ 12 | override val stringValue: String 13 | get() = "" 14 | 15 | /** 16 | * Returns `"NbtEnd"`. 17 | */ 18 | override fun toTechnicalString(): String { 19 | return "NbtEnd" 20 | } 21 | 22 | /** 23 | * Returns itself. 24 | */ 25 | override fun deepCopy(): NbtEnd = NbtEnd 26 | } 27 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtFile.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * The root component of a file, it contains a hint for the file name and the first tag in the file. 5 | * @property name The key for the file name. Empty in most cases. 6 | * @property tag The first tag in the file. A [NbtCompound] in most cases. 7 | * @property compound A shortcut to read or write [NbtFile.tag] as a [NbtCompound]. 8 | * @property version The version of the data stored in this file. 9 | * @property length The length of the file which is cached in the file's header. 10 | * @property isCompressed If the file needed to be uncompressed to load. 11 | * @property isLittleEndian If the file's byte order is little endian instead of big endian. 12 | * Will throw a [ClassCastException] if the tag value is not a [NbtCompound] 13 | */ 14 | public data class NbtFile @JvmOverloads constructor( 15 | var name: String, 16 | var tag: NbtTag, 17 | var version: Int? = null, 18 | var length: Int? = null, 19 | var isCompressed: Boolean? = null, 20 | var isLittleEndian: Boolean? = null 21 | ) { 22 | @Suppress("MemberVisibilityCanBePrivate") 23 | public var compound: NbtCompound 24 | @Throws(ClassCastException::class) 25 | get() = tag as NbtCompound 26 | set(value) { 27 | tag = value 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtFloat.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a float value. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtFloat(var value: Float) : NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | */ 13 | override val stringValue: String 14 | get() = value.toString() 15 | 16 | /** 17 | * Parses the string value as a signed float and wraps it. 18 | * @param signed Signed value from `1.4e-45` to `3.4028235e+38`. NaN and Infinity are also accepted. 19 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 20 | */ 21 | @Throws(NumberFormatException::class) 22 | public constructor(signed: String): this(signed.toFloat()) 23 | 24 | /** 25 | * Returns a new wrapper with the current value. 26 | */ 27 | override fun deepCopy(): NbtFloat = copy() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtIO.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("_NbtIO_Internal") 2 | 3 | package br.com.gamemods.nbtmanipulator 4 | 5 | import java.io.* 6 | import java.util.zip.GZIPInputStream 7 | import java.util.zip.GZIPOutputStream 8 | import kotlin.reflect.KClass 9 | import kotlin.reflect.cast 10 | 11 | /** 12 | * Contains useful methods do read and write [NbtFile] from [File] and [InputStream]/[OutputStream]. 13 | */ 14 | public object NbtIO { 15 | /** 16 | * Calls [writeNbtFile] using the information stored in the [NbtFile], uses the method's default when the information 17 | * is missing (null). This method does not write the Bedrock Edition version and length headers. 18 | * @param outputStream The stream that the file will be written 19 | * @param file The file that will be written to the stream 20 | */ 21 | @JvmStatic 22 | @Throws(IOException::class) 23 | public fun writeNbtFileAsOriginal(outputStream: OutputStream, file: NbtFile) { 24 | writeNbtFile(outputStream, file, 25 | compressed = file.isCompressed ?: true, 26 | littleEndian = file.isLittleEndian ?: false 27 | ) 28 | } 29 | 30 | /** 31 | * Writes the [NbtFile] in the stream. This method does not write the Bedrock Edition version and length headers. 32 | * @param outputStream The stream that the file will be written 33 | * @param file The file that will be written to the stream 34 | * @param compressed If the file will be compressed by [GZIPOutputStream]. 35 | * @param littleEndian Uses little endian to write to the stream as in Bedrock Edition 36 | */ 37 | @JvmStatic 38 | @Throws(IOException::class) 39 | @JvmOverloads 40 | public fun writeNbtFile(outputStream: OutputStream, file: NbtFile, compressed: Boolean = true, littleEndian: Boolean = false) { 41 | val output = if (compressed) GZIPOutputStream(outputStream) else outputStream 42 | val dataOut: DataOutput = if (littleEndian) LittleEndianDataOutputStream(output) else DataOutputStream(output) 43 | writeNbtFileDirectly(dataOut, file) 44 | (dataOut as OutputStream).flush() 45 | if (output is GZIPOutputStream) { 46 | output.finish() 47 | } 48 | } 49 | 50 | /** 51 | * Writes the [NbtFile] to the output. This method does not write the Bedrock Edition version and length headers. 52 | * @param output Where the file will be written, needs to handle compression and endianness. 53 | * @param file The file that will be written to the output 54 | */ 55 | @JvmStatic 56 | @Throws(IOException::class) 57 | public fun writeNbtFileDirectly(output: DataOutput, file: NbtFile) { 58 | val tag = file.tag 59 | val typeId = tag.typeId 60 | val serializer = serializers[typeId] 61 | output.writeByte(typeId) 62 | output.writeUTF(file.name) 63 | 64 | serializer.writeTag(output, tag) 65 | } 66 | 67 | /** 68 | * Writes the [NbtFile] in a [File]. 69 | * @param file The output file 70 | * @param file The NBT file that will be written on the output file 71 | * @param compressed If the file will be compressed by [GZIPOutputStream] 72 | * @param littleEndian Uses little endian to write to the stream as in Bedrock Edition 73 | * @param writeHeaders Writes the [NbtFile.version] and content size headers to the file. 74 | * The [NbtFile.length] property will be updated when this flag is set to true. 75 | * If [NbtFile.version] is null when this flag is true, `0` is assumed. 76 | * The header is always written in little endian regardless of the [littleEndian] param. 77 | */ 78 | @JvmStatic 79 | @Throws(IOException::class) 80 | @JvmOverloads 81 | public fun writeNbtFile( 82 | file: File, tag: NbtFile, compressed: Boolean = true, 83 | littleEndian: Boolean = false, writeHeaders: Boolean = false 84 | ) { 85 | if (!writeHeaders) { 86 | file.outputStream().buffered().use { stream -> 87 | writeNbtFile(stream, tag, compressed, littleEndian) 88 | stream.flush() 89 | } 90 | } else { 91 | RandomAccessFile(file, "rw").use { openFile -> 92 | openFile.setLength(8) 93 | FileOutputStream(openFile.fd).buffered().let { stream -> 94 | with(LittleEndianDataOutputStream(stream)) { 95 | writeInt(tag.version ?: 0) 96 | writeInt(0) 97 | flush() 98 | } 99 | writeNbtFile(stream, tag, compressed, littleEndian) 100 | stream.flush() 101 | } 102 | 103 | val fileLength = openFile.length() - 8L 104 | val intLength = if (fileLength > Int.MAX_VALUE) Int.MAX_VALUE else fileLength.toInt() 105 | tag.length = intLength 106 | 107 | openFile.seek(8) 108 | with(LittleEndianDataOutputStream(FileOutputStream(openFile.fd))) { 109 | writeInt(intLength) 110 | flush() 111 | } 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * Read a [NbtFile] from the [InputStream]. 118 | * @param inputStream The input stream that will be read 119 | * @param compressed If the file needs to be decompressed by [GZIPInputStream] 120 | * @param littleEndian Reads the NBT file using little endian byte order 121 | * @param readHeaders Reads the NBT version and length headers before the content 122 | * These data are read in little endian byte order regardless of the [littleEndian] parameter. 123 | */ 124 | @JvmStatic 125 | @Throws(IOException::class) 126 | @JvmOverloads 127 | public fun readNbtFile( 128 | inputStream: InputStream, compressed: Boolean = true, 129 | littleEndian: Boolean = false, readHeaders: Boolean = false 130 | ): NbtFile { 131 | var version: Int? = null 132 | var length: Int? = null 133 | 134 | if (readHeaders) { 135 | with(LittleEndianDataInputStream(inputStream)) { 136 | version = readInt() 137 | length = readInt() 138 | } 139 | } 140 | 141 | val input = if (compressed) GZIPInputStream(inputStream) else inputStream 142 | val dataIn: DataInput = if (littleEndian) LittleEndianDataInputStream(input) else DataInputStream(input) 143 | val nbtFile = readNbtFileDirectly(dataIn) 144 | nbtFile.version = version 145 | nbtFile.length = length 146 | nbtFile.isCompressed = compressed 147 | nbtFile.isLittleEndian = littleEndian 148 | return nbtFile 149 | } 150 | 151 | /** 152 | * Reads a [NbtFile] from the input. This method does not read the Bedrock Edition version and length headers. 153 | * @param input Where the file will be read, needs to handle compression and endianness. 154 | */ 155 | @JvmStatic 156 | @Throws(IOException::class) 157 | public fun readNbtFileDirectly(input: DataInput): NbtFile { 158 | val typeId = input.readUnsignedByte() 159 | val serializer = serializers[typeId] 160 | 161 | val name = input.readUTF() 162 | 163 | return NbtFile(name, serializer.readTag(input)) 164 | } 165 | 166 | /** 167 | * Read a [NbtFile] from a [File]. 168 | * @param file The input file that will be read 169 | * @param compressed If the file needs to be decompressed by [GZIPInputStream] 170 | * @param littleEndian 171 | * @param readHeaders 172 | */ 173 | @JvmStatic 174 | @Throws(IOException::class) 175 | @JvmOverloads 176 | public fun readNbtFile( 177 | file: File, compressed: Boolean = true, 178 | littleEndian: Boolean = false, 179 | readHeaders: Boolean = false 180 | ): NbtFile { 181 | return file.inputStream().buffered().use { readNbtFile(it, compressed, littleEndian, readHeaders) } 182 | } 183 | 184 | 185 | /** 186 | * Does an exhaustive attempts to load the NBT file, returning it if any of the attempts is successful. 187 | * @param file 188 | */ 189 | @JvmStatic 190 | @Throws(IOException::class) 191 | public fun readNbtFileDetectingSettings(file: File): NbtFile { 192 | RandomAccessFile(file, "r").use { openFile -> 193 | var ex: IOException? = null 194 | fun retry(compressed: Boolean, littleEndian: Boolean, readHeaders: Boolean): NbtFile? { 195 | return try { 196 | openFile.seek(0) 197 | readNbtFile(FileInputStream(openFile.fd).buffered(), compressed, littleEndian, readHeaders) 198 | } catch (e: IOException) { 199 | val lastEx = ex 200 | if (lastEx == null) { 201 | ex = lastEx 202 | } else { 203 | lastEx.addSuppressed(e) 204 | } 205 | null 206 | } 207 | } 208 | return retry(compressed = true, littleEndian = false, readHeaders = false) // Java's level.dat 209 | ?: retry(compressed = false, littleEndian = true, readHeaders = true) // Bedrock's level.dat 210 | ?: retry(compressed = true, littleEndian = false, readHeaders = true) // Trying all possibilities 211 | ?: retry(compressed = true, littleEndian = true, readHeaders = false) 212 | ?: retry(compressed = true, littleEndian = true, readHeaders = true) 213 | ?: retry(compressed = false, littleEndian = false, readHeaders = false) 214 | ?: retry(compressed = false, littleEndian = false, readHeaders = true) 215 | ?: retry(compressed = false, littleEndian = true, readHeaders = false) 216 | ?: retry(compressed = false, littleEndian = true, readHeaders = true) 217 | ?: throw IOException("Could not load the NbtFile $file with any settings", ex) 218 | } 219 | } 220 | 221 | /** 222 | * Writes the [NbtTag] directly, without name and optionally without type id. 223 | * @param output Where the file will be written, needs to handle compression and endianness. 224 | * @param tag The tag that will be written to the output 225 | * @param writeTypeId If the first byte written should be the NBT tag type id. 226 | */ 227 | @JvmStatic 228 | @Throws(IOException::class) 229 | public fun writeNbtTagDirectly(output: DataOutput, tag: NbtTag, writeTypeId: Boolean = true) { 230 | val typeId = tag.typeId 231 | val serializer = serializers[typeId] 232 | output.takeIf { writeTypeId }?.writeByte(typeId) 233 | serializer.writeTag(output, tag) 234 | } 235 | 236 | /** 237 | * Reads a [NbtTag] of type [T] from the input directly, this is a reader for [writeNbtTagDirectly]. 238 | * @param input Where the file will be read, needs to handle compression and endianness. 239 | * @param tagType The type of the tag that will be read, use `null` if the tag was written with `writeTypeId` enabled 240 | * @throws IllegalArgumentException If [T] is exactly [NbtTag]. 241 | */ 242 | @JvmStatic 243 | @Throws(IOException::class, IllegalArgumentException::class) 244 | public fun readNbtTagDirectly(input: DataInput, tagType: Class? = null): T { 245 | if (tagType == null) { 246 | val typeId = input.readByte().toInt() 247 | val serializer = serializers[typeId] 248 | 249 | @Suppress("UNCHECKED_CAST") 250 | return serializer.readTag(input) as T 251 | } else { 252 | return readNbtTagDirectly(input, tagType.kotlin) 253 | } 254 | } 255 | 256 | /** 257 | * Reads a [NbtTag] of type [T] from the input directly, this is a reader for [writeNbtTagDirectly]. 258 | * @param input Where the file will be read, needs to handle compression and endianness. 259 | * @param tagType The type of the tag that will be read. 260 | * @throws IllegalArgumentException If [T] is exactly [NbtTag]. 261 | */ 262 | @PublishedApi 263 | @Throws(IOException::class, IllegalArgumentException::class) 264 | internal fun readNbtTagDirectly(input: DataInput, tagType: KClass): T { 265 | require(tagType != NbtTag::class) { 266 | "A final tag type is required. The NbtTag class is not a valid option for the tag type parameter." 267 | } 268 | val serializer = serializers.first { it.kClass == tagType } 269 | return tagType.cast(serializer.readTag(input)) 270 | } 271 | 272 | /** 273 | * Reads a [NbtTag] of type [T] from the input directly, this is a reader for [writeNbtTagDirectly]. 274 | * @param input Where the file will be read, needs to handle compression and endianness. 275 | * @param T The type of the tag that will be read. 276 | * @throws IllegalArgumentException If [T] is exactly [NbtTag]. 277 | */ 278 | @JvmStatic 279 | @Throws(IOException::class, IllegalArgumentException::class) 280 | public inline fun readNbtTagDirectly(input: DataInput): T { 281 | return readNbtTagDirectly(input, T::class) 282 | } 283 | 284 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 285 | /// PRIVATE AREA // PRIVATE AREA // PRIVATE AREA // PRIVATE AREA // PRIVATE AREA // PRIVATE AREA /// 286 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////// 287 | 288 | 289 | private val serializers = listOf( 290 | NbtEndSerial, 291 | NbtByteSerial, 292 | NbtShortSerial, 293 | NbtIntSerial, 294 | NbtLongSerial, 295 | NbtFloatSerial, 296 | NbtDoubleSerial, 297 | NbtByteArraySerial, 298 | NbtStringSerial, 299 | NbtListSerial, 300 | NbtCompoundSerial, 301 | NbtIntArraySerial, 302 | NbtLongArraySerial 303 | ) 304 | 305 | private val NbtTag.typeId 306 | get() = serializers.indexOfFirst { it.kClass == this::class } 307 | 308 | private sealed class NbtSerial (val kClass: KClass){ 309 | abstract fun readTag(input: DataInput): T 310 | abstract fun writeTag(output: DataOutput, tag: T) 311 | 312 | @Suppress("UNCHECKED_CAST") 313 | @JvmName("writeRawTag") 314 | fun writeTag(output: DataOutput, tag: NbtTag) { 315 | writeTag(output, tag as T) 316 | } 317 | } 318 | 319 | private object NbtEndSerial: NbtSerial(NbtEnd::class) { 320 | override fun readTag(input: DataInput): NbtEnd { 321 | return NbtEnd 322 | } 323 | 324 | override fun writeTag(output: DataOutput, tag: NbtEnd) { 325 | } 326 | } 327 | 328 | private object NbtByteSerial: NbtSerial(NbtByte::class) { 329 | override fun readTag(input: DataInput): NbtByte { 330 | return NbtByte(input.readByte()) 331 | } 332 | 333 | override fun writeTag(output: DataOutput, tag: NbtByte) { 334 | output.writeByte(tag.signed.toInt()) 335 | } 336 | } 337 | 338 | private object NbtShortSerial: NbtSerial(NbtShort::class) { 339 | override fun readTag(input: DataInput): NbtShort { 340 | return NbtShort(input.readShort()) 341 | } 342 | 343 | override fun writeTag(output: DataOutput, tag: NbtShort) { 344 | output.writeShort(tag.value.toInt()) 345 | } 346 | } 347 | 348 | private object NbtIntSerial: NbtSerial(NbtInt::class) { 349 | override fun readTag(input: DataInput): NbtInt { 350 | return NbtInt(input.readInt()) 351 | } 352 | 353 | override fun writeTag(output: DataOutput, tag: NbtInt) { 354 | output.writeInt(tag.value) 355 | } 356 | } 357 | 358 | private object NbtLongSerial: NbtSerial(NbtLong::class) { 359 | override fun readTag(input: DataInput): NbtLong { 360 | return NbtLong(input.readLong()) 361 | } 362 | 363 | override fun writeTag(output: DataOutput, tag: NbtLong) { 364 | output.writeLong(tag.value) 365 | } 366 | } 367 | 368 | private object NbtFloatSerial: NbtSerial(NbtFloat::class) { 369 | override fun readTag(input: DataInput): NbtFloat { 370 | return NbtFloat(input.readFloat()) 371 | } 372 | 373 | override fun writeTag(output: DataOutput, tag: NbtFloat) { 374 | output.writeFloat(tag.value) 375 | } 376 | } 377 | 378 | private object NbtDoubleSerial: NbtSerial(NbtDouble::class) { 379 | override fun readTag(input: DataInput): NbtDouble { 380 | return NbtDouble(input.readDouble()) 381 | } 382 | 383 | override fun writeTag(output: DataOutput, tag: NbtDouble) { 384 | output.writeDouble(tag.value) 385 | } 386 | } 387 | 388 | private object NbtByteArraySerial: NbtSerial(NbtByteArray::class) { 389 | override fun readTag(input: DataInput): NbtByteArray { 390 | val size = input.readInt() 391 | val bytes = ByteArray(size) 392 | input.readFully(bytes) 393 | return NbtByteArray(bytes) 394 | } 395 | 396 | override fun writeTag(output: DataOutput, tag: NbtByteArray) { 397 | output.writeInt(tag.value.size) 398 | output.write(tag.value) 399 | } 400 | } 401 | 402 | private object NbtStringSerial: NbtSerial(NbtString::class) { 403 | override fun readTag(input: DataInput): NbtString { 404 | return NbtString(input.readUTF()) 405 | } 406 | 407 | override fun writeTag(output: DataOutput, tag: NbtString) { 408 | output.writeUTF(tag.value) 409 | } 410 | } 411 | 412 | private object NbtListSerial: NbtSerial>(NbtList::class) { 413 | override fun readTag(input: DataInput): NbtList<*> { 414 | val type = input.readUnsignedByte() 415 | val size = input.readInt() 416 | if (type == 0 && size > 0) { 417 | error("Missing type on NbtList") 418 | } 419 | val serializer = serializers[type] 420 | val list = mutableListOf() 421 | for (i in 1..size) { 422 | list += serializer.readTag(input) 423 | } 424 | return NbtList(list) 425 | } 426 | 427 | override fun writeTag(output: DataOutput, tag: NbtList<*>) { 428 | val sample = tag.firstOrNull() ?: NbtEnd 429 | val typeId = sample.typeId 430 | val serializer = serializers[typeId] 431 | 432 | if (typeId == 0 && tag.size > 0) { 433 | error("NbtList cannot have NbtEnd") 434 | } 435 | 436 | output.writeByte(typeId) 437 | output.writeInt(tag.size) 438 | tag.forEach { 439 | serializer.writeTag(output, it) 440 | } 441 | } 442 | } 443 | 444 | private object NbtCompoundSerial: NbtSerial(NbtCompound::class) { 445 | override fun readTag(input: DataInput): NbtCompound { 446 | val map = mutableMapOf() 447 | while (true) { 448 | val typeId = input.readUnsignedByte() 449 | if (typeId == 0) { 450 | break 451 | } 452 | 453 | val name = input.readUTF() 454 | val serializer = serializers[typeId] 455 | val childTag = serializer.readTag(input) 456 | map[name] = childTag 457 | } 458 | return NbtCompound(map) 459 | } 460 | 461 | override fun writeTag(output: DataOutput, tag: NbtCompound) { 462 | check(tag.values.none { it == NbtEnd }) { 463 | "NbtCompound cannot have an NbtEnd" 464 | } 465 | 466 | tag.forEach { (name, childTag) -> 467 | val typeId = childTag.typeId 468 | val serializer = serializers[typeId] 469 | output.writeByte(typeId) 470 | output.writeUTF(name) 471 | serializer.writeTag(output, childTag) 472 | } 473 | 474 | output.writeByte(0) 475 | } 476 | } 477 | 478 | private object NbtIntArraySerial: NbtSerial(NbtIntArray::class) { 479 | override fun readTag(input: DataInput): NbtIntArray { 480 | val size = input.readInt() 481 | val array = IntArray(size) 482 | for (i in 0 until size) { 483 | array[i] = input.readInt() 484 | } 485 | return NbtIntArray(array) 486 | } 487 | 488 | override fun writeTag(output: DataOutput, tag: NbtIntArray) { 489 | output.writeInt(tag.value.size) 490 | tag.value.forEach { 491 | output.writeInt(it) 492 | } 493 | } 494 | } 495 | 496 | private object NbtLongArraySerial: NbtSerial(NbtLongArray::class) { 497 | override fun readTag(input: DataInput): NbtLongArray { 498 | val size = input.readInt() 499 | val array = LongArray(size) 500 | for (i in 0 until size) { 501 | array[i] = input.readLong() 502 | } 503 | return NbtLongArray(array) 504 | } 505 | 506 | override fun writeTag(output: DataOutput, tag: NbtLongArray) { 507 | output.writeInt(tag.value.size) 508 | tag.value.forEach { 509 | output.writeLong(it) 510 | } 511 | } 512 | } 513 | } 514 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtInt.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps an int value. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtInt(var value: Int) : NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | */ 13 | override val stringValue: String 14 | get() = value.toString() 15 | 16 | /** 17 | * Parses the string value as a signed int and wraps it. 18 | * @param signed Signed value from `-2147483648` to `2147483647`. 19 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 20 | */ 21 | @Throws(NumberFormatException::class) 22 | public constructor(signed: String): this(signed.toInt()) 23 | 24 | /** 25 | * Returns a new wrapper with the current value. 26 | */ 27 | override fun deepCopy(): NbtInt = copy() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtIntArray.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a mutable int array. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtIntArray(var value: IntArray): NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value with a structure similar to a normal [List]. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | * 13 | * Be aware that this may be a slow operation on big arrays. 14 | */ 15 | override val stringValue: String 16 | get() = value.takeIf { it.isNotEmpty() }?.joinToString(prefix = "[", postfix = "]") ?: "[]" 17 | 18 | /** 19 | * Creates a new tag with an empty array. 20 | */ 21 | public constructor(): this(intArrayOf()) 22 | 23 | /** 24 | * Parses the string using the same structure which is returned by [stringValue]. 25 | * 26 | * @param value A string with a structure like `[0, -32, 48, 127]` 27 | * 28 | * @throws IllegalArgumentException if the string does not have the exact format outputted by [stringValue] 29 | */ 30 | @Throws(IllegalArgumentException::class) 31 | public constructor(value: String): this(value 32 | .removeSurrounding("[", "]") 33 | .split(", ") 34 | .takeIf { it.size > 1 || it.firstOrNull()?.isNotEmpty() == true } 35 | ?.map { it.toInt() } 36 | ?.toIntArray() 37 | ?: intArrayOf() 38 | ) 39 | 40 | /** 41 | * A technical string representation of this tag, containing the tag type, and it's value, 42 | * appropriated for developer inspections. 43 | * 44 | * The output will be similar to a normal [List]. 45 | * 46 | * Be aware that this may be a slow operation on big arrays. 47 | */ 48 | override fun toTechnicalString(): String { 49 | return "NbtIntArray$stringValue" 50 | } 51 | 52 | /** 53 | * Properly checks the equality of the array. 54 | */ 55 | override fun equals(other: Any?): Boolean { 56 | if (this === other) return true 57 | if (javaClass != other?.javaClass) return false 58 | 59 | other as NbtIntArray 60 | 61 | if (!value.contentEquals(other.value)) return false 62 | 63 | return true 64 | } 65 | 66 | /** 67 | * Properly calculates the hashcode of the array. 68 | */ 69 | override fun hashCode(): Int { 70 | return value.contentHashCode() 71 | } 72 | 73 | /** 74 | * Returns a new wrapper with a copy of the current value. 75 | */ 76 | override fun deepCopy(): NbtIntArray = copy(value = value.copyOf()) 77 | } 78 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtList.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which contains a [MutableList] structure of [NbtTag]s. All children must have the same class. 5 | * 6 | * @param T The type of the tag that will be wrapped. [NbtEnd] and [NbtTag] are not valid. 7 | */ 8 | public class NbtList private constructor(private val tags: ArrayList): NbtTag(), MutableList by tags, RandomAccess { 9 | /** 10 | * Returns a string representation of the tag's value. 11 | * 12 | * The output will be similar to a normal [List]. 13 | * 14 | * The class names of the children tags will expose. 15 | * 16 | * The returned string is compatible with string constructors of the same type. 17 | * 18 | * Be aware that this may be a slow operation on big lists, arrays or compounds. 19 | */ 20 | override val stringValue: String 21 | get() = tags.toString() 22 | 23 | /** 24 | * Constructs a [NbtList] with the same contents of the given [Collection]. 25 | * 26 | * All items in the list must have the same class. 27 | * 28 | * Null values in the list are not allowed. 29 | * 30 | * The tags in the list will be linked so any modification will also change this tag contents. 31 | */ 32 | public constructor(tags: Collection): this(ArrayList(tags)) 33 | 34 | /** 35 | * Creates an empty list. 36 | */ 37 | public constructor(): this(emptyList()) 38 | 39 | /** 40 | * Uses all tags as initial value of this list. Make sure to use the same class in all values. 41 | */ 42 | public constructor(vararg tags: T): this(tags.toList()) 43 | 44 | /** 45 | * Uses all tags as initial value of this list. Make sure to use the same class in all values. 46 | */ 47 | public constructor(tags: Iterable): this(tags.toList()) 48 | 49 | /** 50 | * Uses all tags as initial value of this list. Make sure to use the same class in all values. 51 | */ 52 | public constructor(tags: Sequence): this(tags.toList()) 53 | 54 | /** 55 | * Uses all tags as initial value of this list. Make sure to use the same class in all values. 56 | */ 57 | public constructor(tags: NbtList): this(tags as Collection) 58 | 59 | /** 60 | * Parses the string using the same structure which is returned by [stringValue]. 61 | * 62 | * @param value A string with a structure like `[NbtInt(0), NbtInt(-32), NbtInt(48), NbtInt(127)]` 63 | * 64 | * @throws IllegalArgumentException if the string does not have the exact format outputted by [stringValue] 65 | */ 66 | @Suppress("UNCHECKED_CAST") 67 | @Throws(IllegalArgumentException::class) 68 | public constructor(value: String): this(NbtListStringParser(value).parseList() as ArrayList) 69 | 70 | override fun add(element: T): Boolean { 71 | checkTagType(element) 72 | return tags.add(element) 73 | } 74 | 75 | override fun add(index: Int, element: T) { 76 | checkTagType(element) 77 | return tags.add(index, element) 78 | } 79 | 80 | override fun set(index: Int, element: T): T { 81 | if (size > 1) { 82 | checkTagType(element) 83 | } 84 | return tags.set(index, element) 85 | } 86 | 87 | override fun subList(fromIndex: Int, toIndex: Int): MutableList { 88 | val subList = tags.subList(fromIndex, toIndex) 89 | return object : MutableList by subList, RandomAccess { 90 | override fun set(index: Int, element: T): T { 91 | checkTagType(element) 92 | return subList.set(index, element) 93 | } 94 | 95 | override fun toString(): String { 96 | return tags.toString() 97 | } 98 | 99 | override fun equals(other: Any?): Boolean { 100 | return subList == other 101 | } 102 | 103 | override fun hashCode(): Int { 104 | return subList.hashCode() 105 | } 106 | } 107 | } 108 | 109 | private fun checkTagType(tag: NbtTag) { 110 | val childrenType = firstOrNull()?.javaClass ?: return 111 | require(childrenType == tag.javaClass) { 112 | "NbtList must have all children tags of the same type. \n" + 113 | "Tried to add a ${tag.javaClass.simpleName} tag in a NbtList of ${childrenType.javaClass.simpleName}" 114 | } 115 | } 116 | 117 | /** 118 | * Returns a new NbtList with all nested values copied deeply. 119 | */ 120 | override fun deepCopy(): NbtList = NbtList(map { 121 | @Suppress("UNCHECKED_CAST") 122 | it.deepCopy() as T 123 | }) 124 | 125 | /** 126 | * A technical string representation of this tag, containing the tag type, and it's value, 127 | * appropriated for developer inspections. 128 | * 129 | * The output will be similar to a normal [List]. 130 | * 131 | * Be aware that this may be a slow operation on big lists, arrays or compounds. 132 | */ 133 | override fun toTechnicalString(): String { 134 | if (tags.isEmpty()) { 135 | return "NbtList[]" 136 | } 137 | return tags.joinToString(prefix = "NbtList[", postfix = "]") 138 | } 139 | 140 | override fun equals(other: Any?): Boolean { 141 | return tags == other 142 | } 143 | 144 | override fun hashCode(): Int { 145 | return tags.hashCode() 146 | } 147 | 148 | 149 | /** 150 | * Contains useful methods to create [NbtList]s from Java. 151 | * 152 | * Kotlin's users may call `list(1,2,3).toNbtList()` or similar methods. 153 | */ 154 | public companion object { 155 | /** 156 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 157 | */ 158 | @JvmStatic 159 | public fun create(vararg tags: Byte): NbtList = tags.toNbtList() 160 | /** 161 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 162 | */ 163 | @JvmStatic 164 | public fun create(vararg tags: Short): NbtList = tags.toNbtList() 165 | /** 166 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 167 | */ 168 | @JvmStatic 169 | public fun create(vararg tags: Int): NbtList = tags.toNbtList() 170 | /** 171 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 172 | */ 173 | @JvmStatic 174 | public fun create(vararg tags: Long): NbtList = tags.toNbtList() 175 | /** 176 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 177 | */ 178 | @JvmStatic 179 | public fun create(vararg tags: Float): NbtList = tags.toNbtList() 180 | /** 181 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 182 | */ 183 | @JvmStatic 184 | public fun create(vararg tags: Double): NbtList = tags.toNbtList() 185 | /** 186 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 187 | */ 188 | @JvmStatic 189 | public fun create(vararg tags: String): NbtList = tags.toNbtList() 190 | /** 191 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 192 | */ 193 | @JvmStatic 194 | public fun create(vararg tags: ByteArray): NbtList = tags.toNbtList() 195 | /** 196 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 197 | */ 198 | @JvmStatic 199 | public fun create(vararg tags: IntArray): NbtList = tags.toNbtList() 200 | /** 201 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 202 | */ 203 | @JvmStatic 204 | public fun create(vararg tags: LongArray): NbtList = tags.toNbtList() 205 | /** 206 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 207 | */ 208 | @JvmStatic 209 | public fun create(vararg tags: Map): NbtList = tags.toNbtList() 210 | /** 211 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 212 | */ 213 | @JvmStatic 214 | public fun create(vararg tags: Iterable): NbtList> = tags.toNbtList() 215 | /** 216 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 217 | */ 218 | @JvmStatic 219 | public fun createByteSublist(vararg tags: Iterable): NbtList> = tags.toNbtList() 220 | /** 221 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 222 | */ 223 | @JvmStatic 224 | public fun createByteSublist(vararg tags: Array): NbtList> = tags.toNbtList() 225 | /** 226 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 227 | */ 228 | @JvmStatic 229 | public fun createByteSublist(vararg tags: ByteArray): NbtList> = tags.map { it.asIterable() }.toNbtList() 230 | /** 231 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 232 | */ 233 | @JvmStatic 234 | public fun createShortSublist(vararg tags: Iterable): NbtList> = tags.toNbtList() 235 | /** 236 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 237 | */ 238 | @JvmStatic 239 | public fun createShortSublist(vararg tags: Array): NbtList> = tags.toNbtList() 240 | /** 241 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 242 | */ 243 | @JvmStatic 244 | public fun createShortSublist(vararg tags: ShortArray): NbtList> = tags.map { it.asIterable() }.toNbtList() 245 | /** 246 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 247 | */ 248 | @JvmStatic 249 | public fun createIntSublist(vararg tags: Iterable): NbtList> = tags.toNbtList() 250 | /** 251 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 252 | */ 253 | @JvmStatic 254 | public fun createIntSublist(vararg tags: Array): NbtList> = tags.toNbtList() 255 | /** 256 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 257 | */ 258 | @JvmStatic 259 | public fun createIntSublist(vararg tags: IntArray): NbtList> = tags.map { it.asIterable() }.toNbtList() 260 | /** 261 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 262 | */ 263 | @JvmStatic 264 | public fun createFloatSublist(vararg tags: Iterable): NbtList> = tags.toNbtList() 265 | /** 266 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 267 | */ 268 | @JvmStatic 269 | public fun createFloatSublist(vararg tags: Array): NbtList> = tags.toNbtList() 270 | /** 271 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 272 | */ 273 | @JvmStatic 274 | public fun createFloatSublist(vararg tags: FloatArray): NbtList> = tags.map { it.asIterable() }.toNbtList() 275 | /** 276 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 277 | */ 278 | @JvmStatic 279 | public fun createDoubleSublist(vararg tags: Iterable): NbtList> = tags.toNbtList() 280 | /** 281 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 282 | */ 283 | @JvmStatic 284 | public fun createDoubleSublist(vararg tags: Array): NbtList> = tags.toNbtList() 285 | /** 286 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 287 | */ 288 | @JvmStatic 289 | public fun createDoubleSublist(vararg tags: DoubleArray): NbtList> = tags.map { it.asIterable() }.toNbtList() 290 | /** 291 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 292 | */ 293 | @JvmStatic 294 | public fun createStringSublist(vararg tags: Iterable): NbtList> = tags.toNbtList() 295 | /** 296 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 297 | */ 298 | @JvmStatic 299 | public fun createStringSublist(vararg tags: Array): NbtList> = tags.toNbtList() 300 | /** 301 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 302 | */ 303 | @JvmStatic 304 | public fun createCompoundSublist(vararg tags: Iterable>): NbtList> = tags.toNbtList() 305 | /** 306 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 307 | */ 308 | @JvmStatic 309 | public fun createCompoundSublist(vararg tags: Array>): NbtList> = tags.toNbtList() 310 | /** 311 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 312 | */ 313 | @JvmStatic 314 | public fun createSublist(vararg tags: Iterable>): NbtList>> = tags.toNbtList() 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtListStringParser.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | internal class NbtListStringParser(value: String): ComplexNbtStringParser('[', ']', value) { 4 | 5 | private val result = ArrayList() 6 | 7 | internal fun parseList(): ArrayList { 8 | if (input.isEmpty()) { 9 | return result 10 | } 11 | 12 | check(endIndex == -2) { 13 | "Already processed." 14 | } 15 | 16 | parseBeginning() 17 | 18 | return when(type) { 19 | "NbtByteArray", "NbtIntArray", "NbtLongArray" -> parse(includeSurrounding = true) 20 | "NbtString" -> parseStringList() 21 | "NbtList", "NbtCompound" -> parse(includeSurrounding = true, father = true) 22 | else -> parse(includeSurrounding = false) 23 | } 24 | } 25 | 26 | private tailrec fun parse(includeSurrounding: Boolean, father: Boolean = false): ArrayList { 27 | val tag = parseTag(includeSurrounding, father) 28 | result += tag 29 | if (!includeSurrounding) { 30 | endIndex++ 31 | } 32 | if (endIndex < input.length) { 33 | startIndex = input.indexOf(openChar, endIndex) 34 | require(startIndex > 0) { "Invalid input: $input" } 35 | require(input.substring(endIndex, startIndex) == ", $type") { 36 | "Invalid input. NbtList can have only one type. Input: $input" 37 | } 38 | return parse(includeSurrounding, father) 39 | } 40 | return result 41 | } 42 | 43 | private tailrec fun parseStrings() { 44 | result += parseStringTag() 45 | endIndex += 2 46 | if (endIndex < input.length) { 47 | startIndex = input.indexOf("(\"", endIndex) 48 | require(startIndex > 0) { "Invalid input. Expected more strings." } 49 | val mid = input.substring(endIndex, startIndex) 50 | val newType = mid.substring(2) 51 | require(", $type" == mid) { 52 | "Invalid input. NbtList can have only one type. Tried to add a tag of $newType to a list of $type" 53 | } 54 | parseStrings() 55 | } 56 | } 57 | 58 | private fun parseStringList(): ArrayList { 59 | require(startIndex + 3 < input.length) { 60 | "Invalid input. Unexpected string format. Too short." 61 | } 62 | require(input[startIndex + 1] == '"') { 63 | "Invalid input. Unexpected string format. No quotes." 64 | } 65 | 66 | parseStrings() 67 | return result 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtLong.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a long value. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtLong(var value: Long) : NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | */ 13 | override val stringValue: String 14 | get() = value.toString() 15 | 16 | /** 17 | * Parses the string value as a signed long and wraps it. 18 | * @param signed Signed value from `-9223372036854775808` to `9223372036854775807`. 19 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 20 | */ 21 | @Throws(NumberFormatException::class) 22 | public constructor(signed: String): this(signed.toLong()) 23 | 24 | /** 25 | * Returns a new wrapper with the current value. 26 | */ 27 | override fun deepCopy(): NbtLong = copy() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtLongArray.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a mutable long array. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtLongArray(var value: LongArray) : NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value with a structure similar to a normal [List]. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | * 13 | * Be aware that this may be a slow operation on big arrays. 14 | */ 15 | override val stringValue: String 16 | get() = value.takeIf { it.isNotEmpty() }?.joinToString(prefix = "[", postfix = "]") ?: "[]" 17 | 18 | /** 19 | * Creates a new tag with an empty array. 20 | */ 21 | public constructor(): this(longArrayOf()) 22 | 23 | /** 24 | * Parses the string using the same structure which is returned by [stringValue]. 25 | * 26 | * @param value A string with a structure like `[0, -32, 48, 127]` 27 | * 28 | * @throws IllegalArgumentException if the string does not have the exact format outputted by [stringValue] 29 | */ 30 | @Throws(IllegalArgumentException::class) 31 | public constructor(value: String): this(value 32 | .removeSurrounding("[", "]") 33 | .split(", ") 34 | .takeIf { it.size > 1 || it.firstOrNull()?.isNotEmpty() == true } 35 | ?.map { it.toLong() } 36 | ?.toLongArray() 37 | ?: longArrayOf() 38 | ) 39 | 40 | /** 41 | * A technical string representation of this tag, containing the tag type, and it's value, 42 | * appropriated for developer inspections. 43 | * 44 | * The output will be similar to a normal [List]. 45 | * 46 | * Be aware that this may be a slow operation on big arrays. 47 | */ 48 | override fun toTechnicalString(): String { 49 | return "NbtLongArray$stringValue" 50 | } 51 | 52 | /** 53 | * Properly checks the equality of the array. 54 | */ 55 | override fun equals(other: Any?): Boolean { 56 | if (this === other) return true 57 | if (javaClass != other?.javaClass) return false 58 | 59 | other as NbtLongArray 60 | 61 | if (!value.contentEquals(other.value)) return false 62 | 63 | return true 64 | } 65 | 66 | /** 67 | * Properly calculates the hashcode of the array. 68 | */ 69 | override fun hashCode(): Int { 70 | return value.contentHashCode() 71 | } 72 | 73 | /** 74 | * Returns a new wrapper with a copy of the current value. 75 | */ 76 | override fun deepCopy(): NbtLongArray = copy(value = value.copyOf()) 77 | } 78 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtShort.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a short value. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtShort(var value: Short) : NbtTag() { 8 | /** 9 | * Returns a string representation of the tag's value. 10 | * 11 | * The returned string is compatible with string constructors of the same type. 12 | */ 13 | override val stringValue: String 14 | get() = value.toString() 15 | 16 | /** 17 | * Parses the string value as a signed short and wraps it. 18 | * @param signed Signed value from `-32768` to `32767`. 19 | * @throws NumberFormatException if the number is not within a valid range or if the string does not contain a valid number. 20 | */ 21 | @Throws(NumberFormatException::class) 22 | public constructor(signed: String): this(signed.toShort()) 23 | 24 | /** 25 | * Returns a new wrapper with the current value. 26 | */ 27 | override fun deepCopy(): NbtShort = copy() 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtString.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * A tag which wraps a [String] value. 5 | * @property value The wrapped value 6 | */ 7 | public data class NbtString(var value: String): NbtTag() { 8 | /** 9 | * Returns a string which is wrapped by this tag. 10 | */ 11 | override val stringValue: String 12 | get() = value 13 | 14 | override fun toTechnicalString(): String { 15 | return buildString { 16 | append("NbtString(\"") 17 | append( 18 | value.replace("\\", "\\\\") 19 | .replace("\"", "\\\"") 20 | ) 21 | append("\")") 22 | } 23 | } 24 | 25 | /** 26 | * Returns a new wrapper with the current value. 27 | */ 28 | override fun deepCopy(): NbtString = copy() 29 | } 30 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtTag.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | /** 4 | * The base class for Nbt Tags. All tag values are mutable. 5 | * 6 | * Do not create new classes extending it. 7 | */ 8 | public sealed class NbtTag { 9 | /** 10 | * Returns a string representation of the tag's value. 11 | * 12 | * The [NbtList] and the array types will have an output similar to a normal [List] and [NbtCompound] to a normal [Map]. 13 | * 14 | * The class names of the [NbtList]'s and [NbtCompound]'s children will expose. 15 | * 16 | * The returned string is compatible with string constructors of the same type. 17 | * 18 | * Be aware that this may be a slow operation on big lists, arrays or compounds. 19 | */ 20 | public abstract val stringValue: String 21 | 22 | /** 23 | * Copies all this and all nested NbtTags into new objects. 24 | */ 25 | public abstract fun deepCopy(): NbtTag 26 | 27 | /** 28 | * A technical string representation of this tag, containing the tag type, and it's value, 29 | * appropriated for developer inspections. 30 | * 31 | * The [NbtList] and the array types will have an output similar to a normal [List] and [NbtCompound] to a normal [Map]. 32 | * 33 | * Be aware that this may be a slow operation on big lists, arrays or compounds. 34 | */ 35 | protected open fun toTechnicalString(): String = "${this::class.java.simpleName}($stringValue)" 36 | 37 | /** 38 | * A technical string representation of this tag, containing the tag type, and it's value, 39 | * appropriated for developer inspections. 40 | * 41 | * The [NbtList] and the array types will have an output similar to a normal [List] and [NbtCompound] to a normal [Map]. 42 | * 43 | * Be aware that this may be a slow operation on big lists, arrays or compounds. 44 | */ 45 | final override fun toString(): String = toTechnicalString() 46 | } 47 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil-add.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | /** 7 | * Adds a value with the appropriated [NbtTag] wrapper. 8 | */ 9 | public fun NbtList.add(value: Byte): Boolean = add(NbtByte(value)) 10 | /** 11 | * Adds a value with the appropriated [NbtTag] wrapper. 12 | */ 13 | public fun NbtList.add(value: Short): Boolean = add(NbtShort(value)) 14 | /** 15 | * Adds a value with the appropriated [NbtTag] wrapper. 16 | */ 17 | public fun NbtList.add(value: Int): Boolean = add(NbtInt(value)) 18 | /** 19 | * Adds a value with the appropriated [NbtTag] wrapper. 20 | */ 21 | public fun NbtList.add(value: Long): Boolean = add(NbtLong(value)) 22 | /** 23 | * Adds a value with the appropriated [NbtTag] wrapper. 24 | */ 25 | public fun NbtList.add(value: Float): Boolean = add(NbtFloat(value)) 26 | /** 27 | * Adds a value with the appropriated [NbtTag] wrapper. 28 | */ 29 | public fun NbtList.add(value: Double): Boolean = add(NbtDouble(value)) 30 | /** 31 | * Adds a value with the appropriated [NbtTag] wrapper. 32 | */ 33 | public fun NbtList.add(value: String): Boolean = add(NbtString(value)) 34 | /** 35 | * Adds a value with the appropriated [NbtTag] wrapper. 36 | */ 37 | public fun NbtList.add(value: ByteArray): Boolean = add(NbtByteArray(value)) 38 | /** 39 | * Adds a value with the appropriated [NbtTag] wrapper. 40 | */ 41 | public fun NbtList.add(value: Array): Boolean = add(NbtByteArray(value.toByteArray())) 42 | /** 43 | * Adds a value with the appropriated [NbtTag] wrapper. 44 | */ 45 | public fun NbtList.add(value: IntArray): Boolean = add(NbtIntArray(value)) 46 | /** 47 | * Adds a value with the appropriated [NbtTag] wrapper. 48 | */ 49 | public fun NbtList.add(value: Array): Boolean = add(NbtIntArray(value.toIntArray())) 50 | /** 51 | * Adds a value with the appropriated [NbtTag] wrapper. 52 | */ 53 | public fun NbtList.add(value: LongArray): Boolean = add(NbtLongArray(value)) 54 | /** 55 | * Adds a value with the appropriated [NbtTag] wrapper. 56 | */ 57 | public fun NbtList.add(value: Array): Boolean = add(NbtLongArray(value.toLongArray())) 58 | /** 59 | * Adds a value with the appropriated [NbtTag] wrapper. 60 | */ 61 | public fun NbtList.add(value: Map): Boolean = add(NbtCompound(value)) 62 | /** 63 | * Adds a value with the appropriated [NbtTag] wrapper. 64 | */ 65 | public fun NbtList>.add(value: Iterable): Boolean = add(NbtList(value)) 66 | /** 67 | * Adds a value with the appropriated [NbtTag] wrapper. 68 | */ 69 | public fun NbtList>.add(value: Array): Boolean = add(NbtList(*value)) 70 | /** 71 | * Adds a value with the appropriated [NbtTag] wrapper. 72 | */ 73 | @JvmName("addListOfList") 74 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 75 | /** 76 | * Adds a value with the appropriated [NbtTag] wrapper. 77 | */ 78 | @JvmName("addListOfList") 79 | public fun NbtList>.add(value: ByteArray): Boolean = add(value.toNbtList()) 80 | /** 81 | * Adds a value with the appropriated [NbtTag] wrapper. 82 | */ 83 | @JvmName("addListOfListIterByte") 84 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 85 | /** 86 | * Adds a value with the appropriated [NbtTag] wrapper. 87 | */ 88 | @JvmName("addListOfList") 89 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 90 | /** 91 | * Adds a value with the appropriated [NbtTag] wrapper. 92 | */ 93 | @JvmName("addListOfList") 94 | public fun NbtList>.add(value: ShortArray): Boolean = add(value.toNbtList()) 95 | /** 96 | * Adds a value with the appropriated [NbtTag] wrapper. 97 | */ 98 | @JvmName("addListOfListIterShort") 99 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 100 | /** 101 | * Adds a value with the appropriated [NbtTag] wrapper. 102 | */ 103 | @JvmName("addListOfList") 104 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 105 | /** 106 | * Adds a value with the appropriated [NbtTag] wrapper. 107 | */ 108 | @JvmName("addListOfList") 109 | public fun NbtList>.add(value: IntArray): Boolean = add(value.toNbtList()) 110 | /** 111 | * Adds a value with the appropriated [NbtTag] wrapper. 112 | */ 113 | @JvmName("addListOfListIterInt") 114 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 115 | /** 116 | * Adds a value with the appropriated [NbtTag] wrapper. 117 | */ 118 | @JvmName("addListOfList") 119 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 120 | /** 121 | * Adds a value with the appropriated [NbtTag] wrapper. 122 | */ 123 | @JvmName("addListOfList") 124 | public fun NbtList>.add(value: LongArray): Boolean = add(value.toNbtList()) 125 | /** 126 | * Adds a value with the appropriated [NbtTag] wrapper. 127 | */ 128 | @JvmName("addListOfListIterLong") 129 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 130 | /** 131 | * Adds a value with the appropriated [NbtTag] wrapper. 132 | */ 133 | @JvmName("addListOfList") 134 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 135 | /** 136 | * Adds a value with the appropriated [NbtTag] wrapper. 137 | */ 138 | @JvmName("addListOfList") 139 | public fun NbtList>.add(value: FloatArray): Boolean = add(value.toNbtList()) 140 | /** 141 | * Adds a value with the appropriated [NbtTag] wrapper. 142 | */ 143 | @JvmName("addListOfListIterFloat") 144 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 145 | /** 146 | * Adds a value with the appropriated [NbtTag] wrapper. 147 | */ 148 | @JvmName("addListOfList") 149 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 150 | /** 151 | * Adds a value with the appropriated [NbtTag] wrapper. 152 | */ 153 | @JvmName("addListOfListIterString") 154 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 155 | /** 156 | * Adds a value with the appropriated [NbtTag] wrapper. 157 | */ 158 | @JvmName("addListOfList") 159 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 160 | /** 161 | * Adds a value with the appropriated [NbtTag] wrapper. 162 | */ 163 | @JvmName("addListOfListIterByteArray") 164 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 165 | /** 166 | * Adds a value with the appropriated [NbtTag] wrapper. 167 | */ 168 | @JvmName("addListOfList") 169 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 170 | /** 171 | * Adds a value with the appropriated [NbtTag] wrapper. 172 | */ 173 | @JvmName("addListOfListIterIntArray") 174 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 175 | /** 176 | * Adds a value with the appropriated [NbtTag] wrapper. 177 | */ 178 | @JvmName("addListOfList") 179 | public fun NbtList>.add(value: Array): Boolean = add(value.toNbtList()) 180 | /** 181 | * Adds a value with the appropriated [NbtTag] wrapper. 182 | */ 183 | @JvmName("addListOfListIterLongArray") 184 | public fun NbtList>.add(value: Iterable): Boolean = add(value.toNbtList()) 185 | /** 186 | * Adds a value with the appropriated [NbtTag] wrapper. 187 | */ 188 | @JvmName("addListOfList") 189 | public fun NbtList>.add(value: Array>): Boolean = add(value.toNbtList()) 190 | /** 191 | * Adds a value with the appropriated [NbtTag] wrapper. 192 | */ 193 | @JvmName("addListOfListIterCompound") 194 | public fun NbtList>.add(value: Iterable>): Boolean = add(value.toNbtList()) 195 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil-contains.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | /** 7 | * Checks if the list contains a [NbtTag] with the given value. 8 | */ 9 | public operator fun NbtList.contains(value: Byte): Boolean = contains(NbtByte(value)) 10 | /** 11 | * Checks if the list contains a [NbtTag] with the given value. 12 | */ 13 | public operator fun NbtList.contains(value: Short): Boolean = contains(NbtShort(value)) 14 | /** 15 | * Checks if the list contains a [NbtTag] with the given value. 16 | */ 17 | public operator fun NbtList.contains(value: Int): Boolean = contains(NbtInt(value)) 18 | /** 19 | * Checks if the list contains a [NbtTag] with the given value. 20 | */ 21 | public operator fun NbtList.contains(value: Long): Boolean = contains(NbtLong(value)) 22 | /** 23 | * Checks if the list contains a [NbtTag] with the given value. 24 | */ 25 | public operator fun NbtList.contains(value: Float): Boolean = contains(NbtFloat(value)) 26 | /** 27 | * Checks if the list contains a [NbtTag] with the given value. 28 | */ 29 | public operator fun NbtList.contains(value: Double): Boolean = contains(NbtDouble(value)) 30 | /** 31 | * Checks if the list contains a [NbtTag] with the given value. 32 | */ 33 | public operator fun NbtList.contains(value: String): Boolean = contains(NbtString(value)) 34 | /** 35 | * Checks if the list contains a [NbtTag] with the given value. 36 | */ 37 | public operator fun NbtList.contains(value: ByteArray): Boolean = contains(NbtByteArray(value)) 38 | /** 39 | * Checks if the list contains a [NbtTag] with the given value. 40 | */ 41 | public operator fun NbtList.contains(value: Array): Boolean = contains(NbtByteArray(value.toByteArray())) 42 | /** 43 | * Checks if the list contains a [NbtTag] with the given value. 44 | */ 45 | public operator fun NbtList.contains(value: IntArray): Boolean = contains(NbtIntArray(value)) 46 | /** 47 | * Checks if the list contains a [NbtTag] with the given value. 48 | */ 49 | public operator fun NbtList.contains(value: Array): Boolean = contains(NbtIntArray(value.toIntArray())) 50 | /** 51 | * Checks if the list contains a [NbtTag] with the given value. 52 | */ 53 | public operator fun NbtList.contains(value: LongArray): Boolean = contains(NbtLongArray(value)) 54 | /** 55 | * Checks if the list contains a [NbtTag] with the given value. 56 | */ 57 | public operator fun NbtList.contains(value: Array): Boolean = contains(NbtLongArray(value.toLongArray())) 58 | /** 59 | * Checks if the list contains a [NbtTag] with the given value. 60 | */ 61 | public operator fun NbtList.contains(value: Map): Boolean = contains(NbtCompound(value)) 62 | /** 63 | * Checks if the list contains a [NbtTag] with the given value. 64 | */ 65 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(NbtList(value)) 66 | /** 67 | * Checks if the list contains a [NbtTag] with the given value. 68 | */ 69 | public operator fun NbtList>.contains(value: Array): Boolean = contains(NbtList(*value)) 70 | /** 71 | * Checks if the list contains a [NbtTag] with the given value. 72 | */ 73 | @JvmName("containsListOfList") 74 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 75 | /** 76 | * Checks if the list contains a [NbtTag] with the given value. 77 | */ 78 | @JvmName("containsListOfList") 79 | public operator fun NbtList>.contains(value: ByteArray): Boolean = contains(value.toNbtList()) 80 | /** 81 | * Checks if the list contains a [NbtTag] with the given value. 82 | */ 83 | @JvmName("containsListOfListIterByte") 84 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 85 | /** 86 | * Checks if the list contains a [NbtTag] with the given value. 87 | */ 88 | @JvmName("containsListOfList") 89 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 90 | /** 91 | * Checks if the list contains a [NbtTag] with the given value. 92 | */ 93 | @JvmName("containsListOfList") 94 | public operator fun NbtList>.contains(value: ShortArray): Boolean = contains(value.toNbtList()) 95 | /** 96 | * Checks if the list contains a [NbtTag] with the given value. 97 | */ 98 | @JvmName("containsListOfListIterShort") 99 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 100 | /** 101 | * Checks if the list contains a [NbtTag] with the given value. 102 | */ 103 | @JvmName("containsListOfList") 104 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 105 | /** 106 | * Checks if the list contains a [NbtTag] with the given value. 107 | */ 108 | @JvmName("containsListOfList") 109 | public operator fun NbtList>.contains(value: IntArray): Boolean = contains(value.toNbtList()) 110 | /** 111 | * Checks if the list contains a [NbtTag] with the given value. 112 | */ 113 | @JvmName("containsListOfListIterInt") 114 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 115 | /** 116 | * Checks if the list contains a [NbtTag] with the given value. 117 | */ 118 | @JvmName("containsListOfList") 119 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 120 | /** 121 | * Checks if the list contains a [NbtTag] with the given value. 122 | */ 123 | @JvmName("containsListOfList") 124 | public operator fun NbtList>.contains(value: LongArray): Boolean = contains(value.toNbtList()) 125 | /** 126 | * Checks if the list contains a [NbtTag] with the given value. 127 | */ 128 | @JvmName("containsListOfListIterLong") 129 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 130 | /** 131 | * Checks if the list contains a [NbtTag] with the given value. 132 | */ 133 | @JvmName("containsListOfList") 134 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 135 | /** 136 | * Checks if the list contains a [NbtTag] with the given value. 137 | */ 138 | @JvmName("containsListOfList") 139 | public operator fun NbtList>.contains(value: FloatArray): Boolean = contains(value.toNbtList()) 140 | /** 141 | * Checks if the list contains a [NbtTag] with the given value. 142 | */ 143 | @JvmName("containsListOfListIterFloat") 144 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 145 | /** 146 | * Checks if the list contains a [NbtTag] with the given value. 147 | */ 148 | @JvmName("containsListOfList") 149 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 150 | /** 151 | * Checks if the list contains a [NbtTag] with the given value. 152 | */ 153 | @JvmName("containsListOfListIterString") 154 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 155 | /** 156 | * Checks if the list contains a [NbtTag] with the given value. 157 | */ 158 | @JvmName("containsListOfList") 159 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 160 | /** 161 | * Checks if the list contains a [NbtTag] with the given value. 162 | */ 163 | @JvmName("containsListOfListIterByteArray") 164 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 165 | /** 166 | * Checks if the list contains a [NbtTag] with the given value. 167 | */ 168 | @JvmName("containsListOfList") 169 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 170 | /** 171 | * Checks if the list contains a [NbtTag] with the given value. 172 | */ 173 | @JvmName("containsListOfListIterIntArray") 174 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 175 | /** 176 | * Checks if the list contains a [NbtTag] with the given value. 177 | */ 178 | @JvmName("containsListOfList") 179 | public operator fun NbtList>.contains(value: Array): Boolean = contains(value.toNbtList()) 180 | /** 181 | * Checks if the list contains a [NbtTag] with the given value. 182 | */ 183 | @JvmName("containsListOfListIterLongArray") 184 | public operator fun NbtList>.contains(value: Iterable): Boolean = contains(value.toNbtList()) 185 | /** 186 | * Checks if the list contains a [NbtTag] with the given value. 187 | */ 188 | @JvmName("containsListOfList") 189 | public operator fun NbtList>.contains(value: Array>): Boolean = contains(value.toNbtList()) 190 | /** 191 | * Checks if the list contains a [NbtTag] with the given value. 192 | */ 193 | @JvmName("containsListOfListIterCompound") 194 | public operator fun NbtList>.contains(value: Iterable>): Boolean = add(value.toNbtList()) 195 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil-minusAssign.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | /** 7 | * Removes a tag containing the given value. 8 | */ 9 | public operator fun NbtList.minusAssign(value: Byte) { remove(value) } 10 | /** 11 | * Removes a tag containing the given value. 12 | */ 13 | public operator fun NbtList.minusAssign(value: Short) { remove(value) } 14 | /** 15 | * Removes a tag containing the given value. 16 | */ 17 | public operator fun NbtList.minusAssign(value: Int) { remove(value) } 18 | /** 19 | * Removes a tag containing the given value. 20 | */ 21 | public operator fun NbtList.minusAssign(value: Long) { remove(value) } 22 | /** 23 | * Removes a tag containing the given value. 24 | */ 25 | public operator fun NbtList.minusAssign(value: Float) { remove(value) } 26 | /** 27 | * Removes a tag containing the given value. 28 | */ 29 | public operator fun NbtList.minusAssign(value: Double) { remove(value) } 30 | /** 31 | * Removes a tag containing the given value. 32 | */ 33 | public operator fun NbtList.minusAssign(value: String) { remove(value) } 34 | /** 35 | * Removes a tag containing the given value. 36 | */ 37 | public operator fun NbtList.minusAssign(value: ByteArray) { remove(value) } 38 | /** 39 | * Removes a tag containing the given value. 40 | */ 41 | public operator fun NbtList.minusAssign(value: Array) { remove(value) } 42 | /** 43 | * Removes a tag containing the given value. 44 | */ 45 | public operator fun NbtList.minusAssign(value: IntArray) { remove(value) } 46 | /** 47 | * Removes a tag containing the given value. 48 | */ 49 | public operator fun NbtList.minusAssign(value: Array) { remove(value) } 50 | /** 51 | * Removes a tag containing the given value. 52 | */ 53 | public operator fun NbtList.minusAssign(value: LongArray) { remove(value) } 54 | /** 55 | * Removes a tag containing the given value. 56 | */ 57 | public operator fun NbtList.minusAssign(value: Array) { remove(value) } 58 | /** 59 | * Removes a tag containing the given value. 60 | */ 61 | public operator fun NbtList.minusAssign(value: Map) { remove(value) } 62 | /** 63 | * Removes a tag containing the given value. 64 | */ 65 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 66 | /** 67 | * Removes a tag containing the given value. 68 | */ 69 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 70 | /** 71 | * Removes a tag containing the given value. 72 | */ 73 | @JvmName("minusAssignListOfList") 74 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 75 | /** 76 | * Removes a tag containing the given value. 77 | */ 78 | @JvmName("minusAssignListOfList") 79 | public operator fun NbtList>.minusAssign(value: ByteArray) { remove(value) } 80 | /** 81 | * Removes a tag containing the given value. 82 | */ 83 | @JvmName("minusAssignListOfListIterByte") 84 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 85 | /** 86 | * Removes a tag containing the given value. 87 | */ 88 | @JvmName("minusAssignListOfList") 89 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 90 | /** 91 | * Removes a tag containing the given value. 92 | */ 93 | @JvmName("minusAssignListOfList") 94 | public operator fun NbtList>.minusAssign(value: ShortArray) { remove(value) } 95 | /** 96 | * Removes a tag containing the given value. 97 | */ 98 | @JvmName("minusAssignListOfListIterShort") 99 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 100 | /** 101 | * Removes a tag containing the given value. 102 | */ 103 | @JvmName("minusAssignListOfList") 104 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 105 | /** 106 | * Removes a tag containing the given value. 107 | */ 108 | @JvmName("minusAssignListOfList") 109 | public operator fun NbtList>.minusAssign(value: IntArray) { remove(value) } 110 | /** 111 | * Removes a tag containing the given value. 112 | */ 113 | @JvmName("minusAssignListOfListIterInt") 114 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 115 | /** 116 | * Removes a tag containing the given value. 117 | */ 118 | @JvmName("minusAssignListOfList") 119 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 120 | /** 121 | * Removes a tag containing the given value. 122 | */ 123 | @JvmName("minusAssignListOfList") 124 | public operator fun NbtList>.minusAssign(value: LongArray) { remove(value) } 125 | /** 126 | * Removes a tag containing the given value. 127 | */ 128 | @JvmName("minusAssignListOfListIterLong") 129 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 130 | /** 131 | * Removes a tag containing the given value. 132 | */ 133 | @JvmName("minusAssignListOfList") 134 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 135 | /** 136 | * Removes a tag containing the given value. 137 | */ 138 | @JvmName("minusAssignListOfList") 139 | public operator fun NbtList>.minusAssign(value: FloatArray) { remove(value) } 140 | /** 141 | * Removes a tag containing the given value. 142 | */ 143 | @JvmName("minusAssignListOfListIterFloat") 144 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 145 | /** 146 | * Removes a tag containing the given value. 147 | */ 148 | @JvmName("minusAssignListOfList") 149 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 150 | /** 151 | * Removes a tag containing the given value. 152 | */ 153 | @JvmName("minusAssignListOfListIterString") 154 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 155 | /** 156 | * Removes a tag containing the given value. 157 | */ 158 | @JvmName("minusAssignListOfList") 159 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 160 | /** 161 | * Removes a tag containing the given value. 162 | */ 163 | @JvmName("minusAssignListOfListIterByteArray") 164 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 165 | /** 166 | * Removes a tag containing the given value. 167 | */ 168 | @JvmName("minusAssignListOfList") 169 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 170 | /** 171 | * Removes a tag containing the given value. 172 | */ 173 | @JvmName("minusAssignListOfListIterIntArray") 174 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 175 | /** 176 | * Removes a tag containing the given value. 177 | */ 178 | @JvmName("minusAssignListOfList") 179 | public operator fun NbtList>.minusAssign(value: Array) { remove(value) } 180 | /** 181 | * Removes a tag containing the given value. 182 | */ 183 | @JvmName("minusAssignListOfListIterLongArray") 184 | public operator fun NbtList>.minusAssign(value: Iterable) { remove(value) } 185 | /** 186 | * Removes a tag containing the given value. 187 | */ 188 | @JvmName("minusAssignListOfList") 189 | public operator fun NbtList>.minusAssign(value: Array>) { remove(value) } 190 | /** 191 | * Removes a tag containing the given value. 192 | */ 193 | @JvmName("minusAssignListOfListIterCompound") 194 | public operator fun NbtList>.minusAssign(value: Iterable>) { remove(value) } 195 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil-plusAssign.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | /** 7 | * Adds a value with the appropriated [NbtTag] wrapper. 8 | */ 9 | public operator fun NbtList.plusAssign(value: Byte) { add(value) } 10 | /** 11 | * Adds a value with the appropriated [NbtTag] wrapper. 12 | */ 13 | public operator fun NbtList.plusAssign(value: Short) { add(value) } 14 | /** 15 | * Adds a value with the appropriated [NbtTag] wrapper. 16 | */ 17 | public operator fun NbtList.plusAssign(value: Int) { add(value) } 18 | /** 19 | * Adds a value with the appropriated [NbtTag] wrapper. 20 | */ 21 | public operator fun NbtList.plusAssign(value: Long) { add(value) } 22 | /** 23 | * Adds a value with the appropriated [NbtTag] wrapper. 24 | */ 25 | public operator fun NbtList.plusAssign(value: Float) { add(value) } 26 | /** 27 | * Adds a value with the appropriated [NbtTag] wrapper. 28 | */ 29 | public operator fun NbtList.plusAssign(value: Double) { add(value) } 30 | /** 31 | * Adds a value with the appropriated [NbtTag] wrapper. 32 | */ 33 | public operator fun NbtList.plusAssign(value: String) { add(value) } 34 | /** 35 | * Adds a value with the appropriated [NbtTag] wrapper. 36 | */ 37 | public operator fun NbtList.plusAssign(value: ByteArray) { add(value) } 38 | /** 39 | * Adds a value with the appropriated [NbtTag] wrapper. 40 | */ 41 | public operator fun NbtList.plusAssign(value: Array) { add(value) } 42 | /** 43 | * Adds a value with the appropriated [NbtTag] wrapper. 44 | */ 45 | public operator fun NbtList.plusAssign(value: IntArray) { add(value) } 46 | /** 47 | * Adds a value with the appropriated [NbtTag] wrapper. 48 | */ 49 | public operator fun NbtList.plusAssign(value: Array) { add(value) } 50 | /** 51 | * Adds a value with the appropriated [NbtTag] wrapper. 52 | */ 53 | public operator fun NbtList.plusAssign(value: LongArray) { add(value) } 54 | /** 55 | * Adds a value with the appropriated [NbtTag] wrapper. 56 | */ 57 | public operator fun NbtList.plusAssign(value: Array) { add(value) } 58 | /** 59 | * Adds a value with the appropriated [NbtTag] wrapper. 60 | */ 61 | public operator fun NbtList.plusAssign(value: Map) { add(value) } 62 | /** 63 | * Adds a value with the appropriated [NbtTag] wrapper. 64 | */ 65 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 66 | /** 67 | * Adds a value with the appropriated [NbtTag] wrapper. 68 | */ 69 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 70 | /** 71 | * Adds a value with the appropriated [NbtTag] wrapper. 72 | */ 73 | @JvmName("plusAssignListOfList") 74 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 75 | /** 76 | * Adds a value with the appropriated [NbtTag] wrapper. 77 | */ 78 | @JvmName("plusAssignListOfList") 79 | public operator fun NbtList>.plusAssign(value: ByteArray) { add(value) } 80 | /** 81 | * Adds a value with the appropriated [NbtTag] wrapper. 82 | */ 83 | @JvmName("plusAssignListOfListIterByte") 84 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 85 | /** 86 | * Adds a value with the appropriated [NbtTag] wrapper. 87 | */ 88 | @JvmName("plusAssignListOfList") 89 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 90 | /** 91 | * Adds a value with the appropriated [NbtTag] wrapper. 92 | */ 93 | @JvmName("plusAssignListOfList") 94 | public operator fun NbtList>.plusAssign(value: ShortArray) { add(value) } 95 | /** 96 | * Adds a value with the appropriated [NbtTag] wrapper. 97 | */ 98 | @JvmName("plusAssignListOfListIterShort") 99 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 100 | /** 101 | * Adds a value with the appropriated [NbtTag] wrapper. 102 | */ 103 | @JvmName("plusAssignListOfList") 104 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 105 | /** 106 | * Adds a value with the appropriated [NbtTag] wrapper. 107 | */ 108 | @JvmName("plusAssignListOfList") 109 | public operator fun NbtList>.plusAssign(value: IntArray) { add(value) } 110 | /** 111 | * Adds a value with the appropriated [NbtTag] wrapper. 112 | */ 113 | @JvmName("plusAssignListOfListIterInt") 114 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 115 | /** 116 | * Adds a value with the appropriated [NbtTag] wrapper. 117 | */ 118 | @JvmName("plusAssignListOfList") 119 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 120 | /** 121 | * Adds a value with the appropriated [NbtTag] wrapper. 122 | */ 123 | @JvmName("plusAssignListOfList") 124 | public operator fun NbtList>.plusAssign(value: LongArray) { add(value) } 125 | /** 126 | * Adds a value with the appropriated [NbtTag] wrapper. 127 | */ 128 | @JvmName("plusAssignListOfListIterLong") 129 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 130 | /** 131 | * Adds a value with the appropriated [NbtTag] wrapper. 132 | */ 133 | @JvmName("plusAssignListOfList") 134 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 135 | /** 136 | * Adds a value with the appropriated [NbtTag] wrapper. 137 | */ 138 | @JvmName("plusAssignListOfList") 139 | public operator fun NbtList>.plusAssign(value: FloatArray) { add(value) } 140 | /** 141 | * Adds a value with the appropriated [NbtTag] wrapper. 142 | */ 143 | @JvmName("plusAssignListOfListIterFloat") 144 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 145 | /** 146 | * Adds a value with the appropriated [NbtTag] wrapper. 147 | */ 148 | @JvmName("plusAssignListOfList") 149 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 150 | /** 151 | * Adds a value with the appropriated [NbtTag] wrapper. 152 | */ 153 | @JvmName("plusAssignListOfListIterString") 154 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 155 | /** 156 | * Adds a value with the appropriated [NbtTag] wrapper. 157 | */ 158 | @JvmName("plusAssignListOfList") 159 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 160 | /** 161 | * Adds a value with the appropriated [NbtTag] wrapper. 162 | */ 163 | @JvmName("plusAssignListOfListIterByteArray") 164 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 165 | /** 166 | * Adds a value with the appropriated [NbtTag] wrapper. 167 | */ 168 | @JvmName("plusAssignListOfList") 169 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 170 | /** 171 | * Adds a value with the appropriated [NbtTag] wrapper. 172 | */ 173 | @JvmName("plusAssignListOfListIterIntArray") 174 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 175 | /** 176 | * Adds a value with the appropriated [NbtTag] wrapper. 177 | */ 178 | @JvmName("plusAssignListOfList") 179 | public operator fun NbtList>.plusAssign(value: Array) { add(value) } 180 | /** 181 | * Adds a value with the appropriated [NbtTag] wrapper. 182 | */ 183 | @JvmName("plusAssignListOfListIterLongArray") 184 | public operator fun NbtList>.plusAssign(value: Iterable) { add(value) } 185 | /** 186 | * Adds a value with the appropriated [NbtTag] wrapper. 187 | */ 188 | @JvmName("plusAssignListOfList") 189 | public operator fun NbtList>.plusAssign(value: Array>) { add(value) } 190 | /** 191 | * Adds a value with the appropriated [NbtTag] wrapper. 192 | */ 193 | @JvmName("plusAssignListOfListIterCompound") 194 | public operator fun NbtList>.plusAssign(value: Iterable>) { add(value) } 195 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil-remove.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | /** 7 | * Removes a tag containing the given value. 8 | */ 9 | public fun NbtList.remove(value: Byte): Boolean = remove(NbtByte(value)) 10 | /** 11 | * Removes a tag containing the given value. 12 | */ 13 | public fun NbtList.remove(value: Short): Boolean = remove(NbtShort(value)) 14 | /** 15 | * Removes a tag containing the given value. 16 | */ 17 | public fun NbtList.remove(value: Int): Boolean = remove(NbtInt(value)) 18 | /** 19 | * Removes a tag containing the given value. 20 | */ 21 | public fun NbtList.remove(value: Long): Boolean = remove(NbtLong(value)) 22 | /** 23 | * Removes a tag containing the given value. 24 | */ 25 | public fun NbtList.remove(value: Float): Boolean = remove(NbtFloat(value)) 26 | /** 27 | * Removes a tag containing the given value. 28 | */ 29 | public fun NbtList.remove(value: Double): Boolean = remove(NbtDouble(value)) 30 | /** 31 | * Removes a tag containing the given value. 32 | */ 33 | public fun NbtList.remove(value: String): Boolean = remove(NbtString(value)) 34 | /** 35 | * Removes a tag containing the given value. 36 | */ 37 | public fun NbtList.remove(value: ByteArray): Boolean = remove(NbtByteArray(value)) 38 | /** 39 | * Removes a tag containing the given value. 40 | */ 41 | public fun NbtList.remove(value: Array): Boolean = remove(NbtByteArray(value.toByteArray())) 42 | /** 43 | * Removes a tag containing the given value. 44 | */ 45 | public fun NbtList.remove(value: IntArray): Boolean = remove(NbtIntArray(value)) 46 | /** 47 | * Removes a tag containing the given value. 48 | */ 49 | public fun NbtList.remove(value: Array): Boolean = remove(NbtIntArray(value.toIntArray())) 50 | /** 51 | * Removes a tag containing the given value. 52 | */ 53 | public fun NbtList.remove(value: LongArray): Boolean = remove(NbtLongArray(value)) 54 | /** 55 | * Removes a tag containing the given value. 56 | */ 57 | public fun NbtList.remove(value: Array): Boolean = remove(NbtLongArray(value.toLongArray())) 58 | /** 59 | * Removes a tag containing the given value. 60 | */ 61 | public fun NbtList.remove(value: Map): Boolean = remove(NbtCompound(value)) 62 | /** 63 | * Removes a tag containing the given value. 64 | */ 65 | public fun NbtList>.remove(value: Iterable): Boolean = remove(NbtList(value)) 66 | /** 67 | * Removes a tag containing the given value. 68 | */ 69 | public fun NbtList>.remove(value: Array): Boolean = remove(NbtList(*value)) 70 | /** 71 | * Removes a tag containing the given value. 72 | */ 73 | @JvmName("removeListOfList") 74 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 75 | /** 76 | * Removes a tag containing the given value. 77 | */ 78 | @JvmName("removeListOfList") 79 | public fun NbtList>.remove(value: ByteArray): Boolean = remove(value.toNbtList()) 80 | /** 81 | * Removes a tag containing the given value. 82 | */ 83 | @JvmName("removeListOfListIterByte") 84 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 85 | /** 86 | * Removes a tag containing the given value. 87 | */ 88 | @JvmName("removeListOfList") 89 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 90 | /** 91 | * Removes a tag containing the given value. 92 | */ 93 | @JvmName("removeListOfList") 94 | public fun NbtList>.remove(value: ShortArray): Boolean = remove(value.toNbtList()) 95 | /** 96 | * Removes a tag containing the given value. 97 | */ 98 | @JvmName("removeListOfListIterShort") 99 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 100 | /** 101 | * Removes a tag containing the given value. 102 | */ 103 | @JvmName("removeListOfList") 104 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 105 | /** 106 | * Removes a tag containing the given value. 107 | */ 108 | @JvmName("removeListOfList") 109 | public fun NbtList>.remove(value: IntArray): Boolean = remove(value.toNbtList()) 110 | /** 111 | * Removes a tag containing the given value. 112 | */ 113 | @JvmName("removeListOfListIterInt") 114 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 115 | /** 116 | * Removes a tag containing the given value. 117 | */ 118 | @JvmName("removeListOfList") 119 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 120 | /** 121 | * Removes a tag containing the given value. 122 | */ 123 | @JvmName("removeListOfList") 124 | public fun NbtList>.remove(value: LongArray): Boolean = remove(value.toNbtList()) 125 | /** 126 | * Removes a tag containing the given value. 127 | */ 128 | @JvmName("removeListOfListIterLong") 129 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 130 | /** 131 | * Removes a tag containing the given value. 132 | */ 133 | @JvmName("removeListOfList") 134 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 135 | /** 136 | * Removes a tag containing the given value. 137 | */ 138 | @JvmName("removeListOfList") 139 | public fun NbtList>.remove(value: FloatArray): Boolean = remove(value.toNbtList()) 140 | /** 141 | * Removes a tag containing the given value. 142 | */ 143 | @JvmName("removeListOfListIterFloat") 144 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 145 | /** 146 | * Removes a tag containing the given value. 147 | */ 148 | @JvmName("removeListOfList") 149 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 150 | /** 151 | * Removes a tag containing the given value. 152 | */ 153 | @JvmName("removeListOfListIterString") 154 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 155 | /** 156 | * Removes a tag containing the given value. 157 | */ 158 | @JvmName("removeListOfList") 159 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 160 | /** 161 | * Removes a tag containing the given value. 162 | */ 163 | @JvmName("removeListOfListIterByteArray") 164 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 165 | /** 166 | * Removes a tag containing the given value. 167 | */ 168 | @JvmName("removeListOfList") 169 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 170 | /** 171 | * Removes a tag containing the given value. 172 | */ 173 | @JvmName("removeListOfListIterIntArray") 174 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 175 | /** 176 | * Removes a tag containing the given value. 177 | */ 178 | @JvmName("removeListOfList") 179 | public fun NbtList>.remove(value: Array): Boolean = remove(value.toNbtList()) 180 | /** 181 | * Removes a tag containing the given value. 182 | */ 183 | @JvmName("removeListOfListIterLongArray") 184 | public fun NbtList>.remove(value: Iterable): Boolean = remove(value.toNbtList()) 185 | /** 186 | * Removes a tag containing the given value. 187 | */ 188 | @JvmName("removeListOfList") 189 | public fun NbtList>.remove(value: Array>): Boolean = remove(value.toNbtList()) 190 | /** 191 | * Removes a tag containing the given value. 192 | */ 193 | @JvmName("removeListOfListIterCompound") 194 | public fun NbtList>.remove(value: Iterable>): Boolean = add(value.toNbtList()) 195 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil-toNbtList.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | /** 7 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 8 | */ 9 | @JvmName("booleanIterableToList") 10 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtByte(it) }) 11 | /** 12 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 13 | */ 14 | @JvmName("byteIterableToList") 15 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtByte(it) }) 16 | /** 17 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 18 | */ 19 | @JvmName("shortIterableToList") 20 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtShort(it) }) 21 | /** 22 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 23 | */ 24 | @JvmName("intIterableToList") 25 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtInt(it) }) 26 | /** 27 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 28 | */ 29 | @JvmName("longIterableToList") 30 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtLong(it) }) 31 | /** 32 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 33 | */ 34 | @JvmName("floatIterableToList") 35 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtFloat(it) }) 36 | /** 37 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 38 | */ 39 | @JvmName("doubleIterableToList") 40 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtDouble(it) }) 41 | /** 42 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 43 | */ 44 | @JvmName("stringIterableToList") 45 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtString(it) }) 46 | /** 47 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 48 | */ 49 | @JvmName("byteArrayIterableToList") 50 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtByteArray(it) }) 51 | /** 52 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 53 | */ 54 | @JvmName("intArrayIterableToList") 55 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtIntArray(it) }) 56 | /** 57 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 58 | */ 59 | @JvmName("longArrayIterableToList") 60 | public fun Iterable.toNbtList(): NbtList = NbtList(map { NbtLongArray(it) }) 61 | /** 62 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 63 | */ 64 | @JvmName("compoundIterableToList") 65 | public fun Iterable>.toNbtList(): NbtList = NbtList(map { NbtCompound(it) }) 66 | /** 67 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 68 | */ 69 | @JvmName("listIterableToList") 70 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it) }) 71 | /** 72 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 73 | */ 74 | @JvmName("byteListIterableToList") 75 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 76 | /** 77 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 78 | */ 79 | @JvmName("shortListIterableToList") 80 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 81 | /** 82 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 83 | */ 84 | @JvmName("intListIterableToList") 85 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 86 | /** 87 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 88 | */ 89 | @JvmName("longListIterableToList") 90 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 91 | /** 92 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 93 | */ 94 | @JvmName("floatListIterableToList") 95 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 96 | /** 97 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 98 | */ 99 | @JvmName("doubleListIterableToList") 100 | public fun Iterable>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 101 | 102 | /** 103 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 104 | */ 105 | @JvmName("arrayToNbtList") 106 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtByte(it) }) 107 | /** 108 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 109 | */ 110 | @JvmName("arrayToNbtList") 111 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtByte(it) }) 112 | /** 113 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 114 | */ 115 | @JvmName("arrayToNbtList") 116 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtShort(it) }) 117 | /** 118 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 119 | */ 120 | @JvmName("arrayToNbtList") 121 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtInt(it) }) 122 | /** 123 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 124 | */ 125 | @JvmName("arrayToNbtList") 126 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtLong(it) }) 127 | /** 128 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 129 | */ 130 | @JvmName("arrayToNbtList") 131 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtFloat(it) }) 132 | /** 133 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 134 | */ 135 | @JvmName("arrayToNbtList") 136 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtDouble(it) }) 137 | /** 138 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 139 | */ 140 | @JvmName("arrayToNbtList") 141 | public fun BooleanArray.toNbtList(): NbtList = NbtList(map { NbtByte(it) }) 142 | /** 143 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 144 | */ 145 | @JvmName("arrayToNbtList") 146 | public fun ByteArray.toNbtList(): NbtList = NbtList(map { NbtByte(it) }) 147 | /** 148 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 149 | */ 150 | @JvmName("arrayToNbtList") 151 | public fun ShortArray.toNbtList(): NbtList = NbtList(map { NbtShort(it) }) 152 | /** 153 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 154 | */ 155 | @JvmName("arrayToNbtList") 156 | public fun IntArray.toNbtList(): NbtList = NbtList(map { NbtInt(it) }) 157 | /** 158 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 159 | */ 160 | @JvmName("arrayToNbtList") 161 | public fun LongArray.toNbtList(): NbtList = NbtList(map { NbtLong(it) }) 162 | /** 163 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 164 | */ 165 | @JvmName("arrayToNbtList") 166 | public fun FloatArray.toNbtList(): NbtList = NbtList(map { NbtFloat(it) }) 167 | /** 168 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 169 | */ 170 | @JvmName("arrayToNbtList") 171 | public fun DoubleArray.toNbtList(): NbtList = NbtList(map { NbtDouble(it) }) 172 | /** 173 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 174 | */ 175 | @JvmName("arrayToNbtList") 176 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtString(it) }) 177 | /** 178 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 179 | */ 180 | @JvmName("arrayToNbtList") 181 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtByteArray(it) }) 182 | /** 183 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 184 | */ 185 | @JvmName("arrayToNbtList") 186 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtIntArray(it) }) 187 | /** 188 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 189 | */ 190 | @JvmName("arrayToNbtList") 191 | public fun Array.toNbtList(): NbtList = NbtList(map { NbtLongArray(it) }) 192 | /** 193 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 194 | */ 195 | @JvmName("arrayToNbtList") 196 | public fun Array>.toNbtList(): NbtList = NbtList(map { NbtCompound(it) }) 197 | /** 198 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 199 | */ 200 | @JvmName("arrayToNbtList") 201 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(*it) }) 202 | /** 203 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 204 | */ 205 | @JvmName("arrayToNbtList") 206 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 207 | /** 208 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 209 | */ 210 | @JvmName("arrayToNbtList") 211 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 212 | /** 213 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 214 | */ 215 | @JvmName("arrayToNbtList") 216 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 217 | /** 218 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 219 | */ 220 | @JvmName("arrayToNbtList") 221 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 222 | /** 223 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 224 | */ 225 | @JvmName("arrayToNbtList") 226 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 227 | /** 228 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 229 | */ 230 | @JvmName("arrayToNbtList") 231 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 232 | /** 233 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 234 | */ 235 | @JvmName("arrayToNbtList") 236 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 237 | /** 238 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 239 | */ 240 | @JvmName("arrayToNbtList") 241 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 242 | /** 243 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 244 | */ 245 | @JvmName("arrayToNbtList") 246 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 247 | /** 248 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 249 | */ 250 | @JvmName("arrayToNbtList") 251 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 252 | /** 253 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 254 | */ 255 | @JvmName("arrayToNbtList") 256 | public fun Array>>.toNbtList(): NbtList>> = NbtList(map { NbtList(it.toNbtList()) }) 257 | /** 258 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 259 | */ 260 | @JvmName("arrayToNbtList") 261 | public fun Array>>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 262 | /** 263 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 264 | */ 265 | @JvmName("arrayIterableNbtTagToNbtList") 266 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it) }) 267 | /** 268 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 269 | */ 270 | @JvmName("arrayIterableByteToNbtList") 271 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 272 | /** 273 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 274 | */ 275 | @JvmName("arrayIterableShortToNbtList") 276 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 277 | /** 278 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 279 | */ 280 | @JvmName("arrayIterableIntToNbtList") 281 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 282 | /** 283 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 284 | */ 285 | @JvmName("arrayIterableLongToNbtList") 286 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 287 | /** 288 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 289 | */ 290 | @JvmName("arrayIterableFloatToNbtList") 291 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 292 | /** 293 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 294 | */ 295 | @JvmName("arrayIterableDoubleToNbtList") 296 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 297 | /** 298 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 299 | */ 300 | @JvmName("arrayIterableStringToNbtList") 301 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 302 | /** 303 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 304 | */ 305 | @JvmName("arrayIterableByteArrayToNbtList") 306 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 307 | /** 308 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 309 | */ 310 | @JvmName("arrayIterableIntArrayToNbtList") 311 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 312 | /** 313 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 314 | */ 315 | @JvmName("arrayIterableLongArrayToNbtList") 316 | public fun Array>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 317 | /** 318 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 319 | */ 320 | @JvmName("arrayIterableIterableNbtTagToNbtList") 321 | public fun Array>>.toNbtList(): NbtList>> = NbtList(map { NbtList(it.toNbtList()) }) 322 | /** 323 | * Returns a [NbtList] contained all elements wrapped in the appropriated [NbtTag]. 324 | */ 325 | @JvmName("arrayIterableCompoundToNbtList") 326 | public fun Array>>.toNbtList(): NbtList> = NbtList(map { NbtList(it.toNbtList()) }) 327 | -------------------------------------------------------------------------------- /src/main/kotlin/br/com/gamemods/nbtmanipulator/NbtUtil.kt: -------------------------------------------------------------------------------- 1 | @file:JvmName("NbtUtil") 2 | @file:JvmMultifileClass 3 | 4 | package br.com.gamemods.nbtmanipulator 5 | 6 | internal const val BYTE_TRUE: Byte = 1 7 | 8 | internal inline fun NbtList<*>.cast(): NbtList { 9 | /*check(Nbt::class == NbtTag::class) { 10 | "NbtTag is not a valid type for NbtList" 11 | }*/ 12 | 13 | if (isNotEmpty()) { 14 | check(first()::class == Nbt::class) { 15 | "Cannot use this list as NbtList<${Nbt::class.simpleName}>" 16 | } 17 | } 18 | 19 | @Suppress("UNCHECKED_CAST") 20 | return this as NbtList 21 | } 22 | -------------------------------------------------------------------------------- /src/pages/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-hacker 2 | -------------------------------------------------------------------------------- /src/pages/assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | 4 | @import "{{ site.theme }}"; 5 | code.highlighter-rouge { 6 | color: #d0d0d0; 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/test/JavaUsage.java: -------------------------------------------------------------------------------- 1 | package test; 2 | 3 | import br.com.gamemods.nbtmanipulator.NbtInt; 4 | import br.com.gamemods.nbtmanipulator.NbtList; 5 | import br.com.gamemods.nbtmanipulator.NbtUtil; 6 | import junit.framework.TestCase; 7 | 8 | import java.util.Arrays; 9 | 10 | public class JavaUsage extends TestCase { 11 | public void testIntListIterableToList() { 12 | NbtList> tag = NbtUtil.intListIterableToList( 13 | Arrays.asList( 14 | Arrays.asList(1, 2, 3), 15 | Arrays.asList(4, 5, 6) 16 | ) 17 | ); 18 | } 19 | 20 | public void testIntIterableToList() { 21 | NbtList tags = NbtUtil.intIterableToList(Arrays.asList(1,2,3)); 22 | } 23 | 24 | public void testNbtList() { 25 | NbtList tags = NbtList.create(1, 2, 3); 26 | } 27 | 28 | public void testCreateSublist() { 29 | NbtList> tags = NbtList.createIntSublist( 30 | new int[]{1,2,3}, 31 | new int[]{4,5,6} 32 | ); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/CompoundStringParserTest.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import junit.framework.TestCase 4 | 5 | class CompoundStringParserTest: TestCase() { 6 | 7 | fun testCompound() { 8 | assertEquals(NbtCompound(), NbtCompound("{}")) 9 | assertEquals(NbtCompound().also { 10 | it["a"] = 2 11 | }, NbtCompound("""{"a"=NbtInt(2)}""")) 12 | 13 | assertEquals(NbtCompound().also { 14 | it["a"] = 2 15 | it["b"] = 3.toByte() 16 | }, NbtCompound("""{"a"=NbtInt(2), "b"=NbtByte(3)}""")) 17 | 18 | assertEquals(NbtCompound().also { 19 | it["abc"] = 2L 20 | it["dfg"] = byteArrayOf(-4, 5, 127) 21 | it["hij"] = listOf(1, 2, 3, 4).toNbtList() 22 | }, NbtCompound("""{"abc"=NbtLong(2), "dfg"=NbtByteArray[-4, 5, 127], "hij"=NbtList[NbtInt(1), NbtInt(2), NbtInt(3), NbtInt(4)]}""")) 23 | } 24 | 25 | fun testComplexCompound() { 26 | assertEquals( 27 | NbtCompound().also { main -> 28 | main["Pos"] = listOf(124.48, 65.125, 813.3).toNbtList() 29 | main["Effects"] = listOf( 30 | NbtCompound().also { 31 | it["Id"] = "minecraft:regeneration" 32 | it["Duration"] = 322 33 | }, 34 | NbtCompound().also { 35 | it["Id"] = "minecraft:health" 36 | it["Strength"] = 2.toByte() 37 | } 38 | ).toNbtList() 39 | main["Hack Attempt\"=NbtInt(2)"] = listOf( 40 | NbtCompound().also { 41 | it["Injection\"}, NbtByteArray[2, 3, 5]"] = "[[[[]]{{{}\")\"}\"=23" 42 | } 43 | ).toNbtList() 44 | }, 45 | NbtCompound("""{"Pos"=NbtList[NbtDouble(124.48), NbtDouble(65.125), NbtDouble(813.3)], "Effects"=NbtList[NbtCompound{"Id"=NbtString("minecraft:regeneration"), "Duration"=NbtInt(322)}, NbtCompound{"Id"=NbtString("minecraft:health"), "Strength"=NbtByte(2)}], "Hack Attempt\"=NbtInt(2)"=NbtList[NbtCompound{"Injection\"}, NbtByteArray[2, 3, 5]"=NbtString("[[[[]]{{{}\")\"}\"=23")}]}""") 46 | ) 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/KotlinUsage.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import junit.framework.TestCase 4 | 5 | class KotlinUsage: TestCase() { 6 | fun testUsage() { 7 | val list = listOf(2,3,4,5,6).toNbtList() 8 | list += 7 9 | assertTrue(7 in list) 10 | list -= 7 11 | assertTrue(7 !in list) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/LevelDatTest.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import junit.framework.TestCase 4 | import java.io.File 5 | 6 | class LevelDatTest: TestCase() { 7 | fun testReadLevelDat() { 8 | assertEquals(NbtList(NbtInt(1), NbtInt(2), NbtInt(3)), listOf(1, 2, 3).toNbtList()) 9 | LevelDatTest::class.java.getResourceAsStream("/level-java-edition.dat").use { inputStream -> 10 | NbtIO.readNbtFile(inputStream) 11 | } 12 | } 13 | 14 | fun testReadBedrockLevelDat() { 15 | LevelDatTest::class.java.getResourceAsStream("/level-bedrock-edition.dat").use { inputStream -> 16 | val nbtFile = NbtIO.readNbtFile(inputStream, compressed = false, littleEndian = true, readHeaders = true) 17 | println(nbtFile) 18 | } 19 | } 20 | 21 | fun testAutoDetection() { 22 | val javaNbt = NbtIO.readNbtFileDetectingSettings(File("src/test/resources/level-java-edition.dat")) 23 | val bedrockNbt = NbtIO.readNbtFileDetectingSettings(File("src/test/resources/level-bedrock-edition.dat")) 24 | println(javaNbt) 25 | println(bedrockNbt) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/ListStringParserTest.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import junit.framework.TestCase 4 | 5 | class ListStringParserTest: TestCase() { 6 | 7 | fun testListOfSimpleTags() { 8 | assertEquals(NbtList(), NbtList("[]")) 9 | assertEquals(listOf(1, 2, -128).toNbtList(), NbtList("[NbtByte(1), NbtByte(2), NbtByte(-128)]")) 10 | assertEquals(listOf(1, 2, -128).toNbtList(), NbtList("[NbtShort(1), NbtShort(2), NbtShort(-128)]")) 11 | assertEquals(listOf(1, 2, -128).toNbtList(), NbtList("[NbtInt(1), NbtInt(2), NbtInt(-128)]")) 12 | assertEquals(listOf(1, 2, -128).toNbtList(), NbtList("[NbtLong(1), NbtLong(2), NbtLong(-128)]")) 13 | assertEquals(listOf(1.1F, 2.1F, -128.1F).toNbtList(), NbtList("[NbtFloat(1.1), NbtFloat(2.1), NbtFloat(-128.1)]")) 14 | assertEquals(listOf(1.1, 2.1, -128.1).toNbtList(), NbtList("[NbtDouble(1.1), NbtDouble(2.1), NbtDouble(-128.1)]")) 15 | } 16 | 17 | fun testListOfArrayTags() { 18 | assertEquals(listOf(listOf(1,2,3), listOf(4,5,6)).toNbtList(), NbtList>( 19 | "[NbtList[NbtInt(1), NbtInt(2), NbtInt(3)], NbtList[NbtInt(4), NbtInt(5), NbtInt(6)]]" 20 | )) 21 | 22 | assertEquals(listOf(byteArrayOf(1, 2, 3), byteArrayOf(4, 5, 6)).toNbtList(), NbtList( 23 | "[NbtByteArray[1, 2, 3], NbtByteArray[4, 5, 6]]" 24 | )) 25 | 26 | assertEquals(listOf(intArrayOf(1, 2, 3), intArrayOf(4, 5, 6)).toNbtList(), NbtList( 27 | "[NbtIntArray[1, 2, 3], NbtIntArray[4, 5, 6]]" 28 | )) 29 | 30 | assertEquals(listOf(longArrayOf(1, 2, 3), longArrayOf(4, 5, 6)).toNbtList(), NbtList( 31 | "[NbtLongArray[1, 2, 3], NbtLongArray[4, 5, 6]]" 32 | )) 33 | } 34 | 35 | fun testListOfStrings() { 36 | assertEquals(listOf("abc", "def").toNbtList(), NbtList( 37 | """[NbtString("abc"), NbtString("def")]""" 38 | )) 39 | 40 | assertEquals(listOf("Injection attempt \")Injected").toNbtList(), NbtList( 41 | """[NbtString("Injection attempt \")Injected")]""" 42 | )) 43 | 44 | assertEquals(listOf("Injection attempt \")]Injected", "after[[[").toNbtList(), NbtList( 45 | """[NbtString("Injection attempt \")]Injected"), NbtString("after[[[")]""" 46 | )) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/SimpleStringParserTest.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import junit.framework.TestCase 4 | import kotlin.test.assertFailsWith 5 | 6 | class SimpleStringParserTest: TestCase() { 7 | fun testSimpleTags() { 8 | assertEquals(NbtByte((-128).toByte()), NbtByte("-128")) 9 | assertEquals(NbtByte(255), NbtByte.unsigned("255")) 10 | assertEquals(NbtShort(3232), NbtShort("3232")) 11 | assertEquals(NbtShort(-444), NbtShort("-444")) 12 | assertEquals(NbtInt(15151555), NbtInt("15151555")) 13 | assertEquals(NbtInt(-15151555), NbtInt("-15151555")) 14 | assertEquals(NbtInt(-15151555), NbtInt("-15151555")) 15 | assertEquals(NbtLong(5645464489787987894), NbtLong("5645464489787987894")) 16 | assertEquals(NbtLong(-5645464489787987894), NbtLong("-5645464489787987894")) 17 | assertEquals(NbtFloat(32e15F), NbtFloat("32e15")) 18 | assertEquals(NbtFloat(-32e-15F), NbtFloat("-32e-15")) 19 | assertEquals(NbtDouble(1247e143), NbtDouble("1247e143")) 20 | assertEquals(NbtDouble(-1247e143), NbtDouble("-1247e143")) 21 | } 22 | 23 | fun testArrays() { 24 | assertEquals(NbtByteArray(byteArrayOf(32, 48, 127, -49)), NbtByteArray("[32, 48, 127, -49]")) 25 | assertEquals(NbtIntArray(intArrayOf(3225, 6484, -4891, 0, -415843255)), NbtIntArray("[3225, 6484, -4891, 0, -415843255]")) 26 | assertEquals(NbtLongArray(longArrayOf(15648489415618, 15648747841152218, -15648489745415, 0)), 27 | NbtLongArray("[15648489415618, 15648747841152218, -15648489745415, 0]")) 28 | } 29 | 30 | fun testEmptyArrays() { 31 | assertEquals(NbtByteArray(), NbtByteArray("[]")) 32 | assertEquals(NbtIntArray(), NbtIntArray("[]")) 33 | assertEquals(NbtLongArray(), NbtLongArray("[]")) 34 | } 35 | 36 | fun testIllegalArrays() { 37 | assertFailsWith(NumberFormatException::class) { NbtByteArray("[-130]") } 38 | assertFailsWith(IllegalArgumentException::class) { NbtIntArray("[5") } 39 | assertFailsWith(IllegalArgumentException::class) { NbtLongArray("[1,2,3]") } 40 | } 41 | 42 | fun testByteRange() { 43 | assertFailsWith(NumberFormatException::class) { NbtByte(256) } 44 | assertFailsWith(NumberFormatException::class) { NbtByte("256") } 45 | assertFailsWith(NumberFormatException::class) { NbtByte(-1) } 46 | assertFailsWith(NumberFormatException::class) { NbtByte.unsigned("-1") } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/StringValueWithStringConstructorTest.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import junit.framework.TestCase 4 | 5 | class StringValueWithStringConstructorTest: TestCase() { 6 | 7 | private fun testEquality(value: V, typed: (V) -> T, string: (String) -> T, getter: (T) -> V) { 8 | assertEquals(value, getter(string(typed(value).stringValue))) 9 | } 10 | 11 | fun testSimpleTags() { 12 | testEquality((-28).toByte(), ::NbtByte, ::NbtByte, NbtByte::signed) 13 | testEquality((-3255).toShort(), ::NbtShort, ::NbtShort, NbtShort::value) 14 | testEquality(32558887, ::NbtInt, ::NbtInt, NbtInt::value) 15 | testEquality(-32558887L, ::NbtLong, ::NbtLong, NbtLong::value) 16 | testEquality(-3225.0, ::NbtDouble, ::NbtDouble, NbtDouble::value) 17 | testEquality(-3225F, ::NbtFloat, ::NbtFloat, NbtFloat::value) 18 | testEquality("Hello \"123\")Injection?", ::NbtString, ::NbtString, NbtString::value) 19 | } 20 | 21 | fun testArrays() { 22 | assertTrue(byteArrayOf(-28 ,0 , 127).contentEquals(NbtByteArray(NbtByteArray(byteArrayOf(-28 ,0 , 127)).stringValue).value)) 23 | assertTrue(intArrayOf(-28 ,0 , 127).contentEquals(NbtIntArray(NbtIntArray(intArrayOf(-28 ,0 , 127)).stringValue).value)) 24 | assertTrue(longArrayOf(-28 ,0 , 127).contentEquals(NbtLongArray(NbtLongArray(longArrayOf(-28 ,0 , 127)).stringValue).value)) 25 | } 26 | 27 | fun testLists() { 28 | val constructor1 = { input: Collection -> NbtList(input) } 29 | val constructor2 = { input: String -> NbtList(input) } 30 | val getter: (NbtList<*>) -> Collection = { list: NbtList<*> -> list } 31 | fun testEquality(list: NbtList<*>) = testEquality(list, constructor1, constructor2, getter) 32 | 33 | testEquality(listOf(1, 2, 3).toNbtList()) 34 | testEquality(listOf(1, 2, 3).toNbtList()) 35 | 36 | val complexCompound = NbtCompound().also { main -> 37 | main["Pos"] = listOf(124.48, 65.125, 813.3).toNbtList() 38 | main["Effects"] = listOf( 39 | NbtCompound().also { 40 | it["Id"] = "minecraft:regeneration" 41 | it["Duration"] = 322 42 | }, 43 | NbtCompound().also { 44 | it["Id"] = "minecraft:health" 45 | it["Strength"] = 2.toByte() 46 | } 47 | ).toNbtList() 48 | main["Hack Attempt\"=NbtInt(2)"] = listOf( 49 | NbtCompound().also { 50 | it["Injection\"}, NbtByteArray[2, 3, 5]"] = "[[[[]]{{{}\")\"}\"=23" 51 | } 52 | ).toNbtList() 53 | } 54 | 55 | testEquality(listOf(complexCompound, complexCompound, complexCompound).toNbtList()) 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/test/kotlin/br/com/gamemods/nbtmanipulator/ToStringTest.kt: -------------------------------------------------------------------------------- 1 | package br.com.gamemods.nbtmanipulator 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | 6 | class ToStringTest { 7 | @Test 8 | fun testList() { 9 | assertEquals("NbtList[NbtInt(1), NbtInt(2), NbtInt(3)]", listOf(1,2,3).toNbtList().toString()) 10 | assertEquals("NbtList[]", emptyList().toNbtList().toString()) 11 | } 12 | 13 | @Test 14 | fun testArrays() { 15 | assertEquals("NbtByteArray[1, 2, 3]", NbtByteArray(byteArrayOf(1, 2, 3)).toString()) 16 | } 17 | 18 | @Test 19 | fun testCompounds() { 20 | assertEquals("NbtCompound{}", NbtCompound().toString()) 21 | assertEquals("""NbtCompound{"id"=NbtString("minecraft:dirt"), "data"=NbtByte(1)}""", 22 | NbtCompound().also { 23 | it["id"] = "minecraft:dirt" 24 | it["data"] = 1.toByte() 25 | }.toString() 26 | ) 27 | } 28 | 29 | @Test 30 | fun testStrings() { 31 | assertEquals("NbtString(\"Hi \\\"PlayerName\\\".\")",NbtString("""Hi "PlayerName".""").toString()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/resources/level-bedrock-edition.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerNukkit/NBT-Manipulator/b63a1bd4a406310097e314ef911650026dd812cb/src/test/resources/level-bedrock-edition.dat -------------------------------------------------------------------------------- /src/test/resources/level-java-edition.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PowerNukkit/NBT-Manipulator/b63a1bd4a406310097e314ef911650026dd812cb/src/test/resources/level-java-edition.dat --------------------------------------------------------------------------------