diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt | 22 | ||||
-rw-r--r-- | src/main/java/moe/nea/firmament/mixins/WorldReadyEventPatch.java | 11 | ||||
-rw-r--r-- | src/main/kotlin/events/WorldReadyEvent.kt | 9 | ||||
-rw-r--r-- | src/main/kotlin/gui/entity/EntityRenderer.kt | 330 | ||||
-rw-r--r-- | src/main/kotlin/gui/entity/FakeWorld.kt | 13 | ||||
-rw-r--r-- | src/main/kotlin/gui/entity/GuiPlayer.kt | 63 | ||||
-rw-r--r-- | src/main/kotlin/repo/SBItemStack.kt | 3 | ||||
-rw-r--r-- | src/main/kotlin/repo/recipes/GenericRecipeRenderer.kt | 19 | ||||
-rw-r--r-- | src/main/kotlin/repo/recipes/RecipeLayouter.kt | 33 | ||||
-rw-r--r-- | src/main/kotlin/repo/recipes/SBCraftingRecipeRenderer.kt | 50 | ||||
-rw-r--r-- | src/main/kotlin/util/MC.kt | 24 |
11 files changed, 357 insertions, 220 deletions
diff --git a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt index da0b645..de173ff 100644 --- a/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt +++ b/src/compat/rei/java/moe/nea/firmament/compat/rei/NEUItemEntryRenderer.kt @@ -26,12 +26,12 @@ import net.minecraft.client.render.OverlayTexture import net.minecraft.client.render.VertexConsumerProvider import net.minecraft.client.render.model.BakedModel import net.minecraft.client.texture.SpriteAtlasTexture -import net.minecraft.item.Item import net.minecraft.item.ModelTransformationMode -import net.minecraft.item.tooltip.TooltipType import moe.nea.firmament.compat.rei.FirmamentReiPlugin.Companion.asItemEntry import moe.nea.firmament.repo.SBItemStack import moe.nea.firmament.util.MC +import moe.nea.firmament.util.mc.displayNameAccordingToNbt +import moe.nea.firmament.util.mc.loreAccordingToNbt object NEUItemEntryRenderer : EntryRenderer<SBItemStack>, BatchedEntryRenderer<SBItemStack, BakedModel> { override fun render( @@ -49,11 +49,19 @@ object NEUItemEntryRenderer : EntryRenderer<SBItemStack>, BatchedEntryRenderer<S override fun getTooltip(entry: EntryStack<SBItemStack>, tooltipContext: TooltipContext): Tooltip? { val stack = entry.value.asImmutableItemStack() - val lore = stack.getTooltip( - Item.TooltipContext.DEFAULT, - null, - TooltipType.BASIC - ) + + val lore = mutableListOf(stack.displayNameAccordingToNbt) + lore.addAll(stack.loreAccordingToNbt) + + // TODO: tags aren't sent as early now so some tooltip components that use tags will crash the game +// stack.getTooltip( +// Item.TooltipContext.create( +// tooltipContext.vanillaContext().registryLookup +// ?: MC.defaultRegistries +// ), +// MC.player, +// TooltipType.BASIC +// ) return Tooltip.create(lore) } 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 } |