Exopack smoke particles when furnace is working

This commit is contained in:
DBotThePony 2023-07-30 00:54:07 +07:00
parent fc715da518
commit bfc7947a62
Signed by: DBot
GPG Key ID: DCC23B5715498507
9 changed files with 190 additions and 79 deletions

View File

@ -1,7 +1,9 @@
package ru.dbotthepony.mc.otm.client.model; package ru.dbotthepony.mc.otm.client.model;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import net.minecraft.client.Minecraft;
import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.model.PlayerModel; import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.PartPose; 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.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.client.event.RenderPlayerEvent; 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.OverdriveThatMatters;
import ru.dbotthepony.mc.otm.capability.MatteryCapability; import ru.dbotthepony.mc.otm.capability.MatteryCapability;
import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.Set; import java.util.Set;
@ -123,7 +128,9 @@ public final class ExosuitModel {
return; return;
} }
if (cap.resolve().get().getHasExopack() && cap.resolve().get().getDisplayExopack()) { var mattery = cap.resolve().get();
if (mattery.getHasExopack() && mattery.isExopackVisible()) {
var model = getParentModel(); var model = getParentModel();
model.copyPropertiesTo(modelNormal); model.copyPropertiesTo(modelNormal);
model.copyPropertiesTo(modelGlow); model.copyPropertiesTo(modelGlow);
@ -152,7 +159,7 @@ public final class ExosuitModel {
); );
} }
if (cap.resolve().get().getExopackGlows()) { if (mattery.getExopackGlows()) {
modelGlow.renderToBuffer( modelGlow.renderToBuffer(
poseStack, poseStack,
bufferSource.getBuffer(RenderType.entityTranslucentEmissive(texture)), bufferSource.getBuffer(RenderType.entityTranslucentEmissive(texture)),
@ -171,6 +178,8 @@ public final class ExosuitModel {
1f, 1f, 1f, 1f 1f, 1f, 1f, 1f
); );
} }
mattery.makeSmokeParticles(poseStack, model);
} }
} }
} }

View File

@ -1,53 +1,37 @@
package ru.dbotthepony.mc.otm.android.feature 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.client.gui.GuiGraphics
import net.minecraft.core.particles.ParticleTypes import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.sounds.SoundSource import net.minecraft.sounds.SoundSource
import net.minecraft.util.RandomSource import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraft.world.phys.Vec3
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.network.PacketDistributor.TargetPoint import net.minecraftforge.network.PacketDistributor.TargetPoint
import ru.dbotthepony.mc.otm.config.ClientConfig 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.config.AndroidConfig
import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability
import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact import ru.dbotthepony.mc.otm.capability.energy.extractEnergyExact
import ru.dbotthepony.mc.otm.capability.matteryPlayer 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.minecraft
import ru.dbotthepony.mc.otm.client.render.ResearchIcons import ru.dbotthepony.mc.otm.client.render.ResearchIcons
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.Vector 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.core.math.plus
import ru.dbotthepony.mc.otm.network.GenericNetworkChannel
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel 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.enqueueWork
import ru.dbotthepony.mc.otm.network.packetHandled import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender import ru.dbotthepony.mc.otm.network.sender
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MNames
import ru.dbotthepony.mc.otm.registry.MSoundEvents import ru.dbotthepony.mc.otm.registry.MSoundEvents
import java.util.function.Supplier 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 { object TriggerJumpBoostPacket : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
// no op // no op
@ -74,36 +58,13 @@ object TriggerJumpBoostPacket : MatteryPacket {
1f, 1f 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<NetworkEvent.Context>) {
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) { class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableFeature(AndroidFeatures.JUMP_BOOST, capability) {
private var tickCooldownClient = false private var tickCooldownClient = false
@ -141,7 +102,7 @@ class JumpBoostFeature(capability: MatteryPlayerCapability) : AndroidSwitchableF
1f, 1f 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())
} }
} }

View File

