aboutsummaryrefslogtreecommitdiff
path: root/src/main/kotlin
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-03-01 21:31:48 +0100
committerLinnea Gräf <nea@nea.moe>2024-03-02 19:43:00 +0100
commit3bfec3033e9d905514d5c1c6c62953c2a1646af0 (patch)
treeafee0b3c20d0bdef9780e5fddb368c9d58fb3c70 /src/main/kotlin
parentf28dee0ef3a0dd4a0819a3d3a1c800a83a0f07f5 (diff)
downloadFirmament-3bfec3033e9d905514d5c1c6c62953c2a1646af0.tar.gz
Firmament-3bfec3033e9d905514d5c1c6c62953c2a1646af0.tar.bz2
Firmament-3bfec3033e9d905514d5c1c6c62953c2a1646af0.zip
Add mob drop viewer to item list
Diffstat (limited to 'src/main/kotlin')
-rw-r--r--src/main/kotlin/moe/nea/firmament/commands/rome.kt41
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt14
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt202
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt40
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt491
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/GuiPlayer.kt55
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyAge.kt30
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyCharged.kt19
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyEquipment.kt59
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyHorse.kt66
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyInvisible.kt18
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyName.kt19
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyPlayerSkin.kt32
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyRiding.kt20
-rw-r--r--src/main/kotlin/moe/nea/firmament/gui/entity/ModifyWither.kt25
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/FirmamentReiPlugin.kt4
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/SBItemEntryDefinition.kt8
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/SkyblockCraftingRecipeDynamicGenerator.kt7
-rw-r--r--src/main/kotlin/moe/nea/firmament/rei/recipes/SBMobDropRecipe.kt113
-rw-r--r--src/main/kotlin/moe/nea/firmament/repo/RepoModResourcePack.kt101
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/ItemUtil.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/LoadResource.kt25
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/assertions.kt1
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/item/SkullItemData.kt40
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/render/TranslatedScissors.kt27
25 files changed, 1447 insertions, 12 deletions
diff --git a/src/main/kotlin/moe/nea/firmament/commands/rome.kt b/src/main/kotlin/moe/nea/firmament/commands/rome.kt
index 91bdf47..7df39b3 100644
--- a/src/main/kotlin/moe/nea/firmament/commands/rome.kt
+++ b/src/main/kotlin/moe/nea/firmament/commands/rome.kt
@@ -1,5 +1,6 @@
/*
* SPDX-FileCopyrightText: 2023 Linnea Gräf <nea@nea.moe>
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
@@ -52,7 +53,12 @@ fun firmamentCommand() = literal("firmament") {
val configObj = AllConfigsGui.allConfigs.find { it.name == config }
if (configObj == null) {
- source.sendFeedback(Text.stringifiedTranslatable("firmament.command.toggle.no-config-found", config))
+ source.sendFeedback(
+ Text.stringifiedTranslatable(
+ "firmament.command.toggle.no-config-found",
+ config
+ )
+ )
return@thenExecute
}
val propertyObj = configObj.allOptions[property]
@@ -72,9 +78,11 @@ fun firmamentCommand() = literal("firmament") {
propertyObj.value = !propertyObj.value
configObj.save()
source.sendFeedback(
- Text.stringifiedTranslatable("firmament.command.toggle.toggled",configObj.labelText,
- propertyObj.labelText,
- Text.translatable("firmament.toggle.${propertyObj.value}"))
+ Text.stringifiedTranslatable(
+ "firmament.command.toggle.toggled", configObj.labelText,
+ propertyObj.labelText,
+ Text.translatable("firmament.toggle.${propertyObj.value}")
+ )
)
}
}
@@ -144,22 +152,37 @@ fun firmamentCommand() = literal("firmament") {
Text.stringifiedTranslatable("firmament.price.bazaar.productid", bazaarData.productId.bazaarId)
)
source.sendFeedback(
- Text.stringifiedTranslatable("firmament.price.bazaar.buy.price", FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1))
+ Text.stringifiedTranslatable(
+ "firmament.price.bazaar.buy.price",
+ FirmFormatters.formatCurrency(bazaarData.quickStatus.buyPrice, 1)
+ )
)
source.sendFeedback(
- Text.stringifiedTranslatable("firmament.price.bazaar.buy.order", bazaarData.quickStatus.buyOrders)
+ Text.stringifiedTranslatable(
+ "firmament.price.bazaar.buy.order",
+ bazaarData.quickStatus.buyOrders
+ )
)
source.sendFeedback(
- Text.stringifiedTranslatable("firmament.price.bazaar.sell.price", FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1))
+ Text.stringifiedTranslatable(
+ "firmament.price.bazaar.sell.price",
+ FirmFormatters.formatCurrency(bazaarData.quickStatus.sellPrice, 1)
+ )
)
source.sendFeedback(
- Text.stringifiedTranslatable("firmament.price.bazaar.sell.order", bazaarData.quickStatus.sellOrders)
+ Text.stringifiedTranslatable(
+ "firmament.price.bazaar.sell.order",
+ bazaarData.quickStatus.sellOrders
+ )
)
}
val lowestBin = HypixelStaticData.lowestBin[itemName]
if (lowestBin != null) {
source.sendFeedback(
- Text.stringifiedTranslatable("firmament.price.lowestbin", FirmFormatters.formatCurrency(lowestBin, 1))
+ Text.stringifiedTranslatable(
+ "firmament.price.lowestbin",
+ FirmFormatters.formatCurrency(lowestBin, 1)
+ )
)
}
}
diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt
new file mode 100644
index 0000000..fae3a4b
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityModifier.kt
@@ -0,0 +1,14 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.gui.entity
+
+import com.google.gson.JsonObject
+import net.minecraft.entity.LivingEntity
+
+fun interface EntityModifier {
+ fun apply(entity: LivingEntity, info: JsonObject): LivingEntity
+}
diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt
new file mode 100644
index 0000000..d645e5b
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityRenderer.kt
@@ -0,0 +1,202 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.gui.entity
+
+import com.google.gson.Gson
+import com.google.gson.JsonArray
+import com.google.gson.JsonObject
+import org.apache.logging.log4j.LogManager
+import org.joml.Quaternionf
+import org.joml.Vector3f
+import kotlin.math.atan
+import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.gui.screen.ingame.InventoryScreen
+import net.minecraft.entity.Entity
+import net.minecraft.entity.EntityType
+import net.minecraft.entity.LivingEntity
+import net.minecraft.util.Identifier
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.assertNotNullOr
+import moe.nea.firmament.util.iterate
+import moe.nea.firmament.util.openFirmamentResource
+import moe.nea.firmament.util.render.enableScissorWithTranslation
+
+object EntityRenderer {
+ val fakeWorld = FakeWorld()
+ private fun <T : Entity> t(entityType: EntityType<T>): () -> T {
+ return { entityType.create(fakeWorld)!! }
+ }
+
+ val entityIds: Map<String, () -> LivingEntity> = mapOf(
+ "Zombie" to t(EntityType.ZOMBIE),
+ "Chicken" to t(EntityType.CHICKEN),
+ "Slime" to t(EntityType.SLIME),
+ "Wolf" to t(EntityType.WOLF),
+ "Skeleton" to t(EntityType.SKELETON),
+ "Creeper" to t(EntityType.CREEPER),
+ "Ocelot" to t(EntityType.OCELOT),
+ "Blaze" to t(EntityType.BLAZE),
+ "Rabbit" to t(EntityType.RABBIT),
+ "Sheep" to t(EntityType.SHEEP),
+ "Horse" to t(EntityType.HORSE),
+ "Eisengolem" to t(EntityType.IRON_GOLEM),
+ "Silverfish" to t(EntityType.SILVERFISH),
+ "Witch" to t(EntityType.WITCH),
+ "Endermite" to t(EntityType.ENDERMITE),
+ "Snowman" to t(EntityType.SNOW_GOLEM),
+ "Villager" to t(EntityType.VILLAGER),
+ "Guardian" to t(EntityType.GUARDIAN),
+ "ArmorStand" to t(EntityType.ARMOR_STAND),
+ "Squid" to t(EntityType.SQUID),
+ "Bat" to t(EntityType.BAT),
+ "Spider" to t(EntityType.SPIDER),
+ "CaveSpider" to t(EntityType.CAVE_SPIDER),
+ "Pigman" to t(EntityType.ZOMBIFIED_PIGLIN),
+ "Ghast" to t(EntityType.GHAST),
+ "MagmaCube" to t(EntityType.MAGMA_CUBE),
+ "Wither" to t(EntityType.WITHER),
+ "Enderman" to t(EntityType.ENDERMAN),
+ "Mooshroom" to t(EntityType.MOOSHROOM),
+ "WitherSkeleton" to t(EntityType.WITHER_SKELETON),
+ "Cow" to t(EntityType.COW),
+ "Dragon" to t(EntityType.ENDER_DRAGON),
+ "Player" to { makeGuiPlayer(fakeWorld) },
+ "Pig" to t(EntityType.PIG),
+ "Giant" to t(EntityType.GIANT),
+ )
+ val entityModifiers: Map<String, EntityModifier> = mapOf(
+ "playerdata" to ModifyPlayerSkin,
+ "equipment" to ModifyEquipment,
+ "riding" to ModifyRiding,
+ "charged" to ModifyCharged,
+ "witherdata" to ModifyWither,
+ "invisible" to ModifyInvisible,
+ "age" to ModifyAge,
+ "horse" to ModifyHorse,
+ "name" to ModifyName,
+ )
+
+ val logger = LogManager.getLogger("Firmament.Entity")
+ fun applyModifiers(entityId: String, modifiers: List<JsonObject>): LivingEntity? {
+ val entityType = assertNotNullOr(entityIds[entityId]) {
+ logger.error("Could not create entity with id $entityId")
+ return null
+ }
+ var entity = entityType()
+ for (modifierJson in modifiers) {
+ val modifier = assertNotNullOr(modifierJson["type"]?.asString?.let(entityModifiers::get)) {
+ logger.error("Unknown modifier $modifierJson")
+ return null
+ }
+ entity = modifier.apply(entity, modifierJson)
+ }
+ return entity
+ }
+
+ fun constructEntity(info: JsonObject): LivingEntity? {
+ val modifiers = (info["modifiers"] as JsonArray?)?.map { it.asJsonObject } ?: emptyList()
+ val entityType = assertNotNullOr(info["entity"]?.asString) {
+ logger.error("Missing entity type on entity object")
+ return null
+ }
+ return applyModifiers(entityType, modifiers)
+ }
+
+ private val gson = Gson()
+ fun constructEntity(location: Identifier): LivingEntity? {
+ return constructEntity(
+ gson.fromJson(
+ location.openFirmamentResource().bufferedReader(), JsonObject::class.java
+ )
+ )
+ }
+
+ fun renderEntity(
+ entity: LivingEntity,
+ renderContext: DrawContext,
+ posX: Int,
+ posY: Int,
+ mouseX: Float,
+ mouseY: Float
+ ) {
+ var bottomOffset = 0.0F
+ var currentEntity = entity
+ val maxSize = entity.iterate { it.firstPassenger as? LivingEntity }
+ .map { it.height }
+ .sum()
+ while (true) {
+ currentEntity.age = MC.player?.age ?: 0
+ drawEntity(
+ renderContext,
+ posX,
+ posY,
+ posX + 50,
+ posY + 80,
+ (2F / maxSize * 30).toInt(),
+ -bottomOffset,
+ mouseX,
+ mouseY,
+ currentEntity
+ )
+ val next = currentEntity.firstPassenger as? LivingEntity ?: break
+ bottomOffset += currentEntity.getPassengerRidingPos(next).y.toFloat() * 0.75F
+ currentEntity = next
+ }
+ }
+
+
+ fun drawEntity(
+ context: DrawContext,
+ x1: Int,
+ y1: Int,
+ x2: Int,
+ y2: Int,
+ size: Int,
+ bottomOffset: Float,
+ mouseX: Float,
+ mouseY: Float,
+ entity: LivingEntity
+ ) {
+ context.enableScissorWithTranslation(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
+ val centerX = (x1 + x2) / 2f
+ val centerY = (y1 + y2) / 2f
+ val targetYaw = atan(((centerX - mouseX) / 40.0f).toDouble()).toFloat()
+ val targetPitch = atan(((centerY - mouseY) / 40.0f).toDouble()).toFloat()
+ val rotateToFaceTheFront = Quaternionf().rotateZ(Math.PI.toFloat())
+ val rotateToFaceTheCamera = Quaternionf().rotateX(targetPitch * 20.0f * (Math.PI.toFloat() / 180))
+ rotateToFaceTheFront.mul(rotateToFaceTheCamera)
+ val oldBodyYaw = entity.bodyYaw
+ val oldYaw = entity.yaw
+ val oldPitch = entity.pitch
+ val oldPrevHeadYaw = entity.prevHeadYaw
+ val oldHeadYaw = entity.headYaw
+ entity.bodyYaw = 180.0f + targetYaw * 20.0f
+ entity.yaw = 180.0f + targetYaw * 40.0f
+ entity.pitch = -targetPitch * 20.0f
+ entity.headYaw = entity.yaw
+ entity.prevHeadYaw = entity.yaw
+ val vector3f = Vector3f(0.0f, entity.height / 2.0f + bottomOffset, 0.0f)
+ InventoryScreen.drawEntity(
+ context,
+ centerX,
+ centerY,
+ size,
+ vector3f,
+ rotateToFaceTheFront,
+ rotateToFaceTheCamera,
+ entity
+ )
+ entity.bodyYaw = oldBodyYaw
+ entity.yaw = oldYaw
+ entity.pitch = oldPitch
+ entity.prevHeadYaw = oldPrevHeadYaw
+ entity.headYaw = oldHeadYaw
+ context.disableScissor()
+ }
+
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt
new file mode 100644
index 0000000..42fa485
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/gui/entity/EntityWidget.kt
@@ -0,0 +1,40 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.gui.entity
+
+import me.shedaniel.math.Dimension
+import me.shedaniel.math.Point
+import me.shedaniel.math.Rectangle
+import me.shedaniel.rei.api.client.gui.widgets.WidgetWithBounds
+import net.minecraft.client.gui.DrawContext
+import net.minecraft.client.gui.Element
+import net.minecraft.entity.LivingEntity
+
+class EntityWidget(val entity: LivingEntity, val point: Point) : WidgetWithBounds() {
+ override fun children(): List<Element> {
+ return emptyList()
+ }
+
+ var hasErrored = false
+
+ override fun render(context: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
+ try {
+ if (!hasErrored)
+ EntityRenderer.renderEntity(entity, context, point.x, point.y, mouseX.toFloat(), mouseY.toFloat())
+ } catch (ex: Exception) {
+ EntityRenderer.logger.error("Failed to render constructed entity: $entity", ex)
+ hasErrored = true
+ }
+ if (hasErrored) {
+ context.fill(point.x, point.y, point.x + 50, point.y + 80, 0xFFAA2222.toInt())
+ }
+ }
+
+ override fun getBounds(): Rectangle {
+ return Rectangle(point, Dimension(50, 80))
+ }
+}
diff --git a/src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt b/src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt
new file mode 100644
index 0000000..4cdfc45
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/gui/entity/FakeWorld.kt
@@ -0,0 +1,491 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.gui.entity
+
+import com.mojang.datafixers.util.Pair
+import com.mojang.serialization.Lifecycle
+import java.util.*
+import java.util.function.BooleanSupplier
+import java.util.function.Consumer
+import java.util.stream.Stream
+import kotlin.jvm.optionals.getOrNull
+import kotlin.streams.asSequence
+import net.minecraft.block.Block
+import net.minecraft.block.BlockState
+import net.minecraft.client.world.ClientWorld
+import net.minecraft.entity.Entity
+import net.minecraft.entity.player.PlayerEntity
+import net.minecraft.fluid.Fluid
+import net.minecraft.item.map.MapState
+import net.minecraft.recipe.RecipeManager
+import net.minecraft.registry.BuiltinRegistries
+import net.minecraft.registry.DynamicRegistryManager
+import net.minecraft.registry.Registry
+import net.minecraft.registry.RegistryKey
+import net.minecraft.registry.RegistryKeys
+import net.minecraft.registry.RegistryWrapper
+import net.minecraft.registry.entry.RegistryEntry
+import net.minecraft.registry.entry.RegistryEntryList
+import net.minecraft.registry.entry.RegistryEntryOwner
+import net.minecraft.registry.tag.TagKey
+import net.minecraft.resource.featuretoggle.FeatureFlag
+import net.minecraft.resource.featuretoggle.FeatureFlags
+import net.minecraft.resource.featuretoggle.FeatureSet
+import net.minecraft.scoreboard.Scoreboard
+import net.minecraft.sound.SoundCategory
+import net.minecraft.sound.SoundEvent
+import net.minecraft.util.Identifier
+import net.minecraft.util.TypeFilter
+import net.minecraft.util.function.LazyIterationConsumer
+import net.minecraft.util.math.BlockPos
+import net.minecraft.util.math.Box
+import net.minecraft.util.math.ChunkPos
+import net.minecraft.util.math.Direction
+import net.minecraft.util.math.Vec3d
+import net.minecraft.util.math.random.Random
+import net.minecraft.util.profiler.DummyProfiler
+import net.minecraft.world.BlockView
+import net.minecraft.world.Difficulty
+import net.minecraft.world.GameRules
+import net.minecraft.world.MutableWorldProperties
+import net.minecraft.world.World
+import net.minecraft.world.biome.Biome
+import net.minecraft.world.biome.BiomeKeys
+import net.minecraft.world.chunk.Chunk
+import net.minecraft.world.chunk.ChunkManager
+import net.minecraft.world.chunk.ChunkStatus
+import net.minecraft.world.chunk.EmptyChunk
+import net.minecraft.world.chunk.light.LightingProvider
+import net.minecraft.world.entity.EntityLookup
+import net.minecraft.world.event.GameEvent
+import net.minecraft.world.tick.OrderedTick
+import net.minecraft.world.tick.QueryableTickScheduler
+import net.minecraft.world.tick.TickManager
+
+fun <T> makeRegistry(registryWrapper: RegistryWrapper.Impl<T>, key: RegistryKey<out Registry<T>>): Registry<T> {
+ val inverseLookup = registryWrapper.streamEntries()
+ .asSequence().map { it.value() to it.registryKey() }
+ .toMap()
+ val idLookup = registryWrapper.streamEntries()
+ .asSequence()
+ .map { it.registryKey() }
+ .withIndex()
+ .associate { it.value to it.index }
+ val map = registryWrapper.streamEntries().asSequence().map { it.registryKey() to it.value() }.toMap(mutableMapOf())
+ val inverseIdLookup = idLookup.asIterable().associate { (k, v) -> v to k }
+ return object : Registry<T> {
+ override fun get(key: RegistryKey<T>?): T? {
+ return registryWrapper.getOptional(key).getOrNull()?.value()
+ }
+
+ override fun iterator(): MutableIterator<T> {
+ return object : MutableIterator<T> {
+ val iterator = registryWrapper.streamEntries().iterator()
+ override fun hasNext(): Boolean {
+ return iterator.hasNext()
+ }
+
+ override fun next(): T {
+ return iterator.next().value()
+ }
+
+ override fun remove() {
+ TODO("Not yet implemented")
+ }
+ }
+ }
+
+ override fun getRawId(value: T?): Int {
+ return idLookup[inverseLookup[value ?: return -1] ?: return -1] ?: return -1
+ }
+
+ override fun get(id: Identifier?): T? {
+ return get(RegistryKey.of(key, id))
+ }
+
+ override fun get(index: Int): T? {
+ return get(inverseIdLookup[index] ?: return null)
+ }
+
+ override fun size(): Int {
+ return idLookup.size
+ }
+
+ override fun getKey(): RegistryKey<out Registry<T>> {
+ return key
+ }
+
+ override fun getLifecycle(): Lifecycle {
+ return Lifecycle.stable()
+ }
+
+ override fun getIds(): MutableSet<Identifier> {
+ return idLookup.keys.mapTo(mutableSetOf()) { it.value }
+ }
+
+ override fun getEntrySet(): MutableSet<MutableMap.MutableEntry<RegistryKey<T>, T>> {
+ return map.entries
+ }
+
+ override fun getKeys(): MutableSet<RegistryKey<T>> {
+ return map.keys
+ }
+
+ override fun getRandom(random: Random?): Optional<RegistryEntry.Reference<T>> {
+ return registryWrapper.streamEntries().findFirst()
+ }
+
+ override fun containsId(id: Identifier?): Boolean {
+ return idLookup.containsKey(RegistryKey.of(key, id ?: return false))
+ }
+
+ override fun freeze(): Registry<T> {
+ return this
+ }
+
+ override fun getEntry(rawId: Int): Optional<RegistryEntry.Reference<T>> {
+ val x = inverseIdLookup[rawId] ?: return Optional.empty()
+ return Optional.of(RegistryEntry.Reference.standAlone(registryWrapper, x))
+ }
+
+ override fun streamEntries(): Stream<RegistryEntry.Reference<T>> {
+ return registryWrapper.streamEntries()
+ }
+
+ override fun streamTagsAndEntries(): Stream<Pair<TagKey<T>, RegistryEntryList.Named<T>>> {
+ return streamTags().map { Pair(it, getOrCreateEntryList(it)) }
+ }
+
+ override fun streamTags(): Stream<TagKey<T>> {
+ return registryWrapper.streamTagKeys()
+ }
+
+ override fun clearTags() {
+ }
+
+ override fun getEntryOwner(): RegistryEntryOwner<T> {
+ return registryWrapper
+ }
+
+ override fun getReadOnlyWrapper(): RegistryWrapper.Impl<T> {
+ return registryWrapper
+ }
+
+ override fun populateTags(tagEntries: MutableMap<TagKey<T>, MutableList<RegistryEntry<T>>>?) {
+ }
+
+ override fun getOrCreateEntryList(tag: TagKey<T>?): RegistryEntryList.Named<T> {
+ return getEntryList(tag).orElseGet { RegistryEntryList.of(registryWrapper, tag) }
+ }
+
+ override fun getEntryList(tag: TagKey<T>?): Optional<RegistryEntryList.Named<T>> {
+ return registryWrapper.getOptional(tag ?: return Optional.empty())
+ }
+
+ override fun getEntry(value: T): RegistryEntry<T> {
+ return registryWrapper.getOptional(inverseLookup[value]!!).get()
+ }
+
+ override fun getEntry(key: RegistryKey<T>?): Optional<RegistryEntry.Reference<T>> {
+ return registryWrapper.getOptional(key ?: return Optional.empty())
+ }
+
+ override fun createEntry(value: T): RegistryEntry.Reference<T> {
+ TODO()
+ }
+
+ override fun contains(key: RegistryKey<T>?): Boolean {
+ return getEntry(key).isPresent
+ }
+
+ override fun getEntryLifecycle(entry: T): Lifecycle {
+ return Lifecycle.stable()
+ }
+
+ override fun getId(value: T): Identifier? {
+ return (inverseLookup[value] ?: return null).value
+ }
+
+ override fun getKey(entry: T): Optional<RegistryKey<T>> {
+ return Optional.ofNullable(inverseLookup[entry ?: return Optional.empty()])
+ }
+ }
+}
+
+fun createDynamicRegistry(): DynamicRegistryManager.Immutable {
+ val wrapperLookup = BuiltinRegistries.createWrapperLookup()
+ return object : DynamicRegistryManager.Immutable {
+ override fun <E : Any?> getOptional(key: RegistryKey<out Registry<out E>>): Optional<Registry<E>> {
+ val lookup = wrapperLookup.getOptionalWrapper(key).getOrNull() ?: return Optional.empty()
+ val registry = makeRegistry(lookup, key as RegistryKey<out Registry<E>>)
+ return Optional.of(registry)
+ }
+
+ fun <T> entry(reg: RegistryKey<out Registry<T>>): DynamicRegistryManager.Entry<T> {
+ return DynamicRegistryManager.Entry(reg, getOptional(reg).get())
+ }
+
+ override fun streamAllRegistries(): Stream<DynamicRegistryManager.Entry<*>> {
+ return wrapperLookup.streamAllRegistryKeys()
+ .map { entry(it as RegistryKey<out Registry<Any>>) }
+ }
+ }
+}
+
+class FakeWorld(registries: DynamicRegistryManager.Immutable = createDynamicRegistry()) : World(
+ Properties,
+ RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")),
+ registries,
+ registries[RegistryKeys.DIMENSION_TYPE].entryOf(
+ RegistryKey.of(
+ RegistryKeys.DIMENSION_TYPE,
+ Identifier("minecraft", "overworld")
+ )
+ ),
+ { DummyProfiler.INSTANCE },
+ true,
+ false,
+ 0, 0
+) {
+ object Properties : MutableWorldProperties {
+ override fun getSpawnX(): Int {
+ return 0
+ }
+
+ override fun getSpawnY(): Int {
+ return 0
+ }
+
+ override fun getSpawnZ(): Int {
+ return 0
+ }
+
+ override fun getSpawnAngle(): Float {
+ return 0F
+ }
+
+ override fun getTime(): Long {
+ return 0
+ }
+
+ override fun getTimeOfDay(): Long {
+ return 0
+ }
+
+ override fun isThundering(): Boolean {
+ return false
+ }
+
+ override fun isRaining(): Boolean {
+ return false
+ }
+
+ override fun setRaining(raining: Boolean) {
+ }
+
+ override fun isHardcore(): Boolean {
+ return false
+ }
+
+ override fun getGameRules(): GameRules {
+ return GameRules()
+ }
+
+ override fun getDifficulty(): Difficulty {
+ return Difficulty.HARD
+ }
+
+ override fun isDifficultyLocked(): Boolean {
+ return false
+ }
+
+ override fun setSpawnX(spawnX: Int) {
+ }
+
+ override fun setSpawnY(spawnY: Int) {
+ }
+
+ override fun setSpawnZ(spawnZ: Int) {
+ }
+
+ override fun setSpawnAngle(spawnAngle: Float) {
+ }
+ }
+
+ override fun getPlayers(): List<PlayerEntity> {
+ return emptyList()
+ }
+
+ override fun getBrightness(direction: Direction?, shaded: Boolean): Float {
+ return 1f
+ }
+
+ override fun getGeneratorStoredBiome(biomeX: Int, biomeY: Int, biomeZ: Int): RegistryEntry<Biome> {
+ return registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS)
+ }
+
+ override fun getEnabledFeatures(): FeatureSet {
+ return FeatureFlags.VANILLA_FEATURES
+ }
+
+ class FakeTickScheduler<T> : QueryableTickScheduler<T> {
+ override fun scheduleTick(orderedTick: OrderedTick<T>?) {
+ }
+
+ override fun isQueued(pos: BlockPos?, type: T): Boolean {
+ return true
+ }
+
+ override fun getTickCount(): Int {
+ return 0
+ }
+
+ override fun isTicking(pos: BlockPos?, type: T): Boolean {
+ return true
+ }
+
+ }
+
+ override fun getBlockTickScheduler(): QueryableTickScheduler<Block> {
+ return FakeTickScheduler()
+ }
+
+ override fun getFluidTickScheduler(): QueryableTickScheduler<Fluid> {
+ return FakeTickScheduler()
+ }
+
+
+ class FakeChunkManager(val world: FakeWorld) : ChunkManager() {
+ override fun getChunk(x: Int, z: Int, leastStatus: ChunkStatus?, create: Boolean): Chunk {
+ return EmptyChunk(world, ChunkPos(x,z), world.registryManager.get(RegistryKeys.BIOME).entryOf(BiomeKeys.PLAINS))
+ }
+
+ override fun getWorld(): BlockView {
+ return world
+ }
+
+ override fun tick(shouldKeepTicking: BooleanSupplier?, tickChunks: Boolean) {
+ }
+
+ override fun getDebugString(): String {
+ return "FakeChunkManager"
+ }
+
+ override fun getLoadedChunkCount(): Int {
+ return 0
+ }
+
+ override fun getLightingProvider(): LightingProvider {
+ return FakeLightingProvider(this)
+ }
+ }
+
+ class FakeLightingProvider(chunkManager: FakeChunkManager) : LightingProvider(chunkManager, false, false)
+
+ override fun getChunkManager(): ChunkManager {
+ return FakeChunkManager(this)
+ }
+
+ override fun playSound(
+ source: PlayerEntity?,
+ x: Double,
+ y: Double,
+ z: Double,
+ sound: RegistryEntry<SoundEvent>?,
+ category: SoundCategory?,