Add a config option to disable the water plants fix

This commit is contained in:
Sollace 2022-10-11 17:19:06 +02:00
parent db8181c45e
commit 5d368d50e9
3 changed files with 107 additions and 52 deletions

View file

@ -27,6 +27,8 @@ public class Config extends JsonConfig {
"The result will always be what is set by this config file.";*/ "The result will always be what is set by this config file.";*/
public final Setting<Boolean> ignoreMineLP = value("client", "ignoreMineLP", false); public final Setting<Boolean> ignoreMineLP = value("client", "ignoreMineLP", false);
public final Setting<Boolean> disableWaterPlantsFix = value("compatibility", "disableWaterPlantsFix", false);
public Config() { public Config() {
super(GamePaths.getConfigDirectory().resolve("unicopia.json")); super(GamePaths.getConfigDirectory().resolve("unicopia.json"));
} }

View file

@ -0,0 +1,80 @@
package com.minelittlepony.unicopia.block.data;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.Unicopia;
import net.minecraft.block.*;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.state.State;
import net.minecraft.state.property.Properties;
import net.minecraft.state.property.Property;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.WorldAccess;
public class WaterLoggingManager<O, S extends State<O, S>> {
private static final WaterLoggingManager<?, ?> INSTANCE = new WaterLoggingManager<>();
@SuppressWarnings("unchecked")
public static <O, S extends State<O, S>> WaterLoggingManager<O, S> getInstance() {
return (WaterLoggingManager<O, S>)INSTANCE;
}
private final boolean enabled;
public WaterLoggingManager() {
enabled = !Unicopia.getConfig().disableWaterPlantsFix.get();
}
public void appendProperties(O owner, StateBuilder builder) {
if (appliesTo(owner)) {
builder.addIfNotPresent(Properties.WATERLOGGED);
}
}
public void getDefaultState(O owner, CallbackInfoReturnable<S> info) {
if (appliesTo(owner, info.getReturnValue())) {
info.setReturnValue(info.getReturnValue().with(Properties.WATERLOGGED, true));
}
}
public void getFluidState(O owner, S state, CallbackInfoReturnable<FluidState> info) {
if (appliesTo(owner, state)) {
info.setReturnValue((state.get(Properties.WATERLOGGED) ? Fluids.WATER : Fluids.EMPTY).getDefaultState());
}
}
public void getUpdatedState(WorldAccess world, BlockPos pos, BlockState oldState, CallbackInfoReturnable<BlockState> info) {
if (shouldPreventRemoval(world, pos, oldState, info.getReturnValue())) {
info.setReturnValue(oldState);
}
}
public boolean appliesTo(O block, S state) {
return appliesTo(block) && state.contains(Properties.WATERLOGGED);
}
public boolean appliesTo(O block) {
return enabled
&& (block instanceof SeagrassBlock
|| block instanceof TallSeagrassBlock
|| block instanceof KelpBlock
|| block instanceof KelpPlantBlock);
}
public boolean shouldPreventRemoval(WorldAccess world, BlockPos pos, AbstractBlock.AbstractBlockState oldState, AbstractBlock.AbstractBlockState newState) {
return enabled
&& newState.isAir()
&& oldState.contains(Properties.WATERLOGGED)
&& oldState.getBlock() instanceof TallSeagrassBlock
&& oldState.contains(TallPlantBlock.HALF)
&& oldState.get(TallPlantBlock.HALF) == DoubleBlockHalf.LOWER
&& world.getBlockState(pos.up()).isOf(oldState.getBlock());
}
public interface StateBuilder {
void addIfNotPresent(Property<?> property);
}
}

View file

@ -8,14 +8,13 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import com.minelittlepony.unicopia.block.data.WaterLoggingManager;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.fluid.FluidState; import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.state.State; import net.minecraft.state.State;
import net.minecraft.state.StateManager; import net.minecraft.state.StateManager;
import net.minecraft.state.StateManager.Factory; import net.minecraft.state.StateManager.Factory;
import net.minecraft.state.property.Properties;
import net.minecraft.state.property.Property; import net.minecraft.state.property.Property;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction; import net.minecraft.util.math.Direction;
@ -28,72 +27,46 @@ abstract class MixinStateManager<O, S extends State<O, S>> {
@Inject(method = "getDefaultState", at = @At("RETURN"), cancellable = true) @Inject(method = "getDefaultState", at = @At("RETURN"), cancellable = true)
private void onGetDefaultState(CallbackInfoReturnable<S> info) { private void onGetDefaultState(CallbackInfoReturnable<S> info) {
if ((owner instanceof SeagrassBlock WaterLoggingManager.<O, S>getInstance().getDefaultState(owner, info);
|| owner instanceof TallSeagrassBlock
|| owner instanceof KelpBlock
|| owner instanceof KelpPlantBlock
) && info.getReturnValue().contains(Properties.WATERLOGGED)) {
info.setReturnValue(info.getReturnValue().with(Properties.WATERLOGGED, true));
}
} }
} }
@Mixin(StateManager.Builder.class) @Mixin(StateManager.Builder.class)
abstract class MixinStateManagerBuilder<O, S extends State<O, S>> { abstract class MixinStateManagerBuilder<O, S extends State<O, S>> implements WaterLoggingManager.StateBuilder {
@Shadow @Shadow
private @Final O owner; private @Final O owner;
@Shadow @Shadow
private @Final Map<String, Property<?>> namedProperties; private @Final Map<String, Property<?>> namedProperties;
@SuppressWarnings("unchecked")
@Inject(method = "build", at = @At("HEAD")) @Inject(method = "build", at = @At("HEAD"))
private void build(Function<O, S> defaultStateGetter, Factory<O, S> factory, CallbackInfoReturnable<StateManager<O, S>> info) { private void build(Function<O, S> defaultStateGetter, Factory<O, S> factory, CallbackInfoReturnable<StateManager<O, S>> info) {
if (owner instanceof SeagrassBlock WaterLoggingManager.<O, S>getInstance().appendProperties(owner, this);
|| owner instanceof TallSeagrassBlock }
|| owner instanceof KelpBlock
|| owner instanceof KelpPlantBlock @Override
) { @SuppressWarnings("unchecked")
if (!namedProperties.containsValue(Properties.WATERLOGGED)) { public void addIfNotPresent(Property<?> property) {
((StateManager.Builder<O, S>)(Object)this).add(Properties.WATERLOGGED); if (!namedProperties.containsValue(property)) {
} ((StateManager.Builder<O, S>)(Object)this).add(property);
} }
} }
} }
@Mixin(BlockState.class) @Mixin(AbstractBlock.AbstractBlockState.class)
abstract class MixinBlockState extends AbstractBlock.AbstractBlockState { abstract class MixinBlockState extends State<Block, BlockState> {
protected MixinBlockState() { MixinBlockState() {super(null, null, null);}
super(null, null, null);
@Shadow
protected abstract BlockState asBlockState();
@Inject(method = "getFluidState", at = @At("HEAD"), cancellable = true)
private void onGetFluidState(CallbackInfoReturnable<FluidState> info) {
WaterLoggingManager.<Block, BlockState>getInstance().getFluidState(owner, asBlockState(), info);
} }
@Override @Inject(method = "getStateForNeighborUpdate", at = @At("RETURN"), cancellable = true)
public FluidState getFluidState() { private void onGetStateForNeighborUpdate(Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos, CallbackInfoReturnable<BlockState> info) {
if (contains(Properties.WATERLOGGED) && ( WaterLoggingManager.<Block, BlockState>getInstance().getUpdatedState(world, pos, asBlockState(), info);
getBlock() instanceof SeagrassBlock
|| getBlock() instanceof TallSeagrassBlock
|| getBlock() instanceof KelpBlock
|| getBlock() instanceof KelpPlantBlock
)) {
return (get(Properties.WATERLOGGED) ? Fluids.WATER : Fluids.EMPTY).getDefaultState();
}
return super.getFluidState();
}
@Override
public BlockState getStateForNeighborUpdate(Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
BlockState newState = super.getStateForNeighborUpdate(direction, neighborState, world, pos, neighborPos);
if (newState.isAir()
&& contains(Properties.WATERLOGGED)
&& getBlock() instanceof TallSeagrassBlock
&& contains(TallPlantBlock.HALF)
&& get(TallPlantBlock.HALF) == DoubleBlockHalf.LOWER) {
BlockState above = world.getBlockState(pos.up());
if (above.isOf(getBlock())) {
return asBlockState();
}
}
return newState;
} }
} }