diff --git a/src/main/kotlin/breadmod/ClientForgeEventBus.kt b/src/main/kotlin/breadmod/ClientForgeEventBus.kt index 115940e0..37db530d 100644 --- a/src/main/kotlin/breadmod/ClientForgeEventBus.kt +++ b/src/main/kotlin/breadmod/ClientForgeEventBus.kt @@ -1,20 +1,17 @@ package breadmod import breadmod.ClientModEventBus.toolGunBindList -import breadmod.client.gui.WarTicker +import breadmod.client.gui.WarTickerClient +import breadmod.commands.client.AltToolGunModelCommand import breadmod.datagen.tool_gun.BreadModToolGunModeProvider.Companion.TOOL_GUN_DEF import breadmod.item.tool_gun.ToolGunItem import breadmod.network.PacketHandler.NETWORK import breadmod.network.serverbound.tool_gun.ToolGunConfigurationPacket -import breadmod.registry.ModConfiguration import breadmod.util.gui.IHoldScreen import breadmod.util.render.modifierMatches import breadmod.util.render.renderBuffer import breadmod.util.render.rgMinecraft import com.mojang.blaze3d.platform.InputConstants -import com.mojang.brigadier.Command -import com.mojang.brigadier.StringReader -import com.mojang.brigadier.arguments.ArgumentType import net.minecraft.client.KeyMapping import net.minecraft.client.Minecraft import net.minecraft.client.gui.screens.Screen @@ -162,60 +159,16 @@ object ClientForgeEventBus { @SubscribeEvent fun registerClientCommands(event: RegisterClientCommandsEvent) { - // todo it would probably be ideal to have each sub command be their own class for cleanness sakes - // CommandMek.java event.dispatcher.register(Commands.literal("breadmod") - .then(Commands.literal("increase_timer") - .then(Commands.argument("amount", IntArgument()) - .executes { amount -> - val arg = amount.getArgument("amount", Int::class.java) - WarTicker.increaseTimer(arg) - return@executes Command.SINGLE_SUCCESS - } - ) - ) - .then(Commands.literal("reset_timer") - .executes { - WarTicker.reset() - return@executes Command.SINGLE_SUCCESS - } - ) - .then(Commands.literal("start_timer") - .executes { - WarTicker.active = true - return@executes Command.SINGLE_SUCCESS - } - ) - .then(Commands.literal("end_timer") - .executes { - WarTicker.active = false - return@executes Command.SINGLE_SUCCESS - } - ) - .then(Commands.literal("alt_toolgun_model") - .then(Commands.argument("value", BooleanArgument()) - .executes { value -> - val arg = value.getArgument("value", Boolean::class.java) - ModConfiguration.CLIENT.ALT_TOOLGUN_MODEL.set(arg) - return@executes Command.SINGLE_SUCCESS - } - ) - ) + .then(AltToolGunModelCommand.register()) ) } - private class IntArgument : ArgumentType { - override fun parse(reader: StringReader): Int = reader.readInt() - } - private class BooleanArgument : ArgumentType { - override fun parse(reader: StringReader): Boolean = reader.readBoolean() - } - @Suppress("UNUSED_PARAMETER") @SubscribeEvent fun onTick(event: ClientTickEvent) { if (Minecraft.getInstance().level == null || Minecraft.getInstance().player == null) return - WarTicker.tick() + WarTickerClient.tick() } } \ No newline at end of file diff --git a/src/main/kotlin/breadmod/CommonForgeEventBus.kt b/src/main/kotlin/breadmod/CommonForgeEventBus.kt index 901689dd..c67030f4 100644 --- a/src/main/kotlin/breadmod/CommonForgeEventBus.kt +++ b/src/main/kotlin/breadmod/CommonForgeEventBus.kt @@ -1,9 +1,17 @@ package breadmod +import breadmod.commands.server.WarTimerServerCommand import breadmod.datagen.tool_gun.ModToolGunModeDataLoader +import breadmod.network.PacketHandler +import breadmod.network.clientbound.war_timer.WarTimerSynchronizationPacket +import net.minecraft.commands.Commands +import net.minecraft.server.level.ServerPlayer import net.minecraftforge.event.AddReloadListenerEvent +import net.minecraftforge.event.RegisterCommandsEvent +import net.minecraftforge.event.TickEvent import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.common.Mod +import net.minecraftforge.network.PacketDistributor @Suppress("unused") @Mod.EventBusSubscriber(modid = ModMain.ID, bus = Mod.EventBusSubscriber.Bus.FORGE) @@ -12,4 +20,62 @@ object CommonForgeEventBus { fun onResourceReload(event: AddReloadListenerEvent) { event.addListener(ModToolGunModeDataLoader) } + + /** + * A map holding a war timer for every player on the server + * * First int holds the time left. + * * Second int holds the delay (or ticker) before the time left decrements by one. + * * Third int holds the increasing timer (how long the timer will increase for). + * * First boolean is for the timer being active or not. + * * Second boolean is if the timer is currently increasing in time. + * * Players need to manually be added to the timer map using the warTimer command + * * Server automatically pauses the player's timer if they leave and unpauses when they rejoin + * * Timer is automatically removed if their time left is 0 or their timer is force ended by an admin + */ + val warTimerMap: MutableMap, Pair>> = mutableMapOf() + + @SubscribeEvent + fun serverTick(event: TickEvent.ServerTickEvent) { + warTimerTick() + } + + private fun warTimerTick() { + warTimerMap.forEach { (key, value) -> + val timeLeft = value.first.first + val ticker = value.first.second + val increaseTime = value.first.third + val active = value.second.first + val isIncreasing = value.second.second + + warTimerMap[key]?.let { + if (active && !isIncreasing) { + if (ticker == 0 && timeLeft > 0) { + val timeDecrement = timeLeft - 1 + warTimerMap[key] = Triple(timeDecrement, 41, increaseTime) to it.second + PacketHandler.NETWORK.send( + PacketDistributor.PLAYER.with { key }, + WarTimerSynchronizationPacket(timeDecrement) + ) + } else if (timeLeft > 0) { + val tickerDecrement = ticker - 1 + warTimerMap[key] = Triple(timeLeft, tickerDecrement, increaseTime) to it.second + } + } + if (increaseTime > 0 && isIncreasing) { + val increasingDecrement = increaseTime - 1 + val increasingTime = timeLeft + 1 + warTimerMap[key] = Triple(increasingTime, ticker, increasingDecrement) to it.second + } else if (isIncreasing && increaseTime == 0) { + warTimerMap[key] = Triple(timeLeft, ticker, increaseTime) to (it.second.first to false) + } + } + } + } + + @SubscribeEvent + fun registerCommands(event: RegisterCommandsEvent) { + event.dispatcher.register(Commands.literal("breadmod") + .then(WarTimerServerCommand.register()) + ) + } } \ No newline at end of file diff --git a/src/main/kotlin/breadmod/ServerForgeEventBus.kt b/src/main/kotlin/breadmod/ServerForgeEventBus.kt index 950e1672..84099b6e 100644 --- a/src/main/kotlin/breadmod/ServerForgeEventBus.kt +++ b/src/main/kotlin/breadmod/ServerForgeEventBus.kt @@ -3,8 +3,10 @@ package breadmod import breadmod.datagen.tool_gun.ModToolGunModeDataLoader import breadmod.network.PacketHandler.NETWORK import breadmod.network.clientbound.tool_gun.ToolGunModeDataPacket +import breadmod.CommonForgeEventBus.warTimerMap import net.minecraft.server.level.ServerPlayer import net.minecraftforge.api.distmarker.Dist +import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent import net.minecraftforge.eventbus.api.SubscribeEvent import net.minecraftforge.fml.common.Mod @@ -24,5 +26,20 @@ object ServerForgeEventBus { ToolGunModeDataPacket(next.second, next.third, list.hasNext()) ) } + + val serverPlayer = event.entity as ServerPlayer + warTimerMap[serverPlayer]?.let { + // sets the joining players active timer state to true so it continues ticking down + warTimerMap[serverPlayer] = it.first to (true to it.second.second) + } + } + + @SubscribeEvent + fun onPlayerLeave(event: PlayerEvent.PlayerLoggedOutEvent) { + val serverPlayer = event.entity as ServerPlayer + // sets the leaving players active timer state to false so it won't tick down anymore + warTimerMap[serverPlayer]?.let { + warTimerMap[serverPlayer] = it.first to (false to it.second.second) + } } } \ No newline at end of file diff --git a/src/main/kotlin/breadmod/client/gui/WarOverlay.kt b/src/main/kotlin/breadmod/client/gui/WarOverlay.kt index 75413ee3..5b9b80a5 100644 --- a/src/main/kotlin/breadmod/client/gui/WarOverlay.kt +++ b/src/main/kotlin/breadmod/client/gui/WarOverlay.kt @@ -1,8 +1,8 @@ package breadmod.client.gui import breadmod.ModMain.modLocation -import breadmod.client.gui.WarTicker.lastScroll -import breadmod.client.gui.WarTicker.scroll +import breadmod.client.gui.WarTickerClient.lastScroll +import breadmod.client.gui.WarTickerClient.scroll import breadmod.util.ModFonts import breadmod.util.render.rgMinecraft import breadmod.util.render.scaleFlat @@ -28,12 +28,12 @@ class WarOverlay : AbstractModGuiOverlay() { pBuffer: MultiBufferSource, pPlayer: LocalPlayer ) { - val seconds = WarTicker.timer % 60 - val minutes = WarTicker.timer / 60 + val seconds = WarTickerClient.timer % 60 + val minutes = WarTickerClient.timer / 60 val formattedSeconds = if (seconds < 10) "0$seconds" else seconds val formattedMinutes = if (minutes < 10) "0$minutes" else minutes val colorPair: Triple = - if (WarTicker.isIncreasing) Triple(0.376f, 0.91f, 0.471f) + if (WarTickerClient.isIncreasing) Triple(0.376f, 0.91f, 0.471f) else Triple(0.973f, 0f, 0f) if (scroll > -110f) { diff --git a/src/main/kotlin/breadmod/client/gui/WarTicker.kt b/src/main/kotlin/breadmod/client/gui/WarTicker.kt deleted file mode 100644 index dfa4af06..00000000 --- a/src/main/kotlin/breadmod/client/gui/WarTicker.kt +++ /dev/null @@ -1,53 +0,0 @@ -package breadmod.client.gui - -import breadmod.registry.sound.ModSounds -import breadmod.util.render.rgMinecraft - -object WarTicker { - var timer = 30 - var ticker = 41 - var isIncreasing = false - var increasingTimer = 0 - var active = false - - var scroll = -110f - var lastScroll = -110f - - fun tick() { - val player = rgMinecraft.player ?: return - if (!rgMinecraft.isPaused && active) { - if (!isIncreasing) { - if (ticker == 0 && timer > 0) { // Tick timer down by one - player.playSound(ModSounds.WAR_TIMER.get(), 0.8f, 1f) - timer-- - ticker = 41 - } else if (timer > 0) ticker-- // Tick down ticker - } - if (increasingTimer > 0) { // Increase timer - increasingTimer-- - timer++ - ticker = 41 - } else isIncreasing = false - } - if (!rgMinecraft.isPaused) { - lastScroll = scroll // hell code until I figure out proper smooth like anims from minecraft's code - if (scroll > -110.0 && !active) { - scroll -= (1f * 0.5f) * 4.0f - } else if (scroll < 0.0 && active) { - scroll += (1f * 0.5f) * 4.0f - } - } - } - - fun reset() { - timer = 30 - ticker = 41 - } - - fun increaseTimer(pAmount: Int = 41) { - val player = rgMinecraft.player ?: return - player.playSound(ModSounds.WAR_TIMER_UP.get(), 1f, 1f) - increasingTimer += pAmount - isIncreasing = true - } -} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/client/gui/WarTickerClient.kt b/src/main/kotlin/breadmod/client/gui/WarTickerClient.kt new file mode 100644 index 00000000..9ab3d104 --- /dev/null +++ b/src/main/kotlin/breadmod/client/gui/WarTickerClient.kt @@ -0,0 +1,25 @@ +package breadmod.client.gui + +object WarTickerClient { + var timer = 30 + var isIncreasing = false + var increasingTimer = 0 + var active = false + + var scroll = -110f + var lastScroll = -110f + + fun tick() { + if (increasingTimer > 0) { // Increase timer + increasingTimer-- + timer++ + } else isIncreasing = false + + lastScroll = scroll // hell code until I figure out proper smooth like anims from minecraft's code + if (scroll > -110.0 && !active) { + scroll -= (1f * 0.5f) * 4.0f + } else if (scroll < 0.0 && active) { + scroll += (1f * 0.5f) * 4.0f + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/commands/CommandArguments.kt b/src/main/kotlin/breadmod/commands/CommandArguments.kt new file mode 100644 index 00000000..8d611cba --- /dev/null +++ b/src/main/kotlin/breadmod/commands/CommandArguments.kt @@ -0,0 +1,13 @@ +package breadmod.commands + +import com.mojang.brigadier.StringReader +import com.mojang.brigadier.arguments.ArgumentType + +object CommandArguments { + class IntArgument : ArgumentType { + override fun parse(reader: StringReader): Int = reader.readInt() + } + class BooleanArgument : ArgumentType { + override fun parse(reader: StringReader): Boolean = reader.readBoolean() + } +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/commands/client/AltToolGunModelCommand.kt b/src/main/kotlin/breadmod/commands/client/AltToolGunModelCommand.kt new file mode 100644 index 00000000..0a071891 --- /dev/null +++ b/src/main/kotlin/breadmod/commands/client/AltToolGunModelCommand.kt @@ -0,0 +1,20 @@ +package breadmod.commands.client + +import breadmod.commands.CommandArguments.BooleanArgument +import breadmod.registry.ModConfiguration +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import net.minecraft.commands.CommandSourceStack +import net.minecraft.commands.Commands + +internal object AltToolGunModelCommand { + fun register(): ArgumentBuilder = + Commands.literal("altToolgunModel") + .then(Commands.argument("value", BooleanArgument()) + .executes { value -> + val arg = value.getArgument("value", Boolean::class.java) + ModConfiguration.CLIENT.ALT_TOOLGUN_MODEL.set(arg) + return@executes Command.SINGLE_SUCCESS + } + ) +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/commands/server/WarTimerServerCommand.kt b/src/main/kotlin/breadmod/commands/server/WarTimerServerCommand.kt new file mode 100644 index 00000000..fe3656ab --- /dev/null +++ b/src/main/kotlin/breadmod/commands/server/WarTimerServerCommand.kt @@ -0,0 +1,79 @@ +package breadmod.commands.server + +import breadmod.CommonForgeEventBus.warTimerMap +import breadmod.network.PacketHandler +import breadmod.network.clientbound.war_timer.WarTimerIncrementPacket +import breadmod.network.clientbound.war_timer.WarTimerTogglePacket +import com.mojang.brigadier.Command +import com.mojang.brigadier.builder.ArgumentBuilder +import net.minecraft.commands.CommandSourceStack +import net.minecraft.commands.Commands +import net.minecraft.commands.arguments.EntityArgument +import net.minecraftforge.network.PacketDistributor + +object WarTimerServerCommand { + fun register(): ArgumentBuilder = + Commands.literal("warTimer") + .then(Commands.argument("player", EntityArgument.player()) + .then(toggle()) + .then(add()) + .then(increase()) + ) + + fun toggle(): ArgumentBuilder = + Commands.literal("toggle") + .executes { ctx -> + val target = EntityArgument.getPlayer(ctx, "player") + warTimerMap[target]?.let { + if (!it.second.first) { + warTimerMap.put(target, it.first to (true to it.second.second)) + PacketHandler.NETWORK.send( + PacketDistributor.PLAYER.with { target }, + WarTimerTogglePacket(true) + ) + } else { + warTimerMap.put(target, it.first to (false to it.second.second)) + PacketHandler.NETWORK.send( + PacketDistributor.PLAYER.with { target }, + WarTimerTogglePacket(false) + ) + } + } + return@executes Command.SINGLE_SUCCESS + } + + fun add(): ArgumentBuilder = + Commands.literal("add") + .executes{ ctx -> + val target = EntityArgument.getPlayer(ctx, "player") + warTimerMap[target] = Triple(30, 41, 0) to (false to false) + return@executes Command.SINGLE_SUCCESS + } + + // todo figure out how to make an argument command to work alongside the player argument command + // todo spamming this command slightly de-syncs client timer from server, corrected on next sync packet + fun increase(): ArgumentBuilder = + Commands.literal("increase") + .executes{ ctx -> + val target = EntityArgument.getPlayer(ctx, "player") + warTimerMap[target]?.let { + val increase = it.first.third + 30 + warTimerMap.put(target, Triple(it.first.first, 41, increase) to (it.second.first to true)) + PacketHandler.NETWORK.send( + PacketDistributor.PLAYER.with { target }, + WarTimerIncrementPacket(true, increase) + ) + } + return@executes Command.SINGLE_SUCCESS + } + +// this throws invalid player data on join +// .then(Commands.argument("increase", CommandArguments.IntArgument()) +// .executes { ctx -> +// val target = EntityArgument.getPlayer(ctx, "player") +// val argument = ctx.getArgument("increase", Int::class.java) +// println("$argument") +// return@executes Command.SINGLE_SUCCESS +// } +// ) +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/network/PacketHandler.kt b/src/main/kotlin/breadmod/network/PacketHandler.kt index f64e3978..cf77ea85 100644 --- a/src/main/kotlin/breadmod/network/PacketHandler.kt +++ b/src/main/kotlin/breadmod/network/PacketHandler.kt @@ -6,6 +6,9 @@ import breadmod.network.clientbound.BeamPacket import breadmod.network.clientbound.CapabilitySideDataPacket import breadmod.network.clientbound.CapabilityTagDataPacket import breadmod.network.clientbound.tool_gun.ToolGunModeDataPacket +import breadmod.network.clientbound.war_timer.WarTimerIncrementPacket +import breadmod.network.clientbound.war_timer.WarTimerSynchronizationPacket +import breadmod.network.clientbound.war_timer.WarTimerTogglePacket import breadmod.network.common.tool_gun.creator.ToolGunCreatorDataRequestPacket import breadmod.network.serverbound.SoundBlockPacket import breadmod.network.serverbound.ToggleMachinePacket @@ -52,6 +55,20 @@ internal object PacketHandler { 3_000, ToolGunModeDataPacket::class.java, ToolGunModeDataPacket::encodeBuf, ToolGunModeDataPacket::decodeBuf, ToolGunModeDataPacket::handle ) + NETWORK.registerMessage( + 4_000, WarTimerTogglePacket::class.java, + WarTimerTogglePacket::encodeBuf, WarTimerTogglePacket::decodeBuf, WarTimerTogglePacket::handle + ) + NETWORK.registerMessage( + 4_001, WarTimerSynchronizationPacket::class.java, + WarTimerSynchronizationPacket::encodeBuf, WarTimerSynchronizationPacket::decodeBuf, + WarTimerSynchronizationPacket::handle + ) + NETWORK.registerMessage( + 4_002, WarTimerIncrementPacket::class.java, + WarTimerIncrementPacket::encodeBuf, WarTimerIncrementPacket::decodeBuf, + WarTimerIncrementPacket::handle + ) LOGGER.info("Registering serverbound message types") // Serverbound // diff --git a/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerIncrementPacket.kt b/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerIncrementPacket.kt new file mode 100644 index 00000000..bf20b060 --- /dev/null +++ b/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerIncrementPacket.kt @@ -0,0 +1,29 @@ +package breadmod.network.clientbound.war_timer + +import breadmod.client.gui.WarTickerClient +import breadmod.registry.sound.ModSounds +import breadmod.util.render.rgMinecraft +import net.minecraft.network.FriendlyByteBuf +import net.minecraftforge.network.NetworkEvent +import java.util.function.Supplier + +class WarTimerIncrementPacket(val isIncreasing: Boolean, val increaseTimer: Int) { + companion object { + fun encodeBuf(input: WarTimerIncrementPacket, buffer: FriendlyByteBuf) { + buffer.writeBoolean(input.isIncreasing) + .writeInt(input.increaseTimer) + } + + fun decodeBuf(input: FriendlyByteBuf): WarTimerIncrementPacket = + WarTimerIncrementPacket(input.readBoolean(), input.readInt()) + + fun handle(input: WarTimerIncrementPacket, ctx: Supplier) = ctx.get().let { + it.enqueueWork { + val player = rgMinecraft.player ?: return@enqueueWork + WarTickerClient.isIncreasing = input.isIncreasing + WarTickerClient.increasingTimer = input.increaseTimer + player.playSound(ModSounds.WAR_TIMER_UP.get(), 0.8f, 1.0f) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerSynchronizationPacket.kt b/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerSynchronizationPacket.kt new file mode 100644 index 00000000..bdda28b5 --- /dev/null +++ b/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerSynchronizationPacket.kt @@ -0,0 +1,30 @@ +package breadmod.network.clientbound.war_timer + +import breadmod.client.gui.WarTickerClient +import breadmod.registry.sound.ModSounds +import breadmod.util.render.rgMinecraft +import net.minecraft.network.FriendlyByteBuf +import net.minecraftforge.network.NetworkEvent +import java.util.function.Supplier + +class WarTimerSynchronizationPacket(val timeLeft: Int) { + companion object { + fun encodeBuf(input: WarTimerSynchronizationPacket, buffer: FriendlyByteBuf) { + buffer.writeVarInt(input.timeLeft) + } + + fun decodeBuf(input: FriendlyByteBuf): WarTimerSynchronizationPacket = + WarTimerSynchronizationPacket(input.readVarInt()) + + fun handle(input: WarTimerSynchronizationPacket, ctx: Supplier) = ctx.get().let { + it.enqueueWork { + if (it.sender == null) { + val player = rgMinecraft.player ?: return@enqueueWork + WarTickerClient.timer = input.timeLeft + player.playSound(ModSounds.WAR_TIMER.get(), 0.8f, 1f) + } + } + it.packetHandled = true + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerTogglePacket.kt b/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerTogglePacket.kt new file mode 100644 index 00000000..e8cc12c7 --- /dev/null +++ b/src/main/kotlin/breadmod/network/clientbound/war_timer/WarTimerTogglePacket.kt @@ -0,0 +1,26 @@ +package breadmod.network.clientbound.war_timer + +import breadmod.client.gui.WarTickerClient +import net.minecraft.network.FriendlyByteBuf +import net.minecraftforge.network.NetworkEvent +import java.util.function.Supplier + +class WarTimerTogglePacket(val isActive: Boolean) { + companion object { + fun encodeBuf(input: WarTimerTogglePacket, buffer: FriendlyByteBuf) { + buffer.writeBoolean(input.isActive) + } + + fun decodeBuf(input: FriendlyByteBuf): WarTimerTogglePacket = + WarTimerTogglePacket(input.readBoolean()) + + fun handle(input: WarTimerTogglePacket, ctx: Supplier) = ctx.get().let { + it.enqueueWork { + if (it.sender == null) { + WarTickerClient.active = input.isActive + } + } + it.packetHandled = true + } + } +} \ No newline at end of file