From 0bdaec8afb1f905bf901f56e288984158d439bd0 Mon Sep 17 00:00:00 2001 From: ttttdoy Date: Tue, 13 Aug 2024 23:51:35 -0400 Subject: [PATCH] big changes are coming (they're already here) --- README.md | 2 +- .../kotlin/breadmod/ClientForgeEventBus.kt | 126 ++++ src/main/kotlin/breadmod/ClientModEventBus.kt | 4 +- .../{hud => gui}/AbstractModGuiOverlay.kt | 5 +- .../client/{hud => gui}/ToolGunOverlay.kt | 3 +- .../gui/components/ScaledAbstractButton.kt | 71 ++ .../gui/components/ScaledAbstractWidget.kt | 39 ++ .../screen/tool_gun/ToolGunCreatorScreen.kt | 663 ++++++++++++++++++ .../creator/PotionEffectGuiElement.kt | 23 - .../tool_gun/creator/ToolGunCreatorScreen.kt | 467 ------------ .../datagen/lang/USEnglishLanguageProvider.kt | 2 + .../breadmod/item/tool_gun/ToolGunItem.kt | 45 +- .../item/tool_gun/mode/creator/CreatorUtil.kt | 9 +- .../mode/creator/ToolGunCreatorMode.kt | 24 +- .../network/tool_gun/ToolGunPacket.kt | 75 +- .../kotlin/breadmod/util/render/General.kt | 2 + .../resources/META-INF/accesstransformer.cfg | 3 + .../gui/item/tool_gun/creator_mode.png | Bin 11214 -> 11201 bytes 18 files changed, 973 insertions(+), 590 deletions(-) rename src/main/kotlin/breadmod/client/{hud => gui}/AbstractModGuiOverlay.kt (95%) rename src/main/kotlin/breadmod/client/{hud => gui}/ToolGunOverlay.kt (98%) create mode 100644 src/main/kotlin/breadmod/client/gui/components/ScaledAbstractButton.kt create mode 100644 src/main/kotlin/breadmod/client/gui/components/ScaledAbstractWidget.kt create mode 100644 src/main/kotlin/breadmod/client/screen/tool_gun/ToolGunCreatorScreen.kt delete mode 100644 src/main/kotlin/breadmod/client/screen/tool_gun/creator/PotionEffectGuiElement.kt delete mode 100644 src/main/kotlin/breadmod/client/screen/tool_gun/creator/ToolGunCreatorScreen.kt diff --git a/README.md b/README.md index d32ed7af..76f12f25 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ - [X] items inputted into machines from their sides are voided out of existence - [X] items not saving on world save/load - [ ] Fluid texture on diesel machine needs to be normalized - - [ ] (major) tool gun stacking up/absorbing clicks when not equipped + - [X] (major) tool gun stacking up/absorbing clicks when not equipped - [ ] Tool gun beam is scuffed - [ ] Certain slots in block entity screens not showing any items on client - [ ] happy block explosion not actually exploding an area diff --git a/src/main/kotlin/breadmod/ClientForgeEventBus.kt b/src/main/kotlin/breadmod/ClientForgeEventBus.kt index 9cbcf0e4..d85e9bfb 100644 --- a/src/main/kotlin/breadmod/ClientForgeEventBus.kt +++ b/src/main/kotlin/breadmod/ClientForgeEventBus.kt @@ -1,10 +1,23 @@ package breadmod import breadmod.ClientModEventBus.createMappingsForControls +import breadmod.ClientModEventBus.toolGunBindList +import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_DEF +import breadmod.item.tool_gun.ToolGunItem +import breadmod.network.PacketHandler.NETWORK +import breadmod.network.tool_gun.ToolGunPacket import breadmod.util.render.renderBuffer +import com.mojang.blaze3d.platform.InputConstants +import net.minecraft.client.KeyMapping import net.minecraft.client.Minecraft +import net.minecraft.client.player.LocalPlayer +import net.minecraft.sounds.SoundEvents import net.minecraftforge.api.distmarker.Dist +import net.minecraftforge.client.event.InputEvent import net.minecraftforge.client.event.RenderLevelStageEvent +import net.minecraftforge.client.settings.KeyConflictContext +import net.minecraftforge.client.settings.KeyModifier +import net.minecraftforge.event.TickEvent import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.common.Mod @@ -32,6 +45,119 @@ object ClientForgeEventBus { options.keyMappings = ArrayUtils.removeElements(options.keyMappings, *createMappingsForControls().toTypedArray()) } +// val keyMap = KeyMapping("tool gun test", GLFW.GLFW_KEY_H, "breadmod") + val changeMode = KeyMapping( + "controls.${ModMain.ID}.$TOOL_GUN_DEF.change_mode", + KeyConflictContext.IN_GAME, + KeyModifier.SHIFT, + InputConstants.Type.MOUSE.getOrCreate(InputConstants.MOUSE_BUTTON_RIGHT), + "controls.${ModMain.ID}.category.$TOOL_GUN_DEF" + ) + + @SubscribeEvent + fun keyInput(event: InputEvent.Key) { + val instance = Minecraft.getInstance() + val player: LocalPlayer = instance.player ?: return + val level = instance.level ?: return + val stack = player.mainHandItem + val item = stack.item + + if(item is ToolGunItem) { + val currentMode = item.getCurrentMode(stack) + if(player.isHolding(item) && changeMode.consumeClick() && + event.action == InputConstants.PRESS) { + NETWORK.sendToServer(ToolGunPacket(true)) + player.playSound(SoundEvents.DISPENSER_FAIL, 1.0f, 1.0f) + } else { + currentMode.keyBinds.forEach { + val bind = toolGunBindList[it] ?: return@forEach + if(player.isHolding(item) && event.key == bind.key.value && event.action == InputConstants.PRESS) { + NETWORK.sendToServer(ToolGunPacket(false, it)) + println("firing action") + currentMode.mode.action(level, player, stack, it) + } + } + } + } + } + + @SubscribeEvent + fun mouseInput(event: InputEvent.MouseButton.Post) { + val instance = Minecraft.getInstance() + val player: LocalPlayer = instance.player ?: return + val level = instance.level ?: return + val stack = player.mainHandItem + val item = stack.item + + if(item is ToolGunItem) { +// println(event.modifiers) + val currentMode = item.getCurrentMode(stack) + currentMode.keyBinds.forEach { + val bind = toolGunBindList[it] ?: return@forEach + if(player.isHolding(item) && event.button == bind.key.value + && event.action == InputConstants.PRESS) { + NETWORK.sendToServer(ToolGunPacket(false, it)) + println("firing action") + currentMode.mode.action(level, player, stack, it) + } + } + } + } + + @SubscribeEvent + fun playerTick(event: TickEvent.ClientTickEvent) { + val instance = Minecraft.getInstance() + val player = instance.player ?: return + val level = instance.level ?: return + val stack = player.mainHandItem + val item = stack.item + + if(item is ToolGunItem) { + val currentMode = item.getCurrentMode(stack) + if(player.isHolding(item)) { + currentMode.mode.open(level, player, stack, null) + } else { + currentMode.mode.close(level, player, stack, null) + } + } + } + +// @SubscribeEvent +// fun clientTick(event: TickEvent.ClientTickEvent) { +// if(event.phase != TickEvent.Phase.END) return +// +// val instance = Minecraft.getInstance() +// val level = instance.level ?: return +// val player = instance.player ?: return +// val stack = player.mainHandItem +// val item = stack.item +// +// if(item is ToolGunItem && player.isHolding(stack.item)) { +// val currentMode = item.getCurrentMode(stack) +// if(level.isClientSide) { +// if(!player.isHolding(item)) currentMode.mode.close(level, player, stack, null) +// else { +// if(ToolGunItem.changeMode.consumeClick()) { +// NETWORK.sendToServer(ToolGunPacket(true)) +// player.playSound(SoundEvents.DISPENSER_FAIL, 1.0f, 1.0f) +// } else { +// currentMode.mode.open(level, player, stack, null) +// currentMode.keyBinds.forEach { +// val bind = toolGunBindList[it] +// if(bind != null && bind.consumeClick()) { +// NETWORK.sendToServer(ToolGunPacket(false, it)) +// currentMode.mode.action(level, player, stack, it) +// } +// } +// } +// } +// } else { +// if(player.isHolding(item)) currentMode.mode.open(level, player, stack, null) +// else currentMode.mode.close(level, player, stack, null) +// } +// } +// } + // @Suppress("UNUSED_PARAMETER") // @SubscribeEvent // fun onTick(event: TickEvent.ClientTickEvent) { diff --git a/src/main/kotlin/breadmod/ClientModEventBus.kt b/src/main/kotlin/breadmod/ClientModEventBus.kt index cff944ff..cc2c2390 100644 --- a/src/main/kotlin/breadmod/ClientModEventBus.kt +++ b/src/main/kotlin/breadmod/ClientModEventBus.kt @@ -1,5 +1,6 @@ package breadmod +import breadmod.ClientForgeEventBus.changeMode import breadmod.ModMain.ID import breadmod.ModMain.modLocation import breadmod.client.render.SidedScreenRenderer @@ -12,13 +13,12 @@ import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_ import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Control import breadmod.client.render.entity.BreadBulletEntityRenderer import breadmod.client.render.entity.PrimedHappyBlockRenderer -import breadmod.client.hud.ToolGunOverlay +import breadmod.client.gui.ToolGunOverlay import breadmod.client.render.ToasterRenderer import breadmod.item.armor.BreadArmorItem import breadmod.item.armor.ArmorColor import breadmod.client.screen.CertificateItemScreen import breadmod.client.screen.tool_gun.ToolGunCreatorScreen -import breadmod.item.tool_gun.ToolGunItem.Companion.changeMode import breadmod.registry.block.ModBlockEntityTypes import breadmod.registry.entity.ModEntityTypes.BREAD_BULLET_ENTITY import breadmod.registry.entity.ModEntityTypes.HAPPY_BLOCK_ENTITY diff --git a/src/main/kotlin/breadmod/client/hud/AbstractModGuiOverlay.kt b/src/main/kotlin/breadmod/client/gui/AbstractModGuiOverlay.kt similarity index 95% rename from src/main/kotlin/breadmod/client/hud/AbstractModGuiOverlay.kt rename to src/main/kotlin/breadmod/client/gui/AbstractModGuiOverlay.kt index cc0680fc..402f05dd 100644 --- a/src/main/kotlin/breadmod/client/hud/AbstractModGuiOverlay.kt +++ b/src/main/kotlin/breadmod/client/gui/AbstractModGuiOverlay.kt @@ -1,5 +1,6 @@ -package breadmod.client.hud +package breadmod.client.gui +import breadmod.util.render.scaleFlat import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.client.Minecraft import net.minecraft.client.gui.GuiGraphics @@ -46,8 +47,6 @@ abstract class AbstractModGuiOverlay: IGuiOverlay { pPlayer: LocalPlayer ) - fun PoseStack.scaleFlat(scale: Float) = this.scale(scale, scale, scale) - fun drawScaledText( pText: Component, pPose: PoseStack, diff --git a/src/main/kotlin/breadmod/client/hud/ToolGunOverlay.kt b/src/main/kotlin/breadmod/client/gui/ToolGunOverlay.kt similarity index 98% rename from src/main/kotlin/breadmod/client/hud/ToolGunOverlay.kt rename to src/main/kotlin/breadmod/client/gui/ToolGunOverlay.kt index 7e7634cd..4305b993 100644 --- a/src/main/kotlin/breadmod/client/hud/ToolGunOverlay.kt +++ b/src/main/kotlin/breadmod/client/gui/ToolGunOverlay.kt @@ -1,4 +1,4 @@ -package breadmod.client.hud +package breadmod.client.gui import breadmod.ClientModEventBus.toolGunBindList import breadmod.ModMain.modLocation @@ -7,6 +7,7 @@ import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_ import breadmod.datagen.tool_gun.ModToolGunModeDataLoader import breadmod.item.tool_gun.ToolGunItem import breadmod.item.tool_gun.ToolGunItem.Companion.MODE_NAMESPACE_TAG +import breadmod.util.render.scaleFlat import com.mojang.blaze3d.platform.InputConstants import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.ChatFormatting diff --git a/src/main/kotlin/breadmod/client/gui/components/ScaledAbstractButton.kt b/src/main/kotlin/breadmod/client/gui/components/ScaledAbstractButton.kt new file mode 100644 index 00000000..35426341 --- /dev/null +++ b/src/main/kotlin/breadmod/client/gui/components/ScaledAbstractButton.kt @@ -0,0 +1,71 @@ +package breadmod.client.gui.components + +import breadmod.util.render.scaleFlat +import com.mojang.blaze3d.systems.RenderSystem +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.Font +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.components.AbstractButton +import net.minecraft.client.gui.narration.NarrationElementOutput +import net.minecraft.network.chat.Component +import java.awt.Color + +/** A scalable button widget. + * ### Note: text currently does not support scrolling */ +abstract class ScaledAbstractButton( + private val pX: Int, + private val pY: Int, + private val pWidth: Int, + private val pHeight: Int, + private val pScale: Double, + private val pMessage: Component +) : AbstractButton(pX, pY, pWidth, pHeight, pMessage) { + val font: Font = Minecraft.getInstance().font + + // todo look into converting clicked, isMouseOver, and renderWidget into using doubles for their positioning instead of using the superclass positioning + // todo look into implementing OnPress from Button.java (might not be possible) + + override fun updateWidgetNarration(pNarrationElementOutput: NarrationElementOutput) {} + + override fun renderWidget(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { + val poseStack = pGuiGraphics.pose() + pGuiGraphics.setColor(1.0f, 1.0f, 1.0f, alpha) + RenderSystem.enableBlend() + RenderSystem.enableDepthTest() + poseStack.pushPose() + poseStack.translate(pX.toDouble(), pY.toDouble(), 0.0) + poseStack.scaleFlat(pScale.toFloat()) + pGuiGraphics.blitNineSliced(WIDGETS_LOCATION, 0, 0, pWidth, pHeight, + 20, 4, 200, 20, 0, textureY + ) +// renderString(pGuiGraphics, font, fgColor or (Mth.ceil(this.alpha * 255.0f) shl 24)) + // todo re-implementation of scrolling string that supports scaling. +// AbstractWidget.renderScrollingString(pGuiGraphics, font, pMessage, 0, 0, pWidth, pHeight, Color.WHITE.rgb) + pGuiGraphics.drawString(font, pMessage, 2, 1, Color.WHITE.rgb, true) + poseStack.popPose() + } + + override fun renderScrollingString(pGuiGraphics: GuiGraphics, pFont: Font, pWidth: Int, pColor: Int) { + super.renderScrollingString(pGuiGraphics, pFont, pWidth, pColor) + } + + override fun render(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { + if(visible) { + isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + (width * pScale) && pMouseY < y + (height * pScale) + renderWidget(pGuiGraphics, pMouseX, pMouseY, pPartialTick) + updateTooltip() + } + } + + // the hitbox for the widget + override fun clicked(pMouseX: Double, pMouseY: Double): Boolean = + active && visible && pMouseX >= x && pMouseY >= y && + pMouseX < x + (width * pScale) && pMouseY < y + (height * pScale) + + // controls the "hover" graphic when mouse is over widget + override fun isMouseOver(pMouseX: Double, pMouseY: Double): Boolean = + active && visible && pMouseX >= x && pMouseY >= y && + pMouseX < x + (width * pScale) && pMouseY < y + (height * pScale) + + override fun isFocused(): Boolean = isHovered +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/client/gui/components/ScaledAbstractWidget.kt b/src/main/kotlin/breadmod/client/gui/components/ScaledAbstractWidget.kt new file mode 100644 index 00000000..13ce83f2 --- /dev/null +++ b/src/main/kotlin/breadmod/client/gui/components/ScaledAbstractWidget.kt @@ -0,0 +1,39 @@ +package breadmod.client.gui.components + +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.components.AbstractWidget +import net.minecraft.client.gui.narration.NarrationElementOutput +import net.minecraft.network.chat.Component + +abstract class ScaledAbstractWidget( + pX: Int, + pY: Int, + pWidth: Int, + pHeight: Int, + private val pScale: Double, + pMessage: Component +) : AbstractWidget(pX, pY, pWidth, pHeight, pMessage) { + override fun updateWidgetNarration(pNarrationElementOutput: NarrationElementOutput) {} + + // todo look into converting clicked, isMouseOver, and renderWidget into using doubles for their positioning instead of using the superclass positioning + + override fun render(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { + if(visible) { + isHovered = pMouseX >= x && pMouseY >= y && pMouseX < x + (width * pScale) && pMouseY < y + (height * pScale) + renderWidget(pGuiGraphics, pMouseX, pMouseY, pPartialTick) + updateTooltip() + } + } + + // the hitbox for the widget + override fun clicked(pMouseX: Double, pMouseY: Double): Boolean = + active && visible && pMouseX >= x && pMouseY >= y && + pMouseX < x + (width * pScale) && pMouseY < y + (height * pScale) + + // controls the "hover" graphic when mouse is over widget + override fun isMouseOver(pMouseX: Double, pMouseY: Double): Boolean = + active && visible && pMouseX >= x && pMouseY >= y && + pMouseX < x + (width * pScale) && pMouseY < y + (height * pScale) + + override fun isFocused(): Boolean = isHovered +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/client/screen/tool_gun/ToolGunCreatorScreen.kt b/src/main/kotlin/breadmod/client/screen/tool_gun/ToolGunCreatorScreen.kt new file mode 100644 index 00000000..e706490b --- /dev/null +++ b/src/main/kotlin/breadmod/client/screen/tool_gun/ToolGunCreatorScreen.kt @@ -0,0 +1,663 @@ +package breadmod.client.screen.tool_gun + +import breadmod.ModMain.modLocation +import breadmod.ModMain.modTranslatable +import breadmod.client.gui.components.ScaledAbstractButton +import breadmod.client.gui.components.ScaledAbstractWidget +import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_DEF +import breadmod.item.tool_gun.mode.creator.* +import breadmod.menu.item.ToolGunCreatorMenu +import breadmod.network.PacketHandler +import breadmod.network.tool_gun.ToolGunCreatorDataPacket +import breadmod.util.render.scaleFlat +import com.google.gson.JsonObject +import com.mojang.blaze3d.systems.RenderSystem +import moze_intel.projecte.gameObjs.registries.PEItems +import net.minecraft.ChatFormatting +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.GuiGraphics +import net.minecraft.client.gui.components.* +import net.minecraft.client.gui.components.Button.CreateNarration +import net.minecraft.client.gui.narration.NarrationElementOutput +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen +import net.minecraft.client.gui.screens.inventory.InventoryScreen +import net.minecraft.client.renderer.GameRenderer +import net.minecraft.client.renderer.RenderType +import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.effect.MobEffect +import net.minecraft.world.effect.MobEffectInstance +import net.minecraft.world.effect.MobEffects +import net.minecraft.world.entity.EntityType +import net.minecraft.world.entity.LivingEntity +import net.minecraft.world.entity.ai.attributes.Attributes +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.level.Level +import net.minecraftforge.fml.loading.FMLPaths +import org.lwjgl.glfw.GLFW +import java.awt.Color +import java.nio.file.Files +import java.util.function.Consumer + +/** A horrifying amalgamation of many inner classes and one gui (will have proper docs soon... maybe) */ +class ToolGunCreatorScreen( + pMenu: ToolGunCreatorMenu, + pPlayerInventory: Inventory, + pTitle: Component +) : AbstractContainerScreen(pMenu, pPlayerInventory, pTitle) { + + companion object { + private val TEXTURE = modLocation("textures", "gui", "item", TOOL_GUN_DEF, "creator_mode.png") + private val TEXTURE_ASSETS = modLocation("textures", "gui", "item", TOOL_GUN_DEF, "creator_mode_assets.png") + private val ICONS = ResourceLocation("minecraft", "textures/gui/icons.png") + + private var customEntityName: String = "" + private var entityString: String = "zombie" + private var entityType: EntityType<*>? = getEntityFromString(entityString) + + private var entityHealth: Double = 20.0 + private var entitySpeed: Double = 5.0 + + // First Int: Duration, Second Int: Amplifier + private var entityEffects: MutableMap> = mutableMapOf( + "jump" to Triple(MobEffects.JUMP, 500, 2) + ) + + private var helmetSlot: ItemStack = Items.DIAMOND_HELMET.defaultInstance + private var chestplateSlot: ItemStack = Items.DIAMOND_CHESTPLATE.defaultInstance + private var leggingsSlot: ItemStack = Items.DIAMOND_LEGGINGS.defaultInstance + private var bootsSlot: ItemStack = Items.DIAMOND_BOOTS.defaultInstance + + private var mainHandSlot: ItemStack = PEItems.RED_MATTER_AXE.get().defaultInstance + private var offHandSlot: ItemStack = ItemStack.EMPTY + + /** holder for mob effects */ + val mobEffectInstanceMap: MutableMap> = mutableMapOf() + + /** holder for adding mob effect widgets */ + private var mobEffectString: String = "" + + /** Holder map to store an [AbstractWidget] linked to [SignType.MAIN] or [SignType.POTION] + * with a unique id + * */ + private val widgetMap: MutableMap>, AbstractWidget> = mutableMapOf() + + /** json data bridge for the creator mode renderer */ + var finalData: String = "" + + private var activeEditBox: EditBox? = null + private var currentTab: Enum = SignType.MAIN + private var entityScale = 32 + } + + private val instance: Minecraft = Minecraft.getInstance() + enum class SignType { MAIN, POTION, ADD, SUBTRACT } + private val entityX = 35 + private val entityY = 94 + + init { + imageWidth = 256 + imageHeight = 220 + + // set the entity type on gui init + entityType = getEntityFromString(entityString) + entityScale = 32 + } + + private var staticAlpha = 1.0f + // todo set this up for a fading static texture + private fun alphaTick() = if (staticAlpha > 0f) staticAlpha -= 0.01f else staticAlpha = 1f + + private fun constructEntity(pLevel: Level): LivingEntity { + val finalEntity = entityType?.create(pLevel) as LivingEntity + + // Health + finalEntity.getAttribute(Attributes.MAX_HEALTH)?.baseValue = entityHealth + finalEntity.health = entityHealth.toFloat() + + // Speed + finalEntity.getAttribute(Attributes.MOVEMENT_SPEED)?.baseValue = entitySpeed + finalEntity.speed = entitySpeed.toFloat() + + // Armor Slots + finalEntity.getSlot(HELMET_SLOT).set(helmetSlot) + finalEntity.getSlot(CHESTPLATE_SLOT).set(chestplateSlot) + finalEntity.getSlot(LEGGINGS_SLOT).set(leggingsSlot) + finalEntity.getSlot(BOOTS_SLOT).set(bootsSlot) + + // Item Slots + finalEntity.getSlot(MAINHAND_SLOT).set(mainHandSlot) + finalEntity.getSlot(OFFHAND_SLOT).set(offHandSlot) + + // Potion Effects + entityEffects.forEach { (_, value) -> + finalEntity.addEffect(MobEffectInstance(value.first, value.second, value.third)) + } + + if(customEntityName != "") { finalEntity.customName = Component.literal(customEntityName) } + + return finalEntity + } + + private fun matchEntityTypeToString(): Boolean { + val level = instance.level ?: return false + val entity = constructEntity(level) + val formattedName = entity.name.string.lowercase().replace(' ', '_') +// return entity.name.string == entityString + return formattedName == entityString + } + + /** + * [pX] and [pY] start at the top left of the gui, [pColor] defaults to White + */ + private fun GuiGraphics.drawText(pText: String, pX: Int, pY: Int, pColor: Int = Color.WHITE.rgb, pDropShadow: Boolean = false) = + drawString(font, Component.literal(pText), pX, pY, pColor, pDropShadow) + private fun GuiGraphics.drawText(pText: Component, pX: Int, pY: Int, pColor: Int = Color.WHITE.rgb, pDropShadow: Boolean = false) = + drawString(font, pText, pX, pY, pColor, pDropShadow) + + // todo revamp for save/load system + private fun setPath(path: String) = FMLPaths.GAMEDIR.get().resolve(path).toAbsolutePath() + private fun createPathAndFile() { + if(!Files.exists(setPath("breadmod/tool_gun"))) { + println("directory does not exist, creating") + Files.createDirectories(setPath("breadmod/tool_gun")) + } + val path = setPath("breadmod/tool_gun") + val data = finalData.encodeToByteArray() + if(!Files.exists(setPath("breadmod/tool_gun/mob.json"))) { + println("writing file") + Files.write(setPath("breadmod/tool_gun/mob.json"), data) + } + + println(path.toString()) + } + + override fun render(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { + val poseStack = pGuiGraphics.pose() + poseStack.pushPose() + poseStack.translate(0.0, 0.0, -130.0) + renderBackground(pGuiGraphics) + poseStack.translate(0.0, 0.0, 130.0) + poseStack.popPose() + + renderTooltip(pGuiGraphics, pMouseX, pMouseY) + + super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick) + } + + // render >> renderBg + override fun renderBg(pGuiGraphics: GuiGraphics, pPartialTick: Float, pMouseX: Int, pMouseY: Int) { + val level = instance.level ?: return + val entity = constructEntity(level) + val formattedName = entity.name.copy().string.lowercase().replace(' ', '_') + + // Setup gui rendering + RenderSystem.setShader { GameRenderer.getRendertypeTranslucentShader() } + RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, staticAlpha) + RenderSystem.setShaderTexture(0, TEXTURE) + + if(currentTab == SignType.MAIN) { + pGuiGraphics.blit(TEXTURE_ASSETS, leftPos + 14, topPos + 24, 0, 0, 42, 75) + InventoryScreen.renderEntityInInventoryFollowsMouse( + pGuiGraphics, leftPos + entityX, topPos + entityY, entityScale, + (leftPos + entityX) - pMouseX.toFloat(), + (topPos + entityY - 50) - pMouseY.toFloat(), + entity + ) + pGuiGraphics.pose().translate(0.0, 0.0, 130.0) + pGuiGraphics.drawCenteredString( + font, + if(matchEntityTypeToString()) Component.translatable(entity.name.copy().string) + .withStyle(if(matchEntityTypeToString()) ChatFormatting.GOLD else ChatFormatting.RED) else + modTranslatable(TOOL_GUN_DEF,"creator", "invalid_entity", + args = listOf(entityString, formattedName) + ).withStyle(if(matchEntityTypeToString()) ChatFormatting.GOLD else ChatFormatting.RED), + leftPos + 35, topPos + 14, + Color.WHITE.rgb + ) + } else if(currentTab == SignType.POTION) { + // todo Gui.java@448 (code that will be immensely useful in rendering mob effect icons) + } + + pGuiGraphics.blit(TEXTURE, leftPos, topPos, 0, 0, imageWidth, imageHeight) + } + + override fun renderLabels(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int) { + pGuiGraphics.drawText(title, 2, 2) + pGuiGraphics.drawText(playerInventoryTitle, 2, 132) + pGuiGraphics.drawText(modTranslatable(TOOL_GUN_DEF, "creator", "save_load"), 167, 132) + } + + // todo this needs to be changed to allow for dynamic potion effect edit boxes. + // todo create confirmation button to apply value to whatever is in the responder parameter + private fun createEditBox( + pX: Int, + pY: Int, + pWidth: Int, + pHeight: Int, + pair: Pair>, + defaultValue: String, + responder: Consumer + ): EditBox { + val editBox = CustomEditBox(pX, pY, pWidth, pHeight) + editBox.setCanLoseFocus(true) + editBox.setMaxLength(50) + editBox.value = if(defaultValue != "") defaultValue else "" + editBox.setResponder(responder) + addToWidgetMap(pair, editBox) + return editBox + } + + private fun threeStageValueButtons( + pair: Pair>, + pX: Int, pY: Int, + mathType: Enum + ) { + when(mathType) { + SignType.ADD -> { + addToWidgetMap("${pair.first}_plus_one" to pair.second, + ValueModifierButton(pX, pY, 10, 10, 0.8, "+", pair.first, 1.0)) + addToWidgetMap("${pair.first}_plus_ten" to pair.second, + ValueModifierButton(pX + 8, pY, 16, 10, 0.8, "++", pair.first, 10.0)) + addToWidgetMap("${pair.first}_plus_hundred" to pair.second, + ValueModifierButton(pX + 2, pY + 8, 21, 10, 0.8, "+++", pair.first, 100.0)) + } + SignType.SUBTRACT -> { + addToWidgetMap("${pair.first}_minus_one" to pair.second, + ValueModifierButton(pX, pY, 10, 10, 0.8, "-", pair.first, -1.0)) + addToWidgetMap("${pair.first}_minus_ten" to pair.second, + ValueModifierButton(pX + 8, pY, 16, 10, 0.8, "--", pair.first, -10.0)) + addToWidgetMap("${pair.first}_minus_hundred" to pair.second, + ValueModifierButton(pX + 2, pY + 8, 21, 10, 0.8, "---", pair.first, -100.0)) + } + } + } + + private fun addToWidgetMap(pair: Pair>, widget: AbstractWidget) { + widgetMap[pair] = widget + } + private fun removeFromWidgetMap(pair: Pair>) { + widgetMap.remove(pair).also { + if (it != null) { + removeWidget(it) + it.visible = false + } + } + } + + /** Only called during gui init and adding potion effects. + * Existing widgets are simply overridden when this function is called again. */ + private fun initWidgetMap() { + println("initializing widgetMap") + // make sure to flush duplicate renderable entries in the list after adding potion effect widgets + clearWidgets() + widgetMap.forEach { (key, value) -> + if(value is MobEffectGuiElement || value is ValueModifierButtonsWithGui) { + addRenderableOnly(value) + } else addRenderableWidget(value) + if(currentTab == SignType.POTION && key.second != SignType.POTION) { + value.visible = false + } else if(currentTab == SignType.MAIN && key.second != SignType.MAIN) { + value.visible = false + } +// println("key: $key, value: $value") + } + } + + override fun init() { + super.init() + // Main tab // + + createEditBox( + leftPos + 100, topPos + 100, 100, 15, + "mob_selector" to SignType.MAIN, entityString + ) { string -> + entityString = string.lowercase().replace(' ', '_') + entityType = getEntityFromString(entityString) + matchEntityTypeToString() +// println(entityString) + } + + addToWidgetMap("potion_tab_button" to SignType.MAIN, + GenericButton(leftPos + 175, topPos, 80, 10, Component.literal("Potion Effects")) { + currentTab = SignType.POTION + widgetMap.forEach { (key, value) -> + value.visible = currentTab == SignType.POTION && key.second == SignType.POTION + } + println(currentTab) + }) + + addToWidgetMap("funny_button" to SignType.MAIN, + FunnyButton(leftPos + 200, topPos + 80, 20, 20, + 0, 0, 20, 20, + modLocation("textures", "block", "fish.gif"))) + + // Fire entity to server-side + addToWidgetMap("json_button" to SignType.MAIN, + JsonButton(leftPos + 169, topPos + 205, 82, 10, + Component.literal("send to server")) + ) + + + // Entity Scale + threeStageValueButtons("scale" to SignType.MAIN, leftPos + 5, topPos + 100, SignType.ADD) + threeStageValueButtons("scale" to SignType.MAIN, leftPos + 38, topPos + 100, SignType.SUBTRACT) + + // Health modifier + ValueModifierButtonsWithGui("health" to SignType.MAIN, leftPos + 72, topPos + 12, 1.0) + + // Potion Effects Tab // + + // Main tab button + addToWidgetMap("main_tab_button" to SignType.POTION, + GenericButton(leftPos + 130, topPos, 30, 10, Component.literal("Main")) { + currentTab = SignType.MAIN + widgetMap.forEach { (key, value) -> + value.visible = currentTab == SignType.MAIN && key.second == SignType.MAIN + } +// println(currentTab) + }) + + // Add potion effect widget from edit box +// addToWidgetMap("add_mob_effect" to SignType.POTION, +// GenericButton(leftPos + 150, topPos + 20, 80, 10, Component.literal("add effect")) { +// if(mobEffectFromString(id = mobEffectString) != null) { +// println(mobEffectFromString(id = mobEffectString)) +// MobEffectGuiElement(mobEffectString to SignType.POTION, leftPos + 20, topPos + 30) +// } else { +// println("mob effect is null!") +// } +// mobEffectString = "" +// }) + + addToWidgetMap("add_mob_effect" to SignType.POTION, + GenericButton(leftPos + 150, topPos + 40, 80, 10, Component.literal("add effect")) { + if(mobEffectFromString(id = mobEffectString) != null) { + println(mobEffectFromString(id = mobEffectString)) + MobEffectGuiElement(mobEffectString to SignType.POTION, leftPos + 20, topPos + 30) + } else { + println("mob effect is null!") + } + mobEffectString = "" + }) + + // Potion effect adder box + createEditBox( + leftPos + 50, topPos + 10, 100, 15, + "mob_effect_edit_box" to SignType.POTION, "" + ) { string -> + mobEffectString = string.lowercase().replace(' ', '_') +// println(potionEffectString) + } + +// widgetMap["health" to SignType.MAIN] = +// ValueModifierButton.ValueModifierButtonsWithGui("health" to SignType.MAIN, 20, 10) + +// widgetMap["test" to SignType.POTION] = PotionEffectGuiElement(50, 50) + +// renderableMap.forEach { (key, value) -> +// addRenderableOnly(value) +// if(key.second == SignType.POTION) value.visible = false +// } + +// PotionEffectGuiElement("potion_test" to SignType.POTION, leftPos + 10, topPos + 30) + + initWidgetMap() + } + + override fun keyPressed(pKeyCode: Int, pScanCode: Int, pModifiers: Int): Boolean { + val box = activeEditBox ?: return super.keyPressed(pKeyCode, pScanCode, pModifiers) + if (pKeyCode == GLFW.GLFW_KEY_ESCAPE && shouldCloseOnEsc()) { + instance.player?.closeContainer() + } + + return !box.keyPressed(pKeyCode, pScanCode, pModifiers) && + if(!box.canConsumeInput()) super.keyPressed(pKeyCode, pScanCode, pModifiers) else true + } + + // todo could be turned into a gui dragging system? (strong maybe) + override fun mouseDragged(pMouseX: Double, pMouseY: Double, pButton: Int, pDragX: Double, pDragY: Double): Boolean { +// println("mouse dragging: X:$pMouseX, y:$pMouseY") + return super.mouseDragged(pMouseX, pMouseY, pButton, pDragX, pDragY) + } + + override fun shouldCloseOnEsc(): Boolean { + val box = activeEditBox ?: return super.shouldCloseOnEsc() + return !box.canConsumeInput() + } + + override fun containerTick() { + super.containerTick() + widgetMap.forEach { (_, value) -> + if(value is EditBox) value.tick() + } + } + + override fun onClose() { +// widgetMap.clear() + activeEditBox = null + super.onClose() + } + + // Custom widget classes past here + + // todo custom texture and scale + inner class CustomEditBox( + pX: Int, pY: Int, pWidth: Int, pHeight: Int + ): EditBox(instance.font, pX, pY, pWidth, pHeight, Component.literal("A TEXT BOX")) { + + override fun tick() { + super.tick() + if(this.isFocused) { + activeEditBox = this + } else return + } + + override fun keyPressed(pKeyCode: Int, pScanCode: Int, pModifiers: Int): Boolean { + if((pKeyCode == GLFW.GLFW_KEY_ENTER || pKeyCode == GLFW.GLFW_KEY_ESCAPE) && canConsumeInput()) { + this.isFocused = false + } + return super.keyPressed(pKeyCode, pScanCode, pModifiers) + } + } + + // todo replace with direct call to ImageButton + // todo custom button scale and textures + inner class FunnyButton( + pX: Int, + pY: Int, + pWidth: Int, + pHeight: Int, + pXTexStart: Int, + pYTexStart: Int, + pTextureWidth: Int, + pTextureHeight: Int, + pResourceLocation: ResourceLocation + ): ImageButton( + pX, pY, + pWidth, pHeight, + pXTexStart, pYTexStart, + 0, + pResourceLocation, pTextureWidth, pTextureHeight, + { createPathAndFile() } + ) + + // todo convert to be scalable using ScaledAbstractButton or ScaledButton (wip) + inner class GenericButton( + pX: Int, + pY: Int, + pWidth: Int, + pHeight: Int, + pText: Component, + onPress: OnPress + ): Button(pX, pY, pWidth, pHeight, pText, onPress, CreateNarration { it.get() }) + + // todo add parameters for automatically adding resize widgets and adding onto a future potion effects map + // todo rebuilding potion widgets from entityEffects after removing another potion widget + + // todo automatically adding valid mob effect to mobEffectInstanceMap with mob effect name as id + // todo setting text color to mob effect color + // todo render calls for rendering the mob effect and bg of that effect instance (Gui.java@448) + // todo automatically adding created effect instance into entityEffect with a system in place for not allowing more than one instance of a potion effect + // todo show null error if entered mob effect doesn't exist + // todo add and remove buttons for deleting the mob effect instance (along with removing that instance from entityEffect) + // todo convert to using scaling + + inner class MobEffectGuiElement( + private val pair: Pair>, + private val pX: Int, + private val pY: Int + ): AbstractWidget(pX, pY, 300, 50, Component.empty()) { + override fun updateWidgetNarration(pNarrationElementOutput: NarrationElementOutput) {} + override fun renderWidget(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { + if(visible) { + pGuiGraphics.fill(RenderType.endPortal(), pX, pY, pX + 100, pY + 50, Color.RED.rgb) + pGuiGraphics.drawText(pair.first, pX + 30, pY + 5, Color.RED.rgb) + } + } + + // todo work on logic to remove this and any child widget matching pair.first + private fun removeThisWidget(pair: Pair>) { +// widgetMap.forEach { (key, value) -> // todo throws ConcurrentModificationException +// if(pair.first in key.first) { +// println("key: $key, value: $value") +// widgetMap.remove(pair.first to pair.second) +// removeWidget(value) +// } +// } + removeFromWidgetMap(pair) + removeFromWidgetMap("${pair.first}_plus_one" to pair.second) + removeFromWidgetMap("${pair.first}_plus_ten" to pair.second) + removeFromWidgetMap("${pair.first}_plus_hundred" to pair.second) + removeFromWidgetMap("${pair.first}_minus_one" to pair.second) + removeFromWidgetMap("${pair.first}_minus_ten" to pair.second) + removeFromWidgetMap("${pair.first}_minus_hundred" to pair.second) + removeFromWidgetMap("${pair.first}_remove" to pair.second) + } + + init { + addToWidgetMap(pair, this) + threeStageValueButtons(pair, pX, pY, SignType.ADD) + threeStageValueButtons(pair, pX + 100, pY, SignType.SUBTRACT) + // todo convert to ScaledButton + addToWidgetMap("${pair.first}_remove" to pair.second, + GenericButton(pX, pY + 30, 20, 10, Component.literal("remove")) { + println("removing ${pair.first}") + removeThisWidget(pair) + }) + initWidgetMap() + } + } + + // todo custom button scale and textures + inner class JsonButton( + pX: Int, + pY: Int, + pWidth: Int, + pHeight: Int, + pText: Component + ): AbstractButton(pX, pY, pWidth, pHeight, pText) { +// private val gson = Gson() + + private fun writeJson(): JsonObject = JsonObject().also { +// it.addProperty("entity", ForgeRegistries.ENTITY_TYPES.getKey(entityType).toString()) + it.addProperty("entity", entityString) + if(customEntityName != "") { it.addProperty("custom_entity_name", customEntityName) } + it.addProperty("entity_health", entityHealth) + it.addProperty("entity_speed", entitySpeed) + it.add("effects", JsonObject().also { effectObject -> + entityEffects.forEach { (_, value) -> + effectObject.add(effectToString(value.first), JsonObject().also { currentEffect -> + currentEffect.addProperty("duration", value.second) + currentEffect.addProperty("amplifier", value.third) + }) + } + }) + it.addProperty("helmet", itemToString(helmetSlot.item)) + it.addProperty("chestplate", itemToString(chestplateSlot.item)) + it.addProperty("leggings", itemToString(leggingsSlot.item)) + it.addProperty("boots", itemToString(bootsSlot.item)) + it.addProperty("main_hand", itemToString(mainHandSlot.item)) + it.addProperty("off_hand", itemToString(offHandSlot.item)) + } + + override fun updateWidgetNarration(pNarrationElementOutput: NarrationElementOutput) {} + + override fun onPress() { + val json = writeJson() + + println("firing string to server") + println(json.toString()) + finalData = json.toString() + PacketHandler.NETWORK.sendToServer(ToolGunCreatorDataPacket(json.toString())) + + // todo this stuff below needs to be converted into a save/load system for storing on the player's computer +// val jsonByteArray = json.toString().encodeToByteArray() +// +// val filePath: Path +// if(!Files.exists(FMLPaths.GAMEDIR.get().resolve("breadmod/tool_gun/mob.json").toAbsolutePath())) { +// Files.write(FMLPaths.GAMEDIR.get().resolve("breadmod/tool_gun/mob.json").toAbsolutePath(), jsonByteArray) +// println("wrote json file to path") +// return +// } else filePath = FMLPaths.GAMEDIR.get().resolve("breadmod/tool_gun/mob.json").toAbsolutePath() +// +// val jsonReader = JsonReader(FileReader(filePath.toFile())) +// val jsonData: JsonObject = gson.fromJson(jsonReader, JsonObject::class.java) + } + } + + // todo custom button scale (DONE) and textures (TODO) + inner class ValueModifierButton( + pX: Int, + pY: Int, + pWidth: Int, + pHeight: Int, + pScale: Double, + pText: String, + private val pType: String, + private val pValue: Double + ): ScaledAbstractButton(pX, pY, pWidth, pHeight, pScale, Component.literal(pText)) { + override fun onPress() { + when(pType) { + "health" -> entityHealth += pValue + "speed" -> entitySpeed += pValue + "scale" -> entityScale += pValue.toInt() + } + } + } + + /** Constructs a widget with 6 add/subtract buttons with a texture to signify what value it changes. + * Automatically adds itself to [widgetMap] + */ + inner class ValueModifierButtonsWithGui( + pair: Pair>, + private val pX: Int, + private val pY: Int, + private val pScale: Double + ): ScaledAbstractWidget(pX, pY, 80, 25, pScale, Component.empty()) { + override fun renderWidget(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { + val poseStack = pGuiGraphics.pose() + poseStack.pushPose() + poseStack.translate(pX.toDouble(), pY.toDouble(), 0.0) + poseStack.scaleFlat(pScale.toFloat()) + pGuiGraphics.fill(RenderType.gui(), 0, 0, width, height, Color(26, 26, 26).rgb) + pGuiGraphics.fill(RenderType.gui(), 1, 1, width - 1, height - 1, Color(51, 51, 51).rgb) + poseStack.scaleFlat(pScale.toFloat() - 0.4f) + pGuiGraphics.drawCenteredString(font, entityHealth.toString(), 66, 28, Color.WHITE.rgb) + poseStack.scaleFlat(pScale.toFloat() + 4f) + poseStack.translate(0.8, -0.2, 0.0) + // todo parameters for choosing icons + pGuiGraphics.blit(ICONS, 8, 0, 52, 0, 9, 9) + poseStack.popPose() + // 52, 0, 61, 9 + } + + init { + addToWidgetMap(pair, this) + threeStageValueButtons(pair, pX + 2, pY + 4, SignType.ADD) + threeStageValueButtons(pair, pX + 57, pY + 4, SignType.SUBTRACT) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/client/screen/tool_gun/creator/PotionEffectGuiElement.kt b/src/main/kotlin/breadmod/client/screen/tool_gun/creator/PotionEffectGuiElement.kt deleted file mode 100644 index 242059ca..00000000 --- a/src/main/kotlin/breadmod/client/screen/tool_gun/creator/PotionEffectGuiElement.kt +++ /dev/null @@ -1,23 +0,0 @@ -package breadmod.client.screen.tool_gun.creator - -import net.minecraft.client.gui.GuiGraphics -import net.minecraft.client.gui.components.Renderable -import net.minecraft.client.renderer.RenderType -import java.awt.Color - -// todo add parameters for automatically adding resize widgets and adding onto a future potion effects map -// todo add and remove buttons for deleting the potion effect instance (along with removing that instance from entityEffect) -// todo render calls for rendering the mob effect and bg of that effect instance (Gui.java@448) -// todo automatically adding created effect instance into entityEffect with a system in place for not allowing more than one instance of a potion effect - -class PotionEffectGuiElement(private val pX: Int, private val pY: Int): Renderable { - var visible = true - - fun isVisible(): Boolean = visible - - override fun render(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - if(isVisible()) { - pGuiGraphics.fill(RenderType.endPortal(), pX, pY, pX + 100, pY + 50, Color.RED.rgb) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/client/screen/tool_gun/creator/ToolGunCreatorScreen.kt b/src/main/kotlin/breadmod/client/screen/tool_gun/creator/ToolGunCreatorScreen.kt deleted file mode 100644 index 94b39100..00000000 --- a/src/main/kotlin/breadmod/client/screen/tool_gun/creator/ToolGunCreatorScreen.kt +++ /dev/null @@ -1,467 +0,0 @@ -package breadmod.client.screen.tool_gun.creator - -import breadmod.ModMain.modLocation -import breadmod.ModMain.modTranslatable -import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_DEF -import breadmod.item.tool_gun.mode.creator.* -import breadmod.menu.item.ToolGunCreatorMenu -import breadmod.network.PacketHandler -import breadmod.network.tool_gun.ToolGunCreatorDataPacket -import com.google.gson.JsonObject -import com.mojang.blaze3d.systems.RenderSystem -import moze_intel.projecte.gameObjs.registries.PEItems -import net.minecraft.ChatFormatting -import net.minecraft.client.Minecraft -import net.minecraft.client.gui.GuiGraphics -import net.minecraft.client.gui.components.AbstractButton -import net.minecraft.client.gui.components.AbstractWidget -import net.minecraft.client.gui.components.Button -import net.minecraft.client.gui.components.EditBox -import net.minecraft.client.gui.components.ImageButton -import net.minecraft.client.gui.components.Renderable -import net.minecraft.client.gui.narration.NarrationElementOutput -import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen -import net.minecraft.client.gui.screens.inventory.InventoryScreen -import net.minecraft.client.renderer.GameRenderer -import net.minecraft.client.renderer.RenderType -import net.minecraft.network.chat.Component -import net.minecraft.resources.ResourceLocation -import net.minecraft.world.effect.MobEffect -import net.minecraft.world.effect.MobEffectInstance -import net.minecraft.world.effect.MobEffects -import net.minecraft.world.entity.EntityType -import net.minecraft.world.entity.LivingEntity -import net.minecraft.world.entity.ai.attributes.Attributes -import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items -import net.minecraft.world.level.Level -import net.minecraftforge.fml.loading.FMLPaths -import org.lwjgl.glfw.GLFW -import java.awt.Color -import java.nio.file.Files -import java.util.function.Consumer - -/** probably the most mind-numbing class I've ever written, and it's still a work in progress... - * @author chris - * */ - -class ToolGunCreatorScreen( - pMenu: ToolGunCreatorMenu, - pPlayerInventory: Inventory, - pTitle: Component -) : AbstractContainerScreen(pMenu, pPlayerInventory, pTitle) { - companion object { - private val TEXTURE = modLocation("textures", "gui", "item", TOOL_GUN_DEF, "creator_mode.png") - private val TEXTURE_ASSETS = modLocation("textures", "gui", "item", TOOL_GUN_DEF, "creator_mode_assets.png") - private val ICONS = ResourceLocation("minecraft", "textures/gui/icons.png") - - private val instance: Minecraft = Minecraft.getInstance() - - private var customEntityName: String = "" - private var entityString: String = "zombie" - private var entityType: EntityType<*>? = getEntityFromString(entityString) - - private var entityHealth: Double = 20.0 - private var entitySpeed: Double = 5.0 - - // First Int: Duration, Second Int: Amplifier - private var entityEffect: MutableList> = mutableListOf( - Triple(MobEffects.HARM, 1000, 10), - Triple(MobEffects.JUMP, 500, 2) - ) - - private var helmetSlot: ItemStack = Items.DIAMOND_HELMET.defaultInstance - private var chestplateSlot: ItemStack = Items.DIAMOND_CHESTPLATE.defaultInstance - private var leggingsSlot: ItemStack = Items.DIAMOND_LEGGINGS.defaultInstance - private var bootsSlot: ItemStack = Items.DIAMOND_BOOTS.defaultInstance - - private var mainHandSlot: ItemStack = PEItems.RED_MATTER_AXE.get().defaultInstance - private var offHandSlot: ItemStack = ItemStack.EMPTY - - private val potionEffectInstanceMap: Nothing = TODO("set up map for holding potion effect instances" + - " (the mob effect, duration, amplifier, tab, and system in place for not allowing more than one instance of a potion effect") - - var finalData: String = "" - - // todo revamp for save/load system - private fun setPath(path: String) = FMLPaths.GAMEDIR.get().resolve(path).toAbsolutePath() - fun createPathAndFile() { - if(!Files.exists(setPath("breadmod/tool_gun"))) { - println("directory does not exist, creating") - Files.createDirectories(setPath("breadmod/tool_gun")) - } - val path = setPath("breadmod/tool_gun") - val data = finalData.encodeToByteArray() - if(!Files.exists(setPath("breadmod/tool_gun/mob.json"))) { - println("writing file") - Files.write(setPath("breadmod/tool_gun/mob.json"), data) - } - - println(path.toString()) - } - } - - /** ## It's short for ToolGunCreatorTabs. */ - private enum class TGCTabs { MAIN, POTION } - private var currentTab: Enum = TGCTabs.MAIN - private val entityX = 35 - private val entityY = 94 - private var entityScale = 32 - - // todo this needs to be extended to support all widgets (AbstractWidget is probably good enough), and probably a separate map for holding potion effects - /** map to initialize widgets specific to certain tabs */ - private val widgetMap: MutableMap>, AbstractWidget> = mutableMapOf() - private var activeEditBox: EditBox? = null - - private val renderableMap: MutableMap>, PotionEffectGuiElement> = mutableMapOf() - - init { - imageWidth = 256 - imageHeight = 220 - - // set the entity type on gui init - entityType = getEntityFromString(entityString) - } - - private var alpha = 1.0f - // todo set this up for a fading static texture - private fun alphaTick() = if (alpha > 0f) alpha -= 0.01f else alpha = 1f - - private fun constructEntity(pLevel: Level): LivingEntity { - val finalEntity = entityType?.create(pLevel) as LivingEntity - - // Health - finalEntity.getAttribute(Attributes.MAX_HEALTH)?.baseValue = entityHealth - finalEntity.health = entityHealth.toFloat() - - // Speed - finalEntity.getAttribute(Attributes.MOVEMENT_SPEED)?.baseValue = entitySpeed - finalEntity.speed = entitySpeed.toFloat() - - // Armor Slots - finalEntity.getSlot(HELMET_SLOT).set(helmetSlot) - finalEntity.getSlot(CHESTPLATE_SLOT).set(chestplateSlot) - finalEntity.getSlot(LEGGINGS_SLOT).set(leggingsSlot) - finalEntity.getSlot(BOOTS_SLOT).set(bootsSlot) - - // Item Slots - finalEntity.getSlot(MAINHAND_SLOT).set(mainHandSlot) - finalEntity.getSlot(OFFHAND_SLOT).set(offHandSlot) - - // Potion Effects - entityEffect.forEach { (effect, duration, amplifier) -> - finalEntity.addEffect(MobEffectInstance(effect, duration, amplifier)) - } - - if(customEntityName != "") { finalEntity.customName = Component.literal(customEntityName) } - - return finalEntity - } - - /** - * [pX] and [pY] start at the top left of the gui, [pColor] defaults to White - */ - private fun GuiGraphics.drawText(pText: String, pX: Int, pY: Int, pColor: Int = Color.WHITE.rgb, pDropShadow: Boolean = false) = - drawString(font, Component.literal(pText), pX, pY, pColor, pDropShadow) - private fun GuiGraphics.drawText(pText: Component, pX: Int, pY: Int, pColor: Int = Color.WHITE.rgb, pDropShadow: Boolean = false) = - drawString(font, pText, pX, pY, pColor, pDropShadow) - - override fun render(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int, pPartialTick: Float) { - val poseStack = pGuiGraphics.pose() - poseStack.pushPose() - poseStack.translate(0.0, 0.0, -130.0) - renderBackground(pGuiGraphics) - poseStack.translate(0.0, 0.0, 130.0) - poseStack.popPose() - - renderTooltip(pGuiGraphics, pMouseX, pMouseY) - - super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick) - } - - // render >> renderBg - override fun renderBg(pGuiGraphics: GuiGraphics, pPartialTick: Float, pMouseX: Int, pMouseY: Int) { - val level = instance.level ?: return - val entity = constructEntity(level) - - // Setup gui rendering - RenderSystem.setShader { GameRenderer.getRendertypeTranslucentShader() } - RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, alpha) - RenderSystem.setShaderTexture(0, TEXTURE) - - if(currentTab == TGCTabs.MAIN) { - pGuiGraphics.blit(TEXTURE_ASSETS, leftPos + 14, topPos + 24, 0, 0, 42, 75) - InventoryScreen.renderEntityInInventoryFollowsMouse( - pGuiGraphics, leftPos + entityX, topPos + entityY, entityScale, - (leftPos + entityX) - pMouseX.toFloat(), - (topPos + entityY - 50) - pMouseY.toFloat(), - entity - ) - pGuiGraphics.pose().translate(0.0, 0.0, 130.0) - pGuiGraphics.drawString( - font, - Component.translatable(entity.name.copy().string) - .withStyle(ChatFormatting.GOLD), - leftPos + 13, topPos + 14, - Color.WHITE.rgb - ) - } else if(currentTab == TGCTabs.POTION) { - // todo Gui.java@448 (code that will be immensely useful in rendering mob effect icons) - } - - pGuiGraphics.blit(TEXTURE, leftPos, topPos, 0, 0, imageWidth, imageHeight) - } - - override fun renderLabels(pGuiGraphics: GuiGraphics, pMouseX: Int, pMouseY: Int) { - pGuiGraphics.drawText(title, 2, 2) - pGuiGraphics.drawText(playerInventoryTitle, 2, 132) - pGuiGraphics.drawText(modTranslatable("tool_gun", "creator", "save_load"), 167, 132) - } - - // todo this needs to be changed to allow for dynamic potion effect edit boxes. - // todo create confirmation button to apply value to whatever is in the responder parameter - private fun createEditBox( - pX: Int, - pY: Int, - pWidth: Int, - pHeight: Int, - tab: Enum, - name: String, - defaultValue: String, - responder: Consumer - ): EditBox { - val editBox = CustomEditBox(pX, pY, pWidth, pHeight) - editBox.setCanLoseFocus(true) - editBox.setMaxLength(50) - editBox.value = if(defaultValue != "") defaultValue else "" - editBox.setResponder(responder) - widgetMap[name to tab] = editBox - return editBox - } - - private inner class CustomEditBox( - pX: Int, pY: Int, pWidth: Int, pHeight: Int - ): EditBox(font, pX, pY, pWidth, pHeight, Component.literal("A TEXT BOX")) { - override fun tick() { - super.tick() - if(this.isFocused) { - activeEditBox = this - } else return - } - - override fun keyPressed(pKeyCode: Int, pScanCode: Int, pModifiers: Int): Boolean { - if((pKeyCode == GLFW.GLFW_KEY_ENTER || pKeyCode == GLFW.GLFW_KEY_ESCAPE) && canConsumeInput()) { - this.isFocused = false - } - return super.keyPressed(pKeyCode, pScanCode, pModifiers) - } - } - - private fun valueModifier() { - // todo graphics for modifying values (ex. health icon + buttons with box around it) - } - - private fun valueModifierButtons( - pair: Pair>, - pX: Int, pY: Int, - mathType: String - ) { - if(mathType == "+") { - widgetMap["${pair.first}_plus_one" to pair.second] = - ValueModifierButton(pX, pY, 10, 10, "+", pair.first, 1.0) - widgetMap["${pair.first}_plus_ten" to pair.second] = - ValueModifierButton(pX + 10, pY, 16, 10, "++", pair.first, 10.0) - widgetMap["${pair.first}_plus_hundred" to pair.second] = - ValueModifierButton(pX + 2, pY + 10, 22, 10, "+++", pair.first, 100.0) - } else if(mathType == "-") { - widgetMap["${pair.first}_minus_one" to pair.second] = - ValueModifierButton(pX, pY, 10, 10, "-", pair.first, -1.0) - widgetMap["${pair.first}_minus_ten" to pair.second] = - ValueModifierButton(pX + 10, pY, 16, 10, "--", pair.first, -10.0) - widgetMap["${pair.first}_minus_hundred" to pair.second] = - ValueModifierButton(pX + 2, pY + 10, 22, 10, "---", pair.first, -100.0) - } - } - - override fun init() { - super.init() - createEditBox( - leftPos + 100, topPos + 100, 100, 15, - TGCTabs.MAIN, "mob_selector", entityString - ) { string -> - entityString = string.lowercase().replace(' ', '_') - entityType = getEntityFromString(entityString) - println(entityString) - } - - widgetMap["potion_tab_button" to TGCTabs.MAIN] = - TabButton(leftPos + 175, topPos, 80, 10, Component.literal("Potion Effects")) { - currentTab = TGCTabs.POTION - widgetMap.forEach { (key, value) -> value.visible = key.second == TGCTabs.POTION } - renderableMap.forEach { (key, value) -> value.visible = key.second == TGCTabs.POTION } - println(currentTab) - } - - widgetMap["main_tab_button" to TGCTabs.POTION] = - TabButton(leftPos + 130, topPos, 30, 10, Component.literal("Main")) { - currentTab = TGCTabs.MAIN - widgetMap.forEach { (key, value) -> value.visible = key.second == TGCTabs.MAIN } - renderableMap.forEach { (key, value) -> value.visible = key.second == TGCTabs.MAIN } - println(currentTab) - } - - widgetMap["funny_button" to TGCTabs.MAIN] = FunnyButton(leftPos + 200, topPos + 80, 20, 20, - 0, 0, 20, 20, - modLocation("textures", "block", "fish.gif")) - - widgetMap["json_button" to TGCTabs.MAIN] = - JsonButton(leftPos + 120, topPos + 30, 80, 10, Component.literal("send to server")) - - valueModifierButtons("scale" to TGCTabs.MAIN, leftPos + 5, topPos + 100, "+") - valueModifierButtons("scale" to TGCTabs.MAIN, leftPos + 38, topPos + 100, "-") - - renderableMap["test" to TGCTabs.POTION] = PotionEffectGuiElement(50, 50) - - renderableMap.forEach { (key, value) -> - addRenderableOnly(value) - if(key.second == TGCTabs.POTION) value.visible = false - } - - widgetMap.forEach { (key, value) -> - addRenderableWidget(value) - if(key.second == TGCTabs.POTION) value.visible = false - } - } - - override fun rebuildWidgets() { - widgetMap.clear() - super.rebuildWidgets() - } - - override fun keyPressed(pKeyCode: Int, pScanCode: Int, pModifiers: Int): Boolean { - val box = activeEditBox ?: return super.keyPressed(pKeyCode, pScanCode, pModifiers) - if (pKeyCode == GLFW.GLFW_KEY_ESCAPE && shouldCloseOnEsc()) { - instance.player?.closeContainer() - } - - return !box.keyPressed(pKeyCode, pScanCode, pModifiers) && - if(!box.canConsumeInput()) super.keyPressed(pKeyCode, pScanCode, pModifiers) else true - } - - override fun shouldCloseOnEsc(): Boolean = activeEditBox?.canConsumeInput() != true - - override fun containerTick() { - super.containerTick() - widgetMap.forEach { (_, value) -> - if(value is EditBox) value.tick() - } - } - - inner class ValueModifierButton( - pX: Int, - pY: Int, - pWidth: Int, - pHeight: Int, - pText: String, - private val pType: String, - private val pValue: Double - ): AbstractButton(pX, pY, pWidth, pHeight, Component.literal(pText)) { - override fun updateWidgetNarration(pNarrationElementOutput: NarrationElementOutput) {} - - override fun onPress() { - when(pType) { - "health" -> entityHealth += pValue - "speed" -> entitySpeed += pValue - "scale" -> entityScale += pValue.toInt() - } - } - - override fun isFocused(): Boolean = false - } - - inner class TabButton( - pX: Int, - pY: Int, - pWidth: Int, - pHeight: Int, - pText: Component, - onPress: OnPress - ): Button(pX, pY, pWidth, pHeight, pText, onPress, CreateNarration { it.get() }) - - inner class JsonButton( - pX: Int, - pY: Int, - pWidth: Int, - pHeight: Int, - pText: Component - ): AbstractButton(pX, pY, pWidth, pHeight, pText) { -// private val gson = Gson() - - private fun writeJson(): JsonObject = JsonObject().also { -// it.addProperty("entity", ForgeRegistries.ENTITY_TYPES.getKey(entityType).toString()) - it.addProperty("entity", entityString) - if(customEntityName != "") { it.addProperty("custom_entity_name", customEntityName) } - it.addProperty("entity_health", entityHealth) - it.addProperty("entity_speed", entitySpeed) - it.add("effects", JsonObject().also { effectObject -> - entityEffect.forEach { (effect, duration, amplifier) -> - effectObject.add(effectToString(effect), JsonObject().also { currentEffect -> - currentEffect.addProperty("duration", duration) - currentEffect.addProperty("amplifier", amplifier) - }) - } - }) - it.addProperty("helmet", itemToString(helmetSlot.item)) - it.addProperty("chestplate", itemToString(chestplateSlot.item)) - it.addProperty("leggings", itemToString(leggingsSlot.item)) - it.addProperty("boots", itemToString(bootsSlot.item)) - it.addProperty("main_hand", itemToString(mainHandSlot.item)) - it.addProperty("off_hand", itemToString(offHandSlot.item)) - } - - override fun updateWidgetNarration(pNarrationElementOutput: NarrationElementOutput) {} - - override fun onPress() { - val json = writeJson() - - println("firing string to server") - println(json.toString()) - finalData = json.toString() - PacketHandler.NETWORK.sendToServer(ToolGunCreatorDataPacket(json.toString())) - - // todo this stuff below needs to be converted into a save/load system for storing on the player's computer -// val jsonByteArray = json.toString().encodeToByteArray() -// -// val filePath: Path -// if(!Files.exists(FMLPaths.GAMEDIR.get().resolve("breadmod/tool_gun/mob.json").toAbsolutePath())) { -// Files.write(FMLPaths.GAMEDIR.get().resolve("breadmod/tool_gun/mob.json").toAbsolutePath(), jsonByteArray) -// println("wrote json file to path") -// return -// } else filePath = FMLPaths.GAMEDIR.get().resolve("breadmod/tool_gun/mob.json").toAbsolutePath() -// -// val jsonReader = JsonReader(FileReader(filePath.toFile())) -// val jsonData: JsonObject = gson.fromJson(jsonReader, JsonObject::class.java) - } - } - - // todo replace with direct call to ImageButton - inner class FunnyButton( - pX: Int, - pY: Int, - pWidth: Int, - pHeight: Int, - pXTexStart: Int, - pYTexStart: Int, - pTextureWidth: Int, - pTextureHeight: Int, - pResourceLocation: ResourceLocation - ): ImageButton( - pX, pY, - pWidth, pHeight, - pXTexStart, pYTexStart, - 0, - pResourceLocation, pTextureWidth, pTextureHeight, - { createPathAndFile() } - ) -} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/datagen/lang/USEnglishLanguageProvider.kt b/src/main/kotlin/breadmod/datagen/lang/USEnglishLanguageProvider.kt index c463d5fd..c2d8abd0 100644 --- a/src/main/kotlin/breadmod/datagen/lang/USEnglishLanguageProvider.kt +++ b/src/main/kotlin/breadmod/datagen/lang/USEnglishLanguageProvider.kt @@ -211,6 +211,8 @@ class USEnglishLanguageProvider( TOOL_GUN_DEF, "mode", "key_tooltip", "creator", "r") modAdd("Save / Load", TOOL_GUN_DEF, "creator", "save_load") + modAdd("expected %s, got %s", + TOOL_GUN_DEF, "creator", "invalid_entity") modAdd("Create Entity", TOOL_GUN_DEF, "mode", "controls", "name", "creator", "rmb") diff --git a/src/main/kotlin/breadmod/item/tool_gun/ToolGunItem.kt b/src/main/kotlin/breadmod/item/tool_gun/ToolGunItem.kt index db1d7097..2ae625bb 100644 --- a/src/main/kotlin/breadmod/item/tool_gun/ToolGunItem.kt +++ b/src/main/kotlin/breadmod/item/tool_gun/ToolGunItem.kt @@ -1,24 +1,18 @@ package breadmod.item.tool_gun -import breadmod.ClientModEventBus.toolGunBindList -import breadmod.ModMain +import breadmod.ClientForgeEventBus.changeMode import breadmod.ModMain.modTranslatable import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_DEF import breadmod.datagen.tool_gun.ModToolGunModeDataLoader import breadmod.item.tool_gun.mode.ToolGunNoMode import breadmod.client.render.tool_gun.ToolGunItemRenderer -import breadmod.network.PacketHandler.NETWORK -import breadmod.network.tool_gun.ToolGunPacket import breadmod.registry.item.IRegisterSpecialCreativeTab import breadmod.registry.menu.ModCreativeTabs import breadmod.util.MapIterator -import com.mojang.blaze3d.platform.InputConstants import net.minecraft.ChatFormatting -import net.minecraft.client.KeyMapping import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer import net.minecraft.nbt.CompoundTag import net.minecraft.network.chat.Component -import net.minecraft.sounds.SoundEvents import net.minecraft.world.entity.Entity import net.minecraft.world.entity.player.Player import net.minecraft.world.item.CreativeModeTab @@ -27,8 +21,6 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.TooltipFlag import net.minecraft.world.level.Level import net.minecraftforge.client.extensions.common.IClientItemExtensions -import net.minecraftforge.client.settings.KeyConflictContext -import net.minecraftforge.client.settings.KeyModifier import net.minecraftforge.registries.RegistryObject import java.util.function.Consumer @@ -82,28 +74,9 @@ internal class ToolGunItem: Item(Properties().stacksTo(1)), IRegisterSpecialCrea override fun inventoryTick(pStack: ItemStack, pLevel: Level, pEntity: Entity, pSlotId: Int, pIsSelected: Boolean) { if(pEntity is Player) { val currentMode = getCurrentMode(pStack) - if(pLevel.isClientSide) { - if(!pIsSelected) currentMode.mode.close(pLevel, pEntity, pStack, null) - else { - if(changeMode.consumeClick()) { - // TODO open/close for client - NETWORK.sendToServer(ToolGunPacket(true, pSlotId)) - pEntity.playSound(SoundEvents.DISPENSER_FAIL, 1.0f, 1.0f) - } else { - currentMode.mode.open(pLevel, pEntity, pStack, null) - currentMode.keyBinds.forEach { - val bind = toolGunBindList[it] - if(bind != null && bind.consumeClick()) { - NETWORK.sendToServer(ToolGunPacket(false, pSlotId, it)) - currentMode.mode.action(pLevel, pEntity, pStack, it) - } - } - } - } - } else - // Server - if(pIsSelected) currentMode.mode.open(pLevel, pEntity, pStack, null) - else currentMode.mode.close(pLevel, pEntity, pStack, null) + + if(pIsSelected) currentMode.mode.open(pLevel, pEntity, pStack, null) + else currentMode.mode.close(pLevel, pEntity, pStack, null) } } @@ -127,15 +100,5 @@ internal class ToolGunItem: Item(Properties().stacksTo(1)), IRegisterSpecialCrea const val NAMESPACE_ITERATOR_STATE_TAG = "namespaceIteratorState" const val MODE_ITERATOR_STATE_TAG = "modeIteratorState" - - val changeMode by lazy { - KeyMapping( - "controls.${ModMain.ID}.$TOOL_GUN_DEF.change_mode", - KeyConflictContext.IN_GAME, - KeyModifier.SHIFT, - InputConstants.Type.MOUSE.getOrCreate(InputConstants.MOUSE_BUTTON_RIGHT), - "controls.${ModMain.ID}.category.$TOOL_GUN_DEF" - ) - } } } \ No newline at end of file diff --git a/src/main/kotlin/breadmod/item/tool_gun/mode/creator/CreatorUtil.kt b/src/main/kotlin/breadmod/item/tool_gun/mode/creator/CreatorUtil.kt index f46e4124..b11251ac 100644 --- a/src/main/kotlin/breadmod/item/tool_gun/mode/creator/CreatorUtil.kt +++ b/src/main/kotlin/breadmod/item/tool_gun/mode/creator/CreatorUtil.kt @@ -1,5 +1,6 @@ package breadmod.item.tool_gun.mode.creator +import net.minecraft.resources.ResourceLocation import net.minecraft.world.effect.MobEffect import net.minecraft.world.entity.EntityType import net.minecraft.world.item.Item @@ -13,8 +14,12 @@ const val BOOTS_SLOT = 100 const val MAINHAND_SLOT = 98 const val OFFHAND_SLOT = 99 -fun getEntityFromString(string: String): EntityType<*>? = - ForgeRegistries.ENTITY_TYPES.getValue(EntityType.byString(string).getOrNull()?.let { EntityType.getKey(it) }) +/** Returns [EntityType.PIG] if provided [id] does not exist */ +fun getEntityFromString(id: String): EntityType<*>? = + ForgeRegistries.ENTITY_TYPES.getValue(EntityType.byString(id).getOrNull()?.let { EntityType.getKey(it) }) +/** Returns null if provided [id] and/or [namespace] does not exist */ +fun mobEffectFromString(namespace: String = "minecraft", id: String): MobEffect? = + ForgeRegistries.MOB_EFFECTS.getValue(ResourceLocation(namespace, id)) fun itemToString(item: Item) = ForgeRegistries.ITEMS.getKey(item).toString() fun effectToString(effect: MobEffect) = ForgeRegistries.MOB_EFFECTS.getKey(effect).toString() \ No newline at end of file diff --git a/src/main/kotlin/breadmod/item/tool_gun/mode/creator/ToolGunCreatorMode.kt b/src/main/kotlin/breadmod/item/tool_gun/mode/creator/ToolGunCreatorMode.kt index 68f03047..4c514b3f 100644 --- a/src/main/kotlin/breadmod/item/tool_gun/mode/creator/ToolGunCreatorMode.kt +++ b/src/main/kotlin/breadmod/item/tool_gun/mode/creator/ToolGunCreatorMode.kt @@ -2,7 +2,6 @@ package breadmod.item.tool_gun.mode.creator import breadmod.ModMain import breadmod.client.render.tool_gun.ToolGunAnimationHandler -import breadmod.client.screen.tool_gun.creator.ToolGunCreatorScreen import breadmod.datagen.tool_gun.BreadModToolGunModeProvider import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_DEF import breadmod.menu.item.ToolGunCreatorMenu @@ -12,9 +11,7 @@ import breadmod.util.RayMarchResult.Companion.rayMarchBlock import com.google.gson.Gson import com.google.gson.JsonElement import com.google.gson.JsonObject -import com.mojang.blaze3d.vertex.PoseStack import net.minecraft.ChatFormatting -import net.minecraft.client.renderer.MultiBufferSource import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerLevel @@ -31,7 +28,6 @@ import net.minecraft.world.entity.animal.Pig import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu -import net.minecraft.world.item.ItemDisplayContext import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraft.world.phys.Vec3 @@ -135,17 +131,17 @@ internal class ToolGunCreatorMode : IToolGunMode, MenuProvider { } else if (pLevel.isClientSide && pControl.id == "use") ToolGunAnimationHandler.trigger() } - override fun render( - pGunStack: ItemStack, - pDisplayContext: ItemDisplayContext, - pPoseStack: PoseStack, - pBuffer: MultiBufferSource, - pPackedLight: Int, - pPackedOverlay: Int - ) { - val jsonData = Gson().fromJson(ToolGunCreatorScreen.finalData, JsonObject::class.java) +// override fun render( +// pGunStack: ItemStack, +// pDisplayContext: ItemDisplayContext, +// pPoseStack: PoseStack, +// pBuffer: MultiBufferSource, +// pPackedLight: Int, +// pPackedOverlay: Int +// ) { +// val jsonData = Gson().fromJson(ToolGunCreatorScreen.finalData, JsonObject::class.java) // println(ToolGunCreatorScreen.finalData) - } +// } override fun createMenu(pContainerId: Int, pPlayerInventory: Inventory, pPlayer: Player): AbstractContainerMenu = ToolGunCreatorMenu(pContainerId, pPlayerInventory) diff --git a/src/main/kotlin/breadmod/network/tool_gun/ToolGunPacket.kt b/src/main/kotlin/breadmod/network/tool_gun/ToolGunPacket.kt index d70512cd..a9a4f4e9 100644 --- a/src/main/kotlin/breadmod/network/tool_gun/ToolGunPacket.kt +++ b/src/main/kotlin/breadmod/network/tool_gun/ToolGunPacket.kt @@ -19,10 +19,10 @@ import net.minecraftforge.network.NetworkEvent import java.util.concurrent.CompletableFuture import java.util.function.Supplier -data class ToolGunPacket(val pModeSwitch: Boolean, val pSlot: Int, val pControl: BreadModToolGunModeProvider.Control? = null) { +data class ToolGunPacket(val pModeSwitch: Boolean, val pControl: BreadModToolGunModeProvider.Control? = null) { companion object { fun encodeBuf(input: ToolGunPacket, buffer: FriendlyByteBuf) { - buffer.writeBoolean(input.pModeSwitch).writeInt(input.pSlot); buffer.writeNullable(input.pControl) { writer, value -> + buffer.writeBoolean(input.pModeSwitch); buffer.writeNullable(input.pControl) { writer, value -> writer.writeUtf(value.id) writer.writeUtf(value.nameKey) writer.writeUtf(value.categoryKey) @@ -31,7 +31,7 @@ data class ToolGunPacket(val pModeSwitch: Boolean, val pSlot: Int, val pControl: writer.writeNullable(value.modifier) { writer2, value2 -> writer2.writeUtf(value2.name) } } } fun decodeBuf(input: FriendlyByteBuf): ToolGunPacket = - ToolGunPacket(input.readBoolean(), input.readInt(), input.readNullable { + ToolGunPacket(input.readBoolean(), input.readNullable { BreadModToolGunModeProvider.Control( input.readUtf(), input.readUtf(), @@ -45,44 +45,47 @@ data class ToolGunPacket(val pModeSwitch: Boolean, val pSlot: Int, val pControl: fun handle(input: ToolGunPacket, ctx: Supplier): CompletableFuture = ctx.get().let { it.enqueueWork { val player = it.sender ?: return@enqueueWork - val stack = player.inventory.items[input.pSlot] +// val stack = player.inventory.items[input.pSlot] + val stack = player.mainHandItem val item = stack.item - if(!player.cooldowns.isOnCooldown(item) && item is ToolGunItem) { - if(input.pModeSwitch) { - val currentMode = item.ensureCurrentMode(stack) - val namespaceIterator = MapIterator(ModToolGunModeDataLoader.modes) - namespaceIterator.restoreState(currentMode.getInt(NAMESPACE_ITERATOR_STATE_TAG)) - val modeIterator = MapIterator(namespaceIterator.current().value) - modeIterator.restoreState(currentMode.getInt(MODE_ITERATOR_STATE_TAG)) + if(item is ToolGunItem) { + if(!player.cooldowns.isOnCooldown(item)) { + if(input.pModeSwitch) { + val currentMode = item.ensureCurrentMode(stack) + val namespaceIterator = MapIterator(ModToolGunModeDataLoader.modes) + namespaceIterator.restoreState(currentMode.getInt(NAMESPACE_ITERATOR_STATE_TAG)) + val modeIterator = MapIterator(namespaceIterator.current().value) + modeIterator.restoreState(currentMode.getInt(MODE_ITERATOR_STATE_TAG)) - val last = modeIterator.current().value.first - when { - modeIterator.hasNext() -> { - currentMode.putString(MODE_NAME_TAG, modeIterator.next().key) - currentMode.putInt(MODE_ITERATOR_STATE_TAG, modeIterator.saveState()) + val last = modeIterator.current().value.first + when { + modeIterator.hasNext() -> { + currentMode.putString(MODE_NAME_TAG, modeIterator.next().key) + currentMode.putInt(MODE_ITERATOR_STATE_TAG, modeIterator.saveState()) + } + namespaceIterator.hasNext() -> { + currentMode.putString(MODE_NAMESPACE_TAG, namespaceIterator.next().key) + currentMode.putInt(NAMESPACE_ITERATOR_STATE_TAG, namespaceIterator.saveState()) + currentMode.putInt(MODE_ITERATOR_STATE_TAG, 0) + currentMode.putString(MODE_NAME_TAG, modeIterator.current().key) + } + else -> { + currentMode.putInt(NAMESPACE_ITERATOR_STATE_TAG, 0) + currentMode.putString(MODE_NAMESPACE_TAG, namespaceIterator.current().key) + currentMode.putInt(MODE_ITERATOR_STATE_TAG, 0) + currentMode.putString(MODE_NAME_TAG, modeIterator.current().key) + } } - namespaceIterator.hasNext() -> { - currentMode.putString(MODE_NAMESPACE_TAG, namespaceIterator.next().key) - currentMode.putInt(NAMESPACE_ITERATOR_STATE_TAG, namespaceIterator.saveState()) - currentMode.putInt(MODE_ITERATOR_STATE_TAG, 0) - currentMode.putString(MODE_NAME_TAG, modeIterator.current().key) - } - else -> { - currentMode.putInt(NAMESPACE_ITERATOR_STATE_TAG, 0) - currentMode.putString(MODE_NAMESPACE_TAG, namespaceIterator.current().key) - currentMode.putInt(MODE_ITERATOR_STATE_TAG, 0) - currentMode.putString(MODE_NAME_TAG, modeIterator.current().key) - } - } - val level = player.level() - last.mode.close(level, player, stack, modeIterator.current().value.first.mode) - modeIterator.current().value.first.mode.open(level, player, stack, last.mode) - player.cooldowns.addCooldown(item, 10) - } else { - item.getCurrentMode(stack).mode.action(player.level(), player, stack, input.pControl ?: return@enqueueWork) + val level = player.level() + last.mode.close(level, player, stack, modeIterator.current().value.first.mode) + modeIterator.current().value.first.mode.open(level, player, stack, last.mode) + player.cooldowns.addCooldown(item, 10) + } else { + item.getCurrentMode(stack).mode.action(player.level(), player, stack, input.pControl ?: return@enqueueWork) + } + it.packetHandled = true } - it.packetHandled = true } } } diff --git a/src/main/kotlin/breadmod/util/render/General.kt b/src/main/kotlin/breadmod/util/render/General.kt index 35eb8d67..dd4772c2 100644 --- a/src/main/kotlin/breadmod/util/render/General.kt +++ b/src/main/kotlin/breadmod/util/render/General.kt @@ -209,6 +209,8 @@ fun renderStaticItem( ) } +fun PoseStack.scaleFlat(scale: Float) = this.scale(scale, scale, scale) + fun vertexTest( pPoseStack: PoseStack, pBuffer: MultiBufferSource, diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index 02742317..21cac9d3 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1 +1,4 @@ public-f net.minecraft.world.item.ItemStack +public net.minecraft.client.gui.components.AbstractWidget m_257936_()V # updateTooltip +public net.minecraft.client.gui.components.CycleButton m_257795_()V # updateTooltip +public net.minecraft.client.gui.components.AbstractButton m_274533_()I # getTextureY \ No newline at end of file diff --git a/src/main/resources/assets/breadmod/textures/gui/item/tool_gun/creator_mode.png b/src/main/resources/assets/breadmod/textures/gui/item/tool_gun/creator_mode.png index 17077231bcfe4fc8f36fcec35f917b5c282adaa1..c1381653478973cd6722bb772360f1c25c6a87e5 100644 GIT binary patch delta 1209 zcma))doWyg6vuz}?!_)f?vBS;Mr`7lkPsRh>4v+(N=Pt5m{#m&v@{QkPCQoC-b<(H zDAsf%XewkxBotdT>lxR`AY<&xh)0NIjf4o|u}U`^^tRLg`cKcynREU)^O-ZB`6{D& zqT~_#CDEt-c@Y`0%hOL2V>qZ@n9FKS3|VVc@?QTLZd7EL45htz)2*jjek^Lqof}Gnj07H8~zPUNZRQ;Ly}3M7dt9K+yg1cTc>_bm9UAma^d` z$rT8ar|J^3)2XRr$am}Y5OQo;p`DgB?Pp2UA9$6sG$dFRQqDS?nC{O~TfP(f7DNT{53vbwXglY0$Y?=rAy zzuV^ub;Hef?8Bhu7<*gDR^Z#QIx;e{qAEOE2nZ{LR>22l*7arq^d2NK;7C0L8&%%_ zk+eY&(x&JTud)^g_a|AY%+_2Sw9=X!=n>{9i2StbFr1E}ART*%5VbH|c{$-(fZ7Cx z)g}Ws*dbL)de^IN|HfuTybUWL+5?kNw z(s>%>qmcH^XcosC7c_A>8aN3`Huko1*JO&tZ6+L*E-y<|(a<|TrAYD&9G>7oNw7(d z_!lw=hK1FlNh5*>LGJXq6xfA9$BWx9xgq+Ldv<9*<5znL8=QZ4uM4#_LqV=^uao>I z97I33wRut)h5_UMOZg9k{3A#{JIIrE_wLNEj3#*fxs^571`W(_E*w|hu_ofPVU=`y zyZ{q9t!pinXMGfVBJWDA3FR&bkRFuevh#&Wuh-U6vWl3&l;Y~iOP)v{ zm6Fnu8iuO_8{E8HGlW`Fv5$+r?I^!NL2Jvs{DfyHs95|n8BQS{q)i$VMh$@c67kEw)gE~JkJ?}!4L!?rQ-=>{jBLec8R0tD l1aleB<(dq0akD(Cw*%ZxwfSrn)*AwYfuws6o$Y3+~@{WLJ<%|5-imKUQ)_55inVAIEX|=T2M4Z5gc2&NR_K3yD*BK zf`LgjT&$$6w%Soqq#zP-t*ue9jgC+e5)vkb=pY1%N-zYv?T`NJbo$MldC!mUednC# z+)DT@;Y$1>d1~~!)$w_fVZ)awl3p<+_C*iZ0&{W$3lSz-&Zm40N)EZMpq_A!th}e-~FDqgtUUyQTBI z#1q9fG41Y3>Ef@HHx{p@%Uy1I^Mp*6ND8cLUZa>M#^eR2^y95BW*1aYFX!B=KEfIi zeYfhg6C2Ij7sBF(aKQbhsNJal3J&nkJivgd3>1I*JGYE7(?HGTmvHq(0&shMkGkh+ z2#}|_>WO{n$pWcK-}0b>W~|^hL9zj|>z@qi8oGkYdnkL(iY@KXPok%>MTEP-&*Iz1lJd5soYF^xMo@#dBLqu?^NES+iIA@@xe%S^FHm zuHJJ(FWObAQ>{o&JE6W>0{c)u)FvQLqA0b|(C7_IXtt~eX7uBCSRmx^V+l6fMUD}x zc?yrjXdGPZj4ce{aXDb-tw^!-J^I{n{NbaNngH|vE9GB9$ljAuEqhO-%*|mnCe%GO zCEKbkb2)X6?}r4X8EDPKR+mW8n`Az0xo1fi@ag&ED}@i_tR z9eiI~jxTZBOQq1MpU=-Xm)ENLqC}?+*rBm4Ggl2psXZzx`F(yJ3uhG#dVZuEw;D53 z<1bjcRSU>8@f~}j6;YN2`N?}Q@*slnGSW~omBtx*snH#pX`K2880^3>B6Y{g_DWry zNZ}T`Cx}KDACZ2Hs-n@^#=^*Rv?Fe~(Fdl`jt3o&(NpvRVt#y_hLtff;{6qyJrXzK zU}=}QHh{O-6s1;5w(|R`EW+#b+WvP5?TH1uNXZP2RJe_WxeMkF4rDW{I|4IZH4m4@tUOVN2Q?LHG(fhbz$ zg@H%&Uc%*!a=x>xtR5LHJax@Qc`!tvREIGCN6qpfYoHuTeVQ*U`^mcq&@Xzuc-`eS H(&9e>EVV37