Skip to content

Commit

Permalink
fix: block placement dupe problem on Fabric
Browse files Browse the repository at this point in the history
Manual adaptation and pull of #213

Merge the block interaction and block edit properties on Fabric, since
we cannot reliably distinguish right-clicking a block to use it versus
right-clicking a block to place it.  Means reduced functionality on
Fabric vs. Forge, but still better than allowing dupes to occur.

Also added a little code to re-sync client's held item from the server
whenever a place or use event is cancelled.

FTBTeam/FTB-Mods-Issues#673
FTBTeam/FTB-Mods-Issues#315
  • Loading branch information
desht committed Feb 21, 2023
1 parent a88930f commit 40c9224
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 10 deletions.
13 changes: 13 additions & 0 deletions common/src/main/java/dev/ftb/mods/ftbchunks/FTBCUtils.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dev.ftb.mods.ftbchunks;

import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.effect.MobEffectCategory;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.PotionItem;
Expand All @@ -17,4 +20,14 @@ public static boolean isBeneficialPotion(ItemStack stack) {
return stack.getItem() instanceof PotionItem && PotionUtils.getMobEffects(stack).stream()
.noneMatch(effect -> effect.getEffect().getCategory() == MobEffectCategory.HARMFUL);
}

/**
* Used after various events have been cancelled server-side; client may already have updated the held item for the
* player, but it needs to be brought back in sync with the server.
* @param sp the player
* @param hand the hand being used
*/
public static void forceHeldItemSync(ServerPlayer sp, InteractionHand hand) {
sp.connection.send(new ClientboundContainerSetSlotPacket(-2, 0, sp.getInventory().selected, sp.getItemInHand(hand)));
}
}
22 changes: 16 additions & 6 deletions common/src/main/java/dev/ftb/mods/ftbchunks/FTBChunks.java
Original file line number Diff line number Diff line change
Expand Up @@ -272,15 +272,19 @@ public EventResult blockLeftClick(Player player, InteractionHand hand, BlockPos
}

