diff --git a/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt b/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt index c05be666d..7b75c02b6 100644 --- a/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt +++ b/src/main/java/de/bixilon/minosoft/config/config/game/OtherGameConfig.kt @@ -17,4 +17,5 @@ import com.squareup.moshi.Json data class OtherGameConfig( @Json(name = "anti_moire_pattern") var antiMoirePattern: Boolean = true, + @Json(name = "flower_random_offset") var flowerRandomOffset: Boolean = true, ) diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt index 75274c952..eb86e72c0 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/Block.kt @@ -27,6 +27,7 @@ open class Block( val explosionResistance: Float = 0.0f, val hasDynamicShape: Boolean = false, val tintColor: RGBColor? = null, + val randomOffsetType: RandomOffsetTypes? = null, private val itemId: Int = 0, val tint: ResourceLocation? = null, val renderOverride: MutableList? = null, @@ -52,6 +53,13 @@ open class Block( var renderOverride: MutableList? = null + val explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f + val hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false + val tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) } + val randomOffsetType = data["offset_type"]?.asString?.let { RandomOffsetTypes[it] } + val itemId = data["item"]?.asInt ?: 0 + val tint = data["tint"]?.asString?.let { ResourceLocation(it) } + val block = when (data["class"].asString) { "FluidBlock" -> { val stillFluid = mappings.fluidRegistry.get(data["still_fluid"].asInt) @@ -60,22 +68,26 @@ open class Block( FluidBlock( - resourceLocation = resourceLocation, explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f, - hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false, - tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) }, - itemId = data["item"]?.asInt ?: 0, - tint = data["tint"]?.asString?.let { ResourceLocation(it) }, + resourceLocation = resourceLocation, + explosionResistance = explosionResistance, + hasDynamicShape = hasDynamicShape, + tintColor = tintColor, + randomOffsetType = randomOffsetType, + itemId = itemId, + tint = tint, renderOverride = renderOverride, stillFluid = stillFluid, flowingFluid = flowingFluid, ) } else -> Block( - resourceLocation = resourceLocation, explosionResistance = data["explosion_resistance"]?.asFloat ?: 0.0f, - hasDynamicShape = data["has_dynamic_shape"]?.asBoolean ?: false, - tintColor = data["tint_color"]?.asInt?.let { TintColorCalculator.getJsonColor(it) }, - itemId = data["item"]?.asInt ?: 0, - tint = data["tint"]?.asString?.let { ResourceLocation(it) }, + resourceLocation = resourceLocation, + explosionResistance = explosionResistance, + hasDynamicShape = hasDynamicShape, + tintColor = tintColor, + randomOffsetType = randomOffsetType, + itemId = itemId, + tint = tint, renderOverride = renderOverride, ) } diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/FluidBlock.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/FluidBlock.kt index 8ca41d884..e6a6f00b3 100644 --- a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/FluidBlock.kt +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/FluidBlock.kt @@ -24,12 +24,13 @@ class FluidBlock( explosionResistance: Float = 0.0f, hasDynamicShape: Boolean = false, tintColor: RGBColor? = null, + randomOffsetType: RandomOffsetTypes? = null, itemId: Int = 0, tint: ResourceLocation? = null, val stillFluid: Fluid, val flowingFluid: Fluid, renderOverride: MutableList = mutableListOf(), -) : Block(resourceLocation, explosionResistance, hasDynamicShape, tintColor, itemId, tint, renderOverride) { +) : Block(resourceLocation, explosionResistance, hasDynamicShape, tintColor, randomOffsetType, itemId, tint, renderOverride) { val fluidRenderer: FluidRenderer = FluidRenderer(this, stillFluid, flowingFluid) init { diff --git a/src/main/java/de/bixilon/minosoft/data/mappings/blocks/RandomOffsetTypes.kt b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/RandomOffsetTypes.kt new file mode 100644 index 000000000..88c56a656 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/data/mappings/blocks/RandomOffsetTypes.kt @@ -0,0 +1,28 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.data.mappings.blocks + +import de.bixilon.minosoft.util.KUtil +import de.bixilon.minosoft.util.enum.ValuesEnum + +enum class RandomOffsetTypes { + XZ, + XYZ, + ; + + companion object : ValuesEnum { + override val VALUES: Array = values() + override val NAME_MAP: Map = KUtil.getEnumValues(VALUES) + } +} diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt index c54d24599..443e67626 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/WorldRenderer.kt @@ -27,11 +27,13 @@ import de.bixilon.minosoft.data.world.ChunkSection.Companion.indexPosition import de.bixilon.minosoft.data.world.World import de.bixilon.minosoft.gui.input.camera.Frustum import de.bixilon.minosoft.gui.rendering.* +import de.bixilon.minosoft.gui.rendering.chunk.models.renderable.BlockLikeRenderContext import de.bixilon.minosoft.gui.rendering.modding.events.FrustumChangeEvent import de.bixilon.minosoft.gui.rendering.modding.events.RenderingStateChangeEvent import de.bixilon.minosoft.gui.rendering.shader.Shader import de.bixilon.minosoft.gui.rendering.textures.Texture import de.bixilon.minosoft.gui.rendering.util.VecUtil.chunkPosition +import de.bixilon.minosoft.gui.rendering.util.VecUtil.getWorldOffset import de.bixilon.minosoft.gui.rendering.util.VecUtil.of import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.VecUtil.sectionHeight @@ -80,9 +82,9 @@ class WorldRenderer( } val blockPosition = Vec3i.of(chunkPosition, sectionHeight, index.indexPosition) - val neighborBlocks: Array = arrayOfNulls(Directions.VALUES.size) + val neighbourBlocks: Array = arrayOfNulls(Directions.VALUES.size) for (direction in Directions.VALUES) { - neighborBlocks[direction.ordinal] = world.getBlockState(blockPosition + direction) + neighbourBlocks[direction.ordinal] = world.getBlockState(blockPosition + direction) } // if (!blockState.block.resourceLocation.full.contains("white_stained_glass_pane")) { @@ -90,11 +92,22 @@ class WorldRenderer( // } + val context = BlockLikeRenderContext( + blockState = blockState, + lightAccessor = world.worldLightAccessor, + renderWindow = renderWindow, + blockPosition = blockPosition, + meshCollection = meshCollection, + neighbourBlocks = neighbourBlocks, + world = world, + offset = blockPosition.getWorldOffset(blockState.block), + ) + if (blockState.properties[BlockProperties.WATERLOGGED] == true) { - waterBlock?.fluidRenderer?.render(waterBlock.defaultState, world.worldLightAccessor, renderWindow, blockPosition, meshCollection, neighborBlocks, world) + waterBlock?.fluidRenderer?.render(context.copy(blockState = waterBlock.defaultState)) } - blockState.getBlockRenderer(blockPosition).render(blockState, world.worldLightAccessor, renderWindow, blockPosition, meshCollection, neighborBlocks, world) + blockState.getBlockRenderer(blockPosition).render(context) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderContext.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderContext.kt new file mode 100644 index 000000000..8d35e0da3 --- /dev/null +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderContext.kt @@ -0,0 +1,33 @@ +/* + * Minosoft + * Copyright (C) 2021 Moritz Zwerger + * + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. If not, see . + * + * This software is not affiliated with Mojang AB, the original developer of Minecraft. + */ + +package de.bixilon.minosoft.gui.rendering.chunk.models.renderable + +import de.bixilon.minosoft.data.mappings.blocks.BlockState +import de.bixilon.minosoft.data.world.World +import de.bixilon.minosoft.data.world.light.LightAccessor +import de.bixilon.minosoft.gui.rendering.RenderWindow +import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection +import glm_.vec3.Vec3 +import glm_.vec3.Vec3i + +data class BlockLikeRenderContext( + val blockState: BlockState, + val lightAccessor: LightAccessor, + val renderWindow: RenderWindow, + val blockPosition: Vec3i, + val meshCollection: ChunkMeshCollection, + val neighbourBlocks: Array, + val world: World, + val offset: Vec3, +) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderer.kt index 5600cdc20..97f80306a 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockLikeRenderer.kt @@ -1,19 +1,13 @@ package de.bixilon.minosoft.gui.rendering.chunk.models.renderable -import de.bixilon.minosoft.data.mappings.blocks.BlockState -import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.data.world.light.LightAccessor -import de.bixilon.minosoft.gui.rendering.RenderWindow -import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize import de.bixilon.minosoft.gui.rendering.textures.Texture -import glm_.vec3.Vec3i interface BlockLikeRenderer { val faceBorderSizes: Array?> // direction indexed val transparentFaces: BooleanArray - fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array, world: World) + fun render(context: BlockLikeRenderContext) fun resolveTextures(indexed: MutableList, textureMap: MutableMap) diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt index 2a3ab1547..f922872ff 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/BlockRenderer.kt @@ -17,13 +17,8 @@ import com.google.common.collect.HashBiMap import com.google.gson.JsonObject import de.bixilon.minosoft.data.Directions import de.bixilon.minosoft.data.mappings.biomes.Biome -import de.bixilon.minosoft.data.mappings.blocks.BlockState import de.bixilon.minosoft.data.text.RGBColor -import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.RenderConstants -import de.bixilon.minosoft.gui.rendering.RenderWindow -import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModel import de.bixilon.minosoft.gui.rendering.textures.Texture @@ -32,7 +27,6 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.VecUtil.toVec3 import glm_.glm import glm_.vec3.Vec3 -import glm_.vec3.Vec3i class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer { private val cullFaces: Array = arrayOfNulls(Directions.VALUES.size) @@ -102,7 +96,7 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer { } } - override fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array, world: World) { + override fun render(context: BlockLikeRenderContext) { if (!RenderConstants.RENDER_BLOCKS) { return } @@ -114,8 +108,8 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer { val invertedDirection = direction.inverted var isNeighbourTransparent = false var neighbourFaceSize: Array? = null - val neighbourBlock = neighbourBlocks[direction.ordinal] - neighbourBlock?.getBlockRenderer(blockPosition + direction)?.let { + val neighbourBlock = context.neighbourBlocks[direction.ordinal] + neighbourBlock?.getBlockRenderer(context.blockPosition + direction)?.let { val itDirection = if (it is BlockRenderer) { it.directionMapping[invertedDirection] ?: invertedDirection } else { @@ -147,7 +141,7 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer { // force draw transparent faces if (isNeighbourTransparent && !transparentFaces[direction.ordinal]) { drawElementFace = true - } else if (isNeighbourTransparent && transparentFaces[direction.ordinal] && neighbourBlock != blockState) { + } else if (isNeighbourTransparent && transparentFaces[direction.ordinal] && neighbourBlock != context.blockState) { drawElementFace = true } } @@ -157,10 +151,10 @@ class BlockRenderer(data: JsonObject, parent: BlockModel) : BlockLikeRenderer { } if (biome == null) { - biome = world.getBiome(blockPosition) - tintColor = renderWindow.tintColorCalculator.getAverageTint(biome, blockState, blockPosition) + biome = context.world.getBiome(context.blockPosition) + tintColor = context.renderWindow.tintColorCalculator.getAverageTint(biome, context.blockState, context.blockPosition) } - element.render(tintColor, blockPosition, lightAccessor, textureMapping, direction, meshCollection) + element.render(tintColor, textureMapping, direction, context) } } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt index 93ad4bef5..9b4f9dfea 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/ElementRenderer.kt @@ -18,7 +18,6 @@ import com.google.gson.JsonObject import de.bixilon.minosoft.data.Axes import de.bixilon.minosoft.data.Directions import de.bixilon.minosoft.data.text.RGBColor -import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection import de.bixilon.minosoft.gui.rendering.chunk.SectionArrayMesh import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize @@ -31,7 +30,6 @@ import de.bixilon.minosoft.gui.rendering.util.VecUtil import de.bixilon.minosoft.gui.rendering.util.VecUtil.plus import de.bixilon.minosoft.gui.rendering.util.VecUtil.rotate import glm_.vec3.Vec3 -import glm_.vec3.Vec3i class ElementRenderer( parent: BlockModelElement, @@ -65,7 +63,7 @@ class ElementRenderer( } } - fun render(tintColor: RGBColor?, blockPosition: Vec3i, lightAccessor: LightAccessor, textureMapping: MutableMap, direction: Directions, meshCollection: ChunkMeshCollection) { + fun render(tintColor: RGBColor?, textureMapping: MutableMap, direction: Directions, context: BlockLikeRenderContext) { val realDirection = directionMapping.inverse()[direction]!! val face = faces[realDirection] ?: return // Not our face @@ -73,16 +71,16 @@ class ElementRenderer( val texture = textureMapping[face.textureName] ?: TODO("Unknown texture used ${face.textureName}") // ToDo: can be replaced with RenderConstants.DEBUG_TEXTURE_ID? - val lightLevel = lightAccessor.getLightLevel(blockPosition + face.cullFace?.let { directionMapping[it] }) // ToDo: rotate cullface + val lightLevel = context.lightAccessor.getLightLevel(context.blockPosition + face.cullFace?.let { directionMapping[it] }) // ToDo: rotate cullface val drawPositions = arrayOf(transformedPositions[positionTemplate[0]], transformedPositions[positionTemplate[1]], transformedPositions[positionTemplate[2]], transformedPositions[positionTemplate[3]]) - val mesh = getMesh(meshCollection, texture.transparency) + val mesh = getMesh(context.meshCollection, texture.transparency) val texturePositions = face.getTexturePositionArray(realDirection) for (vertex in DRAW_ODER) { val input = drawPositions[vertex.first] - val output = blockPosition plus input + DRAW_OFFSET + val output = context.blockPosition plus context.offset + input + DRAW_OFFSET mesh.addVertex( position = output, textureCoordinates = texturePositions[vertex.second]!!, diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/FluidRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/FluidRenderer.kt index bf78d857f..181fe2c46 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/FluidRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/FluidRenderer.kt @@ -8,9 +8,7 @@ import de.bixilon.minosoft.data.mappings.blocks.properties.BlockProperties import de.bixilon.minosoft.data.mappings.fluid.Fluid import de.bixilon.minosoft.data.text.RGBColor import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.data.world.light.LightAccessor import de.bixilon.minosoft.gui.rendering.RenderConstants -import de.bixilon.minosoft.gui.rendering.RenderWindow import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement @@ -32,12 +30,12 @@ class FluidRenderer( private lateinit var stillTexture: Texture private lateinit var flowingTexture: Texture - override fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array, world: World) { + override fun render(context: BlockLikeRenderContext) { if (!RenderConstants.RENDER_FLUIDS) { return } - val lightLevel = lightAccessor.getLightLevel(blockPosition) - val heights = calculateHeights(neighbourBlocks, blockState, world, blockPosition) + val lightLevel = context.lightAccessor.getLightLevel(context.blockPosition) + val heights = calculateHeights(context.neighbourBlocks, context.blockState, context.world, context.blockPosition) val isFlowing = isLiquidFlowing(heights) var texture: Texture @@ -58,18 +56,19 @@ class FluidRenderer( } else { texture = stillTexture } - if (isBlockSameFluid(neighbourBlocks[direction.ordinal]) || neighbourBlocks[direction.ordinal]?.getBlockRenderer(blockPosition + direction)?.faceBorderSizes?.let { it[direction.inverted.ordinal] != null } == true && direction != Directions.UP) { + val neighbourBlocks = context.neighbourBlocks + if (isBlockSameFluid(neighbourBlocks[direction.ordinal]) || neighbourBlocks[direction.ordinal]?.getBlockRenderer(context.blockPosition + direction)?.faceBorderSizes?.let { it[direction.inverted.ordinal] != null } == true && direction != Directions.UP) { continue } val positionTemplate = BlockModelElement.FACE_POSITION_MAP_TEMPLATE[direction.ordinal] val drawPositions = arrayOf(positions[positionTemplate[0]], positions[positionTemplate[1]], positions[positionTemplate[2]], positions[positionTemplate[3]]) if (biome == null) { - biome = world.getBiome(blockPosition) - tintColor = renderWindow.tintColorCalculator.getAverageTint(biome, blockState, blockPosition) + biome = context.world.getBiome(context.blockPosition) + tintColor = context.renderWindow.tintColorCalculator.getAverageTint(biome, context.blockState, context.blockPosition) } - createQuad(drawPositions, face.getTexturePositionArray(direction), texture, blockPosition, meshCollection, tintColor, lightLevel) + createQuad(drawPositions, face.getTexturePositionArray(direction), texture, context.blockPosition, context.meshCollection, tintColor, lightLevel) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/MultipartRenderer.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/MultipartRenderer.kt index 0ace5f872..09cdd230e 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/MultipartRenderer.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/chunk/models/renderable/MultipartRenderer.kt @@ -14,14 +14,8 @@ package de.bixilon.minosoft.gui.rendering.chunk.models.renderable import de.bixilon.minosoft.data.Directions -import de.bixilon.minosoft.data.mappings.blocks.BlockState -import de.bixilon.minosoft.data.world.World -import de.bixilon.minosoft.data.world.light.LightAccessor -import de.bixilon.minosoft.gui.rendering.RenderWindow -import de.bixilon.minosoft.gui.rendering.chunk.ChunkMeshCollection import de.bixilon.minosoft.gui.rendering.chunk.models.FaceSize import de.bixilon.minosoft.gui.rendering.textures.Texture -import glm_.vec3.Vec3i class MultipartRenderer( val models: List, @@ -45,9 +39,9 @@ class MultipartRenderer( this.faceBorderSizes = faceBorderSizes.toTypedArray() } - override fun render(blockState: BlockState, lightAccessor: LightAccessor, renderWindow: RenderWindow, blockPosition: Vec3i, meshCollection: ChunkMeshCollection, neighbourBlocks: Array, world: World) { + override fun render(context: BlockLikeRenderContext) { for (model in models) { - model.render(blockState, lightAccessor, renderWindow, blockPosition, meshCollection, neighbourBlocks, world) + model.render(context) } } diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt index 6b2580e2d..843a9b15d 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/util/VecUtil.kt @@ -16,10 +16,14 @@ package de.bixilon.minosoft.gui.rendering.util import com.google.gson.JsonArray import com.google.gson.JsonElement import com.google.gson.JsonObject +import de.bixilon.minosoft.Minosoft import de.bixilon.minosoft.data.Axes import de.bixilon.minosoft.data.Directions +import de.bixilon.minosoft.data.mappings.blocks.Block +import de.bixilon.minosoft.data.mappings.blocks.RandomOffsetTypes import de.bixilon.minosoft.gui.rendering.chunk.models.loading.BlockModelElement import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition +import glm_.func.common.clamp import glm_.func.cos import glm_.func.sin import glm_.vec2.Vec2 @@ -172,4 +176,40 @@ object VecUtil { infix operator fun Vec2i.plus(direction: Directions): Vec2i { return this + direction.directionVector } + + fun Vec3i.getWorldOffset(block: Block): Vec3 { + if (block.randomOffsetType == null || !Minosoft.config.config.game.other.flowerRandomOffset) { + return EMPTY_VEC3 + + } + val positionHash = generatePositionHash(x, 0, z) + val maxModelOffset = 0.25f // use block.model.max_model_offset + + fun horizontal(axisHash: Long): Float { + return (((axisHash and 0xF) / 15.0f) - 0.5f) / 2.0f + } + + return Vec3( + x = horizontal(positionHash), + y = if (block.randomOffsetType === RandomOffsetTypes.XYZ) { + (((positionHash shr 4 and 0xF) / 15.0f) - 1.0f) / 5.0f + } else { + 0.0f + }, + z = horizontal(positionHash shr 8)).clamp(-maxModelOffset, maxModelOffset) + } + + private fun Vec3.clamp(min: Float, max: Float): Vec3 { + return Vec3( + x = x.clamp(min, max), + y = y.clamp(min, max), + z = z.clamp(min, max), + ) + } + + private fun generatePositionHash(x: Int, y: Int, z: Int): Long { + var hash = (x * 3129871L) xor z.toLong() * 116129781L xor y.toLong() + hash = hash * hash * 42317861L + hash * 11L + return hash shr 16 + } } diff --git a/src/main/java/de/bixilon/minosoft/util/MMath.kt b/src/main/java/de/bixilon/minosoft/util/MMath.kt index 2ba8e821c..6697b3a45 100644 --- a/src/main/java/de/bixilon/minosoft/util/MMath.kt +++ b/src/main/java/de/bixilon/minosoft/util/MMath.kt @@ -51,6 +51,16 @@ object MMath { return value } + fun clamp(value: Double, min: Double, max: Double): Double { + if (value < min) { + return min + } + if (value > max) { + return max + } + return value + } + fun divideUp(value: Int, divider: Int): Int { return (value + divider - 1) / divider } diff --git a/src/main/resources/assets/minosoft/mapping/pixlyzer_index.json b/src/main/resources/assets/minosoft/mapping/pixlyzer_index.json index dd44d5838..ae7e76b32 100644 --- a/src/main/resources/assets/minosoft/mapping/pixlyzer_index.json +++ b/src/main/resources/assets/minosoft/mapping/pixlyzer_index.json @@ -1 +1 @@ -{"21w14a":"63c5cdea4ff7d9dc27e51f2e8fa48c21d1fa8bb3","21w13a":"db3b8724ccab20594580263298dcbbd0783f644e","21w11a":"4af776b44b55be53b4f27dcd7b43b6e9e693feda","21w10a":"4eebc0b218d051421819f1b19f954bd8e0a659e5","21w08b":"9775b9b38b0b7da051d148fcdeac210183093368","21w08a":"53964d56b6e8fa45e0bf89d1fbb3aee312c41778","21w07a":"5afb711140121f9071b9ea91aeb41302730c1282","21w06a":"b22c3c618e40352f42f5bc929682924e1c99146f","21w05b":"ad2685e5da0e44b34c2ae99ae2c04f28050cf0b5","21w05a":"440362cd139c945c31856573e808cf26692a736b","21w03a":"61ce83b6dbf8d541f3362f7da5b722ed5319be55","1.16.5":"dff7472ad31f8ea6cb6e45fafbc0cd06608792a5","20w51a":"e41bb30775d63cf503c2ac2cd910ddb744afd060","20w49a":"cd4cd7939470836a2b83043faa48741d400d9c17","20w48a":"32ed2150b732698df9a5a69167204c2e7940dafe","20w46a":"dfb016530df403406d414f36932277f8724343b4","20w45a":"91d54ddffc0e4e68cd53cae3121b89924fcbdc39","1.16.2-pre3":"7e157499f74b3a6d6e04020fdb86e478d0891089","1.16.2-pre2":"9c6473c3974c7b8f1525da1a18b425633faab1b0","1.16.2-pre1":"707f250b9b366ca01f8fe98769dd0aa2dbd7d942","20w30a":"1fcb8757dd2085a278a7e65b178199d229cce8dc","20w29a":"79c6e6d93f9de616e5381a69b62678ed54233f1f","20w28a":"0054c16fe3b16f3a5eaebd1240e770c458500dcd","20w27a":"f51953fd827b87f0c9d889bfce01aac8eac26087","1.16.1":"17af948f2399a17c6f297cdf48ba74050c70d645","1.16":"3ee2b3ee2fbf8657d1e46e6f7d4e962961613a90","1.16-rc1":"e75c3a3dc4322249e06adbb13acf5f09c38ee165","1.16-pre8":"3b684fea186dbc1c258b3406076cd792814c6bb3","1.16-pre7":"e38c2a179b36511832dac9ace95c84eefe314d3d","1.16-pre6":"9da7f440670375da449e1b1abfa17c000a64c523","1.16-pre5":"e77825ac3f5b07b457080119d03161ad43b60851","1.16-pre4":"3f9e87a1762812ccda77c03851398ba224d7d98d","1.16-pre3":"4de169d590aaf6c7e87b8b7e1fb87291b50a510b","1.16-pre2":"0226ea301c46c5309b4168adec09f816e98bc086","1.16-pre1":"16a1b0d63014f4e4f43566b5963e25f5f354b991","20w22a":"dbdec0f0f44576239db8d8c96a219670bb0a436d","20w21a":"943911f78954352d55b8dfcb3e514e372c267ae7","20w20b":"c81738c81c2b40deb074df5ca64a3a22ee97819d","20w20a":"b54cd8d3d348323d111220b57352e09b711e63c9","20w19a":"dd8b6b260c0b8198f00ba235925fd4ff9c7576b7","20w18a":"4d17bb035688808db6c3b5e099a5f1311d89a4b7","20w17a":"e1d421f76472b5df33a1579d7b489a63c88c755b","20w16a":"6aae3288db7a40b441dba23185c23fad51fb59ea","20w15a":"86cac5259cfe1e6bdfd51308b66d2c5aff05bcce","20w14a":"121535f227eb9ea34a539367da6210f7169483ec","20w14infinite":"5a79ae0ea73dd7134422812408d973f33ce61ae7","20w13b":"d8fcb9f634f06bbad393ab18682c0c921a554fdc","20w13a":"de2f85dfb0dc877a002dc5cf83c09b9bd51b9bc3","20w12a":"a2d74e9831ff1e810782cdaee81b7cdf7a425900","20w11a":"c272c7f1551933df2f244d6b9af253fc100c0d11","20w10a":"048157545607d683b1da615d9a21d2087a3585d9","20w09a":"0a72b712cdd66615c2491c00783e20957361a83f","20w08a":"1586a5d7062b4cb81af044d8cb51ac4877bb261a","20w07a":"02e61911e28e2502180168342eb85c65fe8d781c","20w06a":"2aef48d219b26ba89aa710cf3b6dff2bbfd97351","1.16.5-rc1":"db271c65fe6189a3ecd689a716ff5e3ca40d1e17","1.16.4":"dd71f5248b8fafed23165dc837b9f1de44a5804a","1.16.4-rc1":"94b5cc32c51fa641af462d26002502d4b8d31cdb","1.16.4-pre2":"4bbfbfafa71c6846216891ad1b1cbd64a2e6178a","1.16.4-pre1":"9182e42259f4956b2cf17c2cc220d606076c87c2","1.16.3":"c64b1d4ac82024aa0c27c659e235b1082d7be4b9","1.16.3-rc1":"8487626615a56099ef5502dd05a13c2c72d845b0","1.16.2":"26b5dde0a29e291aab470e8dc3cc5ffbdffb050d","1.16.2-rc2":"e79332175d7f2a1c0d22aa99c244172a844b5601","1.16.2-rc1":"5b89dcf826c3a130ac24ed90806a07db1fc84880","1.15.2":"2f85ea01b2aa2dc22c6b73f1ce2537f7205e5008","1.15.2-pre2":"a6401f7217b6cdf6b58babfba7e9d1b72bf19061","1.15.2-pre1":"7a15f9db809f308cbf9483f40486110ed3fca326","1.15.1":"842660a7bd56b4da8aaa41132a2e3b58ff57398d","1.15.1-pre1":"e6872d3581cd41434c5bd6366c62d6327dcd473d","1.15":"91c21c7939be307e1639355704fee3676320f2fc","1.15-pre7":"63817eecfc0b789693d79cc1cf31109c8fddf177","1.15-pre6":"97408175696fae767d1edd9ef08dee10021e4192","1.15-pre5":"956d7e78a0784e64a4509a87988512c690b5922f","1.15-pre4":"f87dc1ad25d6279f0d9493779dfe2ae18f0574b8","1.15-pre3":"d35a214afd600345a7c73ee87bf200105e42598e","1.15-pre2":"a84bcf68a2d8bdd26e49567e0ad5e628f2584ef2","1.15-pre1":"5950c2a0a8ecc4c5902728b05638a0b43437eca9","19w46b":"350da0b26454badf5b184a1510fc3be69589486c","19w46a":"463171e7e2cfb941c4791cf0de187464f69ac790","19w45b":"b9b2255c935b9056f935e6b8266dd44dc7a59bbe","19w45a":"bed19707b95f8a740bed15dc44ab570d97a1281c","19w44a":"75209190c1445b9a8d4f9fb01c76478150ab6473","19w42a":"f66f9bf9891b601170bdd34c05fb5934ae69adca","19w41a":"efd074ec606ea38a08c385a487f4f9a4638bab98","19w40a":"5181518dbfa297fa7e876ce74d82438f4dcf34d1","19w39a":"f894fd3d6511d36f21ec4926ab418052d77414ce","19w38b":"a36a2040d84cb1967e2cab7c4600193e6a9a6ca3","19w38a":"b067b4424756b9c1f5d4b9eab204bd9f4fe269e3","19w37a":"3a388ac34424254f612006a10e01be124bc14ec6","19w36a":"8b9179fa2f7ba0ab29f27d8065ac15decd4cfff9","19w35a":"0c133b26cdcd0af3d154e643db139771e67d14b9","19w34a":"e82e4ff5747af7bec9c78ed164cd0ddff4ced153","1.14.4":"6939dff578be7b76ffdc89cd6882c1bd8bf97bc1","1.14.4-pre7":"9583c6bdf3b56702028df2dd6c79fef6779af63e","1.14.4-pre6":"d3b118a1ca1a960d6d2c9ab682566d4a344edf99","1.14.4-pre5":"d1d54c15a1caa449fa58f4966b7d230b9e0fa3f4","1.14.4-pre4":"78e84c563f71a9ac0d4116e73e07390b408d1e32","1.14.4-pre3":"6711628b8945eac73975c3dd87144fc14b531add","1.14.4-pre2":"3ad91dcc9a029cac6686a533d979b4c175aa0f89","1.14.4-pre1":"d1c42e0c33b95820ed95b015961d986b2624ded9","1.14.3":"eef08e6f439601e0fd72ff57951306d72a43140c","1.14.3-pre4":"a79220b67d7758f639945d80d001f8b0135ce65d","1.14.3-pre3":"62ef8dd85c438b04db73e953523c4492ebafbfa1","1.14.3-pre2":"8bedd60b99657e0e5cf83b8e1594788c6055b877","1.14.3-pre1":"bcde219f5c3a8f2d616e6577e07793ffb296bd6b","1.14.2":"58266ec4294c63276c7f628c2f41fef6a10c95cb","1.14.2 Pre-Release 4":"ba4891c3126023af3807d7624a7f069e3247eb0c","1.14.2 Pre-Release 3":"13dd1a14b589abb6eeb1a58b1c208109dae1600f","1.14.2 Pre-Release 2":"54f04ec460dfbdb0b543b6afab4a29c76702261f","1.14.2 Pre-Release 1":"71354888138db50749a2fdb4512c3055daf3f858","1.14.1":"6eb3209ee41c3a3fab6a3834e150972b39992a5f","1.14.1 Pre-Release 2":"f621a5bc8d428b5b9140c9a6ab54ca6ca6772389","1.14.1 Pre-Release 1":"bba13cecb85753c66c38e477f6fd47b43e9b5194","1.14":"6ced213dab0f59fc8629d8c5e658373eb9cf5d0c","1.14 Pre-Release 5":"5317a95d449a6258993e652f2602436cee4d3796","1.14 Pre-Release 4":"8dfcb0d985e4fd7162655c8e0eb7731032ac2bf3","1.14 Pre-Release 3":"fea442b33b2f4815272824905f65611477464c5e","1.14 Pre-Release 2":"1953e5b3944c1a8cea3618abbca0c7879398a0cd","1.14 Pre-Release 1":"488264eba3556b8549c0241fc19bc986c864f34f","19w14b":"cce33de8de23a089d3d7d07426ba14cf843cca05","19w14a":"e16b97684c811097a074012f7f22f154adb78f46","3D Shareware v1.34":"9871622b5cf87e2b658a2a4bd0ae403ab663fddc","19w13b":"de7b1e6ebda633d813fd6c7e0a54f409b95fd0c9","19w13a":"c9c8d67c181bfb9eb26a78f11237780c3eaf410e","19w12b":"ca8b33890db962d9b1806ab427aeff7e30e32305","19w12a":"7df41ec7abb67a86a9fbf3fb1aceb20d3a4fae39","19w11b":"054bc37ae4daa7d1361aaf77e321f2044678cc1b","19w11a":"cafef567ac2bcdbf2f2df48cd7e624f224ab10dc","21w15a":"49ab6d0af288262d9abf10331d7da35087a8cf9c","17w46a":"153dff89ed90f91758f847907cd4d48d3b553a3f","21w16a":"ebf9bc1dc76aeed481e587e45d88e6b22b849bb2","21w17a":"fda6c6b2de4a47b9b91b2e8be5aa0f6863ea1fce","21w18a":"c22466cb833f2328fcbc04495244decc622f8363"} +{"21w14a":"ea77d7e2d8f756e7387e9d3917903fee45de7c00","21w13a":"35c5fa0f63bdc7ac0375a7b226dc753d2b3067dc","21w11a":"fd8d2dc202764146d6cc2ef39d1b9ee7688bec2c","21w10a":"d809659ea7f63049199e24398d6e0487f074f99e","21w08b":"19ce618be42ff7c6b7f61b7e1617efab551370da","21w08a":"5d30cfd99a2ac5da7f6fe92f57812cf2d0f7e1db","21w07a":"c6610fd2a210dfa7a9dd7f0c5d0961b8780305a2","21w06a":"d9d472fbb271c099b84baa1cd9b94656aba2cbeb","21w05b":"abd8a7bda90c1f30f0c732059d10d28ea3494ff7","21w05a":"4c87ae49f045801c77d65642a539af3fca14948e","21w03a":"f1c94c05f9afdbd71e90d5ab7f7759550b7759ed","1.16.5":"b388213f9912c8bd64e076d4d6fd7eae95727561","20w51a":"9ebbb00b410bd0ea350262dec47b1382f5b36f29","20w49a":"740b6536746dd90c25cce355560001cc805807cc","20w48a":"7cf6a612a8d7faf786b68ee4a912a3c6a16ef08c","20w46a":"2c8349e4e7dca3112e2e346651b16fc299ed89de","20w45a":"54afca6f479cbad563042c8c149d125b7917d509","1.16.2-pre3":"a12d5287fab7738de16a64be945d3094f10feb62","1.16.2-pre2":"7d0213a8868b72125d08832eeaaf3706484da529","1.16.2-pre1":"fe02fc6087f4790c204198813b74a36ce7f2ee1c","20w30a":"0c52afc1aa3ca8c20ea5da0151bd6992e3ed276f","20w29a":"0682465f4e807698c0ddfc9330d1887043d7aeee","20w28a":"9ce5a9f732227dda84ffc7232f579fac2d813046","20w27a":"cbc6bcf5c7128b66f8a3bc771424aa55e86e5cb7","1.16.1":"09f025bd815b94d8f582276f4019df045a3bd435","1.16":"40c08f94e03d1a094ca89bf515114d726bd8bac9","1.16-rc1":"4b0b44cc7cfcc88d827f68569029049f9ebd646f","1.16-pre8":"d36c0128c8e3fa639b258e425541072c0fefbce3","1.16-pre7":"0733ec035af7de42302f14c1b229831a662a69d9","1.16-pre6":"cef6f71759d0ec03603a5221ff76328af37b31c5","1.16-pre5":"183c9ffb81a1f9a21d997bd5a31baebe46c22e7a","1.16-pre4":"fceb8d9b8dbd3ad3259b13329625b83b82060731","1.16-pre3":"73dc1f89a4f245e3bb556bc61bd03c49ec138a57","1.16-pre2":"789476118c53d05a313baba662898f3631ced920","1.16-pre1":"718a5e3b7ad99dab73d202ae8934d7e8fed31adf","20w22a":"d0f02ef8dca5c46cd80259529b1c754e7d58f15f","20w21a":"de6d7d1a2f0b597f92494470c3f6c48c0be61ab9","20w20b":"dba1c32c3e750b34237e6af9602603514243add0","20w20a":"925d97824265dc900a057d178e4b315f42b47b52","20w19a":"c177aeb546be092d2b38f86d9b8a823b803f331d","20w18a":"cbf9e3b24e27e13a2d65224ca18fff148240ed00","20w17a":"5b2f63548a69ba8181703cbcd8464bca5012ffd6","20w16a":"95108738d0855a171af02fb8d2c487c58823712f","20w15a":"cdfa592431d0d7393b88b4d2bed94c1a7c68e402","20w14a":"0ffb470a674dce7403d9548dd9adbf98ab3c2772","20w14infinite":"59131c99e2aaae8f8516256cd6b2bcf2b4f21b05","20w13b":"c34e2246487c251e0b3d7e68bbbd07dab7de6926","20w13a":"256c4663e2ebae3e664d8107d245e52e96cb46b6","20w12a":"fd049756e5306790e07d67c07efbebad247ffe4e","20w11a":"5a0a83c48fef32f8df58432eeb8c4ceedef1793d","20w10a":"0256d650ab6c193964b6c7f355e513b509696f2e","20w09a":"bf08b0aff59bf2ba58c26e4dcf83713956e93253","20w08a":"7916ea583b4fb6d01106db45b50b854224ebcbd3","20w07a":"fb95d8a4a04ce7a6af393783b9a5facf33cab66f","20w06a":"c422b4d5a2c328bc871a03c0460555a684643051","1.16.5-rc1":"1312757ac610cde170824e0d2f9bfe836f46c17b","1.16.4":"c6a254c6d4efe34cb6ef58fecc2e3b3e1406379d","1.16.4-rc1":"9fdedc82fe16e3f1aac903bf8fa17a9209877930","1.16.4-pre2":"228e911f7f63da9e88c19bceafafed95a6dc82f3","1.16.4-pre1":"1b265a34dd4a14e4c5cb4856e30392a3d25c927c","1.16.3":"885a2879c88a70db36b762e0afe6486dd269650a","1.16.3-rc1":"da50b481d36a3c3f4d1690cd26000b9500de9cd4","1.16.2":"f6a149c52f073f738108f4674db63900a8ae1c84","1.16.2-rc2":"4eca6500f6e188837f4fc95d98a672253ff9e1e2","1.16.2-rc1":"7ef3bea391926374c80e29c187054a83cb904de4","1.15.2":"490df20dd28695c7319e9cf9e52114b93b062bfa","1.15.2-pre2":"23b4f40136f9ad669904f6a4c4b821efd30e4475","1.15.2-pre1":"2df679b6a48a2523b60d36f5a7a728c7b981eeb6","1.15.1":"1fd7f715ae94400ba46e399ae3612984e6db2ca7","1.15.1-pre1":"36e6670980fe17c66740429e96932f2959fdc95f","1.15":"a49b4d579a71adeaa9752014703b0bd2315af29a","1.15-pre7":"637c8d94760328cd366580a3586ed1b0a37c5ad9","1.15-pre6":"0332fb040e476cf9f84ac03c00fab68ad0175333","1.15-pre5":"07f997d9d9818c59141bd6c5e79c60f05512bb7b","1.15-pre4":"b0597069bfc210f8563230cfd4ce86c1173a602a","1.15-pre3":"d8eb262f4729682ee934a561d98030f3677858e8","1.15-pre2":"eb3b8d9a039a75a4f7399ab7d278222c750d0053","1.15-pre1":"1484a02cb7e24296cd39bcd55b028214c4cce915","19w46b":"69891c202b0ce368be3ed7a53b0c5090726b773e","19w46a":"99a8e36e643311b3dcb7d9be610d592da4d644aa","19w45b":"a988ba600404b51ae2e39f483264cc00dd78a71a","19w45a":"a111f84e9ff295e294befd221c8df88c1f6e9866","19w44a":"68306c8c062ad03b463fd28e5fe9a86701482935","19w42a":"ee331c7b22c02ce46e36196ed65bb02b297bcdec","19w41a":"408d1391dbbe5bd2ee35bc4d740f1650c7f05dcd","19w40a":"9684079f941dd82f1f82123fcdd4672cc454d7d3","19w39a":"b811604cf6e43519016292bc30f902d372961576","19w38b":"42f756a93f0522a9c893f036c3de078461cf5701","19w38a":"4693891cff2c8d76661a62cf71cd68841643d7b0","19w37a":"8dbbb3548ce39678bf7059961ce2010563a9b680","19w36a":"28d53d8d7da4ca8d5a7b852362283e5e3bc284c1","19w35a":"7719d28931592ab90c70f89a4e3d2d261b092349","19w34a":"a394a85300f6257346583ec8750f952a8dea89a4","1.14.4":"04b02dea85232909aaabaf7e93e7720d27abc7dc","1.14.4-pre7":"210e5284ad1cb1242e90db9648c099fe96276a89","1.14.4-pre6":"0c57ddb54cd544a59b8587b23d027a0752d07916","1.14.4-pre5":"bae283fa6982fcda53e220e2ae53c24f18875043","1.14.4-pre4":"fabc63854536728294d09e56a1beece72fb16771","1.14.4-pre3":"2195ae6a3ad8d6279ca4648c481d480c46c1e9fc","1.14.4-pre2":"d20214fb2ac3e018e1a074063bb0c7c684bdf162","1.14.4-pre1":"81237a0354f97c397331fca74aef8631ce0cca33","1.14.3":"c260bc3009ba42bac5133c175c08d9417e620fb7","1.14.3-pre4":"a79220b67d7758f639945d80d001f8b0135ce65d","1.14.3-pre3":"62ef8dd85c438b04db73e953523c4492ebafbfa1","1.14.3-pre2":"8bedd60b99657e0e5cf83b8e1594788c6055b877","1.14.3-pre1":"bcde219f5c3a8f2d616e6577e07793ffb296bd6b","1.14.2":"58266ec4294c63276c7f628c2f41fef6a10c95cb","1.14.2 Pre-Release 4":"ba4891c3126023af3807d7624a7f069e3247eb0c","1.14.2 Pre-Release 3":"13dd1a14b589abb6eeb1a58b1c208109dae1600f","1.14.2 Pre-Release 2":"54f04ec460dfbdb0b543b6afab4a29c76702261f","1.14.2 Pre-Release 1":"71354888138db50749a2fdb4512c3055daf3f858","1.14.1":"6eb3209ee41c3a3fab6a3834e150972b39992a5f","1.14.1 Pre-Release 2":"f621a5bc8d428b5b9140c9a6ab54ca6ca6772389","1.14.1 Pre-Release 1":"bba13cecb85753c66c38e477f6fd47b43e9b5194","1.14":"6ced213dab0f59fc8629d8c5e658373eb9cf5d0c","1.14 Pre-Release 5":"5317a95d449a6258993e652f2602436cee4d3796","1.14 Pre-Release 4":"8dfcb0d985e4fd7162655c8e0eb7731032ac2bf3","1.14 Pre-Release 3":"fea442b33b2f4815272824905f65611477464c5e","1.14 Pre-Release 2":"1953e5b3944c1a8cea3618abbca0c7879398a0cd","1.14 Pre-Release 1":"488264eba3556b8549c0241fc19bc986c864f34f","19w14b":"cce33de8de23a089d3d7d07426ba14cf843cca05","19w14a":"e16b97684c811097a074012f7f22f154adb78f46","3D Shareware v1.34":"9871622b5cf87e2b658a2a4bd0ae403ab663fddc","19w13b":"de7b1e6ebda633d813fd6c7e0a54f409b95fd0c9","19w13a":"c9c8d67c181bfb9eb26a78f11237780c3eaf410e","19w12b":"ca8b33890db962d9b1806ab427aeff7e30e32305","19w12a":"7df41ec7abb67a86a9fbf3fb1aceb20d3a4fae39","19w11b":"054bc37ae4daa7d1361aaf77e321f2044678cc1b","19w11a":"cafef567ac2bcdbf2f2df48cd7e624f224ab10dc","21w15a":"061664284e6c10e117d432e10f5ba9edd704fd72","17w46a":"153dff89ed90f91758f847907cd4d48d3b553a3f","21w16a":"cb0f3ca6acbb1ccf96221fb55f18221ca4e22d6c","21w17a":"5a2ddb1e48337cb294d87b2e928e6420af40bada","21w18a":"760568746540eea28e21abb2611fc6a7aafe1e2d","21w19a":"88dd68eafe31c006a896a969ee1fa1bb62470a34"}