Skip to content

Commit

Permalink
Reworked block bumping to use an Event instead of entrypoints. No mor…
Browse files Browse the repository at this point in the history
…e golden hammer!!!!!
  • Loading branch information
floral-qua-floral committed Nov 17, 2024
1 parent c211a28 commit 3a410d7
Show file tree
Hide file tree
Showing 18 changed files with 340 additions and 518 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/floralquafloral/MarioCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private static int executeBump(CommandContext<ServerCommandSource> context, bool
BlockPos position = BlockPosArgumentType.getBlockPos(context, "position");

MarioServerData data = (MarioServerData) MarioDataManager.getMarioData(bumper);
BumpManager.bumpBlockServer(data, bumper.getServerWorld(), position, strength, strength, direction, true, true);
// BumpManager.bumpBlockServer(data, bumper.getServerWorld(), position, strength, strength, direction, true, true);
// BumpManager.bumpResponseCommon(data, data, bumper.getServerWorld(), bumper.getServerWorld().getBlockState(position), position, strength, strength, direction);

return sendFeedback(context, "Made " + bumper.getName().getString() + " bump block " + direction + " with a strength " + strength);
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/floralquafloral/bumping/BlockBumpCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.floralquafloral.bumping;

import com.floralquafloral.mariodata.MarioClientSideData;
import com.floralquafloral.mariodata.MarioData;
import com.floralquafloral.mariodata.moveable.MarioTravelData;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.block.BlockState;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

/**
* Callback for Mario bumping a block in the world.
* Used on the client and server.
* On the client, called before the block is visibly displaced and the attempt is networked to the server.
* On the server, called before the block is given a redstone signal.
* Upon return:
* - PASS falls back to further processing.
* - DISPLACE cancels further processing and displaces the block.
* - BREAK cancels further processing and destroys the block, dropping an item.
* - CANCEL cancels further processing and does not bump the block (or network the attempt!!!).
* - CANCEL_NETWORKED cancels further processing and does not visually displace the block, but will still be networked
* if it occurs on the client.
*/
public interface BlockBumpCallback {
Event<BlockBumpCallback> EVENT = EventFactory.createArrayBacked(BlockBumpCallback.class,
listeners -> (marioData, marioClientData, marioTravelData, world, blockPos, blockState, strength, modifier, direction) -> {
for(BlockBumpCallback listener : listeners) {
BlockBumpResult result = listener.bump(
marioData, marioClientData, marioTravelData,
world, blockPos, blockState,
strength, modifier, direction
);
if(result != BlockBumpResult.PASS) return result;
}


return BlockBumpResult.PASS;
}
);

BlockBumpResult bump(
MarioData marioData, @Nullable MarioClientSideData marioClientData, @Nullable MarioTravelData marioTravelData,
World world, BlockPos blockPos, BlockState blockState,
int strength, int modifier, Direction direction
);
}
132 changes: 132 additions & 0 deletions src/main/java/com/floralquafloral/bumping/BlockBumpHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.floralquafloral.bumping;

import com.floralquafloral.mariodata.MarioClientSideData;
import com.floralquafloral.mariodata.MarioData;
import com.floralquafloral.mariodata.moveable.MarioTravelData;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import net.minecraft.util.crash.CrashException;
import net.minecraft.util.crash.CrashReport;
import net.minecraft.util.crash.CrashReportSection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;

import java.util.HashSet;
import java.util.Set;

import static com.floralquafloral.MarioQuaMario.MOD_ID;

public class BlockBumpHandler {
public static final TagKey<Block> UNBUMPABLE =
TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "unbumpable"));
public static final TagKey<Block> BUMP_REGARDLESS_OF_HARDNESS =
TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "bump_regardless_of_hardness"));
public static final TagKey<Block> EXTREMELY_EASY_TO_BUMP =
TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "extremely_easy_to_bump"));
public static final TagKey<Block> UNBREAKABLE_FROM_BUMPING =
TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "unbreakable_from_bumping"));

public static final TagKey<Block> DO_NOT_POWER =
TagKey.of(RegistryKeys.BLOCK, Identifier.of(MOD_ID, "do_not_power_on_bump"));

public static final Set<BlockPos> FORCED_SIGNALS = new HashSet<>();
public static final Set<ForcedSignalSpot> FORCED_SIGNALS_DATA = new HashSet<>();

