Skip to content

Commit 23d34e0

Browse files
committed
Sponge v3 and Lite v1-v4 support
1 parent 7b4c2be commit 23d34e0

File tree

4 files changed

+99
-12
lines changed

4 files changed

+99
-12
lines changed

common/src/main/kotlin/com/lambda/util/extension/Nbt.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ fun NbtCompound.putIntList(key: String, vararg values: Int) {
2929
put(key, values.fold(NbtList()) { list, value -> list.add(NbtInt.of(value)); list })
3030
}
3131

32+
/**
33+
* Deletes all the keys in a compound
34+
*/
35+
fun NbtCompound.clear() {
36+
keys.forEach { remove(it) }
37+
}
38+
3239
/**
3340
* Retrieves a vector from a tuple
3441
*/

common/src/main/kotlin/com/lambda/util/extension/Structures.kt

Lines changed: 86 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.lambda.util.extension
1919

2020
import com.lambda.Lambda.mc
2121
import com.lambda.util.VarIntIterator
22+
import com.lambda.util.math.MathUtils.logCap
2223
import com.lambda.util.world.FastVector
2324
import com.lambda.util.world.fastVectorOf
2425
import com.lambda.util.world.x
@@ -31,6 +32,7 @@ import net.minecraft.nbt.NbtList
3132
import net.minecraft.registry.RegistryEntryLookup
3233
import net.minecraft.structure.StructureTemplate
3334
import kotlin.experimental.and
35+
import kotlin.math.abs
3436