public EventResult blockRightClick(Player player, InteractionHand hand, BlockPos pos, Direction face) {
if (player instanceof ServerPlayer && FTBChunksAPI.getManager().protect(player, hand, pos, Protection.INTERACT_BLOCK, null)) {
// calling architectury stub method
//noinspection ConstantConditions
if (player instanceof ServerPlayer sp && FTBChunksAPI.getManager().protect(player, hand, pos, FTBChunksExpected.getBlockInteractProtection(), null)) {
FTBCUtils.forceHeldItemSync(sp, hand);
return EventResult.interruptFalse();
}

return EventResult.pass();
}

public CompoundEventResult<ItemStack> itemRightClick(Player player, InteractionHand hand) {
if (player instanceof ServerPlayer && FTBChunksAPI.getManager().protect(player, hand, new BlockPos(player.getEyePosition(1F)), Protection.RIGHT_CLICK_ITEM, null)) {
if (player instanceof ServerPlayer sp && FTBChunksAPI.getManager().protect(player, hand, new BlockPos(player.getEyePosition(1F)), Protection.RIGHT_CLICK_ITEM, null)) {
FTBCUtils.forceHeldItemSync(sp, hand);
return CompoundEventResult.interruptFalse(player.getItemInHand(hand));
}

Expand All @@ -297,15 +301,18 @@ private EventResult interactEntity(Player player, Entity entity, InteractionHand
}

public EventResult blockBreak(Level level, BlockPos pos, BlockState blockState, ServerPlayer player, @Nullable IntValue intValue) {
if (FTBChunksAPI.getManager().protect(player, InteractionHand.MAIN_HAND, pos, Protection.EDIT_BLOCK, null)) {
if (FTBChunksAPI.getManager().protect(player, InteractionHand.MAIN_HAND, pos, FTBChunksExpected.getBlockBreakProtection(), null)) {
return EventResult.interruptFalse();
}

return EventResult.pass();
}

public EventResult blockPlace(Level level, BlockPos pos, BlockState blockState, @Nullable Entity entity) {
if (entity instanceof ServerPlayer && FTBChunksAPI.getManager().protect(entity, InteractionHand.MAIN_HAND, pos, Protection.EDIT_BLOCK, null)) {
// calling architectury stub method
//noinspection ConstantConditions
if (entity instanceof ServerPlayer sp && FTBChunksAPI.getManager().protect(entity, InteractionHand.MAIN_HAND, pos, FTBChunksExpected.getBlockPlaceProtection(), null)) {
FTBCUtils.forceHeldItemSync(sp, InteractionHand.MAIN_HAND);
return EventResult.interruptFalse();
}

Expand Down Expand Up @@ -434,12 +441,15 @@ private void teamConfig(TeamCollectPropertiesEvent event) {
event.add(FTBChunksTeamData.ALLOW_ALL_FAKE_PLAYERS);
event.add(FTBChunksTeamData.ALLOW_NAMED_FAKE_PLAYERS);
event.add(FTBChunksTeamData.ALLOW_FAKE_PLAYERS_BY_ID);
event.add(FTBChunksTeamData.BLOCK_EDIT_MODE);
event.add(FTBChunksTeamData.BLOCK_INTERACT_MODE);

// block edit/interact properties vary on forge & fabric
FTBChunksExpected.getPlatformSpecificProperties(event);

event.add(FTBChunksTeamData.ENTITY_INTERACT_MODE);
event.add(FTBChunksTeamData.NONLIVING_ENTITY_ATTACK_MODE);
event.add(FTBChunksTeamData.CLAIM_VISIBILITY);
event.add(FTBChunksTeamData.LOCATION_MODE);

// event.add(FTBChunksTeamData.MINIMAP_MODE);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package dev.ftb.mods.ftbchunks;

import dev.architectury.injectables.annotations.ExpectPlatform;
import net.minecraft.core.BlockPos;
import dev.ftb.mods.ftbchunks.data.Protection;
import dev.ftb.mods.ftbteams.event.TeamCollectPropertiesEvent;
import net.minecraft.server.level.ServerLevel;

import java.util.UUID;
Expand All @@ -11,4 +12,26 @@ public class FTBChunksExpected {
public static void addChunkToForceLoaded(ServerLevel level, String modId, UUID owner, int chunkX, int chunkY, boolean add) {
throw new AssertionError();
}

@ExpectPlatform
public static void getPlatformSpecificProperties(TeamCollectPropertiesEvent event) {
// required since Forge & Fabric have different requirements:
// https://github.com/FTBTeam/FTB-Chunks/pull/213
throw new AssertionError();
}

@ExpectPlatform
public static Protection getBlockPlaceProtection() {
throw new AssertionError();
}

@ExpectPlatform
public static Protection getBlockInteractProtection() {
throw new AssertionError();
}

@ExpectPlatform
public static Protection getBlockBreakProtection() {
throw new AssertionError();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,19 @@ public class FTBChunksTeamData {
public static final BooleanProperty ALLOW_ALL_FAKE_PLAYERS = new BooleanProperty(new ResourceLocation(FTBChunks.MOD_ID, "allow_fake_players"), false);
public static final StringListProperty ALLOW_NAMED_FAKE_PLAYERS = new StringListProperty(new ResourceLocation(FTBChunks.MOD_ID, "allow_named_fake_players"), new ArrayList<>());
public static final BooleanProperty ALLOW_FAKE_PLAYERS_BY_ID = new BooleanProperty(new ResourceLocation(FTBChunks.MOD_ID, "allow_fake_players_by_id"), true);
// forge
public static final PrivacyProperty BLOCK_EDIT_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "block_edit_mode"), PrivacyMode.ALLIES);
public static final PrivacyProperty BLOCK_INTERACT_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "block_interact_mode"), PrivacyMode.ALLIES);
// fabric
public static final PrivacyProperty BLOCK_EDIT_AND_INTERACT_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "block_edit_and_interact_mode"), PrivacyMode.ALLIES);
public static final PrivacyProperty ENTITY_INTERACT_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "entity_interact_mode"), PrivacyMode.ALLIES);
public static final PrivacyProperty NONLIVING_ENTITY_ATTACK_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "nonliving_entity_attack_mode"), PrivacyMode.ALLIES);
// public static final PrivacyProperty MINIMAP_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "minimap_mode"), PrivacyMode.ALLIES);
public static final PrivacyProperty LOCATION_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "location_mode"), PrivacyMode.ALLIES);
public static final BooleanProperty ALLOW_EXPLOSIONS = new BooleanProperty(new ResourceLocation(FTBChunks.MOD_ID, "allow_explosions"), false);
public static final PrivacyProperty CLAIM_VISIBILITY = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "claim_visibility"), PrivacyMode.PUBLIC);

// public static final PrivacyProperty MINIMAP_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "minimap_mode"), PrivacyMode.ALLIES);

public static final PrivacyProperty LOCATION_MODE = new PrivacyProperty(new ResourceLocation(FTBChunks.MOD_ID, "location_mode"), PrivacyMode.ALLIES);
public final ClaimedChunkManager manager;
private final Team team;
public final Path file;
Expand Down
17 changes: 16 additions & 1 deletion common/src/main/java/dev/ftb/mods/ftbchunks/data/Protection.java
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,20 @@ public interface Protection {
return ProtectionOverride.CHECK;
};

