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
This commit is contained in:
simibubi 2021-06-26 16:32:56 +02:00
parent 6feacd3fc2
commit fbcaa1b931
16 changed files with 670 additions and 329 deletions

View file

@ -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) {

View file

@ -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));

View file

@ -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<ItemStack> 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;

View file

@ -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<PotatoCannonModel> {
@ -26,16 +29,18 @@ public class PotatoCannonItemRenderer extends CustomRenderedItemModelRenderer<Po
ClientPlayerEntity player = Minecraft.getInstance().player;
boolean mainHand = player.getHeldItemMainhand() == stack;
boolean offHand = player.getHeldItemOffhand() == stack;
boolean leftHanded = player.getPrimaryHand() == HandSide.LEFT;
float speed = PotatoCannonItem.PREV_SHOT == 0 ? 0
: (PotatoCannonItem.PREV_SHOT - AnimationTickHolder.getPartialTicks()) / 5f;
float offset = .5f / 16;
float worldTime = AnimationTickHolder.getRenderTime() / 10;
float angle = worldTime * -25;
if (mainHand || offHand)
angle += 30 * speed * speed;
float speed = CreateClient.POTATO_CANNON_RENDER_HANDLER.getAnimation(mainHand ^ leftHanded,
AnimationTickHolder.getPartialTicks());
if (mainHand || offHand)
angle += 360 * MathHelper.clamp(speed * 5, 0, 1);
angle %= 360;
float offset = .5f / 16;
ms.push();
ms.translate(0, offset, 0);
ms.multiply(Vector3f.POSITIVE_Z.getDegreesQuaternion(angle));

View file

@ -1,27 +1,59 @@
package com.simibubi.create.content.curiosities.weapons;
import java.util.function.Supplier;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.curiosities.zapper.ShootGadgetPacket;
import com.simibubi.create.content.curiosities.zapper.ShootableGadgetRenderHandler;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent.Context;
import net.minecraft.util.Hand;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class PotatoCannonPacket extends SimplePacketBase {
public class PotatoCannonPacket extends ShootGadgetPacket {
public PotatoCannonPacket() {}
private float pitch;
private Vector3d motion;
private ItemStack item;
public PotatoCannonPacket(PacketBuffer buffer) {}
public PotatoCannonPacket(Vector3d location, Vector3d motion, ItemStack item, Hand hand, float pitch, boolean self) {
super(location, hand, self);
this.motion = motion;
this.item = item;
this.pitch = pitch;
}
public PotatoCannonPacket(PacketBuffer buffer) {
super(buffer);
}
@Override
public void write(PacketBuffer buffer) {}
protected void readAdditional(PacketBuffer buffer) {
pitch = buffer.readFloat();
motion = new Vector3d(buffer.readFloat(), buffer.readFloat(), buffer.readFloat());
item = buffer.readItemStack();
}
@Override
public void handle(Supplier<Context> 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;
}
}

View file

@ -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<EntityRayTraceResult> onEntityHit = e -> {
};
private Consumer<BlockRayTraceResult> onBlockHit = e -> {
private BiConsumer<IWorld, BlockRayTraceResult> 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<EntityRayTraceResult> 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<IWorld, BlockRayTraceResult> plantCrop(IRegistryDelegate<? extends Block> 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<BlockRayTraceResult> callback) {
public Builder onBlockHit(BiConsumer<IWorld, BlockRayTraceResult> callback) {
result.onBlockHit = callback;
return this;
}

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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) {
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);
}
}

View file

@ -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<ItemStack> 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<Boolean, ? extends ShootGadgetPacket> 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<ItemStack> 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;
}
}

View file

@ -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;
}
}

View file

@ -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) {
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));
}
}

View file

@ -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<ItemStack> 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;

View file

@ -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<M extends CustomRenderedItemModel> 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);
}
}

View file

@ -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<LaserBeam> cachedBeams;
public static float leftHandAnimation;
public static float rightHandAnimation;
public static float lastLeftHandAnimation;
public static float lastRightHandAnimation;
public List<LaserBeam> 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;
}
}

View file

@ -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();