@ -1,11 +1,17 @@
package ru.dbotthepony.mc.otm.capability 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.ints.IntAVLTreeSet
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap
import net.minecraft.ChatFormatting 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.Commands
import net.minecraft.commands.arguments.EntityArgument import net.minecraft.commands.arguments.EntityArgument
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.nbt.ByteTag import net.minecraft.nbt.ByteTag
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.IntTag 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.event.entity.player.PlayerEvent
import net.minecraftforge.eventbus.api.Cancelable import net.minecraftforge.eventbus.api.Cancelable
import net.minecraftforge.eventbus.api.Event import net.minecraftforge.eventbus.api.Event
import net.minecraftforge.network.PacketDistributor
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.server.command.EnumArgument import net.minecraftforge.server.command.EnumArgument
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import org.joml.Vector4f
import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.*
import ru.dbotthepony.mc.otm.android.AndroidFeature import ru.dbotthepony.mc.otm.android.AndroidFeature
import ru.dbotthepony.mc.otm.android.AndroidFeatureType import ru.dbotthepony.mc.otm.android.AndroidFeatureType
import ru.dbotthepony.mc.otm.android.AndroidResearch import ru.dbotthepony.mc.otm.android.AndroidResearch
import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.AndroidResearchType 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.JobContainer
import ru.dbotthepony.mc.otm.block.entity.JobStatus 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.block.entity.MachineJobEventLoop
import ru.dbotthepony.mc.otm.capability.energy.BatteryBackedEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.BatteryBackedEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage 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.collect.filter
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.math.RGBAColor 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.minus
import ru.dbotthepony.mc.otm.core.math.toRadians
import ru.dbotthepony.mc.otm.core.nbt.getByteList import ru.dbotthepony.mc.otm.core.nbt.getByteList
import ru.dbotthepony.mc.otm.core.nbt.getCompoundList import ru.dbotthepony.mc.otm.core.nbt.getCompoundList
import ru.dbotthepony.mc.otm.core.nbt.getIntList 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.core.util.VarIntValueCodec
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
import ru.dbotthepony.mc.otm.network.* 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.network.synchronizer.FieldSynchronizer
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
import ru.dbotthepony.mc.otm.registry.MDamageTypes import ru.dbotthepony.mc.otm.registry.MDamageTypes
@ -116,8 +129,8 @@ import ru.dbotthepony.mc.otm.triggers.ExopackSlotsExpandedTrigger
import java.util.* import java.util.*
import java.util.stream.Stream import java.util.stream.Stream
import kotlin.collections.ArrayDeque import kotlin.collections.ArrayDeque
import kotlin.collections.ArrayList import kotlin.math.cos
import kotlin.collections.HashMap import kotlin.math.sin
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
private fun Player.dropContainer(container: Container, spill: Boolean = true, setThrower: Boolean = false) { 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 * 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 * Whenever to render Exopack glow in dark
@ -376,6 +389,10 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
private var wasInLiquid = false private var wasInLiquid = false
private var lastDimension = ResourceLocation("overworld") 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) * 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<ItemJob>) {
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 input = MatteryContainer({ notify(IdleReason.ITEM) }, 1)
val output = 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(::isAndroid)
savetables.bool(::willBecomeAndroid) savetables.bool(::willBecomeAndroid)
savetables.bool(::hasExopack, "hasExoSuit") savetables.bool(::hasExopack, "hasExoSuit")
savetables.bool(::displayExopack, "displayExoSuit") savetables.bool(::isExopackVisible, "displayExoSuit")
savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded") savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded")
savetables.int(::nextDischargeHurt) savetables.int(::nextDischargeHurt)
savetables.int(::nextHealTick) savetables.int(::nextHealTick)
@ -1431,6 +1456,21 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return stack.isEmpty return stack.isEmpty
} }
fun makeSmokeParticles(poseStack: PoseStack, model: PlayerModel<AbstractClientPlayer>) {
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<MatteryPlayerCapability, Boolean>) { enum class UpgradeType(val prop: KMutableProperty1<MatteryPlayerCapability, Boolean>) {
CRAFTING(MatteryPlayerCapability::isExopackCraftingUpgraded), CRAFTING(MatteryPlayerCapability::isExopackCraftingUpgraded),
SMELTING(MatteryPlayerCapability::isExopackSmeltingInstalled); SMELTING(MatteryPlayerCapability::isExopackSmeltingInstalled);

View File

@ -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.compat.curios.openCuriosScreen
import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.core.math.integerDivisionDown
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu 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 ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak
@ -238,7 +238,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
} }
init { init {
MatteryPlayerNetworkChannel.sendToServer(ExoPackMenuOpen) MatteryPlayerNetworkChannel.sendToServer(ExopackMenuOpen)
ru.dbotthepony.mc.otm.client.minecraft.player?.containerMenu = menu ru.dbotthepony.mc.otm.client.minecraft.player?.containerMenu = menu
} }

View File