ProtectionOverride override(ServerPlayer player, BlockPos pos, InteractionHand hand, @Nullable ClaimedChunk chunk, @Nullable Entity entity);
// for use on Fabric
Protection EDIT_AND_INTERACT_BLOCK = (player, pos, hand, chunk, entity) -> {
BlockState blockState = player.level.getBlockState(pos);

if (blockState.is(FTBChunksAPI.INTERACT_WHITELIST_TAG)) {
return ProtectionOverride.ALLOW;
}

if (chunk != null && chunk.teamData.canUse(player, FTBChunksTeamData.BLOCK_EDIT_AND_INTERACT_MODE)) {
return ProtectionOverride.ALLOW;
}

return ProtectionOverride.CHECK;
};

ProtectionOverride override(ServerPlayer player, BlockPos pos, InteractionHand hand, @Nullable ClaimedChunk chunk, @Nullable Entity entity);
}
2 changes: 2 additions & 0 deletions common/src/main/resources/assets/ftbchunks/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
"ftbteamsconfig.ftbchunks.allow_fake_players_by_id.tooltip": "Allows fake players which have the ID of a real player access to your claims, IF that real player would be permitted, either as ally or team member. Set this to true if you're unsure.",
"ftbteamsconfig.ftbchunks.allow_explosions": "Allow Explosions",
"ftbteamsconfig.ftbchunks.allow_explosions.tooltip": "Should explosions be able to damage blocks in claimed areas?",
"ftbteamsconfig.ftbchunks.block_edit_and_interact_mode": "Block Edit/Interact Mode",
"ftbteamsconfig.ftbchunks.block_edit_and_interact_mode.tooltip": "Used when blocks are being placed, broken, or interacted with",
"ftbteamsconfig.ftbchunks.block_edit_mode": "Block Edit Mode",
"ftbteamsconfig.ftbchunks.block_edit_mode.tooltip": "Used when blocks are being placed or broken",
"ftbteamsconfig.ftbchunks.block_interact_mode": "Block Interact Mode",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dev.ftb.mods.ftbchunks.fabric;

import dev.ftb.mods.ftbchunks.FTBChunks;
import dev.ftb.mods.ftbchunks.data.FTBChunksTeamData;
import dev.ftb.mods.ftbchunks.data.Protection;
import dev.ftb.mods.ftbteams.event.TeamCollectPropertiesEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.level.ChunkPos;
Expand All @@ -18,4 +21,20 @@ public static void addChunkToForceLoaded(ServerLevel level, String modId, UUID o
level.getChunkSource().removeRegionTicket(TicketType.FORCED, chunkPos, 2, chunkPos);
}
}

public static void getPlatformSpecificProperties(TeamCollectPropertiesEvent event) {
event.add(FTBChunksTeamData.BLOCK_EDIT_AND_INTERACT_MODE);
}

public static Protection getBlockPlaceProtection() {
return Protection.EDIT_AND_INTERACT_BLOCK;
}

public static Protection getBlockInteractProtection() {
return Protection.EDIT_AND_INTERACT_BLOCK;
}

public static Protection getBlockBreakProtection() {
return Protection.EDIT_AND_INTERACT_BLOCK;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package dev.ftb.mods.ftbchunks.forge;

import dev.ftb.mods.ftbchunks.FTBChunks;
import dev.ftb.mods.ftbchunks.data.FTBChunksTeamData;
import dev.ftb.mods.ftbchunks.data.Protection;
import dev.ftb.mods.ftbteams.event.TeamCollectPropertiesEvent;
import net.minecraft.server.level.ServerLevel;
import net.minecraftforge.common.world.ForgeChunkManager;

Expand All @@ -11,4 +14,21 @@ public static void addChunkToForceLoaded(ServerLevel level, String modId, UUID o
ForgeChunkManager.forceChunk(level, modId, owner, chunkX, chunkY, add, true);
FTBChunks.LOGGER.debug("force chunk (forge): mod={} owner={}, c=({},{}), load={}", modId, owner, chunkX, chunkY, add);
}

public static void getPlatformSpecificProperties(TeamCollectPropertiesEvent event) {
event.add(FTBChunksTeamData.BLOCK_EDIT_MODE);
event.add(FTBChunksTeamData.BLOCK_INTERACT_MODE);
}

public static Protection getBlockPlaceProtection() {
return Protection.EDIT_BLOCK;
}

public static Protection getBlockInteractProtection() {
return Protection.INTERACT_BLOCK;
}

public static Protection getBlockBreakProtection() {
return Protection.EDIT_BLOCK;
}
}

0 comments on commit 40c9224

Please sign in to comment.