Extract obfuscation config into HiderCore

ObfuscationConfig resolves the hidden blocks, block states (including all
waterlogged states when water is hidden) and block entity types plus the
obfuscation block, either from a gamemode's techhider config or from plain
materials. TechHiderWrapper now only contains the fight specific access rules.
This commit is contained in:
2026-10-31 14:50:32 +01:00
parent da4b684a4b
commit 7d4252325a
3 changed files with 125 additions and 63 deletions
@@ -32,32 +32,21 @@ import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.techhider.AccessPrivilegeProvider;
import de.steamwar.techhider.AccessPrivilegeProvider.ForPlayer;
import de.steamwar.techhider.ObfuscationConfig;
import de.steamwar.techhider.TechHider;
import lombok.Getter;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TechHiderWrapper extends StateDependent implements Listener {
@@ -80,29 +69,15 @@ public class TechHiderWrapper extends StateDependent implements Listener {
@Override
public void enable() {
Set<BlockState> blockStatesToObfuscate = getBlockStatesToHideFromMaterials(Config.GameModeConfig.Techhider.HiddenBlocks);
Set<Block> blocksToObfuscate = Config.GameModeConfig.Techhider.HiddenBlocks.stream()
.map(CraftMagicNumbers::getBlock)
.collect(Collectors.toUnmodifiableSet());
Set<BlockEntityType<?>> blockEntityTypeToObfuscate = Config.GameModeConfig.Techhider.HiddenBlockEntities.stream()
.map(id -> {
ResourceLocation loc = ResourceLocation.parse(id);
return BuiltInRegistries.BLOCK_ENTITY_TYPE.get(loc).orElse(null);
})
.filter(Objects::nonNull)
.map(Holder.Reference::value)
.collect(Collectors.toUnmodifiableSet());
new TechHider(CraftMagicNumbers.getBlock(Config.GameModeConfig.Techhider.ObfuscateWith), newProvider(blockStatesToObfuscate, blocksToObfuscate, blockEntityTypeToObfuscate));
ObfuscationConfig obfuscation = ObfuscationConfig.of(Config.GameModeConfig.Techhider);
new TechHider(obfuscation.getObfuscateWith(), newProvider(obfuscation));
}
private AccessPrivilegeProvider newProvider(Set<BlockState> blockStatesToObfuscate, Set<Block> blocksToObfuscate, Set<BlockEntityType<?>> blockEntityTypeToObfuscate) {
private AccessPrivilegeProvider newProvider(ObfuscationConfig obfuscation) {
return new AccessPrivilegeProvider() {
@Override
public ForPlayer forPlayer(Player p) {
return new FightPlayerAccess(p, getHiddenRegions(p), blockStatesToObfuscate, blocksToObfuscate, blockEntityTypeToObfuscate);
return new FightPlayerAccess(p, getHiddenRegions(p), obfuscation);
}
@Override
@@ -118,16 +93,12 @@ public class TechHiderWrapper extends StateDependent implements Listener {
private class FightPlayerAccess implements ForPlayer {
private final Player player;
private final Region[] hiddenRegions;
private final Set<BlockState> blockStatesToObfuscate;
private final Set<Block> blocksToObfuscate;
private final Set<BlockEntityType<?>> blockEntityTypeToObfuscate;
private final ObfuscationConfig obfuscation;
private FightPlayerAccess(Player player, Region[] hiddenRegions, Set<BlockState> blockStatesToObfuscate, Set<Block> blocksToObfuscate, Set<BlockEntityType<?>> blockEntityTypeToObfuscate) {
private FightPlayerAccess(Player player, Region[] hiddenRegions, ObfuscationConfig obfuscation) {
this.player = player;
this.hiddenRegions = hiddenRegions;
this.blockStatesToObfuscate = blockStatesToObfuscate;
this.blocksToObfuscate = blocksToObfuscate;
this.blockEntityTypeToObfuscate = blockEntityTypeToObfuscate;
this.obfuscation = obfuscation;
}
private boolean isHidden(int blockX, int blockY, int blockZ) {
@@ -155,12 +126,12 @@ public class TechHiderWrapper extends StateDependent implements Listener {
@Override
public boolean canAccessBlock(int blockX, int blockY, int blockZ, Block block) {
return !isHidden(blockX, blockY, blockZ) || !blocksToObfuscate.contains(block);
return !isHidden(blockX, blockY, blockZ) || !obfuscation.hidesBlock(block);
}
@Override
public boolean canAccessBlockState(int blockX, int blockY, int blockZ, BlockState blockState) {
return !isHidden(blockX, blockY, blockZ) || !blockStatesToObfuscate.contains(blockState);
return !isHidden(blockX, blockY, blockZ) || !obfuscation.hidesBlockState(blockState);
}
// TODO will require entity tracking on the netty thread to prevent future race conditions
@@ -177,7 +148,7 @@ public class TechHiderWrapper extends StateDependent implements Listener {
@Override
public boolean canAccessBlockEntity(int blockX, int blockY, int blockZ, BlockEntityType<?> type) {
return !isHidden(blockX, blockY, blockZ) || !blockEntityTypeToObfuscate.contains(type);
return !isHidden(blockX, blockY, blockZ) || !obfuscation.hidesBlockEntity(type);
}
}
@@ -235,27 +206,4 @@ public class TechHiderWrapper extends StateDependent implements Listener {
return new Region[]{Fight.getOpposite(fightPlayer.getTeam()).getExtendRegion()};
}
private Stream<BlockState> getWaterloggedBlockStates() {
FluidState waterFluidState = Fluids.WATER.getSource(false);
return BuiltInRegistries.BLOCK.stream()
.map((block) -> block.getStateDefinition().getPossibleStates())
.flatMap(Collection::stream)
.filter((blockState -> blockState.getFluidState() == waterFluidState));
}
private Set<BlockState> getBlockStatesToHideFromMaterials(Set<Material> materials) {
Stream<BlockState> allStatesFromMaterials = materials.stream()
.map(CraftMagicNumbers::getBlock)
.map((block) -> block.getStateDefinition().getPossibleStates())
.flatMap(Collection::stream);
if(materials.contains(Material.WATER)) {
return Stream.concat(allStatesFromMaterials, getWaterloggedBlockStates()).collect(Collectors.toUnmodifiableSet());
}
else {
return allStatesFromMaterials.collect(Collectors.toUnmodifiableSet());
}
}
}
+1
View File
@@ -35,6 +35,7 @@ dependencies {
compileOnly(libs.netty)
compileOnly(libs.fastutil)
compileOnly(libs.authlib)
compileOnly(libs.datafixer)
}
widener {
@@ -0,0 +1,113 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.sql.GameModeConfig;
import lombok.Getter;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import org.bukkit.Material;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Which blocks, block states and block entities to hide, and the block to replace them with.
*/
@Getter
public final class ObfuscationConfig {
public static ObfuscationConfig of(GameModeConfig.TechhiderConfig<Material> config) {
return new ObfuscationConfig(config.ObfuscateWith, config.HiddenBlocks, config.HiddenBlockEntities);
}
private final Block obfuscateWith;
private final Set<Block> blocks;
private final Set<BlockState> blockStates;
private final Set<BlockEntityType<?>> blockEntityTypes;
/**
* @param hiddenBlocks "water" also hides all waterlogged block states
* @param hiddenBlockEntities block entity type ids, e.g. "minecraft:sign"
*/
public ObfuscationConfig(Material obfuscateWith, Set<Material> hiddenBlocks, Set<String> hiddenBlockEntities) {
this.obfuscateWith = CraftMagicNumbers.getBlock(obfuscateWith);
this.blocks = hiddenBlocks.stream()
.map(CraftMagicNumbers::getBlock)
.collect(Collectors.toUnmodifiableSet());
this.blockStates = getBlockStatesToHideFromMaterials(hiddenBlocks);
this.blockEntityTypes = hiddenBlockEntities.stream()
.map(id -> {
ResourceLocation loc = ResourceLocation.parse(id);
return BuiltInRegistries.BLOCK_ENTITY_TYPE.get(loc).orElse(null);
})
.filter(Objects::nonNull)
.map(Holder.Reference::value)
.collect(Collectors.toUnmodifiableSet());
}
public boolean hidesBlock(Block block) {
return blocks.contains(block);
}
public boolean hidesBlockState(BlockState blockState) {
return blockStates.contains(blockState);
}
public boolean hidesBlockEntity(BlockEntityType<?> type) {
return blockEntityTypes.contains(type);
}
private static Stream<BlockState> getWaterloggedBlockStates() {
FluidState waterFluidState = Fluids.WATER.getSource(false);
return BuiltInRegistries.BLOCK.stream()
.map((block) -> block.getStateDefinition().getPossibleStates())
.flatMap(Collection::stream)
.filter((blockState -> blockState.getFluidState() == waterFluidState));
}
private static Set<BlockState> getBlockStatesToHideFromMaterials(Set<Material> materials) {
Stream<BlockState> allStatesFromMaterials = materials.stream()
.map(CraftMagicNumbers::getBlock)
.map((block) -> block.getStateDefinition().getPossibleStates())
.flatMap(Collection::stream);
if(materials.contains(Material.WATER)) {
return Stream.concat(allStatesFromMaterials, getWaterloggedBlockStates()).collect(Collectors.toUnmodifiableSet());
}
else {
return allStatesFromMaterials.collect(Collectors.toUnmodifiableSet());
}
}
}