@ -59,7 +59,7 @@ private fun createExopackAppearanceWindow(screen: MatteryScreen<*>, matteryPlaye
text = TranslatableComponent("otm.gui.exopack.toggle_visibility"), text = TranslatableComponent("otm.gui.exopack.toggle_visibility"),
isChecked = GetterSetter.of( isChecked = GetterSetter.of(
{ {
matteryPlayer.displayExopack matteryPlayer.isExopackVisible
}, },
{ {
if (it) { if (it) {

View File

@ -14,9 +14,9 @@ import ru.dbotthepony.mc.otm.compat.curios.curiosSlots
import ru.dbotthepony.mc.otm.container.iterator import ru.dbotthepony.mc.otm.container.iterator
import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.network.ExoSuitCarriedPacket import ru.dbotthepony.mc.otm.network.ExopackCarriedPacket
import ru.dbotthepony.mc.otm.network.ExoSuitMenuInitPacket import ru.dbotthepony.mc.otm.network.ExopackMenuInitPacket
import ru.dbotthepony.mc.otm.network.ExoSuitSlotPacket import ru.dbotthepony.mc.otm.network.ExopackSlotPacket
import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel import ru.dbotthepony.mc.otm.network.MatteryPlayerNetworkChannel
class ExopackInventoryMenu(val capability: MatteryPlayerCapability) : MatteryMenu(null, CONTAINER_ID, capability.ply.inventory) { 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<ItemStack>, carried: ItemStack, remoteDataSlots: IntArray) { fun sendInitialData(container: ExopackInventoryMenu, itemStacks: NonNullList<ItemStack>, 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) { fun sendSlotChange(container: ExopackInventoryMenu, slotId: Int, itemStack: ItemStack) {
if (container.slots[slotId].container != container.ply.inventory || container.ply.containerMenu is ExopackInventoryMenu) 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) { 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) { fun sendDataChange(container: ExopackInventoryMenu, dataSlotId: Int, shortData: Int) {

View File

@ -4,10 +4,14 @@ import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.server.level.ServerPlayer
import net.minecraft.util.RandomSource
import net.minecraft.world.level.Level import net.minecraft.world.level.Level
import net.minecraftforge.network.NetworkDirection import net.minecraftforge.network.NetworkDirection
import net.minecraftforge.network.NetworkEvent import net.minecraftforge.network.NetworkEvent
import net.minecraftforge.network.PacketDistributor
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.android.AndroidResearchManager import ru.dbotthepony.mc.otm.android.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket import ru.dbotthepony.mc.otm.android.feature.ItemEntityDataPacket
@ -20,6 +24,34 @@ import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.collections.ArrayList 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<NetworkEvent.Context>) {
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 { class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val validBytes: Int) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
buff.writeBlockPos(position) buff.writeBlockPos(position)
@ -96,9 +128,17 @@ class BlockEntitySyncPacket(val position: BlockPos, val buffer: ByteArray, val v
} }
object GenericNetworkChannel : MatteryNetworkChannel( object GenericNetworkChannel : MatteryNetworkChannel(
version = "3", version = "4",
name = "generic" 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() { fun register() {
add(QuantumBatteryItem.ChargePacket::class.java, QuantumBatteryItem.Companion::readPacket, NetworkDirection.PLAY_TO_CLIENT) 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(AndroidResearchManager.SyncPacket::class.java, AndroidResearchManager::readSyncPacket, NetworkDirection.PLAY_TO_CLIENT)
add(MatterManager.SyncPacket::class.java, MatterManager::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)
} }
} }

View File

@ -122,6 +122,15 @@ abstract class MatteryNetworkChannel(val version: String, val name: String) {
@Volatile @Volatile
private var interrupt = false 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() { private fun run() {
while (!interrupt) { while (!interrupt) {
val task = queue.pollFirst() val task = queue.pollFirst()

View File

@ -1,6 +1,7 @@
package ru.dbotthepony.mc.otm.network package ru.dbotthepony.mc.otm.network
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket 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.AndroidResearchManager
import ru.dbotthepony.mc.otm.android.AndroidResearchType import ru.dbotthepony.mc.otm.android.AndroidResearchType
import ru.dbotthepony.mc.otm.android.AndroidSwitchableFeature 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.TriggerJumpBoostPacket
import ru.dbotthepony.mc.otm.android.feature.TriggerShockwavePacket import ru.dbotthepony.mc.otm.android.feature.TriggerShockwavePacket
import ru.dbotthepony.mc.otm.capability.MatteryPlayerCapability 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.container.set
import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.Vector 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.tech.AndroidStationMenu
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu
import ru.dbotthepony.mc.otm.registry.AndroidFeatures import ru.dbotthepony.mc.otm.registry.AndroidFeatures
@ -223,7 +228,7 @@ class PlayerIterationPacket(val iteration: Int, val deathLog: List<Pair<Int, Com
} }
} }
class ExoSuitCarriedPacket(val itemStack: ItemStack, val containerState: Int) : MatteryPacket { class ExopackCarriedPacket(val itemStack: ItemStack, val containerState: Int) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
buff.writeItem(itemStack) buff.writeItem(itemStack)
buff.writeInt(containerState) buff.writeInt(containerState)
@ -242,13 +247,13 @@ class ExoSuitCarriedPacket(val itemStack: ItemStack, val containerState: Int) :
} }
companion object { companion object {
fun read(buff: FriendlyByteBuf): ExoSuitCarriedPacket { fun read(buff: FriendlyByteBuf): ExopackCarriedPacket {
return ExoSuitCarriedPacket(buff.readItem(), buff.readInt()) return ExopackCarriedPacket(buff.readItem(), buff.readInt())
} }
} }
} }
class ExoSuitSlotPacket(val slotId: Int, val itemStack: ItemStack, val containerState: Int) : MatteryPacket { class ExopackSlotPacket(val slotId: Int, val itemStack: ItemStack, val containerState: Int) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
buff.writeInt(slotId) buff.writeInt(slotId)
buff.writeItem(itemStack) buff.writeItem(itemStack)
@ -286,13 +291,13 @@ class ExoSuitSlotPacket(val slotId: Int, val itemStack: ItemStack, val container
companion object { companion object {
private val LOGGER = LogManager.getLogger() private val LOGGER = LogManager.getLogger()
fun read(buff: FriendlyByteBuf): ExoSuitSlotPacket { fun read(buff: FriendlyByteBuf): ExopackSlotPacket {
return ExoSuitSlotPacket(buff.readInt(), buff.readItem(), buff.readInt()) return ExopackSlotPacket(buff.readInt(), buff.readItem(), buff.readInt())
} }
} }
} }
class ExoSuitMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack, val containerState: Int) : MatteryPacket { class ExopackMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack, val containerState: Int) : MatteryPacket {
override fun write(buff: FriendlyByteBuf) { override fun write(buff: FriendlyByteBuf) {
buff.writeInt(slots.size) buff.writeInt(slots.size)
@ -316,7 +321,7 @@ class ExoSuitMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack,
} }
companion object { companion object {
fun read(buff: FriendlyByteBuf): ExoSuitMenuInitPacket { fun read(buff: FriendlyByteBuf): ExopackMenuInitPacket {
val size = buff.readInt() val size = buff.readInt()
val slots = ArrayList<ItemStack>(size) val slots = ArrayList<ItemStack>(size)
@ -327,12 +332,12 @@ class ExoSuitMenuInitPacket(val slots: List<ItemStack>, val carried: ItemStack,
val carried = buff.readItem() val carried = buff.readItem()
val containerState = buff.readInt() 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 write(buff: FriendlyByteBuf) {}
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: Supplier<NetworkEvent.Context>) {
@ -499,7 +504,7 @@ object DisplayExopackPacket : MatteryPacket {
override fun play(context: Supplier<NetworkEvent.Context>) { override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true 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<NetworkEvent.Context>) { override fun play(context: Supplier<NetworkEvent.Context>) {
context.packetHandled = true 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<NetworkEvent.Context>) {
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( object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
version = "5", version = "6",
name = "player" name = "player"
) { ) {
fun register() { fun register() {
@ -572,18 +622,18 @@ object MatteryPlayerNetworkChannel : MatteryNetworkChannel(
add(PlayerIterationPacket::class, PlayerIterationPacket.Companion::read, PLAY_TO_CLIENT) add(PlayerIterationPacket::class, PlayerIterationPacket.Companion::read, PLAY_TO_CLIENT)
add(ExoSuitCarriedPacket::class, ExoSuitCarriedPacket.Companion::read, PLAY_TO_CLIENT) add(ExopackCarriedPacket::class, ExopackCarriedPacket.Companion::read, PLAY_TO_CLIENT)
add(ExoSuitSlotPacket::class, ExoSuitSlotPacket.Companion::read, PLAY_TO_CLIENT) add(ExopackSlotPacket::class, ExopackSlotPacket.Companion::read, PLAY_TO_CLIENT)
add(ExoSuitMenuInitPacket::class, ExoSuitMenuInitPacket.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(SwitchAndroidFeaturePacket::class, SwitchAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER)
add(ActivateAndroidFeaturePacket::class, ActivateAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER) add(ActivateAndroidFeaturePacket::class, ActivateAndroidFeaturePacket.Companion::read, PLAY_TO_SERVER)
add(TriggerShockwavePacket::class, { TriggerShockwavePacket }, PLAY_TO_SERVER) add(TriggerShockwavePacket::class, { TriggerShockwavePacket }, PLAY_TO_SERVER)
add(TriggerJumpBoostPacket::class, { TriggerJumpBoostPacket }, 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) add(PickItemFromInventoryPacket::class, PickItemFromInventoryPacket.Companion::read, PLAY_TO_SERVER)