3537
private fun positionFromIndex(width: Int, length: Int, index: Int): FastVector {
3638
val y = index / (width * length)
@@ -49,8 +51,11 @@ fun StructureTemplate.readNbtOrException(
4951
fun StructureTemplate.readSpongeOrException(
5052
lookup: RegistryEntryLookup<Block>,
5153
nbt: NbtCompound,
52-
): Throwable? = when (nbt.getInt("Version")) {
53-
1, 2, 3 -> readSpongeV1OrException(lookup, nbt)
54+
): Throwable? = when (nbt.getInt("Version") +
55+
nbt.getCompound("Schematic").getInt("Version"))
56+
{
57+
1, 2 -> readSpongeV1OrException(lookup, nbt)
58+
3 -> readSpongeV3OrException(lookup, nbt)
5459
else -> IllegalStateException("Invalid sponge schematic version")
5560
}
5661

@@ -86,12 +91,8 @@ private fun StructureTemplate.readSpongeV1OrException(
8691
// ?.takeIf { 274945015809L times 16 < it } ?: 0L
8792

8893
val palette = nbt.getCompound("Palette")
89-
90-
val paletteMax = nbt.getInt("PaletteMax")
9194
val newPalette = NbtList()
9295

93-
if (palette.size != paletteMax) return IllegalStateException("Block palette size does not match the provided size (corrupted?)")
94-
9596
palette.keys
9697
.sortedBy { palette.getInt(it) }
9798
.forEach { key ->
@@ -143,16 +144,89 @@ private fun StructureTemplate.readSpongeV3OrException(
143144
lookup: RegistryEntryLookup<Block>,
144145
nbt: NbtCompound,
145146
): Throwable? {
146-
// Third revision
147-
// - 3D Biome support
148-
// - Rename Palette to BlockPalette
149-
// - Wordsmithing varint and palette usages
150-
nbt.put("Palette", nbt.getCompound("BlockPalette"))
147+
val schematic = nbt.getCompound("Schematic")
148+
val blocks = schematic.getCompound("Blocks")
149+
150+
schematic.put("Palette", blocks.getCompound("Palette"))
151+
schematic.putByteArray("BlockData", blocks.getByteArray("Data"))
152+
153+
nbt.clear()
154+
nbt.copyFrom(schematic)
151155

152156
return readSpongeV1OrException(lookup, nbt)
153157
}
154158

155159
fun StructureTemplate.readLitematicaOrException(
156160
lookup: RegistryEntryLookup<Block>,
157161
nbt: NbtCompound,
158-
): Throwable = NotImplementedError("Litematica is not supported, you can help by contributing to the project")
162+
): Throwable? {
163+
val version = nbt.getInt("MinecraftDataVersion")
164+
165+
val metadata = nbt.getCompound("Metadata")
166+
val author = metadata.getString("Author")
167+
168+
val dimension = metadata.getVector("EnclosingSize")
169+
170+
val newPalette = NbtList()
171+
val newBlocks = NbtList()
172+
173+
val regions = nbt.getCompound("Regions")
174+
regions.keys.map { regions.getCompound(it) }
175+
.forEach {
176+
val position = it.getVector("Position")
177+
val size = it.getVector("Size")
178+
179+
val xSizeAbs = abs(size.x)
180+
val ySizeAbs = abs(size.y)
181+
val zSizeAbs = abs(size.z)
182+
183+
if (size.x < 0) position.x %= size.x + 1
184+
if (size.y < 0) position.y %= size.y + 1
185+
if (size.z < 0) position.z %= size.z + 1
186+
187+
// The litematic's block state palette is the same as nbt
188+
newPalette.addAll(it.getList("BlockStatePalette", 10))
189+
190+
val palette = it.getLongArray("BlockStates")
191+
val bits = palette.size.logCap(2)
192+
val maxEntryValue = (1 shl bits) - 1L
193+
194+
for (x in 0 until xSizeAbs) {
195+
for (y in 0 until ySizeAbs) {
196+
for (z in 0 until zSizeAbs) {
197+
val index = (y * xSizeAbs * zSizeAbs) + z * xSizeAbs + x
198+
199+
val startOffset = index * bits
200+
val startArrIndex = startOffset / 64
201+
val endArrIndex = ((index + 1) * bits - 1) / 64
202+
val startBitOffset = startOffset % 64
203+
204+
205+
val stateId = if (startArrIndex == endArrIndex) {
206+
palette[startArrIndex] ushr startBitOffset and maxEntryValue
207+
} else {
208+
(palette[startArrIndex] ushr startBitOffset or palette[endArrIndex] shl (64 - startBitOffset)) and maxEntryValue
209+
}
210+
211+
newBlocks.add(NbtCompound().apply {
212+
putIntList("pos", x, y, z)
213+
putInt("state", stateId.toInt())
214+
})
215+
}
216+
}
217+
}
218+
}
219+
220+
// Construct a structure compatible nbt compound
221+
nbt.putInt("DataVersion", version)
222+
nbt.putIntList("size", dimension.x, dimension.y, dimension.z)
223+
nbt.put("palette", newPalette)
224+
nbt.put("blocks", newBlocks)
225+
nbt.putString("author", author)
226+
227+
// Fix the data for future versions
228+
DataFixTypes.STRUCTURE.update(mc.dataFixer, nbt, version)
229+
230+
// Use the StructureTemplate NBT read utils in order to construct the template
231+
return readNbtOrException(lookup, nbt)
232+
}

common/src/main/kotlin/com/lambda/util/math/MathUtils.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ object MathUtils {
3838

3939
fun Double.floorToInt() = floor(this).toInt()
4040
fun Double.ceilToInt() = ceil(this).toInt()
41+
fun Int.logCap(minimum: Int) = max(minimum.toDouble(), ceil(log2(toDouble()))).toInt()
4142

4243
fun <T : Number> T.roundToStep(step: T): T {
4344
val stepD = step.toDouble()

common/src/main/resources/lambda.accesswidener

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ accessible field net/minecraft/network/packet/c2s/login/LoginKeyC2SPacket nonce
6767
accessible method net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket <init> (IZLnet/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler;)V
6868
accessible field net/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket ATTACK Lnet/minecraft/network/packet/c2s/play/PlayerInteractEntityC2SPacket$InteractTypeHandler;
6969

70+
# Math
71+
accessible method net/minecraft/util/math/Vec3i setX (I)Lnet/minecraft/util/math/Vec3i;
72+
accessible method net/minecraft/util/math/Vec3i setY (I)Lnet/minecraft/util/math/Vec3i;
73+
accessible method net/minecraft/util/math/Vec3i setZ (I)Lnet/minecraft/util/math/Vec3i;
74+
7075
# Other
7176
accessible field net/minecraft/world/explosion/Explosion behavior Lnet/minecraft/world/explosion/ExplosionBehavior;
7277
accessible field net/minecraft/structure/StructureTemplate blockInfoLists Ljava/util/List;

0 commit comments

Comments
 (0)