Skip to content

Commit

Permalink
Don't require players to press the button, just that the first player…
Browse files Browse the repository at this point in the history
… does and others are in the area
  • Loading branch information
Gegy committed Nov 2, 2024
1 parent 7da9418 commit aed90c6
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public BigRedButtonBlockEntityRenderer(BlockEntityRendererProvider.Context conte

@Override
public void render(BigRedButtonBlockEntity entity, float partialTicks, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
int pressedCount = entity.getPlayersPressedCount();
int presentCount = entity.getPlayersPresentCount();
int requiredCount = entity.getPlayersRequiredCount();
String text = pressedCount + "/" + requiredCount;
String text = presentCount + "/" + requiredCount;

poseStack.pushPose();
poseStack.translate(0.5f, 0.5f, 0.5f);
Expand All @@ -47,7 +47,7 @@ public void render(BigRedButtonBlockEntity entity, float partialTicks, PoseStack
float scale = 1.0f / (textWidth + TEXT_PADDING);
poseStack.scale(scale, scale, -scale);

int color = FastColor.ARGB32.lerp((float) pressedCount / requiredCount, START_COLOR, TRIGGERED_COLOR);
int color = FastColor.ARGB32.lerp((float) presentCount / requiredCount, START_COLOR, TRIGGERED_COLOR);
font.drawInBatch(text, -textWidth / 2.0f, -font.lineHeight, color, true, poseStack.last().pose(), bufferSource, Font.DisplayMode.NORMAL, 0, packedLight);

poseStack.popPose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,21 +80,21 @@ public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, Co
@Override
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof BigRedButtonBlockEntity entity) {
if (!state.getValue(TRIGGERED) && entity.press(player)) {
trigger(state, level, pos, player);
if (!state.getValue(TRIGGERED)) {
entity.press();
return InteractionResult.SUCCESS;
}
}
return super.useWithoutItem(state, level, pos, player, hit);
}

private void trigger(BlockState state, Level level, BlockPos pos, Player player) {
public static void trigger(BlockState state, Level level, BlockPos pos) {
level.setBlock(pos, state.setValue(POWERED, true).setValue(TRIGGERED, true), Block.UPDATE_ALL);
level.updateNeighborsAt(pos, this);
level.updateNeighborsAt(pos.relative(getConnectedDirection(state).getOpposite()), this);
level.updateNeighborsAt(pos, state.getBlock());
level.updateNeighborsAt(pos.relative(getConnectedDirection(state).getOpposite()), state.getBlock());

level.playSound(null, pos, SoundEvents.PISTON_EXTEND, SoundSource.BLOCKS);
level.gameEvent(player, GameEvent.BLOCK_ACTIVATE, pos);
level.gameEvent(null, GameEvent.BLOCK_ACTIVATE, pos);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,17 @@
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.network.Connection;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
Expand All @@ -30,20 +27,18 @@
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;

import java.util.Set;
import java.util.UUID;

public class BigRedButtonBlockEntity extends BlockEntity {
private static final Logger LOGGER = LogUtils.getLogger();

private static final String TAG_PLAYERS = "players";
private static final String TAG_PRESSED = "pressed";
private static final String TAG_PRESENT = "present";
private static final String TAG_REQUIREMENTS = "requirements";
private static final String TAG_TRIGGER_POS = "trigger_pos";

private final Set<UUID> playersPressed = new ObjectOpenHashSet<>();
private int playersPressedCount;
private boolean pressed;

private Requirements requirements = new Requirements(0.0f, 1);
private Requirements requirements = new Requirements(0.0f, 1, Requirements.DEFAULT_DISTANCE);
private int playersPresentCount;
private int playersRequiredCount;

@Nullable
Expand All @@ -57,10 +52,27 @@ public static void tick(Level level, BlockPos pos, BlockState state, BigRedButto
if (state.getValue(BigRedButtonBlock.TRIGGERED)) {
return;
}

IGamePhase game = IGameManager.get().getGamePhaseAt(level, pos);
int smallestTeamSize = game != null ? getSmallestTeamSize(game) : 1;
int resolvedRequirement = entity.requirements.resolve(smallestTeamSize);
entity.updateRequiredPlayers(resolvedRequirement);
int requiredCount = entity.requirements.resolve(smallestTeamSize);
int presentCount = game != null && entity.pressed ? entity.countPlayersPresent(game, pos) : 0;
entity.updatePlayerCount(presentCount, requiredCount);

if (entity.pressed && presentCount >= requiredCount) {
entity.trigger();
entity.pressed = false;
}
}

private int countPlayersPresent(IGamePhase game, BlockPos pos) {
int count = 0;
for (ServerPlayer player : game.participants()) {
if (pos.closerToCenterThan(player.position(), requirements.distance)) {
count++;
}
}
return count;
}

private static int getSmallestTeamSize(IGamePhase game) {
Expand All @@ -78,47 +90,38 @@ private static int getSmallestTeamSize(IGamePhase game) {
return smallestTeamSize;
}

private void updateRequiredPlayers(int count) {
if (count != playersRequiredCount) {
playersRequiredCount = count;
markUpdated();
private void updatePlayerCount(int presentCount, int requiredCount) {
if (presentCount == playersPresentCount && requiredCount == playersRequiredCount) {
return;
}
playersPresentCount = presentCount;
playersRequiredCount = requiredCount;
markUpdated();
}

public boolean press(Player player) {
public void press() {
// No game is active, just allow instant trigger
if (IGameManager.get().getGamePhaseAt(level, getBlockPos()) == null) {
applyTriggerEffects();
return true;
}
if (playersPressed.add(player.getUUID())) {
playersPressedCount = playersPressed.size();
markUpdated();
}
if (playersPressedCount >= playersRequiredCount) {
applyTriggerEffects();
return true;
trigger();
return;
}
return false;
pressed = true;
}

private void applyTriggerEffects() {
private void trigger() {
BigRedButtonBlock.trigger(getBlockState(), level, getBlockPos());
if (triggerPos != null) {
BlockState state = level.getBlockState(triggerPos);
if (state.is(SurviveTheTide.LOOT_DISPENSER) && state.getValue(LootDispenserBlock.STATE) == LootDispenserBlock.State.INACTIVE) {
level.setBlockAndUpdate(triggerPos, state.setValue(LootDispenserBlock.STATE, LootDispenserBlock.State.ACTIVE));
BlockState triggerState = level.getBlockState(triggerPos);
if (triggerState.is(SurviveTheTide.LOOT_DISPENSER) && triggerState.getValue(LootDispenserBlock.STATE) == LootDispenserBlock.State.INACTIVE) {
level.setBlockAndUpdate(triggerPos, triggerState.setValue(LootDispenserBlock.STATE, LootDispenserBlock.State.ACTIVE));
}
}
}

@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
ListTag playersList = new ListTag();
for (UUID id : playersPressed) {
playersList.add(NbtUtils.createUUID(id));
}
tag.put(TAG_PLAYERS, playersList);
tag.putBoolean(TAG_PRESSED, pressed);
tag.put(TAG_REQUIREMENTS, Requirements.CODEC.encodeStart(NbtOps.INSTANCE, requirements).getOrThrow());
if (triggerPos != null) {
tag.put(TAG_TRIGGER_POS, NbtUtils.writeBlockPos(triggerPos));
Expand All @@ -128,11 +131,7 @@ protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries)
@Override
public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
playersPressed.clear();
for (Tag id : tag.getList(TAG_PLAYERS, Tag.TAG_LIST)) {
playersPressed.add(NbtUtils.loadUUID(id));
}
playersPressedCount = playersPressed.size();
pressed = tag.getBoolean(TAG_PRESSED);
Requirements.CODEC.parse(NbtOps.INSTANCE, tag.get(TAG_REQUIREMENTS))
.resultOrPartial(LOGGER::error)
.ifPresent(r -> requirements = r);
Expand All @@ -142,7 +141,7 @@ public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
CompoundTag tag = new CompoundTag();
tag.putInt(TAG_PLAYERS, playersPressed.size());
tag.putInt(TAG_PRESENT, playersPresentCount);
tag.putInt(TAG_REQUIREMENTS, playersRequiredCount);
return tag;
}
Expand All @@ -156,7 +155,7 @@ public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt, H

@Override
public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider registries) {
playersPressedCount = tag.getInt(TAG_PLAYERS);
playersPresentCount = tag.getInt(TAG_PRESENT);
playersRequiredCount = tag.getInt(TAG_REQUIREMENTS);
}

Expand All @@ -170,18 +169,20 @@ private void markUpdated() {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_ALL);
}

public int getPlayersPressedCount() {
return playersPressedCount;
public int getPlayersPresentCount() {
return playersPresentCount;
}

public int getPlayersRequiredCount() {
return playersRequiredCount;
}

private record Requirements(float percent, int count) {
private record Requirements(float percent, int count, float distance) {
public static final float DEFAULT_DISTANCE = 4.0f;
public static final Codec<Requirements> CODEC = RecordCodecBuilder.create(i -> i.group(
Codec.FLOAT.optionalFieldOf("percent", 0.0f).forGetter(Requirements::percent),
Codec.INT.optionalFieldOf("count", 1).forGetter(Requirements::count)
Codec.INT.optionalFieldOf("count", 1).forGetter(Requirements::count),
Codec.FLOAT.optionalFieldOf("distance", DEFAULT_DISTANCE).forGetter(Requirements::distance)
).apply(i, Requirements::new));

public int resolve(int smallestTeamSize) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ public static void tick(Level level, BlockPos pos, BlockState state, LootDispens
private static int getPlayerCountAround(ServerLevel level, BlockPos pos, LootConfig loot) {
int count = 0;
for (ServerPlayer player : level.players()) {
if (player.isSpectator()) {
continue;
}
if (!pos.closerToCenterThan(player.position(), loot.playerRange())) {
continue;
}
Expand Down

0 comments on commit aed90c6

Please sign in to comment.