This repository has been archived by the owner on Feb 27, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 305
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement ChangeBlockEvent.Pre for modded liquids. Fixes #892.
A little explanation about this addition. For starters, we now modify the Forge added base classes for custom liquids, but as many know, we cannot mix into other mod code for implementors of IFluidBlock that do not extend BlockFluidBase/Classic/Finite etc. This remains fully implemented for the cases of mod blocks that do extend those classes, and not override the methods themselves. Due to the nature of how the injections work however, a bug with Mixin's refmap generation was discovered, leading to a required addition to the legacy-long-forgotten extraSrg.srg file. It now contains a searge mapping for both BlockFluidFinite and BlockFluidClassic #updateTick method since previously, the refmap would point to net/minecraft/block/Block;updateTick(). This has been minimally tested with some mod fluids and a sponge audit to ensure that mixin application succeeds. To keep up to date with the Mixin issue, it can be referenced here: SpongePowered/Mixin#326. As soon as the issue is resolved, the extraSrg.srg file can be removed from the project. Signed-off-by: Gabriel Harris-Rouquette <[email protected]>
- Loading branch information
Showing
7 changed files
with
585 additions
and
1 deletion.
There are no files selected for viewing
Submodule SpongeCommon
updated
from ced173 to 9ea412
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
MD: net/minecraft/server/management/PlayerList/initializeConnectionToPlayer (Lnet/minecraft/network/NetworkManager;Lnet/minecraft/entity/player/EntityPlayerMP;Lnet/minecraft/network/NetHandlerPlayServer;)V net/minecraft/server/management/PlayerList/func_72355_a (Lnet/minecraft/network/NetworkManager;Lnet/minecraft/entity/player/EntityPlayerMP;Lnet/minecraft/network/NetHandlerPlayServer;)V | ||
MD: net/minecraftforge/fluids/BlockFluidClassic/updateTick (Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V net/minecraftforge/fluids/BlockFluidClassic/func_180650_b (Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V | ||
MD: net/minecraftforge/fluids/BlockFluidFinite/updateTick (Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V net/minecraftforge/fluids/BlockFluidFinite/func_180650_b (Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;Ljava/util/Random;)V |
99 changes: 99 additions & 0 deletions
99
src/main/java/org/spongepowered/mod/mixin/core/forge/fluids/MixinBlockFluidBase.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* This file is part of Sponge, licensed under the MIT License (MIT). | ||
* | ||
* Copyright (c) SpongePowered <https://www.spongepowered.org> | ||
* Copyright (c) contributors | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
* THE SOFTWARE. | ||
*/ | ||
package org.spongepowered.mod.mixin.core.forge.fluids; | ||
|
||
import net.minecraft.block.Block; | ||
import net.minecraft.block.properties.PropertyInteger; | ||
import net.minecraft.block.state.IBlockState; | ||
import net.minecraft.util.math.BlockPos; | ||
import net.minecraft.world.IBlockAccess; | ||
import net.minecraftforge.fluids.BlockFluidBase; | ||
import org.spongepowered.api.event.block.ChangeBlockEvent; | ||
import org.spongepowered.asm.mixin.Final; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Shadow; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.Inject; | ||
import org.spongepowered.asm.mixin.injection.Redirect; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; | ||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture; | ||
import org.spongepowered.common.event.SpongeCommonEventFactory; | ||
import org.spongepowered.common.interfaces.block.IMixinBlock; | ||
import org.spongepowered.common.interfaces.world.IMixinWorld; | ||
import org.spongepowered.common.interfaces.world.IMixinWorldServer; | ||
import org.spongepowered.mod.mixin.core.block.MixinBlock; | ||
|
||
import java.util.Map; | ||
|
||
@Mixin(value = BlockFluidBase.class) | ||
public abstract class MixinBlockFluidBase extends MixinBlock implements IMixinBlock { | ||
|
||
@Shadow @Final public static PropertyInteger LEVEL; | ||
@Shadow protected int tickRate; | ||
|
||
@Redirect(method = "canDisplace", | ||
remap = false, | ||
at = @At( | ||
value = "INVOKE", | ||
target = "Ljava/util/Map;get(Ljava/lang/Object;)Ljava/lang/Object;", | ||
remap = false | ||
) | ||
) | ||
private Object getDisplacementWithSponge(Map map, Object key, IBlockAccess world, BlockPos pos) { | ||
if (!(world instanceof IMixinWorld) || ((IMixinWorld) world).isFake()) { | ||
return map.get(key); | ||
} | ||
if (!((Boolean) map.get(key))) { | ||
return Boolean.FALSE; | ||
} | ||
ChangeBlockEvent.Pre event = SpongeCommonEventFactory.callChangeBlockEventPre((IMixinWorldServer) world, pos); | ||
if (event.isCancelled()) { | ||
return Boolean.FALSE; | ||
} | ||
return Boolean.TRUE; | ||
} | ||
|
||
@Inject(method = "canDisplace", | ||
cancellable = true, | ||
remap = false, | ||
locals = LocalCapture.CAPTURE_FAILSOFT, | ||
at = @At( | ||
value = "INVOKE", | ||
target = "Lnet/minecraftforge/fluids/BlockFluidBase;getDensity(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;)I", | ||
remap = false | ||
) | ||
) | ||
private void onSpongeInjectFailEvent(IBlockAccess world, BlockPos pos, CallbackInfoReturnable<Boolean> cir, IBlockState state, Block block) { | ||
if (!(world instanceof IMixinWorld) || ((IMixinWorld) world).isFake()) { | ||
return; | ||
} | ||
ChangeBlockEvent.Pre event = SpongeCommonEventFactory.callChangeBlockEventPre((IMixinWorldServer) world, pos); | ||
if (event.isCancelled()) { | ||
cir.setReturnValue(false); | ||
} | ||
} | ||
|
||
|
||
} |
149 changes: 149 additions & 0 deletions
149
src/main/java/org/spongepowered/mod/mixin/core/forge/fluids/MixinBlockFluidClassic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* | ||
* This file is part of Sponge, licensed under the MIT License (MIT). | ||
* | ||
* Copyright (c) SpongePowered <https://www.spongepowered.org> | ||
* Copyright (c) contributors | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a copy | ||
* of this software and associated documentation files (the "Software"), to deal | ||
* in the Software without restriction, including without limitation the rights | ||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
* copies of the Software, and to permit persons to whom the Software is | ||
* furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
* THE SOFTWARE. | ||
*/ | ||
package org.spongepowered.mod.mixin.core.forge.fluids; | ||
|
||
import net.minecraft.block.state.IBlockState; | ||
import net.minecraft.util.math.BlockPos; | ||
import net.minecraft.world.IBlockAccess; | ||
import net.minecraft.world.World; | ||
import net.minecraftforge.common.util.Constants; | ||
import net.minecraftforge.fluids.BlockFluidBase; | ||
import net.minecraftforge.fluids.BlockFluidClassic; | ||
import org.spongepowered.api.block.BlockSnapshot; | ||
import org.spongepowered.api.data.Transaction; | ||
import org.spongepowered.api.event.CauseStackManager; | ||
import org.spongepowered.api.event.block.ChangeBlockEvent; | ||
import org.spongepowered.api.event.cause.EventContextKeys; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.injection.At; | ||
import org.spongepowered.asm.mixin.injection.Inject; | ||
import org.spongepowered.asm.mixin.injection.Redirect; | ||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; | ||
import org.spongepowered.common.block.BlockUtil; | ||
import org.spongepowered.common.event.ShouldFire; | ||
import org.spongepowered.common.event.SpongeCommonEventFactory; | ||
import org.spongepowered.common.event.tracking.IPhaseState; | ||
import org.spongepowered.common.event.tracking.PhaseContext; | ||
import org.spongepowered.common.event.tracking.PhaseTracker; | ||
import org.spongepowered.common.interfaces.world.IMixinWorld; | ||
import org.spongepowered.common.interfaces.world.IMixinWorldServer; | ||
|
||
import java.util.Random; | ||
import java.util.function.BiConsumer; | ||
|
||
import javax.annotation.Nullable; | ||
|
||
@Mixin(value = BlockFluidClassic.class) | ||
public abstract class MixinBlockFluidClassic extends MixinBlockFluidBase { | ||
|
||
@Override | ||
public BiConsumer<CauseStackManager.StackFrame, IMixinWorldServer> getTickFrameModifier() { | ||
return (frame, world) -> frame.addContext(EventContextKeys.LIQUID_FLOW, (org.spongepowered.api.world.World) world); | ||
} | ||
|
||
@Inject(method = "updateTick", | ||
at = @At("HEAD"), | ||
cancellable = true | ||
) | ||
private void onUpdateTickCheckSpongePre(World world, BlockPos pos, IBlockState state, Random rand, CallbackInfo ci) { | ||
if (!((IMixinWorld) world).isFake() && ShouldFire.CHANGE_BLOCK_EVENT_PRE) { | ||
if (SpongeCommonEventFactory.callChangeBlockEventPre((IMixinWorldServer) world, pos).isCancelled()) { | ||
ci.cancel(); | ||
} | ||
} | ||
} | ||
|
||
@Nullable private Boolean isPreCancelled; | ||
|
||
/** | ||
* @author gabizou - June 4th, 2019 - 1.12.2 | ||
* @reason In the event the injection above does cancel, we need to duck out of the rest of the method. | ||
* Otherwise, the above injection never went through, the {@link BlockFluidBase#canDisplace(IBlockAccess, BlockPos)} | ||
* ends up getting it's injection thrown anyways. | ||
* | ||
* @param world The world | ||
* @param pos the position being flown into | ||
* @param state The state | ||
* @param rand The rando | ||
* @param ci The callback info | ||
*/ | ||
@Inject( | ||
method = "updateTick", | ||
at = @At( | ||
value = "INVOKE", | ||
target = "Lnet/minecraftforge/fluids/BlockFluidClassic;canDisplace(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;)Z", | ||
remap = false | ||
), | ||
cancellable = true | ||
) | ||
private void onCheckDisplaceIfPreAlreadyCancelled(World world, BlockPos pos, IBlockState state, Random rand, CallbackInfo ci) { | ||
if (this.isPreCancelled == Boolean.TRUE) { | ||
ci.cancel(); | ||
// And reset the field so we don't leak... | ||
this.isPreCancelled = null; | ||
} | ||
} | ||
|
||
// Capture Fluids flowing into other blocks | ||
@SuppressWarnings({"unchecked", "DefaultAnnotationParam"}) | ||
@Redirect( | ||
method = "flowIntoBlock", | ||
remap = false, | ||
at = @At( | ||
value = "INVOKE", | ||
target = "Lnet/minecraft/world/World;setBlockState(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/state/IBlockState;)Z", | ||
remap = true | ||
) | ||
) | ||
private boolean afterCanFlowInto(World targetWorld, BlockPos targetPos, IBlockState newLiquidState, World world, BlockPos pos, int meta) { | ||
if (((IMixinWorld) targetWorld).isFake() || !ShouldFire.CHANGE_BLOCK_EVENT_BREAK) { // Check if we even need to fire. | ||
return world.setBlockState(targetPos, newLiquidState, Constants.BlockFlags.DEFAULT); | ||
} | ||
|
||
final IBlockState existing = targetWorld.getBlockState(targetPos); | ||
// Do not call events when just flowing into air or same liquid | ||
//noinspection RedundantCast | ||
if (!existing.getBlock().isAir(existing, targetWorld, targetPos) && !(existing.getMaterial().isLiquid() || existing.getBlock() == (BlockFluidClassic) (Object) this)) { | ||
ChangeBlockEvent.Break event = SpongeCommonEventFactory.callChangeBlockEventModifyLiquidBreak(world, pos, newLiquidState); | ||
|
||
Transaction<BlockSnapshot> transaction = event.getTransactions().get(0); | ||
if (event.isCancelled() || !transaction.isValid()) { | ||
// We need to clear any drops here because this is called after {@link #displaceIfPossible} and since it was true, well | ||
// there's the likelyhood that there's a dropped item | ||
final PhaseContext<?> currentContext = PhaseTracker.getInstance().getCurrentContext(); | ||
((IPhaseState) currentContext.state).processCancelledTransaction(currentContext, transaction, transaction.getOriginal()); | ||
return false; | ||
} | ||
|
||
// Transaction modified? | ||
if (transaction.getCustom().isPresent()) { | ||
return targetWorld.setBlockState(targetPos, BlockUtil.toNative(transaction.getFinal().getState()), Constants.BlockFlags.DEFAULT); | ||
} | ||
} | ||
|
||
return targetWorld.setBlockState(targetPos, newLiquidState, Constants.BlockFlags.DEFAULT); | ||
} | ||
|
||
} |
Oops, something went wrong.