diff --git a/src/main/java/ru/dbotthepony/mc/otm/client/model/ExosuitModel.java b/src/main/java/ru/dbotthepony/mc/otm/client/model/ExosuitModel.java index 00d07f7d8..a3b528e85 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/client/model/ExosuitModel.java +++ b/src/main/java/ru/dbotthepony/mc/otm/client/model/ExosuitModel.java @@ -1,7 +1,9 @@ package ru.dbotthepony.mc.otm.client.model; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; +import net.minecraft.client.Minecraft; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.PlayerModel; import net.minecraft.client.model.geom.PartPose; @@ -19,8 +21,11 @@ import net.minecraft.client.renderer.entity.layers.RenderLayer; import net.minecraft.client.renderer.entity.player.PlayerRenderer; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.client.event.RenderPlayerEvent; +import org.joml.Vector3f; +import org.joml.Vector4f; import ru.dbotthepony.mc.otm.OverdriveThatMatters; import ru.dbotthepony.mc.otm.capability.MatteryCapability; +import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket; import javax.annotation.Nonnull; import java.util.Set; @@ -123,7 +128,9 @@ public final class ExosuitModel { return; } - if (cap.resolve().get().getHasExopack() && cap.resolve().get().getDisplayExopack()) { + var mattery = cap.resolve().get(); + + if (mattery.getHasExopack() && mattery.isExopackVisible()) { var model = getParentModel(); model.copyPropertiesTo(modelNormal); model.copyPropertiesTo(modelGlow); @@ -152,7 +159,7 @@ public final class ExosuitModel { ); } - if (cap.resolve().get().getExopackGlows()) { + if (mattery.getExopackGlows()) { modelGlow.renderToBuffer( poseStack, bufferSource.getBuffer(RenderType.entityTranslucentEmissive(texture)), @@ -171,6 +178,8 @@ public final class ExosuitModel { 1f, 1f, 1f, 1f ); } + + mattery.makeSmokeParticles(poseStack, model); } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt index fe281455d..ad4205e90 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/android/feature/JumpBoostFeature.kt @@ -1,53 +1,37 @@ package ru.dbotthepony.mc.otm.android.feature -import com.mojang.blaze3d.systems.RenderSystem -import com.mojang.blaze3d.vertex.PoseStack -import net.minecraft.ChatFormatting import net.minecraft.client.gui.GuiGraphics import net.minecraft.core.particles.ParticleTypes import net.minecraft.network.FriendlyByteBuf -import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer import net.minecraft.sounds.SoundSource import net.minecraft.util.RandomSource import net.minecraft.world.level.Level -import net.minecraft.world.phys.Vec3 import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor.TargetPoint import ru.dbotthepony.mc.otm.config.ClientConfig -import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.config.AndroidConfig -import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact import ru.dbotthepony.mc.otm.capability.matteryPlayer -import ru.dbotthepony.mc.otm.client.ShiftPressedCond import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.render.ResearchIcons import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.Vector -import ru.dbotthepony.mc.otm.core.math.component1 -import ru.dbotthepony.mc.otm.core.math.component2 -import ru.dbotthepony.mc.otm.core.math.component3 -import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.core.math.plus +import ru.dbotthepony.mc.otm.network.GenericNetworkChannel import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel +import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket 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.registry.AndroidFeatures -import ru.dbotthepony.mc.otm.registry.MNames import ru.dbotthepony.mc.otm.registry.MSoundEvents import java.util.function.Supplier -private fun makeSmoke(x: Double, y: Double, z: Double, random: RandomSource, level: Level) { - for (i in 0 .. random.nextInt(4, 8)) - level.addParticle(ParticleTypes.POOF, x + random.nextDouble() * 0.5 - 0.25, y + random.nextDouble() * 0.5 - 0.25, z + random.nextDouble() * 0.5 - 0.25, random.nextGaussian() * 0.02, random.nextGaussian() * 0.02, random.nextGaussian() * 0.02) -} - object TriggerJumpBoostPacket : MatteryPacket { override fun write(buff: FriendlyByteBuf) { // no op @@ -74,36 +58,13 @@ object TriggerJumpBoostPacket : MatteryPacket { 1f, 1f ) - MatteryPlayerNetworkChannel.send(PacketDistributor.NEAR.with { TargetPoint(it, it.x, it.y, it.z, 64.0, it.level().dimension()) }, JumpBoostParticlesPacket(it.x, it.y, it.z)) + GenericNetworkChannel.makeSmoke(it, it.x, it.y, it.z) } } } } } -class JumpBoostParticlesPacket(val x: Double, val y: Double, val z: Double) : MatteryPacket { - override fun write(buff: FriendlyByteBuf) { - buff.writeDouble(x) - buff.writeDouble(y) - buff.writeDouble(z) - } - - override fun play(context: Supplier) { - context.packetHandled = true - context.enqueueWork { - minecraft.player?.level()?.let { - makeSmoke(x, y, z, it.random, it) - } - } - } - - companion object { - fun read(buff: FriendlyByteBuf): JumpBoostParticlesPacket { - return JumpBoostParticlesPacket(buff.readDouble(), buff.readDouble(), buff.readDouble()) - } - } -} - class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.JUMP_BOOST, capability) { private var tickCooldownClient = false @@ -141,7 +102,7 @@ class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF 1f, 1f ) - makeSmoke(ply.x, ply.y, ply.z, ply.random, ply.level()) + SmokeParticlesPacket.makeSmoke(ply.x, ply.y, ply.z, ply.random, ply.level()) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index d8c72c869..1764341f0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -1,11 +1,17 @@ package ru.dbotthepony.mc.otm.capability +import com.mojang.blaze3d.systems.RenderSystem +import com.mojang.blaze3d.vertex.PoseStack import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import net.minecraft.ChatFormatting +import net.minecraft.client.Minecraft +import net.minecraft.client.model.PlayerModel +import net.minecraft.client.player.AbstractClientPlayer import net.minecraft.commands.Commands import net.minecraft.commands.arguments.EntityArgument import net.minecraft.core.Direction +import net.minecraft.core.particles.ParticleTypes import net.minecraft.nbt.ByteTag import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.IntTag @@ -52,18 +58,20 @@ import net.minecraftforge.event.entity.living.MobEffectEvent import net.minecraftforge.event.entity.player.PlayerEvent import net.minecraftforge.eventbus.api.Cancelable import net.minecraftforge.eventbus.api.Event +import net.minecraftforge.network.PacketDistributor import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.server.command.EnumArgument import org.apache.logging.log4j.LogManager +import org.joml.Vector4f import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.android.AndroidFeature import ru.dbotthepony.mc.otm.android.AndroidFeatureType import ru.dbotthepony.mc.otm.android.AndroidResearch import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.AndroidResearchType +import ru.dbotthepony.mc.otm.block.entity.ItemJob import ru.dbotthepony.mc.otm.block.entity.JobContainer import ru.dbotthepony.mc.otm.block.entity.JobStatus -import ru.dbotthepony.mc.otm.block.entity.ItemJob import ru.dbotthepony.mc.otm.block.entity.MachineJobEventLoop import ru.dbotthepony.mc.otm.capability.energy.BatteryBackedEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage @@ -83,7 +91,11 @@ import ru.dbotthepony.mc.otm.core.collect.UUIDIntModifiersMap import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.RGBAColor +import ru.dbotthepony.mc.otm.core.math.component1 +import ru.dbotthepony.mc.otm.core.math.component2 +import ru.dbotthepony.mc.otm.core.math.component3 import ru.dbotthepony.mc.otm.core.math.minus +import ru.dbotthepony.mc.otm.core.math.toRadians import ru.dbotthepony.mc.otm.core.nbt.getByteList import ru.dbotthepony.mc.otm.core.nbt.getCompoundList import ru.dbotthepony.mc.otm.core.nbt.getIntList @@ -98,6 +110,7 @@ import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.network.* +import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket.Companion.makeSmoke import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.MDamageTypes @@ -116,8 +129,8 @@ import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger import java.util.* import java.util.stream.Stream import kotlin.collections.ArrayDeque -import kotlin.collections.ArrayList -import kotlin.collections.HashMap +import kotlin.math.cos +import kotlin.math.sin import kotlin.reflect.KMutableProperty1 private fun Player.dropContainer(container: Container, spill: Boolean = true, setThrower: Boolean = false) { @@ -209,7 +222,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial /** * Whenever to render Exopack on player */ - var displayExopack by publicSynchronizer.bool(true).property + var isExopackVisible by publicSynchronizer.bool(true).property /** * Whenever to render Exopack glow in dark @@ -376,6 +389,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial private var wasInLiquid = false private var lastDimension = ResourceLocation("overworld") + // clientside only flag for render hook + // TODO: actual code, currently particles spawn just behind player on ExopackSmokePacket + var spawnExopackSmoke = false + /** * Whenever player should become an Android once transformation conditions are met (e.g. player dies or sleeps in bed) */ @@ -446,6 +463,14 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial } } + override fun onJobTick(status: JobStatus) { + super.onJobTick(status) + + if (isExopackVisible && ply.level().random.nextFloat() <= 0.05f) { + MatteryPlayerNetworkChannel.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with { ply as ServerPlayer }, ExopackSmokePacket(ply.uuid)) + } + } + val input = MatteryContainer({ notify(IdleReason.ITEM) }, 1) val output = MatteryContainer({ notify(IdleReason.ITEM) }, 1) @@ -484,7 +509,7 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial savetables.bool(::isAndroid) savetables.bool(::willBecomeAndroid) savetables.bool(::hasExopack, "hasExoSuit") - savetables.bool(::displayExopack, "displayExoSuit") + savetables.bool(::isExopackVisible, "displayExoSuit") savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded") savetables.int(::nextDischargeHurt) savetables.int(::nextHealTick) @@ -1431,6 +1456,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial return stack.isEmpty } + fun makeSmokeParticles(poseStack: PoseStack, model: PlayerModel) { + if (spawnExopackSmoke) { + spawnExopackSmoke = false + + // TODO: Proper positioning + + val pos = Vector4f(model.body.x / 16f, model.body.y / 16f, model.body.z / 16f, 1f) + val cam = minecraft.gameRenderer.mainCamera.position + + pos.mul(RenderSystem.getProjectionMatrix()) + pos.mul(poseStack.last().pose()) + makeSmoke(cam.x + pos.x, cam.y + pos.y, cam.z + pos.z, ply.level().random, ply.level()) + } + } + enum class UpgradeType(val prop: KMutableProperty1) { CRAFTING(MatteryPlayerCapability::isExopackCraftingUpgraded), SMELTING(MatteryPlayerCapability::isExopackSmeltingInstalled); diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt index 018db7198..3d33f11ff 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded import ru.dbotthepony.mc.otm.compat.curios.openCuriosScreen import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu -import ru.dbotthepony.mc.otm.network.ExoPackMenuOpen +import ru.dbotthepony.mc.otm.network.ExopackMenuOpen import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak @@ -238,7 +238,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen, matteryPlaye text = TranslatableComponent("otm.gui.exopack.toggle_visibility"), isChecked = GetterSetter.of( { - matteryPlayer.displayExopack + matteryPlayer.isExopackVisible }, { if (it) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt index 27810de27..e671e5a9a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt @@ -14,9 +14,9 @@ import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.container.iterator import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget -import ru.dbotthepony.mc.otm.network.ExoSuitCarriedPacket -import ru.dbotthepony.mc.otm.network.ExoSuitMenuInitPacket -import ru.dbotthepony.mc.otm.network.ExoSuitSlotPacket +import ru.dbotthepony.mc.otm.network.ExopackCarriedPacket +import ru.dbotthepony.mc.otm.network.ExopackMenuInitPacket +import ru.dbotthepony.mc.otm.network.ExopackSlotPacket import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel class ExopackInventoryMenu(val capability: MatteryPlayerCapability) : MatteryMenu(null, CONTAINER_ID, capability.ply.inventory) { @@ -223,16 +223,16 @@ class ExopackInventoryMenu(val capability: MatteryPlayerCapability) : MatteryMen } fun sendInitialData(container: ExopackInventoryMenu, itemStacks: NonNullList, carried: ItemStack, remoteDataSlots: IntArray) { - MatteryPlayerNetworkChannel.send(container.ply as ServerPlayer, ExoSuitMenuInitPacket(itemStacks, carried, container.incrementStateId())) + MatteryPlayerNetworkChannel.send(container.ply as ServerPlayer, ExopackMenuInitPacket(itemStacks, carried, container.incrementStateId())) } fun sendSlotChange(container: ExopackInventoryMenu, slotId: Int, itemStack: ItemStack) { if (container.slots[slotId].container != container.ply.inventory || container.ply.containerMenu is ExopackInventoryMenu) - MatteryPlayerNetworkChannel.send(container.ply as ServerPlayer, ExoSuitSlotPacket(slotId, itemStack, container.stateId)) + MatteryPlayerNetworkChannel.send(container.ply as ServerPlayer, ExopackSlotPacket(slotId, itemStack, container.stateId)) } fun sendCarriedChange(container: ExopackInventoryMenu, itemStack: ItemStack) { - MatteryPlayerNetworkChannel.send(container.ply as ServerPlayer, ExoSuitCarriedPacket(itemStack, container.stateId)) + MatteryPlayerNetworkChannel.send(container.ply as ServerPlayer, ExopackCarriedPacket(itemStack, container.stateId)) } fun sendDataChange(container: ExopackInventoryMenu, dataSlotId: Int, shortData: Int) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/GenericNetworkChannel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/GenericNetworkChannel.kt index c98aa769d..c27a9be9e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/GenericNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/GenericNetworkChannel.kt @@ -4,10 +4,14 @@ import it.unimi.dsi.fastutil.io.FastByteArrayInputStream import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap import net.minecraft.core.BlockPos +import net.minecraft.core.particles.ParticleTypes import net.minecraft.network.FriendlyByteBuf +import net.minecraft.server.level.ServerPlayer +import net.minecraft.util.RandomSource import net.minecraft.world.level.Level import net.minecraftforge.network.NetworkDirection import net.minecraftforge.network.NetworkEvent +import net.minecraftforge.network.PacketDistributor import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket @@ -20,6 +24,34 @@ import java.util.* import java.util.function.Supplier import kotlin.collections.ArrayList +class SmokeParticlesPacket(val x: Double, val y: Double, val z: Double) : MatteryPacket { + override fun write(buff: FriendlyByteBuf) { + buff.writeDouble(x) + buff.writeDouble(y) + buff.writeDouble(z) + } + + override fun play(context: Supplier) { + context.packetHandled = true + context.enqueueWork { + minecraft.player?.level()?.let { + makeSmoke(x, y, z, it.random, it) + } + } + } + + companion object { + fun read(buff: FriendlyByteBuf): SmokeParticlesPacket { + return SmokeParticlesPacket(buff.readDouble(), buff.readDouble(), buff.readDouble()) + } + + fun makeSmoke(x: Double, y: Double, z: Double, random: RandomSource, level: Level) { + for (i in 0 .. random.nextInt(4, 8)) + level.addParticle(ParticleTypes.POOF, x + random.nextDouble() * 0.5 - 0.25, y + random.nextDouble() * 0.5 - 0.25, z + random.nextDouble() * 0.5 - 0.25, random.nextGaussian() * 0.02, random.nextGaussian() * 0.02, random.nextGaussian() * 0.02) + } + } +} + class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val validBytes: Int) : MatteryPacket { override fun write(buff: FriendlyByteBuf) { buff.writeBlockPos(position) @@ -96,9 +128,17 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v } object GenericNetworkChannel : MatteryNetworkChannel( - version = "3", + version = "4", name = "generic" ) { + fun makeSmoke(x: Double, y: Double, z: Double, level: Level) { + send(PacketDistributor.NEAR.with { PacketDistributor.TargetPoint(x, y, z, 64.0, level.dimension()) }, SmokeParticlesPacket(x, y, z)) + } + + fun makeSmoke(excluded: ServerPlayer, x: Double, y: Double, z: Double) { + send(PacketDistributor.NEAR.with { PacketDistributor.TargetPoint(excluded, x, y, z, 64.0, excluded.level().dimension()) }, SmokeParticlesPacket(x, y, z)) + } + fun register() { add(QuantumBatteryItem.ChargePacket::class.java, QuantumBatteryItem.Companion::readPacket, NetworkDirection.PLAY_TO_CLIENT) @@ -107,5 +147,7 @@ object GenericNetworkChannel : MatteryNetworkChannel( add(AndroidResearchManager.SyncPacket::class.java, AndroidResearchManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT) add(MatterManager.SyncPacket::class.java, MatterManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT) + + add(SmokeParticlesPacket::class, SmokeParticlesPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) } } 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 4a0fbfc06..d15d9ed8f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryNetworkChannel.kt @@ -122,6 +122,15 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) { @Volatile private var interrupt = false + /** + * Reason behind separate thread is that Minecraft connection class does not allow to enqueue messages, + * nor does Forge. This leads to extensive calls to Netty Channel eventLoop().execute(), which is somehow resource + * heavy, as it calls wakeup on Windows, eventFdWrite on Linux, etc., when all we want to do is to enqueue packet. + * + * Concurrent safety - Minecraft Channel (send method) does not do any writes (unless player is unconnected, in which case it uses thread safe queue), hence it is thread safe. + * OTM packets are always dispatched in correct order to client. + * Netty eventLoop executor is thread safe by definition. + */ private fun run() { while (!interrupt) { val task = queue.pollFirst() 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 9015b11c4..067fb58a3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerNetworkChannel.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.mc.otm.network import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream +import net.minecraft.core.particles.ParticleTypes import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket @@ -16,7 +17,6 @@ import ru.dbotthepony.mc.otm.android.AndroidFeatureType import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.AndroidResearchType import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature -import ru.dbotthepony.mc.otm.android.feature.JumpBoostParticlesPacket import ru.dbotthepony.mc.otm.android.feature.TriggerJumpBoostPacket import ru.dbotthepony.mc.otm.android.feature.TriggerShockwavePacket import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability @@ -29,6 +29,11 @@ import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.Vector +import ru.dbotthepony.mc.otm.core.math.component1 +import ru.dbotthepony.mc.otm.core.math.component2 +import ru.dbotthepony.mc.otm.core.math.component3 +import ru.dbotthepony.mc.otm.core.math.toRadians +import ru.dbotthepony.mc.otm.core.position import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.registry.AndroidFeatures @@ -223,7 +228,7 @@ class PlayerIterationPacket(val iteration: Int, val deathLog: List, val carried: ItemStack, val containerState: Int) : MatteryPacket { +class ExopackMenuInitPacket(val slots: List, val carried: ItemStack, val containerState: Int) : MatteryPacket { override fun write(buff: FriendlyByteBuf) { buff.writeInt(slots.size) @@ -316,7 +321,7 @@ class ExoSuitMenuInitPacket(val slots: List, val carried: ItemStack, } companion object { - fun read(buff: FriendlyByteBuf): ExoSuitMenuInitPacket { + fun read(buff: FriendlyByteBuf): ExopackMenuInitPacket { val size = buff.readInt() val slots = ArrayList(size) @@ -327,12 +332,12 @@ class ExoSuitMenuInitPacket(val slots: List, val carried: ItemStack, val carried = buff.readItem() val containerState = buff.readInt() - return ExoSuitMenuInitPacket(slots, carried, containerState) + return ExopackMenuInitPacket(slots, carried, containerState) } } } -object ExoPackMenuOpen : MatteryPacket { +object ExopackMenuOpen : MatteryPacket { override fun write(buff: FriendlyByteBuf) {} override fun play(context: Supplier) { @@ -499,7 +504,7 @@ object DisplayExopackPacket : MatteryPacket { override fun play(context: Supplier) { context.packetHandled = true - context.sender?.matteryPlayer?.displayExopack = true + context.sender?.matteryPlayer?.isExopackVisible = true } } @@ -508,7 +513,7 @@ object HideExopackPacket : MatteryPacket { override fun play(context: Supplier) { context.packetHandled = true - context.sender?.matteryPlayer?.displayExopack = false + context.sender?.matteryPlayer?.isExopackVisible = false } } @@ -558,8 +563,53 @@ data class SetExopackColorPacket(val color: RGBAColor) : MatteryPacket { } } +data class ExopackSmokePacket(val player: UUID) : MatteryPacket { + override fun write(buff: FriendlyByteBuf) { + buff.writeUUID(player) + } + + override fun play(context: Supplier) { + context.packetHandled = true + // minecraft.player?.level()?.getPlayerByUUID(player)?.matteryPlayer?.spawnExopackSmoke = true + + context.enqueueWork { + minecraft.player?.level()?.getPlayerByUUID(player)?.let { ply -> + if (ply != minecraft.player || minecraft.gameRenderer.mainCamera.isDetached) { + var (x, y, z) = ply.position + + y += 1.5 + val deg = toRadians(ply.yBodyRot + 90f) + + x += kotlin.math.cos(deg) * -0.4 + z += kotlin.math.sin(deg) * -0.4 + + val level = ply.level() + val random = level.random + + for (i in 0 .. random.nextInt(2, 4)) + level.addParticle( + ParticleTypes.SMOKE, + x + random.nextDouble() * 0.4 - 0.2, + y + random.nextDouble() * 0.4 - 0.2, + z + random.nextDouble() * 0.4 - 0.2, + random.nextGaussian() * 0.02, + random.nextGaussian() * 0.02, + random.nextGaussian() * 0.02) + } + } + } + + } + + companion object { + fun read(buff: FriendlyByteBuf): ExopackSmokePacket { + return ExopackSmokePacket(buff.readUUID()) + } + } +} + object MatteryPlayerNetworkChannel : MatteryNetworkChannel( - version = "5", + version = "6", name = "player" ) { fun register() { @@ -572,18 +622,18 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel( add(PlayerIterationPacket::class, PlayerIterationPacket.Companion::read, PLAY_TO_CLIENT) - add(ExoSuitCarriedPacket::class, ExoSuitCarriedPacket.Companion::read, PLAY_TO_CLIENT) - add(ExoSuitSlotPacket::class, ExoSuitSlotPacket.Companion::read, PLAY_TO_CLIENT) - add(ExoSuitMenuInitPacket::class, ExoSuitMenuInitPacket.Companion::read, PLAY_TO_CLIENT) + add(ExopackCarriedPacket::class, ExopackCarriedPacket.Companion::read, PLAY_TO_CLIENT) + add(ExopackSlotPacket::class, ExopackSlotPacket.Companion::read, PLAY_TO_CLIENT) + add(ExopackMenuInitPacket::class, ExopackMenuInitPacket.Companion::read, PLAY_TO_CLIENT) + add(ExopackSmokePacket::class, ExopackSmokePacket.Companion::read, PLAY_TO_CLIENT) - add(ExoPackMenuOpen::class, { ExoPackMenuOpen }, PLAY_TO_SERVER) + add(ExopackMenuOpen::class, { ExopackMenuOpen }, PLAY_TO_SERVER) add(SwitchAndroidFeaturePacket::class, SwitchAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER) add(ActivateAndroidFeaturePacket::class, ActivateAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER) add(TriggerShockwavePacket::class, { TriggerShockwavePacket }, PLAY_TO_SERVER) add(TriggerJumpBoostPacket::class, { TriggerJumpBoostPacket }, PLAY_TO_SERVER) - add(JumpBoostParticlesPacket::class, JumpBoostParticlesPacket.Companion::read, PLAY_TO_CLIENT) add(PickItemFromInventoryPacket::class, PickItemFromInventoryPacket.Companion::read, PLAY_TO_SERVER)