fix: 奇点吞方块前问保护层(BreakEvent);毁灭爆炸遵守 mobGriefing;暴露 getOwnerEntity
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
b51852c15b
commit
770cdec7f9
3 files changed
+100
-2
No files matched your search
@@ -1,11 +1,13 @@
|
||||
package com.pengu.thaumcraft.additions.entity;
|
||||
|
||||
import com.pengu.thaumcraft.additions.api.integration.ThaumicAdditionsDamage;
|
||||
import com.pengu.thaumcraft.additions.misc.TerritoryGuard;
|
||||
import java.util.List;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.boss.EntityDragon;
|
||||
import net.minecraft.entity.boss.EntityWither;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
@@ -58,7 +60,7 @@ public class EntitySingularity extends EntityAlumentum {
|
||||
++this.ticksExisted;
|
||||
if(this.ticksExisted >= 2000 || this.suckedItems >= 2000.0F) {
|
||||
for(p = 0; p < 5; ++p) {
|
||||
this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, this.suckedItems / 200.0F, true);
|
||||
this.worldObj.createExplosion(this, this.posX, this.posY, this.posZ, this.suckedItems / 200.0F, this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
@@ -137,7 +139,7 @@ public class EntitySingularity extends EntityAlumentum {
|
||||
i = (int)this.posX + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
||||
var22 = (int)this.posY + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
||||
var23 = (int)this.posZ + this.worldObj.rand.nextInt(this.radius) - this.worldObj.rand.nextInt(this.radius);
|
||||
if(this.worldObj.getBlock(i, var22, var23) != Blocks.air && this.worldObj.getBlock(i, var22, var23).getBlockHardness(this.worldObj, i, var22, var23) > -1.0F && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing")) {
|
||||
if(this.worldObj.getBlock(i, var22, var23) != Blocks.air && this.worldObj.getBlock(i, var22, var23).getBlockHardness(this.worldObj, i, var22, var23) > -1.0F && this.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing") && this.canDestroy(i, var22, var23)) {
|
||||
this.worldObj.getBlock(i, var22, var23).breakBlock(this.worldObj, i, var22, var23, this.worldObj.getBlock(i, var22, var23), 1);
|
||||
this.worldObj.playSoundEffect((double)i, (double)var22, (double)var23, this.worldObj.getBlock(i, var22, var23).stepSound.getBreakSound(), this.worldObj.getBlock(i, var22, var23).stepSound.getVolume(), this.worldObj.getBlock(i, var22, var23).stepSound.getPitch());
|
||||
if(!this.worldObj.isRemote) {
|
||||
@@ -188,6 +190,17 @@ public class EntitySingularity extends EntityAlumentum {
|
||||
|
||||
}
|
||||
|
||||
/** The player who threw it, or null (dispenser, merged singularity). Protection plugins read this by name. */
|
||||
public EntityPlayer getOwnerEntity() {
|
||||
EntityLivingBase t = this.getThrower();
|
||||
return t instanceof EntityPlayer ? (EntityPlayer)t : null;
|
||||
}
|
||||
|
||||
/** Island/territory check: a BreakEvent as the thrower, or as a fake player when nobody threw it. */
|
||||
private boolean canDestroy(int x, int y, int z) {
|
||||
return TerritoryGuard.canRemoveBlock(this.worldObj, x, y, z, this.getOwnerEntity());
|
||||
}
|
||||
|
||||
protected void onImpact(MovingObjectPosition m) {
|
||||
this.worldObj.playSoundEffect(this.posX, this.posY, this.posZ, "thaumicadditions:singularity", 16.0F, 1.0F);
|
||||
this.inGround = true;
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.pengu.thaumcraft.additions.misc;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.common.util.FakePlayer;
|
||||
import net.minecraftforge.common.util.FakePlayerFactory;
|
||||
import net.minecraftforge.event.world.BlockEvent;
|
||||
|
||||
/**
|
||||
* Standard cancellable BlockEvent.BreakEvent gate for block removal that no player performs directly
|
||||
* (void entity, hungry blocks, ...). Island and territory plugins receive the contract they already handle for player
|
||||
* mining; the actor is the responsible player when there is one, otherwise a per-world fake player (which the
|
||||
* protection layer judges as an unattributed machine). With no receiver nothing changes.
|
||||
*/
|
||||
public final class TerritoryGuard {
|
||||
|
||||
private static WeakReference<EntityPlayer> fallback = new WeakReference<>(null);
|
||||
|
||||
/** @param actor the player responsible for the removal, or null when there is none */
|
||||
public static boolean canRemoveBlock(World world, int x, int y, int z, EntityPlayer actor) {
|
||||
EntityPlayer who = resolveActor(world, actor);
|
||||
if (who == null) {
|
||||
// no world to attribute the event to (client world): nothing to protect
|
||||
return !(world instanceof WorldServer);
|
||||
}
|
||||
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
world,
|
||||
world.getBlock(x, y, z),
|
||||
world.getBlockMetadata(x, y, z),
|
||||
who);
|
||||
return !MinecraftForge.EVENT_BUS.post(event);
|
||||
}
|
||||
|
||||
private static EntityPlayer resolveActor(World world, EntityPlayer actor) {
|
||||
if (actor != null) return actor;
|
||||
if (world instanceof WorldServer) {
|
||||
EntityPlayer player = fallback.get();
|
||||
if (player == null || player.worldObj != world) {
|
||||
FakePlayer fake = FakePlayerFactory.getMinecraft((WorldServer) world);
|
||||
player = fake;
|
||||
fallback = new WeakReference<>(player);
|
||||
}
|
||||
return player;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private TerritoryGuard() {}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
"""The singularity must ask the protection layer before removing a block and respect mobGriefing for its blast."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
SRC = (ROOT / "src/main/java/com/pengu/thaumcraft/additions/entity/EntitySingularity.java").read_text(encoding="utf-8")
|
||||
GUARD = (ROOT / "src/main/java/com/pengu/thaumcraft/additions/misc/TerritoryGuard.java").read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def main():
|
||||
assert "new BlockEvent.BreakEvent(" in GUARD and "EVENT_BUS.post(event)" in GUARD
|
||||
assert "FakePlayerFactory.getMinecraft" in GUARD
|
||||
|
||||
# the block-eating branch is gated by the guard before any breakBlock / setBlockToAir
|
||||
gate = SRC.index("this.canDestroy(i, var22, var23)")
|
||||
assert gate < SRC.index(".breakBlock(this.worldObj, i, var22, var23"), "guard must precede breakBlock"
|
||||
assert gate < SRC.index("this.worldObj.setBlockToAir(i, var22, var23)")
|
||||
assert "TerritoryGuard.canRemoveBlock(this.worldObj, x, y, z, this.getOwnerEntity())" in SRC
|
||||
|
||||
# explosion attribution accessor, plus the end-of-life blast no longer ignores mobGriefing
|
||||
assert "public EntityPlayer getOwnerEntity()" in SRC
|
||||
assert 'this.suckedItems / 200.0F, true)' not in SRC
|
||||
print("ok")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user