From fbcaa1b9310eef920c204a30d272088713308afb Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Sat, 26 Jun 2021 16:32:56 +0200 Subject: [PATCH] Fwoomp of Duty: Black Crops 4 - Introduced proper first-person rendering of Potato Cannons, inherited from blockzappers - Introduced proper dual wield handling for Potato Cannons - Potato cannons are no longer stackable - Added a couple more attributes to ammo types - potatoes and carrots now plant a crop when hitting farmland - Added a couple particle effects - Fwoomp sound now slightly randomizes its pitch --- src/main/java/com/simibubi/create/Create.java | 9 +- .../com/simibubi/create/CreateClient.java | 26 ++- .../curiosities/weapons/PotatoCannonItem.java | 101 ++++++---- .../weapons/PotatoCannonItemRenderer.java | 15 +- .../weapons/PotatoCannonPacket.java | 58 ++++-- .../weapons/PotatoCannonProjectileTypes.java | 92 +++++++-- .../weapons/PotatoCannonRenderHandler.java | 65 +++++++ .../weapons/PotatoProjectileEntity.java | 13 +- .../curiosities/zapper/ShootGadgetPacket.java | 79 ++++++++ .../zapper/ShootableGadgetItemMethods.java | 68 +++++++ .../zapper/ShootableGadgetRenderHandler.java | 150 ++++++++++++++ .../curiosities/zapper/ZapperBeamPacket.java | 65 +++---- .../curiosities/zapper/ZapperItem.java | 61 ++---- .../zapper/ZapperItemRenderer.java | 9 +- .../zapper/ZapperRenderHandler.java | 183 +++--------------- .../simibubi/create/events/ClientEvents.java | 5 +- 16 files changed, 670 insertions(+), 329 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonRenderHandler.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java index 9a54332c1..b22279830 100644 --- a/src/main/java/com/simibubi/create/Create.java +++ b/src/main/java/com/simibubi/create/Create.java @@ -60,8 +60,8 @@ public class Create { public static final Logger LOGGER = LogManager.getLogger(); public static final Gson GSON = new GsonBuilder().setPrettyPrinting() - .disableHtmlEscaping() - .create(); + .disableHtmlEscaping() + .create(); public static final ItemGroup BASE_CREATIVE_TAB = new CreateItemGroup(); public static final ItemGroup PALETTES_CREATIVE_TAB = new PalettesItemGroup(); @@ -90,7 +90,7 @@ public class Create { AllConfigs.register(); IEventBus modEventBus = FMLJavaModLoadingContext.get() - .getModEventBus(); + .getModEventBus(); IEventBus forgeEventBus = MinecraftForge.EVENT_BUS; modEventBus.addListener(Create::init); @@ -104,7 +104,8 @@ public class Create { modEventBus.addListener(EventPriority.LOWEST, this::gatherData); forgeEventBus.addListener(EventPriority.HIGH, Create::onBiomeLoad); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> CreateClient.addClientListeners(modEventBus)); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> CreateClient.addClientListeners(forgeEventBus, modEventBus)); } public static void init(final FMLCommonSetupEvent event) { diff --git a/src/main/java/com/simibubi/create/CreateClient.java b/src/main/java/com/simibubi/create/CreateClient.java index e030c8fbb..27ed9e633 100644 --- a/src/main/java/com/simibubi/create/CreateClient.java +++ b/src/main/java/com/simibubi/create/CreateClient.java @@ -10,6 +10,8 @@ import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.relays.encased.CasingConnectivity; import com.simibubi.create.content.curiosities.armor.CopperBacktankArmorLayer; +import com.simibubi.create.content.curiosities.weapons.PotatoCannonRenderHandler; +import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler; import com.simibubi.create.content.schematics.ClientSchematicLoader; import com.simibubi.create.content.schematics.client.SchematicAndQuillHandler; import com.simibubi.create.content.schematics.client.SchematicHandler; @@ -63,12 +65,15 @@ public class CreateClient { public static final Outliner OUTLINER = new Outliner(); public static final GhostBlocks GHOST_BLOCKS = new GhostBlocks(); + public static final ZapperRenderHandler ZAPPER_RENDER_HANDLER = new ZapperRenderHandler(); + public static final PotatoCannonRenderHandler POTATO_CANNON_RENDER_HANDLER = new PotatoCannonRenderHandler(); + private static CustomBlockModels customBlockModels; private static CustomItemModels customItemModels; private static CustomRenderedItems customRenderedItems; private static CasingConnectivity casingConnectivity; - public static void addClientListeners(IEventBus modEventBus) { + public static void addClientListeners(IEventBus forgeEventBus, IEventBus modEventBus) { modEventBus.addListener(CreateClient::clientInit); modEventBus.addListener(CreateClient::onTextureStitch); modEventBus.addListener(CreateClient::onModelRegistry); @@ -78,6 +83,9 @@ public class CreateClient { modEventBus.addListener(CreateContexts::flwInit); modEventBus.addListener(AllMaterialSpecs::flwInit); modEventBus.addListener(ContraptionRenderDispatcher::invalidateOnGatherContext); + + ZAPPER_RENDER_HANDLER.register(forgeEventBus); + POTATO_CANNON_RENDER_HANDLER.register(forgeEventBus); } public static void clientInit(FMLClientSetupEvent event) { @@ -96,7 +104,7 @@ public class CreateClient { UIRenderHelper.init(); IResourceManager resourceManager = Minecraft.getInstance() - .getResourceManager(); + .getResourceManager(); if (resourceManager instanceof IReloadableResourceManager) ((IReloadableResourceManager) resourceManager).addReloadListener(new ResourceReloadHandler()); @@ -107,19 +115,19 @@ public class CreateClient { public static void onTextureStitch(TextureStitchEvent.Pre event) { if (!event.getMap() - .getId() - .equals(PlayerContainer.BLOCK_ATLAS_TEXTURE)) + .getId() + .equals(PlayerContainer.BLOCK_ATLAS_TEXTURE)) return; SpriteShifter.getAllTargetSprites() - .forEach(event::addSprite); + .forEach(event::addSprite); } public static void onModelRegistry(ModelRegistryEvent event) { PartialModel.onModelRegistry(event); getCustomRenderedItems().foreach((item, modelFunc) -> modelFunc.apply(null) - .getModelLocations() - .forEach(ModelLoader::addSpecialModel)); + .getModelLocations() + .forEach(ModelLoader::addSpecialModel)); } public static void onModelBake(ModelBakeEvent event) { @@ -127,9 +135,9 @@ public class CreateClient { PartialModel.onModelBake(event); getCustomBlockModels() - .foreach((block, modelFunc) -> swapModels(modelRegistry, getAllBlockStateModelLocations(block), modelFunc)); + .foreach((block, modelFunc) -> swapModels(modelRegistry, getAllBlockStateModelLocations(block), modelFunc)); getCustomItemModels() - .foreach((item, modelFunc) -> swapModels(modelRegistry, getItemModelLocation(item), modelFunc)); + .foreach((item, modelFunc) -> swapModels(modelRegistry, getItemModelLocation(item), modelFunc)); getCustomRenderedItems().foreach((item, modelFunc) -> { swapModels(modelRegistry, getItemModelLocation(item), m -> modelFunc.apply(m) .loadPartials(event)); diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java index cd6fd4e0b..51ad8e5e9 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItem.java @@ -5,9 +5,11 @@ import java.util.Optional; import java.util.function.Predicate; import com.simibubi.create.AllEntityTypes; +import com.simibubi.create.Create; +import com.simibubi.create.CreateClient; import com.simibubi.create.content.curiosities.armor.BackTankUtil; +import com.simibubi.create.content.curiosities.zapper.ShootableGadgetItemMethods; import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.AnimationTickHolder; import com.simibubi.create.foundation.utility.VecHelper; @@ -15,16 +17,15 @@ import net.minecraft.block.BlockState; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; import net.minecraft.item.ShootableItem; +import net.minecraft.item.UseAction; import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResultType; -import net.minecraft.util.Direction.Axis; import net.minecraft.util.Hand; -import net.minecraft.util.HandSide; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.text.ITextComponent; @@ -34,14 +35,13 @@ import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.network.PacketDistributor; public class PotatoCannonItem extends ShootableItem { public static ItemStack CLIENT_CURRENT_AMMO = ItemStack.EMPTY; public static final int MAX_DAMAGE = 100; - public static int PREV_SHOT = 0; + public static int PREV_SHOT = 0;// remove this public PotatoCannonItem(Properties p_i48487_1_) { super(p_i48487_1_); @@ -58,6 +58,11 @@ public class PotatoCannonItem extends ShootableItem { return onItemRightClick(context.getWorld(), context.getPlayer(), context.getHand()).getType(); } + @Override + public int getItemStackLimit(ItemStack stack) { + return 1; + } + @Override public int getRGBDurabilityForDisplay(ItemStack stack) { return BackTankUtil.getRGBDurabilityForDisplay(stack, maxUses()); @@ -82,6 +87,10 @@ public class PotatoCannonItem extends ShootableItem { return true; } + public boolean isCannon(ItemStack stack) { + return stack.getItem() instanceof PotatoCannonItem; + } + @Override public int getMaxDamage(ItemStack stack) { return MAX_DAMAGE; @@ -90,32 +99,41 @@ public class PotatoCannonItem extends ShootableItem { @Override public ActionResult onItemRightClick(World world, PlayerEntity player, Hand hand) { ItemStack stack = player.getHeldItem(hand); - if (world.isRemote) - return ActionResult.pass(stack); + return findAmmoInInventory(world, player, stack).map(itemStack -> { - findAmmoInInventory(world, player, stack).ifPresent(itemStack -> { - PotatoProjectileEntity projectile = AllEntityTypes.POTATO_PROJECTILE.create(world); - Vector3d offset = VecHelper.rotate(player.getLookVec() - .scale(1.25f), (hand == Hand.MAIN_HAND) == (player.getPrimaryHand() == HandSide.RIGHT) ? -25 : 25, - Axis.Y); - Vector3d vec = player.getBoundingBox() - .getCenter() - .add(0, player.getBoundingBox() - .getYSize() / 5f, 0) - .add(offset); + if (ShootableGadgetItemMethods.shouldSwap(player, stack, hand, this::isCannon)) + return ActionResult.fail(stack); - projectile.setPosition(vec.x, vec.y, vec.z); - projectile.setMotion(player.getLookVec() - .scale(1.75f)); - projectile.setItem(itemStack); - projectile.setShooter(player); - world.addEntity(projectile); - PotatoProjectileEntity.playLaunchSound(world, player.getPositionVec(), projectile.getProjectileType() - .getSoundPitch()); + if (world.isRemote) { + CreateClient.POTATO_CANNON_RENDER_HANDLER.dontAnimateItem(hand); + return ActionResult.success(stack); + } + + Vector3d barrelPos = ShootableGadgetItemMethods.getGunBarrelVec(player, hand == Hand.MAIN_HAND, + new Vector3d(.75f, -0.3f, 1.5f)); + Vector3d correction = + ShootableGadgetItemMethods.getGunBarrelVec(player, hand == Hand.MAIN_HAND, new Vector3d(-.05f, 0, 0)) + .subtract(player.getPositionVec() + .add(0, player.getEyeHeight(), 0)); - if (player instanceof ServerPlayerEntity) - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), - new PotatoCannonPacket()); + Vector3d lookVec = player.getLookVec(); + + PotatoCannonProjectileTypes projectileType = PotatoCannonProjectileTypes.getProjectileTypeOf(itemStack) + .orElse(PotatoCannonProjectileTypes.FALLBACK); + float soundPitch = projectileType.getSoundPitch() + (Create.RANDOM.nextFloat() - .5f) / 4f; + boolean spray = projectileType.getSplit() > 1; + for (int i = 0; i < projectileType.getSplit(); i++) { + PotatoProjectileEntity projectile = AllEntityTypes.POTATO_PROJECTILE.create(world); + projectile.setItem(itemStack); + Vector3d motion = lookVec.scale(projectileType.getVelocityMultiplier()) + .add(correction); + if (spray) + motion = VecHelper.offsetRandomly(motion, Create.RANDOM, 0.25f); + projectile.setPosition(barrelPos.x, barrelPos.y, barrelPos.z); + projectile.setMotion(motion); + projectile.setShooter(player); + world.addEntity(projectile); + } if (!player.isCreative()) { itemStack.shrink(1); @@ -130,11 +148,13 @@ public class PotatoCannonItem extends ShootableItem { findAmmoInInventory(world, player, stack).flatMap(PotatoCannonProjectileTypes::getProjectileTypeOf) .map(PotatoCannonProjectileTypes::getReloadTicks) .orElse(10); - player.getCooldownTracker() - .setCooldown(this, cooldown); - }); - return ActionResult.pass(stack); + ShootableGadgetItemMethods.applyCooldown(player, stack, hand, this::isCannon, cooldown); + ShootableGadgetItemMethods.sendPackets(player, + b -> new PotatoCannonPacket(barrelPos, lookVec.normalize(), itemStack, hand, soundPitch, b)); + return ActionResult.success(stack); + }) + .orElse(ActionResult.pass(stack)); } @Override @@ -192,6 +212,21 @@ public class PotatoCannonItem extends ShootableItem { .isPresent(); } + @Override + public int getItemEnchantability() { + return 1; + } + + @Override + public boolean onEntitySwing(ItemStack stack, LivingEntity entity) { + return true; + } + + @Override + public UseAction getUseAction(ItemStack stack) { + return UseAction.NONE; + } + @Override public int getRange() { return 15; diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java index d7bc51e0c..35ad66a50 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonItemRenderer.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.curiosities.weapons; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; import com.simibubi.create.foundation.utility.AnimationTickHolder; @@ -13,6 +14,8 @@ import net.minecraft.client.renderer.ItemRenderer; import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.item.ItemStack; +import net.minecraft.util.HandSide; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3f; public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer { @@ -26,16 +29,18 @@ public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer context) { - context.get() - .enqueueWork(() -> PotatoCannonItem.PREV_SHOT = 15); - context.get() - .setPacketHandled(true); + protected void writeAdditional(PacketBuffer buffer) { + buffer.writeFloat(pitch); + buffer.writeFloat((float) motion.x); + buffer.writeFloat((float) motion.y); + buffer.writeFloat((float) motion.z); + buffer.writeItemStack(item); + } + + @Override + @OnlyIn(Dist.CLIENT) + protected void handleAdditional() { + CreateClient.POTATO_CANNON_RENDER_HANDLER.beforeShoot(pitch, location, motion, item); + } + + @Override + @OnlyIn(Dist.CLIENT) + protected ShootableGadgetRenderHandler getHandler() { + return CreateClient.POTATO_CANNON_RENDER_HANDLER; } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonProjectileTypes.java b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonProjectileTypes.java index 2ab4dd6f7..d7385efdf 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonProjectileTypes.java +++ b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonProjectileTypes.java @@ -3,21 +3,30 @@ package com.simibubi.create.content.curiosities.weapons; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.function.BiConsumer; import java.util.function.Consumer; import com.simibubi.create.Create; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.potion.Effect; import net.minecraft.potion.EffectInstance; import net.minecraft.potion.Effects; +import net.minecraft.util.Direction; import net.minecraft.util.IItemProvider; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.EntityRayTraceResult; +import net.minecraft.world.IWorld; +import net.minecraftforge.common.IPlantable; import net.minecraftforge.registries.IRegistryDelegate; public class PotatoCannonProjectileTypes { @@ -31,13 +40,16 @@ public class PotatoCannonProjectileTypes { POTATO = create("potato").damage(4) .reloadTicks(15) + .velocity(1.25f) .knockback(1.5f) .renderTumbling() + .onBlockHit(plantCrop(Blocks.POTATOES.delegate)) .registerAndAssign(Items.POTATO), BAKED_POTATO = create("baked_potato").damage(3) .reloadTicks(15) - .knockback(1.5f) + .velocity(1.05f) + .knockback(0.5f) .renderTumbling() .onEntityHit(ray -> ray.getEntity() .setFireTicks(10)) @@ -45,28 +57,35 @@ public class PotatoCannonProjectileTypes { CARROT = create("carrot").damage(3) .renderTowardMotion(140, 1) - .velocity(1.25f) + .velocity(1.45f) .knockback(0.5f) .soundPitch(1.25f) + .onBlockHit(plantCrop(Blocks.CARROTS.delegate)) .registerAndAssign(Items.CARROT), GOLDEN_CARROT = create("golden_carrot").damage(8) .reloadTicks(20) .knockback(0.5f) - .velocity(1.25f) + .velocity(1.45f) .renderTowardMotion(140, 2) .soundPitch(1.25f) .registerAndAssign(Items.GOLDEN_CARROT), + SWEET_BERRIES = create("sweet_berry").damage(1) + .reloadTicks(10) + .knockback(0.1f) + .velocity(1.05f) + .renderTumbling() + .splitInto(3) + .soundPitch(1.25f) + .registerAndAssign(Items.SWEET_BERRIES), + POISON_POTATO = create("poison_potato").damage(5) .reloadTicks(15) - .knockback(0.5f) + .knockback(0.05f) + .velocity(1.25f) .renderTumbling() - .onEntityHit(ray -> { - Entity entity = ray.getEntity(); - if (entity instanceof LivingEntity) - ((LivingEntity) entity).addPotionEffect(new EffectInstance(Effects.POISON, 40)); - }) + .onEntityHit(potion(Effects.POISON, 4)) .registerAndAssign(Items.POISONOUS_POTATO) ; @@ -93,20 +112,30 @@ public class PotatoCannonProjectileTypes { private float gravityMultiplier = 1; private float velocityMultiplier = 1; + private float drag = 0.99f; private float knockback = 1; private int reloadTicks = 10; private int damage = 1; + private int split = 1; private float fwoompPitch = 1; private PotatoProjectileRenderMode renderMode = new PotatoProjectileRenderMode.Billboard(); private Consumer onEntityHit = e -> { }; - private Consumer onBlockHit = e -> { + private BiConsumer onBlockHit = (w, ray) -> { }; public float getGravityMultiplier() { return gravityMultiplier; } + public float getDrag() { + return drag; + } + + public int getSplit() { + return split; + } + public float getVelocityMultiplier() { return velocityMultiplier; } @@ -135,8 +164,35 @@ public class PotatoCannonProjectileTypes { onEntityHit.accept(ray); } - public void onBlockHit(BlockRayTraceResult ray) { - onBlockHit.accept(ray); + public void onBlockHit(IWorld world, BlockRayTraceResult ray) { + onBlockHit.accept(world, ray); + } + + private static Consumer potion(Effect effect, int seconds) { + return ray -> { + Entity entity = ray.getEntity(); + if (entity instanceof LivingEntity) + ((LivingEntity) entity).addPotionEffect(new EffectInstance(Effects.POISON, 80)); + }; + } + + private static BiConsumer plantCrop(IRegistryDelegate cropBlock) { + return (world, ray) -> { + BlockPos pos = ray.getPos(); + if (!world.isAreaLoaded(pos, 1)) + return; + BlockState blockState = world.getBlockState(pos); + if (!world.getBlockState(pos.up()) + .getMaterial() + .isReplaceable()) + return; + if (!(cropBlock.get() instanceof IPlantable)) + return; + if (!blockState.canSustainPlant(world, pos, Direction.UP, (IPlantable) cropBlock.get())) + return; + world.setBlockState(pos.up(), cropBlock.get() + .getDefaultState(), 3); + }; } public static class Builder { @@ -164,11 +220,21 @@ public class PotatoCannonProjectileTypes { return this; } + public Builder drag(float drag) { + result.drag = drag; + return this; + } + public Builder reloadTicks(int reload) { result.reloadTicks = reload; return this; } + public Builder splitInto(int split) { + result.split = split; + return this; + } + public Builder soundPitch(float pitch) { result.fwoompPitch = pitch; return this; @@ -199,7 +265,7 @@ public class PotatoCannonProjectileTypes { return this; } - public Builder onBlockHit(Consumer callback) { + public Builder onBlockHit(BiConsumer callback) { result.onBlockHit = callback; return this; } diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonRenderHandler.java b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonRenderHandler.java new file mode 100644 index 000000000..4cec8dcc2 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoCannonRenderHandler.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.curiosities.weapons; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllItems; +import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.particle.AirParticleData; +import com.simibubi.create.content.curiosities.zapper.ShootableGadgetRenderHandler; +import com.simibubi.create.foundation.utility.MatrixStacker; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.item.ItemStack; +import net.minecraft.particles.ItemParticleData; +import net.minecraft.particles.ParticleTypes; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; + +public class PotatoCannonRenderHandler extends ShootableGadgetRenderHandler { + + private float nextPitch; + + @Override + protected void playSound(Hand hand, BlockPos position) { + PotatoProjectileEntity.playLaunchSound(Minecraft.getInstance().world, position, nextPitch); + } + + @Override + protected boolean appliesTo(ItemStack stack) { + return AllItems.POTATO_CANNON.get() + .isCannon(stack); + } + + public void beforeShoot(float nextPitch, Vector3d location, Vector3d motion, ItemStack stack) { + this.nextPitch = nextPitch; + if (stack.isEmpty()) + return; + ClientWorld world = Minecraft.getInstance().world; + for (int i = 0; i < 2; i++) { + Vector3d m = VecHelper.offsetRandomly(motion.scale(0.1f), Create.RANDOM, .025f); + world.addParticle(new ItemParticleData(ParticleTypes.ITEM, stack), location.x, location.y, location.z, m.x, + m.y, m.z); + + Vector3d m2 = VecHelper.offsetRandomly(motion.scale(2f), Create.RANDOM, .5f); + world.addParticle(new AirParticleData(1, 1 / 4f), location.x, location.y, location.z, m2.x, m2.y, m2.z); + } + } + + @Override + protected void transformTool(MatrixStack ms, float flip, float equipProgress, float recoil, float pt) { + ms.translate(flip * -.1f, 0, .14f); + ms.scale(.75f, .75f, .75f); + MatrixStacker.of(ms) + .rotateX(recoil * 80); + } + + @Override + protected void transformHand(MatrixStack ms, float flip, float equipProgress, float recoil, float pt) { + ms.translate(flip * -.09, -.275, -.25); + MatrixStacker.of(ms) + .rotateZ(flip * -10); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoProjectileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoProjectileEntity.java index 2849bbd03..0ee33981f 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoProjectileEntity.java +++ b/src/main/java/com/simibubi/create/content/curiosities/weapons/PotatoProjectileEntity.java @@ -69,8 +69,9 @@ public class PotatoProjectileEntity extends DamagingProjectileEntity implements } public void tick() { - setMotion(getMotion().add(0, -.05, 0) - .scale(.99f)); + PotatoCannonProjectileTypes projectileType = getProjectileType(); + setMotion(getMotion().add(0, -.05 * projectileType.getGravityMultiplier(), 0) + .scale(projectileType.getDrag())); super.tick(); } @@ -104,6 +105,8 @@ public class PotatoProjectileEntity extends DamagingProjectileEntity implements return; if (owner instanceof LivingEntity) ((LivingEntity) owner).setLastAttackedEntity(target); + if (target instanceof PotatoProjectileEntity && ticksExisted < 10 && target.ticksExisted < 10) + return; pop(hit); @@ -164,15 +167,15 @@ public class PotatoProjectileEntity extends DamagingProjectileEntity implements AllSoundEvents.POTATO_HIT.playOnServer(world, new BlockPos(location)); } - public static void playLaunchSound(World world, Vector3d location, float pitch) { - AllSoundEvents.FWOOMP.playOnServer(world, new BlockPos(location), 1, pitch); + public static void playLaunchSound(World world, BlockPos location, float pitch) { + AllSoundEvents.FWOOMP.playAt(world, location, 1, pitch, true); } @Override protected void onBlockHit(BlockRayTraceResult ray) { Vector3d hit = ray.getHitVec(); pop(hit); - getProjectileType().onBlockHit(ray); + getProjectileType().onBlockHit(world, ray); super.onBlockHit(ray); remove(); } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java new file mode 100644 index 000000000..370cbf401 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootGadgetPacket.java @@ -0,0 +1,79 @@ +package com.simibubi.create.content.curiosities.zapper; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public abstract class ShootGadgetPacket extends SimplePacketBase { + + public Vector3d location; + public Hand hand; + public boolean self; + + public ShootGadgetPacket(Vector3d location, Hand hand, boolean self) { + this.location = location; + this.hand = hand; + this.self = self; + } + + public ShootGadgetPacket(PacketBuffer buffer) { + hand = buffer.readBoolean() ? Hand.MAIN_HAND : Hand.OFF_HAND; + self = buffer.readBoolean(); + location = new Vector3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); + readAdditional(buffer); + } + + public final void write(PacketBuffer buffer) { + buffer.writeBoolean(hand == Hand.MAIN_HAND); + buffer.writeBoolean(self); + buffer.writeDouble(location.x); + buffer.writeDouble(location.y); + buffer.writeDouble(location.z); + writeAdditional(buffer); + } + + protected abstract void readAdditional(PacketBuffer buffer); + + protected abstract void writeAdditional(PacketBuffer buffer); + + @OnlyIn(Dist.CLIENT) + protected abstract void handleAdditional(); + + @OnlyIn(Dist.CLIENT) + protected abstract ShootableGadgetRenderHandler getHandler(); + + @Override + @OnlyIn(Dist.CLIENT) + public final void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + Entity renderViewEntity = Minecraft.getInstance() + .getRenderViewEntity(); + if (renderViewEntity == null) + return; + if (renderViewEntity.getPositionVec() + .distanceTo(location) > 100) + return; + + ShootableGadgetRenderHandler handler = getHandler(); + handleAdditional(); + if (self) + handler.shoot(hand); + else + handler.playSound(hand, new BlockPos(location)); + }); + context.get() + .setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java new file mode 100644 index 000000000..cefdd485f --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetItemMethods.java @@ -0,0 +1,68 @@ +package com.simibubi.create.content.curiosities.zapper; + +import java.util.function.Function; +import java.util.function.Predicate; + +import com.simibubi.create.foundation.networking.AllPackets; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.HandSide; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraftforge.fml.network.PacketDistributor; + +public class ShootableGadgetItemMethods { + + public static void applyCooldown(PlayerEntity player, ItemStack item, Hand hand, Predicate predicate, + int cooldown) { + boolean gunInOtherHand = + predicate.test(player.getHeldItem(hand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND)); + player.getCooldownTracker() + .setCooldown(item.getItem(), gunInOtherHand ? cooldown * 2 / 3 : cooldown); + } + + public static void sendPackets(PlayerEntity player, Function factory) { + if (!(player instanceof ServerPlayerEntity)) + return; + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> player), factory.apply(false)); + AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), factory.apply(true)); + } + + public static boolean shouldSwap(PlayerEntity player, ItemStack item, Hand hand, Predicate predicate) { + boolean isSwap = item.getTag() + .contains("_Swap"); + boolean mainHand = hand == Hand.MAIN_HAND; + boolean gunInOtherHand = predicate.test(player.getHeldItem(mainHand ? Hand.OFF_HAND : Hand.MAIN_HAND)); + + // Pass To Offhand + if (mainHand && isSwap && gunInOtherHand) + return true; + if (mainHand && !isSwap && gunInOtherHand) + item.getTag() + .putBoolean("_Swap", true); + if (!mainHand && isSwap) + item.getTag() + .remove("_Swap"); + if (!mainHand && gunInOtherHand) + player.getHeldItem(Hand.MAIN_HAND) + .getTag() + .remove("_Swap"); + player.setActiveHand(hand); + return false; + } + + public static Vector3d getGunBarrelVec(PlayerEntity player, boolean mainHand, Vector3d rightHandForward) { + Vector3d start = player.getPositionVec() + .add(0, player.getEyeHeight(), 0); + float yaw = (float) ((player.rotationYaw) / -180 * Math.PI); + float pitch = (float) ((player.rotationPitch) / -180 * Math.PI); + int flip = mainHand == (player.getPrimaryHand() == HandSide.RIGHT) ? -1 : 1; + Vector3d barrelPosNoTransform = new Vector3d(flip * rightHandForward.x, rightHandForward.y, rightHandForward.z); + Vector3d barrelPos = start.add(barrelPosNoTransform.rotatePitch(pitch) + .rotateYaw(yaw)); + return barrelPos; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java new file mode 100644 index 000000000..82ed26ba6 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ShootableGadgetRenderHandler.java @@ -0,0 +1,150 @@ +package com.simibubi.create.content.curiosities.zapper; + +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.AbstractClientPlayerEntity; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.FirstPersonRenderer; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.entity.PlayerRenderer; +import net.minecraft.client.renderer.model.ItemCameraTransforms; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.HandSide; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Vector3f; +import net.minecraftforge.client.event.RenderHandEvent; +import net.minecraftforge.eventbus.api.IEventBus; + +public abstract class ShootableGadgetRenderHandler { + + protected float leftHandAnimation; + protected float rightHandAnimation; + protected float lastLeftHandAnimation; + protected float lastRightHandAnimation; + protected boolean dontReequipLeft; + protected boolean dontReequipRight; + + public void tick() { + lastLeftHandAnimation = leftHandAnimation; + lastRightHandAnimation = rightHandAnimation; + leftHandAnimation *= animationDecay(); + rightHandAnimation *= animationDecay(); + } + + public float getAnimation(boolean rightHand, float partialTicks) { + return MathHelper.lerp(partialTicks, rightHand ? lastRightHandAnimation : lastLeftHandAnimation, + rightHand ? rightHandAnimation : leftHandAnimation); + } + + protected float animationDecay() { + return 0.8f; + } + + public void shoot(Hand hand) { + ClientPlayerEntity player = Minecraft.getInstance().player; + boolean rightHand = hand == Hand.MAIN_HAND ^ player.getPrimaryHand() == HandSide.LEFT; + if (rightHand) { + rightHandAnimation = .2f; + dontReequipRight = false; + } else { + leftHandAnimation = .2f; + dontReequipLeft = false; + } + playSound(hand, player.getBlockPos()); + } + + protected abstract void playSound(Hand hand, BlockPos position); + + protected abstract boolean appliesTo(ItemStack stack); + + protected abstract void transformTool(MatrixStack ms, float flip, float equipProgress, float recoil, float pt); + + protected abstract void transformHand(MatrixStack ms, float flip, float equipProgress, float recoil, float pt); + + public void register(IEventBus bus) { + bus.addListener(this::onRenderPlayerHand); + } + + protected void onRenderPlayerHand(RenderHandEvent event) { + ItemStack heldItem = event.getItemStack(); + if (!appliesTo(heldItem)) + return; + + Minecraft mc = Minecraft.getInstance(); + AbstractClientPlayerEntity player = mc.player; + TextureManager textureManager = mc.getTextureManager(); + PlayerRenderer playerrenderer = (PlayerRenderer) mc.getRenderManager() + .getRenderer(player); + FirstPersonRenderer firstPersonRenderer = mc.getFirstPersonRenderer(); + + MatrixStack ms = event.getMatrixStack(); + IRenderTypeBuffer buffer = event.getBuffers(); + int light = event.getLight(); + float pt = event.getPartialTicks(); + + boolean rightHand = event.getHand() == Hand.MAIN_HAND ^ mc.player.getPrimaryHand() == HandSide.LEFT; + float recoil = rightHand ? MathHelper.lerp(pt, lastRightHandAnimation, rightHandAnimation) + : MathHelper.lerp(pt, lastLeftHandAnimation, leftHandAnimation); + float equipProgress = event.getEquipProgress(); + + if (rightHand && (rightHandAnimation > .01f || dontReequipRight)) + equipProgress = 0; + if (!rightHand && (leftHandAnimation > .01f || dontReequipLeft)) + equipProgress = 0; + + // Render arm + ms.push(); + textureManager.bindTexture(player.getLocationSkin()); + + float flip = rightHand ? 1.0F : -1.0F; + float f1 = MathHelper.sqrt(event.getSwingProgress()); + float f2 = -0.3F * MathHelper.sin(f1 * (float) Math.PI); + float f3 = 0.4F * MathHelper.sin(f1 * ((float) Math.PI * 2F)); + float f4 = -0.4F * MathHelper.sin(event.getSwingProgress() * (float) Math.PI); + float f5 = MathHelper.sin(event.getSwingProgress() * event.getSwingProgress() * (float) Math.PI); + float f6 = MathHelper.sin(f1 * (float) Math.PI); + + ms.translate(flip * (f2 + 0.64F - .1f), f3 + -0.4F + equipProgress * -0.6F, f4 + -0.72F + .3f + recoil); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(flip * 75.0F)); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(flip * f6 * 70.0F)); + ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(flip * f5 * -20.0F)); + ms.translate(flip * -1.0F, 3.6F, 3.5F); + ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(flip * 120.0F)); + ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(200.0F)); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(flip * -135.0F)); + ms.translate(flip * 5.6F, 0.0F, 0.0F); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(flip * 40.0F)); + transformHand(ms, flip, equipProgress, recoil, pt); + if (rightHand) + playerrenderer.renderRightArm(ms, buffer, light, player); + else + playerrenderer.renderLeftArm(ms, buffer, light, player); + ms.pop(); + + // Render gadget + ms.push(); + ms.translate(flip * (f2 + 0.64F - .1f), f3 + -0.4F + equipProgress * -0.6F, f4 + -0.72F - 0.1f + recoil); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(flip * f6 * 70.0F)); + ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(flip * f5 * -20.0F)); + transformTool(ms, flip, equipProgress, recoil, pt); + firstPersonRenderer.renderItem(mc.player, heldItem, + rightHand ? ItemCameraTransforms.TransformType.FIRST_PERSON_RIGHT_HAND + : ItemCameraTransforms.TransformType.FIRST_PERSON_LEFT_HAND, + !rightHand, ms, buffer, light); + ms.pop(); + + event.setCanceled(true); + } + + public void dontAnimateItem(Hand hand) { + ClientPlayerEntity player = Minecraft.getInstance().player; + boolean rightHand = hand == Hand.MAIN_HAND ^ player.getPrimaryHand() == HandSide.LEFT; + dontReequipRight |= rightHand; + dontReequipLeft |= !rightHand; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java index a99ebf2cd..0bf447cbe 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperBeamPacket.java @@ -1,64 +1,49 @@ package com.simibubi.create.content.curiosities.zapper; -import java.util.function.Supplier; - +import com.simibubi.create.CreateClient; import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler.LaserBeam; -import com.simibubi.create.foundation.networking.SimplePacketBase; -import net.minecraft.client.Minecraft; import net.minecraft.network.PacketBuffer; import net.minecraft.util.Hand; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.network.NetworkEvent.Context; +import net.minecraftforge.api.distmarker.OnlyIn; -public class ZapperBeamPacket extends SimplePacketBase { +public class ZapperBeamPacket extends ShootGadgetPacket { - public Vector3d start; public Vector3d target; - public Hand hand; - public boolean self; public ZapperBeamPacket(Vector3d start, Vector3d target, Hand hand, boolean self) { - this.start = start; + super(start, hand, self); this.target = target; - this.hand = hand; - this.self = self; - } - - public ZapperBeamPacket(PacketBuffer buffer) { - start = new Vector3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); - target = new Vector3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); - hand = buffer.readBoolean()? Hand.MAIN_HAND : Hand.OFF_HAND; - self = buffer.readBoolean(); } - public void write(PacketBuffer buffer) { - buffer.writeDouble(start.x); - buffer.writeDouble(start.y); - buffer.writeDouble(start.z); + public ZapperBeamPacket(PacketBuffer buffer) { + super(buffer); + } + + @Override + protected void readAdditional(PacketBuffer buffer) { + target = new Vector3d(buffer.readDouble(), buffer.readDouble(), buffer.readDouble()); + } + + @Override + protected void writeAdditional(PacketBuffer buffer) { buffer.writeDouble(target.x); buffer.writeDouble(target.y); buffer.writeDouble(target.z); - - buffer.writeBoolean(hand == Hand.MAIN_HAND); - buffer.writeBoolean(self); } - public void handle(Supplier context) { - context.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { - if (Minecraft.getInstance().player.getPositionVec().distanceTo(start) > 100) - return; - ZapperRenderHandler.addBeam(new LaserBeam(start, target).followPlayer(self, hand == Hand.MAIN_HAND)); - - if (self) - ZapperRenderHandler.shoot(hand); - else - ZapperRenderHandler.playSound(hand, new BlockPos(start)); - })); - context.get().setPacketHandled(true); + @Override + @OnlyIn(Dist.CLIENT) + protected ShootableGadgetRenderHandler getHandler() { + return CreateClient.ZAPPER_RENDER_HANDLER; + } + + @Override + @OnlyIn(Dist.CLIENT) + protected void handleAdditional() { + CreateClient.ZAPPER_RENDER_HANDLER.addBeam(new LaserBeam(location, target)); } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java index f6e573b8e..3d2f209e4 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItem.java @@ -6,8 +6,8 @@ import javax.annotation.Nonnull; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllTags.AllBlockTags; +import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.item.ItemDescription; -import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.BlockHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.NBTProcessors; @@ -17,7 +17,6 @@ import net.minecraft.block.Blocks; import net.minecraft.client.util.ITooltipFlag; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; @@ -28,7 +27,6 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; -import net.minecraft.util.HandSide; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.RayTraceContext; @@ -43,7 +41,6 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.network.PacketDistributor; public abstract class ZapperItem extends Item { @@ -95,7 +92,10 @@ public abstract class ZapperItem extends Item { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { openHandgunGUI(context.getItem(), context.getHand() == Hand.OFF_HAND); }); - applyCooldown(context.getPlayer(), context.getItem(), false); + context.getPlayer() + .getCooldownTracker() + .setCooldown(context.getItem() + .getItem(), 10); } return ActionResultType.SUCCESS; } @@ -106,6 +106,7 @@ public abstract class ZapperItem extends Item { public ActionResult onItemRightClick(World world, PlayerEntity player, Hand hand) { ItemStack item = player.getHeldItem(hand); CompoundNBT nbt = item.getOrCreateTag(); + boolean mainHand = hand == Hand.MAIN_HAND; // Shift -> Open GUI if (player.isSneaking()) { @@ -113,36 +114,21 @@ public abstract class ZapperItem extends Item { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> { openHandgunGUI(item, hand == Hand.OFF_HAND); }); - applyCooldown(player, item, false); + player.getCooldownTracker() + .setCooldown(item.getItem(), 10); } return new ActionResult<>(ActionResultType.SUCCESS, item); } - boolean mainHand = hand == Hand.MAIN_HAND; - boolean isSwap = item.getTag() - .contains("_Swap"); - boolean gunInOtherHand = isZapper(player.getHeldItem(mainHand ? Hand.OFF_HAND : Hand.MAIN_HAND)); - - // Pass To Offhand - if (mainHand && isSwap && gunInOtherHand) + if (ShootableGadgetItemMethods.shouldSwap(player, item, hand, this::isZapper)) return new ActionResult<>(ActionResultType.FAIL, item); - if (mainHand && !isSwap && gunInOtherHand) - item.getTag() - .putBoolean("_Swap", true); - if (!mainHand && isSwap) - item.getTag() - .remove("_Swap"); - if (!mainHand && gunInOtherHand) - player.getHeldItem(Hand.MAIN_HAND) - .getTag() - .remove("_Swap"); - player.setActiveHand(hand); // Check if can be used ITextComponent msg = validateUsage(item); if (msg != null) { AllSoundEvents.DENY.play(world, player, player.getBlockPos()); - player.sendStatusMessage(msg.copy().formatted(TextFormatting.RED), true); + player.sendStatusMessage(msg.copy() + .formatted(TextFormatting.RED), true); return new ActionResult<>(ActionResultType.FAIL, item); } @@ -167,31 +153,24 @@ public abstract class ZapperItem extends Item { // No target if (pos == null || stateReplaced.getBlock() == Blocks.AIR) { - applyCooldown(player, item, gunInOtherHand); + ShootableGadgetItemMethods.applyCooldown(player, item, hand, this::isZapper, getCooldownDelay(item)); return new ActionResult<>(ActionResultType.SUCCESS, item); } // Find exact position of gun barrel for VFX - float yaw = (float) ((player.rotationYaw) / -180 * Math.PI); - float pitch = (float) ((player.rotationPitch) / -180 * Math.PI); - Vector3d barrelPosNoTransform = - new Vector3d(mainHand == (player.getPrimaryHand() == HandSide.RIGHT) ? -.35f : .35f, -0.1f, 1); - Vector3d barrelPos = start.add(barrelPosNoTransform.rotatePitch(pitch) - .rotateYaw(yaw)); + Vector3d barrelPos = ShootableGadgetItemMethods.getGunBarrelVec(player, mainHand, new Vector3d(.35f, -0.1f, 1)); // Client side if (world.isRemote) { - ZapperRenderHandler.dontAnimateItem(hand); + CreateClient.ZAPPER_RENDER_HANDLER.dontAnimateItem(hand); return new ActionResult<>(ActionResultType.SUCCESS, item); } // Server side if (activate(world, player, item, stateToUse, raytrace, data)) { - applyCooldown(player, item, gunInOtherHand); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> player), - new ZapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, false)); - AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity) player), - new ZapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, true)); + ShootableGadgetItemMethods.applyCooldown(player, item, hand, this::isZapper, getCooldownDelay(item)); + ShootableGadgetItemMethods.sendPackets(player, + b -> new ZapperBeamPacket(barrelPos, raytrace.getHitVec(), hand, b)); } return new ActionResult<>(ActionResultType.SUCCESS, item); @@ -218,12 +197,6 @@ public abstract class ZapperItem extends Item { return false; } - protected void applyCooldown(PlayerEntity playerIn, ItemStack item, boolean dual) { - int delay = getCooldownDelay(item); - playerIn.getCooldownTracker() - .setCooldown(item.getItem(), dual ? delay * 2 / 3 : delay); - } - @Override public boolean onEntitySwing(ItemStack stack, LivingEntity entity) { return true; diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java index db8beb57b..91f05d0b0 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperItemRenderer.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.curiosities.zapper; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.item.render.CustomRenderedItemModel; import com.simibubi.create.foundation.item.render.CustomRenderedItemModelRenderer; import com.simibubi.create.foundation.item.render.PartialItemModelRenderer; @@ -50,12 +51,8 @@ public abstract class ZapperItemRenderer exte } protected float getAnimationProgress(float pt, boolean leftHanded, boolean mainHand) { - float last = mainHand ^ leftHanded ? ZapperRenderHandler.lastRightHandAnimation - : ZapperRenderHandler.lastLeftHandAnimation; - float current = - mainHand ^ leftHanded ? ZapperRenderHandler.rightHandAnimation : ZapperRenderHandler.leftHandAnimation; - float animation = MathHelper.clamp(MathHelper.lerp(pt, last, current) * 5, 0, 1); - return animation; + float animation = CreateClient.ZAPPER_RENDER_HANDLER.getAnimation(mainHand ^ leftHanded, pt); + return MathHelper.clamp(animation * 5, 0, 1); } } diff --git a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java index 38d37a547..90875e628 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java +++ b/src/main/java/com/simibubi/create/content/curiosities/zapper/ZapperRenderHandler.java @@ -8,79 +8,28 @@ import java.util.function.Supplier; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.CreateClient; -import com.simibubi.create.foundation.utility.AnimationTickHolder; import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.player.AbstractClientPlayerEntity; -import net.minecraft.client.entity.player.ClientPlayerEntity; -import net.minecraft.client.renderer.FirstPersonRenderer; -import net.minecraft.client.renderer.entity.PlayerRenderer; -import net.minecraft.client.renderer.model.ItemCameraTransforms; import net.minecraft.client.world.ClientWorld; import net.minecraft.item.ItemStack; import net.minecraft.particles.ParticleTypes; import net.minecraft.util.Hand; -import net.minecraft.util.HandSide; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3f; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RenderHandEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod.EventBusSubscriber; -@EventBusSubscriber(value = Dist.CLIENT) -public class ZapperRenderHandler { +public class ZapperRenderHandler extends ShootableGadgetRenderHandler { - public static List cachedBeams; - public static float leftHandAnimation; - public static float rightHandAnimation; - public static float lastLeftHandAnimation; - public static float lastRightHandAnimation; + public List cachedBeams; - private static boolean dontReequipLeft; - private static boolean dontReequipRight; - - public static class LaserBeam { - float itensity; - Vector3d start; - Vector3d end; - boolean follow; - boolean mainHand; - - public LaserBeam(Vector3d start, Vector3d end) { - this.start = start; - this.end = end; - itensity = 1; - } - - public LaserBeam followPlayer(boolean follow, boolean mainHand) { - this.follow = follow; - this.mainHand = mainHand; - return this; - } + @Override + protected boolean appliesTo(ItemStack stack) { + return stack.getItem() instanceof ZapperItem; } - public static Vector3d getExactBarrelPos(boolean mainHand) { - float partialTicks = AnimationTickHolder.getPartialTicks(); - ClientPlayerEntity player = Minecraft.getInstance().player; - float yaw = (float) ((player.getYaw(partialTicks)) / -180 * Math.PI); - float pitch = (float) ((player.getPitch(partialTicks)) / -180 * Math.PI); - boolean rightHand = mainHand == (player.getPrimaryHand() == HandSide.RIGHT); - float zOffset = ((float) Minecraft.getInstance().gameSettings.fov - 70) / -100; - Vector3d barrelPosNoTransform = new Vector3d(rightHand ? -.35f : .35f, -0.115f, .75f + zOffset); - Vector3d barrelPos = player.getEyePosition(partialTicks) - .add(barrelPosNoTransform.rotatePitch(pitch) - .rotateYaw(yaw)); - return barrelPos; - } - - public static void tick() { - lastLeftHandAnimation = leftHandAnimation; - lastRightHandAnimation = rightHandAnimation; - leftHandAnimation *= 0.8f; - rightHandAnimation *= 0.8f; + @Override + public void tick() { + super.tick(); if (cachedBeams == null) cachedBeams = new LinkedList<>(); @@ -91,34 +40,31 @@ public class ZapperRenderHandler { cachedBeams.forEach(beam -> { CreateClient.OUTLINER.endChasingLine(beam, beam.start, beam.end, 1 - beam.itensity) - .disableNormals() - .colored(0xffffff) - .lineWidth(beam.itensity * 1 / 8f); + .disableNormals() + .colored(0xffffff) + .lineWidth(beam.itensity * 1 / 8f); }); cachedBeams.forEach(b -> b.itensity *= .6f); } - public static void shoot(Hand hand) { - ClientPlayerEntity player = Minecraft.getInstance().player; - boolean rightHand = hand == Hand.MAIN_HAND ^ player.getPrimaryHand() == HandSide.LEFT; - if (rightHand) { - rightHandAnimation = .2f; - dontReequipRight = false; - } else { - leftHandAnimation = .2f; - dontReequipLeft = false; - } - playSound(hand, player.getBlockPos()); + @Override + protected void transformTool(MatrixStack ms, float flip, float equipProgress, float recoil, float pt) { + ms.translate(flip * -0.1f, 0.1f, -0.4f); + ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(flip * 5.0F)); } - public static void playSound(Hand hand, BlockPos position) { + @Override + protected void transformHand(MatrixStack ms, float flip, float equipProgress, float recoil, float pt) {} + + @Override + protected void playSound(Hand hand, BlockPos position) { float pitch = hand == Hand.MAIN_HAND ? 0.1f : 0.9f; Minecraft mc = Minecraft.getInstance(); AllSoundEvents.WORLDSHAPER_PLACE.play(mc.world, mc.player, position, 0.1f, pitch); } - public static void addBeam(LaserBeam beam) { + public void addBeam(LaserBeam beam) { Random r = new Random(); double x = beam.end.x; double y = beam.end.y; @@ -135,87 +81,16 @@ public class ZapperRenderHandler { cachedBeams.add(beam); } - @SubscribeEvent - public static void onRenderPlayerHand(RenderHandEvent event) { - ItemStack heldItem = event.getItemStack(); - if (!(heldItem.getItem() instanceof ZapperItem)) - return; + public static class LaserBeam { + float itensity; + Vector3d start; + Vector3d end; - Minecraft mc = Minecraft.getInstance(); - boolean rightHand = event.getHand() == Hand.MAIN_HAND ^ mc.player.getPrimaryHand() == HandSide.LEFT; - - MatrixStack ms = event.getMatrixStack(); - - ms.push(); - float recoil = rightHand ? MathHelper.lerp(event.getPartialTicks(), lastRightHandAnimation, rightHandAnimation) - : MathHelper.lerp(event.getPartialTicks(), lastLeftHandAnimation, leftHandAnimation); - - float equipProgress = event.getEquipProgress(); - - if (rightHand && (rightHandAnimation > .01f || dontReequipRight)) - equipProgress = 0; - if (!rightHand && (leftHandAnimation > .01f || dontReequipLeft)) - equipProgress = 0; - - // Render arm - float f = rightHand ? 1.0F : -1.0F; - float f1 = MathHelper.sqrt(event.getSwingProgress()); - float f2 = -0.3F * MathHelper.sin(f1 * (float) Math.PI); - float f3 = 0.4F * MathHelper.sin(f1 * ((float) Math.PI * 2F)); - float f4 = -0.4F * MathHelper.sin(event.getSwingProgress() * (float) Math.PI); - float f5 = MathHelper.sin(event.getSwingProgress() * event.getSwingProgress() * (float) Math.PI); - float f6 = MathHelper.sin(f1 * (float) Math.PI); - - ms.translate(f * (f2 + 0.64000005F - .1f), f3 + -0.4F + equipProgress * -0.6F, - f4 + -0.71999997F + .3f + recoil); - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(f * 75.0F)); - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(f * f6 * 70.0F)); - ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(f * f5 * -20.0F)); - AbstractClientPlayerEntity abstractclientplayerentity = mc.player; - mc.getTextureManager() - .bindTexture(abstractclientplayerentity.getLocationSkin()); - ms.translate(f * -1.0F, 3.6F, 3.5F); - ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(f * 120.0F)); - ms.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(200.0F)); - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(f * -135.0F)); - ms.translate(f * 5.6F, 0.0F, 0.0F); - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(f * 40.0F)); - - PlayerRenderer playerrenderer = (PlayerRenderer) mc.getRenderManager() - .getRenderer(abstractclientplayerentity); - if (rightHand) { - playerrenderer.renderRightArm(event.getMatrixStack(), event.getBuffers(), event.getLight(), - abstractclientplayerentity); - } else { - playerrenderer.renderLeftArm(event.getMatrixStack(), event.getBuffers(), event.getLight(), - abstractclientplayerentity); + public LaserBeam(Vector3d start, Vector3d end) { + this.start = start; + this.end = end; + itensity = 1; } - ms.pop(); - - // Render gun - ms.push(); - ms.translate(f * (f2 + 0.64000005F - .1f), f3 + -0.4F + equipProgress * -0.6F, - f4 + -0.71999997F - 0.1f + recoil); - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(f * f6 * 70.0F)); - ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(f * f5 * -20.0F)); - - ms.translate(f * -0.1f, 0.1f, -0.4f); - ms.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(f * 5.0F)); - - FirstPersonRenderer firstPersonRenderer = mc.getFirstPersonRenderer(); - firstPersonRenderer.renderItem(mc.player, heldItem, - rightHand ? ItemCameraTransforms.TransformType.FIRST_PERSON_RIGHT_HAND - : ItemCameraTransforms.TransformType.FIRST_PERSON_LEFT_HAND, - !rightHand, event.getMatrixStack(), event.getBuffers(), event.getLight()); - ms.pop(); - - event.setCanceled(true); - } - - public static void dontAnimateItem(Hand hand) { - boolean rightHand = hand == Hand.MAIN_HAND ^ Minecraft.getInstance().player.getPrimaryHand() == HandSide.LEFT; - dontReequipRight |= rightHand; - dontReequipLeft |= !rightHand; } } diff --git a/src/main/java/com/simibubi/create/events/ClientEvents.java b/src/main/java/com/simibubi/create/events/ClientEvents.java index 03ec16835..a3cc41529 100644 --- a/src/main/java/com/simibubi/create/events/ClientEvents.java +++ b/src/main/java/com/simibubi/create/events/ClientEvents.java @@ -3,7 +3,6 @@ package com.simibubi.create.events; import java.util.ArrayList; import java.util.List; -import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.systems.RenderSystem; import com.simibubi.create.AllFluids; @@ -30,7 +29,6 @@ import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; import com.simibubi.create.content.curiosities.tools.ExtendoGripRenderHandler; import com.simibubi.create.content.curiosities.weapons.PotatoCannonItem; import com.simibubi.create.content.curiosities.zapper.ZapperItem; -import com.simibubi.create.content.curiosities.zapper.ZapperRenderHandler; import com.simibubi.create.content.curiosities.zapper.terrainzapper.WorldshaperRenderHandler; import com.simibubi.create.content.logistics.block.depot.EjectorTargetHandler; import com.simibubi.create.content.logistics.block.mechanicalArm.ArmInteractionPointHandler; @@ -117,6 +115,8 @@ public class ClientEvents { CreateClient.SCHEMATIC_SENDER.tick(); CreateClient.SCHEMATIC_AND_QUILL_HANDLER.tick(); CreateClient.SCHEMATIC_HANDLER.tick(); + CreateClient.ZAPPER_RENDER_HANDLER.tick(); + CreateClient.POTATO_CANNON_RENDER_HANDLER.tick(); ContraptionHandler.tick(world); CapabilityMinecartController.tick(world); @@ -135,7 +135,6 @@ public class ClientEvents { CouplingHandlerClient.tick(); CouplingRenderer.tickDebugModeRenders(); KineticDebugger.tick(); - ZapperRenderHandler.tick(); ExtendoGripRenderHandler.tick(); // CollisionDebugger.tick(); ArmInteractionPointHandler.tick();