diff --git a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java index 4a0da66a7..27459d451 100644 --- a/src/main/java/com/atsuishio/superbwarfare/ModUtils.java +++ b/src/main/java/com/atsuishio/superbwarfare/ModUtils.java @@ -146,6 +146,7 @@ public class ModUtils { addNetworkMessage(ModVariables.PlayerVariablesSyncMessage.class, ModVariables.PlayerVariablesSyncMessage::buffer, ModVariables.PlayerVariablesSyncMessage::new, ModVariables.PlayerVariablesSyncMessage::handler); addNetworkMessage(ModVariables.PlayerVariablesSyncMessage.class, ModVariables.PlayerVariablesSyncMessage::buffer, ModVariables.PlayerVariablesSyncMessage::new, ModVariables.PlayerVariablesSyncMessage::handler); addNetworkMessage(ShootMessage.class, ShootMessage::encode, ShootMessage::decode, ShootMessage::handler); + addNetworkMessage(LaserShootMessage.class, LaserShootMessage::encode, LaserShootMessage::decode, LaserShootMessage::handler); addNetworkMessage(ShootClientMessage.class, ShootClientMessage::encode, ShootClientMessage::decode, ShootClientMessage::handle, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); addNetworkMessage(DrawClientMessage.class, DrawClientMessage::encode, DrawClientMessage::decode, DrawClientMessage::handle, Optional.of(NetworkDirection.PLAY_TO_CLIENT)); addNetworkMessage(EditModeMessage.class, EditModeMessage::encode, EditModeMessage::decode, EditModeMessage::handler); diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/BeamRenderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/BeamRenderer.java new file mode 100644 index 000000000..a6df77999 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/BeamRenderer.java @@ -0,0 +1,57 @@ +package com.atsuishio.superbwarfare.client.renderer.entity; + +import com.atsuishio.superbwarfare.entity.BeamEntity; +import com.atsuishio.superbwarfare.entity.layer.BeamLayer; +import com.atsuishio.superbwarfare.entity.model.BeamModel; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRendererProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoEntityRenderer; + +public class BeamRenderer extends GeoEntityRenderer { + + public BeamRenderer(EntityRendererProvider.Context renderManager) { + super(renderManager, new BeamModel()); + this.addRenderLayer(new BeamLayer(this)); + this.shadowRadius = 0f; + } + + @Override + public RenderType getRenderType(BeamEntity animatable, ResourceLocation texture, MultiBufferSource bufferSource, float partialTick) { + return RenderType.entityTranslucent(getTextureLocation(animatable)); + } + + @Override + public void preRender(PoseStack poseStack, BeamEntity entity, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, + float blue, float alpha) { + float scale = 0.5f; + this.scaleHeight = scale; + this.scaleWidth = scale; + super.preRender(poseStack, entity, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha); + } + + @Override + public void render(BeamEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + poseStack.pushPose(); + poseStack.mulPose(Axis.YP.rotationDegrees(-Mth.lerp(partialTicks, entityIn.yRotO, entityIn.getYRot()))); + poseStack.mulPose(Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entityIn.xRotO, entityIn.getXRot()))); + super.render(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn); + poseStack.popPose(); + } + + @Override + protected float getDeathMaxRotation(BeamEntity entityLivingBaseIn) { + return 0.0F; + } + + @Override + public boolean shouldShowName(BeamEntity animatable) { + return false; + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/BeamEntity.java b/src/main/java/com/atsuishio/superbwarfare/entity/BeamEntity.java new file mode 100644 index 000000000..b50f33e4b --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/BeamEntity.java @@ -0,0 +1,221 @@ +package com.atsuishio.superbwarfare.entity; + +import com.atsuishio.superbwarfare.init.ModEntities; +import com.atsuishio.superbwarfare.init.ModItems; +import com.atsuishio.superbwarfare.tools.TraceTool; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.players.OldUsersConverter; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.OwnableEntity; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.GlassBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import software.bernie.geckolib.animatable.GeoEntity; +import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.util.GeckoLibUtil; + +import javax.annotation.Nullable; +import java.util.Optional; +import java.util.UUID; + +public class BeamEntity extends Entity implements GeoEntity, AnimatedEntity, OwnableEntity { + protected static final EntityDataAccessor> OWNER_UUID = SynchedEntityData.defineId(BeamEntity.class, EntityDataSerializers.OPTIONAL_UUID); + + public static final EntityDataAccessor LENGTH = SynchedEntityData.defineId(BeamEntity.class, EntityDataSerializers.FLOAT); + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + protected int interpolationSteps; + protected double serverYRot; + protected double serverXRot; + protected double x; + protected double y; + protected double z; + + public BeamEntity(EntityType type, Level world) { + super(type, world); + } + + public BeamEntity(LivingEntity owner, Level level) { + super(ModEntities.BEAM.get(), level); + this.setOwnerUUID(owner.getUUID()); + } + + @Override + protected void defineSynchedData() { + this.entityData.define(OWNER_UUID, Optional.empty()); + this.entityData.define(LENGTH, 0f); + + } + + @Override + public boolean isPickable() { + return !this.isRemoved(); + } + + @Override + public boolean hurt(DamageSource source, float amount) { + return false; + } + + public void setOwnerUUID(@Nullable UUID pUuid) { + this.entityData.set(OWNER_UUID, Optional.ofNullable(pUuid)); + } + + @Nullable + public UUID getOwnerUUID() { + return this.entityData.get(OWNER_UUID).orElse(null); + } + + @Override + public boolean shouldRenderAtSqrDistance(double pDistance) { + return true; + } + + + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + if (this.getOwnerUUID() != null) { + compound.putUUID("Owner", this.getOwnerUUID()); + } + compound.putFloat("Length", this.entityData.get(LENGTH)); + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + UUID uuid; + if (compound.hasUUID("Owner")) { + uuid = compound.getUUID("Owner"); + } else { + String s = compound.getString("Owner"); + + assert this.getServer() != null; + uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s); + } + + if (uuid != null) { + try { + this.setOwnerUUID(uuid); + } catch (Throwable ignored) { + } + } + + if (compound.contains("Length")) { + this.entityData.set(LENGTH, compound.getFloat("Length")); + } + } + + @Override + public void tick() { + super.tick(); + + if (this.getOwner() == null) { + this.discard(); + } + + if (!this.getOwner().getMainHandItem().is(ModItems.BEAM_TEST.get()) || (this.getOwner().getMainHandItem().is(ModItems.BEAM_TEST.get()) && !this.getOwner().getMainHandItem().getOrCreateTag().getBoolean("Using"))) { + this.discard(); + } + + this.updatePositionAndRotation(); + + boolean lookAtEntity = false; + double block_range = this.position().distanceTo((Vec3.atLowerCornerOf(this.level().clip( + new ClipContext(this.getEyePosition(), this.getEyePosition().add(this.getViewVector(1f).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this)).getBlockPos()))); + + BlockHitResult blockResult = this.level().clip( + new ClipContext(this.getEyePosition(), this.getEyePosition().add(this.getViewVector(1f).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this)); + + BlockPos resultPos = blockResult.getBlockPos(); + BlockState state = this.level().getBlockState(resultPos); + + double entity_range = 0; + + Entity lookingEntity = TraceTool.findLookingEntity(this, 512); + + if (lookingEntity != null) { + lookAtEntity = true; + entity_range = this.distanceTo(lookingEntity); + } + + if (lookAtEntity && lookingEntity != this.getOwner()) { + entityData.set(LENGTH, (float)entity_range); + } else if (!(state.getBlock() instanceof GlassBlock)){ + entityData.set(LENGTH, (float)block_range); + } + + this.refreshDimensions(); + } + + @Override + public boolean isPushable() { + return true; + } + + @Override + public String getSyncedAnimation() { + return null; + } + + @Override + public void setAnimation(String animation) { + } + + @Override + public boolean isNoGravity() { + return true; + } + + public void updatePositionAndRotation() { + LivingEntity owner = this.getOwner(); + if (owner != null) { + this.setPos(this.getOwner().getX() + 0.5 * this.getOwner().getLookAngle().x, + this.getOwner().getEyeY() - 0.3 + 0.5 * this.getOwner().getLookAngle().y, + this.getOwner().getZ() + 0.5 * this.getOwner().getLookAngle().z); + + this.setYRot(boundDegrees(owner.getYRot())); + this.setXRot(boundDegrees(owner.getXRot())); + this.yRotO = boundDegrees(owner.yRotO); + this.xRotO = boundDegrees(owner.xRotO); + } + } + + private float boundDegrees(float v) { + return (v % 360 + 360) % 360; + } + + @Override + public void lerpTo(double x, double y, double z, float yaw, float pitch, int interpolationSteps, boolean interpolate) { + this.x = x; + this.y = y; + this.z = z; + serverYRot = yaw; + serverXRot = pitch; + this.interpolationSteps = 10; + } + + @Override + public void setAnimationProcedure(String procedure) { + } + + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar data) { + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} \ No newline at end of file diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/Mk42Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/Mk42Entity.java index 2ba19d5fb..796250146 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/Mk42Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/Mk42Entity.java @@ -10,7 +10,6 @@ import com.atsuishio.superbwarfare.tools.ParticleTool; import com.atsuishio.superbwarfare.tools.SoundTool; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.syncher.EntityDataAccessor; @@ -371,10 +370,6 @@ public class Mk42Entity extends Entity implements GeoEntity, ICannonEntity { diffX = diffX * 0.15f; this.setYRot(this.getYRot() + diffY); - - if (passenger instanceof Player player) { - player.displayClientMessage(Component.literal("Angle:" + new java.text.DecimalFormat("##.##").format(this.getYRot()) + " diffY:" + new java.text.DecimalFormat("##.#").format(diffY)), true); - } this.setXRot(Mth.clamp(this.getXRot() + Mth.clamp(diffX, -3f, 3f), -85, 16.3f)); this.setRot(this.getYRot(), this.getXRot()); } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/layer/BeamLayer.java b/src/main/java/com/atsuishio/superbwarfare/entity/layer/BeamLayer.java new file mode 100644 index 000000000..72f603598 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/layer/BeamLayer.java @@ -0,0 +1,28 @@ +package com.atsuishio.superbwarfare.entity.layer; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.BeamEntity; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoRenderer; +import software.bernie.geckolib.renderer.layer.GeoRenderLayer; + +public class BeamLayer extends GeoRenderLayer { + + private static final ResourceLocation LAYER = ModUtils.loc("textures/entity/laser_beam_e.png"); + + public BeamLayer(GeoRenderer entityRenderer) { + super(entityRenderer); + } + + @Override + public void render(PoseStack poseStack, BeamEntity animatable, BakedGeoModel bakedModel, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, float partialTick, int packedLight, int packedOverlay) { + RenderType glowRenderType = RenderType.energySwirl(LAYER,1,1); + getRenderer().reRender(getDefaultBakedModel(animatable), poseStack, bufferSource, animatable, glowRenderType, bufferSource.getBuffer(glowRenderType), partialTick, packedLight, OverlayTexture.NO_OVERLAY, 1, 1, 1, 1); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/model/BeamModel.java b/src/main/java/com/atsuishio/superbwarfare/entity/model/BeamModel.java new file mode 100644 index 000000000..cd0a0f38a --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/entity/model/BeamModel.java @@ -0,0 +1,38 @@ +package com.atsuishio.superbwarfare.entity.model; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.entity.BeamEntity; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import software.bernie.geckolib.core.animatable.model.CoreGeoBone; +import software.bernie.geckolib.core.animation.AnimationState; +import software.bernie.geckolib.model.GeoModel; + +import static com.atsuishio.superbwarfare.entity.BeamEntity.LENGTH; + +public class BeamModel extends GeoModel { + + @Override + public ResourceLocation getAnimationResource(BeamEntity entity) { + return null; + } + + @Override + public ResourceLocation getModelResource(BeamEntity entity) { + return ModUtils.loc("geo/laser_beam.geo.json"); + } + + @Override + public ResourceLocation getTextureResource(BeamEntity entity) { + return ModUtils.loc("textures/entity/laser_beam.png"); + } + + @Override + public void setCustomAnimations(BeamEntity animatable, long instanceId, AnimationState animationState) { + CoreGeoBone bone = getAnimationProcessor().getBone("bone"); + bone.setScaleX(3); + bone.setScaleY(3); + bone.setScaleZ(2 * (float)(Mth.clamp(animatable.getEntityData().get(LENGTH), 0.1, 512))); +// bone.setHidden(Minecraft.getInstance().options.getCameraType() == CameraType.FIRST_PERSON && animatable.getOwner() == Minecraft.getInstance().player); + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java index 9775557f0..4ec8d2cb6 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java @@ -3,23 +3,23 @@ package com.atsuishio.superbwarfare.event; import com.atsuishio.superbwarfare.ModUtils; import com.atsuishio.superbwarfare.client.ClickHandler; import com.atsuishio.superbwarfare.config.client.DisplayConfig; +import com.atsuishio.superbwarfare.entity.BeamEntity; import com.atsuishio.superbwarfare.entity.DroneEntity; import com.atsuishio.superbwarfare.entity.ICannonEntity; import com.atsuishio.superbwarfare.init.*; import com.atsuishio.superbwarfare.item.common.ammo.CannonShellItem; import com.atsuishio.superbwarfare.network.ModVariables; +import com.atsuishio.superbwarfare.network.message.LaserShootMessage; import com.atsuishio.superbwarfare.network.message.ShootMessage; import com.atsuishio.superbwarfare.perk.AmmoPerk; import com.atsuishio.superbwarfare.perk.Perk; import com.atsuishio.superbwarfare.perk.PerkHelper; -import com.atsuishio.superbwarfare.tools.EntityFindUtil; -import com.atsuishio.superbwarfare.tools.GunsTool; -import com.atsuishio.superbwarfare.tools.MillisTimer; -import com.atsuishio.superbwarfare.tools.SeekTool; +import com.atsuishio.superbwarfare.tools.*; import net.minecraft.client.CameraType; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; @@ -200,6 +200,8 @@ public class ClientEventHandler { if (notInGame() && !ClickHandler.switchZoom) { zoom = false; } + + beamShoot(player, stack); } @SubscribeEvent @@ -343,6 +345,34 @@ public class ClientEventHandler { } } + public static void beamShoot(Player player, ItemStack stack) { + if (stack.is(ModItems.BEAM_TEST.get()) && stack.getOrCreateTag().getBoolean("Using")) { + Entity lookingEntity = TraceTool.laserfindLookingEntity(player, 512); + + if (player.isCrouching()) { + Entity seekingEntity = SeekTool.seekEntity(player, player.level(), 64, 32); + if (seekingEntity != null && seekingEntity.isAlive()) { + player.lookAt(EntityAnchorArgument.Anchor.EYES, seekingEntity.getEyePosition()); + } + } + + if (lookingEntity == null) { + return; + } + + if (lookingEntity instanceof BeamEntity) { + return; + } + + boolean canAttack = lookingEntity != player && !(lookingEntity instanceof Player player_ && (player_.isCreative() || player_.isSpectator())) + && (!player.isAlliedTo(lookingEntity) || lookingEntity.getTeam() == null || lookingEntity.getTeam().getName().equals("TDM")); + + if (canAttack) { + ModUtils.PACKET_HANDLER.sendToServer(new LaserShootMessage(2, lookingEntity.getUUID())); + } + } + } + public static void shootClient(Player player) { ItemStack stack = player.getMainHandItem(); if (stack.is(ModTags.Items.NORMAL_GUN)) { diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java index d9bf20a5a..2b6ef4cd6 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntities.java @@ -30,6 +30,8 @@ public class ModEntities { .sized(0.6f, 2f)); public static final RegistryObject> CLAYMORE = register("claymore", EntityType.Builder.of(ClaymoreEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(true).setTrackingRange(512).setUpdateInterval(1).sized(0.5f, 0.5f)); + public static final RegistryObject> BEAM = register("beam", + EntityType.Builder.of(BeamEntity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(true).setTrackingRange(512).setUpdateInterval(1).sized(0.1f, 0.1f)); public static final RegistryObject> MK_42 = register("mk_42", EntityType.Builder.of(Mk42Entity::new, MobCategory.MISC).setShouldReceiveVelocityUpdates(true).setTrackingRange(5124).setUpdateInterval(3).setCustomClientFactory(Mk42Entity::new).fireImmune().sized(3.4f, 3.5f)); public static final RegistryObject> MLE_1934 = register("mle_1934", diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java index 45fb82e23..a2a2a204b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModEntityRenderers.java @@ -14,6 +14,7 @@ public class ModEntityRenderers { event.registerEntityRenderer(ModEntities.MORTAR.get(), MortarRenderer::new); event.registerEntityRenderer(ModEntities.SENPAI.get(), SenpaiRenderer::new); event.registerEntityRenderer(ModEntities.CLAYMORE.get(), ClaymoreRenderer::new); + event.registerEntityRenderer(ModEntities.BEAM.get(), BeamRenderer::new); event.registerEntityRenderer(ModEntities.TASER_BULLET_PROJECTILE.get(), TaserBulletProjectileRenderer::new); event.registerEntityRenderer(ModEntities.GUN_GRENADE.get(), GunGrenadeRenderer::new); event.registerEntityRenderer(ModEntities.TARGET.get(), TargetRenderer::new); diff --git a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java index 33a63cea6..ce5b71082 100644 --- a/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java +++ b/src/main/java/com/atsuishio/superbwarfare/init/ModItems.java @@ -104,6 +104,7 @@ public class ModItems { public static final RegistryObject HAND_GRENADE = AMMO.register("hand_grenade", HandGrenade::new); public static final RegistryObject RGO_GRENADE = AMMO.register("rgo_grenade", RgoGrenade::new); public static final RegistryObject CLAYMORE_MINE = AMMO.register("claymore_mine", ClaymoreMine::new); + public static final RegistryObject BEAM_TEST = AMMO.register("beam_test", BeamTest::new); /** * items diff --git a/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java b/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java new file mode 100644 index 000000000..c4569cea3 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/item/BeamTest.java @@ -0,0 +1,54 @@ +package com.atsuishio.superbwarfare.item; + +import com.atsuishio.superbwarfare.entity.BeamEntity; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class BeamTest extends Item { + public BeamTest() { + super(new Properties()); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + + if (!stack.getOrCreateTag().getBoolean("Using")) { + if (!level.isClientSide) { + BeamEntity entity = getBeamEntity(level, player); + level.addFreshEntity(entity); + } + stack.getOrCreateTag().putBoolean("Using", true); + player.getCooldowns().addCooldown(this, 10); + } else { + stack.getOrCreateTag().putBoolean("Using", false); + } + + return InteractionResultHolder.consume(stack); + } + + private static BeamEntity getBeamEntity(Level level, Player player) { + BeamEntity entity = new BeamEntity(player, level); + entity.moveTo(player.getX() + 0.5 * player.getLookAngle().x, + player.getEyeY() - 0.3 + 0.5 * player.getLookAngle().y, + player.getZ() + 0.5 * player.getLookAngle().z, player.getYRot(), 0); + entity.setYBodyRot(player.getYRot()); + entity.setYHeadRot(player.getYRot()); + return entity; + } + + @Override + public void inventoryTick(ItemStack itemstack, Level world, Entity entity, int slot, boolean selected) { + super.inventoryTick(itemstack, world, entity, slot, selected); + if (!selected) { + if (itemstack.getOrCreateTag().getBoolean("Using")) { + itemstack.getOrCreateTag().putBoolean("Using", false); + } + } + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/network/message/LaserShootMessage.java b/src/main/java/com/atsuishio/superbwarfare/network/message/LaserShootMessage.java new file mode 100644 index 000000000..795ae1a22 --- /dev/null +++ b/src/main/java/com/atsuishio/superbwarfare/network/message/LaserShootMessage.java @@ -0,0 +1,67 @@ +package com.atsuishio.superbwarfare.network.message; + +import com.atsuishio.superbwarfare.ModUtils; +import com.atsuishio.superbwarfare.init.ModDamageTypes; +import com.atsuishio.superbwarfare.init.ModSounds; +import com.atsuishio.superbwarfare.tools.EntityFindUtil; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraftforge.network.NetworkEvent; +import net.minecraftforge.network.PacketDistributor; + +import java.util.UUID; +import java.util.function.Supplier; + +public class LaserShootMessage { + private final double damage; + + private final UUID uuid; + + public LaserShootMessage(double damage, UUID uuid) { + this.damage = damage; + this.uuid = uuid; + } + + public static LaserShootMessage decode(FriendlyByteBuf buffer) { + return new LaserShootMessage(buffer.readDouble(), buffer.readUUID()); + } + + public static void encode(LaserShootMessage message, FriendlyByteBuf buffer) { + buffer.writeDouble(message.damage); + buffer.writeUUID(message.uuid); + } + + public static void handler(LaserShootMessage message, Supplier contextSupplier) { + NetworkEvent.Context context = contextSupplier.get(); + context.enqueueWork(() -> { + if (context.getSender() != null) { + pressAction(context.getSender(), message.damage, message.uuid); + } + }); + context.setPacketHandled(true); + } + + public static void pressAction(Player player, double damage, UUID uuid) { + Level level = player.level(); + + if (!level.isLoaded(player.blockPosition())) { + return; + } + + Entity entity = EntityFindUtil.findEntity(level, String.valueOf(uuid)); + + if (entity != null) { + entity.hurt(ModDamageTypes.causeGunFireDamage(level.registryAccess(), player, player), (float) damage); + entity.invulnerableTime = 0; + if (player instanceof ServerPlayer serverPlayer) { + player.level().playSound(null, player.blockPosition(), ModSounds.INDICATION.get(), SoundSource.VOICE, 0.1f, 1); + ModUtils.PACKET_HANDLER.send(PacketDistributor.PLAYER.with(() -> serverPlayer), new ClientIndicatorMessage(0, 5)); + } + } + + } +} diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java index c38476cbb..3051c81ff 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/SeekTool.java @@ -1,5 +1,6 @@ package com.atsuishio.superbwarfare.tools; +import com.atsuishio.superbwarfare.entity.BeamEntity; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; @@ -14,7 +15,7 @@ public class SeekTool { public static Entity seekEntity(Entity entity, Level level, double seekRange, double seekAngle) { return StreamSupport.stream(EntityFindUtil.getEntities(level).getAll().spliterator(), false) .filter(e -> { - if (e.distanceTo(entity) <= seekRange && calculateAngle(e, entity) < seekAngle && e != entity) { + if (e.distanceTo(entity) <= seekRange && calculateAngle(e, entity) < seekAngle && e != entity && !(e instanceof BeamEntity) && e.isAlive()) { return level.clip(new ClipContext(entity.getEyePosition(), e.getEyePosition(), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType() != HitResult.Type.BLOCK; } diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java index d7125a187..ac81ea61a 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/TraceTool.java @@ -4,6 +4,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.projectile.ProjectileUtil; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.*; public class TraceTool { @@ -39,6 +41,48 @@ public class TraceTool { return null; } + public static Entity laserfindLookingEntity(Entity player, double entityReach) { + + BlockHitResult blockResult = player.level().clip( + new ClipContext(player.getEyePosition(), player.getEyePosition().add(player.getViewVector(1f).scale(512)), + ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); + + BlockPos resultPos = blockResult.getBlockPos(); + BlockState state = player.level().getBlockState(resultPos); + + double distance = entityReach * entityReach; + Vec3 eyePos = player.getEyePosition(1.0f); + HitResult hitResult = player.pick(entityReach, 1.0f, false); + if (hitResult.getType() != HitResult.Type.MISS) { + distance = hitResult.getLocation().distanceToSqr(eyePos); + double blockReach = 5; + if (distance > blockReach * blockReach) { + Vec3 pos = hitResult.getLocation(); + hitResult = BlockHitResult.miss(pos, Direction.getNearest(eyePos.x, eyePos.y, eyePos.z), BlockPos.containing(pos)); + } + } + + Vec3 viewVec = player.getViewVector(1.0F); + Vec3 toVec = eyePos.add(viewVec.x * entityReach, viewVec.y * entityReach, viewVec.z * entityReach); + AABB aabb = player.getBoundingBox().expandTowards(viewVec.scale(entityReach)).inflate(1.0D, 1.0D, 1.0D); + EntityHitResult entityhitresult = ProjectileUtil.getEntityHitResult(player, eyePos, toVec, aabb, p -> !p.isSpectator(), distance); + if (entityhitresult != null) { + Vec3 targetPos = entityhitresult.getLocation(); + double distanceToTarget = eyePos.distanceToSqr(targetPos); + if (distanceToTarget > distance || distanceToTarget > entityReach * entityReach) { + hitResult = BlockHitResult.miss(targetPos, Direction.getNearest(viewVec.x, viewVec.y, viewVec.z), BlockPos.containing(targetPos)); + } else if (distanceToTarget < distance) { + hitResult = entityhitresult; + } + } + if (hitResult.getType() == HitResult.Type.ENTITY) { + if (((EntityHitResult) hitResult).getEntity().isAlive()) { + return ((EntityHitResult) hitResult).getEntity(); + } + } + return null; + } + public static Entity cannonFindLookingEntity(Entity player, double entityReach) { double distance = entityReach * entityReach; Vec3 eyePos = new Vec3(player.getX(), player.getEyeY() + 1, player.getZ()); diff --git a/src/main/resources/assets/superbwarfare/geo/laser_beam.geo.json b/src/main/resources/assets/superbwarfare/geo/laser_beam.geo.json new file mode 100644 index 000000000..fa41d8f33 --- /dev/null +++ b/src/main/resources/assets/superbwarfare/geo/laser_beam.geo.json @@ -0,0 +1,89 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.laser_beam", + "texture_width": 16, + "texture_height": 16, + "visible_bounds_width": 2, + "visible_bounds_height": 1.5, + "visible_bounds_offset": [0, 0.25, 0] + }, + "bones": [ + { + "name": "bone", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [-0.5, -0.5, -16], + "size": [1, 1, 16], + "uv": { + "north": {"uv": [0, 0], "uv_size": [8, 8]}, + "east": {"uv": [0, 0], "uv_size": [8, 8]}, + "south": {"uv": [0, 0], "uv_size": [8, 8]}, + "west": {"uv": [0, 0], "uv_size": [8, 8]}, + "up": {"uv": [8, 8], "uv_size": [-8, -8]}, + "down": {"uv": [8, 8], "uv_size": [-8, -8]} + } + }, + { + "origin": [-0.75, -0.75, -16], + "size": [1.5, 0, 16], + "uv": { + "north": {"uv": [8, 0], "uv_size": [8, 8]}, + "east": {"uv": [8, 0], "uv_size": [8, 8]}, + "south": {"uv": [8, 0], "uv_size": [8, 8]}, + "west": {"uv": [8, 0], "uv_size": [8, 8]}, + "up": {"uv": [16, 8], "uv_size": [-8, -8]}, + "down": {"uv": [16, 8], "uv_size": [-8, -8]} + } + }, + { + "origin": [-1.5005, -0.7495, -16], + "size": [1.5, 0, 16], + "pivot": [-0.375, -0.3745, -8], + "rotation": [0, 0, 90], + "uv": { + "north": {"uv": [8, 0], "uv_size": [8, 8]}, + "east": {"uv": [8, 0], "uv_size": [8, 8]}, + "south": {"uv": [8, 0], "uv_size": [8, 8]}, + "west": {"uv": [8, 0], "uv_size": [8, 8]}, + "up": {"uv": [16, 8], "uv_size": [-8, -8]}, + "down": {"uv": [16, 8], "uv_size": [-8, -8]} + } + }, + { + "origin": [0, 0, -16], + "size": [1.5, 0, 16], + "pivot": [0.375, 0.3755, -8], + "rotation": [0, 0, -180], + "uv": { + "north": {"uv": [8, 0], "uv_size": [8, 8]}, + "east": {"uv": [8, 0], "uv_size": [8, 8]}, + "south": {"uv": [8, 0], "uv_size": [8, 8]}, + "west": {"uv": [8, 0], "uv_size": [8, 8]}, + "up": {"uv": [16, 8], "uv_size": [-8, -8]}, + "down": {"uv": [16, 8], "uv_size": [-8, -8]} + } + }, + { + "origin": [-0.7505, 0.0005, -16], + "size": [1.5, 0, 16], + "pivot": [0.375, 0.3755, -8], + "rotation": [0, 0, -90], + "uv": { + "north": {"uv": [8, 0], "uv_size": [8, 8]}, + "east": {"uv": [8, 0], "uv_size": [8, 8]}, + "south": {"uv": [8, 0], "uv_size": [8, 8]}, + "west": {"uv": [8, 0], "uv_size": [8, 8]}, + "up": {"uv": [16, 8], "uv_size": [-8, -8]}, + "down": {"uv": [16, 8], "uv_size": [-8, -8]} + } + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/superbwarfare/textures/entity/laser_beam.png b/src/main/resources/assets/superbwarfare/textures/entity/laser_beam.png new file mode 100644 index 000000000..ec0f3d041 Binary files /dev/null and b/src/main/resources/assets/superbwarfare/textures/entity/laser_beam.png differ diff --git a/src/main/resources/assets/superbwarfare/textures/entity/laser_beam_e.png b/src/main/resources/assets/superbwarfare/textures/entity/laser_beam_e.png new file mode 100644 index 000000000..0d122b830 Binary files /dev/null and b/src/main/resources/assets/superbwarfare/textures/entity/laser_beam_e.png differ