diff --git a/gradle.properties b/gradle.properties index 7d27403a..13ef279d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,10 +9,9 @@ major_mod=3 # Changing the order or variables of enums. etc major_api=4 # Adding items, blocks, tile entities, etc. -minor=0 +minor=1 # bugfix patch=0 -# A or B or R forge_version=1.16.5-36.2.34 patchouli_version=1.16.4-53.3 jei_version=7.7.1.153 \ No newline at end of file diff --git a/src/main/java/com/alrex/parcool/ParCool.java b/src/main/java/com/alrex/parcool/ParCool.java index 2297a9e7..b93928fa 100644 --- a/src/main/java/com/alrex/parcool/ParCool.java +++ b/src/main/java/com/alrex/parcool/ParCool.java @@ -44,7 +44,7 @@ @Mod(ParCool.MOD_ID) public class ParCool { public static final String MOD_ID = "parcool"; - private static final String PROTOCOL_VERSION = "3.4.0.0"; + private static final String PROTOCOL_VERSION = "3.4.0.5"; public static final SimpleChannel CHANNEL_INSTANCE = NetworkRegistry.newSimpleChannel( new ResourceLocation(ParCool.MOD_ID, "message"), () -> PROTOCOL_VERSION, diff --git a/src/main/java/com/alrex/parcool/client/hud/impl/LightStaminaHUD.java b/src/main/java/com/alrex/parcool/client/hud/impl/LightStaminaHUD.java index 84872700..8f488662 100644 --- a/src/main/java/com/alrex/parcool/client/hud/impl/LightStaminaHUD.java +++ b/src/main/java/com/alrex/parcool/client/hud/impl/LightStaminaHUD.java @@ -71,20 +71,17 @@ public void onTick(TickEvent.ClientTickEvent event, ClientPlayerEntity player) { } } - public void render(RenderGameOverlayEvent.Post event, MatrixStack stack) { + public void render(RenderGameOverlayEvent.Post event, MatrixStack stack, Parkourability parkourability, IStamina stamina) { ClientPlayerEntity player = Minecraft.getInstance().player; if (player == null || player.isCreative()) return; - IStamina stamina = IStamina.get(player); - Parkourability parkourability = Parkourability.get(player); - if (stamina == null || parkourability == null) return; - final boolean inexhaustible = player.hasEffect(Effects.INEXHAUSTIBLE.get()); final boolean exhausted = stamina.isExhausted(); if (!showStatus) { long gameTime = player.level.getGameTime(); - if (gameTime - lastStaminaChangedTick > 40) return; + if (gameTime - lastStaminaChangedTick > 40 && !ParCoolConfig.Client.Booleans.ShowLightStaminaHUDAlways.get()) + return; } float staminaScale = (float) stamina.get() / stamina.getActualMaxStamina(); if (staminaScale < 0) staminaScale = 0; diff --git a/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUD.java b/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUD.java index 7a37a775..13ea37d5 100644 --- a/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUD.java +++ b/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUD.java @@ -63,19 +63,11 @@ public void onTick(TickEvent.ClientTickEvent event, ClientPlayerEntity player) { } } - public void render(RenderGameOverlayEvent.Post event, MatrixStack stack) { + public void render(RenderGameOverlayEvent.Post event, MatrixStack stack, Parkourability parkourability, IStamina stamina) { ClientPlayerEntity player = Minecraft.getInstance().player; if (player == null) return; if (player.isCreative()) return; - IStamina stamina = IStamina.get(player); - Parkourability parkourability = Parkourability.get(player); - if (stamina == null || parkourability == null) return; - - if (ParCoolConfig.Client.Booleans.HideStaminaHUDWhenStaminaIsInfinite.get() && - parkourability.getActionInfo().isStaminaInfinite(player.isCreative() || player.isSpectator()) - ) return; - MainWindow window = Minecraft.getInstance().getWindow(); Position position = new Position( ParCoolConfig.Client.AlignHorizontalStaminaHUD.get(), diff --git a/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUDController.java b/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUDController.java index b02b06e3..e68c3f0d 100644 --- a/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUDController.java +++ b/src/main/java/com/alrex/parcool/client/hud/impl/StaminaHUDController.java @@ -2,7 +2,8 @@ import com.alrex.parcool.api.client.gui.ParCoolHUDEvent; import com.alrex.parcool.common.capability.IStamina; -import com.alrex.parcool.common.capability.stamina.Stamina; +import com.alrex.parcool.common.capability.Parkourability; +import com.alrex.parcool.common.capability.stamina.ParCoolStamina; import com.alrex.parcool.config.ParCoolConfig; import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.Minecraft; @@ -36,18 +37,29 @@ public void onTick(TickEvent.ClientTickEvent event) { public void render(RenderGameOverlayEvent.Post event, MatrixStack stack) { ClientPlayerEntity player = Minecraft.getInstance().player; if (player == null) return; - if (!ParCoolConfig.Client.Booleans.ParCoolIsActive.get() || - !(IStamina.get(player) instanceof Stamina)) - return; + if (!ParCoolConfig.Client.Booleans.ParCoolIsActive.get()) return; if (event.getType() != RenderGameOverlayEvent.ElementType.EXPERIENCE) return; + + Parkourability parkourability = Parkourability.get(player); + if (parkourability == null) return; + + if (ParCoolConfig.Client.Booleans.HideStaminaHUDWhenStaminaIsInfinite.get() && + parkourability.getActionInfo().isStaminaInfinite(player.isCreative() || player.isSpectator()) + ) return; + + IStamina stamina = IStamina.get(player); + if (stamina == null) return; + + if (!(stamina instanceof ParCoolStamina)) return; + if (MinecraftForge.EVENT_BUS.post(new ParCoolHUDEvent.RenderEvent(event, stack))) return; switch (ParCoolConfig.Client.StaminaHUDType.get()) { case Light: - lightStaminaHUD.render(event, stack); + lightStaminaHUD.render(event, stack, parkourability, stamina); break; case Normal: - staminaHUD.render(event, stack); + staminaHUD.render(event, stack, parkourability, stamina); break; } } diff --git a/src/main/java/com/alrex/parcool/client/input/KeyBindings.java b/src/main/java/com/alrex/parcool/client/input/KeyBindings.java index 067d911a..b747e4d7 100644 --- a/src/main/java/com/alrex/parcool/client/input/KeyBindings.java +++ b/src/main/java/com/alrex/parcool/client/input/KeyBindings.java @@ -40,7 +40,8 @@ public static KeyBinding getKeySprint() { public static Boolean isKeyJumpDown() { return mc.player != null - && mc.player.input.jumping; + && mc.player.input != null + && mc.player.input.jumping; } public static KeyBinding getKeySneak() { @@ -49,30 +50,31 @@ public static KeyBinding getKeySneak() { public static Boolean isAnyMovingKeyDown() { return mc.player != null - && (mc.player.input.left - || mc.player.input.right - || mc.player.input.forwardImpulse != 0 - || mc.player.input.leftImpulse != 0); + && mc.player.input != null + && (mc.player.input.left + || mc.player.input.right + || mc.player.input.forwardImpulse != 0 + || mc.player.input.leftImpulse != 0); } public static Boolean isLeftAndRightDown() { - return mc.player != null && mc.player.input.left && mc.player.input.right; + return mc.player != null && mc.player.input != null && mc.player.input.left && mc.player.input.right; } public static Boolean isKeyForwardDown() { - return mc.player != null && mc.player.input.forwardImpulse > 0; + return mc.player != null && mc.player.input != null && mc.player.input.forwardImpulse > 0; } public static Boolean isKeyLeftDown() { - return mc.player != null && mc.player.input.left; + return mc.player != null && mc.player.input != null && mc.player.input.left; } public static Boolean isKeyRightDown() { - return mc.player != null && mc.player.input.right; + return mc.player != null && mc.player.input != null && mc.player.input.right; } public static Boolean isKeyBackDown() { - return mc.player != null && mc.player.input.forwardImpulse < 0; + return mc.player != null && mc.player.input != null && mc.player.input.forwardImpulse < 0; } public static KeyBinding getKeyBindEnable() { diff --git a/src/main/java/com/alrex/parcool/client/renderer/entity/ZiplineRopeRenderer.java b/src/main/java/com/alrex/parcool/client/renderer/entity/ZiplineRopeRenderer.java index cbaa3e98..b01da073 100644 --- a/src/main/java/com/alrex/parcool/client/renderer/entity/ZiplineRopeRenderer.java +++ b/src/main/java/com/alrex/parcool/client/renderer/entity/ZiplineRopeRenderer.java @@ -77,7 +77,7 @@ private void renderRope(ZiplineRopeEntity entity, float partialTick, MatrixStack int endSkyBrightness = entity.level.getBrightness(LightType.SKY, end); - final int divisionCount = 24; + int divisionCount = Math.min((int) Math.ceil(endOffsetFromStart.length() / 0.6), 24); float invLengthSqrtXZ = (float) MathHelper.fastInvSqrt(endOffsetFromStart.x() * endOffsetFromStart.x() + endOffsetFromStart.z() * endOffsetFromStart.z()); float unitLengthX = (float) (endOffsetFromStart.x() * invLengthSqrtXZ); float unitLengthZ = (float) (endOffsetFromStart.z() * invLengthSqrtXZ); diff --git a/src/main/java/com/alrex/parcool/common/action/Action.java b/src/main/java/com/alrex/parcool/common/action/Action.java index 42e218e2..671f914a 100644 --- a/src/main/java/com/alrex/parcool/common/action/Action.java +++ b/src/main/java/com/alrex/parcool/common/action/Action.java @@ -15,6 +15,10 @@ public abstract class Action { private int doingTick = 0; private int notDoingTick = 0; + public boolean isJustStarted() { + return isDoing() && getDoingTick() == 0; + } + public void setDoingTick(int doingTick) { this.doingTick = doingTick; } diff --git a/src/main/java/com/alrex/parcool/common/action/ActionList.java b/src/main/java/com/alrex/parcool/common/action/ActionList.java index ff9466a5..a245ff05 100644 --- a/src/main/java/com/alrex/parcool/common/action/ActionList.java +++ b/src/main/java/com/alrex/parcool/common/action/ActionList.java @@ -1,6 +1,7 @@ package com.alrex.parcool.common.action; import com.alrex.parcool.common.action.impl.*; +import com.alrex.parcool.common.action.instant.StartSwimByCrawl; import javax.annotation.Nullable; import java.util.Arrays; @@ -37,7 +38,9 @@ public class ActionList { new ActionRegistry<>(Vault.class, Vault::new, 50), new ActionRegistry<>(VerticalWallRun.class, VerticalWallRun::new, 150), new ActionRegistry<>(WallJump.class, WallJump::new, 120), - new ActionRegistry<>(WallSlide.class, WallSlide::new, 8) + new ActionRegistry<>(WallSlide.class, WallSlide::new, 8), + + new ActionRegistry<>(StartSwimByCrawl.class, StartSwimByCrawl::new, 0) ); private static final HashMap, Short> INDEX_MAP; private static final TreeMap NAME_2_INDEX_MAP; diff --git a/src/main/java/com/alrex/parcool/common/action/ActionProcessor.java b/src/main/java/com/alrex/parcool/common/action/ActionProcessor.java index 989347fb..3693d28a 100644 --- a/src/main/java/com/alrex/parcool/common/action/ActionProcessor.java +++ b/src/main/java/com/alrex/parcool/common/action/ActionProcessor.java @@ -70,8 +70,9 @@ public void onTick(TickEvent.PlayerTickEvent event) { } ParCool.LOGGER.log(Level.WARN, "Detected ParCool Limitation is not synced. Sending synchronization request..."); } else if (trialCount == 5) { + parkourability.incrementSynchronizeTrialCount(); player.displayClientMessage(new TranslationTextComponent("parcool.message.error.limitation.fail_sync").withStyle(TextFormatting.DARK_RED), false); - ParCool.LOGGER.log(Level.ERROR, "Failed to synchronize ParCool Limitation. Please report to developer"); + ParCool.LOGGER.log(Level.ERROR, "Failed to synchronize ParCool Limitation. There may be problems about server connection. Please report to the developer after checking connection"); } } } @@ -173,7 +174,7 @@ public void onTick(TickEvent.PlayerTickEvent event) { staminaSyncCoolTimeTick = 0; SyncStaminaMessage.sync(player); } - if (stamina.isExhausted()) { + if (stamina.isImposingExhaustionPenalty() && parkourability.getClientInfo().get(ParCoolConfig.Client.Booleans.EnableStaminaExhaustionPenalty)) { player.setSprinting(false); } } diff --git a/src/main/java/com/alrex/parcool/common/action/InstantAction.java b/src/main/java/com/alrex/parcool/common/action/InstantAction.java new file mode 100644 index 00000000..e46cd49e --- /dev/null +++ b/src/main/java/com/alrex/parcool/common/action/InstantAction.java @@ -0,0 +1,44 @@ +package com.alrex.parcool.common.action; + +import com.alrex.parcool.common.capability.IStamina; +import com.alrex.parcool.common.capability.Parkourability; +import net.minecraft.entity.player.PlayerEntity; + +public abstract class InstantAction extends Action { + @Override + public final boolean canContinue(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + return false; + } + + @Override + public final void onWorkingTick(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + } + + @Override + public final void onWorkingTickInClient(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + } + + @Override + public final void onWorkingTickInLocalClient(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + } + + @Override + public final void onWorkingTickInServer(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + } + + @Override + public final void onStop(PlayerEntity player) { + } + + @Override + public final void onStopInServer(PlayerEntity player) { + } + + @Override + public final void onStopInOtherClient(PlayerEntity player) { + } + + @Override + public final void onStopInLocalClient(PlayerEntity player) { + } +} diff --git a/src/main/java/com/alrex/parcool/common/action/impl/CatLeap.java b/src/main/java/com/alrex/parcool/common/action/impl/CatLeap.java index aff23896..aba89c7d 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/CatLeap.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/CatLeap.java @@ -60,6 +60,7 @@ public boolean canStart(PlayerEntity player, Parkourability parkourability, ISta movement = movement.multiply(1, 0, 1).normalize(); startInfo.putDouble(movement.x()).putDouble(movement.z()); return (player.isOnGround() + && !player.isInWater() && !stamina.isExhausted() && coolTimeTick <= 0 && readyTick > 0 diff --git a/src/main/java/com/alrex/parcool/common/action/impl/Crawl.java b/src/main/java/com/alrex/parcool/common/action/impl/Crawl.java index 141c5ae1..7bea6bee 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/Crawl.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/Crawl.java @@ -32,6 +32,7 @@ && disambiguateCommands(player, pose) && !parkourability.isDoingAny(Roll.class, Tap.class, ClingToCliff.class, Dive.class) && parkourability.get(Vault.class).getNotDoingTick() >= 8 && !parkourability.get(HideInBlock.class).isDoing() + && !parkourability.get(RideZipline.class).isDoing() && player.getVehicle() == null && (pose == Pose.STANDING || pose == Pose.CROUCHING) && !player.isInWaterOrBubble() diff --git a/src/main/java/com/alrex/parcool/common/action/impl/HideInBlock.java b/src/main/java/com/alrex/parcool/common/action/impl/HideInBlock.java index 1943c1d6..36d609b6 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/HideInBlock.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/HideInBlock.java @@ -220,13 +220,6 @@ public void onStopInLocalClient(PlayerEntity player) { player.playSound(player.level.getBlockState(new BlockPos(hidingPoint.add(0, 0.2, 0))).getSoundType().getBreakSound(), 1, 1); } - @Override - public void onTick(PlayerEntity player, Parkourability parkourability, IStamina stamina) { - if (!isDoing() && getNotDoingTick() <= 1) { - player.noPhysics = true; - } - } - @Override public void onStopInOtherClient(PlayerEntity player) { spawnOnHideParticles(player); diff --git a/src/main/java/com/alrex/parcool/common/action/impl/HorizontalWallRun.java b/src/main/java/com/alrex/parcool/common/action/impl/HorizontalWallRun.java index 2ea673dd..f9d663b8 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/HorizontalWallRun.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/HorizontalWallRun.java @@ -15,12 +15,14 @@ import com.alrex.parcool.utilities.WorldUtil; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; +import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.ai.attributes.Attributes; import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particles.BlockParticleData; import net.minecraft.particles.ParticleTypes; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector2f; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; @@ -142,16 +144,26 @@ public boolean canStart(PlayerEntity player, Parkourability parkourability, ISta public boolean canContinue(PlayerEntity player, Parkourability parkourability, IStamina stamina) { Vector3d wallDirection = WorldUtil.getRunnableWall(player, player.getBbWidth() * 0.65f); if (wallDirection == null) return false; + if (!(player instanceof ClientPlayerEntity)) return false; + ClientPlayerEntity localPlayer = (ClientPlayerEntity) player; + if (localPlayer.input == null) return false; + Vector2f moveVector = localPlayer.input.getMoveVector(); + Vector3d actualInputVector + = new Vector3d(moveVector.x, 0, moveVector.y) + .normalize() + .yRot((float) -Math.toRadians(player.yRot)); + // Input almost opposite to wall + if (wallDirection.normalize().dot(actualInputVector) < -0.86) { + return false; + } return (getDoingTick() < getMaxRunningTick(parkourability.getActionInfo()) && !stamina.isExhausted() && !parkourability.get(WallJump.class).justJumped() && !parkourability.get(Crawl.class).isDoing() && !parkourability.get(Dodge.class).isDoing() && !parkourability.get(Vault.class).isDoing() - && ( - (ParCoolConfig.Client.HWallRunControl.get() == ControlType.PressKey && KeyBindings.getKeyHorizontalWallRun().isDown()) - || ParCoolConfig.Client.HWallRunControl.get() == ControlType.Auto - ) + && ((ParCoolConfig.Client.HWallRunControl.get() == ControlType.PressKey && KeyBindings.getKeyHorizontalWallRun().isDown()) + || ParCoolConfig.Client.HWallRunControl.get() == ControlType.Auto) && !player.isOnGround() ); } diff --git a/src/main/java/com/alrex/parcool/common/action/impl/RideZipline.java b/src/main/java/com/alrex/parcool/common/action/impl/RideZipline.java index 7b750007..2dba07d2 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/RideZipline.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/RideZipline.java @@ -13,6 +13,9 @@ import com.alrex.parcool.common.zipline.Zipline; import com.alrex.parcool.utilities.BufferUtil; import com.alrex.parcool.utilities.VectorUtil; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.entity.ai.attributes.Attributes; +import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; @@ -34,6 +37,7 @@ public class RideZipline extends Action { private float currentT; @Nullable private Vector3d currentPos; + private boolean previouslyStopByCollision = false; public double getAcceleration() { return acceleration; @@ -58,6 +62,7 @@ public boolean canStart(PlayerEntity player, Parkourability parkourability, ISta && !player.isSwimming() && !stamina.isExhausted() && (!KeyBindings.isKeyJumpDown() || getNotDoingTick() > 5) + && (!previouslyStopByCollision || getNotDoingTick() > 5) && !parkourability.get(Dive.class).isDoing() && !parkourability.get(Vault.class).isDoing() && !parkourability.get(HangDown.class).isDoing() @@ -78,15 +83,17 @@ public boolean canStart(PlayerEntity player, Parkourability parkourability, ISta @Override public boolean canContinue(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + if (player.horizontalCollision || player.verticalCollision) { + previouslyStopByCollision = true; + return false; + } return KeyBindings.getKeyRideZipline().isDown() && !KeyRecorder.keyJumpState.isPressed() && !player.isInWall() && !stamina.isExhausted() && ridingZipline != null && ridingZipline.isAlive() - && 0 <= currentT && currentT <= 1 - && !player.horizontalCollision - && !player.verticalCollision; + && 0 <= currentT && currentT <= 1; } @Override @@ -120,6 +127,7 @@ public void onStartInOtherClient(PlayerEntity player, Parkourability parkourabil @Override public void onStart(PlayerEntity player, Parkourability parkourability, ByteBuffer startData) { + previouslyStopByCollision = false; endOffsetFromStart = BufferUtil.getVector3d(startData); player.setSprinting(false); parkourability.getBehaviorEnforcer().addMarkerCancellingFallFlying(ID_FALL_FLY_CANCEL, this::isDoing); @@ -128,6 +136,10 @@ public void onStart(PlayerEntity player, Parkourability parkourability, ByteBuff @Override public void onWorkingTickInLocalClient(PlayerEntity player, Parkourability parkourability, IStamina stamina) { if (ridingZipline == null) return; + ModifiableAttributeInstance speedAttr = player.getAttribute(Attributes.MOVEMENT_SPEED); + if (speedAttr == null) return; + if (!(player instanceof ClientPlayerEntity)) return; + ClientPlayerEntity clientPlayer = (ClientPlayerEntity) player; double oldSpeed = speed; Zipline zipline = ridingZipline.getZipline(); @@ -136,11 +148,7 @@ public void onWorkingTickInLocalClient(PlayerEntity player, Parkourability parko speed *= 0.98; if (player.isInWater()) speed *= 0.8; speed -= gravity * slope * (MathHelper.fastInvSqrt(slope * slope + 1)); - Vector3d input = new Vector3d( - (KeyBindings.isKeyRightDown() ? 1. : 0.) + (KeyBindings.isKeyLeftDown() ? -1. : 0.), - 0., - (KeyBindings.isKeyForwardDown() ? 1. : 0.) + (KeyBindings.isKeyBackDown() ? -1. : 0.) - ); + Vector3d input = new Vector3d(-clientPlayer.input.leftImpulse, 0., clientPlayer.input.forwardImpulse); Vector3d offset = zipline.getOffsetToEndFromStart(); if (input.lengthSqr() > 0.01) { double dot = player.getLookAngle() @@ -148,7 +156,7 @@ public void onWorkingTickInLocalClient(PlayerEntity player, Parkourability parko .multiply(1, 0, 1) .normalize() .dot(new Vector3d(offset.x(), 0, offset.z()).normalize()); - speed += dot * 0.01; + speed += Math.min(dot * 0.01 * (speedAttr.getValue() / speedAttr.getBaseValue()), 0.08); } currentT = (float) zipline.getMovedPositionByParameterApproximately(currentT, (float) speed); acceleration = speed - oldSpeed; diff --git a/src/main/java/com/alrex/parcool/common/action/impl/Vault.java b/src/main/java/com/alrex/parcool/common/action/impl/Vault.java index 86df4e7c..923aae04 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/Vault.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/Vault.java @@ -83,9 +83,9 @@ public boolean canStart(PlayerEntity player, Parkourability parkourability, ISta .putDouble(wallHeight); return (!stamina.isExhausted() + && !player.isInWater() && !(ParCoolConfig.Client.Booleans.VaultKeyPressedNeeded.get() && !KeyBindings.getKeyVault().isDown()) && parkourability.get(FastRun.class).canActWithRunning(player) - && !stamina.isExhausted() && (player.isOnGround() || ParCoolConfig.Client.Booleans.EnableVaultInAir.get()) && wallHeight > player.getBbHeight() * 0.44 /*about 0.8*/ ); diff --git a/src/main/java/com/alrex/parcool/common/action/impl/WallJump.java b/src/main/java/com/alrex/parcool/common/action/impl/WallJump.java index 4b001d61..0701933f 100644 --- a/src/main/java/com/alrex/parcool/common/action/impl/WallJump.java +++ b/src/main/java/com/alrex/parcool/common/action/impl/WallJump.java @@ -5,6 +5,7 @@ import com.alrex.parcool.client.animation.impl.WallJumpAnimator; import com.alrex.parcool.client.input.KeyRecorder; import com.alrex.parcool.common.action.Action; +import com.alrex.parcool.common.action.BehaviorEnforcer; import com.alrex.parcool.common.action.StaminaConsumeTiming; import com.alrex.parcool.common.capability.Animation; import com.alrex.parcool.common.capability.IStamina; @@ -30,7 +31,11 @@ public enum ControlType { PressKey, ReleaseKey } + private static final BehaviorEnforcer.ID ID_FALL_FLY_CANCEL = BehaviorEnforcer.newID(); private boolean jump = false; + private boolean inPossibleState = false; + private final ByteBuffer startInfoTempBuffer = ByteBuffer.allocate(64); + private final BehaviorEnforcer.Marker persistentFallFlyCanceler = () -> this.inPossibleState; public boolean justJumped() { return jump; @@ -48,12 +53,19 @@ public void onTick(PlayerEntity player, Parkourability parkourability, IStamina jump = false; } + @Override + public void onClientTick(PlayerEntity player, Parkourability parkourability, IStamina stamina) { + startInfoTempBuffer.clear(); + inPossibleState = checkCanStart(player, parkourability, stamina, startInfoTempBuffer); + startInfoTempBuffer.flip(); + parkourability.getBehaviorEnforcer().addMarkerCancellingFallFlying(ID_FALL_FLY_CANCEL, persistentFallFlyCanceler); + } + @Override public StaminaConsumeTiming getStaminaConsumeTiming() { return StaminaConsumeTiming.OnStart; } - @OnlyIn(Dist.CLIENT) @Nullable private Vector3d getJumpDirection(PlayerEntity player, Vector3d wall) { @@ -78,12 +90,28 @@ private Vector3d getJumpDirection(PlayerEntity player, Vector3d wall) { } @Override + @OnlyIn(Dist.CLIENT) public boolean canStart(PlayerEntity player, Parkourability parkourability, IStamina stamina, ByteBuffer startInfo) { + if (inPossibleState && isInputDone() && startInfoTempBuffer.hasRemaining()) { + startInfo.put(startInfoTempBuffer); + startInfoTempBuffer.rewind(); + return true; + } + return false; + } + + @OnlyIn(Dist.CLIENT) + public boolean isInputDone() { + ControlType control = ParCoolConfig.Client.WallJumpControl.get(); + return (control == ControlType.PressKey && KeyRecorder.keyWallJump.isPressed()) || (control == ControlType.ReleaseKey && KeyRecorder.keyWallJump.isReleased()); + } + + @OnlyIn(Dist.CLIENT) + public boolean checkCanStart(PlayerEntity player, Parkourability parkourability, IStamina stamina, ByteBuffer startInfo) { Vector3d wallDirection = WorldUtil.getWall(player, player.getBbWidth() * 0.65); Vector3d jumpDirection = getJumpDirection(player, wallDirection); if (jumpDirection == null) return false; ClingToCliff cling = parkourability.get(ClingToCliff.class); - ControlType control = ParCoolConfig.Client.WallJumpControl.get(); boolean value = (!stamina.isExhausted() && !player.isOnGround() @@ -93,7 +121,6 @@ public boolean canStart(PlayerEntity player, Parkourability parkourability, ISta && parkourability.getAdditionalProperties().getNotCreativeFlyingTick() > 10 && ((!cling.isDoing() && cling.getNotDoingTick() > 3) || (cling.isDoing() && cling.getFacingDirection() != ClingToCliff.FacingDirection.ToWall)) - && ((control == ControlType.PressKey && KeyRecorder.keyWallJump.isPressed()) || (control == ControlType.ReleaseKey && KeyRecorder.keyWallJump.isReleased())) && !parkourability.get(Crawl.class).isDoing() && !parkourability.get(VerticalWallRun.class).isDoing() && !parkourability.get(RideZipline.class).isDoing() diff --git a/src/main/java/com/alrex/parcool/common/action/instant/StartSwimByCrawl.java b/src/main/java/com/alrex/parcool/common/action/instant/StartSwimByCrawl.java new file mode 100644 index 00000000..50091cde --- /dev/null +++ b/src/main/java/com/alrex/parcool/common/action/instant/StartSwimByCrawl.java @@ -0,0 +1,30 @@ +package com.alrex.parcool.common.action.instant; + +import com.alrex.parcool.client.input.KeyRecorder; +import com.alrex.parcool.common.action.InstantAction; +import com.alrex.parcool.common.action.StaminaConsumeTiming; +import com.alrex.parcool.common.capability.IStamina; +import com.alrex.parcool.common.capability.Parkourability; +import net.minecraft.entity.player.PlayerEntity; + +import java.nio.ByteBuffer; + +public class StartSwimByCrawl extends InstantAction { + @Override + public boolean canStart(PlayerEntity player, Parkourability parkourability, IStamina stamina, ByteBuffer startInfo) { + return player.isInWaterOrBubble() + && !player.isSwimming() + && KeyRecorder.keyCrawlState.isPressed(); + } + + @Override + public void onStart(PlayerEntity player, Parkourability parkourability, ByteBuffer startData) { + player.setSprinting(true); + player.setSwimming(true); + } + + @Override + public StaminaConsumeTiming getStaminaConsumeTiming() { + return StaminaConsumeTiming.None; + } +} diff --git a/src/main/java/com/alrex/parcool/common/block/zipline/ZiplineHookTileEntity.java b/src/main/java/com/alrex/parcool/common/block/zipline/ZiplineHookTileEntity.java index e169d79b..f6cb0a2c 100644 --- a/src/main/java/com/alrex/parcool/common/block/zipline/ZiplineHookTileEntity.java +++ b/src/main/java/com/alrex/parcool/common/block/zipline/ZiplineHookTileEntity.java @@ -194,22 +194,25 @@ public void handleUpdateTag(BlockState state, CompoundNBT tag) { @Override public void tick() { - if (level != null && !level.isClientSide() && connectionEntities.size() < getConnectionPoints().size()) { - List tileEntities = getConnectionPoints() - .stream() - .filter(it -> !connectionEntities.containsKey(it)) - .filter(level::isLoaded) - .map(level::getBlockEntity) - .map(it -> it instanceof ZiplineHookTileEntity ? (ZiplineHookTileEntity) it : null) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - tileEntities.forEach(it -> { - if (it.getConnectionPoints().contains(this.getBlockPos())) { - this.spawnRope(level, it, getConnectionInfo().get(it.getBlockPos())); - } else { - this.getConnectionPoints().remove(it.getBlockPos()); - } - }); + if (level != null && !level.isClientSide()) { + connectionEntities.values().removeIf(it -> !it.isAlive()); + if (connectionEntities.size() < getConnectionPoints().size()) { + List tileEntities = getConnectionPoints() + .stream() + .filter(it -> !connectionEntities.containsKey(it)) + .filter(level::isLoaded) + .map(level::getBlockEntity) + .map(it -> it instanceof ZiplineHookTileEntity ? (ZiplineHookTileEntity) it : null) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + tileEntities.forEach(it -> { + if (it.getConnectionPoints().contains(this.getBlockPos())) { + this.spawnRope(level, it, getConnectionInfo().get(it.getBlockPos())); + } else { + this.getConnectionPoints().remove(it.getBlockPos()); + } + }); + } } } } diff --git a/src/main/java/com/alrex/parcool/common/capability/Animation.java b/src/main/java/com/alrex/parcool/common/capability/Animation.java index b003e517..81304cdf 100644 --- a/src/main/java/com/alrex/parcool/common/capability/Animation.java +++ b/src/main/java/com/alrex/parcool/common/capability/Animation.java @@ -85,6 +85,10 @@ public void cameraSetup(EntityViewRenderEvent.CameraSetup event, ClientPlayerEnt && Minecraft.getInstance().options.getCameraType().isFirstPerson() && !ParCoolConfig.Client.Booleans.EnableFPVAnimation.get() ) return; + if (animator.shouldRemoved(player, parkourability)) { + animator = null; + return; + } if (option.isCanceled(AnimationPart.CAMERA)) return; animator.onCameraSetUp(event, player, parkourability); } diff --git a/src/main/java/com/alrex/parcool/common/capability/IStamina.java b/src/main/java/com/alrex/parcool/common/capability/IStamina.java index 8a0f770f..5d8853a5 100644 --- a/src/main/java/com/alrex/parcool/common/capability/IStamina.java +++ b/src/main/java/com/alrex/parcool/common/capability/IStamina.java @@ -2,7 +2,7 @@ import com.alrex.parcool.common.capability.capabilities.Capabilities; import com.alrex.parcool.common.capability.stamina.HungerStamina; -import com.alrex.parcool.common.capability.stamina.Stamina; +import com.alrex.parcool.common.capability.stamina.ParCoolStamina; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraftforge.common.util.LazyOptional; @@ -13,7 +13,7 @@ public interface IStamina { public enum Type { - Default(Stamina.class, Stamina::new, null), + Default(ParCoolStamina.class, ParCoolStamina::new, null), Hunger(HungerStamina.class, HungerStamina::new, HungerStamina::consumeOnServer); Type(Class clazz, Function constructor, BiConsumer serverStaminaHandler) { @@ -73,6 +73,10 @@ public static IStamina get(PlayerEntity player) { public default void updateOldValue() { } + public default boolean isImposingExhaustionPenalty() { + return isExhausted(); + } + public default boolean wantToConsumeOnServer() { return false; } diff --git a/src/main/java/com/alrex/parcool/common/capability/Parkourability.java b/src/main/java/com/alrex/parcool/common/capability/Parkourability.java index a5cf685d..e5b7c611 100644 --- a/src/main/java/com/alrex/parcool/common/capability/Parkourability.java +++ b/src/main/java/com/alrex/parcool/common/capability/Parkourability.java @@ -105,6 +105,10 @@ public int getSynchronizeTrialCount() { return synchronizeTrialCount; } + public void incrementSynchronizeTrialCount() { + synchronizeTrialCount++; + } + @OnlyIn(Dist.CLIENT) public boolean limitationIsNotSynced() { return !getServerLimitation().isSynced(); diff --git a/src/main/java/com/alrex/parcool/common/capability/capabilities/Capabilities.java b/src/main/java/com/alrex/parcool/common/capability/capabilities/Capabilities.java index 8d3d510d..1b1010a6 100644 --- a/src/main/java/com/alrex/parcool/common/capability/capabilities/Capabilities.java +++ b/src/main/java/com/alrex/parcool/common/capability/capabilities/Capabilities.java @@ -4,7 +4,7 @@ import com.alrex.parcool.common.capability.Animation; import com.alrex.parcool.common.capability.IStamina; import com.alrex.parcool.common.capability.Parkourability; -import com.alrex.parcool.common.capability.stamina.Stamina; +import com.alrex.parcool.common.capability.stamina.ParCoolStamina; import com.alrex.parcool.common.capability.storage.AnimationStorage; import com.alrex.parcool.common.capability.storage.ParkourabilityStorage; import com.alrex.parcool.common.capability.storage.StaminaStorage; @@ -33,7 +33,7 @@ public class Capabilities { public static void register(CapabilityManager manager) { manager.register(Parkourability.class, new ParkourabilityStorage(), Parkourability::new); - manager.register(IStamina.class, new StaminaStorage(), Stamina::new); + manager.register(IStamina.class, new StaminaStorage(), ParCoolStamina::new); } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/alrex/parcool/common/capability/stamina/OtherStamina.java b/src/main/java/com/alrex/parcool/common/capability/stamina/OtherStamina.java index 67db7c51..1a8ced0b 100644 --- a/src/main/java/com/alrex/parcool/common/capability/stamina/OtherStamina.java +++ b/src/main/java/com/alrex/parcool/common/capability/stamina/OtherStamina.java @@ -1,6 +1,8 @@ package com.alrex.parcool.common.capability.stamina; import com.alrex.parcool.common.capability.IStamina; +import com.alrex.parcool.common.capability.Parkourability; +import com.alrex.parcool.config.ParCoolConfig; import net.minecraft.entity.ai.attributes.AttributeModifier; import net.minecraft.entity.ai.attributes.Attributes; import net.minecraft.entity.ai.attributes.ModifiableAttributeInstance; @@ -21,6 +23,7 @@ public OtherStamina(PlayerEntity player) { private int max = 0; private int value = 0; private boolean exhausted; + private boolean imposingPenalty; public void setMax(int value) { max = value; @@ -66,7 +69,9 @@ public void tick() { if (attr == null) return; if (attr.getModifier(EXHAUSTED_SPEED_MODIFIER_UUID) != null) attr.removeModifier(EXHAUSTED_SPEED_MODIFIER_UUID); - if (isExhausted()) { + Parkourability parkourability = Parkourability.get(player); + if (parkourability == null) return; + if (isImposingExhaustionPenalty() && parkourability.getClientInfo().get(ParCoolConfig.Client.Booleans.EnableStaminaExhaustionPenalty)) { player.setSprinting(false); attr.addTransientModifier(new AttributeModifier( EXHAUSTED_SPEED_MODIFIER_UUID, @@ -78,6 +83,15 @@ public void tick() { } } + @Override + public boolean isImposingExhaustionPenalty() { + return imposingPenalty; + } + + public void setImposingPenalty(boolean imposingPenalty) { + this.imposingPenalty = imposingPenalty; + } + @Override public void set(int value) { this.value = value; diff --git a/src/main/java/com/alrex/parcool/common/capability/stamina/Stamina.java b/src/main/java/com/alrex/parcool/common/capability/stamina/ParCoolStamina.java similarity index 95% rename from src/main/java/com/alrex/parcool/common/capability/stamina/Stamina.java rename to src/main/java/com/alrex/parcool/common/capability/stamina/ParCoolStamina.java index 0269d411..0681eec9 100644 --- a/src/main/java/com/alrex/parcool/common/capability/stamina/Stamina.java +++ b/src/main/java/com/alrex/parcool/common/capability/stamina/ParCoolStamina.java @@ -9,15 +9,15 @@ import javax.annotation.Nullable; -public class Stamina implements IStamina { - public Stamina(@Nullable PlayerEntity player) { +public class ParCoolStamina implements IStamina { + public ParCoolStamina(@Nullable PlayerEntity player) { this.player = player; if (player != null && player.isLocalPlayer()) { set(Integer.MAX_VALUE); } } - public Stamina() { + public ParCoolStamina() { this.player = null; } diff --git a/src/main/java/com/alrex/parcool/common/entity/EntityType.java b/src/main/java/com/alrex/parcool/common/entity/EntityType.java index f1864558..c7552899 100644 --- a/src/main/java/com/alrex/parcool/common/entity/EntityType.java +++ b/src/main/java/com/alrex/parcool/common/entity/EntityType.java @@ -15,8 +15,9 @@ public class EntityType { = REGISTER.register("zipline_rope", () -> net.minecraft.entity.EntityType.Builder .of((net.minecraft.entity.EntityType.IFactory) ZiplineRopeEntity::new, EntityClassification.MISC) .noSave() - .clientTrackingRange((int) (Zipline.MAXIMUM_DISTANCE / 1.9)) + .clientTrackingRange((int) (Zipline.MAXIMUM_HORIZONTAL_DISTANCE / 1.9)) .updateInterval(Integer.MAX_VALUE) + .sized(0.1f, 0.1f) .noSummon() .build("zipline_rope") ); diff --git a/src/main/java/com/alrex/parcool/common/entity/zipline/ZiplineRopeEntity.java b/src/main/java/com/alrex/parcool/common/entity/zipline/ZiplineRopeEntity.java index 116bd50f..2b19c060 100644 --- a/src/main/java/com/alrex/parcool/common/entity/zipline/ZiplineRopeEntity.java +++ b/src/main/java/com/alrex/parcool/common/entity/zipline/ZiplineRopeEntity.java @@ -5,10 +5,7 @@ import com.alrex.parcool.common.item.zipline.ZiplineRopeItem; import com.alrex.parcool.common.zipline.Zipline; import com.alrex.parcool.common.zipline.ZiplineType; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntitySize; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.Pose; +import net.minecraft.entity.*; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.IPacket; @@ -53,7 +50,6 @@ public ZiplineRopeEntity(World world, BlockPos start, BlockPos end, ZiplineInfo setPos((end.getX() + start.getX()) / 2.0 + 0.5, Math.min(end.getY(), start.getY()), (end.getZ() + start.getZ()) / 2.0 + 0.5); noPhysics = true; forcedLoading = true; - size = EntitySize.fixed(Math.max(Math.abs(end.getX() - start.getX()), Math.abs(end.getZ() - start.getZ())) + 0.3f, Math.abs(end.getY() - start.getY()) + 0.3f); } private BlockPos zipline_start; @@ -76,17 +72,25 @@ public Zipline getZipline() { Vector3d endPos; TileEntity startEntity = level.getBlockEntity(start); TileEntity endEntity = level.getBlockEntity(end); + boolean delayInit = false; if (startEntity instanceof ZiplineHookTileEntity) { startPos = ((ZiplineHookTileEntity) startEntity).getActualZiplinePoint(end); } else { - startPos = new Vector3d(start.getX() + 0.5, start.getY() + 0.7, start.getZ() + 0.5); + startPos = new Vector3d(start.getX() + 0.5, start.getY() + 0.5, start.getZ() + 0.5); + delayInit = true; } if (endEntity instanceof ZiplineHookTileEntity) { endPos = ((ZiplineHookTileEntity) endEntity).getActualZiplinePoint(start); } else { - endPos = new Vector3d(end.getX() + 0.5, end.getY() + 0.7, end.getZ() + 0.5); + endPos = new Vector3d(end.getX() + 0.5, end.getY() + 0.5, end.getZ() + 0.5); + delayInit = true; } - zipline = type.getZipline(startPos, endPos); + if (delayInit) { + return type.getZipline(startPos, endPos); + } else { + zipline = type.getZipline(startPos, endPos); + } + } return zipline; } @@ -108,7 +112,7 @@ public boolean shouldRender(double x, double y, double z) { double t = -(xOffset * baseXOffset + yOffset * baseYOffset + zOffset * baseZOffset) / (xOffset * xOffset + yOffset * yOffset + zOffset * zOffset); Vector3d mostNearPoint = new Vector3d(xOffset * t + start.getX(), yOffset * t + start.getY(), zOffset * t + start.getZ()); distanceSqr = mostNearPoint.distanceToSqr(x, y, z); - return distanceSqr < Zipline.MAXIMUM_DISTANCE * Zipline.MAXIMUM_DISTANCE; + return distanceSqr < Zipline.MAXIMUM_HORIZONTAL_DISTANCE * Zipline.MAXIMUM_HORIZONTAL_DISTANCE; } @Nonnull @@ -121,23 +125,30 @@ public EntitySize getDimensions(@Nonnull Pose p_213305_1_) { return size; } + @Override + public void move(MoverType p_213315_1_, Vector3d p_213315_2_) { + } + + /* @Override public void refreshDimensions() { - if (size != null) { - BlockPos end = getEndPos(); - BlockPos start = getStartPos(); - if (end != BlockPos.ZERO || start != BlockPos.ZERO) { - size = EntitySize.fixed(Math.max(Math.abs(end.getX() - start.getX()), Math.abs(end.getZ() - start.getZ())) + 0.3f, Math.abs(end.getY() - start.getY()) + 0.3f); - } + super.refreshDimensions(); + BlockPos end = getEndPos(); + BlockPos start = getStartPos(); + if (end != BlockPos.ZERO || start != BlockPos.ZERO) { + size = EntitySize.fixed(Math.max(Math.abs(end.getX() - start.getX()), Math.abs(end.getZ() - start.getZ())) + 0.3f, Math.abs(end.getY() - start.getY()) + 0.3f); + double d0 = size.width / 2.0; + this.setBoundingBox(new AxisAlignedBB(this.getX() - d0, this.getY(), this.getZ() - d0, this.getX() + d0, this.getY() + size.height, this.getZ() + d0)); } } @Override public void onSyncedDataUpdated(@Nonnull DataParameter param) { - if (param.equals(DATA_END_POS)) { + if (param.equals(DATA_START_POS) || param.equals(DATA_END_POS)) { refreshDimensions(); } } + */ public BlockPos getStartPos() { return getEntityData().get(DATA_START_POS); @@ -147,11 +158,11 @@ public BlockPos getEndPos() { return getEntityData().get(DATA_END_POS); } - public void setStartPos(BlockPos start) { + private void setStartPos(BlockPos start) { getEntityData().set(DATA_START_POS, start); } - public void setEndPos(BlockPos end) { + private void setEndPos(BlockPos end) { getEntityData().set(DATA_END_POS, end); } diff --git a/src/main/java/com/alrex/parcool/common/handlers/PlayerDamageHandler.java b/src/main/java/com/alrex/parcool/common/handlers/PlayerDamageHandler.java index 1adbd6f4..48cf8f51 100644 --- a/src/main/java/com/alrex/parcool/common/handlers/PlayerDamageHandler.java +++ b/src/main/java/com/alrex/parcool/common/handlers/PlayerDamageHandler.java @@ -49,8 +49,10 @@ public static void onFall(LivingFallEvent event) { ) { boolean justTime = parkourability.get(BreakfallReady.class).getDoingTick() < 5; float distance = event.getDistance(); - if (distance > 2) { + if (distance > parkourability.getClientInfo().get(ParCoolConfig.Client.Doubles.LowestFallDistanceForBreakfall)) { StartBreakfallMessage.send(player, justTime); + } else { + return; } if (distance < 6 || (justTime && distance < 8)) { event.setCanceled(true); diff --git a/src/main/java/com/alrex/parcool/common/item/zipline/ZiplineRopeItem.java b/src/main/java/com/alrex/parcool/common/item/zipline/ZiplineRopeItem.java index 64820da4..4fb205f1 100644 --- a/src/main/java/com/alrex/parcool/common/item/zipline/ZiplineRopeItem.java +++ b/src/main/java/com/alrex/parcool/common/item/zipline/ZiplineRopeItem.java @@ -90,7 +90,8 @@ public ActionResultType useOn(@Nonnull ItemUseContext context) { BlockPos end = context.getClickedPos(); if (start.equals(end)) return ActionResultType.PASS; - if (start.distSqr(end) > Zipline.MAXIMUM_DISTANCE * Zipline.MAXIMUM_DISTANCE) { + double horizontalDistSqr = MathHelper.square(start.getX() - end.getX()) + MathHelper.square(start.getZ() - end.getZ()); + if (horizontalDistSqr > Zipline.MAXIMUM_HORIZONTAL_DISTANCE * Zipline.MAXIMUM_HORIZONTAL_DISTANCE) { if (context.getLevel().isClientSide()) { PlayerEntity player = context.getPlayer(); if (player != null) { @@ -98,14 +99,17 @@ public ActionResultType useOn(@Nonnull ItemUseContext context) { } } return ActionResultType.FAIL; - } else if (Math.abs(end.getY() - start.getY()) * MathHelper.fastInvSqrt(Math.pow(end.getX() - start.getX(), 2) + Math.pow(end.getZ() - start.getZ(), 2)) > 1.) { - if (context.getLevel().isClientSide()) { - PlayerEntity player = context.getPlayer(); - if (player != null) { - player.displayClientMessage(new TranslationTextComponent("parcool.message.zipline.too_steep"), true); + } else { + double verticalDist = Math.abs(end.getY() - start.getY()); + if (verticalDist * MathHelper.fastInvSqrt(horizontalDistSqr) > 1. || verticalDist > Zipline.MAXIMUM_VERTICAL_DISTANCE) { + if (context.getLevel().isClientSide()) { + PlayerEntity player = context.getPlayer(); + if (player != null) { + player.displayClientMessage(new TranslationTextComponent("parcool.message.zipline.too_steep"), true); + } } + return ActionResultType.FAIL; } - return ActionResultType.FAIL; } TileEntity startEntity = context.getLevel().getBlockEntity(start); diff --git a/src/main/java/com/alrex/parcool/common/network/SyncClientInformationMessage.java b/src/main/java/com/alrex/parcool/common/network/SyncClientInformationMessage.java index 065405ea..d5297ad6 100644 --- a/src/main/java/com/alrex/parcool/common/network/SyncClientInformationMessage.java +++ b/src/main/java/com/alrex/parcool/common/network/SyncClientInformationMessage.java @@ -92,10 +92,14 @@ public void handleServer(Supplier contextSupplier) { contextSupplier.get().setPacketHandled(true); } - public void logReceived(PlayerEntity player) { + public static void logReceived(PlayerEntity player) { ParCool.LOGGER.log(Level.INFO, "Received Client Information of [" + player.getGameProfile().getName() + "]"); } + public static void logSent(PlayerEntity player) { + ParCool.LOGGER.log(Level.INFO, "Sent Client Information of [" + player.getGameProfile().getName() + "]"); + } + @OnlyIn(Dist.CLIENT) public static void sync(ClientPlayerEntity player, boolean requestSendLimitation) { Parkourability parkourability = Parkourability.get(player); @@ -107,5 +111,6 @@ public static void sync(ClientPlayerEntity player, boolean requestSendLimitation message.requestLimitations = requestSendLimitation; ParCool.CHANNEL_INSTANCE.send(PacketDistributor.SERVER.noArg(), message); + logSent(player); } } diff --git a/src/main/java/com/alrex/parcool/common/network/SyncServerInfoMessage.java b/src/main/java/com/alrex/parcool/common/network/SyncServerInfoMessage.java index 6e88f474..76c141f2 100644 --- a/src/main/java/com/alrex/parcool/common/network/SyncServerInfoMessage.java +++ b/src/main/java/com/alrex/parcool/common/network/SyncServerInfoMessage.java @@ -14,8 +14,6 @@ import net.minecraftforge.fml.network.NetworkEvent; import net.minecraftforge.fml.network.PacketDistributor; import org.apache.logging.log4j.Level; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.util.function.Supplier; @@ -66,10 +64,14 @@ public void handle(Supplier contextSupplier) { contextSupplier.get().setPacketHandled(true); } - public void logReceived(PlayerEntity player) { + public static void logReceived(PlayerEntity player) { ParCool.LOGGER.log(Level.INFO, "Received Server Limitation of [" + player.getGameProfile().getName() + "]"); } + public static void logSent(PlayerEntity player) { + ParCool.LOGGER.log(Level.INFO, "Sent Server Limitation of [" + player.getGameProfile().getName() + "]"); + } + public static void sync(ServerPlayerEntity player) { Parkourability parkourability = Parkourability.get(player); if (parkourability == null) return; @@ -92,5 +94,6 @@ public static void syncWithStamina(ServerPlayerEntity player, IStamina stamina) msg.staminaValue = stamina.get(); } ParCool.CHANNEL_INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), msg); + logSent(player); } } diff --git a/src/main/java/com/alrex/parcool/common/network/SyncStaminaMessage.java b/src/main/java/com/alrex/parcool/common/network/SyncStaminaMessage.java index 02c93328..478fe1b0 100644 --- a/src/main/java/com/alrex/parcool/common/network/SyncStaminaMessage.java +++ b/src/main/java/com/alrex/parcool/common/network/SyncStaminaMessage.java @@ -22,6 +22,7 @@ public class SyncStaminaMessage { private int stamina = 0; private int max = 0; private boolean exhausted = false; + private boolean imposingPenalty = false; private int consumeOnServer = 0; private int staminaType = -1; private UUID playerID = null; @@ -30,6 +31,7 @@ public void encode(PacketBuffer packet) { packet.writeInt(this.stamina); packet.writeInt(this.max); packet.writeBoolean(this.exhausted); + packet.writeBoolean(this.imposingPenalty); packet.writeInt(this.staminaType); packet.writeInt(this.consumeOnServer); packet.writeLong(this.playerID.getMostSignificantBits()); @@ -41,6 +43,7 @@ public static SyncStaminaMessage decode(PacketBuffer packet) { message.stamina = packet.readInt(); message.max = packet.readInt(); message.exhausted = packet.readBoolean(); + message.imposingPenalty = packet.readBoolean(); message.staminaType = packet.readInt(); message.consumeOnServer = packet.readInt(); message.playerID = new UUID(packet.readLong(), packet.readLong()); @@ -58,6 +61,7 @@ public void handleServer(Supplier contextSupplier) { if (stamina == null) return; if (stamina instanceof OtherStamina) { ((OtherStamina) stamina).setMax(this.max); + ((OtherStamina) stamina).setImposingPenalty(imposingPenalty); } if (staminaType != -1 && consumeOnServer > 0) { IStamina.Type.values()[staminaType].handleConsumeOnServer(player, consumeOnServer); @@ -87,6 +91,7 @@ public void handleClient(Supplier contextSupplier) { if (stamina == null) return; if (stamina instanceof OtherStamina) { ((OtherStamina) stamina).setMax(this.max); + ((OtherStamina) stamina).setImposingPenalty(imposingPenalty); } if (serverPlayer != null && staminaType != -1 && consumeOnServer > 0) { IStamina.Type.values()[staminaType].handleConsumeOnServer(serverPlayer, consumeOnServer); @@ -106,6 +111,7 @@ public static void sync(PlayerEntity player) { message.stamina = stamina.get(); message.max = stamina.getActualMaxStamina(); message.exhausted = stamina.isExhausted(); + message.imposingPenalty = stamina.isImposingExhaustionPenalty(); message.consumeOnServer = stamina.getRequestedValueConsumedOnServer(); IStamina.Type type = IStamina.Type.getFromInstance(stamina); message.staminaType = type != null ? type.ordinal() : -1; diff --git a/src/main/java/com/alrex/parcool/common/tags/BlockTags.java b/src/main/java/com/alrex/parcool/common/tags/BlockTags.java index cc8c1119..f02ffac7 100644 --- a/src/main/java/com/alrex/parcool/common/tags/BlockTags.java +++ b/src/main/java/com/alrex/parcool/common/tags/BlockTags.java @@ -5,4 +5,5 @@ public class BlockTags { public static final ResourceLocation HIDE_ABLE = new ResourceLocation(ParCool.MOD_ID, "hide_able"); + public static final ResourceLocation POLE_CLIMBABLE = new ResourceLocation(ParCool.MOD_ID, "pole_climbable"); } diff --git a/src/main/java/com/alrex/parcool/common/zipline/Zipline.java b/src/main/java/com/alrex/parcool/common/zipline/Zipline.java index 5a1d1c65..cc3c303e 100644 --- a/src/main/java/com/alrex/parcool/common/zipline/Zipline.java +++ b/src/main/java/com/alrex/parcool/common/zipline/Zipline.java @@ -4,6 +4,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; @@ -11,7 +12,8 @@ import java.util.List; public abstract class Zipline { - public static final double MAXIMUM_DISTANCE = 72.; + public static final double MAXIMUM_HORIZONTAL_DISTANCE = 115.; + public static final double MAXIMUM_VERTICAL_DISTANCE = MAXIMUM_HORIZONTAL_DISTANCE * 0.51; protected Zipline(Vector3d point1, Vector3d point2) { if (point1.y() <= point2.y()) { @@ -53,11 +55,15 @@ public static ZiplineRopeEntity getHangableZipline(World world, PlayerEntity pla @Nullable public static ZiplineRopeEntity getHangableZipline(World world, PlayerEntity player, @Nullable ZiplineRopeEntity except) { + final double d = MAXIMUM_HORIZONTAL_DISTANCE * 0.52 + 1; List entities = world.getEntitiesOfClass( ZiplineRopeEntity.class, - player.getBoundingBox().inflate(MAXIMUM_DISTANCE * 0.52) + player.getBoundingBox().inflate(d, Zipline.MAXIMUM_VERTICAL_DISTANCE + 1, d) ); - Vector3d grabPos = player.position().add(0, player.getBbHeight() * 1.11, 0); + double catchRange = player.getBbWidth() * 0.6; + double yDeltaMovement = player.getDeltaMovement().y(); + double yDistanceScale = MathHelper.clamp(catchRange / yDeltaMovement, 0.4d, 1d); + Vector3d grabPos = player.position().add(0, player.getBbHeight() * 1.11 + MathHelper.clamp(yDeltaMovement * 0.4f, player.getBbHeight() * -0.4, player.getBbHeight() * 0.4), 0); for (ZiplineRopeEntity ziplineEntity : entities) { if (except == ziplineEntity) continue; @@ -65,8 +71,7 @@ public static ZiplineRopeEntity getHangableZipline(World world, PlayerEntity pla continue; Zipline zipline = ziplineEntity.getZipline(); if (zipline.isPossiblyHangable(grabPos)) { - double distSqr = zipline.getSquaredDistanceApproximately(grabPos); - double catchRange = player.getBbWidth() * 0.5; + double distSqr = zipline.getSquaredDistanceApproximately(grabPos, yDistanceScale); if (distSqr < catchRange * catchRange) { return ziplineEntity; } @@ -116,7 +121,11 @@ public Vector3d getMidPoint(float t) { public abstract double getMovedPositionByParameterApproximately(float currentT, float movement); // return not accurate distance - public abstract double getSquaredDistanceApproximately(Vector3d position); + public double getSquaredDistanceApproximately(Vector3d position) { + return getSquaredDistanceApproximately(position, 1); + } + + public abstract double getSquaredDistanceApproximately(Vector3d position, double yDistanceScale); public abstract boolean isPossiblyHangable(Vector3d position); } diff --git a/src/main/java/com/alrex/parcool/common/zipline/impl/GeneralQuadraticCurveZipline.java b/src/main/java/com/alrex/parcool/common/zipline/impl/GeneralQuadraticCurveZipline.java index ad9d1021..05cc9080 100644 --- a/src/main/java/com/alrex/parcool/common/zipline/impl/GeneralQuadraticCurveZipline.java +++ b/src/main/java/com/alrex/parcool/common/zipline/impl/GeneralQuadraticCurveZipline.java @@ -98,16 +98,19 @@ public double getMovedPositionByParameterApproximately(float currentT, float mov } @Override - public double getSquaredDistanceApproximately(Vector3d position) { + public double getSquaredDistanceApproximately(Vector3d position, double yDistanceScale) { float t = getParameter(position); Vector3d simplifiedNearestPoint = getMidPoint(t); - return position.distanceToSqr(simplifiedNearestPoint); + double xOffset = simplifiedNearestPoint.x - position.x; + double zOffset = simplifiedNearestPoint.z - position.z; + double yOffset = (simplifiedNearestPoint.y - position.y) * yDistanceScale; + return xOffset * xOffset + zOffset * zOffset + yOffset * yOffset; } @Override public boolean isPossiblyHangable(Vector3d position) { return new AxisAlignedBB(getStartPos().x(), getMidPoint((float) tAtVertex).y(), getStartPos().z(), getEndPos().x(), getEndPos().y(), getEndPos().z()) - .inflate(0.5) + .inflate(1d) .contains(position); } } diff --git a/src/main/java/com/alrex/parcool/common/zipline/impl/QuadraticCurveZipline.java b/src/main/java/com/alrex/parcool/common/zipline/impl/QuadraticCurveZipline.java index 88d5e536..d8346c28 100644 --- a/src/main/java/com/alrex/parcool/common/zipline/impl/QuadraticCurveZipline.java +++ b/src/main/java/com/alrex/parcool/common/zipline/impl/QuadraticCurveZipline.java @@ -66,16 +66,19 @@ public double getMovedPositionByParameterApproximately(float currentT, float mov } @Override - public double getSquaredDistanceApproximately(Vector3d position) { + public double getSquaredDistanceApproximately(Vector3d position, double yDistanceScale) { float t = getParameter(position); Vector3d simplifiedNearestPoint = getMidPoint(t); - return position.distanceToSqr(simplifiedNearestPoint); + double xOffset = simplifiedNearestPoint.x - position.x; + double zOffset = simplifiedNearestPoint.z - position.z; + double yOffset = (simplifiedNearestPoint.y - position.y) * yDistanceScale; + return xOffset * xOffset + zOffset * zOffset + yOffset * yOffset; } @Override public boolean isPossiblyHangable(Vector3d position) { return new AxisAlignedBB(getStartPos().x(), getStartPos().y(), getStartPos().z(), getEndPos().x(), getEndPos().y(), getEndPos().z()) - .inflate(0.5) + .inflate(1d) .contains(position); } diff --git a/src/main/java/com/alrex/parcool/common/zipline/impl/StraightZipline.java b/src/main/java/com/alrex/parcool/common/zipline/impl/StraightZipline.java index ca3708a9..ef9968a7 100644 --- a/src/main/java/com/alrex/parcool/common/zipline/impl/StraightZipline.java +++ b/src/main/java/com/alrex/parcool/common/zipline/impl/StraightZipline.java @@ -55,16 +55,19 @@ public double getMovedPositionByParameterApproximately(float currentT, float mov } @Override - public double getSquaredDistanceApproximately(Vector3d position) { + public double getSquaredDistanceApproximately(Vector3d position, double yDistanceScale) { double t = getParameterD(position); Vector3d mostNearPoint = getMidPoint(t); - return mostNearPoint.distanceToSqr(position); + double xOffset = mostNearPoint.x - position.x; + double zOffset = mostNearPoint.z - position.z; + double yOffset = (mostNearPoint.y - position.y) * yDistanceScale; + return xOffset * xOffset + zOffset * zOffset + yOffset * yOffset; } @Override public boolean isPossiblyHangable(Vector3d position) { return new AxisAlignedBB(getStartPos().x(), getStartPos().y(), getStartPos().z(), getEndPos().x(), getEndPos().y(), getEndPos().z()) - .inflate(0.5) + .inflate(1d) .contains(position); } } diff --git a/src/main/java/com/alrex/parcool/config/ParCoolConfig.java b/src/main/java/com/alrex/parcool/config/ParCoolConfig.java index ef81f543..671c6569 100644 --- a/src/main/java/com/alrex/parcool/config/ParCoolConfig.java +++ b/src/main/java/com/alrex/parcool/config/ParCoolConfig.java @@ -120,6 +120,14 @@ public enum Booleans implements Item { ConfigGroup.HUD, "Stamina HUD shows action charge rate, cool time or etc", "show_action_status_bar", true ), + ShowLightStaminaHUDAlways( + ConfigGroup.HUD, "Light stamina HUD shows always", + "show_light_hud_always", false + ), + EnableStaminaExhaustionPenalty( + ConfigGroup.Stamina, "Enable slowing down of stamina exhaustion", + "enable_stamina_exhaustion_penalty", true + ), EnableDoubleTappingForDodge( ConfigGroup.Control, "Enable double-tapping ctrl for Dodge", "enable_double_tapping_for_dodge", false @@ -178,7 +186,7 @@ public enum Booleans implements Item { ), ShowAutoResynchronizationNotification( ConfigGroup.Other, "Notify if auto resynchronization of Limitation is executed", - "notify_limitation_auto_resync", true + "notify_limitation_auto_resync", false ), ParCoolIsActive( ConfigGroup.Other, "Whether ParCool is active", @@ -369,6 +377,10 @@ public enum Doubles implements Item { DodgeSpeedModifier( ConfigGroup.Modifier, "Dodge speed modifier", "dodge-speed_modifier", 1, Server.Doubles.MaxDodgeSpeedModifier.Min, Server.Doubles.MaxDodgeSpeedModifier.Max + ), + LowestFallDistanceForBreakfall( + ConfigGroup.Control, "Lowest fall distance needed to trigger breakfall movements", + "lowest_fall_distance_for_breakfall", 2, 0, 10 ); public final ConfigGroup Group; @Nullable diff --git a/src/main/java/com/alrex/parcool/mixin/common/LivingEntityMixin.java b/src/main/java/com/alrex/parcool/mixin/common/LivingEntityMixin.java index 135f68ee..ce8ac19e 100644 --- a/src/main/java/com/alrex/parcool/mixin/common/LivingEntityMixin.java +++ b/src/main/java/com/alrex/parcool/mixin/common/LivingEntityMixin.java @@ -5,6 +5,7 @@ import com.alrex.parcool.common.action.impl.ClimbPoles; import com.alrex.parcool.common.action.impl.ClimbUp; import com.alrex.parcool.common.capability.Parkourability; +import com.alrex.parcool.common.tags.BlockTags; import net.minecraft.block.*; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -38,6 +39,9 @@ public abstract class LivingEntityMixin extends Entity { @Shadow public abstract void releaseUsingItem(); + @Shadow + public int removeArrowTime; + public LivingEntityMixin(EntityType p_i48580_1_, World p_i48580_2_) { super(p_i48580_1_, p_i48580_2_); } @@ -130,6 +134,6 @@ public void onClimbable(CallbackInfoReturnable cir) { Direction direction = state.getValue(DirectionalBlock.FACING); return !state.isCollisionShapeFullBlock(world, pos) && (direction == Direction.UP || direction == Direction.DOWN); } - return false; + return block.getTags().contains(BlockTags.POLE_CLIMBABLE); } } diff --git a/src/main/java/com/alrex/parcool/utilities/WorldUtil.java b/src/main/java/com/alrex/parcool/utilities/WorldUtil.java index ca5949f2..ca5e3cad 100644 --- a/src/main/java/com/alrex/parcool/utilities/WorldUtil.java +++ b/src/main/java/com/alrex/parcool/utilities/WorldUtil.java @@ -14,50 +14,48 @@ import net.minecraft.world.World; import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; public class WorldUtil { + @Nullable public static Vector3d getRunnableWall(LivingEntity entity, double range) { double width = entity.getBbWidth() * 0.4f; double wallX = 0; double wallZ = 0; Vector3d pos = entity.position(); - AxisAlignedBB baseBox1 = new AxisAlignedBB( - pos.x() - width, - pos.y(), - pos.z() - width, - pos.x() + width, - pos.y() + entity.getBbHeight() / 1.63, - pos.z() + width - ); - AxisAlignedBB baseBox2 = new AxisAlignedBB( - pos.x() - width, - pos.y() + entity.getBbHeight() / 1.63, - pos.z() - width, - pos.x() + width, - pos.y() + entity.getBbHeight(), - pos.z() + width + List boxes = Arrays.asList( + new AxisAlignedBB( + pos.x() - width, + pos.y(), + pos.z() - width, + pos.x() + width, + pos.y() + entity.getBbHeight() * 0.3, + pos.z() + width + ), + new AxisAlignedBB( + pos.x() - width, + pos.y() + entity.getBbHeight() * 0.85, + pos.z() - width, + pos.x() + width, + pos.y() + entity.getBbHeight(), + pos.z() + width + ) ); - if (!entity.level.noCollision(baseBox1.expandTowards(range, 0, 0)) - && !entity.level.noCollision(baseBox2.expandTowards(range, 0, 0)) - ) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(range, 0, 0)))) { wallX++; } - if (!entity.level.noCollision(baseBox1.expandTowards(-range, 0, 0)) - && !entity.level.noCollision(baseBox2.expandTowards(-range, 0, 0)) - ) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(-range, 0, 0)))) { wallX--; } - if (!entity.level.noCollision(baseBox1.expandTowards(0, 0, range)) - && !entity.level.noCollision(baseBox2.expandTowards(0, 0, range)) - ) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(0, 0, range)))) { wallZ++; } - if (!entity.level.noCollision(baseBox1.expandTowards(0, 0, -range)) - && !entity.level.noCollision(baseBox1.expandTowards(0, 0, -range)) - ) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(0, 0, -range)))) { wallZ--; } if (wallX == 0 && wallZ == 0) return null; @@ -76,25 +74,30 @@ public static Vector3d getWall(LivingEntity entity, double range) { double wallZ = 0; Vector3d pos = entity.position(); - AxisAlignedBB baseBox = new AxisAlignedBB( - pos.x() - width, - pos.y(), - pos.z() - width, - pos.x() + width, - pos.y() + entity.getBbHeight(), - pos.z() + width - ); + List boxes = new LinkedList<>(); + final int division = 2; + double singleYHeight = entity.getBbHeight() / division; + for (int i = 0; i < division; i++) { + boxes.add(new AxisAlignedBB( + pos.x() - width, + pos.y() + singleYHeight * i, + pos.z() - width, + pos.x() + width, + pos.y() + singleYHeight * (i + 1), + pos.z() + width + )); + } - if (!entity.level.noCollision(baseBox.expandTowards(range, 0, 0))) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(range, 0, 0)))) { wallX++; } - if (!entity.level.noCollision(baseBox.expandTowards(-range, 0, 0))) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(-range, 0, 0)))) { wallX--; } - if (!entity.level.noCollision(baseBox.expandTowards(0, 0, range))) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(0, 0, range)))) { wallZ++; } - if (!entity.level.noCollision(baseBox.expandTowards(0, 0, -range))) { + if (boxes.stream().noneMatch(box -> entity.level.noCollision(box.expandTowards(0, 0, -range)))) { wallZ--; } if (wallX == 0 && wallZ == 0) return null; diff --git a/src/main/resources/assets/parcool/lang/en_us.json b/src/main/resources/assets/parcool/lang/en_us.json index 33a06cf2..bab98ff2 100644 --- a/src/main/resources/assets/parcool/lang/en_us.json +++ b/src/main/resources/assets/parcool/lang/en_us.json @@ -110,7 +110,7 @@ "parcool.message.zipline.reset_point": "Reset point registration", "parcool.message.zipline.change_tension": "Change tension : %s", "parcool.message.error.limitation.not_synced": "[Warn] ParCool Limitation is not synchronized. Sending a request to server. Please wait a moment...", - "parcool.message.error.limitation.fail_sync": "[Error] Failed to synchronize ParCool Limitation. Please report this issue to the developer.", + "parcool.message.error.limitation.fail_sync": "[Error] Failed to synchronize ParCool Limitation. There may be problems about server connection. Please report to the developer if this is not solved after checking connection", "parcool.command.message.invalidActionName": "No Such Action : %s", "parcool.command.message.invalidConfigName": "No Such Limitation : %s", "parcool.command.message.success.set": "Set %d player's [%s] with %s", @@ -174,7 +174,10 @@ "parcool.config.c.vault_animation_mode": "Vault Animation Type", "parcool.config.c.enable_particles": "Enable action particles", "parcool.config.c.gui_color_theme": "GUI Theme Color", + "parcool.config.c.show_light_hud_always": "Always show Light Stamina HUD", + "parcool.config.c.enable_stamina_exhaustion_penalty": "Enable slowing down of stamina exhaustion", "parcool.config.c.parcool_activation": "Whether ParCool is active", "parcool.config.c.enable_particles_jt_breakfall": "Enable particle of just time breakfall", - "parcool.config.c.enable_just_time_effect_breakfall": "Enable effects of just time breakfall" + "parcool.config.c.enable_just_time_effect_breakfall": "Enable effects of just time breakfall", + "parcool.config.c.lowest_fall_distance_for_breakfall": "Enable effects of just time breakfall" } \ No newline at end of file diff --git a/src/main/resources/assets/parcool/sounds.json b/src/main/resources/assets/parcool/sounds.json index 91952696..839d8c05 100644 --- a/src/main/resources/assets/parcool/sounds.json +++ b/src/main/resources/assets/parcool/sounds.json @@ -84,7 +84,7 @@ "sounds": [ { "name": "parcool:jumping", - "volume": 0.4, + "volume": 0.2, "pitch": 0.7 } ] @@ -94,7 +94,7 @@ "sounds": [ { "name": "parcool:grabbing", - "volume": 0.85, + "volume": 0.8, "pitch": 0.6 } ] @@ -104,7 +104,7 @@ "sounds": [ { "name": "parcool:jumping", - "volume": 0.4, + "volume": 0.2, "pitch": 0.6 } ]