From e15c4261351a15e8aa73b66e79bfda7e8b4adc7a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 17 Oct 2022 11:25:14 +0700 Subject: [PATCH] Shockwave visual effects or something Fixes #118 --- .../mc/otm/OverdriveThatMatters.java | 4 +- .../otm/android/feature/ShockwaveFeature.kt | 7 +- .../mc/otm/client/render/ShockwaveRenderer.kt | 87 +++++++++++++++++++ .../mc/otm/network/MatteryNetworkChannel.kt | 18 ++++ .../network/MatteryPlayerNetworkChannel.kt | 24 +++++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ShockwaveRenderer.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index c30344635..47389689f 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -18,7 +18,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import ru.dbotthepony.mc.otm.android.AndroidResearchManager; import ru.dbotthepony.mc.otm.android.feature.EnderTeleporterFeature; -import ru.dbotthepony.mc.otm.android.feature.NanobotsArmorFeature; import ru.dbotthepony.mc.otm.block.entity.SynchronizedBlockEntity; import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue; import ru.dbotthepony.mc.otm.capability.MatteryCapability; @@ -31,6 +30,7 @@ import ru.dbotthepony.mc.otm.client.ClientTickHandlerKt; import ru.dbotthepony.mc.otm.client.MatteryGUI; import ru.dbotthepony.mc.otm.client.model.GravitationStabilizerModel; import ru.dbotthepony.mc.otm.client.model.TritaniumArmorModel; +import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer; import ru.dbotthepony.mc.otm.client.render.WidgetAtlasHolder; import ru.dbotthepony.mc.otm.compat.mekanism.QIOKt; import ru.dbotthepony.mc.otm.compat.mekanism.TooltipsKt; @@ -179,6 +179,8 @@ public final class OverdriveThatMatters { EVENT_BUS.addListener(EventPriority.NORMAL, MatteryGUI.INSTANCE::onRenderGuiEvent); EVENT_BUS.addListener(EventPriority.HIGH, MatteryGUI.INSTANCE::onLayerRenderEvent); + EVENT_BUS.addListener(EventPriority.NORMAL, ShockwaveRenderer.INSTANCE::onRender); + EVENT_BUS.addListener(EventPriority.NORMAL, ClientEventHandlerKt::onMovementInputUpdate); EVENT_BUS.addListener(EventPriority.NORMAL, ClientEventHandlerKt::onScreenOpen); EVENT_BUS.addListener(EventPriority.NORMAL, ClientEventHandlerKt::onPostScreenInit); diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt index ac2cd0b1b..30d50a2fb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/ShockwaveFeature.kt @@ -31,9 +31,11 @@ import ru.dbotthepony.mc.otm.core.times import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.network.MatteryPacket +import ru.dbotthepony.mc.otm.network.ShockwaveEffectPacket import ru.dbotthepony.mc.otm.network.enqueueWork import ru.dbotthepony.mc.otm.network.packetHandled import ru.dbotthepony.mc.otm.network.sender +import ru.dbotthepony.mc.otm.onceServer import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.ShockwaveDamageSource @@ -54,7 +56,9 @@ object TriggerShockwavePacket : MatteryPacket { val shockwave = context.sender?.matteryPlayer?.getFeature(AndroidFeatures.SHOCKWAVE) as ShockwaveFeature? ?: return@enqueueWork if (!shockwave.isOnCooldown && shockwave.isActive && shockwave.airTicks > 0) { - shockwave.shockwave() + onceServer { // delay by one tick so player update its position as well + shockwave.shockwave() + } } } } @@ -93,6 +97,7 @@ class ShockwaveFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF if (ply is ServerPlayer) { ShockwaveTrigger.trigger(ply as ServerPlayer) + MatteryPlayerNetworkChannel.sendTrackingAndSelf(ply, ShockwaveEffectPacket(ply.position)) } // TODO: raycasting diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ShockwaveRenderer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ShockwaveRenderer.kt new file mode 100644 index 000000000..0829467e5 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/ShockwaveRenderer.kt @@ -0,0 +1,87 @@ +package ru.dbotthepony.mc.otm.client.render + +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.BufferUploader +import com.mojang.blaze3d.vertex.DefaultVertexFormat +import com.mojang.blaze3d.vertex.VertexFormat +import com.mojang.math.Vector3f +import net.minecraft.client.renderer.GameRenderer +import net.minecraftforge.client.event.RenderLevelStageEvent +import org.lwjgl.opengl.GL11.GL_LESS +import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.core.Vector +import ru.dbotthepony.mc.otm.core.component1 +import ru.dbotthepony.mc.otm.core.component2 +import ru.dbotthepony.mc.otm.core.component3 +import ru.dbotthepony.mc.otm.core.linearInterpolation +import ru.dbotthepony.mc.otm.core.position +import ru.dbotthepony.mc.otm.network.ShockwaveEffectPacket +import kotlin.math.PI + +object ShockwaveRenderer { + private val activeShockwaves = ArrayList() + + private class State(val pos: Vector, val finalRadius: Float = 6f) { + var radius = 0f + var lastRender = System.nanoTime() + + init { + synchronized(activeShockwaves) { + activeShockwaves.add(this) + } + } + + fun render(event: RenderLevelStageEvent): Boolean { + val diff = System.nanoTime() - lastRender + + radius += diff / (1_000_000_000f / EXPANSION_PER_SECOND) + lastRender = System.nanoTime() + + if (radius <= finalRadius) { + val builder = tesselator.builder + + RenderSystem.setShader(GameRenderer::getPositionShader) + RenderSystem.setShaderColor(1f, 1f, 1f, linearInterpolation(radius / finalRadius, 0.5f, 0f)) + RenderSystem.defaultBlendFunc() + RenderSystem.enableBlend() + RenderSystem.enableDepthTest() + RenderSystem.depthFunc(GL_LESS) + + builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION) + + event.poseStack.pushPose() + val (x, y, z) = event.camera.position + event.poseStack.translate(pos.x - x, pos.y - y + 0.1f, pos.z - z) // render slightly above landed position + event.poseStack.mulPose(Vector3f.XP.rotation(PI.toFloat() / 2f)) + uploadArc(event.poseStack.last.pose, builder, x = 0f, y = 0f, innerRadius = (radius - 1f).coerceAtLeast(0f), outerRadius = radius, triangleFan = false) + event.poseStack.popPose() + + BufferUploader.drawWithShader(builder.end()) + } + + return radius <= finalRadius + } + } + + private const val EXPANSION_PER_SECOND = 18f + + fun onRender(event: RenderLevelStageEvent) { + if (event.stage !== RenderLevelStageEvent.Stage.AFTER_TRANSLUCENT_BLOCKS) { + return + } + + synchronized(activeShockwaves) { + val iterator = activeShockwaves.listIterator() + + for (value in iterator) { + if (!value.render(event)) { + iterator.remove() + } + } + } + } + + fun handle(packet: ShockwaveEffectPacket) { + State(packet.pos) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt index d238dc8b1..00f8ae47a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt @@ -4,12 +4,14 @@ import java.util.function.Function import net.minecraft.network.FriendlyByteBuf import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.Entity import net.minecraft.world.entity.player.Player import net.minecraftforge.network.NetworkDirection import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkRegistry import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.simple.SimpleChannel +import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.OverdriveThatMatters import java.math.BigDecimal import java.math.BigInteger @@ -61,6 +63,22 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) { } } + fun sendTracking(entity: Entity, packet: Any) { + if ((NULLABLE_MINECRAFT_SERVER?.playerCount ?: 0) <= 0) { + return + } + + channel.send(PacketDistributor.TRACKING_ENTITY.with { entity }, packet) + } + + fun sendTrackingAndSelf(entity: Entity, packet: Any) { + if ((NULLABLE_MINECRAFT_SERVER?.playerCount ?: 0) <= 0) { + return + } + + channel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with { entity }, packet) + } + fun send(distributor: PacketDistributor.PacketTarget, packet: Any) = channel.send(distributor, packet) private var nextNetworkPacketID = 0 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt index 834c53ddb..40352588e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt @@ -6,12 +6,14 @@ import net.minecraft.network.chat.Component import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.Entity import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.minecraftforge.network.NetworkDirection.PLAY_TO_CLIENT import net.minecraftforge.network.NetworkDirection.PLAY_TO_SERVER import net.minecraftforge.network.NetworkEvent +import net.minecraftforge.network.PacketDistributor import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.android.AndroidActiveFeature import ru.dbotthepony.mc.otm.android.AndroidFeatureType @@ -24,8 +26,10 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.MatteryGUI import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.render.GlitchRenderer +import ru.dbotthepony.mc.otm.client.render.ShockwaveRenderer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.core.Vector import ru.dbotthepony.mc.otm.menu.AndroidStationMenu import ru.dbotthepony.mc.otm.menu.ExoSuitInventoryMenu import ru.dbotthepony.mc.otm.registry.AndroidFeatures @@ -448,6 +452,25 @@ class GlitchPacket(val millis: Long) : MatteryPacket { } } +class ShockwaveEffectPacket(val pos: Vector) : MatteryPacket { + override fun write(buff: FriendlyByteBuf) { + buff.writeDouble(pos.x) + buff.writeDouble(pos.y) + buff.writeDouble(pos.z) + } + + override fun play(context: Supplier) { + context.packetHandled = true + ShockwaveRenderer.handle(this) + } + + companion object { + fun read(buff: FriendlyByteBuf): ShockwaveEffectPacket { + return ShockwaveEffectPacket(Vector(buff.readDouble(), buff.readDouble(), buff.readDouble())) + } + } +} + object MatteryPlayerNetworkChannel : MatteryNetworkChannel( version = "1", name = "player" @@ -477,5 +500,6 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel( add(PickItemFromInventoryPacket::class, PickItemFromInventoryPacket.Companion::read, PLAY_TO_SERVER) add(GlitchPacket::class, GlitchPacket.Companion::read, PLAY_TO_CLIENT) + add(ShockwaveEffectPacket::class, ShockwaveEffectPacket.Companion::read, PLAY_TO_CLIENT) } }