public static BlockBumpResult processBumpResult(
MarioData marioData, @Nullable MarioClientSideData marioClientData, @Nullable MarioTravelData marioTravelData,
World world, BlockPos blockPos, BlockState blockState,
int strength, int modifier, Direction direction
) {
BlockBumpResult result = getBumpResult(
marioData, marioClientData, marioTravelData,
world, blockPos, blockState,
strength, modifier, direction
);

if(result == BlockBumpResult.PASS) {
CrashReport crashReport = CrashReport.create(new InvalidBumpResultException(), "Bumping a block");
throw new CrashException(crashReport);
}

if(result == BlockBumpResult.BREAK) world.breakBlock(blockPos, true, marioData.getMario());
else if(result == BlockBumpResult.DISPLACE) {
// Apply redstone power
if(!blockState.isIn(BlockBumpHandler.DO_NOT_POWER)) {
BlockBumpHandler.FORCED_SIGNALS.add(blockPos);
BlockBumpHandler.FORCED_SIGNALS_DATA.add(new BlockBumpHandler.ForcedSignalSpot(blockPos, world));
world.updateNeighbor(blockPos, blockState.getBlock(), blockPos);
}
}

return result;
}

private static class InvalidBumpResultException extends RuntimeException {}

private static BlockBumpResult getBumpResult(
MarioData marioData, @Nullable MarioClientSideData marioClientData, @Nullable MarioTravelData marioTravelData,
World world, BlockPos blockPos, BlockState blockState,
int strength, int modifier, Direction direction
) {
BlockBumpResult result = BlockBumpCallback.EVENT.invoker().bump(
marioData, marioClientData, marioTravelData,
world, blockPos, blockState,
strength, modifier, direction
);
if (result != BlockBumpResult.PASS)
return result;
else {
if(blockState.isIn(BlockBumpHandler.UNBUMPABLE)) return BlockBumpResult.CANCEL;
if(blockState.isIn(BlockBumpHandler.BUMP_REGARDLESS_OF_HARDNESS) && strength >= 4) return BlockBumpResult.DISPLACE;
if(blockState.isIn(BlockBumpHandler.EXTREMELY_EASY_TO_BUMP) && strength >= 1) return BlockBumpResult.DISPLACE;

int modifiedStrength = strength + modifier;

float adjustedHardness = blockState.getHardness(world, blockPos);
if(blockState.isTransparent(world, blockPos) && !blockState.hasSidedTransparency()) adjustedHardness *= 0.5F;

if(adjustedHardness == -1 || modifiedStrength <= 1) return BlockBumpResult.CANCEL;

BlockBumpResult strongEnoughToBreakResult =
blockState.isIn(UNBREAKABLE_FROM_BUMPING) ? BlockBumpResult.DISPLACE : BlockBumpResult.BREAK;

// Super Mario spin-jumping can destroy fairly fragile blocks (ice, leaves).
// Failing to destroy a block in this manner won't bump it at all.
if(modifiedStrength == 2)
return (adjustedHardness <= 0.25F) ? strongEnoughToBreakResult : BlockBumpResult.CANCEL;

BlockBumpResult failedToBreakResult = (adjustedHardness <= 0.75F * Math.max(strength, modifiedStrength))
? BlockBumpResult.DISPLACE : BlockBumpResult.CANCEL;

// Small Mario ground-pounding or bopping a ceiling can only break exceptionally fragile blocks (candles, moss, scaffolding).
if(modifiedStrength == 3)
return (adjustedHardness < 0.2F) ? strongEnoughToBreakResult : failedToBreakResult;

// If we get to this point, we know for sure modifiedStrength >= 3.
// Super Mario gets a bonus to breaking bricks
if(blockState.getBlock().toString().contains("brick")) adjustedHardness -= 1;

// Super Mario ground-pounding or bopping a ceiling can break somewhat fragile blocks (dirt, pumpkins),
// and relatively weak brick blocks (mud bricks, stone bricks, NOT end bricks)
return (adjustedHardness <= modifiedStrength * 0.25F) ? strongEnoughToBreakResult : failedToBreakResult;
}
}

public static class ForcedSignalSpot {
public final BlockPos POSITION;
public final World WORLD;
public int delay;

private ForcedSignalSpot(BlockPos position, World world) {
this.POSITION = position;
this.WORLD = world;
this.delay = 3;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.floralquafloral.bumping;

public enum BlockBumpResult {
PASS,
DISPLACE,
BREAK,
CANCEL,
CANCEL_NETWORKED
}
Loading

0 comments on commit 3a410d7

Please sign in to comment.