Skip to content

Commit

Permalink
Implemented Double Jumps and Triple Jumps. Implemented the Ground Pou…
Browse files Browse the repository at this point in the history
…nd's associated stomp type. Implemented repeat-ground-pounding, where Mario can hold the button down after pounding some blocks to slam them repeatedly. Repeat ground pounding is allowed when the previous pound caused some change to the blockstate.
  • Loading branch information
floral-qua-floral committed Nov 16, 2024
1 parent 6ffeae1 commit c211a28
Show file tree
Hide file tree
Showing 28 changed files with 445 additions and 67 deletions.
48 changes: 41 additions & 7 deletions src/main/java/com/floralquafloral/bumping/BumpManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.floralquafloral.mariodata.MarioClientSideData;
import com.floralquafloral.mariodata.MarioData;
import com.floralquafloral.mariodata.MarioDataManager;
import com.floralquafloral.mariodata.MarioDataPackets;
import com.floralquafloral.mariodata.moveable.MarioMainClientData;
import com.floralquafloral.mariodata.moveable.MarioServerData;
import com.floralquafloral.mariodata.moveable.MarioTravelData;
Expand All @@ -24,11 +23,13 @@
import net.minecraft.block.BlockState;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.RegistryByteBuf;
import net.minecraft.network.codec.PacketCodec;
import net.minecraft.network.codec.PacketCodecs;
import net.minecraft.network.packet.CustomPayload;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.sound.SoundCategory;
Expand All @@ -45,21 +46,28 @@

import java.util.*;

import static com.floralquafloral.MarioQuaMario.MOD_ID;

public abstract class BumpManager {
public static final Map<BlockPos, BumpedBlockParticle> BUMPED_BLOCKS = new HashMap<>();
public static final Set<BlockPos> HIDDEN_BLOCKS = new HashSet<>();
private static final Set<BlockBumpingPlan> BLOCKS_TO_BUMP = new HashSet<>();

public static final TagKey<Block> ALWAYS_REPEAT_BUMP = TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "always_repeat_bump"));
public static final TagKey<Block> NEVER_REPEAT_BUMP = TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "never_repeat_bump"));

private record BlockBumpingPlan(ClientWorld world, BlockPos pos, BlockState state, Direction direction) {}

public static void registerPackets() {
BumpC2SPayload.register();
BumpC2SPayload.registerReceiver();

BumpS2CPayload.register();
AllowRepeatBumpS2CPayload.register();
}
public static void registerPacketsClient() {
BumpS2CPayload.registerReceiver();
AllowRepeatBumpS2CPayload.registerReceiver();
}

