aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2024-11-08 22:02:10 +0100
committerLinnea Gräf <nea@nea.moe>2024-11-08 22:02:10 +0100
commit0e1ddd2c913656a631e26dd0c560f25179a7dc2d (patch)
tree4b4ed01165aa51c23115333dec20075473f4e8c6 /src/main
parentf6f8fef556e74f24187ad2a6296f573024a378b3 (diff)
downloadFirmament-0e1ddd2c913656a631e26dd0c560f25179a7dc2d.tar.gz
Firmament-0e1ddd2c913656a631e26dd0c560f25179a7dc2d.tar.bz2
Firmament-0e1ddd2c913656a631e26dd0c560f25179a7dc2d.zip
Fix missing tags in REI renderingupdate
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java11
-rw-r--r--src/main/kotlin/events/WorldReadyEvent.kt9
-rw-r--r--src/main/kotlin/gui/entity/EntityRenderer.kt330
-rw-r--r--src/main/kotlin/gui/entity/FakeWorld.kt13
-rw-r--r--src/main/kotlin/gui/entity/GuiPlayer.kt63
-rw-r--r--src/main/kotlin/repo/SBItemStack.kt3
-rw-r--r--src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt19
-rw-r--r--src/main/kotlin/repo/recipes/RecipeLayouter.kt33
-rw-r--r--src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt50
-rw-r--r--src/main/kotlin/util/MC.kt24
10 files changed, 342 insertions, 213 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java b/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java
index c444f12..d4b8c9e 100644
--- a/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java
+++ b/src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java
@@ -3,16 +3,17 @@
package moe.nea.firmament.mixins;
import moe.nea.firmament.events.WorldReadyEvent;
+import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.DownloadingTerrainScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-@Mixin(DownloadingTerrainScreen.class)
+@Mixin(MinecraftClient.class)
public class WorldReadyEventPatch {
- @Inject(method = "close", at = @At("HEAD"))
- public void onClose(CallbackInfo ci) {
- WorldReadyEvent.Companion.publish(new WorldReadyEvent());
- }
+ @Inject(method = "joinWorld", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MinecraftClient;setWorld(Lnet/minecraft/client/world/ClientWorld;)V", shift = At.Shift.AFTER))
+ public void onClose(CallbackInfo ci) {
+ WorldReadyEvent.Companion.publish(new WorldReadyEvent());
+ }
}
diff --git a/src/main/kotlin/events/WorldReadyEvent.kt b/src/main/kotlin/events/WorldReadyEvent.kt
index 2c76c44..c79b100 100644
--- a/src/main/kotlin/events/WorldReadyEvent.kt
+++ b/src/main/kotlin/events/WorldReadyEvent.kt
@@ -1,7 +1,10 @@
-
-
package moe.nea.firmament.events
class WorldReadyEvent : FirmamentEvent() {
- companion object : FirmamentEventBus<WorldReadyEvent>()
+ companion object : FirmamentEventBus<WorldReadyEvent>()
+// class FullyLoaded : FirmamentEvent() {
+// companion object : FirmamentEventBus<FullyLoaded>() {
+// TODO: check WorldLoadingState
+// }
+// }
}
diff --git a/src/main/kotlin/gui/entity/EntityRenderer.kt b/src/main/kotlin/gui/entity/EntityRenderer.kt
index ebff1a0..ddb862f 100644
--- a/src/main/kotlin/gui/entity/EntityRenderer.kt
+++ b/src/main/kotlin/gui/entity/EntityRenderer.kt
@@ -1,4 +1,3 @@
-
package moe.nea.firmament.gui.entity
import com.google.gson.Gson
@@ -15,6 +14,7 @@ import net.minecraft.entity.EntityType
import net.minecraft.entity.LivingEntity
import net.minecraft.entity.SpawnReason
import net.minecraft.util.Identifier
+import net.minecraft.world.World
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.assertNotNullOr
import moe.nea.firmament.util.iterate
@@ -22,177 +22,177 @@ 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, SpawnReason.LOAD)!! }
- }
+ val fakeWorld: World get() = MC.lastWorld!!
+ private fun <T : Entity> t(entityType: EntityType<T>): () -> T {
+ return { entityType.create(fakeWorld, SpawnReason.LOAD)!! }
+ }
- 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 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
- }
+ 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)
- }
+ 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
- )
- )
- }
+ 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,
- minOf(2F / maxSize, 1F) * 30,
- -bottomOffset,
- mouseX,
- mouseY,
- currentEntity
- )
- val next = currentEntity.firstPassenger as? LivingEntity ?: break
- bottomOffset += currentEntity.getPassengerRidingPos(next).y.toFloat() * 0.75F
- currentEntity = next
- }
- }
+ 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,
+ minOf(2F / maxSize, 1F) * 30,
+ -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: Float,
- 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()
- }
+ fun drawEntity(
+ context: DrawContext,
+ x1: Int,
+ y1: Int,
+ x2: Int,
+ y2: Int,
+ size: Float,
+ 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/gui/entity/FakeWorld.kt b/src/main/kotlin/gui/entity/FakeWorld.kt
index c17f2ad..7ec385c 100644
--- a/src/main/kotlin/gui/entity/FakeWorld.kt
+++ b/src/main/kotlin/gui/entity/FakeWorld.kt
@@ -5,6 +5,7 @@ import java.util.function.BooleanSupplier
import java.util.function.Consumer
import net.minecraft.block.Block
import net.minecraft.block.BlockState
+import net.minecraft.client.gui.screen.world.SelectWorldScreen
import net.minecraft.component.type.MapIdComponent
import net.minecraft.entity.Entity
import net.minecraft.entity.damage.DamageSource
@@ -22,10 +23,15 @@ import net.minecraft.registry.DynamicRegistryManager
import net.minecraft.registry.Registries
import net.minecraft.registry.RegistryKey
import net.minecraft.registry.RegistryKeys
+import net.minecraft.registry.ServerDynamicRegistryType
import net.minecraft.registry.entry.RegistryEntry
+import net.minecraft.resource.DataConfiguration
+import net.minecraft.resource.ResourcePackManager
import net.minecraft.resource.featuretoggle.FeatureFlags
import net.minecraft.resource.featuretoggle.FeatureSet
import net.minecraft.scoreboard.Scoreboard
+import net.minecraft.server.SaveLoading
+import net.minecraft.server.command.CommandManager
import net.minecraft.sound.SoundCategory
import net.minecraft.sound.SoundEvent
import net.minecraft.util.Identifier
@@ -53,8 +59,10 @@ import net.minecraft.world.explosion.ExplosionBehavior
import net.minecraft.world.tick.OrderedTick
import net.minecraft.world.tick.QueryableTickScheduler
import net.minecraft.world.tick.TickManager
+import moe.nea.firmament.util.MC
fun createDynamicRegistry(): DynamicRegistryManager.Immutable {
+ // TODO: use SaveLoading.load() to properly load a full registry
return DynamicRegistryManager.of(Registries.REGISTRIES)
}
@@ -64,9 +72,8 @@ class FakeWorld(
Properties,
RegistryKey.of(RegistryKeys.WORLD, Identifier.of("firmament", "fakeworld")),
registries,
- registries.getOrThrow(RegistryKeys.DIMENSION_TYPE).getEntry(
- Identifier.of("minecraft", "overworld")
- ).get(),
+ MC.defaultRegistries.getOrThrow(RegistryKeys.DIMENSION_TYPE)
+ .getOrThrow(RegistryKey.of(RegistryKeys.DIMENSION_TYPE, Identifier.of("minecraft", "overworld"))),
true,
false,
0L,
diff --git a/src/main/kotlin/gui/entity/GuiPlayer.kt b/src/main/kotlin/gui/entity/GuiPlayer.kt
index d00b44d..aa0bea8 100644
--- a/src/main/kotlin/gui/entity/GuiPlayer.kt
+++ b/src/main/kotlin/gui/entity/GuiPlayer.kt
@@ -1,8 +1,7 @@
-
package moe.nea.firmament.gui.entity
import com.mojang.authlib.GameProfile
-import java.util.*
+import java.util.UUID
import net.minecraft.client.network.AbstractClientPlayerEntity
import net.minecraft.client.util.DefaultSkinHelper
import net.minecraft.client.util.SkinTextures
@@ -15,40 +14,40 @@ import net.minecraft.world.World
/**
* @see moe.nea.firmament.init.EarlyRiser
*/
-fun makeGuiPlayer(world: FakeWorld): GuiPlayer {
- val constructor = GuiPlayer::class.java.getDeclaredConstructor(
- World::class.java,
- BlockPos::class.java,
- Float::class.javaPrimitiveType,
- GameProfile::class.java
- )
- return constructor.newInstance(world, BlockPos.ORIGIN, 0F, GameProfile(UUID.randomUUID(), "Linnea"))
+fun makeGuiPlayer(world: World): GuiPlayer {
+ val constructor = GuiPlayer::class.java.getDeclaredConstructor(
+ World::class.java,
+ BlockPos::class.java,
+ Float::class.javaPrimitiveType,
+ GameProfile::class.java
+ )
+ return constructor.newInstance(world, BlockPos.ORIGIN, 0F, GameProfile(UUID.randomUUID(), "Linnea"))
}
class GuiPlayer(world: ClientWorld?, profile: GameProfile?) : AbstractClientPlayerEntity(world, profile) {
- override fun isSpectator(): Boolean {
- return false
- }
+ override fun isSpectator(): Boolean {
+ return false
+ }
- override fun isCreative(): Boolean {
- return false
- }
+ override fun isCreative(): Boolean {
+ return false
+ }
- override fun shouldRenderName(): Boolean {
- return false
- }
+ override fun shouldRenderName(): Boolean {
+ return false
+ }
- var skinTexture: Identifier = DefaultSkinHelper.getSkinTextures(this.getUuid()).texture
- var capeTexture: Identifier? = null
- var model: Model = Model.WIDE
- override fun getSkinTextures(): SkinTextures {
- return SkinTextures(
- skinTexture,
- null,
- capeTexture,
- null,
- model,
- true
- )
- }
+ var skinTexture: Identifier = DefaultSkinHelper.getSkinTextures(this.getUuid()).texture
+ var capeTexture: Identifier? = null
+ var model: Model = Model.WIDE
+ override fun getSkinTextures(): SkinTextures {
+ return SkinTextures(
+ skinTexture,
+ null,
+ capeTexture,
+ null,
+ model,
+ true
+ )
+ }
}
diff --git a/src/main/kotlin/repo/SBItemStack.kt b/src/main/kotlin/repo/SBItemStack.kt
index e1cbdbb..18126ee 100644
--- a/src/main/kotlin/repo/SBItemStack.kt
+++ b/src/main/kotlin/repo/SBItemStack.kt
@@ -58,6 +58,7 @@ data class SBItemStack constructor(
SBItemStack(id, count)
}
}
+ val EMPTY = SBItemStack(SkyblockId.NULL, 0)
operator fun invoke(itemStack: ItemStack): SBItemStack {
val skyblockId = itemStack.skyBlockId ?: SkyblockId.NULL
@@ -133,6 +134,8 @@ data class SBItemStack constructor(
val itemStack = itemStack_ ?: run {
if (skyblockId == SkyblockId.COINS)
return@run ItemCache.coinItem(stackSize).also { it.appendLore(extraLore) }
+ if (stackSize == 0)
+ return@run ItemStack.EMPTY
val replacementData = mutableMapOf<String, String>()
injectReplacementDataForPets(replacementData)
return@run neuItem.asItemStack(idHint = skyblockId, replacementData)
diff --git a/src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt b/src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt
new file mode 100644
index 0000000..9a1aea5
--- /dev/null
+++ b/src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt
@@ -0,0 +1,19 @@
+package moe.nea.firmament.repo.recipes
+
+import io.github.moulberry.repo.NEURepository
+import io.github.moulberry.repo.data.NEURecipe
+import me.shedaniel.math.Rectangle
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Text
+import net.minecraft.util.Identifier
+import moe.nea.firmament.repo.SBItemStack
+
+interface GenericRecipeRenderer<T : NEURecipe> {
+ fun render(recipe: T, bounds: Rectangle, layouter: RecipeLayouter)
+ fun getInputs(recipe: T): Collection<SBItemStack>
+ fun getOutputs(recipe: T): Collection<SBItemStack>
+ val icon: ItemStack
+ val title: Text
+ val identifier: Identifier
+ fun findAllRecipes(neuRepository: NEURepository): Iterable<T>
+}
diff --git a/src/main/kotlin/repo/recipes/RecipeLayouter.kt b/src/main/kotlin/repo/recipes/RecipeLayouter.kt
new file mode 100644
index 0000000..109bff5
--- /dev/null
+++ b/src/main/kotlin/repo/recipes/RecipeLayouter.kt
@@ -0,0 +1,33 @@
+package moe.nea.firmament.repo.recipes
+
+import io.github.notenoughupdates.moulconfig.gui.GuiComponent
+import net.minecraft.text.Text
+import moe.nea.firmament.repo.SBItemStack
+
+interface RecipeLayouter {
+ enum class SlotKind {
+ SMALL_INPUT,
+ SMALL_OUTPUT,
+
+ /**
+ * Create a bigger background and mark the slot as output. The coordinates should still refer the upper left corner of the item stack, not of the bigger background.
+ */
+ BIG_OUTPUT,
+ }
+
+ fun createItemSlot(
+ x: Int, y: Int,
+ content: SBItemStack?,
+ slotKind: SlotKind,
+ )
+
+ fun createLabel(
+ x: Int, y: Int,
+ text: Text
+ )
+
+ fun createArrow(x: Int, y: Int)
+
+ fun createMoulConfig(x: Int, y: Int, w: Int, h: Int, component: GuiComponent)
+}
+
diff --git a/src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt b/src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt
new file mode 100644
index 0000000..fd0c750
--- /dev/null
+++ b/src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt
@@ -0,0 +1,50 @@
+package moe.nea.firmament.repo.recipes
+
+import io.github.moulberry.repo.NEURepository
+import io.github.moulberry.repo.data.NEUCraftingRecipe
+import me.shedaniel.math.Point
+import me.shedaniel.math.Rectangle
+import net.minecraft.block.Blocks
+import net.minecraft.item.ItemStack
+import net.minecraft.text.Text
+import net.minecraft.util.Identifier
+import moe.nea.firmament.Firmament
+import moe.nea.firmament.repo.SBItemStack
+import moe.nea.firmament.util.tr
+
+class SBCraftingRecipeRenderer : GenericRecipeRenderer<NEUCraftingRecipe> {
+ override fun render(recipe: NEUCraftingRecipe, bounds: Rectangle, layouter: RecipeLayouter) {
+ val point = Point(bounds.centerX - 58, bounds.centerY - 27)
+ layouter.createArrow(point.x + 60, point.y + 18)
+ for (i in 0 until 3) {
+ for (j in 0 until 3) {
+ val item = recipe.inputs[i + j * 3]
+ layouter.createItemSlot(point.x + 1 + i * 18,
+ point.y + 1 + j * 18,
+ SBItemStack(item),
+ RecipeLayouter.SlotKind.SMALL_INPUT)
+ }
+ }
+ layouter.createItemSlot(
+ point.x + 95, point.y + 19,
+ SBItemStack(recipe.output),
+ RecipeLayouter.SlotKind.BIG_OUTPUT
+ )
+ }
+
+ override fun getInputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
+ return recipe.allInputs.mapNotNull { SBItemStack(it) }
+ }
+
+ override fun getOutputs(recipe: NEUCraftingRecipe): Collection<SBItemStack> {
+ return SBItemStack(recipe.output)?.let(::listOf) ?: emptyList()
+ }
+
+ override fun findAllRecipes(neuRepository: NEURepository): Iterable<NEUCraftingRecipe> {
+ return neuRepository.items.items.values.flatMap { it.recipes }.filterIsInstance<NEUCraftingRecipe>()
+ }
+
+ override val icon: ItemStack = ItemStack(Blocks.CRAFTING_TABLE)
+ override val title: Text = tr("firmament.category.crafting", "SkyBlock Crafting")
+ override val identifier: Identifier = Firmament.identifier("crafting_recipe")
+}
diff --git a/src/main/kotlin/util/MC.kt b/src/main/kotlin/util/MC.kt
index 33825f1..1b7739f 100644
--- a/src/main/kotlin/util/MC.kt
+++ b/src/main/kotlin/util/MC.kt
@@ -3,10 +3,13 @@ package moe.nea.firmament.util
import io.github.moulberry.repo.data.Coordinate
import java.util.concurrent.ConcurrentLinkedQueue
import net.minecraft.client.MinecraftClient
+import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen
-import net.minecraft.client.option.GameOptions
+import net.minecraft.client.network.ClientPlayerEntity
import net.minecraft.client.render.WorldRenderer
import net.minecraft.client.render.item.ItemRenderer
+import net.minecraft.client.world.ClientWorld
+import net.minecraft.entity.Entity
import net.minecraft.item.Item
import net.minecraft.network.packet.c2s.play.CommandExecutionC2SPacket
import net.minecraft.registry.BuiltinRegistries
@@ -15,7 +18,9 @@ import net.minecraft.registry.RegistryWrapper
import net.minecraft.resource.ReloadableResourceManagerImpl
import net.minecraft.text.Text
import net.minecraft.util.math.BlockPos
+import net.minecraft.world.World
import moe.nea.firmament.events.TickEvent
+import moe.nea.firmament.events.WorldReadyEvent
object MC {
@@ -30,6 +35,9 @@ object MC {
(nextTickTodos.poll() ?: break).invoke()
}
}
+ WorldReadyEvent.subscribe("MC:ready") {
+ this.lastWorld
+ }
}
fun sendChat(text: Text) {
@@ -81,11 +89,11 @@ object MC {
inline val inGameHud get() = instance.inGameHud
inline val font get() = instance.textRenderer
inline val soundManager get() = instance.soundManager
- inline val player get() = instance.player
- inline val camera get() = instance.cameraEntity
+ inline val player: ClientPlayerEntity? get() = instance.player
+ inline val camera: Entity? get() = instance.cameraEntity
inline val guiAtlasManager get() = instance.guiAtlasManager
- inline val world get() = instance.world
- inline var screen
+ inline val world: ClientWorld? get() = instance.world
+ inline var screen: Screen?
get() = instance.currentScreen
set(value) = instance.setScreen(value)
val screenName get() = screen?.title?.unformattedString?.trim()
@@ -95,6 +103,12 @@ object MC {
val defaultRegistries: RegistryWrapper.WrapperLookup = BuiltinRegistries.createWrapperLookup()
inline val currentOrDefaultRegistries get() = currentRegistries ?: defaultRegistries
val defaultItems: RegistryWrapper.Impl<Item> = defaultRegistries.getOrThrow(RegistryKeys.ITEM)
+ var lastWorld: World? = null
+ get() {
+ field = world ?: field
+ return field
+ }
+ private set
}