private static BlockPos eyeAdjustmentParticlePos;
Expand All @@ -79,7 +87,6 @@ public static void registerEventListeners() {
if(!BLOCKS_TO_BUMP.isEmpty()) {
for(BlockBumpingPlan plan : BLOCKS_TO_BUMP) {
visuallyBumpBlock(plan.world, plan.pos, plan.direction);
MarioQuaMario.LOGGER.info("Pos1: {}, Pos2: {}, Equal: {}", plan.pos, eyeAdjustmentParticlePos, plan.pos.equals(eyeAdjustmentParticlePos));
if(plan.pos.equals(eyeAdjustmentParticlePos)) {
eyeAdjustmentParticle = BUMPED_BLOCKS.get(plan.pos);
}
Expand Down Expand Up @@ -137,6 +144,7 @@ public static void bumpBlocks(MarioMainClientData data, ClientWorld world, Itera
int modifiedStrength = baseStrength + data.getPowerUp().BUMP_STRENGTH_MODIFIER + data.getCharacter().BUMP_STRENGTH_MODIFIER;
Set<BlockSoundGroup> blockSoundGroups = new HashSet<>();
BlockPos lastPos = null;
data.getTimers().canRepeatPound = false;
for(BlockPos bumpPos : blocks) {
bumpAttemptCount++;
lastPos = new BlockPos(bumpPos);
Expand Down Expand Up @@ -165,7 +173,6 @@ public static void bumpBlocks(MarioMainClientData data, ClientWorld world, Itera
);

if(direction == Direction.DOWN && bumpCount == bumpAttemptCount) {
MarioQuaMario.LOGGER.info("Bumped down with full success! Setting EAPP to {}", lastPos);
eyeAdjustmentParticlePos = lastPos;
}
}
Expand Down Expand Up @@ -239,10 +246,19 @@ public static void bumpResponseCommon(
BlockState state, BlockPos pos,
int baseStrength, int modifiedStrength, Direction direction
) {
for(BumpingHandler handler : HANDLERS) {
if(handler.bumpResponseCommon(data, travelData, world, state, pos, baseStrength, modifiedStrength, direction)) return;
response: {
for(BumpingHandler handler : HANDLERS) {
if(handler.bumpResponseCommon(data, travelData, world, state, pos, baseStrength, modifiedStrength, direction))
break response;
}
BASELINE_HANDLER.bumpResponseCommon(data, travelData, world, state, pos, baseStrength, modifiedStrength, direction);
}
if(!state.isIn(NEVER_REPEAT_BUMP) && (state.isIn(ALWAYS_REPEAT_BUMP) || !state.equals(world.getBlockState(pos)))) {
if(data.getMario() instanceof ServerPlayerEntity marioServer)
ServerPlayNetworking.send(marioServer, new AllowRepeatBumpS2CPayload());
else if(data.getMario().isMainPlayer())
((MarioMainClientData) data).getTimers().canRepeatPound = true; // is this even possible??
}
BASELINE_HANDLER.bumpResponseCommon(data, travelData, world, state, pos, baseStrength, modifiedStrength, direction);
}

public static void bumpResponseClients(
Expand Down Expand Up @@ -315,4 +331,22 @@ public static void register() {
PayloadTypeRegistry.playS2C().register(ID, CODEC);
}
}

private record AllowRepeatBumpS2CPayload() implements CustomPayload {
public static final CustomPayload.Id<AllowRepeatBumpS2CPayload> ID = new CustomPayload.Id<>(Identifier.of(MarioQuaMario.MOD_ID, "allow_repeat_bump"));
public static final PacketCodec<RegistryByteBuf, AllowRepeatBumpS2CPayload> CODEC = PacketCodec.unit(new AllowRepeatBumpS2CPayload());
public static void registerReceiver() {
ClientPlayNetworking.registerGlobalReceiver(ID, (payload, context) -> {
MarioMainClientData data = MarioMainClientData.getInstance();
if(data != null) data.getTimers().canRepeatPound = true;
});
}

@Override public Id<? extends CustomPayload> getId() {
return ID;
}
public static void register() {
PayloadTypeRegistry.playS2C().register(ID, CODEC);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,40 +55,61 @@ private ForcedSignalSpot(BlockPos position, World world) {
public static final TagKey<Block> UNBREAKABLE_FROM_BUMPING = TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "unbreakable_from_bumping"));
// public static final TagKey<Block> BRICK_BLOCKS = TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "brick_blocks"));

private float getAdjustedHardness(BlockState state, BlockView world, BlockPos pos, Direction direction) {
float adjustedHardness = state.getHardness(world, pos);
if(state.isTransparent(world, pos) && !state.hasSidedTransparency()) adjustedHardness *= 0.5F;

return adjustedHardness;
}

@Override @NotNull
public BumpLegality evaluateBumpLegality(BlockState state, BlockView world, BlockPos pos, int strength, Direction direction) {
if(state.isIn(UNBUMPABLE)) return BumpLegality.IGNORE;
if(state.isIn(BUMP_REGARDLESS_OF_HARDNESS) && strength >= 4) return BumpLegality.BUMP;
if(state.isIn(EXTREMELY_EASY_TO_BUMP) && strength >= 1) return BumpLegality.BUMP;

float hardnessToolless = state.getHardness(world, pos);
if(state.isToolRequired()) hardnessToolless *= 3.33333333333F;
if(state.isTransparent(world, pos) && !state.hasSidedTransparency()) hardnessToolless *= 0.5F;
if(state.isIn(BlockTags.AXE_MINEABLE)) hardnessToolless *= 3.6F;
if(state.getBlock().toString().contains("brick")) hardnessToolless *= 0.5F;
// float hardnessToolless = state.getHardness(world, pos);
// if(state.isToolRequired()) hardnessToolless *= 3.33333333333F;
// if(state.isTransparent(world, pos) && !state.hasSidedTransparency()) hardnessToolless *= 0.5F;
// if(state.isIn(BlockTags.AXE_MINEABLE)) hardnessToolless *= 3.6F;
// if(state.getBlock().toString().contains("brick")) hardnessToolless *= 0.5F;

if(hardnessToolless == -1) return BumpLegality.IGNORE;
float adjustedHardness = getAdjustedHardness(state, world, pos, direction);

if(adjustedHardness == -1) return BumpLegality.IGNORE;
if(strength <= 1) return BumpLegality.IGNORE;
if(strength == 2 && hardnessToolless <= 0.25F) return BumpLegality.SILENT_REACTION;
else if(hardnessToolless <= 2.5F * strength) return BumpLegality.BUMP;
if(strength == 2) return (adjustedHardness <= 0.25F) ? BumpLegality.SILENT_REACTION : BumpLegality.IGNORE;
if(adjustedHardness <= 0.75F * strength) return BumpLegality.BUMP;

return BumpLegality.IGNORE;
}

@Override
public boolean bumpResponseCommon(MarioData data, @Nullable MarioTravelData travelData, World world, BlockState state, BlockPos pos, int baseStrength, int modifiedStrength, Direction direction) {
float hardnessToolless = state.getHardness(world, pos);
if(state.isToolRequired()) hardnessToolless *= 3.33333333333F;
if(state.isTransparent(world, pos) && !state.hasSidedTransparency()) hardnessToolless *= 0.5F;
if(state.isIn(BlockTags.AXE_MINEABLE)) hardnessToolless *= 3.6F;
if(state.getBlock().toString().contains("brick")) hardnessToolless *= 0.5F;

if(!state.isIn(UNBREAKABLE_FROM_BUMPING) && hardnessToolless != -1) {
if (modifiedStrength >= 4 && hardnessToolless <= 3.5 && world.breakBlock(pos, true, data.getMario()))
return true;

if (modifiedStrength >= 2 && hardnessToolless <= 0.3 && world.breakBlock(pos, true, data.getMario()))
float adjustedHardness = getAdjustedHardness(state, world, pos, direction);

attemptBreak: if(!state.isIn(UNBREAKABLE_FROM_BUMPING) && adjustedHardness != -1) {
if(modifiedStrength <= 1) break attemptBreak;

// Super Mario spin-jumping can destroy fairly fragile blocks (ice,
if(modifiedStrength == 2) {
if(adjustedHardness <= 0.25F && world.breakBlock(pos, true, data.getMario()))
return true;
else break attemptBreak;
}
// if(!state.isToolRequired()) adjustedHardness -= 1;

// Small Mario ground-pounding or bopping a ceiling can only break exceptionally fragile blocks (candles, moss, scaffolding)
if(modifiedStrength == 3) {
if(adjustedHardness < 0.2F && world.breakBlock(pos, true, data.getMario()))
return true;
else break attemptBreak;
}

// Super Mario gets a bonus to breaking bricks
if(state.getBlock().toString().contains("brick")) adjustedHardness -= 1;

if(adjustedHardness <= modifiedStrength * 0.25F && world.breakBlock(pos, true, data.getMario()))
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import org.jetbrains.annotations.Nullable;

public class PistonBumpingHandler implements BumpingHandler {
public static boolean forceRetract;

@Override
public @Nullable BumpLegality evaluateBumpLegality(BlockState state, BlockView world, BlockPos pos, int strength, Direction direction) {
if(state.isOf(Blocks.PISTON_HEAD) && state.get(Properties.FACING) == Direction.UP) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.floralquafloral.bumping.handlers;

import com.floralquafloral.mariodata.MarioClientSideData;
import com.floralquafloral.mariodata.MarioData;
import com.floralquafloral.mariodata.moveable.MarioTravelData;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.SpawnerBlock;
import net.minecraft.block.TrialSpawnerBlock;
import net.minecraft.block.entity.MobSpawnerBlockEntity;
import net.minecraft.block.entity.TrialSpawnerBlockEntity;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.state.property.Properties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockView;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

public class SpawnerBumpingHandler implements BumpingHandler {
@Override
public @Nullable BumpLegality evaluateBumpLegality(BlockState state, BlockView world, BlockPos pos, int strength, Direction direction) {
if(state.isOf(Blocks.SPAWNER) || state.isOf(Blocks.TRIAL_SPAWNER)) {
return BumpLegality.BUMP;
}
return null;
}

@Override
public boolean bumpResponseCommon(MarioData data, @Nullable MarioTravelData travelData, World world, BlockState state, BlockPos pos, int baseStrength, int modifiedStrength, Direction direction) {
if(world instanceof ServerWorld serverWorld) {
if(world.getBlockEntity(pos) instanceof MobSpawnerBlockEntity spawnerEntity) {
for(int incrementeroo = 0; incrementeroo < 7; incrementeroo++) {
spawnerEntity.getLogic().serverTick(serverWorld, pos);
}
return true;
}

if(world.getBlockEntity(pos) instanceof TrialSpawnerBlockEntity trialSpawnerEntity) {
for(int incrementeroo = 0; incrementeroo < 3; incrementeroo++) {
trialSpawnerEntity.getSpawner().trySpawnMob(serverWorld, pos);
}
return true;
}
}

return false;
}

@Override
public boolean bumpResponseClients(MarioClientSideData data, ClientWorld world, BlockState state, BlockPos pos, int baseStrength, int modifiedStrength, Direction direction) {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
public class TrapdoorBumpingHandler implements BumpingHandler {
@Override
public @Nullable BumpLegality evaluateBumpLegality(BlockState state, BlockView world, BlockPos pos, int strength, Direction direction) {
if(state.isIn(BlockTags.TRAPDOORS)) {
if(state.isIn(BlockTags.TRAPDOORS) && strength >= (state.isIn(BlockTags.WOODEN_TRAPDOORS) ? 3 : 4)) {
if(state.get(Properties.OPEN)) {
// It's an open trapdoor; check to see if we'd be knocking it closed
if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public MarioMainClientData(ClientPlayerEntity mario) {
public final float[] CAMERA_ROTATIONS = new float[3];

@Override public void setActionTransitionless(ParsedAction action) {
MarioQuaMario.LOGGER.info("MarioMainClientData setAction to " + action.ID);
// MarioQuaMario.LOGGER.info("MarioMainClientData setAction to " + action.ID);
if(action != getAction()) getTimers().actionTimer = 0;

// CPM animation
Expand Down Expand Up @@ -102,6 +102,9 @@ public MarioMainClientData(ClientPlayerEntity mario) {
getAction().travelHook(this);
getAction().attemptTransitions(this, TransitionPhase.POST_TICK);

getTimers().jumpLandingTime--;
getTimers().doubleJumpLandingTime--;

applyModifiedVelocity();
marioClient.move(MovementType.SELF, marioClient.getVelocity());

Expand Down Expand Up @@ -182,7 +185,7 @@ private static class ClientButton implements ButtonInput {
}

private boolean unbuffer() {
this.pressBuffer = 1;
this.pressBuffer = 0;
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public MarioServerData(ServerPlayerEntity mario) {

@Override
public void setActionTransitionless(ParsedAction action) {
MarioQuaMario.LOGGER.info("MarioServerData setAction to {}", action.ID);
// MarioQuaMario.LOGGER.info("MarioServerData setAction to {}", action.ID);

if(this.getAction().ANIMATION != null)
CPMIntegration.commonAPI.playAnimation(PlayerEntity.class, this.marioServer, this.getAction().ANIMATION, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,6 @@ class MarioTimers {
public int doubleJumpLandingTime = 0;

public boolean jumpCapped = false;
public boolean canRepeatPound = true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public static ActionTransitionDefinition makeJumpCapTransition(ActionDefinition
public static final ActionTransitionDefinition GROUND_POUND = new ActionTransitionDefinition(
"qua_mario:ground_pound_windup",
data -> data.getInputs().DUCK.isPressed(),
null,
data -> data.getMario().fallDistance *= 0.4F,
(data, isSelf, seed) -> data.playSoundEvent(MarioSFX.GROUND_POUND_PRE, seed)
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class GroundPound implements ActionDefinition {
return SlidingStatus.NOT_SLIDING;
}
@Override public @Nullable Identifier getStompType() {
return Identifier.of("qua_mario", "stomp");
return Identifier.of("qua_mario", "ground_pound");
}

@Override public void travelHook(MarioTravelData data) {
Expand Down Expand Up @@ -73,7 +73,7 @@ public class GroundPound implements ActionDefinition {
new ActionTransitionDefinition(
"qua_mario:ground_pound_landing",
AirborneActionDefinition.AerialTransitions.BASIC_LANDING.EVALUATOR,
data -> {},
data -> data.setForwardStrafeVel(0, 0),
(data, isSelf, seed) -> data.playSoundEvent(MarioSFX.GROUND_POUND, seed)
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,8 @@ else airborneAccel(data,

@Override public List<ActionTransitionDefinition> getPostTickTransitions() {
return List.of(
AerialTransitions.makeJumpCapTransition(this, 0.765),
AerialTransitions.GROUND_POUND
);
}

@Override
public List<ActionTransitionDefinition> getPostMoveTransitions() {
return List.of(
AerialTransitions.BASIC_LANDING
AerialTransitions.GROUND_POUND,
AerialTransitions.makeJumpCapTransition(this, 0.765)
);
}
}
Loading

0 comments on commit c211a28

Please sign in to comment.